<commit_before>import $ from 'blingblingjs'
import hotkeys from 'hotkeys-js'

import { EditText } from './text'
import { canMoveLeft, canMoveRight, canMoveUp } from './move'
import { watchImagesForUpload } from './imageswap'
import { queryPage } from './search'
import { htmlStringToDom, createClassname, isOffBounds, getStyles } from './utils'

export function Selectable() {
  const elements          = $('body')
  let selected            = []
  let selectedCallbacks   = []
  let labels              = []
  let handles             = []

  const listen = () => {
    elements.forEach(el => el.addEventListener('click', on_click, true))
    elements.forEach(el => el.addEventListener('dblclick', on_dblclick, true))
    elements.on('selectstart', on_selection)
    elements.on('mouseover', on_hover)
    elements.on('mouseout', on_hoverout)

    document.addEventListener('copy', on_copy)
    document.addEventListener('cut', on_cut)
    document.addEventListener('paste', on_paste)

    hotkeys('cmd+alt+c', on_copy_styles)
    hotkeys('cmd+alt+v', e => on_paste_styles())
    hotkeys('esc', on_esc)
    hotkeys('cmd+d', on_duplicate)
    hotkeys('backspace,del,delete', on_delete)
    hotkeys('alt+del,alt+backspace', on_clearstyles)
    hotkeys('cmd+e,cmd+shift+e', on_expand_selection)
    hotkeys('cmd+g,cmd+shift+g', on_group)
    hotkeys('tab,shift+tab,enter,shift+enter', on_keyboard_traversal)
  }

  const unlisten = () => {
    elements.forEach(el => el.removeEventListener('click', on_click))
    elements.forEach(el => el.removeEventListener('dblclick', on_dblclick))
    elements.off('selectstart', on_selection)
    elements.off('mouseover', on_hover)
    elements.off('mouseout', on_hoverout)

    document.removeEventListener('copy', on_copy)
    document.removeEventListener('cut', on_cut)
    document.removeEventListener('paste', on_paste)

    hotkeys.unbind('esc,cmd+d,backspace,del,delete,alt+del,alt+backspace,cmd+e,cmd+shift+e,cmd+g,cmd+shift+g,tab,shift+tab,enter,shift+enter')
  }

  const on_click = e => {
    if (isOffBounds(e.target) && !selected.filter(el => el == e.target).length)
      return

    e.preventDefault()
    if (!e.altKey) e.stopPropagation()
    if (!e.shiftKey) unselect_all()
    select(e.target)
  }

  const on_dblclick = e => {
    e.preventDefault()
    e.stopPropagation()
    if (isOffBounds(e.target)) return
    $('tool-pallete')[0].toolSelected('text')
  }

  const on_esc = _ =>
    selected.length && unselect_all()

  const on_duplicate = e => {
    const root_node = selected[0]
    if (!root_node) return

    const deep_clone = root_node.cloneNode(true)
    deep_clone.removeAttribute('data-selected')
    root_node.parentNode.insertBefore(deep_clone, root_node.nextSibling)
    e.preventDefault()
  }

  const on_delete = e =>
    selected.length && delete_all()

  const on_clearstyles = e =>
    selected.forEach(el =>
      el.attr('style', null))

  const on_copy = e => {
    if (selected[0] && this.node_clipboard !== selected[0]) {
      e.preventDefault()
      let $node = selected[0].cloneNode(true)
      $node.removeAttribute('data-selected')
      this.copy_backup = $node.outerHTML
      e.clipboardData.setData('text/html', this.copy_backup)
    }
  }

  const on_cut = e => {
    if (selected[0] && this.node_clipboard !== selected[0]) {
      let $node = selected[0].cloneNode(true)
      $node.removeAttribute('data-selected')
      this.copy_backup = $node.outerHTML
      e.clipboardData.setData('text/html', this.copy_backup)
      selected[0].remove()
    }
  }

  const on_paste = e => {
    const clipData = e.clipboardData.getData('text/html')
    const potentialHTML = clipData || this.copy_backup
    if (selected[0] && potentialHTML) {
      e.preventDefault()
      selected[0].appendChild(
        htmlStringToDom(potentialHTML))
    }
  }

  const on_copy_styles = e => {
    e.preventDefault()
    this.copied_styles = selected.map(el =>
      getStyles(el))
  }

  const on_paste_styles = (index = 0) =>
    selected.forEach(el => {
      index = 0
      this.copied_styles[index]
        .map(({prop, value}) =>
          el.style[prop] = value)
    })

  const on_expand_selection = (e, {key}) => {
    e.preventDefault()

    expandSelection({
      query:  combineNodeNameAndClass(selected[0]),
      all:    key.includes('shift'),
    })
  }

  const on_group = (e, {key}) => {
    e.preventDefault()

    if (key.split('+').includes('shift')) {
      let $selected = [...selected]
      unselect_all()
      $selected.reverse().forEach(el => {
        let l = el.children.length
        while (el.children.length > 0) {
          var node = el.childNodes[el.children.length - 1]
          if (node.nodeName !== '#text')
            select(node)
          el.parentNode.prepend(node)
        }
        el.parentNode.removeChild(el)
      })
    }
    else {
      let div = document.createElement('div')
      selected[0].parentNode.prepend(
        selected.reverse().reduce((div, el) => {
          div.appendChild(el)
          return div
        }, div)
      )
      unselect_all()
      select(div)
    }
  }

  const on_selection = e =>
    !isOffBounds(e.target)
    && selected.length
    && selected[0].textContent != e.target.textContent
    && e.preventDefault()

  const on_keyboard_traversal = (e, {key}) => {
    if (selected.length !== 1) return

    e.preventDefault()
    e.stopPropagation()

    const current = selected[0]

    if (key.includes('shift')) {
      if (key.includes('tab') && canMoveLeft(current)) {
        unselect_all()
        select(canMoveLeft(current))
      }
      if (key.includes('enter') && canMoveUp(current)) {
        unselect_all()
        select(current.parentNode)
      }
    }
    else {
      if (key.includes('tab') && canMoveRight(current)) {
        unselect_all()
        select(canMoveRight(current))
      }
      if (key.includes('enter') && current.children.length) {
        unselect_all()
        select(current.children[0])
      }
    }
  }

  const on_hover = ({target}) => {
    if (isOffBounds(target)) return
    target.setAttribute('data-hover', true)
  }

  const on_hoverout = ({target}) => {
    target.removeAttribute('data-hover')
  }

  const select = el => {
    el.setAttribute('data-selected', true)
    overlayMetaUI(el)
    selected.unshift(el)
    tellWatchers()
  }

  const unselect_all = () => {
    selected
      .forEach(el =>
        $(el).attr({
          'data-selected':      null,
          'data-selected-hide': null,
          'data-label-id':      null,
          'data-hover':         null,
        }))

    handles.forEach(el =>
      el.remove())

    labels.forEach(el =>
      el.remove())

    labels    = []
    handles   = []
    selected  = []
  }

  const delete_all = () => {
    [...selected, ...labels, ...handles].forEach(el =>
      el.remove())

    labels    = []
    handles   = []
    selected  = []
  }

  const expandSelection = ({query, all = false}) => {
    if (all) {
      const unselecteds = $(query + ':not([data-selected])')
      unselecteds.forEach(select)
    }
    else {
      const potentials = $(query)
      if (!potentials) return

      const root_node_index = potentials.reduce((index, node, i) =>
        combineNodeNameAndClass(node) == query
          ? index = i
          : index
      , null)

      if (root_node_index !== null) {
        if (!potentials[root_node_index + 1]) {
          const potential = potentials.filter(el => !el.attr('data-selected'))[0]
          if (potential) select(potential)
        }
        else {
          select(potentials[root_node_index + 1])
        }
      }
    }
  }

  const combineNodeNameAndClass = node =>
    `${node.nodeName.toLowerCase()}${createClassname(node)}`

  const overlayMetaUI = el => {
    let handle = createHandle(el)
    let label  = createLabel(el, `
      ${el.nodeName.toLowerCase()}
      ${el.id && '#' + el.id}
      ${createClassname(el).split('.')
        .filter(name => name != '')
        .reduce((links, name) => `
          ${links}
          .${name}
        `, '')
      }
    `)

    let observer        = createObserver(el, {handle,label})
    let parentObserver  = createObserver(el, {handle,label})

    observer.observe(el, { attributes: true })
    parentObserver.observe(el.parentNode, { childList:true, subtree:true })

    $(label).on('DOMNodeRemoved', _ => {
      observer.disconnect()
      parentObserver.disconnect()
    })
  }

  const setLabel = (el, label) =>
    label.update = el.getBoundingClientRect()

  const createLabel = (el, text) => {
    if (!labels[parseInt(el.getAttribute('data-label-id'))]) {
      const label = document.createElement('pb-label')

      label.text = text
      label.position = {
        boundingRect:   el.getBoundingClientRect(),
        node_label_id:  labels.length,
      }
      el.setAttribute('data-label-id', labels.length)

      document.body.appendChild(label)

      $(label).on('query', ({detail}) => {
        if (!detail.text) return
        this.query_text = detail.text

        queryPage('[data-hover]', el =>
          el.setAttribute('data-hover', null))

        queryPage(this.query_text + ':not([data-selected])', el =>
          detail.activator === 'mouseenter'
            ? el.setAttribute('data-hover', true)
            : select(el))
      })

      $(label).on('mouseleave', e => {
        e.preventDefault()
        e.stopPropagation()
        queryPage('[data-hover]', el =>
          el.setAttribute('data-hover', null))
      })

      labels[labels.length] = label
      return label
    }
  }

  const createHandle = el => {
    if (!handles[parseInt(el.getAttribute('data-label-id'))]) {
      const handle = document.createElement('pb-handles')

      handle.position = {
        boundingRect:   el.getBoundingClientRect(),
        node_label_id:  handles.length,
      }

      document.body.appendChild(handle)

      handles[handles.length] = handle
      return handle
    }
  }

  const setHandle = (node, handle) => {
    handle.position = {
      boundingRect:   node.getBoundingClientRect(),
      node_label_id:  node.getAttribute('data-label-id'),
    }
  }

  const createObserver = (node, {label,handle}) =>
    new MutationObserver(list => {
      setLabel(node, label)
      setHandle(node, handle)
    })

  const onSelectedUpdate = (cb, immediateCallback = true) => {
    selectedCallbacks.push(cb)
    if (immediateCallback) cb(selected)
  }

  const removeSelectedCallback = cb =>
    selectedCallbacks = selectedCallbacks.filter(callback => callback != cb)

  const tellWatchers = () =>
    selectedCallbacks.forEach(cb => cb(selected))

  const disconnect = () => {
    unselect_all()
    unlisten()
  }

  watchImagesForUpload()
  listen()

  return {
    select,
    unselect_all,
    onSelectedUpdate,
    removeSelectedCallback,
    disconnect
  }
}<commit_msg>really really fixed paste style this time<commit_after>import $ from 'blingblingjs'
import hotkeys from 'hotkeys-js'

import { EditText } from './text'
import { canMoveLeft, canMoveRight, canMoveUp } from './move'
import { watchImagesForUpload } from './imageswap'
import { queryPage } from './search'
import { htmlStringToDom, createClassname, isOffBounds, getStyles } from './utils'

