#
# Modules
#

readdirp     = require('readdirp')
path         = require('path')
es           = require('event-stream')
coffeescript = require('coffee-script')
_            = require('underscore')

#
# Parsers
#

frontMatterParser = require('./parsers/front_matter_parser')
markdownParser    = require('./parsers/markdown_parser')
fileParser        = require('./parsers/file_parser')
linkParser        = require('./parsers/link_parser')

F =
  failed: null

App =
  analyze: ->
    readdirp @readOpts(), (file) =>
      _.each @parsers, (parser) =>
        failed = F.failed
        F.failed = parser.parse(file, failed)
    , (err, res) =>
      if F.failed then process.exit(1) else process.exit(0)

  parsers: [frontMatterParser, markdownParser, fileParser]
  #parsers: [fileParser]

  # Uncomment for production files
  directoryFilters: ['!node_modules', '!Release Notes']
  fileFilters: '*.md'

  # Uncomment for test files
  #directoryFilters: ['Accounts & Users']
  #fileFilters: 'creating-users.md'

  readOpts: ->
    root: path.join(__dirname, '..')
    fileFilter: @fileFilters
    directoryFilter: @directoryFilters

App.analyze()

#
# Modules
#

readdirp     = require('readdirp')
path         = require('path')
es           = require('event-stream')
coffeescript = require('coffee-script')
fs           = require('graceful-fs')
_            = require('underscore')

#
# Parsers
#

frontMatterParser = require('./parsers/front_matter_parser')
markdownParser    = require('./parsers/markdown_parser')
fileParser        = require('./parsers/file_parser')
linkParser        = require('./parsers/link_parser')

F =
  failed: null

Ignored =
  files: []

App =
  analyze: ->
    @loadIgnored()
    readdirp @readOpts(), (file) =>
      return if @fileIsIgnored file.name
      _.each @parsers, (parser) =>
        failed = F.failed
        F.failed = parser.parse(file, failed)
    , (err, res) =>
      if F.failed then process.exit(1) else process.exit(0)

  parsers: [frontMatterParser, markdownParser, fileParser]
  #parsers: [fileParser]

  # Uncomment for production files
  directoryFilters: ['!node_modules', '!Release Notes']
  fileFilters: '*.md'

  # Uncomment for test files
  #directoryFilters: ['Accounts & Users']
  #fileFilters: '!sinatra.md'

  readOpts: ->
    root: path.join(__dirname, '..')
    fileFilter: @fileFilters
    directoryFilter: @directoryFilters

  fileIsIgnored: (file) ->
    _.indexOf(Ignored.files, file) >= 0

  loadIgnored: ->
    files = fs.readFileSync 'commit_analyzer_ignore.txt', 'utf-8'
    files = files.split('\n')
    _.each files, (file) -> Ignored.files.push file

App.analyze()

Support a commit_analyzer_ignore.txt file in project root


describe 'NoFlo UI initialization', ->
  win = null
  doc = null
  db = null
  before (done) ->
    @timeout 20000
    iframe = document.getElementById 'app'
    iframe.src = '../app.html'
    iframe.onload = ->
      win = iframe.contentWindow
      doc = iframe.contentDocument
      setTimeout ->
        done()
      , 3000
  it 'should start with the main screen', ->
    chai.expect(win.location.hash).to.equal ''
  it 'should have created the IndexedDB database', (done) ->
    chai.expect(win.indexedDB).to.be.an 'object'
    req = win.indexedDB.open 'noflo-ui', 3
    req.onerror = ->
      chai.expect(true).to.equal false
      done()
    req.onsuccess = (event) ->
      db = event.target.result
      chai.expect(db).to.be.an 'object'
      db.close()
      done()
  it 'should have created the object stores', (done) ->
    req = win.indexedDB.open 'noflo-ui', 3
    req.onerror = ->
      chai.expect(true).to.equal false
      done()
    req.onsuccess = (event) ->
      db = event.target.result
      chai.expect(db.objectStoreNames.contains('projects')).to.equal true
      chai.expect(db.objectStoreNames.contains('graphs')).to.equal true
      chai.expect(db.objectStoreNames.contains('components')).to.equal true
      chai.expect(db.objectStoreNames.contains('runtimes')).to.equal true
      db.close()
      done()

describe 'NoFlo UI initialization', ->
  win = null
  doc = null
  db = null
  before (done) ->
    @timeout 20000
    iframe = document.getElementById 'app'
    iframe.src = '../app.html'
    iframe.onload = ->
      win = iframe.contentWindow
      doc = iframe.contentDocument
      setTimeout ->
        done()
      , 1000
  after ->
    db.close()

  it 'should start with the main screen', ->
    chai.expect(win.location.hash).to.equal ''
  it 'should have created the IndexedDB database', (done) ->
    chai.expect(win.indexedDB).to.be.an 'object'
    req = win.indexedDB.open 'noflo-ui', 3
    req.onerror = ->
      chai.expect(true).to.equal false
      done()
    req.onsuccess = (event) ->
      db = event.target.result
      chai.expect(db).to.be.an 'object'
      done()
  it 'should have created the project store', ->
    chai.expect(db.objectStoreNames.contains('projects')).to.equal true
  it 'should have created the graph store', ->
    chai.expect(db.objectStoreNames.contains('graphs')).to.equal true
  it 'should have created the component store', ->
    chai.expect(db.objectStoreNames.contains('components')).to.equal true
  it 'should have created the runtime store', ->
    chai.expect(db.objectStoreNames.contains('runtimes')).to.equal true

Split store checks to separate tests to get better output from CI


{View} = require 'atom'

# Status bar view for the soft wrap indicator.
module.exports =
class SoftWrapIndicatorView extends View
  @content: ->
    @div class: 'inline-block', =>
      @a 'Wrap', class: 'soft-wrap-indicator', outlet: 'light'

  # Initializes the view by subscribing to various events.
  #
  # statusBar - {StatusBar} of the application
  initialize: (@statusBar) ->
    @subscribe @statusBar, 'active-buffer-changed', @update

    atom.workspace.eachEditor (editor) =>
      @subscribe editor.displayBuffer, 'soft-wrap-changed', @update

    @subscribe this, 'click', => @getActiveEditor()?.toggleSoftWrap()

  # Gets the currently active `Editor`.
  #
  # Returns the {Editor} that is currently active or `null` if there is not one active.
  getActiveEditor: ->
    atom.workspace.getActiveEditor()

  # Updates the indicator based on the current state of the application.
  update: =>
    if @getActiveEditor()?.getSoftWrap()
      @light.addClass('lit').show()
    else if @getActiveEditor()?
      @light.removeClass('lit').show()
    else
      @light.hide()

  # Tear down any state and detach.
  destroy: ->
    @remove()

{View} = require 'atom'

# Status bar view for the soft wrap indicator.
module.exports =
class SoftWrapIndicatorView extends View
  @content: ->
    @div class: 'inline-block', =>
      @a 'Wrap', class: 'soft-wrap-indicator', outlet: 'light'

  # Initializes the view by subscribing to various events.
  #
  # statusBar - {StatusBar} of the application
  initialize: (@statusBar) ->
    @subscribe @statusBar, 'active-buffer-changed', @update

    atom.workspace.eachEditor (editor) =>
      @subscribe editor.displayBuffer, 'soft-wrap-changed', @update

    @subscribe this, 'click', => @getActiveEditor()?.toggleSoftWrap()

  # Internal: Executes after the view is added to the status bar.
  afterAttach: ->
    @update()

  # Gets the currently active `Editor`.
  #
  # Returns the {Editor} that is currently active or `null` if there is not one active.
  getActiveEditor: ->
    atom.workspace.getActiveEditor()

  # Updates the indicator based on the current state of the application.
  update: =>
    if @getActiveEditor()?.getSoftWrap()
      @light.addClass('lit').show()
    else if @getActiveEditor()?
      @light.removeClass('lit').show()
    else
      @light.hide()

  # Tear down any state and detach.
  destroy: ->
    @remove()

:bug: Update indicator when first attached to status bar


Path = require 'path'
{CompositeDisposable, Emitter} = require 'atom'

{LinterTrace, LinterMessage, LinterError, LinterWarning} = require './messages'

class Linter
  constructor: ->
    @Emitter = new Emitter
    @SubRegular = new CompositeDisposable
    @SubFly = new CompositeDisposable

Path = require 'path'
{CompositeDisposable, Emitter} = require 'atom'

{LinterTrace, LinterMessage, LinterError, LinterWarning} = require './messages'

class Linter

  constructor: ->
    @Emitter = new Emitter
    @Subscriptions = new CompositeDisposable
    @SubscriptionsFly = new CompositeDisposable # Fly needs to be kept separate from all others
    @Editors = new Map # I <3 ES6

  getActiveEditorLinter:->
    ActiveEditor = atom.workspace.getActiveEditor()
    return ActiveEditor unless ActiveEditor
    return @Editors.get ActiveEditor

  getEditorLinter:(Editor)->
    return @Editors.get Editor

  observeEditorLinters:(Callback)->
    @Emitter.on 'linters-observe', Callback

  onDidAddEditorLinter:(Callback)->
    @Emitter.on 'linter-add', Callback

  onDidRemoveEditorLinter:(Callback)->
    @Emitter.on 'linter-remove', Callback

Add a Basic API Structure

:new: Add a Basic API Structure


{CompositeDisposable} = require 'atom'
{View, $} = require 'atom-space-pen-views'

module.exports =
class ToolbarButtonView extends View
  @content: ->
    @div class: 'icon'

  initialize: (icon, callback, tooltip = null, iconset = null) ->
    @subscriptions = new CompositeDisposable

    iconClass = if !iconset then 'icon-' + icon else iconset + '-' + icon

    @addClass 'icon ' + iconClass

    if tooltip
      @prop 'title', tooltip
      @subscriptions.add atom.tooltips.add(@, title: tooltip)

    if iconset
      @addClass iconset

    @on 'click', =>

      @previouslyFocusedElement = $(document.activeElement);

      if @previouslyFocusedElement[0] and @previouslyFocusedElement[0] isnt document.body
        @eventElement = @previouslyFocusedElement[0]
      else
        @eventElement = atom.views.getView(atom.workspace)

      if !@hasClass('disabled')
        if typeof(callback) == 'string'
          atom.commands.dispatch @eventElement, callback
        else
          callback()

  setEnabled: (enabled) ->
    if enabled
      @removeClass 'disabled'
    else
      @addClass 'disabled'

  destroy: ->
    @subscriptions.dispose()

{CompositeDisposable} = require 'atom'
{View} = require 'atom-space-pen-views'

module.exports =
class ToolbarButtonView extends View
  @content: ->
    @div class: 'icon'

  initialize: (icon, callback, tooltip = null, iconset = null) ->
    @subscriptions = new CompositeDisposable

    iconClass = if !iconset then 'icon-' + icon else iconset + '-' + icon

    @addClass 'icon ' + iconClass

    if tooltip
      @prop 'title', tooltip
      @subscriptions.add atom.tooltips.add(@, title: tooltip)

    if iconset
      @addClass iconset

    @on 'click', =>
      if !@hasClass('disabled')
        if typeof(callback) == 'string'
          atom.commands.dispatch document.activeElement, callback
        else
          callback()

  setEnabled: (enabled) ->
    if enabled
      @removeClass 'disabled'
    else
      @addClass 'disabled'

  destroy: ->
    @subscriptions.dispose()

Simplify getting command dispatch target


{exec, child} = require('child_process')
fs = require('fs')
Linter = require(atom.packages.getLoadedPackage('linter').path + '/lib/linter')

class LinterScalac extends Linter
	@syntax: ['source.scala']

	classpath: null

	cmd: 'scalac'

	linterName: 'scalac'

	regex: 'scala:(?<line>\\d+): ((?<error>error)|(?<warning>warning)): (?<message>.+)\\n'

	constructor: (editor) ->
		super(editor)

		atom.config.observe('linter-scalac.scalacExecutablePath', =>
			dotClasspath = atom.project.path + '/.classpath'

			if atom.config.get('linter-scalac.scalacOptions')?
				@cmd = @cmd + ' ' + atom.config.get('linter-scalac.scalacOptions')

			if fs.existsSync(dotClasspath)
				@classpath = fs.readFileSync(dotClasspath).toString().trim()
				@cwd = @classpath.split(':')[0]
				@cmd = @cmd + ' -classpath "' + @classpath + '"'

			@executablePath = atom.config.get('linter-scalac.scalacExecutablePath')
		)

	destroy: ->
		atom.config.unobserve('linter-scalac.scalacExecutablePath')

	lintFile: (filePath, callback) ->
		exec(@getCmd(filePath), cwd: @cwd, (error, stdout, stderr) =>
			if stderr then @processMessage(stderr, callback)
		)

