<commit_before>import { css, html, LitElement } from 'lit-element';
import { nothing } from 'lit-html';
import { ResizeObserver as roPolyfill } from '@juggle/resize-observer';
import SearchProvider from './search/search-provider.js';
import DownloadProvider from './downloads/downloads-provider.js';
import VisualAdjustmentProvider from './visual-adjustments/visual-adjustments-provider.js';
import BookmarksProvider from './bookmarks/bookmarks-provider.js';
import SharingProvider from '../ItemNavigator/providers/sharing.js';
import VolumesProvider from './volumes/volumes-provider.js';
import BRFullscreenMgr from './br-fullscreen-mgr.js';
import { Book } from './BookModel.js';
import bookLoader from './assets/book-loader.js';

const ResizeObserver = window.ResizeObserver || roPolyfill;

const events = {
  menuUpdated: 'menuUpdated',
  updateSideMenu: 'updateSideMenu',
  PostInit: 'PostInit',
  ViewportInFullScreen: 'ViewportInFullScreen',
};
export class BookNavigator extends LitElement {
  static get properties() {
    return {
      book: { type: Object },
      pageContainerSelector: { type: String },
      brWidth: { type: Number },
      bookReaderLoaded: { type: Boolean },
      bookreader: { type: Object },
      downloadableTypes: { type: Array },
      isAdmin: { type: Boolean },
      lendingInitialized: { type: Boolean },
      lendingStatus: { type: Object },
      menuProviders: { type: Object },
      menuShortcuts: { type: Array },
      sideMenuOpen: { type: Boolean },
      signedIn: { type: Boolean },
    };
  }

  constructor() {
    super();
    this.book = {};
    this.pageContainerSelector = '.BRcontainer';
    this.brWidth = 0;
    this.bookReaderCannotLoad = false;
    this.bookReaderLoaded = false;
    this.bookreader = null;
    this.downloadableTypes = [];
    this.isAdmin = false;
    this.lendingInitialized = false;
    this.lendingStatus = {};
    this.menuProviders = {};
    this.menuShortcuts = [];
    this.sideMenuOpen = false;
    this.signedIn = false;

    // Untracked properties
    this.fullscreenMgr = null;
    this.brResizeObserver = null;
    this.model = new Book();
    this.shortcutOrder = ['volumes', 'search', 'bookmarks'];
  }

  firstUpdated() {
    this.model.setMetadata(this.book);
    this.bindEventListeners();
    this.emitPostInit();
  }

  updated(changed) {
    if (!this.bookreader) {
      return;
    }
    const isFirstSideMenuUpdate = changed.has('sideMenuOpen') && (changed.get('sideMenuOpen') === undefined);
    if (!isFirstSideMenuUpdate) {
      // realign image
      if (this.bookreader.animating) {
        return;
      }
      this.bookreader.resize();
    }
  }

  /**
   * Global event emitter for when Book Navigator loads
   */
  emitPostInit() {
    // emit global event when book nav has loaded with current bookreader selector
    this.dispatchEvent(new CustomEvent(`BrBookNav:${events.PostInit}`, {
      detail: { brSelector: this.bookreader?.el },
      bubbles: true,
      composed: true,
    }));
  }

  /**
   * Instantiates books submenus & their update callbacks
   *
   * NOTE: we are doing our best to scope bookreader's instance.
   * If your submenu provider uses a bookreader instance to read, manually
   * manipulate BookReader, please update the navigator's instance of it
   * to keep it in sync.
   */
  initializeBookSubmenus() {
    const isBookProtected = this.bookreader.options.protected;
    this.menuProviders = {
      search: new SearchProvider(
        /**
         * Search specific menu updates
         * @param {BookReader} brInstance
         * @param {{ searchCanceled: boolean }} searchUpdates
         */
        (brInstance = null, searchUpdates = {}) => {
          if (brInstance) {
            /* refresh br instance reference */
            this.bookreader = brInstance;
          }
          this.updateMenuContents();
          const wideEnoughToOpenMenu = this.brWidth >= 640;
          if (wideEnoughToOpenMenu && !searchUpdates?.searchCanceled) {
            /* open side search menu */
            this.updateSideMenu('search', 'open');
          }
        },
        this.bookreader,
      ),
      downloads: new DownloadProvider(isBookProtected),
      visualAdjustments: new VisualAdjustmentProvider({
        onOptionChange: (event, brInstance = null) => {
          if (brInstance) {
            /* refresh br instance reference */
            this.bookreader = brInstance;
          }
          this.updateMenuContents();
        },
        bookContainerSelector: this.pageContainerSelector,
        bookreader: this.bookreader,
      }),
      share: new SharingProvider(this.book.metadata, this.baseHost, this.itemType, this.bookreader.options.subPrefix),
      bookmarks: new BookmarksProvider(this.bookmarksOptions, this.bookreader),
    };

    // add shortcut for volumes if multipleBooksList exists
    if (this.bookreader.options.enableMultipleBooks) {
      this.menuProviders.volumes = new VolumesProvider(this.baseHost, this.bookreader, (brInstance) => {
        if (brInstance) {
          /* refresh br instance reference */
          this.bookreader = brInstance;
        }
        this.updateMenuContents();
        this.updateSideMenu('volumes', 'open');
      });
      this.addMenuShortcut('volumes');
    }

    this.addMenuShortcut('search'); /* start with search as a shortcut */
    this.updateMenuContents();
  }

  /** gets element that houses the bookreader in light dom */
  get mainBRContainer() {
    return document.querySelector(this.bookreader.el);
  }

  get bookmarksOptions() {
    const referrerStr = `referer=${encodeURIComponent(location.href)}`;
    return {
      loginUrl: `https://${this.baseHost}/account/login?${referrerStr}`,
      displayMode: this.signedIn ? 'bookmarks' : 'login',
      showItemNavigatorModal: this.showItemNavigatorModal.bind(this),
      closeItemNavigatorModal: this.closeItemNavigatorModal.bind(this),
      onBookmarksChanged: (bookmarks) => {
        const method = Object.keys(bookmarks).length ? 'add' : 'remove';
        this[`${method}MenuShortcut`]('bookmarks');
        this.updateMenuContents();
      },
    };
  }

  /**
   * Open side menu
   * @param {string} menuId
   * @param {('open'|'close'|'toggle')} action
   */
  updateSideMenu(menuId = '', action = 'open') {
    if (!menuId || !action) {
      return;
    }
    const event = new CustomEvent(
      events.updateSideMenu, {
        detail: { menuId, action },
      },
    );
    this.dispatchEvent(event);
  }

  /**
   * Sets order of menu and emits custom event when done
   */
  updateMenuContents() {
    const {
      search, downloads, visualAdjustments, share, bookmarks, volumes
    } = this.menuProviders;
    const availableMenus = [volumes, search, bookmarks, visualAdjustments, share].filter((menu) => !!menu);

    if (this.shouldShowDownloadsMenu()) {
      downloads.update(this.downloadableTypes);
      availableMenus.splice(1, 0, downloads);
    }

    const event = new CustomEvent(
      events.menuUpdated, {
        detail: availableMenus,
      },
    );
    this.dispatchEvent(event);
  }

  /**
   * Confirms if we should show the downloads menu
   * @returns {bool}
   */
  shouldShowDownloadsMenu() {
    if (this.model.isRestricted === false) { return true; }
    if (this.isAdmin) { return true; }
    const { user_loan_record = {} } = this.lendingStatus;
    const hasNoLoanRecord = Array.isArray(user_loan_record); /* (bc PHP assoc. arrays) */

    if (hasNoLoanRecord) { return false; }

    const hasValidLoan = user_loan_record.type && (user_loan_record.type !== 'SESSION_LOAN');
    return hasValidLoan;
  }

  /**
   * Adds a provider object to the menuShortcuts array property if it isn't
   * already added. menuShortcuts are then sorted by shortcutOrder and
   * a menuShortcutsUpdated event is emitted.
   *
   * @param {string} menuId - a string matching the id property of a provider
   */
  addMenuShortcut(menuId) {
    if (this.menuShortcuts.find((m) => m.id === menuId)) { return; }

    this.menuShortcuts.push(this.menuProviders[menuId]);
    this.sortMenuShortcuts();
    this.emitMenuShortcutsUpdated();
  }

  /**
   * Removes a provider object from the menuShortcuts array and emits a
   * menuShortcutsUpdated event.
   *
   * @param {string} menuId - a string matching the id property of a provider
   */
  removeMenuShortcut(menuId) {
    this.menuShortcuts = this.menuShortcuts.filter((m) => m.id !== menuId);
    this.emitMenuShortcutsUpdated();
  }

  /**
   * Sorts the menuShortcuts property by comparing each provider's id to
   * the id in each iteration over the shortcutOrder array.
   */
  sortMenuShortcuts() {
    this.menuShortcuts = this.shortcutOrder.reduce((shortcuts, id) => {
      const menu = this.menuShortcuts.find((m) => m.id === id);
      if (menu) { shortcuts.push(menu); }
      return shortcuts;
    }, []);
  }

  emitMenuShortcutsUpdated() {
    const event = new CustomEvent('menuShortcutsUpdated', {
      detail: this.menuShortcuts,
    });
    this.dispatchEvent(event);
  }

  /**
   * Core bookreader event handler registry
   *
   * NOTE: we are trying to keep bookreader's instance in scope
   * Please update Book Navigator's instance reference of it to keep it current
   */
  bindEventListeners() {
    window.addEventListener('BookReader:PostInit', (e) => {
      this.bookreader = e.detail.props;
      this.bookReaderLoaded = true;
      this.bookReaderCannotLoad = false;
      this.fullscreenMgr = new BRFullscreenMgr(this.bookreader.el);

      this.initializeBookSubmenus();
      setTimeout(() => this.bookreader.resize(), 0);
      this.brResizeObserver = new ResizeObserver((elements) => this.reactToBrResize(elements));
      this.brResizeObserver.observe(this.mainBRContainer);
    });
    window.addEventListener('BookReader:fullscreenToggled', (event) => {
      const { detail: { props: brInstance = null } } = event;
      if (brInstance) {
        this.bookreader = brInstance;
      }
      this.manageFullScreenBehavior(event);
    }, { passive: true });
    window.addEventListener('BookReader:ToggleSearchMenu', (event) => {
      this.dispatchEvent(new CustomEvent(events.updateSideMenu, {
        detail: { menuId: 'search', action: 'toggle' },
      }));
    });
    window.addEventListener('LendingFlow:PostInit', ({ detail }) => {
      const {
        downloadTypesAvailable, lendingStatus, isAdmin, previewType,
      } = detail;
      this.lendingInitialized = true;
      this.downloadableTypes = downloadTypesAvailable;
      this.lendingStatus = lendingStatus;
      this.isAdmin = isAdmin;
      this.bookReaderCannotLoad = previewType === 'singlePagePreview';
    });
    window.addEventListener('BRJSIA:PostInit', ({ detail }) => {
      const { isRestricted, downloadURLs } = detail;
      this.bookReaderLoaded = true;
      this.downloadableTypes = downloadURLs;
      this.model.setRestriction(isRestricted);
    });
  }