export function Selectable() {
  const elements          = $('body')
  let selected            = []
  let selectedCallbacks   = []
  let labels              = []
  let handles             = []

  const listen = () => {
    elements.forEach(el => el.addEventListener('click', on_click, true))
    elements.forEach(el => el.addEventListener('dblclick', on_dblclick, true))
    elements.on('selectstart', on_selection)
    elements.on('mouseover', on_hover)
    elements.on('mouseout', on_hoverout)

    document.addEventListener('copy', on_copy)
    document.addEventListener('cut', on_cut)
    document.addEventListener('paste', on_paste)

    hotkeys('cmd+alt+c', on_copy_styles)
    hotkeys('cmd+alt+v', e => on_paste_styles())
    hotkeys('esc', on_esc)
    hotkeys('cmd+d', on_duplicate)
    hotkeys('backspace,del,delete', on_delete)
    hotkeys('alt+del,alt+backspace', on_clearstyles)
    hotkeys('cmd+e,cmd+shift+e', on_expand_selection)
    hotkeys('cmd+g,cmd+shift+g', on_group)
    hotkeys('tab,shift+tab,enter,shift+enter', on_keyboard_traversal)
  }

  const unlisten = () => {
    elements.forEach(el => el.removeEventListener('click', on_click))
    elements.forEach(el => el.removeEventListener('dblclick', on_dblclick))
    elements.off('selectstart', on_selection)
    elements.off('mouseover', on_hover)
    elements.off('mouseout', on_hoverout)

    document.removeEventListener('copy', on_copy)
    document.removeEventListener('cut', on_cut)
    document.removeEventListener('paste', on_paste)

    hotkeys.unbind('esc,cmd+d,backspace,del,delete,alt+del,alt+backspace,cmd+e,cmd+shift+e,cmd+g,cmd+shift+g,tab,shift+tab,enter,shift+enter')
  }

  const on_click = e => {
    if (isOffBounds(e.target) && !selected.filter(el => el == e.target).length)
      return

    e.preventDefault()
    if (!e.altKey) e.stopPropagation()
    if (!e.shiftKey) unselect_all()
    select(e.target)
  }

  const on_dblclick = e => {
    e.preventDefault()
    e.stopPropagation()
    if (isOffBounds(e.target)) return
    $('tool-pallete')[0].toolSelected('text')
  }

  const on_esc = _ =>
    selected.length && unselect_all()

  const on_duplicate = e => {
    const root_node = selected[0]
    if (!root_node) return

    const deep_clone = root_node.cloneNode(true)
    deep_clone.removeAttribute('data-selected')
    root_node.parentNode.insertBefore(deep_clone, root_node.nextSibling)
    e.preventDefault()
  }

  const on_delete = e =>
    selected.length && delete_all()

  const on_clearstyles = e =>
    selected.forEach(el =>
      el.attr('style', null))

  const on_copy = e => {
    if (selected[0] && this.node_clipboard !== selected[0]) {
      e.preventDefault()
      let $node = selected[0].cloneNode(true)
      $node.removeAttribute('data-selected')
      this.copy_backup = $node.outerHTML
      e.clipboardData.setData('text/html', this.copy_backup)
    }
  }

  const on_cut = e => {
    if (selected[0] && this.node_clipboard !== selected[0]) {
      let $node = selected[0].cloneNode(true)
      $node.removeAttribute('data-selected')
      this.copy_backup = $node.outerHTML
      e.clipboardData.setData('text/html', this.copy_backup)
      selected[0].remove()
    }
  }

  const on_paste = e => {
    const clipData = e.clipboardData.getData('text/html')
    const potentialHTML = clipData || this.copy_backup
    if (selected[0] && potentialHTML) {
      e.preventDefault()
      selected[0].appendChild(
        htmlStringToDom(potentialHTML))
    }
  }

  const on_copy_styles = e => {
    e.preventDefault()
    this.copied_styles = selected.reverse().map(el =>
      getStyles(el))
  }

  const on_paste_styles = (index = 0) =>
    selected.forEach(el => {
      this.copied_styles[index]
        .map(({prop, value}) =>
          el.style[prop] = value)

      index >= this.copied_styles.length - 1
        ? index = 0
        : index++
    })

  const on_expand_selection = (e, {key}) => {
    e.preventDefault()

    expandSelection({
      query:  combineNodeNameAndClass(selected[0]),
      all:    key.includes('shift'),
    })
  }

  const on_group = (e, {key}) => {
    e.preventDefault()

    if (key.split('+').includes('shift')) {
      let $selected = [...selected]
      unselect_all()
      $selected.reverse().forEach(el => {
        let l = el.children.length
        while (el.children.length > 0) {
          var node = el.childNodes[el.children.length - 1]
          if (node.nodeName !== '#text')
            select(node)
          el.parentNode.prepend(node)
        }
        el.parentNode.removeChild(el)
      })
    }
    else {
      let div = document.createElement('div')
      selected[0].parentNode.prepend(
        selected.reverse().reduce((div, el) => {
          div.appendChild(el)
          return div
        }, div)
      )
      unselect_all()
      select(div)
    }
  }

  const on_selection = e =>
    !isOffBounds(e.target)
    && selected.length
    && selected[0].textContent != e.target.textContent
    && e.preventDefault()

  const on_keyboard_traversal = (e, {key}) => {
    if (selected.length !== 1) return

    e.preventDefault()
    e.stopPropagation()

    const current = selected[0]

    if (key.includes('shift')) {
      if (key.includes('tab') && canMoveLeft(current)) {
        unselect_all()
        select(canMoveLeft(current))
      }
      if (key.includes('enter') && canMoveUp(current)) {
        unselect_all()
        select(current.parentNode)
      }
    }
    else {
      if (key.includes('tab') && canMoveRight(current)) {
        unselect_all()
        select(canMoveRight(current))
      }
      if (key.includes('enter') && current.children.length) {
        unselect_all()
        select(current.children[0])
      }
    }
  }

  const on_hover = ({target}) => {
    if (isOffBounds(target)) return
    target.setAttribute('data-hover', true)
  }

  const on_hoverout = ({target}) => {
    target.removeAttribute('data-hover')
  }

  const select = el => {
    el.setAttribute('data-selected', true)
    overlayMetaUI(el)
    selected.unshift(el)
    tellWatchers()
  }

  const unselect_all = () => {
    selected
      .forEach(el =>
        $(el).attr({
          'data-selected':      null,
          'data-selected-hide': null,
          'data-label-id':      null,
          'data-hover':         null,
        }))

    handles.forEach(el =>
      el.remove())

    labels.forEach(el =>
      el.remove())

    labels    = []
    handles   = []
    selected  = []
  }

  const delete_all = () => {
    [...selected, ...labels, ...handles].forEach(el =>
      el.remove())

    labels    = []
    handles   = []
    selected  = []
  }

  const expandSelection = ({query, all = false}) => {
    if (all) {
      const unselecteds = $(query + ':not([data-selected])')
      unselecteds.forEach(select)
    }
    else {
      const potentials = $(query)
      if (!potentials) return

      const root_node_index = potentials.reduce((index, node, i) =>
        combineNodeNameAndClass(node) == query
          ? index = i
          : index
      , null)

      if (root_node_index !== null) {
        if (!potentials[root_node_index + 1]) {
          const potential = potentials.filter(el => !el.attr('data-selected'))[0]
          if (potential) select(potential)
        }
        else {
          select(potentials[root_node_index + 1])
        }
      }
    }
  }

  const combineNodeNameAndClass = node =>
    `${node.nodeName.toLowerCase()}${createClassname(node)}`

  const overlayMetaUI = el => {
    let handle = createHandle(el)
    let label  = createLabel(el, `
      ${el.nodeName.toLowerCase()}
      ${el.id && '#' + el.id}
      ${createClassname(el).split('.')
        .filter(name => name != '')
        .reduce((links, name) => `
          ${links}
          .${name}
        `, '')
      }
    `)

    let observer        = createObserver(el, {handle,label})
    let parentObserver  = createObserver(el, {handle,label})

    observer.observe(el, { attributes: true })
    parentObserver.observe(el.parentNode, { childList:true, subtree:true })

    $(label).on('DOMNodeRemoved', _ => {
      observer.disconnect()
      parentObserver.disconnect()
    })
  }

  const setLabel = (el, label) =>
    label.update = el.getBoundingClientRect()

  const createLabel = (el, text) => {
    if (!labels[parseInt(el.getAttribute('data-label-id'))]) {
      const label = document.createElement('pb-label')

      label.text = text
      label.position = {
        boundingRect:   el.getBoundingClientRect(),
        node_label_id:  labels.length,
      }
      el.setAttribute('data-label-id', labels.length)

      document.body.appendChild(label)

      $(label).on('query', ({detail}) => {
        if (!detail.text) return
        this.query_text = detail.text

        queryPage('[data-hover]', el =>
          el.setAttribute('data-hover', null))

        queryPage(this.query_text + ':not([data-selected])', el =>
          detail.activator === 'mouseenter'
            ? el.setAttribute('data-hover', true)
            : select(el))
      })

      $(label).on('mouseleave', e => {
        e.preventDefault()
        e.stopPropagation()
        queryPage('[data-hover]', el =>
          el.setAttribute('data-hover', null))
      })

      labels[labels.length] = label
      return label
    }
  }

  const createHandle = el => {
    if (!handles[parseInt(el.getAttribute('data-label-id'))]) {
      const handle = document.createElement('pb-handles')

      handle.position = {
        boundingRect:   el.getBoundingClientRect(),
        node_label_id:  handles.length,
      }

      document.body.appendChild(handle)

      handles[handles.length] = handle
      return handle
    }
  }

  const setHandle = (node, handle) => {
    handle.position = {
      boundingRect:   node.getBoundingClientRect(),
      node_label_id:  node.getAttribute('data-label-id'),
    }
  }

  const createObserver = (node, {label,handle}) =>
    new MutationObserver(list => {
      setLabel(node, label)
      setHandle(node, handle)
    })

  const onSelectedUpdate = (cb, immediateCallback = true) => {
    selectedCallbacks.push(cb)
    if (immediateCallback) cb(selected)
  }

  const removeSelectedCallback = cb =>
    selectedCallbacks = selectedCallbacks.filter(callback => callback != cb)

  const tellWatchers = () =>
    selectedCallbacks.forEach(cb => cb(selected))

  const disconnect = () => {
    unselect_all()
    unlisten()
  }

  watchImagesForUpload()
  listen()

  return {
    select,
    unselect_all,
    onSelectedUpdate,
    removeSelectedCallback,
    disconnect
  }
}<|endoftext|>


<commit_before>let gulp,
    clean,
    merge,
    ghPages,
    sass,
    browserify,
    babelify,
    watchify,
    uglify,
    buffer,
    source,
    paths,
    displayError,
    browserifyOptions;

gulp = require('gulp');
clean = require('del');
merge = require('merge-stream');
ghPages = require('gulp-gh-pages');
sass = require('gulp-sass');
browserify = require('browserify');
babelify = require('babelify');
watchify = require('watchify');
uglify = require('gulp-uglify');
buffer = require('vinyl-buffer');
source = require('vinyl-source-stream');
paths = require('./filepaths.js');
displayError = paths.displayError;

browserifyOptions = {
  entries: paths.entries,
  basedir: paths.jsRoot,
  paths: paths.includes,
  extensions: ['.js'],
  debug: true,
  cache: {},
  packageCache: {},
  fullPaths: true
};

/**
 * @name buildJs
 * @param destination {String} path to the output destination. This value changes based on
 * production / development deploy and should be set (using bind) in the export of this file.
 * @return {Function} stream object used for gulp tasks
 * @summary Function responsible for building the javascript bundle using babelify (babel 6).
 */
function buildJs(destination){
  let browserBundle;

  browserBundle = browserify(browserifyOptions);
  return browserBundle.transform(babelify, {
    presets: ['es2015']
  })
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest(destination));
}

/**
 * @name initializeWatcher
 * @param bundleToWatch {Function} output of `browserify#transform` that is to be prepped for
 * watching.
 * @return {Function} stream watcher to be used by gulp tasks / event listening
 * @listens {event:update} gulp event emmitted when an update has occurred
 * @listens {event:error} gulp event error emmitted when a bundle compilation fails
 * @description define the update event to initialize a bundle and display the error should one
 * occur. outputs a `bundle.js` file to the build path. additionally, output a timestamp notifying
 * completion of the build
 */