module.exports = LinterScalac

{exec, child} = require('child_process')
fs = require('fs')
Linter = require(atom.packages.getLoadedPackage('linter').path + '/lib/linter')

class LinterScalac extends Linter
	@syntax: ['source.scala']

	classpath: null

	cmd: 'scalac'

	linterName: 'scalac'

	regex: 'scala:(?<line>\\d+): ((?<error>error)|(?<warning>warning)): (?<message>(.+)\\n(.+))\\n'

	constructor: (editor) ->
		super(editor)

		atom.config.observe('linter-scalac.scalacExecutablePath', =>
			dotClasspath = atom.project.path + '/.classpath'

			if atom.config.get('linter-scalac.scalacOptions')?
				@cmd = @cmd + ' ' + atom.config.get('linter-scalac.scalacOptions')

			if fs.existsSync(dotClasspath)
				@classpath = fs.readFileSync(dotClasspath).toString().trim()
				@cwd = @classpath.split(':')[0]
				@cmd = @cmd + ' -classpath "' + @classpath + '"'

			@executablePath = atom.config.get('linter-scalac.scalacExecutablePath')
		)

	destroy: -> atom.config.unobserve('linter-scalac.scalacExecutablePath')

	lintFile: (filePath, callback) -> exec(@getCmd(filePath), cwd: @cwd, (error, stdout, stderr) =>
		if stderr then @processMessage(stderr, callback)
	)

module.exports = LinterScalac

Include verbose details about error/warning.


mid = new Date('02/25/14 00:00:00')
Template.agenda.day1 = ->
  _.sortBy(@items.filter((i) -> i.time < mid), (i) -> i.time)

Template.agenda.day2 = ->
  _.sortBy(@items.filter((i) -> i.time > mid), (i) -> i.time)

Template.agenda.canSee = -> true
  # u = User.current()
  # u and (u.admin() or u.moderator())

Template.agenda.canEdit = ->
  u = User.current()
  u and u.admin()

Template.agenda.events
  'submit #add-form': (event, context) ->
    event.preventDefault()
    time = context.find('#time').value
    class1 = context.find('#class1').value
    icon1 = context.find('#icon1').value
    class2 = context.find('#class2').value
    icon2 = context.find('#icon2').value
    class3 = context.find('#class3').value
    icon3 = context.find('#icon3').value
    if not time then return
    time = new Date(time)
    if not time
      console.error('bad time string')
      return
    AgendaItem.create
      time: time
      class1: class1
      class2: class2
      class3: class3
      icon1: icon1
      icon2: icon2
      icon3: icon3

  'click #edit': ->
    Session.set('editingAgenda', not Session.get('editingAgenda'))

mid = new Date('02/25/2014 00:00:00')
Template.agenda.day1 = ->
  _.sortBy(@items.filter((i) -> i.time < mid), (i) -> i.time)

Template.agenda.day2 = ->
  _.sortBy(@items.filter((i) -> i.time > mid), (i) -> i.time)

Template.agenda.canSee = -> true
  # u = User.current()
  # u and (u.admin() or u.moderator())

Template.agenda.canEdit = ->
  u = User.current()
  u and u.admin()

Template.agenda.events
  'submit #add-form': (event, context) ->
    event.preventDefault()
    time = context.find('#time').value
    class1 = context.find('#class1').value
    icon1 = context.find('#icon1').value
    class2 = context.find('#class2').value
    icon2 = context.find('#icon2').value
    class3 = context.find('#class3').value
    icon3 = context.find('#icon3').value
    if not time then return
    time = new Date(time)
    if not time
      console.error('bad time string')
      return
    AgendaItem.create
      time: time
      class1: class1
      class2: class2
      class3: class3
      icon1: icon1
      icon2: icon2
      icon3: icon3

  'click #edit': ->
    Session.set('editingAgenda', not Session.get('editingAgenda'))

Fix FF bug: parsing the mid date was wrong. cc: @urielster @ofri


describe "RequireJS", ->
  beforeEach ->
    @addMatchers
      requirejsTobeUndefined: ->
        typeof requirejs is "undefined"

      requireTobeUndefined: ->
        typeof require is "undefined"

      defineTobeUndefined: ->
        typeof define is "undefined"

  it "check that the RequireJS object is present in the global namespace", ->
    expect(RequireJS).toEqual jasmine.any(Object)
    expect(window.RequireJS).toEqual jasmine.any(Object)

  it "check that requirejs(), require(), and define() are not in the global namespace", ->
    expect({}).requirejsTobeUndefined()
    expect({}).requireTobeUndefined()
    expect({}).defineTobeUndefined()
    expect(window.requirejs).not.toBeDefined()
    expect(window.require).not.toBeDefined()
    expect(window.define).not.toBeDefined()

  it "check that the RequireJS has requirejs(), require(), and define() functions as its properties", ->
    expect(RequireJS.requirejs).toEqual jasmine.any(Function)
    expect(RequireJS.require).toEqual jasmine.any(Function)
    expect(RequireJS.define).toEqual jasmine.any(Function)

describe "RequireJS namespacing", ->
  beforeEach ->
    @addMatchers
      requirejsTobeUndefined: ->
        typeof requirejs is "undefined"

      requireTobeUndefined: ->
        typeof require is "undefined"

      defineTobeUndefined: ->
        typeof define is "undefined"

  it "check that the RequireJS object is present in the global namespace", ->
    expect(RequireJS).toEqual jasmine.any(Object)
    expect(window.RequireJS).toEqual jasmine.any(Object)

  it "check that requirejs(), require(), and define() are not in the global namespace", ->
    expect({}).requirejsTobeUndefined()
    expect({}).requireTobeUndefined()
    expect({}).defineTobeUndefined()
    expect(window.requirejs).not.toBeDefined()
    expect(window.require).not.toBeDefined()
    expect(window.define).not.toBeDefined()

describe "RequireJS module creation", ->
  inCallback = undefined
  it "check that we can use RequireJS.define() to create a module", ->
    runs ->
      inCallback = false
      RequireJS.define [], ->
        inCallback = true
        module_status: "OK"

    waitsFor (->
      inCallback
    ), "We should eventually end up in the defined callback", 1000
    runs ->
      expects(inCallback).toBeTruthy()

# it('check that we can use RequireJS.require() to get our defined module', function () {

# });

Work on RequireJS Jasmine test.

Work on RequireJS Jasmine test.


template = require 'views/templates/home'
PageView = require 'views/base/page_view'

module.exports = class HomePageView extends PageView
  template: template
  className: 'home-page'
  id: 'home-page'

Make home page trackable by sidebar

Make home page trackable by sidebar


{React, ReactBootstrap} = window
{Button} = ReactBootstrap
remote = require 'remote'
BrowserWindow = remote.require 'browser-window'

module.exports =
  name: 'OwnedList'
  priority: 50
  displayName: '详细信息'
  description: '提供已有舰娘和已有装备详细信息查看'
  reactClass: React.createClass
    shipInfoWindow: new BrowserWindow
      #Need test / use config?
      x: 0
      y: 0
      width: 800
      height: 600
      show: false

    initialShipInfoWindow: ->
      @shipInfoWindow.loadUrl "file://#{__dirname}/parts/info-panel/ships/index.html"
      ###
      issue code: failed to hide the window
      @shipInfoWindow.onbeforeunload = (e) ->
        @shipInfoWindow.hide()
        false

      or

      @shipInfoWindow.on 'close', () ->
        @shipInfoWindow.preventDefault()
        @shipInfoWindow.hide()
      ###

    handleClickShipButton: ->
      @shipInfoWindow.show()

    handleTest: ->
      @shipInfoWindow.hide()

    render: ->
      @initialShipInfoWindow()
      <div>
        <Button bsStyle='info' bsSize='large' block onClick={@handleClickShipButton} >舰娘信息</Button>
        <Button bsStyle='info' bsSize='large' block onClick={@handleTest} >装备信息</Button>
      </div>

{React, ReactBootstrap} = window
{Button} = ReactBootstrap
remote = require 'remote'
BrowserWindow = remote.require 'browser-window'

shipInfoWindow = null

initialShipInfoWindow = ->
  shipInfoWindow = new BrowserWindow
    #Use cconfig
    x: 0
    y: 0
    width: 800
    height: 600
    show: false

  shipInfoWindow.loadUrl "file://#{__dirname}/parts/info-panel/ships/index.html"
  shipInfoWindow.openDevTools
    detach: true
  shipInfoWindow.onbeforeunload = ->
    false
    ###
  shipInfoWindow.on 'close', (e) =>
    console.log "It works!"
    e.preventDefault()
    shipInfoWindow.hide()
    ###
initialShipInfoWindow()

module.exports =
  name: 'OwnedList'
  priority: 50
  displayName: '详细信息'
  description: '提供已有舰娘和已有装备详细信息查看'
  reactClass: React.createClass

    handleClickShipButton: ->
      shipInfoWindow.show()

    render: ->
      <div>
        <Button bsStyle='info' bsSize='large' block onClick={@handleClickShipButton} >舰娘信息</Button>
        <Button bsStyle='info' bsSize='large' block onClick={@handleTest} >装备信息</Button>
      </div>

Adjust pop-up window as a variable

Adjust pop-up window as a variable [issue]

Issue:

Failed to hide window


{View, $} = require 'atom'

module.exports =
class SideView extends View
  @content: (side) ->
    @div class: "side #{side.klass()} ui-site-#{side.site()}", =>
      @div class: 'controls', =>
        @label class: 'text-highlight', side.ref
        @span class: 'text-subtle', "// #{side.description()}"
        @button class: 'btn btn-xs pull-right', click: 'useMe', "Use Me"

  initialize: (@side) ->

  installIn: (editorView) ->
    console.log "== Initial installation // #{@side.description()}"
    @reposition(editorView, true)
    @appendTo editorView.overlayer

    @side.refBannerMarker.on "changed", =>
      console.log ">> Banner marker changed // #{@side.description()}"
      @reposition(editorView)

  reposition: (editorView, initial) ->
    # @side.lines().addClass("conflict-line #{@side.klass()}")
    anchor = editorView.renderedLines.offset()
    ref = @side.refBannerOffset()
    if initial
      top = ref.top
    else
      top = ref.top + anchor.top

    console.log "anchor: #{anchor.top} moving to: #{top}"
    console.log "matched lines: #{@side.lines().text()}"

    @offset top: top
    @height @side.refBannerLine().height()

  useMe: ->
    @side.resolve()

  getModel: -> null

{View, $} = require 'atom'

module.exports =
class SideView extends View
  @content: (side) ->
    @div class: "side #{side.klass()} ui-site-#{side.site()}", =>
      @div class: 'controls', =>
        @label class: 'text-highlight', side.ref
        @span class: 'text-subtle', "// #{side.description()}"
        @button class: 'btn btn-xs pull-right', click: 'useMe', "Use Me"

  initialize: (@side) ->

  installIn: (editorView) ->
    @appendTo editorView.overlayer
    @reposition(editorView)

    @side.refBannerMarker.on "changed", =>
      @reposition(editorView)

  reposition: (editorView, initial) ->
    # @side.lines().addClass("conflict-line #{@side.klass()}")
    anchor = editorView.renderedLines.offset()
    ref = @side.refBannerOffset()

    @offset top: ref.top + anchor.top
    @height @side.refBannerLine().height()

  useMe: ->
    @side.resolve()

  getModel: -> null

Reposition *after* you add to the DOM.

Reposition *after* you add to the DOM.

It doesn't seem to flicker, and you need the parent for positioning to work
properly.


SHARED_COLLECTION = new Skr.Models.PaymentTerm.Collection

class Skr.Components.TermsChooser extends Lanes.React.Component

    propTypes:
        model: Lanes.PropTypes.Model.isRequired
        label: React.PropTypes.string
        name:  React.PropTypes.string

    getDefaultProps: ->
        label: 'Payment Terms', name: 'terms'

    componentWillMount: ->
        SHARED_COLLECTION.ensureLoaded()

    render: ->
        <LC.SelectField sm=3
            labelField="code"
            {...@props}
            fetchWhenOpen={false}
            collection={SHARED_COLLECTION}
            model={@props.model} />

SHARED_COLLECTION = new Skr.Models.PaymentTerm.Collection