  /**
   * Uses resize observer to fire BookReader's `resize` functionality
   * We do not want to trigger resize IF:
   *  - book animation is happening
   *  - book is in fullscreen (fullscreen is handled separately)
   *
   * @param { Object } entries - resize observer entries
   */
  reactToBrResize(entries = []) {
    const startBrWidth = this.brWidth;
    const { animating } = this.bookreader;

    entries.forEach(({ contentRect, target }) => {
      if (target === this.mainBRContainer) {
        this.brWidth = contentRect.width;
      }
    });
    setTimeout(() => {
      if (startBrWidth && !animating) {
        this.bookreader.resize();
      }
    }, 0);
  }

  /**
   * Manages Fullscreen behavior
   * This makes sure that controls are _always_ in view
   * We need this to accommodate LOAN BAR during fullscreen
   */
  manageFullScreenBehavior() {
    this.emitFullScreenState();

    if (!this.bookreader.isFullscreen()) {
      this.fullscreenMgr.teardown();
    } else {
      this.fullscreenMgr.setup(this.bookreader);
    }
  }

  /**
   * Intercepts and relays fullscreen toggle events
   */
  emitFullScreenState() {
    const isFullScreen = this.bookreader.isFullscreen();
    const event = new CustomEvent('ViewportInFullScreen', {
      detail: { isFullScreen },
    });
    this.dispatchEvent(event);
  }

  emitShowItemNavigatorModal(e) {
    this.dispatchEvent(new CustomEvent('showItemNavigatorModal', {
      detail: e.detail,
    }));
  }

  emitCloseItemNavigatorModal() {
    this.dispatchEvent(new CustomEvent('closeItemNavigatorModal'));
  }

  showItemNavigatorModal(e) {
    this.emitShowItemNavigatorModal(e);
  }

  closeItemNavigatorModal() {
    this.emitCloseItemNavigatorModal();
  }

  get loader() {
    const loader = html`

${bookLoader}

Loading viewer

    `;
    return !this.bookReaderLoaded ? loader : nothing;
  }

  get loadingClass() {
    return !this.bookReaderLoaded ? 'loading' : '';
  }

  get itemImage() {
    const url = `https://${this.baseHost}/services/img/${this.book.metadata.identifier}`;
    return html`<img src="${url}" alt="cover image for ${this.book.metadata.identifier}">`;
  }

  render() {
    const placeholder = this.bookReaderCannotLoad ? this.itemImage : this.loader;
    return html`

      ${placeholder}
      <slot name="bookreader"></slot>

  `;
  }

  static get styles() {
    return css`
    #book-navigator.loading {
      display: flex;
      align-items: center;
      justify-content: center;
      min-height: 30vh;
    }

    #book-navigator .book-loader {
      width: 30%;
      margin: auto;
      text-align: center;
      color: var(--primaryTextColor);
    }

    .book-loader {
      position: relative;
    }

    .book-loader svg {
      display: block;
      width: 60%;
      max-width: 100px;
      height: auto;
      margin: auto;
    }

    svg * {
      fill: var(--primaryTextColor);
    }

    svg .ring {
      animation: rotate 1.3s infinite linear;
      transform-origin: 50px 50px;
      transform-box: fill-box;
      display: block; // transform won't work on inline style
    }

    @keyframes rotate {
      0% {
        transform: rotate(-360deg);
      }
    }
  `;
  }
}