function initializeWatcher(bundleToWatch){
  let watcher, updateStart;

  watcher = watchify(bundleToWatch);
  watcher.on('update', function(){
    updateStart = Date.now();
    watcher.bundle().on('error', function(e){
      displayError(e);
      return;
    }).pipe(source('bundle.js'))
    .pipe(gulp.dest(paths.build));
    console.log(`Updated! ${Date.now() - updateStart}ms. Complete at ${new Date()}`);
  });
  return watcher;
}

/**
 * @name watchJs
 * @borrows initializeWatcher
 * @listens {event:error} gulp event error emmitted when a bundle compilation fails
 * @summary responsible for watching the javascript bundle. This is the end function for the
 * watching gulp task. invoke the watcher function and additionally build the bundle immediately
 */
function watchJs(){
  let browserBundle, watcher;

  browserBundle = browserify(browserifyOptions);
  browserBundle.transform(babelify);
  watcher = initializeWatcher(browserBundle);
  watcher.bundle().on('error', function(e){
    displayError(e);
    return;
  })
  .pipe(source('bundle.js'))
  .pipe(gulp.dest(paths.build));
  return;
}

/**
 * @name buildSass
 * @function
 * @param destination {String} path to the output destination. This value changes based on
 * production / development deploy and should be set (using bind) in the export of this file.
 * @return {Function} stream object used for gulp tasks
 * @summary build task used to build minified css sheets.
 */
function buildSass(destination){
  return gulp.src('public/style/sass/application.scss')
    .pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError))
    .pipe(gulp.dest(destination));
}

/**
 * @name watchSass
 * @function
 * @listens {event:change} gulp event emmitted on a changed scss file
 * @summary watch task used to build minified css sheets on change.
 */
function watchSass(){
  gulp.watch(paths.sassFiles, ['build:sass'])
  .on('change', function(e){
    console.log(`[watcher] File ${e.path.replace(/.*(?=sass)/, '')} was ${e.type} at ${new Date()}, compiling...`);
  });
}

/**
 * @name cleanScripts
 * @function
 * @requires del
 * @return {Function} stream used for gulp tasks
 * @summary gulp task used to clear out listed directories or files
 */
function cleanScripts(){
  return clean([
    './dist'
  ]);
}

/**
 * @name deployPrep
 * @function
 * @borrows buildSass
 * @borrows buildJs
 * @return {Function} stream used for gulp tasks
 * @summary executes a set of gulp tasks. These tasks must all be asyncronous (must not depend on a
 * previous task in order to run) and must all return gulp streams. Its primary use is to build the
 * `dist` directory for deployment
 */
function deployPrep(){
  return merge(
    buildSass(paths.stylesDeployRoot),
    buildJs(paths.jsDeployRoot),
    gulp.src('README.md').pipe(gulp.dest('./dist/')),
    gulp.src('favicon.ico').pipe(gulp.dest('./dist/')),
    gulp.src('public/img/*').pipe(gulp.dest('./dist/img')),
    gulp.src('index.html').pipe(gulp.dest('./dist/'))
  );
}

function deployProd(){
  return gulp.src('./dist/**/*').pipe(ghPages({ force: true }));
}

module.exports.watch = {
  js: watchJs,
  sass: watchSass
};
module.exports.build = {
  js: buildJs.bind(null, paths.build),
  sass: buildSass.bind(null, paths.stylesRoot)
};
module.exports.deploy = {
  clean: cleanScripts,
  prep: deployPrep,
  prod: deployProd
}
<commit_msg>docs(gulpfile) document the `deployProd` function<commit_after>let gulp,
    clean,
    merge,
    ghPages,
    sass,
    browserify,
    babelify,
    watchify,
    uglify,
    buffer,
    source,
    paths,
    displayError,
    browserifyOptions;

gulp = require('gulp');
clean = require('del');
merge = require('merge-stream');
ghPages = require('gulp-gh-pages');
sass = require('gulp-sass');
browserify = require('browserify');
babelify = require('babelify');
watchify = require('watchify');
uglify = require('gulp-uglify');
buffer = require('vinyl-buffer');
source = require('vinyl-source-stream');
paths = require('./filepaths.js');
displayError = paths.displayError;

browserifyOptions = {
  entries: paths.entries,
  basedir: paths.jsRoot,
  paths: paths.includes,
  extensions: ['.js'],
  debug: true,
  cache: {},
  packageCache: {},
  fullPaths: true
};

/**
 * @name buildJs
 * @param destination {String} path to the output destination. This value changes based on
 * production / development deploy and should be set (using bind) in the export of this file.
 * @return {Function} stream object used for gulp tasks
 * @summary Function responsible for building the javascript bundle using babelify (babel 6).
 */
function buildJs(destination){
  let browserBundle;

  browserBundle = browserify(browserifyOptions);
  return browserBundle.transform(babelify, {
    presets: ['es2015']
  })
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest(destination));
}

/**
 * @name initializeWatcher
 * @param bundleToWatch {Function} output of `browserify#transform` that is to be prepped for
 * watching.
 * @return {Function} stream watcher to be used by gulp tasks / event listening
 * @listens {event:update} gulp event emmitted when an update has occurred
 * @listens {event:error} gulp event error emmitted when a bundle compilation fails
 * @description define the update event to initialize a bundle and display the error should one
 * occur. outputs a `bundle.js` file to the build path. additionally, output a timestamp notifying
 * completion of the build
 */
function initializeWatcher(bundleToWatch){
  let watcher, updateStart;

  watcher = watchify(bundleToWatch);
  watcher.on('update', function(){
    updateStart = Date.now();
    watcher.bundle().on('error', function(e){
      displayError(e);
      return;
    }).pipe(source('bundle.js'))
    .pipe(gulp.dest(paths.build));
    console.log(`Updated! ${Date.now() - updateStart}ms. Complete at ${new Date()}`);
  });
  return watcher;
}

/**
 * @name watchJs
 * @borrows initializeWatcher
 * @listens {event:error} gulp event error emmitted when a bundle compilation fails
 * @summary responsible for watching the javascript bundle. This is the end function for the
 * watching gulp task. invoke the watcher function and additionally build the bundle immediately
 */
function watchJs(){
  let browserBundle, watcher;

  browserBundle = browserify(browserifyOptions);
  browserBundle.transform(babelify);
  watcher = initializeWatcher(browserBundle);
  watcher.bundle().on('error', function(e){
    displayError(e);
    return;
  })
  .pipe(source('bundle.js'))
  .pipe(gulp.dest(paths.build));
  return;
}

/**
 * @name buildSass
 * @function
 * @param destination {String} path to the output destination. This value changes based on
 * production / development deploy and should be set (using bind) in the export of this file.
 * @return {Function} stream object used for gulp tasks
 * @summary build task used to build minified css sheets.
 */
function buildSass(destination){
  return gulp.src('public/style/sass/application.scss')
    .pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError))
    .pipe(gulp.dest(destination));
}

/**
 * @name watchSass
 * @function
 * @listens {event:change} gulp event emmitted on a changed scss file
 * @summary watch task used to build minified css sheets on change.
 */
function watchSass(){
  gulp.watch(paths.sassFiles, ['build:sass'])
  .on('change', function(e){
    console.log(`[watcher] File ${e.path.replace(/.*(?=sass)/, '')} was ${e.type} at ${new Date()}, compiling...`);
  });
}

/**
 * @name cleanScripts
 * @function
 * @requires del
 * @return {Function} stream used for gulp tasks
 * @summary gulp task used to clear out listed directories or files
 */
function cleanScripts(){
  return clean([
    './dist'
  ]);
}

/**
 * @name deployPrep
 * @function
 * @borrows buildSass
 * @borrows buildJs
 * @return {Function} stream used for gulp tasks
 * @summary executes a set of gulp tasks. These tasks must all be asyncronous (must not depend on a
 * previous task in order to run) and must all return gulp streams. Its primary use is to build the
 * `dist` directory for deployment
 */
function deployPrep(){
  return merge(
    buildSass(paths.stylesDeployRoot),
    buildJs(paths.jsDeployRoot),
    gulp.src('README.md').pipe(gulp.dest('./dist/')),
    gulp.src('favicon.ico').pipe(gulp.dest('./dist/')),
    gulp.src('public/img/*').pipe(gulp.dest('./dist/img')),
    gulp.src('index.html').pipe(gulp.dest('./dist/'))
  );
}

/**
 * @name deployProd
 * @function
 * @return {Function} stream used for gulp tasks
 * @summary Task used to deploy everything in the dist folder to gh-pages
 */
function deployProd(){
  return gulp.src('./dist/**/*').pipe(ghPages({ force: true }));
}

module.exports.watch = {
  js: watchJs,
  sass: watchSass
};
module.exports.build = {
  js: buildJs.bind(null, paths.build),
  sass: buildSass.bind(null, paths.stylesRoot)
};
module.exports.deploy = {
  clean: cleanScripts,
  prep: deployPrep,
  prod: deployProd
}
<|endoftext|>