class Skr.Components.TermsChooser extends Lanes.React.Component

    propTypes:
        model: Lanes.PropTypes.Model.isRequired
        label: React.PropTypes.string
        name:  React.PropTypes.string
        useFinder: React.PropTypes.bool

    getDefaultProps: ->
        label: 'Payment Terms', name: 'terms'

    componentWillMount: ->
        SHARED_COLLECTION.ensureLoaded()

    dataObjects:
        query: ->
            new Lanes.Models.Query({
                syncOptions: @props.syncOptions
                src: Skr.Models.PaymentTerm, fields: [
                    { id:'id', visible: false}
                    { id: 'code', fixedWidth: 130 },
                    'description',
                    { id: 'days', fixedWidth: 80 }
                    { id: 'discount_days', label: 'Disc Days', fixedWidth: 80 }
                    { id: 'discount_amount', label: 'Disc Amt', fixedWidth: 80 }

                ]
            })

    render: ->
        if @props.useFinder
            <LC.RecordFinder ref="finder"
                commands={@props.commands} query={@query}
                {...@props} />
        else
            <LC.SelectField sm=3
                labelField="code"
                {...@props}
                fetchWhenOpen={false}
                collection={SHARED_COLLECTION}
                model={@props.model} />

Add finder to terms chooser

Add finder to terms chooser


'.workspace':
  'alt-g o': 'open-on-github:file'
  'alt-g b': 'open-on-github:blame'
  'alt-g h': 'open-on-github:history'
  'alt-g c': 'open-on-github:copy-url'
  'alt-g r': 'open-on-github:branch-compare'

'atom-workspace':
  'alt-g o': 'open-on-github:file'
  'alt-g b': 'open-on-github:blame'
  'alt-g h': 'open-on-github:history'
  'alt-g c': 'open-on-github:copy-url'
  'alt-g r': 'open-on-github:branch-compare'

Fix deprecated selector in keymap

Fix deprecated selector in keymap


Command = require('../command')
Range = require('../range')
Compiler = require('../compiler')

class Xecute extends Command

  name: ''

  last_error: null

  args: new Range(1, Infinity)

  constructor: ->
    super
    @compiler = new Compiler({@scope})

  execute: (input, chain) ->
    return @switch_mode(chain) if input[0] == 'mode'
    @execute_code input.join(' ')
    chain.next()

  execute_code: (code, language = null) ->
    try
      @output.send @compiler.execute(code, language)
    catch err
      @last_error = err
      @output.send err

  switch_mode: (chain) ->
    @compiler.toggle_mode()
    @output.send "Switched mode to '#{@compiler.mode()}'."
    chain.next()

  # Should always fallback to this
  match: (input) ->
    [input, input]

module.exports = Xecute

Command = require('../command')
Range = require('../range')
Compiler = require('../compiler')

class Xecute extends Command

  name: 'mode'
  definition: 'Switched between CoffeeScript and JavaScript execution.'
  help: 'Type `mode` to switch between using JavaScript or CoffeeScript.'

  last_error: null

  args: new Range(1, Infinity)

  constructor: ->
    super
    @compiler = new Compiler({@scope})

  execute: (input, chain) ->
    return @switch_mode(chain) if input[0] == 'mode'
    @execute_code input.join(' ')
    chain.next()

  execute_code: (code, language = null) ->
    try
      @output.send @compiler.execute(code, language)
    catch err
      @last_error = err
      @output.send err

  switch_mode: (chain) ->
    @compiler.toggle_mode()
    @output.send "Switched mode to '#{@compiler.mode()}'."
    chain.next()

  # Should always fallback to this
  match: (input) ->
    [input, input]

module.exports = Xecute

Document hidden feature to switch between javascript and coffeescript.


_ = require 'underscore'
Rx = require 'rx-lite'

NylasAPI = require './flux/nylas-api'
DatabaseStore = require './flux/stores/database-store'
Thread = require './flux/models/thread'
MutableQuerySubscription = require './flux/models/mutable-query-subscription'

class SearchSubscription extends MutableQuerySubscription

  constructor: (@_terms, @_accountId) ->
    super(null, {asResultSet: true})

    @_version = 0
    _.defer => @retrievePage(0)

  terms: =>
    @_terms

  setTerms: (terms) =>
    @_terms = terms
    @_version += 1
    @retrievePage(0)

  replaceRange: (range) =>
    @retrievePage(Math.floor(range.start / 100))

  # Accessing Data

  retrievePage: (idx) =>
    version = @_version += 1

    NylasAPI.makeRequest
      method: 'GET'
      path: "/threads/search?q=#{encodeURIComponent(@_terms)}"
      accountId: @_accountId
      json: true
      returnsModel: true
    .then (threads) =>
      return unless @_version is version
      query = DatabaseStore.findAll(Thread).where(id: _.pluck(threads, 'id'))
      @replaceQuery(query)

module.exports = SearchSubscription

_ = require 'underscore'
Rx = require 'rx-lite'

NylasAPI = require './flux/nylas-api'
DatabaseStore = require './flux/stores/database-store'
Thread = require './flux/models/thread'
MutableQuerySubscription = require './flux/models/mutable-query-subscription'

class SearchSubscription extends MutableQuerySubscription

  constructor: (@_terms, @_accountIds) ->
    super(null, {asResultSet: true})

    @_version = 0
    _.defer => @retrievePage(0)

  terms: =>
    @_terms

  setTerms: (terms) =>
    @_terms = terms
    @_version += 1
    @retrievePage(0)

  replaceRange: (range) =>
    @retrievePage(Math.floor(range.start / 100))

  # Accessing Data

  retrievePage: (idx) =>
    version = @_version += 1

    requests = @_accountIds.map (aid) =>
      NylasAPI.makeRequest
        method: 'GET'
        path: "/threads/search?q=#{encodeURIComponent(@_terms)}"
        accountId: aid
        json: true
        returnsModel: true

    Promise.all(requests).then (resultArrays) =>
      return unless @_version is version
      resultIds = []
      for resultArray in resultArrays
        resultIds = resultIds.concat _.pluck(resultArray, 'id')

      query = DatabaseStore.findAll(Thread).where(id: resultIds).order(Thread.attributes.lastMessageReceivedTimestamp.descending())
      @replaceQuery(query)

module.exports = SearchSubscription

Update SearchSubscription to support basic multiaccount search... seems to work?


#= require es5-shim/es5-shim.js
#= require spin.js/dist/spin
#= require jquery/jquery
#= require angular/angular
#= require angular-bootstrap/ui-bootstrap-tpls
#= require angular-bootstrap-colorpicker/js/bootstrap-colorpicker-module
#= require angular-file-upload/angular-file-upload
#= require angular-resource/angular-resource.js
#= require angularjs-rails-resource/angularjs-rails-resource.js
#= require_self

#= require es5-shim/es5-shim.js
#= require spin.js/dist/spin
#= require jquery/jquery
#= require angular/angular
#= require angular-bootstrap/ui-bootstrap-tpls
#= require angular-bootstrap-colorpicker/js/bootstrap-colorpicker-module
#= require angular-file-upload/angular-file-upload
#= require angularjs-rails-resource/angularjs-rails-resource.js
#= require_self

Remove ng-resource include (keep the bower component for now)


MinimapFindAndReplaceBinding = require './minimap-find-and-replace-binding'

module.exports =
  binding: null
  activate: (state) ->
    findPackage = atom.packages.getLoadedPackage('find-and-replace')
    minimapPackage = atom.packages.getLoadedPackage('minimap')

    return @deactivate() unless findPackage? and minimapPackage?

    minimap = require(minimapPackage.path)
    return @deactivate() unless minimap.versionMatch('2.x')

    @binding = new MinimapFindAndReplaceBinding findPackage, minimapPackage

  deactivate: ->
    @binding?.deactivate()
    @minimapPackage = null
    @findPackage = null
    @binding = null

MinimapFindAndReplaceBinding = require './minimap-find-and-replace-binding'

module.exports =
  binding: null
  activate: (state) ->
    findPackage = atom.packages.getLoadedPackage('find-and-replace')
    minimapPackage = atom.packages.getLoadedPackage('minimap')

    return @deactivate() unless findPackage? and minimapPackage?

    minimap = require(minimapPackage.path)
    return @deactivate() unless minimap.versionMatch('3.x')

    @binding = new MinimapFindAndReplaceBinding findPackage, minimapPackage

  deactivate: ->
    @binding?.deactivate()
    @minimapPackage = null
    @findPackage = null
    @binding = null

Add version test for minimap v3

Add version test for minimap v3


React = require 'react'
LoadableItem = require '../loadable-item'

{PerformanceStore, PerformanceActions} = require '../../flux/performance'

ViewingAsStudentName = React.createClass
  displayName: 'ViewingAsStudentName'
  propTypes:
    courseId: React.PropTypes.string.isRequired
    taskId: React.PropTypes.string.isRequired
    className: React.PropTypes.string

  render: ->
    {courseId, taskId, className} = @props
    studentName = null

    className += ' task-student'
    student = PerformanceStore.getStudentOfTask(courseId, taskId)

    studentName = <div className={className}>
      {student.first_name} {student.last_name}
    </div> if student?

    studentName

ViewingAsStudentNameShell = React.createClass
  displayName: 'ViewingAsStudentNameShell'
  propTypes:
    courseId: React.PropTypes.string.isRequired
    taskId: React.PropTypes.string.isRequired

  render: ->
    {courseId} = @props

    <LoadableItem
      id={courseId}
      store={PerformanceStore}
      actions={PerformanceActions}
      renderItem={=> <ViewingAsStudentName {...@props}/>}
    />

module.exports = {ViewingAsStudentName, ViewingAsStudentNameShell}

React = require 'react'
LoadableItem = require '../loadable-item'
Name = require '../name'
{PerformanceStore, PerformanceActions} = require '../../flux/performance'

ViewingAsStudentName = React.createClass
  displayName: 'ViewingAsStudentName'
  propTypes:
    courseId: React.PropTypes.string.isRequired
    taskId: React.PropTypes.string.isRequired
    className: React.PropTypes.string

  render: ->
    {courseId, taskId, className} = @props
    studentName = null

    className += ' task-student'
    student = PerformanceStore.getStudentOfTask(courseId, taskId)

    studentName = <div className={className}>
      <Name {...student} />
    </div> if student?

    studentName

ViewingAsStudentNameShell = React.createClass
  displayName: 'ViewingAsStudentNameShell'
  propTypes:
    courseId: React.PropTypes.string.isRequired
    taskId: React.PropTypes.string.isRequired

  render: ->
    {courseId} = @props

    <LoadableItem
      id={courseId}
      store={PerformanceStore}
      actions={PerformanceActions}
      renderItem={=> <ViewingAsStudentName {...@props}/>}
    />

module.exports = {ViewingAsStudentName, ViewingAsStudentNameShell}

Use Name comp for teacher viewing student tasks


$               = require('jquery')
attachFastClick = require('fastclick')
app             = require('./app')

$ ->
  app.start()
  attachFastClick(document.body)

  # Stretch main container height so it's not resized when the viewport is
  # resized. This happens on Android when the keyboard pops up.
  setTimeout ->
    window.containerOffsetTop = $(app.getRegion().el).offset().top
    initialWindowHeight = $(window).height() - window.containerOffsetTop
    $(app.getRegion().el).css('height', initialWindowHeight)
  , 0

$               = require('jquery')
FastClick       = require('fastclick')
app             = require('./app')

$ ->
  app.start()
  FastClick.attach(document.body)

  # Stretch main container height so it's not resized when the viewport is
  # resized. This happens on Android when the keyboard pops up.
  setTimeout ->
    window.containerOffsetTop = $(app.getRegion().el).offset().top
    initialWindowHeight = $(window).height() - window.containerOffsetTop
    $(app.getRegion().el).css('height', initialWindowHeight)
  , 0

Fix FastClick for webpack compatibility

Fix FastClick for webpack compatibility

https://github.com/ftlabs/fastclick/issues/398


define [
    './cilantro/core'
    './cilantro/changelog'
    './cilantro/models'
    './cilantro/structs'
    './cilantro/ui'
], (c, changelog, models, structs, ui) ->

    c.changelog = changelog
    c.models = models
    c.structs = structs
    c.ui = ui

    # Defines the minimum version of Serrano that this version of Cilantro is
    # 100% compatible with. While Cilantro will attempt to run normally despite
    # the version number received from the server, the user will be warned if
    # no version number is found or if it is less than this minimum to
    # prepare them in the case of missing or broken functionality.
    c.minimumSerranoVersion = [2, 0, 24]

    c.data =
        concepts: new models.ConceptCollection
        fields: new models.FieldCollection
        contexts: new models.ContextCollection
        views: new models.ViewCollection
        results: new models.Results
        exporters: new models.ExporterCollection

    if c.getOption('autoload')
        c.openSession()

    return (@cilantro = c)