customElements.define('book-navigator', BookNavigator);
<commit_msg>booknav theater preview - cap cover image height so it does not overflow theater (#869)<commit_after>import { css, html, LitElement } from 'lit-element';
import { nothing } from 'lit-html';
import { ResizeObserver as roPolyfill } from '@juggle/resize-observer';
import SearchProvider from './search/search-provider.js';
import DownloadProvider from './downloads/downloads-provider.js';
import VisualAdjustmentProvider from './visual-adjustments/visual-adjustments-provider.js';
import BookmarksProvider from './bookmarks/bookmarks-provider.js';
import SharingProvider from '../ItemNavigator/providers/sharing.js';
import VolumesProvider from './volumes/volumes-provider.js';
import BRFullscreenMgr from './br-fullscreen-mgr.js';
import { Book } from './BookModel.js';
import bookLoader from './assets/book-loader.js';

const ResizeObserver = window.ResizeObserver || roPolyfill;

const events = {
  menuUpdated: 'menuUpdated',
  updateSideMenu: 'updateSideMenu',
  PostInit: 'PostInit',
  ViewportInFullScreen: 'ViewportInFullScreen',
};
export class BookNavigator extends LitElement {
  static get properties() {
    return {
      book: { type: Object },
      pageContainerSelector: { type: String },
      brWidth: { type: Number },
      bookReaderLoaded: { type: Boolean },
      bookreader: { type: Object },
      downloadableTypes: { type: Array },
      isAdmin: { type: Boolean },
      lendingInitialized: { type: Boolean },
      lendingStatus: { type: Object },
      menuProviders: { type: Object },
      menuShortcuts: { type: Array },
      sideMenuOpen: { type: Boolean },
      signedIn: { type: Boolean },
    };
  }

  constructor() {
    super();
    this.book = {};
    this.pageContainerSelector = '.BRcontainer';
    this.brWidth = 0;
    this.bookReaderCannotLoad = false;
    this.bookReaderLoaded = false;
    this.bookreader = null;
    this.downloadableTypes = [];
    this.isAdmin = false;
    this.lendingInitialized = false;
    this.lendingStatus = {};
    this.menuProviders = {};
    this.menuShortcuts = [];
    this.sideMenuOpen = false;
    this.signedIn = false;

    // Untracked properties
    this.fullscreenMgr = null;
    this.brResizeObserver = null;
    this.model = new Book();
    this.shortcutOrder = ['volumes', 'search', 'bookmarks'];
  }

  firstUpdated() {
    this.model.setMetadata(this.book);
    this.bindEventListeners();
    this.emitPostInit();
  }

  updated(changed) {
    if (!this.bookreader) {
      return;
    }
    const isFirstSideMenuUpdate = changed.has('sideMenuOpen') && (changed.get('sideMenuOpen') === undefined);
    if (!isFirstSideMenuUpdate) {
      // realign image
      if (this.bookreader.animating) {
        return;
      }
      this.bookreader.resize();
    }
  }

  /**
   * Global event emitter for when Book Navigator loads
   */
  emitPostInit() {
    // emit global event when book nav has loaded with current bookreader selector
    this.dispatchEvent(new CustomEvent(`BrBookNav:${events.PostInit}`, {
      detail: { brSelector: this.bookreader?.el },
      bubbles: true,
      composed: true,
    }));
  }

  /**
   * Instantiates books submenus & their update callbacks
   *
   * NOTE: we are doing our best to scope bookreader's instance.
   * If your submenu provider uses a bookreader instance to read, manually
   * manipulate BookReader, please update the navigator's instance of it
   * to keep it in sync.
   */
  initializeBookSubmenus() {
    const isBookProtected = this.bookreader.options.protected;
    this.menuProviders = {
      search: new SearchProvider(
        /**
         * Search specific menu updates
         * @param {BookReader} brInstance
         * @param {{ searchCanceled: boolean }} searchUpdates
         */
        (brInstance = null, searchUpdates = {}) => {
          if (brInstance) {
            /* refresh br instance reference */
            this.bookreader = brInstance;
          }
          this.updateMenuContents();
          const wideEnoughToOpenMenu = this.brWidth >= 640;
          if (wideEnoughToOpenMenu && !searchUpdates?.searchCanceled) {
            /* open side search menu */
            this.updateSideMenu('search', 'open');
          }
        },
        this.bookreader,
      ),
      downloads: new DownloadProvider(isBookProtected),
      visualAdjustments: new VisualAdjustmentProvider({
        onOptionChange: (event, brInstance = null) => {
          if (brInstance) {
            /* refresh br instance reference */
            this.bookreader = brInstance;
          }
          this.updateMenuContents();
        },
        bookContainerSelector: this.pageContainerSelector,
        bookreader: this.bookreader,
      }),
      share: new SharingProvider(this.book.metadata, this.baseHost, this.itemType, this.bookreader.options.subPrefix),
      bookmarks: new BookmarksProvider(this.bookmarksOptions, this.bookreader),
    };

    // add shortcut for volumes if multipleBooksList exists
    if (this.bookreader.options.enableMultipleBooks) {
      this.menuProviders.volumes = new VolumesProvider(this.baseHost, this.bookreader, (brInstance) => {
        if (brInstance) {
          /* refresh br instance reference */
          this.bookreader = brInstance;
        }
        this.updateMenuContents();
        this.updateSideMenu('volumes', 'open');
      });
      this.addMenuShortcut('volumes');
    }

    this.addMenuShortcut('search'); /* start with search as a shortcut */
    this.updateMenuContents();
  }

  /** gets element that houses the bookreader in light dom */
  get mainBRContainer() {
    return document.querySelector(this.bookreader.el);
  }

  get bookmarksOptions() {
    const referrerStr = `referer=${encodeURIComponent(location.href)}`;
    return {
      loginUrl: `https://${this.baseHost}/account/login?${referrerStr}`,
      displayMode: this.signedIn ? 'bookmarks' : 'login',
      showItemNavigatorModal: this.showItemNavigatorModal.bind(this),
      closeItemNavigatorModal: this.closeItemNavigatorModal.bind(this),
      onBookmarksChanged: (bookmarks) => {
        const method = Object.keys(bookmarks).length ? 'add' : 'remove';
        this[`${method}MenuShortcut`]('bookmarks');
        this.updateMenuContents();
      },
    };
  }

  /**
   * Open side menu
   * @param {string} menuId
   * @param {('open'|'close'|'toggle')} action
   */
  updateSideMenu(menuId = '', action = 'open') {
    if (!menuId || !action) {
      return;
    }
    const event = new CustomEvent(
      events.updateSideMenu, {
        detail: { menuId, action },
      },
    );
    this.dispatchEvent(event);
  }

  /**
   * Sets order of menu and emits custom event when done
   */
  updateMenuContents() {
    const {
      search, downloads, visualAdjustments, share, bookmarks, volumes
    } = this.menuProviders;
    const availableMenus = [volumes, search, bookmarks, visualAdjustments, share].filter((menu) => !!menu);

    if (this.shouldShowDownloadsMenu()) {
      downloads.update(this.downloadableTypes);
      availableMenus.splice(1, 0, downloads);
    }

    const event = new CustomEvent(
      events.menuUpdated, {
        detail: availableMenus,
      },
    );
    this.dispatchEvent(event);
  }

  /**
   * Confirms if we should show the downloads menu
   * @returns {bool}
   */
  shouldShowDownloadsMenu() {
    if (this.model.isRestricted === false) { return true; }
    if (this.isAdmin) { return true; }
    const { user_loan_record = {} } = this.lendingStatus;
    const hasNoLoanRecord = Array.isArray(user_loan_record); /* (bc PHP assoc. arrays) */

    if (hasNoLoanRecord) { return false; }

    const hasValidLoan = user_loan_record.type && (user_loan_record.type !== 'SESSION_LOAN');
    return hasValidLoan;
  }

  /**
   * Adds a provider object to the menuShortcuts array property if it isn't
   * already added. menuShortcuts are then sorted by shortcutOrder and
   * a menuShortcutsUpdated event is emitted.
   *
   * @param {string} menuId - a string matching the id property of a provider
   */
  addMenuShortcut(menuId) {
    if (this.menuShortcuts.find((m) => m.id === menuId)) { return; }

    this.menuShortcuts.push(this.menuProviders[menuId]);
    this.sortMenuShortcuts();
    this.emitMenuShortcutsUpdated();
  }

  /**
   * Removes a provider object from the menuShortcuts array and emits a
   * menuShortcutsUpdated event.
   *
   * @param {string} menuId - a string matching the id property of a provider
   */
  removeMenuShortcut(menuId) {
    this.menuShortcuts = this.menuShortcuts.filter((m) => m.id !== menuId);
    this.emitMenuShortcutsUpdated();
  }

  /**
   * Sorts the menuShortcuts property by comparing each provider's id to
   * the id in each iteration over the shortcutOrder array.
   */
  sortMenuShortcuts() {
    this.menuShortcuts = this.shortcutOrder.reduce((shortcuts, id) => {
      const menu = this.menuShortcuts.find((m) => m.id === id);
      if (menu) { shortcuts.push(menu); }
      return shortcuts;
    }, []);
  }

  emitMenuShortcutsUpdated() {
    const event = new CustomEvent('menuShortcutsUpdated', {
      detail: this.menuShortcuts,
    });
    this.dispatchEvent(event);
  }

  /**
   * Core bookreader event handler registry
   *
   * NOTE: we are trying to keep bookreader's instance in scope
   * Please update Book Navigator's instance reference of it to keep it current
   */
  bindEventListeners() {
    window.addEventListener('BookReader:PostInit', (e) => {
      this.bookreader = e.detail.props;
      this.bookReaderLoaded = true;
      this.bookReaderCannotLoad = false;
      this.fullscreenMgr = new BRFullscreenMgr(this.bookreader.el);

      this.initializeBookSubmenus();
      setTimeout(() => this.bookreader.resize(), 0);
      this.brResizeObserver = new ResizeObserver((elements) => this.reactToBrResize(elements));
      this.brResizeObserver.observe(this.mainBRContainer);
    });
    window.addEventListener('BookReader:fullscreenToggled', (event) => {
      const { detail: { props: brInstance = null } } = event;
      if (brInstance) {
        this.bookreader = brInstance;
      }
      this.manageFullScreenBehavior(event);
    }, { passive: true });
    window.addEventListener('BookReader:ToggleSearchMenu', (event) => {
      this.dispatchEvent(new CustomEvent(events.updateSideMenu, {
        detail: { menuId: 'search', action: 'toggle' },
      }));
    });
    window.addEventListener('LendingFlow:PostInit', ({ detail }) => {
      const {
        downloadTypesAvailable, lendingStatus, isAdmin, previewType,
      } = detail;
      this.lendingInitialized = true;
      this.downloadableTypes = downloadTypesAvailable;
      this.lendingStatus = lendingStatus;
      this.isAdmin = isAdmin;
      this.bookReaderCannotLoad = previewType === 'singlePagePreview';
    });
    window.addEventListener('BRJSIA:PostInit', ({ detail }) => {
      const { isRestricted, downloadURLs } = detail;
      this.bookReaderLoaded = true;
      this.downloadableTypes = downloadURLs;
      this.model.setRestriction(isRestricted);
    });
  }

  /**
   * Uses resize observer to fire BookReader's `resize` functionality
   * We do not want to trigger resize IF:
   *  - book animation is happening
   *  - book is in fullscreen (fullscreen is handled separately)
   *
   * @param { Object } entries - resize observer entries
   */
  reactToBrResize(entries = []) {
    const startBrWidth = this.brWidth;
    const { animating } = this.bookreader;

    entries.forEach(({ contentRect, target }) => {
      if (target === this.mainBRContainer) {
        this.brWidth = contentRect.width;
      }
    });
    setTimeout(() => {
      if (startBrWidth && !animating) {
        this.bookreader.resize();
      }
    }, 0);
  }

  /**
   * Manages Fullscreen behavior
   * This makes sure that controls are _always_ in view
   * We need this to accommodate LOAN BAR during fullscreen
   */
  manageFullScreenBehavior() {
    this.emitFullScreenState();

    if (!this.bookreader.isFullscreen()) {
      this.fullscreenMgr.teardown();
    } else {
      this.fullscreenMgr.setup(this.bookreader);
    }
  }

  /**
   * Intercepts and relays fullscreen toggle events
   */
  emitFullScreenState() {
    const isFullScreen = this.bookreader.isFullscreen();
    const event = new CustomEvent('ViewportInFullScreen', {
      detail: { isFullScreen },
    });
    this.dispatchEvent(event);
  }

  emitShowItemNavigatorModal(e) {
    this.dispatchEvent(new CustomEvent('showItemNavigatorModal', {
      detail: e.detail,
    }));
  }

  emitCloseItemNavigatorModal() {
    this.dispatchEvent(new CustomEvent('closeItemNavigatorModal'));
  }

  showItemNavigatorModal(e) {
    this.emitShowItemNavigatorModal(e);
  }

  closeItemNavigatorModal() {
    this.emitCloseItemNavigatorModal();
  }

  get loader() {
    const loader = html`

${bookLoader}

Loading viewer

    `;
    return !this.bookReaderLoaded ? loader : nothing;
  }

  get loadingClass() {
    return !this.bookReaderLoaded ? 'loading' : '';
  }

  get itemImage() {
    const url = `https://${this.baseHost}/services/img/${this.book.metadata.identifier}`;
    return html`<img class="cover-img" src="${url}" alt="cover image for ${this.book.metadata.identifier}">`;
  }

  render() {
    const placeholder = this.bookReaderCannotLoad ? this.itemImage : this.loader;
    return html`

      ${placeholder}
      <slot name="bookreader"></slot>

  `;
  }

  static get styles() {
    return css`
    #book-navigator.loading {
      display: flex;
      align-items: center;
      justify-content: center;
      min-height: 30vh;
    }

    #book-navigator .book-loader {
      width: 30%;
      margin: auto;
      text-align: center;
      color: var(--primaryTextColor);
    }

    .book-loader {
      position: relative;
    }

    .book-loader svg {
      display: block;
      width: 60%;
      max-width: 100px;
      height: auto;
      margin: auto;
    }

    svg * {
      fill: var(--primaryTextColor);
    }

    svg .ring {
      animation: rotate 1.3s infinite linear;
      transform-origin: 50px 50px;
      transform-box: fill-box;
      display: block; // transform won't work on inline style
    }

    @keyframes rotate {
      0% {
        transform: rotate(-360deg);
      }
    }

    .cover-img {
      max-height: 300px;
    }
  `;
  }
}

customElements.define('book-navigator', BookNavigator);
<|endoftext|>


<commit_before>
/*****************************************************************************/
/* TravelRequisitionDetail: Event Handlers */
/*****************************************************************************/
import _ from 'underscore';

/*
* invokeReason
* {
*   requisitionId: String,
*   reason: 'edit' | 'approve'
*   approverId: optional
* }
* */

Template.TravelRequisitionDetail.events({
    'click #requisition-save-draft': function(e, tmpl) {
        e.preventDefault()
        let procurementDetails = Template.instance().procurementDetails.get()
        if(procurementDetails) {
            let description = $("input[name=description]").val()
            let dateRequired = $("input[name=dateRequired]").val()
            let requisitionReason = $("textarea[name=requisitionReason]").val()

            if(description && description.length > 0) {
                let requisitionDoc = {}
                requisitionDoc.description = description
                if(dateRequired && dateRequired.length > 0)
                    requisitionDoc.dateRequired = new Date(dateRequired)
                else
                    requisitionDoc.dateRequired = null
                requisitionDoc.requisitionReason = requisitionReason

                let businessUnitId = Session.get('context')

                Meteor.call('ProcurementRequisition/createDraft', businessUnitId, requisitionDoc, procurementDetails._id, function(err, res) {
                    if(!err) {
                        swal({title: "Success", text: "Requisition Draft saved", type: "success",
                            confirmButtonColor: "#DD6B55", confirmButtonText: "OK!", closeOnConfirm: true
                        }, () => {
                            Modal.hide()
                        })
                    } else {
                        swal('Validation error', err.message, 'error')
                    }
                })
            } else {
                swal('Validation error', "Please fill a description", 'error')
            }
        }
    },
    'click #requisition-create': function(e, tmpl) {
        e.preventDefault()

        let procurementDetails = Template.instance().procurementDetails.get()
        if(procurementDetails) {
            let description = $("input[name=description]").val()
            let dateRequired = $("input[name=dateRequired]").val()
            let requisitionReason = $("textarea[name=requisitionReason]").val()

            let validation = tmpl.areInputsValid(description, dateRequired, requisitionReason)
            if(validation === true) {
                let requisitionDoc = {}

                requisitionDoc.description = description
                requisitionDoc.dateRequired = new Date(dateRequired)
                requisitionDoc.requisitionReason = requisitionReason

                let businessUnitId = Session.get('context')

                Meteor.call('ProcurementRequisition/create', businessUnitId, requisitionDoc, procurementDetails._id, function(err, res) {
                    if(!err) {
                        swal({title: "Success", text: "Requisition is now pending treatment", type: "success",
                            confirmButtonColor: "#DD6B55", confirmButtonText: "OK!", closeOnConfirm: true
                        }, () => {
                            Modal.hide()
                        })
                    } else {
                        // console.log(`Err: ${JSON.stringify(err)}`)
                        swal('Validation error', err.message, 'error')
                    }
                })
            } else {
                swal('Validation error', validation, 'error')
            }
        }
    },
    'click #requisition-approve': function(e, tmpl) {
        e.preventDefault()
        let procurementDetails = Template.instance().procurementDetails.get()
        if(procurementDetails) {
            let businessUnitId = Session.get('context')

            Meteor.call('ProcurementRequisition/approve', businessUnitId, procurementDetails._id, function(err, res) {
                if(!err) {
                    swal({title: "Success", text: "Requisition treated", type: "success",
                        confirmButtonColor: "#DD6B55", confirmButtonText: "OK!", closeOnConfirm: true
                    }, () => {
                        Modal.hide()
                    })
                } else {
                    swal('Validation error', err.message, 'error')
                }
            })
        }
    },
    'click #requisition-reject': function(e, tmpl) {
        e.preventDefault()
        let procurementDetails = Template.instance().procurementDetails.get()
        if(procurementDetails) {
            let businessUnitId = Session.get('context')

            Meteor.call('ProcurementRequisition/reject', businessUnitId, procurementDetails._id, function(err, res) {
                if(!err) {
                    swal({title: "Success", text: "Requisition rejected", type: "success",
                        confirmButtonColor: "#DD6B55", confirmButtonText: "OK!", closeOnConfirm: true
                    }, () => {
                        Modal.hide()
                    })
                } else {
                    swal('Validation error', err.message, 'error')
                }
            })
        }
    }
});

Template.registerHelper('formatDate', function(date) {
    return moment(date).format('DD-MM-YYYY');
});

/*****************************************************************************/
/* TravelRequisitionDetail: Helpers */
/*****************************************************************************/
Template.TravelRequisitionDetail.helpers({
    'procurementDetails': function() {
        return Template.instance().procurementDetails.get()
    },
    'isInEditMode': function() {
        return Template.instance().isInEditMode.get()
    },
    'isInApproveMode': function() {
        return Template.instance().isInApproveMode.get()
    },
    'getUnitName': function(unitId) {
        if(unitId)
            return EntityObjects.findOne({_id: unitId}).name
    }
});

/*****************************************************************************/
/* TravelRequisitionDetail: Lifecycle Hooks */
/*****************************************************************************/
Template.TravelRequisitionDetail.onCreated(function () {
    let self = this;
    let businessUnitId = Session.get('context');

    self.procurementDetails = new ReactiveVar()
    self.isInEditMode = new ReactiveVar()
    self.isInViewMode = new ReactiveVar()
    self.isInApproveMode = new ReactiveVar()

    let invokeReason = self.data;
    console.log(`invokeReason: ${JSON.stringify(invokeReason)}`)
    if(invokeReason.reason === 'edit') {
        self.isInEditMode.set(true)
    }
    if(invokeReason.reason === 'approve') {
        self.isInApproveMode.set(true)
    }

    self.autorun(function() {
        let procurementSub = self.subscribe('ProcurementRequisition', invokeReason.requisitionId)
        if(procurementSub.ready()) {
            console.log(`procurement subscription ready `)
            let procurementDetails = ProcurementRequisitions.findOne({_id: invokeReason.requisitionId})
            self.procurementDetails.set(procurementDetails)

            if(procurementDetails.unitId) {
                self.subscribe('getEntity', procurementDetails.unitId)
            }
        }
    })

    self.areInputsValid = function(description, dateRequired, requisitionReason) {
        let errMsg = null
        if(!description || description.length < 1) {
            errMsg = "Please fill description"
            return errMsg
        }
        if(!dateRequired || dateRequired.length < 1) {
            errMsg = "Please fill date required"
            return errMsg
        }
        if(!requisitionReason || requisitionReason.length < 1) {
            errMsg = "Please fill requisition reason"
            return errMsg
        }
        return true
    }
});

Template.TravelRequisitionDetail.onRendered(function () {
    $('select.dropdown').dropdown();
    let self = this

    let procurementDetails = self.procurementDetails.get()
    if(procurementDetails) {
        if(procurementDetails.status !== 'Draft') {
            if(self.isInEditMode()) {
                swal('Error', "Sorry, you can't edit this procurement requisition. ", 'error')
            }
        } else if(procurementDetails.status === 'Pending') {
            self.isInViewMode.set(true)
        } else if(procurementDetails.status === 'Approve') {
            if(self.isInEditMode()) {
                swal('Error', "Sorry, you can't edit this procurement requisition. It has been approved", 'error')
            }
        }
    }
});

Template.TravelRequisitionDetail.onDestroyed(function () {
});
<commit_msg>Can view details of previously created travel request<commit_after>
/*****************************************************************************/
/* TravelRequisitionDetail: Event Handlers */
/*****************************************************************************/
import _ from 'underscore';

/*
* invokeReason
* {
*   requisitionId: String,
*   reason: 'edit' | 'approve'
*   approverId: optional
* }
* */

Template.TravelRequisitionDetail.events({
    'click #requisition-save-draft': function(e, tmpl) {
        e.preventDefault()
        let procurementDetails = Template.instance().procurementDetails.get()
        if(procurementDetails) {
            let description = $("input[name=description]").val()
            let dateRequired = $("input[name=dateRequired]").val()
            let requisitionReason = $("textarea[name=requisitionReason]").val()

            if(description && description.length > 0) {
                let requisitionDoc = {}
                requisitionDoc.description = description
                if(dateRequired && dateRequired.length > 0)
                    requisitionDoc.dateRequired = new Date(dateRequired)
                else
                    requisitionDoc.dateRequired = null
                requisitionDoc.requisitionReason = requisitionReason

                let businessUnitId = Session.get('context')

                Meteor.call('TravelRequest/createDraft', businessUnitId, requisitionDoc, procurementDetails._id, function(err, res) {
                    if(!err) {
                        swal({title: "Success", text: "Requisition Draft saved", type: "success",
                            confirmButtonColor: "#DD6B55", confirmButtonText: "OK!", closeOnConfirm: true
                        }, () => {
                            Modal.hide()
                        })
                    } else {
                        swal('Validation error', err.message, 'error')
                    }
                })
            } else {
                swal('Validation error', "Please fill a description", 'error')
            }
        }
    },
    'click #requisition-create': function(e, tmpl) {
        e.preventDefault()

        let procurementDetails = Template.instance().procurementDetails.get()
        if(procurementDetails) {
            let description = $("input[name=description]").val()
            let dateRequired = $("input[name=dateRequired]").val()
            let requisitionReason = $("textarea[name=requisitionReason]").val()

            let validation = tmpl.areInputsValid(description, dateRequired, requisitionReason)
            if(validation === true) {
                let requisitionDoc = {}

                requisitionDoc.description = description
                requisitionDoc.dateRequired = new Date(dateRequired)
                requisitionDoc.requisitionReason = requisitionReason

                let businessUnitId = Session.get('context')

                Meteor.call('TravelRequest/create', businessUnitId, requisitionDoc, procurementDetails._id, function(err, res) {
                    if(!err) {
                        swal({title: "Success", text: "Requisition is now pending treatment", type: "success",
                            confirmButtonColor: "#DD6B55", confirmButtonText: "OK!", closeOnConfirm: true
                        }, () => {
                            Modal.hide()
                        })
                    } else {
                        // console.log(`Err: ${JSON.stringify(err)}`)
                        swal('Validation error', err.message, 'error')
                    }
                })
            } else {
                swal('Validation error', validation, 'error')
            }
        }
    },
    'click #requisition-approve': function(e, tmpl) {
        e.preventDefault()
        let procurementDetails = Template.instance().procurementDetails.get()
        if(procurementDetails) {
            let businessUnitId = Session.get('context')

            Meteor.call('TravelRequest/approve', businessUnitId, procurementDetails._id, function(err, res) {
                if(!err) {
                    swal({title: "Success", text: "Requisition treated", type: "success",
                        confirmButtonColor: "#DD6B55", confirmButtonText: "OK!", closeOnConfirm: true
                    }, () => {
                        Modal.hide()
                    })
                } else {
                    swal('Validation error', err.message, 'error')
                }
            })
        }
    },
    'click #requisition-reject': function(e, tmpl) {
        e.preventDefault()
        let procurementDetails = Template.instance().procurementDetails.get()
        if(procurementDetails) {
            let businessUnitId = Session.get('context')

            Meteor.call('TravelRequest/reject', businessUnitId, procurementDetails._id, function(err, res) {
                if(!err) {
                    swal({title: "Success", text: "Requisition rejected", type: "success",
                        confirmButtonColor: "#DD6B55", confirmButtonText: "OK!", closeOnConfirm: true
                    }, () => {
                        Modal.hide()
                    })
                } else {
                    swal('Validation error', err.message, 'error')
                }
            })
        }
    }
});

Template.registerHelper('formatDate', function(date) {
    return moment(date).format('DD-MM-YYYY');
});

/*****************************************************************************/
/* TravelRequisitionDetail: Helpers */
/*****************************************************************************/
Template.TravelRequisitionDetail.helpers({
    'procurementDetails': function() {
        return Template.instance().procurementDetails.get()
    },
    'isInEditMode': function() {
        return Template.instance().isInEditMode.get()
    },
    'isInApproveMode': function() {
        return Template.instance().isInApproveMode.get()
    },
    'getUnitName': function(unitId) {
        if(unitId)
            return EntityObjects.findOne({_id: unitId}).name
    }
});

/*****************************************************************************/
/* TravelRequisitionDetail: Lifecycle Hooks */
/*****************************************************************************/
Template.TravelRequisitionDetail.onCreated(function () {
    let self = this;
    let businessUnitId = Session.get('context');

    self.procurementDetails = new ReactiveVar()
    self.isInEditMode = new ReactiveVar()
    self.isInViewMode = new ReactiveVar()
    self.isInApproveMode = new ReactiveVar()

    let invokeReason = self.data;
    console.log(`invokeReason: ${JSON.stringify(invokeReason)}`)
    if(invokeReason.reason === 'edit') {
        self.isInEditMode.set(true)
    }
    if(invokeReason.reason === 'approve') {
        self.isInApproveMode.set(true)
    }

    self.autorun(function() {
        let procurementSub = self.subscribe('TravelRequest', invokeReason.requisitionId)
        if(procurementSub.ready()) {
            console.log(`procurement subscription ready `)
            let procurementDetails = TravelRequisitions.findOne({_id: invokeReason.requisitionId})
            self.procurementDetails.set(procurementDetails)

            if(procurementDetails.unitId) {
                self.subscribe('getEntity', procurementDetails.unitId)
            }
        }
    })

    self.areInputsValid = function(description, dateRequired, requisitionReason) {
        let errMsg = null
        if(!description || description.length < 1) {
            errMsg = "Please fill description"
            return errMsg
        }
        if(!dateRequired || dateRequired.length < 1) {
            errMsg = "Please fill date required"
            return errMsg
        }
        if(!requisitionReason || requisitionReason.length < 1) {
            errMsg = "Please fill requisition reason"
            return errMsg
        }
        return true
    }
});

Template.TravelRequisitionDetail.onRendered(function () {
    $('select.dropdown').dropdown();
    let self = this

    let procurementDetails = self.procurementDetails.get()
    if(procurementDetails) {
        if(procurementDetails.status !== 'Draft') {
            if(self.isInEditMode()) {
                swal('Error', "Sorry, you can't edit this procurement requisition. ", 'error')
            }
        } else if(procurementDetails.status === 'Pending') {
            self.isInViewMode.set(true)
        } else if(procurementDetails.status === 'Approve') {
            if(self.isInEditMode()) {
                swal('Error', "Sorry, you can't edit this procurement requisition. It has been approved", 'error')
            }
        }
    }
});

Template.TravelRequisitionDetail.onDestroyed(function () {
});
<|endoftext|>


<commit_before><<<<<<< HEAD

// describe('requests made', function() {

//   afterEach(function() {
//     mock.teardown();
//   });

//   beforeEach(function() {
//     mock([{
//       request: {
//         path: '/api/medications',
//         method: 'GET'
//       },
//       response: {
//         data: [{
//           id: 12,
//           name: "Abilify (Aripiprazole)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 123,
//           name: "Actiq (Fentanyl Citrate)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 1234,
//           name: "Halcion (Triazolam)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 12345,
//           name: "Quinidex (Quinidine)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }]
//       }
//     }]);

//     get();
//   });

//   it('can evaluate requests made', function() {

//     expect(mock.requestsMade()).toEqual([{
//       url: '/api/medications',
//       method: 'GET'
//     }, ]);
//   });

// describe('requests made', function() {

//   afterEach(function() {
//     mock.teardown();
//   });

//   beforeEach(function() {
//     mock([{
//       request: {
//         path: '/api/medications',
//         method: 'GET'
//       },
//       response: {
//         data: [{
//           id: 12,
//           name: "Abilify (Aripiprazole)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 123,
//           name: "Actiq (Fentanyl Citrate)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 1234,
//           name: "Halcion (Triazolam)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 12345,
//           name: "Quinidex (Quinidine)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }]
//       }
//     }]);

//     get();
//   });

//   it('can evaluate requests made', function() {

//     expect(mock.requestsMade()).toEqual([{
//       url: '/api/medications',
//       method: 'GET'
//     }, ]);
//   });

=======
// describe('requests made', function() {

//   afterEach(function() {
//     mock.teardown();
//   });

//   beforeEach(function() {
//     mock([{
//       request: {
//         path: '/api/medications',
//         method: 'GET'
//       },
//       response: {
//         data: [{
//           id: 12,
//           name: "Abilify (Aripiprazole)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 123,
//           name: "Actiq (Fentanyl Citrate)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 1234,
//           name: "Halcion (Triazolam)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 12345,
//           name: "Quinidex (Quinidine)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }]
//       }
//     }]);

//     get();
//   });

//   it('can evaluate requests made', function() {

//     expect(mock.requestsMade()).toEqual([{
//       url: '/api/medications',
//       method: 'GET'
//     }, ]);
//   });

>>>>>>> (refactor) testing
//   it('can clear requests', function() {
//     mock.clearRequests();
//     expect(mock.requestsMade()).toEqual([]);
//   });
// });
<<<<<<< HEAD

=======
>>>>>>> (refactor) testing
<commit_msg>(refactor) testing<commit_after>

// describe('requests made', function() {

//   afterEach(function() {
//     mock.teardown();
//   });

//   beforeEach(function() {
//     mock([{
//       request: {
//         path: '/api/medications',
//         method: 'GET'
//       },
//       response: {
//         data: [{
//           id: 12,
//           name: "Abilify (Aripiprazole)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 123,
//           name: "Actiq (Fentanyl Citrate)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 1234,
//           name: "Halcion (Triazolam)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 12345,
//           name: "Quinidex (Quinidine)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }]
//       }
//     }]);

//     get();
//   });

//   it('can evaluate requests made', function() {

//     expect(mock.requestsMade()).toEqual([{
//       url: '/api/medications',
//       method: 'GET'
//     }, ]);
//   });

// describe('requests made', function() {

//   afterEach(function() {
//     mock.teardown();
//   });

//   beforeEach(function() {
//     mock([{
//       request: {
//         path: '/api/medications',
//         method: 'GET'
//       },
//       response: {
//         data: [{
//           id: 12,
//           name: "Abilify (Aripiprazole)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 123,
//           name: "Actiq (Fentanyl Citrate)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 1234,
//           name: "Halcion (Triazolam)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 12345,
//           name: "Quinidex (Quinidine)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }]
//       }
//     }]);

//     get();
//   });

//   it('can evaluate requests made', function() {

//     expect(mock.requestsMade()).toEqual([{
//       url: '/api/medications',
//       method: 'GET'
//     }, ]);
//   });

// describe('requests made', function() {

//   afterEach(function() {
//     mock.teardown();
//   });

//   beforeEach(function() {
//     mock([{
//       request: {
//         path: '/api/medications',
//         method: 'GET'
//       },
//       response: {
//         data: [{
//           id: 12,
//           name: "Abilify (Aripiprazole)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 123,
//           name: "Actiq (Fentanyl Citrate)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 1234,
//           name: "Halcion (Triazolam)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }, {
//           id: 12345,
//           name: "Quinidex (Quinidine)",
//           dosage: "5mg",
//           instruction: "Take one tablet by mouth every morning",
//           reminder: "10:30AM Every Day",
//           image: "http://pillbox.nlm.nih.gov/assets/small/540920173.jpg"
//         }]
//       }
//     }]);

//     get();
//   });

//   it('can evaluate requests made', function() {

//     expect(mock.requestsMade()).toEqual([{
//       url: '/api/medications',
//       method: 'GET'
//     }, ]);
//   });

//   it('can clear requests', function() {
//     mock.clearRequests();
//     expect(mock.requestsMade()).toEqual([]);
//   });
// });

<|endoftext|>


<commit_before>const $ = window.jQuery

const createLink = require('../helpers').createLink

module.exports.process = function process () {
  if (location.pathname.split('/').slice(-1)[0].match(/stack[\d.-]*\.yaml/)) {
    stackyaml()
  }
}

function stackyaml () {
  var depsOpen = false

  $('.blob-code-inner').each((_, elem) => {
    elem = $(elem)
    let line = elem.text().trim()

    if (line.match('packages:') || line.match('extra-deps:')) {
      depsOpen = true
      return
    }

    if (depsOpen && line.match(/^- *[\w-]+[\d.]*$/)) {
      let link = elem.find('.pl-s').eq(0)
      let moduleName = link.text().trim()

      let url = `https://hackage.haskell.org/package/${moduleName}`
      createLink(elem.get(0), moduleName, url)
    }

    if (!line.match(/^- /)) {
      depsOpen = false
    }
  })
}
<commit_msg>pubspec.yaml<commit_after>const $ = window.jQuery

const darturl = require('./dart').darturl

const createLink = require('../helpers').createLink

module.exports.process = function process () {
  if (window.pathdata.last.match(/stack[\d.-]*\.yaml/)) {
    stackyaml()
  } else {
    switch (window.pathdata.last) {
      case 'pubspec.yaml':
        pubspecyaml()
        break
    }
  }
}

function stackyaml () {
  // haskell
  var depsOpen = false

  $('.blob-code-inner').each((_, elem) => {
    elem = $(elem)
    let line = elem.text().trim()

    if (line.match('packages:') || line.match('extra-deps:')) {
      depsOpen = true
      return
    }

    if (depsOpen && line.match(/^- *[\w-]+[\d.]*$/)) {
      let link = elem.find('.pl-s').eq(0)
      let moduleName = link.text().trim()

      let url = `https://hackage.haskell.org/package/${moduleName}`
      createLink(elem.get(0), moduleName, url)
    }

    if (!line.match(/^- /)) {
      depsOpen = false
    }
  })
}

function pubspecyaml () {
  // dart
  var depsOpen = false

  $('.blob-code-inner').each((_, elem) => {
    elem = $(elem)
    let rawline = elem.text()

    if (rawline.match(/^dependencies:/) || rawline.match(/^dev_dependencies:/)) {
      depsOpen = true
      return
    }

    if (depsOpen && rawline.match(/^ +[\w_]*:/)) {
      let link = elem.find('.pl-ent').eq(0)
      let moduleName = link.text().trim()

      darturl(moduleName)
        .catch(() => url => `pub.dartlang.org/api/packages/${moduleName}`)
        .then(url => createLink(link.get(0), moduleName, url))
    }

    if (!rawline.match(/^ /)) {
      depsOpen = false
    }
  })
}
<|endoftext|>


<commit_before>(function(cms){

///// Content Handler Function definition //////////////////////////

   /**
    * Displays the content of the preview item.
    *
    * @param {Object} itemData server response as JSON object with preview data
    */
   var showItemPreview = function(itemData) {
       //display the html preview
       $('.preview-area').append(itemData['previewdata']['itemhtml']);

       // display editable properties
       showEditArea(itemData['previewdata']['properties']);

       //bind click event to preview close button
       $('#cms-preview div.close-icon').click(function() {
          if ($(this).hasClass('cms-properties-changed')) {
              cms.galleries.loadSearchResults();
              $(this).removeClass('cms-properties-changed');
          }
          $(this).parent().fadeOut('slow');

       });

       $('.button-bar button').live('mouseover', function() {
             $(this).toggleClass('ui-state-hover', true);
          }).live('mouseout', function() {
             $(this).toggleClass('ui-state-hover', false);
      });

       // fade in the preview
       $('#cms-preview').fadeIn('slow');
   }

   /**
    * Generates html for the editable properties and add to the dom.
    *
    * @param {Object} itemProperties server response as JSON object with the editable properties
    */
   var showEditArea = function(itemProperties) {
       var buttonBar = $('

')
                                       .append('<button id="previewSave" disabled="true" class="ui-state-default ui-corner-all">\
                                                    Save\
                                                </button>')
                                       .append('<button id="previewPublish" class="ui-state-default ui-corner-all">\
                                                    Publish\
                                                </button>');

       var target = $('.edit-area').append(buttonBar);
       $('#previewSave').click(saveChangedProperty);
       $('#publishSave').click(publishChangedProperty);

       if (cms.galleries.displaySelectButton()) {
           $('.edit-area').find('.button-bar').append('<button id="previewSelect" class="ui-state-default ui-corner-all">\
                                Select\
                          </button>');
           $('#previewSelect').click(function() {
               //TODO:
               var itemType = '';
               var itemId = $(this).closest('#cms-preview').attr('alt');
               cms.galleries.getContentHandler(itemType)['setValues'][cms.galleries.initValues['dialogMode']](itemId, cms.galleries.initValues['fieldId']);
           });
       }

       // generate editable form
       var form = $('

');
       $.each(itemProperties, function() {
              $('

').attr('alt', this.name).appendTo(form)
                   .append('' + this.name + '')
                   .append('' + (this.value ? this.value : '') + '');
           });
       $(target).append(form);

       // bind direct input to the editable fields
       $('.cms-item-edit').directInput({
                     marginHack: true,
                     live: false,
                     setValue: markChangedProperty,
                     onChange: function(element, input){
                         $('#previewSave').removeAttr('disabled');
                     }
               });
   }

   /**
    * Updates the value of the changed property in the preview and marks the element as changed.
    * This function overwrites 'setValue' method from the 'directInput' extension.
    *
    * @param {Object} elem the html element to be changed
    * @param {Object} input the input field used to change the content of the html element
    */
   var markChangedProperty = function(elem, input) {
      var previous = elem.text();
      var current = input.val();
      if (previous != current) {
            elem.text(current);
            elem.addClass('cms-item-changed');
      }
      elem.css('display', '');
      input.remove();
   }

   /**
    * Refresh the preview after changes.
    *
    * @param {Object} itemData the data to update the preview
    */
   var refreshItemPreview = function (itemData) {
       $('#cms-preview div.preview-area, #cms-preview div.edit-area').empty();
       //display the html preview
       $('.preview-area').append(itemData['previewdata']['itemhtml']);
       showEditArea(itemData['previewdata']['properties']);

   }

   /**
    * Callback function for click event on the 'save' button.
    */
   var saveChangedProperty = function() {
       var changedProperties = $('.cms-item-edit.cms-item-changed');

       // build json object with changed properties
       var changes = {
           'properties': []};
       $.each(changedProperties, function () {
           var property = {};
           property['name'] =  $(this).closest('div').attr('alt');
           property['value'] = $(this).text();
           changes['properties'].push(property);
       });

       // save changes via ajax if there are any
       if (changes['properties'].length != 0) {
          $.ajax({
             'url': vfsPathAjaxJsp,
             'data': {
                'action': 'setproperties',
                'data': JSON.stringify({
                   'path': $('#cms-preview').attr('alt'),
                   'properties': changes['properties']
                })
             },
             'type': 'POST',
             'dataType': 'json',
             'success': refreshItemPreview
          });
          $('#cms-preview div.close-icon').addClass('cms-properties-changed');
       }

   }

   /**
    * Callback function for click event on the 'publish' button.
    */
   var publishChangedProperty = cms.galleries.publishChangedProperty = function() {
       alert('Publish');
   }

   var selectPath = function(itemId, fieldId) {
       if ( fieldId != null && fieldId != "") {
		var imgField = window.opener.document.getElementById(fieldId);
		imgField.value = itemId;
		try {
			// toggle preview icon if possible
			window.opener.checkPreview(fieldid);
		} catch (e) {}
	}
	window.close();
       //alert($(item).closest('li').attr('alt') +", " + fieldId );
   }

///// Default Content Handler ////////////////
   /**
    * Default handler to display the preview for a resource.
    * It can be used for all possible resource types.
    */
   var defaultContentTypeHandler = cms.previewhandler.defaultContentTypeHandler = {
       'init': showItemPreview,
       'setValues': { 'widget': selectPath,
               'editor': 'test2'}
   };

})(cms);<commit_msg>- direct publish button is invisible for now<commit_after>(function(cms){

///// Content Handler Function definition //////////////////////////

   /**
    * Displays the content of the preview item.
    *
    * @param {Object} itemData server response as JSON object with preview data
    */
   var showItemPreview = function(itemData) {
       //display the html preview
       $('.preview-area').append(itemData['previewdata']['itemhtml']);

       // display editable properties
       showEditArea(itemData['previewdata']['properties']);

       //bind click event to preview close button
       $('#cms-preview div.close-icon').click(function() {
          if ($(this).hasClass('cms-properties-changed')) {
              cms.galleries.loadSearchResults();
              $(this).removeClass('cms-properties-changed');
          }
          $(this).parent().fadeOut('slow');

       });

       $('.button-bar button').live('mouseover', function() {
             $(this).toggleClass('ui-state-hover', true);
          }).live('mouseout', function() {
             $(this).toggleClass('ui-state-hover', false);
      });

       // fade in the preview
       $('#cms-preview').fadeIn('slow');
   }

   /**
    * Generates html for the editable properties and add to the dom.
    *
    * @param {Object} itemProperties server response as JSON object with the editable properties
    */
   var showEditArea = function(itemProperties) {
       var buttonBar = $('

');
       if (itemProperties.length > 0) {
             buttonBar.append('<button id="previewSave" disabled="true" class="ui-state-default ui-corner-all">\
                                     Save\
                               </button>');
                     /*.append('<button id="previewPublish" class="ui-state-default ui-corner-all">\
                                    Publish\
                                </button>');*/
       }

       var target = $('.edit-area').append(buttonBar);
       $('#previewSave').click(saveChangedProperty);
       // TODO: comment in for direct publish
       /* $('#publishSave').click(publishChangedProperty);*/

       if (cms.galleries.displaySelectButton()) {
           $('.edit-area').find('.button-bar').append('<button id="previewSelect" class="ui-state-default ui-corner-all">\
                                Select\
                          </button>');
           $('#previewSelect').click(function() {
               var itemType = '';
               var itemId = $(this).closest('#cms-preview').attr('alt');
               cms.galleries.getContentHandler(itemType)['setValues'][cms.galleries.initValues['dialogMode']](itemId, cms.galleries.initValues['fieldId']);
           });
       }

       // generate editable form
       var form = $('

');
       $.each(itemProperties, function() {
              $('

').attr('alt', this.name).appendTo(form)
                   .append('' + this.name + '')
                   .append('' + (this.value ? this.value : '') + '');
           });
       $(target).append(form);

       // bind direct input to the editable fields
       $('.cms-item-edit').directInput({
                     marginHack: true,
                     live: false,
                     setValue: markChangedProperty,
                     onChange: function(element, input){
                         $('#previewSave').removeAttr('disabled');
                     }
               });
   }

   /**
    * Updates the value of the changed property in the preview and marks the element as changed.
    * This function overwrites 'setValue' method from the 'directInput' extension.
    *
    * @param {Object} elem the html element to be changed
    * @param {Object} input the input field used to change the content of the html element
    */
   var markChangedProperty = function(elem, input) {
      var previous = elem.text();
      var current = input.val();
      if (previous != current) {
            elem.text(current);
            elem.addClass('cms-item-changed');
      }
      elem.css('display', '');
      input.remove();
   }

   /**
    * Refresh the preview after changes.
    *
    * @param {Object} itemData the data to update the preview
    */
   var refreshItemPreview = function (itemData) {
       $('#cms-preview div.preview-area, #cms-preview div.edit-area').empty();
       //display the html preview
       $('.preview-area').append(itemData['previewdata']['itemhtml']);
       showEditArea(itemData['previewdata']['properties']);

   }

   /**
    * Callback function for click event on the 'save' button.
    */
   var saveChangedProperty = function() {
       var changedProperties = $('.cms-item-edit.cms-item-changed');

       // build json object with changed properties
       var changes = {
           'properties': []};
       $.each(changedProperties, function () {
           var property = {};
           property['name'] =  $(this).closest('div').attr('alt');
           property['value'] = $(this).text();
           changes['properties'].push(property);
       });

       // save changes via ajax if there are any
       if (changes['properties'].length != 0) {
          $.ajax({
             'url': vfsPathAjaxJsp,
             'data': {
                'action': 'setproperties',
                'data': JSON.stringify({
                   'path': $('#cms-preview').attr('alt'),
                   'properties': changes['properties']
                })
             },
             'type': 'POST',
             'dataType': 'json',
             'success': refreshItemPreview
          });
          $('#cms-preview div.close-icon').addClass('cms-properties-changed');
       }

   }

   /**
    * Callback function for click event on the 'publish' button.
    */
   var publishChangedProperty = cms.galleries.publishChangedProperty = function() {
       alert('Publish');
   }

   var selectPath = function(itemId, fieldId) {
       if ( fieldId != null && fieldId != "") {
		var imgField = window.opener.document.getElementById(fieldId);
		imgField.value = itemId;
		try {
			// toggle preview icon if possible
			window.opener.checkPreview(fieldid);
		} catch (e) {}
	}
	window.close();
       //alert($(item).closest('li').attr('alt') +", " + fieldId );
   }

///// Default Content Handler ////////////////
   /**
    * Default handler to display the preview for a resource.
    * It can be used for all possible resource types.
    */
   var defaultContentTypeHandler = cms.previewhandler.defaultContentTypeHandler = {
       'init': showItemPreview,
       'setValues': { 'widget': selectPath,
               'editor': 'test2'}
   };

})(cms);<|endoftext|>


<commit_before>"use strict";

// namespace: delegarity
(function(delegarity, $, undefined) {

    //Polls until Clarity Workspace is loaded and then fires the callback
    delegarity.onClarityReady = function(callback, timesheetsUrl) {

        var workspace = document.getElementById("ppm_workspace");

        if(workspace) {
            if(document.location.href.toLowerCase().startsWith(timesheetsUrl)) {
                callback(workspace);
            }
        }
        else {
            window.setTimeout(function() {
                delegarity.onClarityReady(callback, timesheetsUrl);
            }, 500)
        }
    };

    // Creates HTML based on adding data to the provided HTML template
    delegarity.useTemplatebyId = function(templateId, data) {
        var template = document.getElementById(templateId).innerHTML;
        return delegarity.useTemplateByElement(template, data);
    }

    // Creates HTML based on adding data to the provided HTML template
    delegarity.useTemplateByElement = function(template, data) {

        if( template === null ||template === undefined)
            throw "Cannot find template " + templateId;

        // Replace the {{XXX}} with the corresponding property
        function replaceWithData(data_bit) {
            var html_snippet, prop, regex;
            for (prop in data_bit) {
                regex = new RegExp('{{' + prop + '}}', 'ig');
                html_snippet = (html_snippet || template).replace(regex, data_bit[prop]);
            }
            return html_snippet;
        }

        var html = '';

        if( Array.isArray(data) ) {
            // Go through each element in the array and add the properties to the template
            for (var i = 0; i < data.length; i++) {
                html += replaceWithData(data[i]);
            }
        } else {
            html = replaceWithData(data);
        }
        return html;
    }

    delegarity.logXhrError = function (jqXHR, exception) {
        var msg = '';

        if (jqXHR.status === 0) {
            msg = 'Not connect.\n Verify Network.';
        } else if (jqXHR.status == 404) {
            msg = 'Requested page not found. [404]';
        } else if (jqXHR.status == 500) {
            msg = 'Internal Server Error [500].';
        } else if (exception === 'parsererror') {
            msg = 'Requested JSON parse failed.';
        } else if (exception === 'timeout') {
            msg = 'Time out error.';
        } else if (exception === 'abort') {
            msg = 'Ajax request aborted.';
        } else {
            msg = 'Uncaught Error.\n' + jqXHR.responseText;
        }

        console.log("[delegarity] jQuery XHR Exception. Status: " + jqXHR.status + ". Exception: " + exception + ". Information: " + msg);
    }

})(window.delegarity = window.delegarity || {}, jQuery)<commit_msg>Remove custom template engine<commit_after>"use strict";

// namespace: delegarity
(function(delegarity, $, undefined) {

    //Polls until Clarity Workspace is loaded and then fires the callback
    delegarity.onClarityReady = function(callback, timesheetsUrl) {

        var workspace = document.getElementById("ppm_workspace");

        if(workspace) {
            if(document.location.href.toLowerCase().startsWith(timesheetsUrl)) {
                callback(workspace);
            }
        }
        else {
            window.setTimeout(function() {
                delegarity.onClarityReady(callback, timesheetsUrl);
            }, 500)
        }
    };

    delegarity.logXhrError = function (jqXHR, exception) {
        var msg = '';

        if (jqXHR.status === 0) {
            msg = 'Not connect.\n Verify Network.';
        } else if (jqXHR.status == 404) {
            msg = 'Requested page not found. [404]';
        } else if (jqXHR.status == 500) {
            msg = 'Internal Server Error [500].';
        } else if (exception === 'parsererror') {
            msg = 'Requested JSON parse failed.';
        } else if (exception === 'timeout') {
            msg = 'Time out error.';
        } else if (exception === 'abort') {
            msg = 'Ajax request aborted.';
        } else {
            msg = 'Uncaught Error.\n' + jqXHR.responseText;
        }

        console.log("[delegarity] jQuery XHR Exception. Status: " + jqXHR.status + ". Exception: " + exception + ". Information: " + msg);
    }

})(window.delegarity = window.delegarity || {}, jQuery)<|endoftext|>


<commit_before>var signinCallback = function (json) {
    json = json || {};

    Backbone.GoogleAPIs.set("access_token", json["access_token"]);
    Backbone.GoogleAPIs.set("signed_in_user", json);

    _.defer(function() {
        $(".signed-out").hide();
        $(".signed-in").hide();

        var m = new Backbone.GoogleAPIs.UserInfo({});
        m.on("change", function() {
            var email = m.get("email");
            if (_.isEmpty(email)) {
                $(".signed-out").show().removeClass("hide");
                return;
            }

            $(".signed-in").show().removeClass("hide");
            $(".signed-in-email").html(email);

            var picture = m.get("picture");
            if (!_.isEmpty(picture)) $(".signed-in-picture").attr("src", picture);
        });
        m.on("error", function () {
            $(".signed-out").show().removeClass("hide");
        });
        m.fetch();
    });

    try {
        Backbone.history.start();
    } catch (e) {
        console.warn(e);
    }
};

_.defer(function () {
    var App = Backbone.Router.extend({
        "__route": function (name, target_fn) {
            var wrapping_fn = function () {
                if (_.isFunction(target_fn)) _.defer(target_fn);
                if (!_.isUndefined(ChangeList) && _.isFunction(ChangeList.unpoll)) ChangeList.unpoll();

                $(".json-container").empty();
                $(".error-container").empty();

                // pretty printing target_fn
                var strFn = "" + target_fn;
                var clnFn = _.map(strFn.split("\n"), function(line) {
                    return line.replace("        ", "");
                });
                $(".code-container").html(clnFn.join("\n"));

                var auxparts = [];
                if (strFn.indexOf("displayJson") >= 0) auxparts.push("var displayJson = " + displayJson + ";");
                if (strFn.indexOf("displayError") >= 0) auxparts.push("var displayError = " + displayError + ";");
                $(".aux-code-container").html(auxparts.join("\n\n"));
            };

            this.route(name, name, wrapping_fn);
        }
    });

    app = new App();

    // resets buckets inputs
    app.on("route", function (href) {
        if (_.isEqual(href, "list-buckets")) {
            $(".list-buckets-inputs").show().removeClass("hide");
        } else {
            $(".list-buckets-inputs").hide();
        }
        $(".buckets-needs-project-id").hide();
    });
    // resets comments inputs
    app.on("route", function (href) {
        if (_.isEqual(href, "plus-list-comments")) {
            $(".list-comments-inputs").show().removeClass("hide");
        } else {
            $(".list-comments-inputs").hide();
        }
        $(".list-comments-needs-activity-id").hide();
    });
    // toggles active list item
    app.on("route", function (href) {
        _.each($(".top-level-anchors").find("a.list-group-item"), function (item) {
            $(item).removeClass("active");
            if (_.isEqual($(item).attr("href"), "#" + href)) $(item).addClass("active");
        });
    });

    // configures buttons for controlling model instantiation strategy
    var readyRoutes = function(e) {
        var modelTypeSelector = localStorage.getItem("modeltype-selector") || "model-factory";

        $(".btn-modeltype-selector").removeClass("active btn-success");
        _.each($(".btn-modeltype-selector"), function(e) {
            var newType = $(e).data("type");
            if (newType === modelTypeSelector) $(e).addClass("active btn-success");
        });

        var demoFnRoutes = ["about", "userinfo", "list-apps", "list-folders", "list-changes", "list-buckets",
            "file-insert", "file-fetch", "file-update", "file-touch", "file-trash", "file-untrash", "file-empty-trash",
            "plus-get-person", "plus-list-people", "plus-list-activity", "plus-list-moments", "plus-list-comments"];
        _.each(demoFnRoutes, function(demoFnRoute) {
            var fn = DemoFns[modelTypeSelector][demoFnRoute] || DemoFns["neither"][demoFnRoute];
            if (_.isFunction(fn)) app.__route(demoFnRoute, fn);
        });
    };

    $(".btn-modeltype-selector").on("click", function(e) {
        localStorage.setItem("modeltype-selector", $(e.target).data("type"));
        _.defer(readyRoutes);
        _.defer(function() {
            Backbone.history.loadUrl(Backbone.history.fragment)
        });
    });

    $(".ls-vars-activate").on("click", function() {
        $(".aux-vars-container").html(JSON.stringify(localStorage, undefined, 2));
    });

    // change to HTTPS
    app.route("goto-https", "goto-https", function() {
        var loca = document["location"];
        document["location"] = "https:" + (loca["host"] || loca["hostname"]) + loca["pathname"];
    });
    if (document.location.protocol === "https:") {
        $(".goto-https-container").hide();
    }

    app.__route("sign-out", function() {
        if (_.isEmpty(Backbone.GoogleAPIs.get("access_token"))) {
            document.location = document.location.href.replace("#sign-out", "");
            return;
        }

        var po = document.createElement("script");
        po["type"] = "text/javascript";
        po["async"] = true;
        po["src"] = "https://accounts.google.com/o/oauth2/revoke?token=" + Backbone.GoogleAPIs.get("access_token");
        po["onload"] = function () {
            document.location = document.location.href.replace("#sign-out", "");
        };

        var s = document.getElementsByTagName("script")[0];
        s["parentNode"].insertBefore(po, s);
    });

    _.defer(readyRoutes);
});

// displays JS dependencies
_.defer(function () {
    _.each($("script"), function (script) {
        if (script && _.has(script, "src")) {
            if (script["src"].indexOf("chrome-extension") >= 0) return;
            if (script["src"].indexOf("apps-static") >= 0) return;
            $(".deps-container").append("
" + script["src"] + "
");
        }
    });
});
<commit_msg>hide https message on localhost usage<commit_after>var signinCallback = function (json) {
    json = json || {};

    Backbone.GoogleAPIs.set("access_token", json["access_token"]);
    Backbone.GoogleAPIs.set("signed_in_user", json);

    _.defer(function() {
        $(".signed-out").hide();
        $(".signed-in").hide();

        var m = new Backbone.GoogleAPIs.UserInfo({});
        m.on("change", function() {
            var email = m.get("email");
            if (_.isEmpty(email)) {
                $(".signed-out").show().removeClass("hide");
                return;
            }

            $(".signed-in").show().removeClass("hide");
            $(".signed-in-email").html(email);

            var picture = m.get("picture");
            if (!_.isEmpty(picture)) $(".signed-in-picture").attr("src", picture);
        });
        m.on("error", function () {
            $(".signed-out").show().removeClass("hide");
        });
        m.fetch();
    });

    try {
        Backbone.history.start();
    } catch (e) {
        console.warn(e);
    }
};

_.defer(function () {
    var App = Backbone.Router.extend({
        "__route": function (name, target_fn) {
            var wrapping_fn = function () {
                if (_.isFunction(target_fn)) _.defer(target_fn);
                if (!_.isUndefined(ChangeList) && _.isFunction(ChangeList.unpoll)) ChangeList.unpoll();

                $(".json-container").empty();
                $(".error-container").empty();

                // pretty printing target_fn
                var strFn = "" + target_fn;
                var clnFn = _.map(strFn.split("\n"), function(line) {
                    return line.replace("        ", "");
                });
                $(".code-container").html(clnFn.join("\n"));

                var auxparts = [];
                if (strFn.indexOf("displayJson") >= 0) auxparts.push("var displayJson = " + displayJson + ";");
                if (strFn.indexOf("displayError") >= 0) auxparts.push("var displayError = " + displayError + ";");
                $(".aux-code-container").html(auxparts.join("\n\n"));
            };

            this.route(name, name, wrapping_fn);
        }
    });

    app = new App();

    // resets buckets inputs
    app.on("route", function (href) {
        if (_.isEqual(href, "list-buckets")) {
            $(".list-buckets-inputs").show().removeClass("hide");
        } else {
            $(".list-buckets-inputs").hide();
        }
        $(".buckets-needs-project-id").hide();
    });
    // resets comments inputs
    app.on("route", function (href) {
        if (_.isEqual(href, "plus-list-comments")) {
            $(".list-comments-inputs").show().removeClass("hide");
        } else {
            $(".list-comments-inputs").hide();
        }
        $(".list-comments-needs-activity-id").hide();
    });
    // toggles active list item
    app.on("route", function (href) {
        _.each($(".top-level-anchors").find("a.list-group-item"), function (item) {
            $(item).removeClass("active");
            if (_.isEqual($(item).attr("href"), "#" + href)) $(item).addClass("active");
        });
    });

    // configures buttons for controlling model instantiation strategy
    var readyRoutes = function(e) {
        var modelTypeSelector = localStorage.getItem("modeltype-selector") || "model-factory";

        $(".btn-modeltype-selector").removeClass("active btn-success");
        _.each($(".btn-modeltype-selector"), function(e) {
            var newType = $(e).data("type");
            if (newType === modelTypeSelector) $(e).addClass("active btn-success");
        });

        var demoFnRoutes = ["about", "userinfo", "list-apps", "list-folders", "list-changes", "list-buckets",
            "file-insert", "file-fetch", "file-update", "file-touch", "file-trash", "file-untrash", "file-empty-trash",
            "plus-get-person", "plus-list-people", "plus-list-activity", "plus-list-moments", "plus-list-comments"];
        _.each(demoFnRoutes, function(demoFnRoute) {
            var fn = DemoFns[modelTypeSelector][demoFnRoute] || DemoFns["neither"][demoFnRoute];
            if (_.isFunction(fn)) app.__route(demoFnRoute, fn);
        });
    };

    $(".btn-modeltype-selector").on("click", function(e) {
        localStorage.setItem("modeltype-selector", $(e.target).data("type"));
        _.defer(readyRoutes);
        _.defer(function() {
            Backbone.history.loadUrl(Backbone.history.fragment)
        });
    });

    $(".ls-vars-activate").on("click", function() {
        $(".aux-vars-container").html(JSON.stringify(localStorage, undefined, 2));
    });

    // change to HTTPS
    app.route("goto-https", "goto-https", function() {
        var loca = document["location"];
        document["location"] = "https:" + (loca["host"] || loca["hostname"]) + loca["pathname"];
    });
    if (document.location["protocol"] === "https:") $(".goto-https-container").hide();
    if (document.location["hostname"] === "localhost") $(".goto-https-container").hide();

    app.__route("sign-out", function() {
        if (_.isEmpty(Backbone.GoogleAPIs.get("access_token"))) {
            document.location = document.location.href.replace("#sign-out", "");
            return;
        }

        var po = document.createElement("script");
        po["type"] = "text/javascript";
        po["async"] = true;
        po["src"] = "https://accounts.google.com/o/oauth2/revoke?token=" + Backbone.GoogleAPIs.get("access_token");
        po["onload"] = function () {
            document.location = document.location.href.replace("#sign-out", "");
        };

        var s = document.getElementsByTagName("script")[0];
        s["parentNode"].insertBefore(po, s);
    });

    _.defer(readyRoutes);
});

// displays JS dependencies
_.defer(function () {
    _.each($("script"), function (script) {
        if (script && _.has(script, "src")) {
            if (script["src"].indexOf("chrome-extension") >= 0) return;
            if (script["src"].indexOf("apps-static") >= 0) return;
            $(".deps-container").append("
" + script["src"] + "
");
        }
    });
});
<|endoftext|>


<commit_before>var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
var StyleConstants = require('builder/components/form-components/_constants/_style');

var NO_PANES_CLASS = 'Editor-formInner--NoTabs';

module.exports = {
  generate: function (params) {
    var strokeParams = {
      querySchemaModel: params.querySchemaModel,
      styleType: params.styleType,
      configModel: params.configModel,
      userModel: params.userModel,
      modals: params.modals
    };

    return params.queryGeometryModel.get('simple_geom') === 'line'
      ? this._generateLineStrokeColor(strokeParams)
      : this._generateSimpleStrokeColor(strokeParams, params.queryGeometryModel.get('simple_geom'));
  },

  _generateLineStrokeColor: function (params) {
    if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
    if (!params.configModel) throw new Error('configModel is required');
    if (!params.styleType) throw new Error('styleType is required');
    if (!params.userModel) throw new Error('userModel is required');
    if (!params.modals) throw new Error('modals is required');

    var queryStatus = params.querySchemaModel.get('status');
    var isDisabled = queryStatus !== 'fetched';
    var helpMessage = _t('editor.style.components.stroke.' + queryStatus);

    return {
      type: 'FillColor',
      title: _t('editor.style.components.stroke.label'),
      fieldClass: NO_PANES_CLASS,
      options: StyleFormDictionaryHelpers.getOptionsByStyleType({
        querySchemaModel: params.querySchemaModel,
        styleType: params.styleType
      }),
      query: params.querySchemaModel.get('query'),
      configModel: params.configModel,
      userModel: params.userModel,
      modals: params.modals,
      dialogMode: DialogConstants.Mode.FLOAT,
      editorAttrs: {
        imageEnabled: false,
        hidePanes: ['value'],
        disabled: isDisabled,
        help: isDisabled ? helpMessage : _t('editor.style.tooltips.stroke.color', { type: _t('editor.style.tooltips.line') })
      },
      validators: ['required']
    };
  },

  _generateSimpleStrokeColor: function (params, type) {
    if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
    if (!params.configModel) throw new Error('configModel is required');
    if (!params.styleType) throw new Error('styleType is required');
    if (!params.userModel) throw new Error('userModel is required');
    if (!params.modals) throw new Error('modals is required');

    var styleType = type === StyleConstants.Type.POLYGON
      ? StyleConstants.Type.POLYGON
      : params.styleType;

    return {
      type: 'FillColor',
      title: _t('editor.style.components.stroke-color.label'),
      fieldClass: NO_PANES_CLASS,
      options: [],
      query: params.querySchemaModel.get('query'),
      configModel: params.configModel,
      userModel: params.userModel,
      modals: params.modals,
      dialogMode: DialogConstants.Mode.FLOAT,
      editorAttrs: {
        imageEnabled: false,
        hidePanes: ['value'],
        help: _t('editor.style.tooltips.stroke.color', { type: _t('editor.style.tooltips.' + styleType) })
      },
      validators: ['required']
    };
  }
};
<commit_msg>Fix stroke color label<commit_after>var StyleFormDictionaryHelpers = require('builder/editor/style/style-form/style-form-helpers');
var DialogConstants = require('builder/components/form-components/_constants/_dialogs');
var StyleConstants = require('builder/components/form-components/_constants/_style');

var NO_PANES_CLASS = 'Editor-formInner--NoTabs';

module.exports = {
  generate: function (params) {
    var strokeParams = {
      querySchemaModel: params.querySchemaModel,
      styleType: params.styleType,
      configModel: params.configModel,
      userModel: params.userModel,
      modals: params.modals
    };

    return params.queryGeometryModel.get('simple_geom') === 'line'
      ? this._generateLineStrokeColor(strokeParams)
      : this._generateSimpleStrokeColor(strokeParams, params.queryGeometryModel.get('simple_geom'));
  },

  _generateLineStrokeColor: function (params) {
    if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
    if (!params.configModel) throw new Error('configModel is required');
    if (!params.styleType) throw new Error('styleType is required');
    if (!params.userModel) throw new Error('userModel is required');
    if (!params.modals) throw new Error('modals is required');

    var queryStatus = params.querySchemaModel.get('status');
    var isDisabled = queryStatus !== 'fetched';
    var helpMessage = _t('editor.style.components.stroke.' + queryStatus);

    return {
      type: 'FillColor',
      title: _t('editor.style.components.stroke-color.label'),
      fieldClass: NO_PANES_CLASS,
      options: StyleFormDictionaryHelpers.getOptionsByStyleType({
        querySchemaModel: params.querySchemaModel,
        styleType: params.styleType
      }),
      query: params.querySchemaModel.get('query'),
      configModel: params.configModel,
      userModel: params.userModel,
      modals: params.modals,
      dialogMode: DialogConstants.Mode.FLOAT,
      editorAttrs: {
        imageEnabled: false,
        hidePanes: ['value'],
        disabled: isDisabled,
        help: isDisabled ? helpMessage : _t('editor.style.tooltips.stroke.color', { type: _t('editor.style.tooltips.line') })
      },
      validators: ['required']
    };
  },

  _generateSimpleStrokeColor: function (params, type) {
    if (!params.querySchemaModel) throw new Error('querySchemaModel is required');
    if (!params.configModel) throw new Error('configModel is required');
    if (!params.styleType) throw new Error('styleType is required');
    if (!params.userModel) throw new Error('userModel is required');
    if (!params.modals) throw new Error('modals is required');

    var styleType = type === StyleConstants.Type.POLYGON
      ? StyleConstants.Type.POLYGON
      : params.styleType;

    return {
      type: 'FillColor',
      title: _t('editor.style.components.stroke-color.label'),
      fieldClass: NO_PANES_CLASS,
      options: [],
      query: params.querySchemaModel.get('query'),
      configModel: params.configModel,
      userModel: params.userModel,
      modals: params.modals,
      dialogMode: DialogConstants.Mode.FLOAT,
      editorAttrs: {
        imageEnabled: false,
        hidePanes: ['value'],
        help: _t('editor.style.tooltips.stroke.color', { type: _t('editor.style.tooltips.' + styleType) })
      },
      validators: ['required']
    };
  }
};
<|endoftext|>


<commit_before>var cdb = require('cartodb.js');
var template = require('./basemap-category.tpl');
var CarouselFormView = require('../../../components/carousel-form-view');

module.exports = cdb.core.View.extend({

  initialize: function (opts) {
    if (!opts.categoriesCollection) throw new Error('categoriesCollection is required');

    this._categoriesCollection = opts.categoriesCollection;
  },

  render: function () {
    this.clearSubViews();

    this.$el.html(template());

    this._renderCarousel();

    return this;
  },

  _renderCarousel: function () {
    var view = new CarouselFormView({
      collection: this._categoriesCollection,
      template: require('./basemap-carousel.tpl')
    });
    this.addView(view);
    this.$('.js-select').append(view.render().el);
  }

});
<commit_msg>basemaps: add_related_model<commit_after>var cdb = require('cartodb.js');
var template = require('./basemap-category.tpl');
var CarouselFormView = require('../../../components/carousel-form-view');

module.exports = cdb.core.View.extend({

  initialize: function (opts) {
    if (!opts.categoriesCollection) throw new Error('categoriesCollection is required');

    this._categoriesCollection = opts.categoriesCollection;

    this._initBinds();
  },

  _initBinds: function () {
    this.add_related_model(this._categoriesCollection);
  },

  render: function () {
    this.clearSubViews();

    this.$el.html(template());

    this._renderCarousel();

    return this;
  },

  _renderCarousel: function () {
    var view = new CarouselFormView({
      collection: this._categoriesCollection,
      template: require('./basemap-carousel.tpl')
    });
    this.addView(view);
    this.$('.js-select').append(view.render().el);
  }

});
<|endoftext|>