<commit_before>;(function() {
  'use strict';

  var React;
  var ModalFormAnchor;
  if (typeof require !== 'undefined') {
    React = require('react');
    ModalFormAnchor = require('./anchor');
  } else if (typeof window !== 'undefined') {
    React = window.React;
    ModalFormAnchor = window.ZUIModalFormAnchor;
  }

  var ESC_KEY = 27;

  var UNDERLAY_STYLE = {
    left: 0,
    position: 'absolute',
    top: 0
  };

  var FORM_STYLE = {
    position: 'absolute'
  };

  function ModalFormBase() {
    React.Component.apply(this, arguments);
    this.reposition = this.reposition.bind(this);
    this.handleGlobalKeyDown = this.handleGlobalKeyDown.bind(this);
    this.handleGlobalNavigation = this.handleGlobalNavigation.bind(this);
    this.state = {
      underlayWidth: 0,
      underlayHeight: 0
    };
  }

  ModalFormBase.locationChangeEvent = 'locationchange';

  ModalFormBase.propTypes = {
    tag: React.PropTypes.node,
    required: React.PropTypes.bool,
    underlayStyle: React.PropTypes.object,
    persistAcrossLocations: React.PropTypes.bool,
    loose: React.PropTypes.bool,
    onReposition: React.PropTypes.func,
    onSubmit: React.PropTypes.func,
    onCancel: React.PropTypes.func
  };

  ModalFormBase.defaultProps = {
    tag: 'form',
    required: false,
    underlayStyle: {},
    persistAcrossLocations: false,
    loose: false,
    onReposition: Function.prototype,
    onSubmit: Function.prototype,
    onCancel: Function.prototype
  };

  ModalFormBase.prototype = Object.assign(Object.create(React.Component.prototype), {
    _originalScrollPosition: null,

    componentWillMount: function() {
      if (typeof pageXOffset !== 'undefined') {
        // Mounting a modal with `autoFocus` content scrolls to the top before it repositions.
        this._originalScrollPosition = [pageXOffset, pageYOffset];
      }
    },

    componentDidMount: function() {
      addEventListener('scroll', this.reposition);
      addEventListener('resize', this.reposition);
      addEventListener('keydown', this.handleGlobalKeyDown);
      addEventListener('hashchange', this.handleGlobalNavigation);
      addEventListener(ModalFormBase.locationChangeEvent, this.handleGlobalNavigation);
      this.reposition();
      if (this._originalScrollPosition !== null) {
        scrollTo.apply(null, this._originalScrollPosition);
      }
    },

    componentWillUnmount: function() {
      removeEventListener('scroll', this.reposition);
      removeEventListener('resize', this.reposition);
      removeEventListener('keydown', this.handleGlobalKeyDown);
      removeEventListener('hashchange', this.handleGlobalNavigation);
      removeEventListener(ModalFormBase.locationChangeEvent, this.handleGlobalNavigation);
    },

    handleGlobalKeyDown: function (event) {
      if (event.which === ESC_KEY && !this.props.required) {
        this.props.onCancel.apply(null, arguments);
      }
    },

    handleGlobalNavigation: function() {
      if (!this.props.required && !this.props.persistAcrossLocations) {
        this.props.onCancel.apply(null, arguments);
      }
    },

    getUnderlayChildren: function() {
      var action;
      var onSubmit;
      if (this.props.tag === 'form') {
        action = 'POST';
        onSubmit = this.handleFormSubmit.bind(this)
      }

      return React.createElement(this.props.tag, {
        ref: 'form',
        className: ('modal-form ' + (this.props.className || '')).trim(),
        action: action,
        style: Object.assign({}, FORM_STYLE, this.props.style),
        onSubmit: onSubmit
      }, this.props.children);
    },

    render: function() {
      if (this.props.loose) {
        return this.renderLoose();
      } else {
        return this.renderWithAnchor();
      }
    },

    renderLoose: function() {
      var underlaySize = {
        width: this.state.underlayWidth + 'px',
        height: this.state.underlayHeight + 'px'
      };
      return React.createElement.apply(React, ['div', {
        ref: 'underlay',
        className: ('modal-form-underlay ' + (this.props.className || '')).trim(),
        style: Object.assign({}, UNDERLAY_STYLE, underlaySize, this.props.underlayStyle),
        onClick: this.handleUnderlayClick.bind(this)
      }].concat(this.getUnderlayChildren()));
    },

    renderWithAnchor: function() {
      var looseRenderResult = this.renderLoose.apply(this, arguments);
      return React.createElement(ModalFormAnchor, null, looseRenderResult);
    },

    componentDidUpdate: function() {
      this.reposition();
    },

    reposition: function() {
      var formRect = this.refs.form.getBoundingClientRect();
      var formStyle = getComputedStyle(this.refs.form);
      var formRight = pageXOffset + formRect.right + parseFloat(formStyle.marginRight);
      var formBottom = pageYOffset + formRect.bottom + parseFloat(formStyle.marginBottom);
      var totalWidth = Math.max(document.documentElement.offsetWidth, innerWidth, formRight);
      var totalHeight = Math.max(document.documentElement.offsetHeight, innerHeight, formBottom);
      if (totalWidth !== this.state.underlayWidth || totalHeight !== this.state.underlayHeight) {
        this.setState({
          underlayWidth: totalWidth,
          underlayHeight: totalHeight
        });
      }
      this.props.onReposition();
    },

    handleFormSubmit: function(event) {
      event.preventDefault();
      this.props.onSubmit.apply(null, arguments);
    },

    handleUnderlayClick: function(event) {
      if (!this.props.required && event.target === this.refs.underlay) {
        this.props.onCancel.apply(null, arguments);
      }
    }
  });

  if (typeof module !== 'undefined') {
    module.exports = ModalFormBase;
  } else if (typeof window !== 'undefined') {
    window.ZUIModalFormBase = ModalFormBase;
  }
}());
<commit_msg>Remove Require Prop from Conditional<commit_after>;(function() {
  'use strict';

  var React;
  var ModalFormAnchor;
  if (typeof require !== 'undefined') {
    React = require('react');
    ModalFormAnchor = require('./anchor');
  } else if (typeof window !== 'undefined') {
    React = window.React;
    ModalFormAnchor = window.ZUIModalFormAnchor;
  }

  var ESC_KEY = 27;

  var UNDERLAY_STYLE = {
    left: 0,
    position: 'absolute',
    top: 0
  };

  var FORM_STYLE = {
    position: 'absolute'
  };

  function ModalFormBase() {
    React.Component.apply(this, arguments);
    this.reposition = this.reposition.bind(this);
    this.handleGlobalKeyDown = this.handleGlobalKeyDown.bind(this);
    this.handleGlobalNavigation = this.handleGlobalNavigation.bind(this);
    this.state = {
      underlayWidth: 0,
      underlayHeight: 0
    };
  }

  ModalFormBase.locationChangeEvent = 'locationchange';

  ModalFormBase.propTypes = {
    tag: React.PropTypes.node,
    required: React.PropTypes.bool,
    underlayStyle: React.PropTypes.object,
    persistAcrossLocations: React.PropTypes.bool,
    loose: React.PropTypes.bool,
    onReposition: React.PropTypes.func,
    onSubmit: React.PropTypes.func,
    onCancel: React.PropTypes.func
  };

  ModalFormBase.defaultProps = {
    tag: 'form',
    required: false,
    underlayStyle: {},
    persistAcrossLocations: false,
    loose: false,
    onReposition: Function.prototype,
    onSubmit: Function.prototype,
    onCancel: Function.prototype
  };

  ModalFormBase.prototype = Object.assign(Object.create(React.Component.prototype), {
    _originalScrollPosition: null,

    componentWillMount: function() {
      if (typeof pageXOffset !== 'undefined') {
        // Mounting a modal with `autoFocus` content scrolls to the top before it repositions.
        this._originalScrollPosition = [pageXOffset, pageYOffset];
      }
    },

    componentDidMount: function() {
      addEventListener('scroll', this.reposition);
      addEventListener('resize', this.reposition);
      addEventListener('keydown', this.handleGlobalKeyDown);
      addEventListener('hashchange', this.handleGlobalNavigation);
      addEventListener(ModalFormBase.locationChangeEvent, this.handleGlobalNavigation);
      this.reposition();
      if (this._originalScrollPosition !== null) {
        scrollTo.apply(null, this._originalScrollPosition);
      }
    },

    componentWillUnmount: function() {
      removeEventListener('scroll', this.reposition);
      removeEventListener('resize', this.reposition);
      removeEventListener('keydown', this.handleGlobalKeyDown);
      removeEventListener('hashchange', this.handleGlobalNavigation);
      removeEventListener(ModalFormBase.locationChangeEvent, this.handleGlobalNavigation);
    },

    handleGlobalKeyDown: function (event) {
      if (event.which === ESC_KEY && !this.props.required) {
        this.props.onCancel.apply(null, arguments);
      }
    },

    handleGlobalNavigation: function() {
      if (!this.props.persistAcrossLocations) {
        this.props.onCancel.apply(null, arguments);
      }
    },

    getUnderlayChildren: function() {
      var action;
      var onSubmit;
      if (this.props.tag === 'form') {
        action = 'POST';
        onSubmit = this.handleFormSubmit.bind(this)
      }

      return React.createElement(this.props.tag, {
        ref: 'form',
        className: ('modal-form ' + (this.props.className || '')).trim(),
        action: action,
        style: Object.assign({}, FORM_STYLE, this.props.style),
        onSubmit: onSubmit
      }, this.props.children);
    },

    render: function() {
      if (this.props.loose) {
        return this.renderLoose();
      } else {
        return this.renderWithAnchor();
      }
    },

    renderLoose: function() {
      var underlaySize = {
        width: this.state.underlayWidth + 'px',
        height: this.state.underlayHeight + 'px'
      };
      return React.createElement.apply(React, ['div', {
        ref: 'underlay',
        className: ('modal-form-underlay ' + (this.props.className || '')).trim(),
        style: Object.assign({}, UNDERLAY_STYLE, underlaySize, this.props.underlayStyle),
        onClick: this.handleUnderlayClick.bind(this)
      }].concat(this.getUnderlayChildren()));
    },

    renderWithAnchor: function() {
      var looseRenderResult = this.renderLoose.apply(this, arguments);
      return React.createElement(ModalFormAnchor, null, looseRenderResult);
    },

    componentDidUpdate: function() {
      this.reposition();
    },

    reposition: function() {
      var formRect = this.refs.form.getBoundingClientRect();
      var formStyle = getComputedStyle(this.refs.form);
      var formRight = pageXOffset + formRect.right + parseFloat(formStyle.marginRight);
      var formBottom = pageYOffset + formRect.bottom + parseFloat(formStyle.marginBottom);
      var totalWidth = Math.max(document.documentElement.offsetWidth, innerWidth, formRight);
      var totalHeight = Math.max(document.documentElement.offsetHeight, innerHeight, formBottom);
      if (totalWidth !== this.state.underlayWidth || totalHeight !== this.state.underlayHeight) {
        this.setState({
          underlayWidth: totalWidth,
          underlayHeight: totalHeight
        });
      }
      this.props.onReposition();
    },

    handleFormSubmit: function(event) {
      event.preventDefault();
      this.props.onSubmit.apply(null, arguments);
    },

    handleUnderlayClick: function(event) {
      if (!this.props.required && event.target === this.refs.underlay) {
        this.props.onCancel.apply(null, arguments);
      }
    }
  });

  if (typeof module !== 'undefined') {
    module.exports = ModalFormBase;
  } else if (typeof window !== 'undefined') {
    window.ZUIModalFormBase = ModalFormBase;
  }
}());
<|endoftext|>


<commit_before>import GameLoop3D from './GameLoop3D';
import GameUserClient from './GameUserClient';

export default class GameLoopClient {
    constructor(DOMcontainer) {
        this.container = DOMcontainer;

        this.socket = require('socket.io-client')('http://localhost:3000');

        this.socket.on('userSettings', (data) => {
            console.log('recived userSettings', data);
            this.socket = data;
            this.gameUser = new GameUserClient(this.userSettings, this.socket);
            this.gameLoop3D = new GameLoop3D(container, this.gameUser);
            this.startTicking = true;
        });

        this.socket.on('tick', (data) => {
            // console.log(data);
            if (this.startTicking) this.gameLoop3D.animate(data);
        });
    }

    destroy() {
        // var container = document.getElementById( 'container' ).innerHTML = "";
        this.container.innerHTML = '';
        this.gameLoop3D.destroy()
        this.startTicking = false;
        console.log('close game');
        // this.socket.emit('close');
        this.socket.close();
    }
}
<commit_msg>build a 🚀, aim for the 💫, land on the 🌜<commit_after>import GameLoop3D from './GameLoop3D';
import GameUserClient from './GameUserClient';

export default class GameLoopClient {
    constructor(DOMcontainer) {
        this.container = DOMcontainer;

        this.socket = require('socket.io-client')('http://localhost:3000');

        this.socket.on('userSettings', (data) => {
            console.log('recived userSettings', data);
            this.socket = data;
            this.gameUser = new GameUserClient(this.userSettings, this.socket);
            this.gameLoop3D = new GameLoop3D(this.container, this.gameUser);
            this.startTicking = true;
        });

        this.socket.on('tick', (data) => {
            // console.log(data);
            if (this.startTicking) this.gameLoop3D.animate(data);
        });
    }

    destroy() {
        // var container = document.getElementById( 'container' ).innerHTML = "";
        this.container.innerHTML = '';
        this.gameLoop3D.destroy();
        this.startTicking = false;
        console.log('close game');
        // this.socket.emit('close');
        this.socket.close();
    }
}
<|endoftext|>


<commit_before>/**
 * This module implements a thumbnails bar
 */