define [
    './cilantro/core'
    './cilantro/changelog'
    './cilantro/models'
    './cilantro/structs'
    './cilantro/ui'
], (c, changelog, models, structs, ui) ->

    c.changelog = changelog
    c.models = models
    c.structs = structs
    c.ui = ui

    # Defines the minimum version of Serrano that this version of Cilantro is
    # 100% compatible with. While Cilantro will attempt to run normally despite
    # the version number received from the server, the user will be warned if
    # no version number is found or if it is less than this minimum to
    # prepare them in the case of missing or broken functionality.
    c.minimumSerranoVersion = [2, 0, 18]

    c.data =
        concepts: new models.ConceptCollection
        fields: new models.FieldCollection
        contexts: new models.ContextCollection
        views: new models.ViewCollection
        results: new models.Results
        exporters: new models.ExporterCollection

    if c.getOption('autoload')
        c.openSession()

    return (@cilantro = c)

Drop the minimum Serrano version to >= 2.0.18


_ = require 'underscore'
flux = require 'flux-react'

LOADING = 'loading'
FAILED  = 'failed'

EcosystemsActions = flux.createActions [
  'load'
  'loaded'
  'FAILED'
]

EcosystemsStore = flux.createStore
  actions: _.values(EcosystemsActions)

  _asyncStatus: null

  load: -> # Used by API
    @_asyncStatus = LOADING
    @emit('load')

  loaded: (ecosystems) ->
    @_ecosystems = ecosystems
    @emit('loaded')

  FAILED: ->
    @_asyncStatus = FAILED
    @emit('failed')

  exports:
    isLoaded: -> not _.isEmpty(@_ecosystems)
    isLoading: -> @_asyncStatus is LOADING
    isFailed:  -> @_asyncStatus is FAILED

    allBooks: ->
      _.map @_ecosystems, (ecosystem) ->
        _.extend( _.first(ecosystem.books), {ecosystemId: "#{ecosystem.id}"} )

    first: ->
      _.first @_ecosystems

    getBook: (ecosystemId) ->
      _.findWhere(@_ecosystems, id: parseInt(ecosystemId, 10))

module.exports = {EcosystemsActions, EcosystemsStore}

_ = require 'underscore'
flux = require 'flux-react'

LOADING = 'loading'
FAILED  = 'failed'

EcosystemsActions = flux.createActions [
  'load'
  'loaded'
  'FAILED'
]

EcosystemsStore = flux.createStore
  actions: _.values(EcosystemsActions)

  _asyncStatus: null

  load: -> # Used by API
    @_asyncStatus = LOADING
    @emit('load')

  loaded: (ecosystems) ->
    @_ecosystems = ecosystems
    @emit('loaded')

  FAILED: ->
    @_asyncStatus = FAILED
    @emit('failed')

  exports:
    isLoaded: -> not _.isEmpty(@_ecosystems)
    isLoading: -> @_asyncStatus is LOADING
    isFailed:  -> @_asyncStatus is FAILED

    allBooks: ->
      _.map @_ecosystems, (ecosystem) ->
        _.extend( _.first(ecosystem.books), {ecosystemId: "#{ecosystem.id}"} )

    first: ->
      _.first @_ecosystems

    getBook: (ecosystemId) ->
      _.first( _.findWhere(@_ecosystems, id: parseInt(ecosystemId, 10)).books )

module.exports = {EcosystemsActions, EcosystemsStore}

Return book instead of ecosystem

Return book instead of ecosystem


module.exports =
class OverlayManager
  constructor: (@container) ->
    @overlayNodesById = {}

  render: (props) ->
    {presenter} = props

    for decorationId, {pixelPosition, item} of presenter.state.content.overlays
      @renderOverlay(presenter, decorationId, item, pixelPosition)

    for id, overlayNode of @overlayNodesById
      unless presenter.state.content.overlays.hasOwnProperty(id)
        overlayNode.remove()
        delete @overlayNodesById[id]

    return

  renderOverlay: (presenter, decorationId, item, pixelPosition) ->
    item = atom.views.getView(item)
    unless overlayNode = @overlayNodesById[decorationId]
      overlayNode = @overlayNodesById[decorationId] = document.createElement('atom-overlay')
      overlayNode.appendChild(item)
      @container.appendChild(overlayNode)

    itemWidth = item.offsetWidth
    itemHeight = item.offsetHeight

    {scrollTop, scrollLeft} = presenter.state.content

    left = pixelPosition.left
    if left + itemWidth - scrollLeft > presenter.contentFrameWidth and left - itemWidth >= scrollLeft
      left -= itemWidth

    top = pixelPosition.top + presenter.lineHeight
    if top + itemHeight - scrollTop > presenter.computeHeight() and top - itemHeight - presenter.lineHeight >= scrollTop
      top -= itemHeight + presenter.lineHeight

    overlayNode.style.top = top + 'px'
    overlayNode.style.left = left + 'px'

module.exports =
class OverlayManager
  constructor: (@container) ->
    @overlayNodesById = {}

  render: (props) ->
    {presenter} = props

    for decorationId, {pixelPosition, item} of presenter.state.content.overlays
      @renderOverlay(presenter, decorationId, item, pixelPosition)

    for id, overlayNode of @overlayNodesById
      unless presenter.state.content.overlays.hasOwnProperty(id)
        overlayNode.remove()
        delete @overlayNodesById[id]

    return

  renderOverlay: (presenter, decorationId, item, pixelPosition) ->
    item = atom.views.getView(item)
    unless overlayNode = @overlayNodesById[decorationId]
      overlayNode = @overlayNodesById[decorationId] = document.createElement('atom-overlay')
      overlayNode.appendChild(item)
      @container.appendChild(overlayNode)

    itemWidth = item.offsetWidth
    itemHeight = item.offsetHeight

    {scrollTop, scrollLeft} = presenter.state.content

    left = pixelPosition.left
    if left + itemWidth - scrollLeft > presenter.contentFrameWidth and left - itemWidth >= scrollLeft
      left -= itemWidth

    top = pixelPosition.top + presenter.lineHeight
    if top + itemHeight - scrollTop > presenter.height and top - itemHeight - presenter.lineHeight >= scrollTop
      top -= itemHeight + presenter.lineHeight

    overlayNode.style.top = top + 'px'
    overlayNode.style.left = left + 'px'

Use property instead of non-existent method in OverlayManager


# Toggle the administration system.
($ document).keypress (e) ->
  ($ '.administration').toggleClass 'visible' if (e.keyCode || e.which) == 96

# "Hero" image fade-in.
window.onload = ->
  ($ '.hero-image img').animate({opacity: 1}, 300)

# Search field highlighting.
($ document).ready ->
  ($ '#id_q').focus ->
    ($ this).closest('.searchbar').addClass 'focus'
  ($ '#id_q').blur ->
    ($ this).closest('.searchbar').removeClass 'focus'

# NProgress-related calls.
($ document).on 'page:fetch', ->
  NProgress.start()

($ document).on 'page:change', ->
  NProgress.done()

($ document).on 'page:restore', ->
  NProgress.remove()

# Happenings-related calls.
($ document).ready ->
  ($ document).on 'click', '.happening-toggle', ->
    ($ '.happening-decade-list').toggleClass 'visible'
    ($ '.happening-toggle .ss-icon:last-child').toggleClass 'ss-navigatedown ss-navigateup'

# Toggle the administration system.
($ document).keypress (e) ->
  ($ '.administration').toggleClass 'visible' if (e.keyCode || e.which) == 96

# "Hero" image fade-in.
window.onload = ->
  ($ '.hero-image img').animate({opacity: 1}, 300)

($ document).ready ->
  # Search field highlighting.
  ($ '#id_q').focus ->
    ($ this).closest('.searchbar').addClass 'focus'
  ($ '#id_q').blur ->
    ($ this).closest('.searchbar').removeClass 'focus'

  # Happenings-related calls.
  ($ document).on 'click', '.happening-toggle', ->
    ($ '.happening-decade-list').toggleClass 'visible'
    ($ '.happening-toggle .ss-icon:last-child').toggleClass 'ss-navigatedown ss-navigateup'

# NProgress-related calls.
($ document).on 'page:fetch', ->
  NProgress.start()

($ document).on 'page:change', ->
  NProgress.done()

($ document).on 'page:restore', ->
  NProgress.remove()

Move all the JS under one .ready() call. Not sure if correct.


class window.EvidenceCollection extends Backbone.Factlink.Collection

  initialize: (models, options) ->
    @fact = options.fact

    @_supportingCollection = new OneSidedEvidenceCollection null, fact: @fact, type: 'supporting'
    @_weakeningCollection = new OneSidedEvidenceCollection null, fact: @fact, type: 'weakening'

    @_containedCollections = [
      new OpinionatersCollection null, fact: @fact
      @_supportingCollection
      @_weakeningCollection
    ]

    for collection in @_containedCollections
      @listenTo collection, 'sync', @loadFromCollections
      @listenTo collection, 'add', (model) -> @add model
      @listenTo collection, 'saved_added_model', -> @trigger 'saved_added_model'
      @listenTo collection, 'error_adding_model', -> @trigger 'error_adding_model'

  comparator: (item) -> - item.get('impact')

  loading: ->
    _.some @_containedCollections, (collection) -> collection.loading()

  fetch: (options={}) ->
    @trigger 'request', this
    _.invoke @_containedCollections, 'fetch', _.extend {}, options, reset: true

  loadFromCollections: (collectionOrModel) ->
    return if @loading()
    return unless collectionOrModel in @_containedCollections # collection proxies model's sync

    @reset(_.union (col.models for col in @_containedCollections)...)
    @trigger 'sync'

  oneSidedEvidenceCollection: (type) ->
    switch type
      when 'supporting' then @_supportingCollection
      when 'weakening' then @_weakeningCollection
      else throw 'Unknown OneSidedEvidenceCollection type'

class window.EvidenceCollection extends Backbone.Factlink.Collection

  initialize: (models, options) ->
    @fact = options.fact

    @_supportingCollection = new OneSidedEvidenceCollection null, fact: @fact, type: 'supporting'
    @_weakeningCollection = new OneSidedEvidenceCollection null, fact: @fact, type: 'weakening'

    @_containedCollections = [
      new OpinionatersCollection null, fact: @fact
      @_supportingCollection
      @_weakeningCollection
    ]

    for collection in @_containedCollections
      @listenTo collection, 'sync', @loadFromCollections
      @listenTo collection, 'add', (model) -> @add model
      @listenTo collection, 'remove', (model) -> @remove model
      @listenTo collection, 'saved_added_model', -> @trigger 'saved_added_model'
      @listenTo collection, 'error_adding_model', -> @trigger 'error_adding_model'

  comparator: (item) -> - item.get('impact')

  loading: ->
    _.some @_containedCollections, (collection) -> collection.loading()

  fetch: (options={}) ->
    @trigger 'request', this
    _.invoke @_containedCollections, 'fetch', _.extend {}, options, reset: true

  loadFromCollections: (collectionOrModel) ->
    return if @loading()
    return unless collectionOrModel in @_containedCollections # collection proxies model's sync

    @reset(_.union (col.models for col in @_containedCollections)...)
    @trigger 'sync'

  oneSidedEvidenceCollection: (type) ->
    switch type
      when 'supporting' then @_supportingCollection
      when 'weakening' then @_weakeningCollection
      else throw 'Unknown OneSidedEvidenceCollection type'

Remove evidence when it is removed from an underlying collection


#= require data/ViewData.coffee
#= require gui/GuiBase.coffee

class SourceFileMarkup extends GuiBase
  constructor: (@filename, @id, @uri, @sourceFile) ->
    @formatted_code = null
    @element = $("
#{@filename}
", id: @id)
    super()

  # Create HTML code to represent a source file
  getFormattedCode: ->
    code = @sourceFile.getRawSourceCode()
    breakpointCallback = @sourceFile.getBreakpointCallback()

    @formatted_code = $("

")
    cnt = @sourceFile.getOffset()

    for line in code.split("\n")
      linediv = $("

")
      loc = $("

")

      # Prevent HTML markup at all cost
      loc[0].innerText = line

      # But set a class for breakpoint indications
      linediv.addClass "file-#{@id}-line-#{cnt}"

      linediv.append loc
      @formatted_code.append linediv

      # Put linediv and the line number in a closure...
      f = (element, line) =>
        callback = =>
          breakpointCallback line, @id, @uri

        linediv.click =>
          @click element, callback

      # ...and call it
      f linediv, cnt

      cnt++

    return @formatted_code

  getSourceFileLine: ->
    @element

Fix line numbering of source files

Fix line numbering of source files


Handlebars.registerHelper "selected", (selected) ->
  return if selected then "checked" else ""

Handlebars.registerHelper "truncate", (text, length) ->
  truncated = text.substring(0, length)
  if text.length > length
    truncated = truncated + "..."
  return truncated

Handlebars.registerHelper "strip", (text) ->
  return text.toString().replace(/^\s\s*/, '').replace(/\s\s*$/, '')

Handlebars.registerHelper "linkify", (text) ->
  exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
  return text.toString().replace(exp,"$1")

Handlebars.registerHelper "modalValue", (key, text) ->
  text = Handlebars.helpers.formatTimestamp(text) if key in ["issued", "timestamp"]
  linkified = Handlebars.helpers.linkify(text)
  return Handlebars.helpers.strip(linkified)

Handlebars.registerHelper "formatTimestamp", (text) ->
    return Date(text*100)

Handlebars.registerHelper "selected", (selected) ->
  return if selected then "checked" else ""

Handlebars.registerHelper "truncate", (text, length) ->
  truncated = text.substring(0, length)
  if text.length > length
    truncated = truncated + "..."
  return truncated

Handlebars.registerHelper "strip", (text) ->
  return text.toString().replace(/^\s\s*/, '').replace(/\s\s*$/, '')

Handlebars.registerHelper "linkify", (text) ->
  exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
  return text.toString().replace(exp,"$1")

Handlebars.registerHelper "modalValue", (key, text) ->
  text = Handlebars.helpers.formatTimestamp(text) if key in ["issued", "timestamp"]
  linkified = Handlebars.helpers.linkify(text)
  return Handlebars.helpers.strip(linkified)

Handlebars.registerHelper "formatTimestamp", (text) ->
  date = new Date(text*1000)
  return date.toISOString()

Use ISO8601 format for timestamps

Use ISO8601 format for timestamps


@mockEventStreamResponse = ->
  @server.respondWith 'GET', '/event_stream', [
    400
    'Content-Type': 'application/json'
    JSON.stringify {}
  ]

@mockAuthorizedRouteReponse = ->
  @server.respondWith 'GET', '/admin/journals', [
    403
    'Tahi-Authorization-Check': 'true'
    JSON.stringify {}
  ]

  # papers/:id/manuscript_manager
  @server.respondWith 'GET', /\/papers\/\d+\/manuscript_manager/, [
    403
    'Tahi-Authorization-Check': 'true'
    JSON.stringify {}
  ]

@mockCurrentUserResponse = ->
  @server.respondWith 'GET', "/users/#{@currentUserId}", [
    200
    'Content-Type': 'application/json'
    JSON.stringify {user: @fakeUser}
  ]

@setupMockServer = ->
  @server.restore() if @server
  @server = sinon.fakeServer.create()
  @server.autoRespond = true
  @server.xhr.useFilters = true
  @server.xhr.addFilter (method, url) -> !!url.match(/visualEditor/) || !!url.match(/visual-editor/)
  @mockCurrentUserResponse()
  @mockAuthorizedRouteReponse()
  @mockEventStreamResponse()

@mockEventStreamResponse = ->
  @server.respondWith 'GET', '/event_stream', [
    400
    'Content-Type': 'application/json'
    JSON.stringify {}
  ]

@mockAuthorizedRouteReponse = ->
  @server.respondWith 'GET', '/admin/journals/authorization', [
    204
    'Tahi-Authorization-Check': 'true'
    'Content-Type': 'application/html'
    ""
  ]

  # papers/:id/manuscript_manager
  @server.respondWith 'GET', /\/papers\/\d+\/manuscript_manager/, [
    403
    'Tahi-Authorization-Check': 'true'
    JSON.stringify {}
  ]

@mockCurrentUserResponse = ->
  @server.respondWith 'GET', "/users/#{@currentUserId}", [
    200
    'Content-Type': 'application/json'
    JSON.stringify {user: @fakeUser}
  ]

@mockCommentLookResponse = ->
  @server.respondWith 'GET', "/comment_looks", [
    200
    'Content-Type': 'application/json'
    JSON.stringify {}
  ]

@setupMockServer = ->
  @server.restore() if @server
  @server = sinon.fakeServer.create()
  @server.autoRespond = true
  @server.xhr.useFilters = true
  @server.xhr.addFilter (method, url) -> !!url.match(/visualEditor/) || !!url.match(/visual-editor/)
  @mockCurrentUserResponse()
  @mockAuthorizedRouteReponse()
  @mockEventStreamResponse()
  @mockCommentLookResponse()

Add a standard authorization response

Add a standard authorization response


_ = require('lodash')
Promise = require('bluebird')

IS_BROWSER = window?

if (IS_BROWSER)
	# The browser mock assumes global fetch prototypes exist
	realFetchModule = require('fetch-ponyfill')({ Promise })
	global.Promise = Promise
	global.Headers = realFetchModule.Headers
	global.Request = realFetchModule.Request
	global.Response = realFetchModule.Response

fetchMock = require('fetch-mock').sandbox(Promise)
fetchMock.fetchMock.Promise = Promise
fetchMock.patch = (matcher, response, options) ->
	options = _.assign({}, options, { method: 'PATCH' })
	@mock(matcher, response, options)

utils = require('../lib/utils')
utils.fetch = fetchMock.fetchMock

getToken = require('resin-token')
getRequest = require('../lib/request')

dataDirectory = null
if not IS_BROWSER
	settings = require('resin-settings-client')
	dataDirectory = settings.get('dataDirectory')

getCustomRequest = (opts) ->
	opts = _.assign({}, opts, { dataDirectory, debug: false, isBrowser: IS_BROWSER })
	getRequest(opts)

module.exports = ->
	IS_BROWSER: IS_BROWSER
	fetchMock: fetchMock
	token: getToken({ dataDirectory })
	request: getCustomRequest()
	getCustomRequest: getCustomRequest

_ = require('lodash')
Promise = require('bluebird')

IS_BROWSER = window?

if (IS_BROWSER)
	# The browser mock assumes global fetch prototypes exist
	# Can improve after https://github.com/wheresrhys/fetch-mock/issues/158
	realFetchModule = require('fetch-ponyfill')({ Promise })
	global.Headers = realFetchModule.Headers
	global.Request = realFetchModule.Request
	global.Response = realFetchModule.Response

fetchMock = require('fetch-mock').sandbox(Promise)

# Promise sandbox config needs a little help. See:
# https://github.com/wheresrhys/fetch-mock/issues/159#issuecomment-268249788
fetchMock.fetchMock.Promise = Promise

fetchMock.patch = (matcher, response, options) ->
	options = _.assign({}, options, { method: 'PATCH' })
	@mock(matcher, response, options)

utils = require('../lib/utils')
# Can probably just be 'fetchMock' after https://github.com/wheresrhys/fetch-mock/issues/159
utils.fetch = fetchMock.fetchMock

getToken = require('resin-token')
getRequest = require('../lib/request')

dataDirectory = null
if not IS_BROWSER
	settings = require('resin-settings-client')
	dataDirectory = settings.get('dataDirectory')

getCustomRequest = (opts) ->
	opts = _.assign({}, opts, { dataDirectory, debug: false, isBrowser: IS_BROWSER })
	getRequest(opts)

module.exports = ->
	IS_BROWSER: IS_BROWSER
	fetchMock: fetchMock
	token: getToken({ dataDirectory })
	request: getCustomRequest()
	getCustomRequest: getCustomRequest

Document fetch-mock issue workarounds so we can remove them later

This also removes global.Promise - that workaround was independently
solved by setting fetchMock.fetchMock.Promise


class @CommitsList
  @timer = null

  @init: (ref, limit) ->
    $("body").on "click", ".day-commits-table li.commit", (event) ->
      if event.target.nodeName != "A"
        location.href = $(this).attr("url")
        e.stopPropagation()
        return false

    Pager.init limit, false

    @content = $("#commits-list")
    @searchField = $("#commits-search")
    @initSearch()

  @initSearch: ->
    @timer = null
    @searchField.keyup =>
      clearTimeout(@timer)
      @timer = setTimeout(@filterResults, 500)

  @filterResults: =>
    form = $(".commits-search-form")
    search = @searchField.val()
    commitsUrl = form.attr("action") + '?' + form.serialize()
    @setOpacity(0.5)

    $.ajax
      type: "GET"
      url: form.attr("action")
      data: form.serialize()
      complete: =>
        @setOpacity(1.0)
      success: (data) =>
        @content.html(data.html)
        # Change url so if user reload a page - search results are saved
        history.replaceState {page: commitsUrl}, document.title, commitsUrl
      dataType: "json"

  @setOpacity: (opacity) ->
    @content.css("opacity", opacity)

class @CommitsList
  @timer = null

  @init: (ref, limit) ->
    $("body").on "click", ".day-commits-table li.commit", (event) ->
      if event.target.nodeName != "A"
        location.href = $(this).attr("url")
        e.stopPropagation()
        return false

    Pager.init limit, false

    @content = $("#commits-list")
    @searchField = $("#commits-search")
    @initSearch()

  @initSearch: ->
    @timer = null
    @searchField.keyup =>
      clearTimeout(@timer)
      @timer = setTimeout(@filterResults, 500)

  @filterResults: =>
    form = $(".commits-search-form")
    search = @searchField.val()
    commitsUrl = form.attr("action") + '?' + form.serialize()
    @content.fadeTo('fast', 0.5)

    $.ajax
      type: "GET"
      url: form.attr("action")
      data: form.serialize()
      complete: =>
        @content.fadeTo('fast', 1.0)
      success: (data) =>
        @content.html(data.html)
        # Change url so if user reload a page - search results are saved
        history.replaceState {page: commitsUrl}, document.title, commitsUrl
      dataType: "json"

Use fadeTo instead of css

Use fadeTo instead of css

Signed-off-by: Dmitriy Zaporozhets <be23d75b156792e5acab51b196a2deb155d35d6a@gmail.com>


# Description:
#  Taunt dat ass
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   butt name
#
# Author:
#   sshirokov

insult = [
  (opt) -> "#{opt.name} has a big butt.",
  (opt) -> "And their big butt smells.",
  (opt) -> "#{opt.name} likes to smell their big butt."
]

module.exports = (robot) ->
  robot.respond /butt( \w+)?/, (msg) ->
    name = msg.match[1]?.trim() or 'me'
    name = msg.message.user.name if name == 'me'

    delay = 0
    for section in insult
      do (section) ->
        delay += Math.random() * 1500
        setTimeout (->
          msg.send section(name: name)
          ), delay

# Description:
#  Taunt dat ass
#
# Dependencies:
#   None
#
# Configuration:
#   None
#
# Commands:
#   butt name
#
# Author:
#   sshirokov

insult = [
  (opt) -> "#{opt.name} has a big butt.",
  (opt) -> "And their big butt smells.",
  (opt) -> "#{opt.name} likes to smell their big butt."
]

module.exports = (robot) ->
  robot.respond /butts?( \w+)?/, (msg) ->
    name = msg.match[1]?.trim() or 'me'
    name = msg.message.user.name if name == 'me'

    delay = 0
    for section in insult
      do (section) ->
        delay += Math.random() * 1500
        setTimeout (->
          msg.send section(name: name)
          ), delay

Allow for a plurality of ass.

Allow for a plurality of ass.


class FakeWindow
  clearInterval: sinon.spy()
  setInterval: sinon.spy -> Math.random()
  localStorage:
    getItem: sinon.stub().returns('[]')
    setItem: sinon.stub()
  document:
    hidden: false

module.exports = FakeWindow

_ = require 'underscore'

EmptyFn = ->
  return undefined

class FakeWindow
  clearInterval: EmptyFn
  setInterval: -> Math.random()
  localStorage:
    getItem: -> []
    setItem: EmptyFn
  document:
    hidden: false

  constructor: ->
    for method in _.functions(@)
      sinon.spy(@, method)

module.exports = FakeWindow

Make FakeWindow spy on itself when instantiated


packages: [
  "atom-beautify"
  "atom-ide-ui"
  "atom-python-virtualenv"
  "autocomplete-python"
  "autocomplete-robot-framework"
  "build-gradle"
  "busy-signal"
  "editorconfig"
  "file-icons"
  "highlight-selected"
  "hyperclick"
  "hyperclick-robot-framework"
  "ide-flowtype"
  "ide-java"
  "ide-php"
  "ide-python"
  "ide-typescript"
  "intentions"
  "js-refactor"
  "language-docker"
  "language-gitignore"
  "language-gradle"
  "language-ini"
  "language-restructuredtext"
  "language-robot-framework"
  "language-twig"
  "linter"
  "linter-flake8"
  "linter-jshint"
  "linter-phpcs"
  "linter-phpmd"
  "linter-python-pep8"
  "linter-sass-lint"
  "linter-twig"
  "linter-ui-default"
  "markdown-scroll-sync"
  "package-sync"
  "platformio-ide-terminal"
  "python-tools"
  "refactor"
  "rst-preview"
  "script"
  "tree-view-git-status"
  "zenburn-syntax"
  "zenburn-ui"
]

packages: [
  "atom-beautify"
  "atom-ide-ui"
  "atom-python-virtualenv"
  "autocomplete-python"
  "autocomplete-robot-framework"
  "build-gradle"
  "busy-signal"
  "editorconfig"
  "emmet"
  "file-icons"
  "highlight-selected"
  "hyperclick"
  "hyperclick-robot-framework"
  "ide-flowtype"
  "ide-java"
  "ide-php"
  "ide-python"
  "ide-typescript"
  "intentions"
  "js-refactor"
  "language-docker"
  "language-gitignore"
  "language-gradle"
  "language-ini"
  "language-restructuredtext"
  "language-robot-framework"
  "language-twig"
  "linter"
  "linter-flake8"
  "linter-jshint"
  "linter-phpcs"
  "linter-phpmd"
  "linter-python-pep8"
  "linter-sass-lint"
  "linter-twig"
  "linter-ui-default"
  "markdown-scroll-sync"
  "package-sync"
  "platformio-ide-terminal"
  "python-tools"
  "refactor"
  "rst-preview"
  "script"
  "tree-view-git-status"
  "zenburn-syntax"
  "zenburn-ui"
]

Add Emmet plugin to Atom.

Add Emmet plugin to Atom.


humanizeDuration = require ".."

assert = require "assert"
fs = require "fs"
path = require "path"
parseCSV = require "csv-parse"

options = (language) ->
  return {
    language: language
    delimiter: "+"
    units: [
      "year"
      "month"
      "week"
      "day"
      "hour"
      "minute"
      "second"
      "millisecond"
    ]
  }

describe "localized humanization", ->

  definitionsPath = path.resolve(__dirname, "definitions")

  languages = []
  for file in fs.readdirSync(definitionsPath)
    if path.extname(file) is ".csv"
      languages.push path.basename(file, ".csv")

  for language in languages

    describe "for #{language}", ->

      pairs = null
      before (done) ->
        file = path.resolve(definitionsPath, language + ".csv")
        fs.readFile file, { encoding: "utf8" }, (err, data) ->
          return done(err) if err?
          parseCSV data, (err, rows) ->
            return done(err) if err?
            pairs = rows.map (r) -> [parseInt(r[0]), r[1]]
            done()

      it "humanizes with arguments", ->
        for pair in pairs
          result = humanizeDuration(pair[0], options(language))
          assert.equal(result, pair[1])

      it "humanizes with a humanizer", ->
        h = humanizeDuration.humanizer(options(language))
        for pair in pairs
          assert.equal(h(pair[0]), pair[1])

humanizeDuration = require ".."

assert = require "assert"
fs = require "fs"
path = require "path"
parseCSV = require "csv-parse"

options = (language) ->
  return {
    language: language
    delimiter: "+"
    units: [
      "year"
      "month"
      "week"
      "day"
      "hour"
      "minute"
      "second"
      "millisecond"
    ]
  }

describe "localized humanization", ->

  definitionsPath = path.resolve(__dirname, "definitions")

  languages = []
  for file in fs.readdirSync(definitionsPath)
    if path.extname(file) is ".csv"
      languages.push path.basename(file, ".csv")

  languages.forEach (language) ->

    describe "for #{language}", ->

      pairs = null
      before (done) ->
        file = path.resolve(definitionsPath, language + ".csv")
        fs.readFile file, { encoding: "utf8" }, (err, data) ->
          return done(err) if err?
          parseCSV data, (err, rows) ->
            return done(err) if err?
            pairs = rows.map (r) -> [parseFloat(r[0]), r[1]]
            done()

      it "humanizes with arguments", ->
        for pair in pairs
          result = humanizeDuration(pair[0], options(language))
          assert.equal(result, pair[1])

      it "humanizes with a humanizer", ->
        h = humanizeDuration.humanizer(options(language))
        for pair in pairs
          assert.equal(h(pair[0]), pair[1])

Fix tests that'd give false positives

Fix tests that'd give false positives


_ = require "underscore"
$ = require "jquery"
net = require "net"
{AppDispatcher} = require "./dispatchers"

setupGlobals = (g, win) ->
  g = _.extend g,
    window: win.window
    document: win.window.document
    navigator: win.window.navigator

configureReload = (document) ->
  client = net.connect {port: 35729}, ->
    script = document.createElement "script"
    script.src = "http://localhost:35729/livereload.js"
    document.body.appendChild script

module.exports = (gui) ->
  win = gui.Window.get()
  win.showDevTools()

  $(window).ready ->
    setupGlobals global, win
    configureReload win.window.document
    require("./components/app")(window.document.body)

_ = require "underscore"
$ = require "jquery"
net = require "net"
{AppDispatcher} = require "./dispatchers"

setupGlobals = (g, win) ->
  g = _.extend g,
    window: win.window
    document: win.window.document
    navigator: win.window.navigator

configureReload = (document) ->
  client = net.connect {port: 35729}, ->
    script = document.createElement "script"
    script.src = "http://localhost:35729/livereload.js"
    document.body.appendChild script

module.exports = (gui) ->
  win = gui.Window.get()
  win.showDevTools()

  nativeMenuBar = new gui.Menu type: "menubar"
  try
    nativeMenuBar.createMacBuiltin "Dide"
    win.menu = nativeMenuBar
  catch ex
    console.log ex.message

  $(window).ready ->
    setupGlobals global, win
    configureReload win.window.document
    require("./components/app")(window.document.body)

Add code to enable native menu and fix copy-n-paste

This fix was from https://github.com/nwjs/nw.js/issues/1955.


Sprangular.directive 'creditCardForm', ->
  restrict: 'E'
  templateUrl: 'credit_cards/form.html'
  scope:
    creditCard: '='
  controller: ($scope) ->
    $scope.months = [
      {index: 1, name: 'January'},
      {index: 2, name: 'February'},
      {index: 3, name: 'March'},
      {index: 4, name: 'April'},
      {index: 5, name: 'May'},
      {index: 6, name: 'June'},
      {index: 7, name: 'July'},
      {index: 8, name: 'August'},
      {index: 9, name: 'September'},
      {index: 10, name: 'October'},
      {index: 11, name: 'November'},
      {index: 12, name: 'December'}
    ]

    currentYear = (new Date).getFullYear()
    $scope.years = [currentYear .. currentYear+15]

    $scope.$watch 'creditCard.number', (number) ->
      return unless number
      $scope.creditCard.lastDigits = number.substr(-4)
      $scope.creditCard.determineType()

Sprangular.directive 'creditCardForm', ->
  restrict: 'E'
  templateUrl: 'credit_cards/form.html'
  scope:
    creditCard: '='
  controller: ($scope, $locale) ->
    $scope.months = _.map $locale.DATETIME_FORMATS.MONTH, (month, index) ->
      {"index": index, "name": month}

    currentYear = (new Date).getFullYear()
    $scope.years = [currentYear .. currentYear+15]

    $scope.$watch 'creditCard.number', (number) ->
      return unless number
      $scope.creditCard.lastDigits = number.substr(-4)
      $scope.creditCard.determineType()

Use angular locale for credit card months


# Copyright (c) 2012 Mattes Groeger
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

#= require LinkGrabber

document.body.onmouseup = (event) ->
	chrome.extension.sendMessage({type:"verifySelection", links:getLinksFromSelection()})

document.body.onkeyup = (event) ->
	chrome.extension.sendMessage({type:"verifySelection", links:getLinksFromSelection()})

getLinksFromSelection = ->
	selection = window.getSelection()
	LinkGrabber.fromSelection(selection).allLinks()

# Copyright (c) 2012 Mattes Groeger
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

#= require LinkGrabber

document.body.onmouseup = (event) ->
	window.setTimeout(->
		chrome.extension.sendMessage({type:"verifySelection", links:getLinksFromSelection()})
	, 0)

document.body.onkeyup = (event) ->
	chrome.extension.sendMessage({type:"verifySelection", links:getLinksFromSelection()})

getLinksFromSelection = ->
	selection = window.getSelection()
	LinkGrabber.fromSelection(selection).allLinks()

Update context menu after deselection click


{registerOrUpdateElement, SpacePenDSL} = require 'atom-utils'

module.exports =
class CSVProgressElement extends HTMLElement
  SpacePenDSL.includeInto(this)

  @content: ->
    @div class: 'wrapper', =>
      @label class: 'bytes', outlet: 'bytesLabel', '---'
      @label class: 'lines', outlet: 'linesLabel', '---'
      @div class: 'block', =>
        @tag 'progress', max: '100', outlet: 'progress'

  createdCallback: ->

  attachedCallback: ->

  updateReadData: (input, lines) ->
    progressData = input.getProgress()
    @linesLabel.textContent = "#{lines} #{if lines is 1 then 'line' else 'lines'}"
    @bytesLabel.textContent = "#{progressData.length}/#{progressData.total}"
    @progress.setAttribute('value', Math.floor(progressData.ratio * 100))

  updateFillTable: (lines, ratio) ->
    @linesLabel.textContent = "#{lines} #{if lines is 1 then 'row' else 'rows'} added"
    @bytesLabel.textContent = ''
    @progress.setAttribute('value', Math.floor(ratio * 100))

module.exports =
CSVPreviewElement =
registerOrUpdateElement 'atom-csv-progress', CSVProgressElement.prototype

{registerOrUpdateElement, SpacePenDSL} = require 'atom-utils'

byteUnits = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']

module.exports =
class CSVProgressElement extends HTMLElement
  SpacePenDSL.includeInto(this)

  @content: ->
    @div class: 'wrapper', =>
      @label class: 'bytes', outlet: 'bytesLabel', '---'
      @label class: 'lines', outlet: 'linesLabel', '---'
      @div class: 'block', =>
        @tag 'progress', max: '100', outlet: 'progress'

  updateReadData: (input, lines) ->
    progressData = input.getProgress()
    @linesLabel.textContent = "#{lines} #{if lines is 1 then 'line' else 'lines'}"

    {total, length, ration} = progressData

    byteScale = @getByteScale(total)
    byteDivider = Math.max(1, Math.pow(1000, byteScale))
    unit = @getUnit(byteScale)

    @bytesLabel.textContent = "#{(length / byteDivider).toFixed(1)}/#{(total / byteDivider).toFixed(1)}#{unit}"
    @progress.setAttribute('value', Math.floor(progressData.ratio * 100))

  getByteScale: (size) ->
    i = 0

    while size > 1000
      size = size / 1000
      i++

    i

  getUnit: (scale) -> byteUnits[scale]

  updateFillTable: (lines, ratio) ->
    @linesLabel.textContent = "#{lines} #{if lines is 1 then 'row' else 'rows'} added"
    @bytesLabel.textContent = ''
    @progress.setAttribute('value', Math.floor(ratio * 100))

module.exports =
CSVPreviewElement =
registerOrUpdateElement 'atom-csv-progress', CSVProgressElement.prototype

Add human readable file size in progress


{WorkspaceView} = require 'atom'
require 'fs'

format = require '../lib/format'

describe "JSFormat package tests", ->
  beforeEach ->
    atom.workspaceView = new WorkspaceView()
    atom.workspace = atom.workspaceView.model

  # JSFormat tests here

  describe "when the textbuffer is being formatted", ->
    beforeEach ->
      atom.workspaceView.attachToDom()

    it "can format the whole buffer with the use of the command", ->
      # general format test

      waitsForPromise ->
        atom.workspace.open('specfiles/index.js')

      runs ->
        @fileText = atom.workspace.getActiveTextEditor().getText()
        atom.workspaceView.getActiveView().trigger 'jsformat:format'

      runs ->
        # just check that some whitespace and other goodies got added
        expect(atom.workspace.getActiveTextEditor().getText()).not.toMatch(@fileText)

    it "can format the whole buffer if Format on save is turned on", ->
      # format_on_save test

      waitsForPromise ->
        atom.workspace.open('specfiles/index.js')

      runs ->
        fileText = atom.workspace.getActiveTextEditor().getText()
        atom.config.set('jsformat.format_on_save', true)
        atom.workspace.getActiveTextEditor().save()

        # just check that some whitespace and other goodies got added
        expect(atom.workspace.getActiveTextEditor().getText()).not.toMatch(fileText)
        atom.config.set('jsformat.format_on_save', false)

Format on save test passing

Format on save test passing


React = require 'react'
{Testing, expect, sinon, _} = require 'openstax-react-components/test/helpers'

Collection = require 'task/collection'
{Progress} = require 'progress'
TASK = require 'cc/tasks/C_UUID/m_uuid/GET'

Wrapper = React.createClass
  childContextTypes:
    moduleUUID:     React.PropTypes.string

  getChildContext: ->
    _.pick @props, 'moduleUUID', 'collectionUUID'

  render: ->
    React.createElement(Progress, @props)

describe 'Progress Component', ->

  beforeEach ->
    @props =
      moduleUUID: 'm_uuid'

    Collection.load("#{@props.collectionUUID}/#{@props.moduleUUID}", _.extend({}, TASK, @props))

  # Note. somethings wrong with the format of the task.  It doesn't render the title text from it
  it 'renders status', ->
    Testing.renderComponent(Wrapper, props: @props).then ({dom, element}) ->
      expect(dom.querySelector('.concept-coach-progress-page-title')).not.to.be.null

React = require 'react'
{Testing, expect, sinon, _} = require 'openstax-react-components/test/helpers'

Collection = require 'task/collection'
{Progress} = require 'progress'
TASK = require 'cc/tasks/C_UUID/m_uuid/GET'

Wrapper = React.createClass
  childContextTypes:
    moduleUUID:     React.PropTypes.string
    collectionUUID: React.PropTypes.string

  getChildContext: ->
    _.pick @props, 'moduleUUID', 'collectionUUID'

  render: ->
    React.createElement(Progress, @props)

describe 'Progress Component', ->

  beforeEach ->
    @props =
      moduleUUID: 'm_uuid'
      collectionUUID: 'C_UUID'

    Collection.load("#{@props.collectionUUID}/#{@props.moduleUUID}", _.extend({}, TASK, @props))

  # Note. somethings wrong with the format of the task.  It doesn't render the title text from it
  it 'renders status', ->
    Testing.renderComponent(Wrapper, props: @props).then ({dom, element}) ->
      expect(dom.querySelector('.concept-coach-progress-page-title')).not.to.be.null

Add collectionUUID to context & props

Add collectionUUID to context & props


nav = document.querySelectorAll('header.page-header')[0]
window.onscroll = ->
  if window.pageYOffset > 400
    nav.classList.add 'start'
  else
    nav.classList.remove 'start'
  return

nav = document.querySelectorAll('header.page-header')[0]
window.onscroll = ->
  if window.pageYOffset > 150
    nav.classList.add 'start'
  else
    nav.classList.remove 'start'
  return

Change header sooner on homepage

Change header sooner on homepage


path = require('path')
gulp = require('gulp')
coffee = require('gulp-coffee')
inlinesource = require('gulp-inline-source')
mocha = require('gulp-mocha')
shell = require('gulp-shell')
packageJSON = require('./package.json')

OPTIONS =
	files:
		coffee: [ 'lib/**/*.coffee', 'gulpfile.coffee' ]
		app: 'lib/**/*.coffee'
		tests: 'tests/**/*.spec.coffee'
		pages: 'lib/auth/pages/*.ejs'
	directories:
		build: 'build/'

gulp.task 'pages', ->
	gulp.src(OPTIONS.files.pages)
		.pipe(inlinesource())
		.pipe(gulp.dest('build/auth/pages'))

gulp.task 'coffee', ->
	gulp.src(OPTIONS.files.app)
		.pipe(coffee(bare: true, header: true))
		.pipe(gulp.dest(OPTIONS.directories.build))

gulp.task 'test', ->
	gulp.src(OPTIONS.files.tests, read: false)
		.pipe(mocha({
			reporter: 'min'
		}))

gulp.task 'build', [
	'coffee',
	'pages'
]

gulp.task 'watch', [ 'build' ], ->
	gulp.watch([ OPTIONS.files.coffee ], [ 'build' ])

path = require('path')
gulp = require('gulp')
coffee = require('gulp-coffee')
inlinesource = require('gulp-inline-source')
mocha = require('gulp-mocha')
shell = require('gulp-shell')
packageJSON = require('./package.json')

OPTIONS =
	files:
		coffee: [ 'lib/**/*.coffee', 'gulpfile.coffee' ]
		app: 'lib/**/*.coffee'
		tests: 'tests/**/*.spec.coffee'
		pages: 'lib/auth/pages/*.ejs'
	directories:
		build: 'build/'

gulp.task 'pages', ->
	gulp.src(OPTIONS.files.pages)
		.pipe(inlinesource())
		.pipe(gulp.dest('build/auth/pages'))

gulp.task 'coffee', ->
	gulp.src(OPTIONS.files.app)
		.pipe(coffee(bare: true, header: true))
		.pipe(gulp.dest(OPTIONS.directories.build))

gulp.task 'test', ->
	gulp.src(OPTIONS.files.tests, read: false)
		.pipe(mocha({
			reporter: 'spec'
		}))

gulp.task 'build', [
	'coffee',
	'pages'
]

gulp.task 'watch', [ 'build' ], ->
	gulp.watch([ OPTIONS.files.coffee ], [ 'build' ])

Use spec test reporter, so we can debug with output


'use strict'

[utils, Model] = ['utils', 'model'].map require

exports.Request = require('./request.coffee')()
exports.Response = require('./response.coffee')()

exports.init = ->

	uri = location.pathname

	uid = utils.uid()

	res = @onRequest
		uid: uid
		method: @constructor.GET
		uri: uri.slice 1
		data: null

exports.sendRequest = (opts, callback) ->

	xhr = new XMLHttpRequest

	xhr.open opts.method, opts.url, true
	xhr.setRequestHeader 'X-Expected-Type', Model.OBJECT
	xhr.onload = ->
		response = utils.tryFunc JSON.parse, null, xhr.response, xhr.response
		callback xhr.status, response

	xhr.send()

'use strict'

[utils, Model] = ['utils', 'model'].map require

exports.Request = require('./request.coffee')()
exports.Response = require('./response.coffee')()

exports.init = ->

	# Send internal request to change the page based on the URI
	changePage = (uri) =>

		# change browser URI in the history
		history.pushState null, '', uri

		# send internal request
		uid = utils.uid()

		res = @onRequest
			uid: uid
			method: @constructor.GET
			uri: uri.slice 1
			data: null

	# don't refresh page on click anchor
	document.addEventListener 'click', (e) ->

		{target} = e

		# consider only anchors
		# omit anchors with the `target` attribute
		return if target.nodeName isnt 'A' or target.getAttribute('target')

		# avoid browser to refresh page
		e.preventDefault()

		# change page to the anchor pathname
		changePage target.pathname

	# change page to the current one
	changePage location.pathname

exports.sendRequest = (opts, callback) ->

	xhr = new XMLHttpRequest

	xhr.open opts.method, opts.url, true
	xhr.setRequestHeader 'X-Expected-Type', Model.OBJECT
	xhr.onload = ->
		response = utils.tryFunc JSON.parse, null, xhr.response, xhr.response
		callback xhr.status, response

	xhr.send()

Add support for anchors in the browser impl


module.exports =

  build: (options) =>

    field = options.field

    fieldClass = require "./#{field.get 'as'}"

    new fieldClass
      controller: options.controller
      presenter: field
      fieldStyle: options.fieldStyle

module.exports =

  build: (options) =>

    field = options.field

    fieldClass = require "./#{field.get 'as'}"

    new fieldClass
      controller: options.controller
      presenter: field
      name: field.get 'key'
      fieldStyle: options.fieldStyle

Set 'name' on editor view based on field key


checkFlag = require './checkFlag'

module.exports = isVideoFeatureEnabled = ->

  return yes

  # for now we are only allowing super-admins to start video chat.
  # After we release it publicly, we only need to change the logic here. ~Umut
  # checkFlag 'super-admin'

kd = require 'kd'

module.exports = isVideoFeatureEnabled = ->

  not kd.singletons.mainController.isFeatureDisabled 'video-collaboration'

Use mainController's feature check to enable video


DEFAULT_ENV = 'staging'

API_HOSTS =
  production: 'https://panoptes.zooniverse.org'
  staging: 'https://panoptes-staging.zooniverse.org'

API_APPLICATION_IDS =
  production: 'f79cf5ea821bb161d8cbb52d061ab9a2321d7cb169007003af66b43f7b79ce2a'
  staging: '535759b966935c297be11913acee7a9ca17c025f9f15520e7504728e71110a27'

hostFromBrowser = location?.search.match(/\W?panoptes-api-host=([^&]+)/)?[1]
appFromBrowser = location?.search.match(/\W?panoptes-api-application=([^&]+)/)?[1]

hostFromShell = process.env.PANOPTES_API_HOST
appFromShell = process.env.PANOPTES_API_APPLICATION

envFromBrowser = location?.search.match(/\W?env=(\w+)/)?[1]
envFromShell = process.env.NODE_ENV

env = envFromBrowser ? envFromShell ? DEFAULT_ENV
env = 'production'

module.exports =
  host: hostFromBrowser ? hostFromShell ? API_HOSTS[env]
  clientAppID: appFromBrowser ? appFromShell ? API_APPLICATION_IDS[env]

DEFAULT_ENV = 'staging'

API_HOSTS =
  production: 'https://www.zooniverse.org'
  staging: 'https://panoptes-staging.zooniverse.org'

API_APPLICATION_IDS =
  production: 'f79cf5ea821bb161d8cbb52d061ab9a2321d7cb169007003af66b43f7b79ce2a'
  staging: '535759b966935c297be11913acee7a9ca17c025f9f15520e7504728e71110a27'

hostFromBrowser = location?.search.match(/\W?panoptes-api-host=([^&]+)/)?[1]
appFromBrowser = location?.search.match(/\W?panoptes-api-application=([^&]+)/)?[1]

hostFromShell = process.env.PANOPTES_API_HOST
appFromShell = process.env.PANOPTES_API_APPLICATION

envFromBrowser = location?.search.match(/\W?env=(\w+)/)?[1]
envFromShell = process.env.NODE_ENV

env = envFromBrowser ? envFromShell ? DEFAULT_ENV
env = 'production'

module.exports =
  host: hostFromBrowser ? hostFromShell ? API_HOSTS[env]
  clientAppID: appFromBrowser ? appFromShell ? API_APPLICATION_IDS[env]

Change API host to zooniverse.org

Change API host to zooniverse.org


class Dashing.Textcarousel extends Dashing.Widget

  ready: ->
    @currentIndex = 0
    @textElem = $(@node).find('p')
    @nextComment()
    @startCarousel()

  onData: (data) ->
    @currentIndex = 0

  startCarousel: ->
    setInterval(@nextComment, 8000)

  nextComment: =>
    texts = @get('texts')
    if texts
      @textElem.fadeOut =>
        @currentIndex = (@currentIndex + 1) % texts.length
        @set 'current_text', texts[@currentIndex]
        @textElem.fadeIn()

class Dashing.Textcarousel extends Dashing.Widget

  ready: ->
    @currentIndex = 0
    @textElem = $(@node).find('p')
    @nextComment()
    @startCarousel()

  onData: (data) ->
    # attempt to pick up where we left off, but default to starting over
    @currentIndex = Math.max(0, @get('texts').indexOf(@get('current_text')))

  startCarousel: ->
    setInterval(@nextComment, 8000)

  nextComment: =>
    texts = @get('texts')
    if texts
      @textElem.fadeOut =>
        @currentIndex = (@currentIndex + 1) % texts.length
        @set 'current_text', texts[@currentIndex]
        @textElem.fadeIn()

Make text carousel pick up where it left off


class PgHoffTypes
    @Type:
        1184:
            name: 'Timestamp'
            format: (value) ->
                return new Date(value).toLocaleString(atom.config.get('pg-hoff.locale'))
            compare: (left, right) ->
                return Date.parse(left) - Date.parse(right)
        23:
            name: 'Integer'
            compare: (left, right) ->
                return left - right
        25:
            name: 'Text'
            compare: (left, right) ->
                if left < right
                    return -1
                else if left > right
                    return 1
                else
                    return 0
        701:
            name: 'Numeric'
            compare: (left, right) ->
                return left - right
        114:
            name: 'JSON'
            format: (text) ->
                return JSON.stringify(JSON.parse(text), null, '  ')

module.exports = PgHoffTypes

class PgHoffTypes
    @Type:
        1184:
            name: 'Timestamp'
            format: (value) ->
                return new Date(value).toLocaleString(atom.config.get('pg-hoff.locale'))
            compare: (left, right) ->
                return Date.parse(left) - Date.parse(right)
        23:
            name: 'Integer'
            compare: (left, right) ->
                return left - right
        25:
            name: 'Text'
            compare: (left, right) ->
                if left < right
                    return -1
                else if left > right
                    return 1
                else
                    return 0
        1043:
            name: 'Character Varying'
            compare: (left, right) ->
                if left < right
                    return -1
                else if left > right
                    return 1
                else
                    return 0
        701:
            name: 'Numeric'
            compare: (left, right) ->
                return left - right
        20:
            name: 'Bigint'
            compare: (left, right) ->
                return left - right
        114:
            name: 'JSON'
            format: (text) ->
                return JSON.stringify(JSON.parse(text), null, '  ')

module.exports = PgHoffTypes

Add support for bigint and character varying


translate = require 'lib/translate'
Classification = require 'models/classification'
User = require 'zooniverse/lib/models/user'

userCount = -> User.count or 0

none = -> ''
social = -> translate('classify.splits.social').replace '###', userCount()
task = -> translate 'classify.splits.task'
science = -> translate 'classify.splits.science'

countClassifications = ->
  return 0 unless User.current?
  count = User.current?.project?.classification_count || 0
  count += Classification.sentThisSession

oneClassification = -> countClassifications() is 1
lessThanThreeClassifications = -> countClassifications() <= 3

splits =
  classifier_messaging:
    a: body: none,    isShown: oneClassification
    b: body: none,    isShown: lessThanThreeClassifications
    c: body: social,  isShown: oneClassification
    d: body: social,  isShown: lessThanThreeClassifications
    e: body: task,    isShown: oneClassification
    f: body: task,    isShown: lessThanThreeClassifications
    g: body: science, isShown: oneClassification
    h: body: science, isShown: lessThanThreeClassifications

get = (key) ->
  body = ''

  if User.current?.project?.splits?[key]?
    splitId = User.current.project.splits[key]
    message = splits[key][splitId]
    body = message.body() if message.isShown()

  body

module.exports = {get}

translate = require 'lib/translate'
Classification = require 'models/classification'
User = require 'zooniverse/lib/models/user'

userCount = -> User.count or 0

none = -> ''
social = -> translate('classify.splits.social').replace '###', userCount()
task = -> translate 'classify.splits.task'
science = -> translate 'classify.splits.science'

countClassifications = ->
  return 0 unless User.current?
  count = User.current?.project?.classification_count || 0
  count += Classification.sentThisSession

oneClassification = -> countClassifications() is 1
lessThanThreeClassifications = -> countClassifications() <= 4 # That's 3 + tutorial

splits =
  classifier_messaging:
    a: body: none,    isShown: oneClassification
    b: body: none,    isShown: lessThanThreeClassifications
    c: body: social,  isShown: oneClassification
    d: body: social,  isShown: lessThanThreeClassifications
    e: body: task,    isShown: oneClassification
    f: body: task,    isShown: lessThanThreeClassifications
    g: body: science, isShown: oneClassification
    h: body: science, isShown: lessThanThreeClassifications

get = (key) ->
  body = ''

  if User.current?.project?.splits?[key]?
    splitId = User.current.project.splits[key]
    message = splits[key][splitId]
    body = message.body() if message.isShown()

  body

module.exports = {get}

Change split to ignore tutorial

Change split to ignore tutorial


DefaultFileIcons = require '../lib/default-file-icons'
getIconServices = require '../lib/get-icon-services'

describe 'IconServices', ->
  describe 'FileIcons', ->
    afterEach ->
      getIconServices().resetFileIcons()
      getIconServices().resetElementIcons()

    it 'provides a default', ->
      expect(getIconServices().fileIcons).toBeDefined()
      expect(getIconServices().fileIcons).toBe(DefaultFileIcons)

    it 'allows the default to be overridden', ->
      service = new Object
      getIconServices().setFileIcons service
      expect(getIconServices().fileIcons).toBe(service)

    it 'allows the service to be reset to the default easily', ->
      service = new Object
      getIconServices().setFileIcons service
      getIconServices().resetFileIcons()
      expect(getIconServices().fileIcons).toBe(DefaultFileIcons)

# vim: ts=2
DefaultFileIcons = require '../lib/default-file-icons'
getIconServices = require '../lib/get-icon-services'
{Disposable} = require 'atom'

describe 'IconServices', ->
  afterEach ->
    getIconServices().resetFileIcons()
    getIconServices().resetElementIcons()

  describe 'FileIcons', ->
    it 'provides a default', ->
      expect(getIconServices().fileIcons).toBeDefined()
      expect(getIconServices().fileIcons).toBe(DefaultFileIcons)

    it 'allows the default to be overridden', ->
      service = new Object
      getIconServices().setFileIcons service
      expect(getIconServices().fileIcons).toBe(service)

    it 'allows the service to be reset to the default easily', ->
      service = new Object
      getIconServices().setFileIcons service
      getIconServices().resetFileIcons()
      expect(getIconServices().fileIcons).toBe(DefaultFileIcons)

  describe 'ElementIcons', ->
    it 'does not provide a default', ->
      expect(getIconServices().elementIcons).toBe(null)

    it 'consumes the ElementIcons service', ->
      service = ->
      getIconServices().setElementIcons service
      expect(getIconServices().elementIcons).toBe(service)

    it 'does not call the FileIcons service when the ElementIcons service is provided', ->
      elementIcons = ->
        new Disposable ->
      fileIcons =
        iconClassForPath: ->
      spyOn(fileIcons, 'iconClassForPath').andCallThrough()
      getIconServices().setElementIcons elementIcons
      getIconServices().setFileIcons fileIcons
      getIconServices().updateFileIcon(file: {}, fileName: classList: add: ->)
      expect(fileIcons.iconClassForPath).not.toHaveBeenCalled()

Add specs for element-icons service

Add specs for element-icons service


jQuery.fn.render = (data) ->
  data     = [data] unless jQuery.isArray(data)
  context  = this
  template = this.clone()

  # Iterate over data objects
  jQuery.each data, (index, object) ->
    tmp = template.clone()

    # Iterate over keys in the data object
    jQuery.each object, (key, value) ->

      [klass, attribute] = key.split('@')
      tmp.find(".#{klass}").each ->

        if attribute
          jQuery(this).attr attribute, value
        else
          jQuery(this).prepend value

    # Add rendered template to dom
    context.before(tmp)

  return context.remove()

'

            John            That rules

            Arnold            Great post!

      '

'

            John            That rules

            Arnold            Great post!

      '

Handle list of data objects

Handle list of data objects


TentStatus.UnifiedCollection = class UnifiedCollection extends Marbles.UnifiedCollection

  fetchNext: (options = {}) =>
    collections = _.select @collections(), (c) => !!c.pagination.next
    next_params = null
    for collection in collections
      continue unless collection.pagination.next
      next_params ?= {}
      next_params[collection.cid] = Marbles.History::parseQueryParams(collection.pagination.next)
    return false unless next_params
    @fetch(next_params, _.extend({ append: true }, options))

  postTypes: =>
    types = []
    for collection in @collections()
      types.push(collection.postTypes()...)
    _.uniq(types)

TentStatus.UnifiedCollection = class UnifiedCollection extends Marbles.UnifiedCollection

  sortModelsBy: (model) =>
    model.get('received_at') * -1

  fetchNext: (options = {}) =>
    collections = _.select @collections(), (c) => !!c.pagination.next
    next_params = null
    for collection in collections
      continue unless collection.pagination.next
      next_params ?= {}
      next_params[collection.cid] = Marbles.History::parseQueryParams(collection.pagination.next)
    return false unless next_params
    @fetch(next_params, _.extend({ append: true }, options))

  postTypes: =>
    types = []
    for collection in @collections()
      types.push(collection.postTypes()...)
    _.uniq(types)

Sort by received_at for merging unified collection results


linterPath = atom.packages.getLoadedPackage("linter").path
Linter = require "#{linterPath}/lib/linter"

class LinterPyflakes extends Linter
  # The syntax that the linter handles. May be a string or
  # list/tuple of strings. Names should be all lowercase.
  @syntax: 'source.python'

  # A string, list, tuple or callable that returns a string, list or tuple,
  # containing the command line (with arguments) used to lint.
  cmd: 'pyflakes'

  executablePath: null

  linterName: 'pyflakes'

  # A regex pattern used to extract information from the executable's output.
  # regex: ""/path/to/python/file.py:28: redefinition of unused 'models' from line 5"
  regex: ':(?<line>\\d+): (?<message>.*?)\n'

  constructor: (editorView)->
    @executablePath = atom.config.get 'linter-pyflakes.pyflakesExecutablePath'

module.exports = LinterPyflakes

linterPath = atom.packages.getLoadedPackage("linter").path
Linter = require "#{linterPath}/lib/linter"

class LinterPyflakes extends Linter
  # The syntax that the linter handles. May be a string or
  # list/tuple of strings. Names should be all lowercase.
  @syntax: 'source.python'

  # A string, list, tuple or callable that returns a string, list or tuple,
  # containing the command line (with arguments) used to lint.
  cmd: 'pyflakes'

  executablePath: null

  linterName: 'pyflakes'

  # A regex pattern used to extract information from the executable's output.
  # regex: ""/path/to/python/file.py:28: redefinition of unused 'models' from line 5"
  regex: ':(?<line>\\d+): (?<message>.*?)\n'

  constructor: (editor)->
    super editor
    @executablePath = atom.config.get 'linter-pyflakes.pyflakesExecutablePath'

module.exports = LinterPyflakes

Call constructor to initialize @cwd

Call constructor to initialize @cwd

Fixes similar error to https://github.com/AtomLinter/linter-pep8/issues/2


# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

$ ->
    $('.update').on 'input', (event) ->
        $(this).parent().find('.update').val(this.value)

    $('#select_all_btn').on 'click', (e) ->
        $('.checkbox').prop 'checked', true
    $('#deselect_all_btn').on 'click', (e) ->
        $('.checkbox').prop 'checked', false

    $('#toggle_all_btn').on 'click', (e) ->
        $('.checkbox').each () ->
            $this = $(this)
            $this.prop 'checked', !$this.prop('checked')

    $('.party-button').on 'click', (e) ->
        togglePartyMode()

    $('.bulb').on 'click', (e) ->
      setSliders(parseInt(e.target.dataset.lightId))

    $('#change_btn').on 'click', (e) ->
        e.preventDefault()
        $.post '/lights/multi_update', $("#hue-form").serialize(), (data) ->
            updateLights(data)
            renderLamps()

    $('.link-btn').on 'click', (e) ->
        $.post e.target.dataset.url, (data) ->
            if data != " "
                updateLights(data)
                renderLamps()

    $('.update').on 'input', (e) ->
        draw_hue_canvas()
        draw_sat_canvas()

# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/

$ ->
    $('.update').on 'input', (event) ->
        $(this).parent().find('.update').val(this.value)

    $('#select_all_btn').on 'click', (e) ->
        $('.checkbox').prop 'checked', true
    $('#deselect_all_btn').on 'click', (e) ->
        $('.checkbox').prop 'checked', false

    $('#toggle_all_btn').on 'click', (e) ->
        $('.checkbox').each () ->
            $this = $(this)
            $this.prop 'checked', !$this.prop('checked')

    $('.party-button').on 'click', (e) ->
        togglePartyMode()

    $('.bulb').on 'click', (e) ->
      setSliders(parseInt(e.target.dataset.lightId))
      draw_hue_canvas()
      draw_sat_canvas()

    $('#change_btn').on 'click', (e) ->
        e.preventDefault()
        $.post '/lights/multi_update', $("#hue-form").serialize(), (data) ->
            updateLights(data)
            renderLamps()

    $('.link-btn').on 'click', (e) ->
        $.post e.target.dataset.url, (data) ->
            if data != " "
                updateLights(data)
                renderLamps()

    $('.update').on 'input', (e) ->
        draw_hue_canvas()
        draw_sat_canvas()

Update canvases when a bulb is pressed

Update canvases when a bulb is pressed