// define a new module
define(['utiljs', 'rendererjs', 'jquery_ui'], function(util, renderer) {

  /**
   * Provide a namespace for the thumbnails bar module
   *
   * @namespace
   */
   var thbarjs = thbarjs || {};

   /**
    * Class implementing the thumbnails bar
    *
    * @constructor
    * @param {Object} thumbnails bar's options with properties:
    *   -container: thumbnails bar's container's DOM id or DOM object
    *   -position: thumbnails bar's css position object with possible properties top, bottom, left, right
    *   -layout: thumbnails bar's layout, either of the strings 'vertical', 'horizontal' or 'grid'
    *   -thumbnailsIdPrefix: a prefix string for the DOM ids used for all of the thumbnails' containers
    * @param {Object} optional file manager object to enable reading of files from the cloud or HTML5
    * sandboxed filesystem.
    */
    thbarjs.ThumbnailBar = function(options, fileManager) {

      this.version = 0.0;

      // thumbnails bar's container
      if (typeof options.container === 'string') {

        // a DOM id was passed
        this.container = $('#' + options.container);

      } else {

        // a DOM object was passed
        this.container = $(options.container);
      }

      // thumbnails bar's css position object with possible properties top, bottom, left, right
      if (options.position) {
        this.position = options.position;
      } else {
        this.position = {};
      }

      // layout: vertical or horizontal
      this.layout = 'vertical';
      if (options.layout) {
        this.layout = options.layout;
      }

      // prefix string for the DOM ids that are going to be used for the thumbnails' containers
      this.thumbnailsIdPrefix = options.thumbnailsIdPrefix;

      // jQuery object for the sortable div element inside the thumbnails bar
      this.jqSortable = null;

      // number of thumbnails in the thumbnails bar
      this.numThumbnails = 0;

      // number of currently loaded thumbnails
      this.numOfLoadedThumbnails = 0;

      // file manager object
      this.fileManager = null;
      if (fileManager) {this.fileManager = fileManager;}
    };

    /**
     * Initialize the thumbnails bar.
     *
     * @param {Array} array of image file objects. Each object contains the following properties:
     *  -id: Integer, the object's id
     *  -baseUrl: String ‘directory/containing/the/files’
     *  -imgType: String neuroimage type. Any of the possible values returned by rendererjs.Renderer.imgType
     *  -files: Array of HTML5 File objects or custom file objects with properties:
     *     -remote: a boolean indicating whether the file has not been read locally (with a filepicker)
     *     -url the file's url
     *     -cloudId: the id of the file in a cloud storage system if stored in the cloud
     *     -name: file name
     *  The files array contains a single file for imgType different from 'dicom' or 'dicomzip'
     *  -thumbnail: Optional HTML5 or custom File object (optional jpg file for a thumbnail image)
     * @param {Function} optional callback to be called when the thumbnails bar is ready
     */
     thbarjs.ThumbnailBar.prototype.init = function(imgFileArr, callback) {
       var self = this;

       // append a bar handle
       self.container.append('
...
');

       // append sortable div
       self.jqSortable = $('

');
       self.container.append(self.jqSortable);

       // add the appropriate classes
       self.container.addClass("view-thumbnailsbar");

       // jQuery UI options object for sortable elems
       // ui-sortable CSS class is by default added to the containing elem
       // an elem being moved is assigned the ui-sortable-helper class
       var sort_opts = {
         cursor: 'move',
         containment: self.container.parent(), // within which elem displacement is restricted
         helper: 'clone', // visually moving element is a clone of the corresponding thumbnail
         dropOnEmpty: true, // allows depositing items into an empty list

         //event handlers
         // beforeStop is called when the placeholder is still in the list
         beforeStop: function(evt, ui) {
           self.onBeforeStop(evt, ui);
         }
      };

      // make the sortable div within the thumbnails bar a jQuery UI's sortable element
      self.jqSortable.sortable(sort_opts);

      var checkIfThumbnailBarIsReady =  function() {

        if (++self.numOfLoadedThumbnails === self.numThumbnails) {

          // all thumbnails loaded, thumbnails bar is ready
          if (callback) {callback();}
        }
      };

      // load thumbnail images and create their UIs when ready
      self.numThumbnails = imgFileArr.length;
      for (var i=0; i<self.numThumbnails; i++) {
        self.addThumbnail(imgFileArr[i], checkIfThumbnailBarIsReady);
      }

      // set the layout and position of the thumbnails bar
      self.setLayout(self.layout);
    };

    /**
     * Set thumbnails bar's layout.
     *
     * @param {String} layout: "vertical", "horizontal" or "grid".
     */
     thbarjs.ThumbnailBar.prototype.setLayout = function(layout) {
       var cont = this.container;
       var ths = $('.view-thumbnail', cont);

       this.layout = layout;

       if (layout === 'vertical') {

         cont.removeClass("view-thumbnailsbar-x");
         cont.addClass("view-thumbnailsbar-y");
         ths.removeClass("view-thumbnail-x");
         ths.addClass("view-thumbnail-y");

       } else if (layout === 'horizontal') {

         cont.removeClass("view-thumbnailsbar-y");
         cont.addClass("view-thumbnailsbar-x");
         ths.removeClass("view-thumbnail-y");
         ths.addClass("view-thumbnail-x");

       } else if (layout === 'grid') {
         cont.removeClass("view-thumbnailsbar-y view-thumbnailsbar-x");
         ths.removeClass("view-thumbnail-y");
         ths.addClass("view-thumbnail-x");
       }

       this.setPosition(this.position);
     };

    /**
     * Set a new css position for the thumbnails bar.
     *
     * @param {Object} css position object with possible properties: "top", "bottom", "left" and "right".
     */
     thbarjs.ThumbnailBar.prototype.setPosition = function(pos) {
       var cont = this.container;
       var layout = this.layout;
       var t = "", r = "", b = "", l = "";

       if (pos) {

         if (pos.top) {
           this.position.top = pos.top;
           cont.css({ top: pos.top });
           t = ' - ' + pos.top;
         }

         if (pos.right) {
           this.position.right = pos.right;
           cont.css({ right: pos.right });
           r = ' - ' + pos.right;
         }

         if (pos.bottom) {
           this.position.bottom = pos.bottom;
           cont.css({ bottom: pos.bottom });
           b = ' - ' + pos.bottom;
         }

         if (pos.left) {
           this.position.left = pos.left;
           cont.css({ left: pos.left });
           l = ' - ' + pos.left;
         }

         if ((layout === 'vertical') && (t || b)) {
           cont.css({ height: 'calc(100%' + t + b + ')' });

         } else if ((layout === 'horizontal') && (r || l)) {
           cont.css({ width: 'calc(100%' + r + l + ')' });

         } else if (layout === 'grid') {

           if (t || b) {
             cont.css({ height: 'calc(100%' + t + b + ')' });
           }

           if (r || l) {
             cont.css({ width: 'calc(100%' + r + l + ')' });
           }
         }
       }
     };

    /**
    * This method is called just before dropping a moving thumbnail's visual element on a complementary
    * jQuery UI's sortable element.
     *
     * @param {Object} jQuery UI event object.
     * @param {Object} jQuery UI ui object.
     */
     thbarjs.ThumbnailBar.prototype.onBeforeStop = function(evt, ui) {

       console.log('onBeforeStop not overwritten!');
       console.log('event obj: ', evt);
       console.log('ui obj: ', ui);
     };

   /**
    * Set complementary jQuery UI sortable elements which the moving helper can be visually appended to.
    *
    * @param {String} css selector indicating the complementary sortable elements.
    */
    thbarjs.ThumbnailBar.prototype.setComplementarySortableElems = function(cssSelector) {

      // the moving helper element can be appended to these elements
      this.jqSortable.sortable( "option", "appendTo", cssSelector);

      // connect with these sortable elements
      this.jqSortable.sortable( "option", "connectWith", cssSelector);
    };

    /**
     * Return a thumbnail's container DOM id.
     *
     * @param {Number} thumbnail's integer id.
     * @return {String} the thumbnail's container DOM id.
     */
     thbarjs.ThumbnailBar.prototype.getThumbnailContId = function(thumbnailId) {

       // the thumbnail's container DOM id is related to the thumbnail's integer id
       return this.thumbnailsIdPrefix + thumbnailId;
    };

    /**
     * Returns a thumbnail's integer id.
     *
     * @param {String} thumbnail's container DOM id.
     * @return {Number} thumbnail's integer id.
     */
     thbarjs.ThumbnailBar.prototype.getThumbnailId = function(thumbnailContId) {

       // the thumbnail's integer id is related to the thumbnail's container DOM id
       return  parseInt(thumbnailContId.replace(this.thumbnailsIdPrefix, ""));
    };

    /**
     * Create and add a thumbnail to the thumbnails bar.
     *
     * @param {Oject} Image file object with the properties:
     *  -id: Integer, the object's id
     *  -baseUrl: String ‘directory/containing/the/files’
     *  -imgType: String neuroimage type. Any of the possible values returned by rendererjs.Renderer.imgType
     *  -files: Array of HTML5 File objects or custom file objects with properties:
     *     -remote: a boolean indicating whether the file has not been read locally (with a filepicker)
     *     -url the file's url
     *     -cloudId: the id of the file in a cloud storage system if stored in the cloud
     *     -name: file name
     *  The files array contains a single file for imgType different from 'dicom' or 'dicomzip'
     *  -thumbnail: Optional HTML5 File or custom file object (optional jpg file for a thumbnail image)
     * @param {Function} optional callback to be called when the thumbnail has been added
     */
     thbarjs.ThumbnailBar.prototype.addThumbnail = function(imgFileObj, callback) {
       var fname, info, title;
       var id = imgFileObj.id;
       var self = this;

       // we assume the name of an already existing thumbnail (eg. generated on the server side) is of the form:
       // 1.3.12.2.1107.5.2.32.35288.30000012092602261631200043880-AXIAL_RFMT_MPRAGE-Sag_T1_MEMPRAGE_1_mm_4e_nomoco.jpg
       if (imgFileObj.thumbnail) {
         fname = imgFileObj.thumbnail.name;
       } else if (imgFileObj.imgType !== 'dicom'){
         fname = imgFileObj.files[0].name;
       } else {
         fname = ''; title = ''; info = '';
       }

       if (fname) {
         if (fname.lastIndexOf('-') !== -1) {
           title = fname.substring(0, fname.lastIndexOf('.'));
           title = title.substring(title.lastIndexOf('-') + 1);
           info = title.substr(0, 10);
         } else {
           title = fname;
           info = fname.substring(0, fname.lastIndexOf('.')).substr(-10);
         }
       }

       // append this thumbnail to the sortable div within the thumbnails bar
       var jqTh = $(
         '
' +
           '' +
           '
' + info + '
' +
         '
'
       );
       self.jqSortable.append(jqTh);

       if (imgFileObj.thumbnail) {

         self.readThumbnail(imgFileObj.thumbnail, $('.view-thumbnail-img', jqTh), function() {
           if (callback) {callback();}
         });

       } else {

         self.createThumbnail(imgFileObj, $('.view-thumbnail-img', jqTh), function() {
           if (callback) {callback();}
         });
       }
     };

     /**
      * Load the thumbnail corresponding to the imgFileObj argument. If there is a thumbnail
      * property in the imgFileObj then load it otherwise automatically create the thumbnail
      * from an internal renderer's canvas object
      *
      * @param {Oject} HTML5 File object or custom file object with properties:
      *   -remote: a boolean indicating whether the file has not been read locally (with a filepicker)
      *   -url the file's url
      *   -cloudId: the id of the file in a cloud storage system if stored in the cloud
      *   -name: file name
      * @param {Function} jQuery object for the thumbnail's  element.
      * @param {Function} callback to be called when the thumbnail has been loaded.
      */
      thbarjs.ThumbnailBar.prototype.loadThumbnail = function(thFile, jqImg, callback) {

        // renderer options object
        var options = {
          container: null,
          rendererId: '',
        };

        var tmpRenderer = new renderer.Renderer(options, this.fileManager);

        tmpRenderer.readFile(thFile, 'readAsDataURL', function(thData) {

          jqImg.attr('src', thData);
          if (callback) {callback();}
        });
      };

    /**
     * Load the thumbnail corresponding to the imgFileObj argument. If there is a thumbnail
     * property in the imgFileObj then load it otherwise automatically create the thumbnail
     * from an internal renderer's canvas object
     *
     * @param {Oject} Image file object as in the addThumbnail method.
     * @param {Function} jQuery object for the thumbnail's  element.
     * @param {Function} callback to be called when the thumbnail has been craated.
     */
     thbarjs.ThumbnailBar.prototype.createThumbnail = function(imgFileObj, jqImg, callback) {
       var self = this;

       // append an internal temporal renderer
       var tempRenderCont = $('

');
       self.container.append(tempRenderCont);

       // renderer options object
       var options = {
         container: tempRenderCont[0],
         rendererId: self.thumbnailsIdPrefix + '_tmprenderer' + imgFileObj.id, // for the internal XTK renderer container
       };

       // create an internal temporal renderer
       var tmpRenderer = new renderer.Renderer(options, self.fileManager);

       tmpRenderer.init(imgFileObj, function() {

         // make div for the renderer's canvas the same size as the  element
         var imgWidth = jqImg.css('width');
         var imgHeight = jqImg.css('height');
         $('#' + options.rendererId).css({ width: imgWidth, height: imgHeight });

         tmpRenderer.getThumbnail( function(thData) {

           jqImg.attr('src', thData);
           if (callback) {callback();}

           // destroy this renderer
           tmpRenderer.destroy();
           tempRenderCont.remove();
         });
       });
     };

    /**
     * Remove event handlers and html interface.
     */
     thbarjs.ThumbnailBar.prototype.destroy = function() {

       this.numThumbnails = 0;
       this.numOfLoadedThumbnails = 0;
       this.container.empty();
       this.container = null;
     };

    return thbarjs;
  });
<commit_msg>removed renderer UI in createThumbnail<commit_after>/**
 * This module implements a thumbnails bar
 */

// define a new module
define(['utiljs', 'rendererjs', 'jquery_ui'], function(util, renderer) {

  /**
   * Provide a namespace for the thumbnails bar module
   *
   * @namespace
   */
   var thbarjs = thbarjs || {};

   /**
    * Class implementing the thumbnails bar
    *
    * @constructor
    * @param {Object} thumbnails bar's options with properties:
    *   -container: thumbnails bar's container's DOM id or DOM object
    *   -position: thumbnails bar's css position object with possible properties top, bottom, left, right
    *   -layout: thumbnails bar's layout, either of the strings 'vertical', 'horizontal' or 'grid'
    *   -thumbnailsIdPrefix: a prefix string for the DOM ids used for all of the thumbnails' containers
    * @param {Object} optional file manager object to enable reading of files from the cloud or HTML5
    * sandboxed filesystem.
    */
    thbarjs.ThumbnailBar = function(options, fileManager) {

      this.version = 0.0;

      // thumbnails bar's container
      if (typeof options.container === 'string') {

        // a DOM id was passed
        this.container = $('#' + options.container);

      } else {

        // a DOM object was passed
        this.container = $(options.container);
      }

      // thumbnails bar's css position object with possible properties top, bottom, left, right
      if (options.position) {
        this.position = options.position;
      } else {
        this.position = {};
      }

      // layout: vertical or horizontal
      this.layout = 'vertical';
      if (options.layout) {
        this.layout = options.layout;
      }

      // prefix string for the DOM ids that are going to be used for the thumbnails' containers
      this.thumbnailsIdPrefix = options.thumbnailsIdPrefix;

      // jQuery object for the sortable div element inside the thumbnails bar
      this.jqSortable = null;

      // number of thumbnails in the thumbnails bar
      this.numThumbnails = 0;

      // number of currently loaded thumbnails
      this.numOfLoadedThumbnails = 0;

      // file manager object
      this.fileManager = null;
      if (fileManager) {this.fileManager = fileManager;}
    };

    /**
     * Initialize the thumbnails bar.
     *
     * @param {Array} array of image file objects. Each object contains the following properties:
     *  -id: Integer, the object's id
     *  -baseUrl: String ‘directory/containing/the/files’
     *  -imgType: String neuroimage type. Any of the possible values returned by rendererjs.Renderer.imgType
     *  -files: Array of HTML5 File objects or custom file objects with properties:
     *     -remote: a boolean indicating whether the file has not been read locally (with a filepicker)
     *     -url the file's url
     *     -cloudId: the id of the file in a cloud storage system if stored in the cloud
     *     -name: file name
     *  The files array contains a single file for imgType different from 'dicom' or 'dicomzip'
     *  -thumbnail: Optional HTML5 or custom File object (optional jpg file for a thumbnail image)
     * @param {Function} optional callback to be called when the thumbnails bar is ready
     */
     thbarjs.ThumbnailBar.prototype.init = function(imgFileArr, callback) {
       var self = this;

       // append a bar handle
       self.container.append('
...
');

       // append sortable div
       self.jqSortable = $('

');
       self.container.append(self.jqSortable);

       // add the appropriate classes
       self.container.addClass("view-thumbnailsbar");

       // jQuery UI options object for sortable elems
       // ui-sortable CSS class is by default added to the containing elem
       // an elem being moved is assigned the ui-sortable-helper class
       var sort_opts = {
         cursor: 'move',
         containment: self.container.parent(), // within which elem displacement is restricted
         helper: 'clone', // visually moving element is a clone of the corresponding thumbnail
         dropOnEmpty: true, // allows depositing items into an empty list

         //event handlers
         // beforeStop is called when the placeholder is still in the list
         beforeStop: function(evt, ui) {
           self.onBeforeStop(evt, ui);
         }
      };

      // make the sortable div within the thumbnails bar a jQuery UI's sortable element
      self.jqSortable.sortable(sort_opts);

      var checkIfThumbnailBarIsReady =  function() {

        if (++self.numOfLoadedThumbnails === self.numThumbnails) {

          // all thumbnails loaded, thumbnails bar is ready
          if (callback) {callback();}
        }
      };

      // load thumbnail images and create their UIs when ready
      self.numThumbnails = imgFileArr.length;
      for (var i=0; i<self.numThumbnails; i++) {
        self.addThumbnail(imgFileArr[i], checkIfThumbnailBarIsReady);
      }

      // set the layout and position of the thumbnails bar
      self.setLayout(self.layout);
    };

    /**
     * Set thumbnails bar's layout.
     *
     * @param {String} layout: "vertical", "horizontal" or "grid".
     */
     thbarjs.ThumbnailBar.prototype.setLayout = function(layout) {
       var cont = this.container;
       var ths = $('.view-thumbnail', cont);

       this.layout = layout;

       if (layout === 'vertical') {

         cont.removeClass("view-thumbnailsbar-x");
         cont.addClass("view-thumbnailsbar-y");
         ths.removeClass("view-thumbnail-x");
         ths.addClass("view-thumbnail-y");

       } else if (layout === 'horizontal') {

         cont.removeClass("view-thumbnailsbar-y");
         cont.addClass("view-thumbnailsbar-x");
         ths.removeClass("view-thumbnail-y");
         ths.addClass("view-thumbnail-x");

       } else if (layout === 'grid') {
         cont.removeClass("view-thumbnailsbar-y view-thumbnailsbar-x");
         ths.removeClass("view-thumbnail-y");
         ths.addClass("view-thumbnail-x");
       }

       this.setPosition(this.position);
     };

    /**
     * Set a new css position for the thumbnails bar.
     *
     * @param {Object} css position object with possible properties: "top", "bottom", "left" and "right".
     */
     thbarjs.ThumbnailBar.prototype.setPosition = function(pos) {
       var cont = this.container;
       var layout = this.layout;
       var t = "", r = "", b = "", l = "";

       if (pos) {

         if (pos.top) {
           this.position.top = pos.top;
           cont.css({ top: pos.top });
           t = ' - ' + pos.top;
         }

         if (pos.right) {
           this.position.right = pos.right;
           cont.css({ right: pos.right });
           r = ' - ' + pos.right;
         }

         if (pos.bottom) {
           this.position.bottom = pos.bottom;
           cont.css({ bottom: pos.bottom });
           b = ' - ' + pos.bottom;
         }

         if (pos.left) {
           this.position.left = pos.left;
           cont.css({ left: pos.left });
           l = ' - ' + pos.left;
         }

         if ((layout === 'vertical') && (t || b)) {
           cont.css({ height: 'calc(100%' + t + b + ')' });

         } else if ((layout === 'horizontal') && (r || l)) {
           cont.css({ width: 'calc(100%' + r + l + ')' });

         } else if (layout === 'grid') {

           if (t || b) {
             cont.css({ height: 'calc(100%' + t + b + ')' });
           }

           if (r || l) {
             cont.css({ width: 'calc(100%' + r + l + ')' });
           }
         }
       }
     };

    /**
    * This method is called just before dropping a moving thumbnail's visual element on a complementary
    * jQuery UI's sortable element.
     *
     * @param {Object} jQuery UI event object.
     * @param {Object} jQuery UI ui object.
     */
     thbarjs.ThumbnailBar.prototype.onBeforeStop = function(evt, ui) {

       console.log('onBeforeStop not overwritten!');
       console.log('event obj: ', evt);
       console.log('ui obj: ', ui);
     };

   /**
    * Set complementary jQuery UI sortable elements which the moving helper can be visually appended to.
    *
    * @param {String} css selector indicating the complementary sortable elements.
    */
    thbarjs.ThumbnailBar.prototype.setComplementarySortableElems = function(cssSelector) {

      // the moving helper element can be appended to these elements
      this.jqSortable.sortable( "option", "appendTo", cssSelector);

      // connect with these sortable elements
      this.jqSortable.sortable( "option", "connectWith", cssSelector);
    };

    /**
     * Return a thumbnail's container DOM id.
     *
     * @param {Number} thumbnail's integer id.
     * @return {String} the thumbnail's container DOM id.
     */
     thbarjs.ThumbnailBar.prototype.getThumbnailContId = function(thumbnailId) {

       // the thumbnail's container DOM id is related to the thumbnail's integer id
       return this.thumbnailsIdPrefix + thumbnailId;
    };

    /**
     * Returns a thumbnail's integer id.
     *
     * @param {String} thumbnail's container DOM id.
     * @return {Number} thumbnail's integer id.
     */
     thbarjs.ThumbnailBar.prototype.getThumbnailId = function(thumbnailContId) {

       // the thumbnail's integer id is related to the thumbnail's container DOM id
       return  parseInt(thumbnailContId.replace(this.thumbnailsIdPrefix, ""));
    };

    /**
     * Create and add a thumbnail to the thumbnails bar.
     *
     * @param {Oject} Image file object with the properties:
     *  -id: Integer, the object's id
     *  -baseUrl: String ‘directory/containing/the/files’
     *  -imgType: String neuroimage type. Any of the possible values returned by rendererjs.Renderer.imgType
     *  -files: Array of HTML5 File objects or custom file objects with properties:
     *     -remote: a boolean indicating whether the file has not been read locally (with a filepicker)
     *     -url the file's url
     *     -cloudId: the id of the file in a cloud storage system if stored in the cloud
     *     -name: file name
     *  The files array contains a single file for imgType different from 'dicom' or 'dicomzip'
     *  -thumbnail: Optional HTML5 File or custom file object (optional jpg file for a thumbnail image)
     * @param {Function} optional callback to be called when the thumbnail has been added
     */
     thbarjs.ThumbnailBar.prototype.addThumbnail = function(imgFileObj, callback) {
       var fname, info, title;
       var id = imgFileObj.id;
       var self = this;

       // we assume the name of an already existing thumbnail (eg. generated on the server side) is of the form:
       // 1.3.12.2.1107.5.2.32.35288.30000012092602261631200043880-AXIAL_RFMT_MPRAGE-Sag_T1_MEMPRAGE_1_mm_4e_nomoco.jpg
       if (imgFileObj.thumbnail) {
         fname = imgFileObj.thumbnail.name;
       } else if (imgFileObj.imgType !== 'dicom'){
         fname = imgFileObj.files[0].name;
       } else {
         fname = ''; title = ''; info = '';
       }

       if (fname) {
         if (fname.lastIndexOf('-') !== -1) {
           title = fname.substring(0, fname.lastIndexOf('.'));
           title = title.substring(title.lastIndexOf('-') + 1);
           info = title.substr(0, 10);
         } else {
           title = fname;
           info = fname.substring(0, fname.lastIndexOf('.')).substr(-10);
         }
       }

       // append this thumbnail to the sortable div within the thumbnails bar
       var jqTh = $(
         '
' +
           '' +
           '
' + info + '
' +
         '
'
       );
       self.jqSortable.append(jqTh);

       if (imgFileObj.thumbnail) {

         self.readThumbnail(imgFileObj.thumbnail, $('.view-thumbnail-img', jqTh), function() {

           if (callback) {callback();}
         });

       } else {

         self.createThumbnail(imgFileObj, $('.view-thumbnail-img', jqTh), function() {

           if (callback) {callback();}
         });
       }
     };

     /**
      * Load the thumbnail corresponding to the imgFileObj argument. If there is a thumbnail
      * property in the imgFileObj then load it otherwise automatically create the thumbnail
      * from an internal renderer's canvas object
      *
      * @param {Oject} HTML5 File object or custom file object with properties:
      *   -remote: a boolean indicating whether the file has not been read locally (with a filepicker)
      *   -url the file's url
      *   -cloudId: the id of the file in a cloud storage system if stored in the cloud
      *   -name: file name
      * @param {Function} jQuery object for the thumbnail's  element.
      * @param {Function} callback to be called when the thumbnail has been loaded.
      */
      thbarjs.ThumbnailBar.prototype.loadThumbnail = function(thFile, jqImg, callback) {

        // renderer options object
        var options = {
          container: null,
          rendererId: '',
        };

        var tmpRenderer = new renderer.Renderer(options, this.fileManager);

        tmpRenderer.readFile(thFile, 'readAsDataURL', function(thData) {

          jqImg.attr('src', thData);
          if (callback) {callback();}
        });
      };

    /**
     * Load the thumbnail corresponding to the imgFileObj argument. If there is a thumbnail
     * property in the imgFileObj then load it otherwise automatically create the thumbnail
     * from the canvas of an internal renderer object.
     *
     * @param {Oject} Image file object as in the addThumbnail method.
     * @param {Function} jQuery object for the thumbnail's  element.
     * @param {Function} callback to be called when the thumbnail has been craated.
     */
     thbarjs.ThumbnailBar.prototype.createThumbnail = function(imgFileObj, jqImg, callback) {
       var self = this;

       // append a container for the internal temporal renderer
       var tempRenderCont = $('

');
       self.container.append(tempRenderCont);

       // renderer options object
       var options = {
         container: tempRenderCont[0],
         rendererId: self.thumbnailsIdPrefix + '_tmprenderer' + imgFileObj.id, // for the internal XTK renderer container
       };

       // append a container for the temporal renderer's internal XTK renderer
       tempRenderCont.append('

');

       // make div for the renderer's canvas the same size as the  element
       var imgWidth = jqImg.css('width');
       var imgHeight = jqImg.css('height');
       $('#' + options.rendererId).css({ width: imgWidth, height: imgHeight });

       // create the temporal renderer object
       var tmpRenderer = new renderer.Renderer(options, self.fileManager);

       tmpRenderer.imgFileObj = imgFileObj;
       tmpRenderer.createRenderer();
       tmpRenderer.createVolume();

       tmpRenderer.readVolumeFiles( function() {

         tmpRenderer.renderVolume( function() {

           tmpRenderer.getThumbnail( function(thData) {

             jqImg.attr('src', thData);

             if (callback) {callback();}

             // destroy this renderer
             tmpRenderer.destroy();
             tempRenderCont.remove();
           });
         });
       });
     };

    /**
     * Remove event handlers and html interface.
     */
     thbarjs.ThumbnailBar.prototype.destroy = function() {

       this.numThumbnails = 0;
       this.numOfLoadedThumbnails = 0;
       this.container.empty();
       this.container = null;
     };

    return thbarjs;
  });
<|endoftext|>


<commit_before>'use strict'

/**
 * adonis-commands
 * Copyright(c) 2015-2015 Harminder Virk
 * MIT Licensed
*/
/* global it,describe,context,before,after */
const Ioc = require('adonis-fold').Ioc
const chai = require('chai')
const expect = chai.expect
const path = require('path')
const fs = require('co-fs-extra')
require('co-mocha')

const GeneratorHelpers = require('../src/Generators/helpers')
const ControllerGenerator = require('../src/Generators/Controller')
const CommandGenerator = require('../src/Generators/Command')
const MiddlewareGenerator = require('../src/Generators/Middleware')
const ModelGenerator = require('../src/Generators/Model')

let globalError = ''
let globalSuccess = ''

describe('Generators', function () {
  before(function () {
    Ioc.bind('Adonis/Src/Ansi', function () {
      return {
        error: function (error) {
          globalError = error
        },
        success: function (success) {
          globalSuccess = success
        }
      }
    })
    Ioc.alias('Ansi', 'Adonis/Src/Ansi')
  })
  context('Helpers', function () {
    before(function * () {
      yield fs.emptydir(path.join(__dirname, './blueprints'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './blueprints'))
    })

    it('should join entity and name to form new name in pascal case', function () {
      const thisName = 'user'
      const newName = GeneratorHelpers.makeName(thisName, 'Controller')
      expect(newName).to.equal('UserController')
    })

    it('should remove entity name from actual name', function () {
      const thisName = 'userController'
      const newName = GeneratorHelpers.makeName(thisName, 'Controller')
      expect(newName).to.equal('UserController')
    })

    it('should remove entity name passed as snakeCase from actual name', function () {
      const thisName = 'user_Controller'
      const newName = GeneratorHelpers.makeName(thisName, 'Controller')
      expect(newName).to.equal('UserController')
    })

    it('should remove entity name when true is passed as 3rd argument', function () {
      const thisName = 'user'
      const newName = GeneratorHelpers.makeName(thisName, 'Model', true)
      expect(newName).to.equal('User')
    })

    it("should make controller method by passing it's name", function () {
      const name = 'index'
      const method = GeneratorHelpers.makeControllerMethod(name)
      expect(method.trim()).to.equal(`* ${name} (request, response) {}`)
    })

    it('should generate blueprint with given content to a given path', function * () {
      const name = 'UserController'
      const contents = 'module.exports = function ({})'
      const response = yield GeneratorHelpers.generateBlueprint(contents, path.join(__dirname, './blueprints/userController.js'), name)
      expect(response).to.match(/Created UserController/)
    })

    it('should generate blueprint and return message should have entity name inside it', function * () {
      const name = 'NewController'
      const contents = 'module.exports = function ({})'
      const response = yield GeneratorHelpers.generateBlueprint(contents, path.join(__dirname, './blueprints/NewController.js'), name, 'controller')
      expect(response).to.match(/Created NewController\.js controller/)
    })

    it('should throw an error when file already exists', function * () {
      const name = 'UserController'
      const contents = 'module.exports = function ({})'
      try {
        yield GeneratorHelpers.generateBlueprint(contents, path.join(__dirname, './blueprints/userController.js'), name)
      } catch (e) {
        expect(e.message).to.match(/I am afraid/)
      }
    })
  })

  context('Commands', function () {
    const Helpers = {
      appPath: function () {
        return __dirname
      }
    }
    before(function * () {
      Ioc.bind('Adonis/Src/Helpers', function () {
        return Helpers
      })
      yield fs.emptydir(path.join(__dirname, './Commands'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './Commands'))
    })

    it('should generate a new command using command handle method', function * () {
      yield CommandGenerator.handle({name: 'Greet'})
      expect(globalSuccess).to.match(/Created Greet\.js command/)
      const Command = require(path.join(__dirname, './Commands/Greet.js'))
      expect(Command.description).to.be.a('string')
      expect(Command.signature).to.be.a('string')
      expect(new Command().handle).to.be.a('function')
    })

    it('should handle error silently and make use of console error method to print the error', function * () {
      yield CommandGenerator.handle({name: 'Greet'}, {})
      expect(globalError).to.match(/I am afraid Greet.js already exists/)
    })
  })

  context('Controllers', function () {
    const Helpers = {
      appPath: function () {
        return __dirname
      }
    }

    before(function * () {
      Ioc.bind('Adonis/Src/Helpers', function () {
        return Helpers
      })
      yield fs.emptydir(path.join(__dirname, './Http/Controllers'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './Http/Controllers'))
    })

    it('should generate a new controller using controller handle method', function * () {
      yield ControllerGenerator.handle({name: 'User'}, {})
      expect(globalSuccess).to.match(/Created UserController\.js controller/)
      const UserController = require(path.join(__dirname, './Http/Controllers/UserController.js'))
      const user = new UserController()
      expect(user.index).to.be.a('function')
      expect(user.show).to.be.a('function')
      expect(user.create).to.be.a('function')
      expect(user.store).to.be.a('function')
      expect(user.update).to.be.a('function')
      expect(user.destroy).to.be.a('function')
    })

    it('should generate a plain controller when plain flag is passed', function * () {
      yield ControllerGenerator.handle({name: 'Accounts'}, {plain: true})
      const AccountsController = require(path.join(__dirname, './Http/Controllers/AccountsController.js'))
      const accounts = new AccountsController()
      expect(accounts.index).to.equal(undefined)
      expect(accounts.create).to.equal(undefined)
      expect(accounts.store).to.equal(undefined)
      expect(accounts.show).to.equal(undefined)
      expect(accounts.update).to.equal(undefined)
      expect(accounts.destroy).to.equal(undefined)
    })

    it('should handle error silently and make use of console error method to print the error', function * () {
      yield ControllerGenerator.handle({name: 'Accounts'}, {})
      expect(globalError).to.match(/I am afraid AccountsController.js already exists/)
    })
  })

  context('Middleware', function () {
    const Helpers = {
      appPath: function () {
        return __dirname
      }
    }

    before(function * () {
      Ioc.bind('Adonis/Src/Helpers', function () {
        return Helpers
      })
      yield fs.emptydir(path.join(__dirname, './Http/Middleware'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './Http/Middleware'))
    })

    it('should generate a new middleware using middleware handle method', function * () {
      yield MiddlewareGenerator.handle({name: 'CorsMiddleware'}, {})
      expect(globalSuccess).to.match(/Created Cors\.js middleware/)
      const Cors = require(path.join(__dirname, './Http/Middleware/Cors.js'))
      const cors = new Cors()
      expect(cors.handle).to.be.a('function')
    })

    it('should handle error silently and make use of console error method to print the error', function * () {
      yield MiddlewareGenerator.handle({name: 'CorsMiddleware'}, {})
      expect(globalError).to.match(/I am afraid Cors.js already exists/)
    })
  })

  context('Model', function () {
    const Helpers = {
      appPath: function () {
        return __dirname
      }
    }

    class Lucid {
    }

    before(function * () {
      Ioc.bind('Adonis/Src/Helpers', function () {
        return Helpers
      })
      Ioc.bind('Lucid', function () {
        return Lucid
      })
      yield fs.emptydir(path.join(__dirname, './Model'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './Model'))
    })

    it('should generate a new model using model handle method', function * () {
      yield ModelGenerator.handle({name: 'UserModel'}, {})
      expect(globalSuccess).to.match(/Created User\.js model/)
      const User = require(path.join(__dirname, './Model/User.js'))
      const user = new User()
      expect(user instanceof Lucid).to.equal(true)
    })

    it('should handle error silently and make use of console error method to print the error', function * () {
      yield ModelGenerator.handle({name: 'UserModel'}, {})
      expect(globalError).to.match(/I am afraid User.js already exists/)
    })
  })
})
<commit_msg>test(controller): change test according to the new method<commit_after>'use strict'

/**
 * adonis-commands
 * Copyright(c) 2015-2015 Harminder Virk
 * MIT Licensed
*/
/* global it,describe,context,before,after */
const Ioc = require('adonis-fold').Ioc
const chai = require('chai')
const expect = chai.expect
const path = require('path')
const fs = require('co-fs-extra')
require('co-mocha')

const GeneratorHelpers = require('../src/Generators/helpers')
const ControllerGenerator = require('../src/Generators/Controller')
const CommandGenerator = require('../src/Generators/Command')
const MiddlewareGenerator = require('../src/Generators/Middleware')
const ModelGenerator = require('../src/Generators/Model')

let globalError = ''
let globalSuccess = ''

describe('Generators', function () {
  before(function () {
    Ioc.bind('Adonis/Src/Ansi', function () {
      return {
        error: function (error) {
          globalError = error
        },
        success: function (success) {
          globalSuccess = success
        }
      }
    })
    Ioc.alias('Ansi', 'Adonis/Src/Ansi')
  })
  context('Helpers', function () {
    before(function * () {
      yield fs.emptydir(path.join(__dirname, './blueprints'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './blueprints'))
    })

    it('should join entity and name to form new name in pascal case', function () {
      const thisName = 'user'
      const newName = GeneratorHelpers.makeName(thisName, 'Controller')
      expect(newName).to.equal('UserController')
    })

    it('should remove entity name from actual name', function () {
      const thisName = 'userController'
      const newName = GeneratorHelpers.makeName(thisName, 'Controller')
      expect(newName).to.equal('UserController')
    })

    it('should remove entity name passed as snakeCase from actual name', function () {
      const thisName = 'user_Controller'
      const newName = GeneratorHelpers.makeName(thisName, 'Controller')
      expect(newName).to.equal('UserController')
    })

    it('should remove entity name when true is passed as 3rd argument', function () {
      const thisName = 'user'
      const newName = GeneratorHelpers.makeName(thisName, 'Model', true)
      expect(newName).to.equal('User')
    })

    it("should make controller method by passing it's name", function () {
      const name = 'index'
      const method = GeneratorHelpers.makeControllerMethod(name)
      expect(method.trim()).to.equal(`* ${name} (request, response) {}`)
    })

    it('should generate blueprint with given content to a given path', function * () {
      const name = 'UserController'
      const contents = 'module.exports = function ({})'
      const response = yield GeneratorHelpers.generateBlueprint(contents, path.join(__dirname, './blueprints/userController.js'), name)
      expect(response).to.match(/Created UserController/)
    })

    it('should generate blueprint and return message should have entity name inside it', function * () {
      const name = 'NewController'
      const contents = 'module.exports = function ({})'
      const response = yield GeneratorHelpers.generateBlueprint(contents, path.join(__dirname, './blueprints/NewController.js'), name, 'controller')
      expect(response).to.match(/Created NewController\.js controller/)
    })

    it('should throw an error when file already exists', function * () {
      const name = 'UserController'
      const contents = 'module.exports = function ({})'
      try {
        yield GeneratorHelpers.generateBlueprint(contents, path.join(__dirname, './blueprints/userController.js'), name)
      } catch (e) {
        expect(e.message).to.match(/I am afraid/)
      }
    })
  })

  context('Commands', function () {
    const Helpers = {
      appPath: function () {
        return __dirname
      }
    }
    before(function * () {
      Ioc.bind('Adonis/Src/Helpers', function () {
        return Helpers
      })
      yield fs.emptydir(path.join(__dirname, './Commands'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './Commands'))
    })

    it('should generate a new command using command handle method', function * () {
      yield CommandGenerator.handle({name: 'Greet'})
      expect(globalSuccess).to.match(/Created Greet\.js command/)
      const Command = require(path.join(__dirname, './Commands/Greet.js'))
      expect(Command.description).to.be.a('string')
      expect(Command.signature).to.be.a('string')
      expect(new Command().handle).to.be.a('function')
    })

    it('should handle error silently and make use of console error method to print the error', function * () {
      yield CommandGenerator.handle({name: 'Greet'}, {})
      expect(globalError).to.match(/I am afraid Greet.js already exists/)
    })
  })

  context('Controllers', function () {
    const Helpers = {
      appPath: function () {
        return __dirname
      }
    }

    before(function * () {
      Ioc.bind('Adonis/Src/Helpers', function () {
        return Helpers
      })
      yield fs.emptydir(path.join(__dirname, './Http/Controllers'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './Http/Controllers'))
    })

    it('should generate a new controller using controller handle method', function * () {
      yield ControllerGenerator.handle({name: 'User'}, {})
      expect(globalSuccess).to.match(/Created UserController\.js controller/)
      const UserController = require(path.join(__dirname, './Http/Controllers/UserController.js'))
      const user = new UserController()
      expect(user.index).to.be.a('function')
      expect(user.show).to.be.a('function')
      expect(user.create).to.be.a('function')
      expect(user.store).to.be.a('function')
      expect(user.edit).to.be.a('function')
      expect(user.update).to.be.a('function')
      expect(user.destroy).to.be.a('function')
    })

    it('should generate a plain controller when plain flag is passed', function * () {
      yield ControllerGenerator.handle({name: 'Accounts'}, {plain: true})
      const AccountsController = require(path.join(__dirname, './Http/Controllers/AccountsController.js'))
      const accounts = new AccountsController()
      expect(accounts.index).to.equal(undefined)
      expect(accounts.create).to.equal(undefined)
      expect(accounts.store).to.equal(undefined)
      expect(accounts.show).to.equal(undefined)
      expect(accounts.edit).to.equal(undefined)
      expect(accounts.update).to.equal(undefined)
      expect(accounts.destroy).to.equal(undefined)
    })

    it('should handle error silently and make use of console error method to print the error', function * () {
      yield ControllerGenerator.handle({name: 'Accounts'}, {})
      expect(globalError).to.match(/I am afraid AccountsController.js already exists/)
    })
  })

  context('Middleware', function () {
    const Helpers = {
      appPath: function () {
        return __dirname
      }
    }

    before(function * () {
      Ioc.bind('Adonis/Src/Helpers', function () {
        return Helpers
      })
      yield fs.emptydir(path.join(__dirname, './Http/Middleware'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './Http/Middleware'))
    })

    it('should generate a new middleware using middleware handle method', function * () {
      yield MiddlewareGenerator.handle({name: 'CorsMiddleware'}, {})
      expect(globalSuccess).to.match(/Created Cors\.js middleware/)
      const Cors = require(path.join(__dirname, './Http/Middleware/Cors.js'))
      const cors = new Cors()
      expect(cors.handle).to.be.a('function')
    })

    it('should handle error silently and make use of console error method to print the error', function * () {
      yield MiddlewareGenerator.handle({name: 'CorsMiddleware'}, {})
      expect(globalError).to.match(/I am afraid Cors.js already exists/)
    })
  })

  context('Model', function () {
    const Helpers = {
      appPath: function () {
        return __dirname
      }
    }

    class Lucid {
    }

    before(function * () {
      Ioc.bind('Adonis/Src/Helpers', function () {
        return Helpers
      })
      Ioc.bind('Lucid', function () {
        return Lucid
      })
      yield fs.emptydir(path.join(__dirname, './Model'))
    })

    after(function * () {
      yield fs.emptydir(path.join(__dirname, './Model'))
    })

    it('should generate a new model using model handle method', function * () {
      yield ModelGenerator.handle({name: 'UserModel'}, {})
      expect(globalSuccess).to.match(/Created User\.js model/)
      const User = require(path.join(__dirname, './Model/User.js'))
      const user = new User()
      expect(user instanceof Lucid).to.equal(true)
    })

    it('should handle error silently and make use of console error method to print the error', function * () {
      yield ModelGenerator.handle({name: 'UserModel'}, {})
      expect(globalError).to.match(/I am afraid User.js already exists/)
    })
  })
})
<|endoftext|>


<commit_before>function handlePaste() {
	$('#gnupg').attr('rows', 10)
}

function resetForm() {
	$('#name').val("")
	$('#email').val("")
	$('#gpgform').val("")
	$('#gpgform').fadeOut(1000)
}

function checkFilled() {
	if($('#email').val() != ""){
		$('#gpgform').fadeIn(1000)
		stateToggle = true
	}
	if($('#email').val() == "" && stateToggle){
		$('#gpgform').fadeOut(1000)
		stateToggle = false
	}
}

function showTimeline() {
	$('#timeline').fadeIn(1000)
}

function getUrlVars() {
	var vars = {};
	var parts = window.location.href.replace(/[?&]+([^=&#]+)=([^&#]*)/gi, function(m,key,value) {
	vars[key] = value;
	});
	return vars;
}

var stateToggle = false

if(getUrlVars()['show'] == "error"){
	if(getUrlVars()['type'] == "name"){
		//name empty
		document.getElementById('status').innerHTML = 'Name fehlerhaft!'
	}else if (getUrlVars()['type'] == "email"){
		//email empty
		document.getElementById('status').innerHTML = 'E-Mail fehlerhaft!'
	}else if(getUrlVars()['type'] == "message"){
		//message empty
		document.getElementById('status').innerHTML = 'Nachricht fehlerhaft!'
	}else if (getUrlVars()['type'] == "gpg"){
		//GPG fehlerhaft
		document.getElementById('status').innerHTML = 'Dein GnuPG Key scheint fehlerhaft zu sein!'
	}else{
		document.getElementById('status').innerHTML = 'Error!'
	}
}else if(getUrlVars()['show'] == "success"){
	//success
	document.getElementById('status').innerHTML = 'Deine Nachricht wurde gesendet!'
}<commit_msg>changes in custom js<commit_after>function handlePaste() {
	$('#gnupg').attr('rows', 10)
}

function resetForm() {
	$('#name').val("")
	$('#email').val("")
	$('#gpgform').val("")
	$('#gpgform').fadeOut(1000)
}

function checkFilled() {
	if($('#email').val() != ""){
		$('#gpgform').fadeIn(1000)
		stateToggle = true
	}
	if($('#email').val() == "" && stateToggle){
		$('#gpgform').fadeOut(1000)
		stateToggle = false
	}
	if($('#message').val() != ""){

	}
}

function showTimeline() {
	$('#timeline').fadeIn(1000)
}

function getUrlVars() {
	var vars = {};
	var parts = window.location.href.replace(/[?&]+([^=&#]+)=([^&#]*)/gi, function(m,key,value) {
	vars[key] = value;
	});
	return vars;
}

var stateToggle = false

if(getUrlVars()['show'] == "error"){
	if(getUrlVars()['type'] == "name"){
		//name empty
		document.getElementById('status').innerHTML = 'Name fehlerhaft!'
	}else if (getUrlVars()['type'] == "email"){
		//email empty
		document.getElementById('status').innerHTML = 'E-Mail fehlerhaft!'
	}else if(getUrlVars()['type'] == "message"){
		//message empty
		document.getElementById('status').innerHTML = 'Nachricht fehlerhaft!'
	}else if (getUrlVars()['type'] == "gpg"){
		//GPG fehlerhaft
		document.getElementById('status').innerHTML = 'Dein GnuPG Key scheint fehlerhaft zu sein!'
	}else{
		document.getElementById('status').innerHTML = 'Error!'
	}
}else if(getUrlVars()['show'] == "success"){
	//success
	document.getElementById('status').innerHTML = 'Deine Nachricht wurde gesendet!'
}<|endoftext|>