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

    propTypes:
        onModelSet: React.PropTypes.func
        name:       React.PropTypes.string

    getDefaultProps: ->
        label: 'Location', name: 'location'

    dataObjects:
        query: ->
            new Lanes.Models.Query({
                autoRetrieve: true
                syncOptions: Lanes.Models.Query.mergedSyncOptions(
                    @props.syncOptions, { include: [ 'address' ] }
                )
                src: Skr.Models.Location, fields: [
                    {id:'id', visible: false}
                    { id: 'code', fixedWidth: 130 }
                    'name'
                ]
            })

    render: ->
        props = _.clone(@props)
        if props.displayFinder
            <LC.RecordFinder ref="finder" sm=3 autoFocus
                commands={@state.commands}
                collection={Skr.Models.Location.all}
                query={@query}
                {...props} />
        else
            <LC.SelectField {...props} choices={Skr.Models.Location.all.models}
                labelField='code' model={@props.model} />

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

    propTypes:
        onModelSet: React.PropTypes.func
        name:       React.PropTypes.string
        hideSingle: React.PropTypes.bool

    getDefaultProps: ->
        label: 'Location', name: 'location'

    dataObjects:
        query: ->
            new Lanes.Models.Query({
                autoRetrieve: true
                syncOptions: Lanes.Models.Query.mergedSyncOptions(
                    @props.syncOptions, { include: [ 'address' ] }
                )
                src: Skr.Models.Location, fields: [
                    {id:'id', visible: false}
                    { id: 'code', fixedWidth: 130 }
                    'name'
                ]
            })

    render: ->
        if @props.hideSingle and Skr.Models.Location.all.length < 2
            return LC.SelectField.renderEmptyColumn(@props)

        props = _.clone(@props)
        if props.displayFinder
            <LC.RecordFinder ref="finder" sm=3 autoFocus
                commands={@state.commands}
                collection={Skr.Models.Location.all}
                query={@query}
                {...props} />
        else
            <LC.SelectField {...props} choices={Skr.Models.Location.all.models}
                fetchOnSelect={false} labelField='code' model={@props.model} />

Allow hiding if operating as single location


@Infeedl ||= {}

@Infeedl.init = ->
  Infeedl.$("[data-infeedl-placement]").each ->
    placement = new Infeedl.Placement($(this).attr("data-infeedl-placement"), this)
    placement.fetch()

Infeedl.$ = jQuery.noConflict()
@Infeedl.init()

@Infeedl ||= {}

@Infeedl.init = ->
  Infeedl.$("[data-infeedl-placement]").each ->
    placement = new Infeedl.Placement(Infeedl.$(this).attr("data-infeedl-placement"), this)
    placement.fetch()

Infeedl.$ = jQuery.noConflict()
@Infeedl.init()

Fix stupid bug with jQuery reference

Fix stupid bug with jQuery reference


grunt = require 'grunt'

module.exports =

  'gh-pages':
    options:
      base: 'gh-pages'
      add: yes
    src: ['**']

  clean: [
    'gh-pages/*'
    '!gh-pages/.gitignore'
    '!gh-pages/template.html'
  ]

  copy:
    expand: yes
    src: [
      'dist/**/*'
      'docs/**/*'
      'lib/**/*'
      'tests/**/*.{css,html,js}'
      'README.md'
    ]
    dest: 'gh-pages/'

  markdown:
    options:
      template: 'gh-pages/template.html'
    src: 'gh-pages/README.md'
    dest: 'gh-pages/index.html'

  task: ->
    grunt.registerTask 'pages', [
      'dist'
      'docs'
      'clean:gh-pages'
      'copy:gh-pages'
      'markdown:gh-pages'
      'gh-pages'
    ]

grunt = require 'grunt'

module.exports =

  'gh-pages':
    options:
      base: 'gh-pages'
      add: yes
    src: ['**']

  clean: [
    'gh-pages/*'
    '!gh-pages/.gitignore'
    '!gh-pages/template.html'
  ]

  copy:
    expand: yes
    src: [
      'dist/**/*'
      'docs/**/*'
      'lib/**/*'
      'tests/**/*'
      '!tests/**/*.{scss,coffee}'
      'README.md'
    ]
    dest: 'gh-pages/'

  markdown:
    options:
      template: 'gh-pages/template.html'
    src: 'gh-pages/README.md'
    dest: 'gh-pages/index.html'

  task: ->
    grunt.registerTask 'pages', [
      'dist'
      'docs'
      'clean:gh-pages'
      'copy:gh-pages'
      'markdown:gh-pages'
      'gh-pages'
    ]

Update Grunt pages task. [ci skip]

Update Grunt pages task. [ci skip]


packages: [
  "advanced-open-file"
  "atom-alignment"
  "atom-beautify"
  "atom-transpose"
  "color-picker"
  "docblockr"
  "editorconfig"
  "emmet"
  "expand-region"
  "language-apache"
  "language-applescript"
  "language-awk"
  "language-babel"
  "language-diff"
  "language-env"
  "language-gitattributes"
  "language-gitignore"
  "language-har"
  "language-hosts"
  "language-ini"
  "language-latex"
  "language-liquid"
  "language-lisp"
  "language-pegjs"
  "language-prolog"
  "language-sca"
  "language-svg"
  "language-tcl"
  "language-viml"
  "language-x86"
  "linter"
  "linter-coffeescript"
  "linter-eslint"
  "linter-flake8"
  "linter-jsonlint"
  "linter-php"
  "linter-shellcheck"
  "linter-ui-default"
  "monokai"
  "package-sync"
  "resize-indent"
  "sort-lines"
  "ssh-config"
  "svg-preview"
  "swap-selection"
  "tabs-to-spaces"
  "teletype"
]

packages: [
  "advanced-open-file"
  "atom-alignment"
  "atom-beautify"
  "atom-transpose"
  "color-picker"
  "docblockr"
  "editorconfig"
  "emmet"
  "expand-region"
  "language-apache"
  "language-applescript"
  "language-awk"
  "language-babel"
  "language-diff"
  "language-env"
  "language-gitattributes"
  "language-gitignore"
  "language-har"
  "language-hosts"
  "language-ini"
  "language-latex"
  "language-liquid"
  "language-lisp"
  "language-pegjs"
  "language-pip"
  "language-prolog"
  "language-sca"
  "language-svg"
  "language-tcl"
  "language-viml"
  "language-x86"
  "linter"
  "linter-coffeescript"
  "linter-eslint"
  "linter-flake8"
  "linter-jsonlint"
  "linter-php"
  "linter-shellcheck"
  "linter-ui-default"
  "monokai"
  "package-sync"
  "resize-indent"
  "sort-lines"
  "ssh-config"
  "svg-preview"
  "swap-selection"
  "tabs-to-spaces"
  "teletype"
]

Add language-pip to Atom package list

Add language-pip to Atom package list


module.exports = (grunt)->
  grunt.initConfig
    pkg: grunt.file.readJSON('package.json')

    jshint:
      options:
        jshintrc: '.jshintrc'

      all: [
        'Standards/**/*.js'
        'PhantomJS/*.js'
      ]

    uglify:
      options:
        banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      dist:
        files:
          'dist/HTMLCS.min.js': [
            'Standards/**/*.js'
            'HTMLCS.js'
            'PhantomJS/runner.js'
          ]

    watch:
      jade:
        files: ['<%= jshint.all %>']
        tasks: ['jshint:all']

  require('load-grunt-tasks') grunt

  grunt.registerTask 'default', ['jshint']
  grunt.registerTask 'build',   ['uglify:dist']

module.exports = (grunt)->
  grunt.initConfig
    pkg: grunt.file.readJSON('package.json')

    jshint:
      options:
        jshintrc: '.jshintrc'

      all: [
        'Standards/**/*.js'
        'PhantomJS/*.js'
      ]

    uglify:
      options:
        banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      dist:
        files:
          'dist/HTMLCS.min.js': [
            'Standards/**/*.js'
            'HTMLCS.js'
            'PhantomJS/runner.js'
            'Auditor/HTMLCSAuditor.js'
          ]

    copy:
      dist:
        files: [
          {
            expand: true
            flatten: true,
            src: 'Auditor/HTMLCSAuditor.css'
            rename: (dest, src) -> dest + '/HTMLCS.css'
            dest: 'dist'
            filter: 'isFile'
          },
          {
            expand: true
            flatten: true,
            src: 'Auditor/Images/*'
            dest: 'dist/Images'
            filter: 'isFile'
          }
        ]
    watch:
      jade:
        files: ['<%= jshint.all %>']
        tasks: ['jshint:all']

  require('load-grunt-tasks') grunt

  grunt.registerTask 'default', ['jshint']
  grunt.registerTask 'build',   ['uglify:dist', 'copy:dist']

Include the auditor gui in the build

Include the auditor gui in the build


{Document} = require 'telepath'

# Public: Manages the deserializers used for serialized state
module.exports =
class DeserializerManager
  constructor: ->
    @deserializers = {}
    @deferredDeserializers = {}

  # Public: Add a deserializer.
  add: (klasses...) ->
    @deserializers[klass.name] = klass for klass in klasses

  # Public: Add a deferred deserializer.
  addDeferred: (name, fn) ->
    @deferredDeserializers[name] = fn

  # Public: Remove a deserializer.
  remove: (klasses...) ->
    delete @deserializers[klass.name] for klass in klasses

  # Public: Deserialize the state and params.
  deserialize: (state, params) ->
    return unless state?

    if deserializer = @get(state)
      stateVersion = state.get?('version') ? state.version
      return if deserializer.version? and deserializer.version isnt stateVersion
      if (state instanceof Document) and not deserializer.acceptsDocuments
        state = state.toObject()
      deserializer.deserialize(state, params)
    else
      console.warn "No deserializer found for", state

  # Public: Get the deserializer for the state.
  get: (state) ->
    return unless state?

    name = state.get?('deserializer') ? state.deserializer
    if @deferredDeserializers[name]
      @deferredDeserializers[name]()
      delete @deferredDeserializers[name]

    @deserializers[name]

{Document} = require 'telepath'

# Public: Manages the deserializers used for serialized state
module.exports =
class DeserializerManager
  constructor: ->
    @deserializers = {}
    @deferredDeserializers = {}

  # Public: Register the given class(es) as deserializers.
  add: (klasses...) ->
    @deserializers[klass.name] = klass for klass in klasses

  # Public: Add a deferred deserializer for the given class name.
  addDeferred: (name, fn) ->
    @deferredDeserializers[name] = fn

  # Public: Remove the given class(es) as deserializers.
  remove: (klasses...) ->
    delete @deserializers[klass.name] for klass in klasses

  # Public: Deserialize the state and params.
  deserialize: (state, params) ->
    return unless state?

    if deserializer = @get(state)
      stateVersion = state.get?('version') ? state.version
      return if deserializer.version? and deserializer.version isnt stateVersion
      if (state instanceof Document) and not deserializer.acceptsDocuments
        state = state.toObject()
      deserializer.deserialize(state, params)
    else
      console.warn "No deserializer found for", state

  # Private: Get the deserializer for the state.
  get: (state) ->
    return unless state?

    name = state.get?('deserializer') ? state.deserializer
    if @deferredDeserializers[name]
      @deferredDeserializers[name]()
      delete @deferredDeserializers[name]

    @deserializers[name]

:memo: Mark ::get as private and tweak comments


ETahi.PhaseHeaderView = Em.View.extend
  templateName: 'phase_header'
  classNames: ['column-header']
  classNameBindings: ['active']
  active: false

  focusIn: (e)->
    @set('active', true)

  phaseNameDidChange: (->
    # race condition with binding and cancel action? :(
    Em.run.later (->
      Tahi.utils.resizeColumnHeaders()
    ), 30
  ).observes('phase.name')

  actions:
    save: ->
      @set('active', false)
      @get('phase').save()

    cancel: ->
      @set('active', false)
      @get('phase').rollback()

ETahi.PhaseHeaderView = Em.View.extend
  templateName: 'phase_header'
  classNames: ['column-header']
  classNameBindings: ['active']
  active: false

  focusIn: (e)->
    @set('active', true)

  phaseNameDidChange: (->
    Ember.run.schedule('afterRender' , this, ->
      Tahi.utils.resizeColumnHeaders()
    )
  ).observes('phase.name')

  actions:
    save: ->
      @set('active', false)
      @get('phase').save()

    cancel: ->
      @set('active', false)
      @get('phase').rollback()

Change out Ember.run.later for Ember.run.schedule


require [
  "jquery"
  "underscore"
  "backbone"
  "foundation"
  "foundation.topbar"
  "raven"
  "AppRouter"
  "signet"
], ($, _, Backbone, foundation, topbar, Raven, Router) ->

  $ ->
    # Config Sentry Raven Client
    if jailbreak.sentry.enabled
      Raven.config(jailbreak.sentry.dsn, {
        whitelistUrls: ['local.jailbreakhq.org', 'builds.jailbreakhq.org']
      }).install();

    # Sentry Foundation javascript events/handlers
    $(document).foundation()

    # Backbone setup
    AppRouter = new Router()

    # Clean up after any previous runs
    window.location.hash = ''
    Backbone.history.stop()

    Backbone.history.start
      pushState: true

    # hook all links on the page
    $(document).on "click", "a[href^='/']", (event) ->

      href = $(event.currentTarget).attr("href")

      # Allow shift+click for new tabs, etc.
      if !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey
        event.preventDefault()

        # Remove leading slashes and hash bangs (backward compatablility)
        url = href.replace(/^\//, "").replace("\#\!\/", "")

        # Instruct Backbone to trigger routing events
        AppRouter.navigate url, { trigger: true }

        return false

require [
  "jquery"
  "underscore"
  "backbone"
  "foundation"
  "foundation.topbar"
  "raven"
  "AppRouter"
  "signet"
  "async"
], ($, _, Backbone, foundation, topbar, Raven, Router) ->

  $ ->
    # Config Sentry Raven Client
    if jailbreak.sentry.enabled
      Raven.config(jailbreak.sentry.dsn, {
        whitelistUrls: ['local.jailbreakhq.org', 'builds.jailbreakhq.org']
      }).install();

    # Sentry Foundation javascript events/handlers
    $(document).foundation()

    # Backbone setup
    AppRouter = new Router()

    # Clean up after any previous runs
    window.location.hash = ''
    Backbone.history.stop()

    Backbone.history.start
      pushState: true

    # hook all links on the page
    $(document).on "click", "a[href^='/']", (event) ->

      href = $(event.currentTarget).attr("href")

      # Allow shift+click for new tabs, etc.
      if !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey
        event.preventDefault()

        # Remove leading slashes and hash bangs (backward compatablility)
        url = href.replace(/^\//, "").replace("\#\!\/", "")

        # Instruct Backbone to trigger routing events
        AppRouter.navigate url, { trigger: true }

        return false

Fix requirejs errors for googles map in QA


BaseView = require 'views/base_view'
Manager = require 'modules/manager'

class DashboardDialog extends BaseView
  className: 'dialog'
  tag: 'div'

  projects: require 'config/projects_config'

  template: require './templates/dashboard_dialog'

  initialize: (options) ->
    @parent = options.parent
    @selected = Manager.get('project')

  events:
    'click span.window-close' : 'close'
    'click button.close' : 'close'
    'click button.new-dashboard' : 'newDashboard'

  render: =>
    @$el.html @template(@)
    @

  close: =>
    @remove()

  newDashboard: =>
    name = @$('input#name').val()
    project = @$('select#project_type').val()
    dashboard = @parent.createDashboard(name, [], project)
    dashboard.save().done =>
      @parent.loadDashboard(dashboard.id)
    @close()

module.exports = DashboardDialog

BaseView = require 'views/base_view'
Manager = require 'modules/manager'

class DashboardDialog extends BaseView
  className: 'dialog'
  tag: 'div'

  projects: require 'config/projects_config'

  template: require './templates/dashboard_dialog'

  initialize: (options) ->
    @parent = options.parent
    @selected = Manager.get('project')

  events:
    'click span.window-close' : 'close'
    'click button.close' : 'close'
    'click button.new-dashboard' : 'newDashboard'

  render: =>
    @$el.html @template(@)
    @

  close: =>
    @remove()

  newDashboard: =>
    name = @$('input#name').val()
    project = @$('select#project_type').val()
    dashboard = @parent.createDashboard(name, [], project)
    dashboard.save().done =>
      @parent.loadDashboard(dashboard.id)
      @parent.navigateToDashboard()
    @close()

module.exports = DashboardDialog

Fix bug where creating a dashboard didn't direct you to its url


#= require dashboard
#= require mock-ajax

describe "Dashboard - getData()", ->
  beforeEach ->
    jasmine.Ajax.useMock()
    @dashboard = Dashboard

  describe "when the report is ready on the first iteration", ->
    it "should return the dashboard data", ->
      that = this

      @dashboard.getData 'lesson_leaders', {}, (data) ->
        that.data = data

      request = mostRecentAjaxRequest()
      expect(request.url).toBe('/dashboard/queries')
      expect(request.method).toBe('POST')
      request.response { status: 200, responseText: '{"id": "REPORT_ID" }' }

      waits(1000)

      runs ->
        request = mostRecentAjaxRequest()
        expect(request.url).toBe('/dashboard/queries/REPORT_ID/ready')
        expect(request.method).toBe('GET')
        request.response { status: 200, responseText: '{"is_ready": true, "data":"DATA" }' }

        expect(that.data).toEqual 'DATA'

#= require lib/dashboard_poller
#= require mock-ajax

describe "Dashboard - getData()", ->
  beforeEach ->
    jasmine.Ajax.useMock()
    @dashboard = ttm.lib.DashboardPoller.build()

  describe "when the report is ready on the first iteration", ->
    it "should return the dashboard data", ->
      that = this

      @dashboard.getData 'lesson_leaders', {}, (data) ->
        that.data = data

      request = mostRecentAjaxRequest()
      expect(request.url).toBe('/dashboard/queries')
      expect(request.method).toBe('POST')
      request.response { status: 200, responseText: '{"id": "REPORT_ID" }' }

      waits(1000)

      runs ->
        request = mostRecentAjaxRequest()
        expect(request.url).toBe('/dashboard/queries/REPORT_ID/ready')
        expect(request.method).toBe('GET')
        request.response { status: 200, responseText: '{"is_ready": true, "data":"DATA" }' }

        expect(that.data).toEqual 'DATA'

Move the poller into the lib and mix it with the other classmixer stuffs. Update the test.


class Enumeration
  #Registered enums
  @types:[]
  #Static function that creates an enum object value. Uniqueness guarantied by object reference.
  #This objects's unique own field is the Enumeration name. It's read only.
  #string value shall be uppercase
  @value:(value,enumName="Enumeration")->
    prototype= id: -> @[enumName]
    properties={}
    properties[enumName]=
      value:value
      enumerable:true
    Object.create prototype, properties

  constructor:(enumName,enumValues) ->
    #Check for uniqueness
    if enumName in Enumeration.types then throw "#{enumName} already exists!"
    else Enumeration.types.push enumName
    #Lambda to write enum values
    writeProperty = (property,key) => @[key or property]=Enumeration.value(property,enumName)
    if enumValues instanceof Array then writeProperty val for val in enumValues
    else writeProperty val,key for key,val of enumValues
    #Define non-enumerable property
    Object.defineProperty @, 'concise', {
      #Returns a concise string representing the enumeration
      value:-> "#{enumName}:[#{" "+val+" " for val in enumValues}]"
    }
    Object.defineProperty @, 'from', {
      #Returns the enum instance that matches value
      value: (lookupVal) -> (@[key] for key,val of enumValues when val is lookupVal)[0]
    }
    #Guaranties properties to be 'final', non writable
    Object.freeze(this)

#Registered enums
enumNames=[]
class Enumeration
  #Static function that creates an enum object value. Uniqueness guarantied by object reference.
  #This objects's unique own field is the Enumeration name. It's read only.
  #string value shall be uppercase
  @value:(value,enumName="Enumeration")->
    prototype= id: -> @[enumName]
    properties={}
    properties[enumName]=
      value:value
      enumerable:true
    Object.create prototype, properties

  constructor:(enumName,enumValues) ->
    #Check for uniqueness
    if enumName in enumNames then throw "#{enumName} already exists!"
    else enumNames.push enumName
    #Lambda to write enum values
    writeProperty = (property,key) => @[key or property]=Enumeration.value(property,enumName)
    if enumValues instanceof Array then writeProperty val for val in enumValues
    else writeProperty val,key for key,val of enumValues
    #Define non-enumerable property
    Object.defineProperty @, 'concise', {
      #Returns a concise string representing the enumeration
      value:-> "#{enumName}:[#{" "+val+" " for val in enumValues}]"
    }
    Object.defineProperty @, 'from', {
      #Returns the enum instance that matches value
      value: (lookupVal) -> (@[key] for key,val of enumValues when val is lookupVal)[0]
    }
    #Guaranties properties to be 'final', non writable
    Object.freeze(this)

#If you want to export the class, you'll need window.Enumeration=Enumeration or global.Enumeration=Enumeration

Move enumNames out of class

Move enumNames out of class


React = require 'react'

module.exports = React.createClass
  displayName: 'SubjectViewer'

  mediaSrcs: {}

  getInitialState: ->
    text: 'Loading'

  componentDidMount: ->
    @loadText @props.subject?.locations

  componentWillReceiveProps: (newProps) ->
    @loadText newProps.subject?.locations

  render: ->
    classList=["readymade-marking-surface-container"]
    classList.push "current" if @props.isCurrent
    image = @mediaSrcs['image/jpeg']

Page {@props.subject.metadata.page} {@props.subject.metadata.filename}

{@state.text}

Scanned page

        { if image}

  fetchOCR: (url) ->
    fetch url
    .then (response)-> return response.text()

  loadText: (locations) ->
    @mediaSrcs = {}
    locations?.map (location, i) =>
      @mediaSrcs["#{Object.keys(location)[0]}"] = location["#{Object.keys(location)[0]}"]
    if @mediaSrcs['text/plain']
      @fetchOCR @mediaSrcs['text/plain']
        .then @updateText
    else
      @updateText ''

  updateText: (text) ->
    @setState {text}

React = require 'react'

module.exports = React.createClass
  displayName: 'SubjectViewer'

  mediaSrcs: {}

  getInitialState: ->
    text: 'Loading'

  componentDidMount: ->
    @loadText @props.subject?.locations

  componentWillReceiveProps: (newProps) ->
    @loadText newProps.subject?.locations

  render: ->
    classList=["readymade-marking-surface-container"]
    classList.push "current" if @props.isCurrent
    image = @mediaSrcs['image/jpeg']

Page {@props.subject.metadata.page}

{@state.text}

Scanned page

        { if image}

  fetchOCR: (url) ->
    fetch url
    .then (response)-> return response.text()

  loadText: (locations) ->
    @mediaSrcs = {}
    locations?.map (location, i) =>
      @mediaSrcs["#{Object.keys(location)[0]}"] = location["#{Object.keys(location)[0]}"]
    if @mediaSrcs['text/plain']
      @fetchOCR @mediaSrcs['text/plain']
        .then @updateText
    else
      @updateText ''

  updateText: (text) ->
    @setState {text}

Remove filename debugging info from the subject viewer


".source.js":
  "Object.assign":
    prefix: "assign"
    body: "Object.assign(${1:dest}, ${2:source})"
  "Object.assign +":
    prefix: "Object.assign"
    body: "Object.assign(${1:dest}, ${2:source})"

  "Object.create":
    prefix: "create"
    body: "Object.create(${1:object})"
  "Object.create +":
    prefix: "Object.create"
    body: "Object.create(${1:object})"
  "Object.keys":
    prefix: "keys"
    body: "Object.keys(${1:object})"
  "Object.keys +":
    prefix: "Object.keys"
    body: "Object.keys(${1:object})"

  "Object method":
    prefix: "km"
    body: """${1:methodName}: function ${1:methodName}(${2}) {
      $0
    }${3:,}
    """
  "Object method - anonymous":
    prefix: "kf"
    body: """${1:methodName}: function(${2}) {
      $0
    }${3:,}
    """
  "Object arrow method":
    prefix: "karrow"
    body: """${1:methodName}: (${2}) => {
      $0
    }${3:,}
    """

".source.js":
  "Object.assign":
    prefix: "assign"
    body: "Object.assign(${1:dest}, ${2:source})"
  "Object.assign +":
    prefix: "Object.assign"
    body: "Object.assign(${1:dest}, ${2:source})"

  "Object.create":
    prefix: "create"
    body: "Object.create(${1:object})"
  "Object.create +":
    prefix: "Object.create"
    body: "Object.create(${1:object})"

  "Object.entries":
    prefix: "entries"
    body: "Object.entries(${1:object})"
  "Object.entries +":
    prefix: "Object.entries"
    body: "Object.keys(${1:object})"

  "Object.keys":
    prefix: "keys"
    body: "Object.keys(${1:object})"
  "Object.keys +":
    prefix: "Object.keys"
    body: "Object.keys(${1:object})"

  "Object.values":
    prefix: "values"
    body: "Object.values(${1:object})"
  "Object.values +":
    prefix: "Object.values"
    body: "Object.values(${1:object})"

  "Object method":
    prefix: "km"
    body: """${1:methodName}: function ${1:methodName}(${2}) {
      $0
    }${3:,}
    """
  "Object method - anonymous":
    prefix: "kf"
    body: """${1:methodName}: function(${2}) {
      $0
    }${3:,}
    """
  "Object arrow method":
    prefix: "ka"
    body: """${1:methodName}: (${2}) => {
      $0
    }${3:,}
    """

Add Object.values & Object.entries snippets


class FinderPane extends Pane

  constructor: (options = {}, data) ->

    super options, data

    @createFinderController()
    @bindListeners()

  createFinderController: ->
    finderApp         = new FinderController
    @finderController = finderApp.create()

    @addSubView @finderController.getView()
    @finderController.reset()

    # this is legacy, should be deleted when we open source koding finder
    @finderController.getView().subViews.first.destroy()

  bindListeners: ->
    appManager = KD.getSingleton 'appManager'

    @finderController.on 'FileNeedsToBeOpened', (file) =>
      file.fetchContents (err, contents) ->
        appManager.tell 'IDE', 'openFile', file, contents

    @finderController.treeController.on 'TerminalRequested', (vm) =>
      appManager.tell 'IDE', 'openVMTerminal', vm

    @on 'VMMountRequested', (vm) =>
      @finderController.mountVm vm

    @on 'VMUnmountRequested', (vm) =>
      @finderController.unmountVm vm.hostnameAlias

class FinderPane extends Pane

  constructor: (options = {}, data) ->

    super options, data

    vmController = KD.getSingleton 'vmController'
    vmController.fetchDefaultVmName (vmName) =>
     @finder = new NFinderController
       nodeIdPath       : 'path'
       nodeParentIdPath : 'parentPath'
       contextMenu      : yes
       useStorage       : no

     @addSubView @finder.getView()
     @finder.updateVMRoot vmName, "/home/#{KD.nick()}"

     @finder.on 'FileNeedsToBeOpened', (file) =>
       file.fetchContents (err, contents) ->
         appManager = KD.getSingleton 'appManager'
         appManager.tell 'IDE', 'openFile', file, contents

  bindListeners: ->
    appManager = KD.getSingleton 'appManager'

    @finderController.on 'FileNeedsToBeOpened', (file) =>
      file.fetchContents (err, contents) ->
        appManager.tell 'IDE', 'openFile', file, contents

    @finderController.treeController.on 'TerminalRequested', (vm) =>
      appManager.tell 'IDE', 'openVMTerminal', vm

    @on 'VMMountRequested', (vm) =>
      @finderController.mountVm vm

    @on 'VMUnmountRequested', (vm) =>
      @finderController.unmountVm vm.hostnameAlias

Revert custom finder related logic.

Revert custom finder related logic.


angular.module('loomioApp').factory 'TimeService', (AppConfig) ->
  new class TimeService

    displayDate: (m, zone) =>
      if moment._f == 'YYYY-MM-DD'
        m.format("D MMMM#{@sameYear(m)}")
      else
        @inTimeZone(m, zone).format("D MMMM#{@sameYear(m)} - h:mma")

    isoDate: (m, zone) =>
      @inTimeZone(m, zone).toISOString()

    hasTime: (m) ->
      m._f != 'YYYY-MM-DD'

    inTimeZone: (m, zone) =>
      m.tz(zone || AppConfig.timeZone)

    sameYear: (date) ->
      if date.year() == moment().year() then "" else " YYYY"

angular.module('loomioApp').factory 'TimeService', (AppConfig) ->
  new class TimeService

    displayDate: (m, zone) =>
      if m._f == 'YYYY-MM-DD'
        m.format("D MMMM#{@sameYear(m)}")
      else
        @inTimeZone(m, zone).format("D MMMM#{@sameYear(m)} - h:mma")

    isoDate: (m, zone) =>
      @inTimeZone(m, zone).toISOString()

    inTimeZone: (m, zone) =>
      m.tz(zone || AppConfig.timeZone)

    sameYear: (date) ->
      if date.year() == moment().year() then "" else " YYYY"

Fix in app date display for meeting tiems


EmailPasswordController = require './email-password-controller'
debug = require('debug')('meshblu-email-password-authenticator:sessions-controller')

class SessionController
  constructor: (uuid, meshblu) ->
    @emailPasswordController = new EmailPasswordController uuid, meshblu: meshblu

  create: (request, response) =>
    debug "Got request: #{JSON.stringify(request.body)}"
    {email,password}  = request.body

    @emailPasswordController.getToken email, password, (error, device) =>
      return response.status(401).send error.message if error?
      response.status(201).send token: device.token

module.exports = SessionController

EmailPasswordController = require './email-password-controller'
debug = require('debug')('meshblu-email-password-authenticator:sessions-controller')
url = require 'url'

class SessionController
  constructor: (uuid, meshblu) ->
    @emailPasswordController = new EmailPasswordController uuid, meshblu: meshblu

  create: (request, response) =>
    debug "Got request: #{JSON.stringify(request.body)}"
    {email,password,callbackUrl}  = request.body

    @emailPasswordController.getToken email, password, (error, device) =>
      return response.status(401).send error.message if error?

      uriParams = url.parse callbackUrl
      uriParams.query ?= {}
      uriParams.query.uuid = device.uuid
      uriParams.query.token = device.token

      response.redirect url.format uriParams

module.exports = SessionController

Use the callback url to redirect the user


angular.module("admin.products").controller "variantUnitsCtrl", ($scope, VariantUnitManager, $timeout, UnitPrices) ->

  $scope.unitName = (scale, type) ->
    VariantUnitManager.getUnitName(scale, type)

  $scope.$watchCollection "[unit_value_human, variant.price]", ->
    $scope.processUnitPrice()

  $scope.processUnitPrice = ->
    if ($scope.variant)
      price = $scope.variant.price
      scale = $scope.scale
      unit_type = angular.element("#product_variant_unit").val()
      if (unit_type != "items")
        $scope.updateValue()
        unit_value = $scope.unit_value
      else
        unit_value = 1
      variant_unit_name = angular.element("#product_variant_unit_name").val()
      $scope.unit_price = UnitPrices.displayableUnitPrice(price, scale, unit_type, unit_value, variant_unit_name)

  $scope.scale = angular.element('#product_variant_unit_scale').val()

  $scope.updateValue = ->
    unit_value_human = angular.element('#unit_value_human').val()
    $scope.unit_value = unit_value_human * $scope.scale

  variant_unit_value = angular.element('#variant_unit_value').val()
  $scope.unit_value_human = variant_unit_value / $scope.scale

  $timeout -> $scope.processUnitPrice()
  $timeout -> $scope.updateValue()

angular.module("admin.products").controller "variantUnitsCtrl", ($scope, VariantUnitManager, $timeout, UnitPrices, unlocalizeCurrencyFilter) ->

  $scope.unitName = (scale, type) ->
    VariantUnitManager.getUnitName(scale, type)

  $scope.$watchCollection "[unit_value_human, variant.price]", ->
    $scope.processUnitPrice()

  $scope.processUnitPrice = ->
    if ($scope.variant)
      price = $scope.variant.price
      scale = $scope.scale
      unit_type = angular.element("#product_variant_unit").val()
      if (unit_type != "items")
        $scope.updateValue()
        unit_value = $scope.unit_value
      else
        unit_value = 1
      variant_unit_name = angular.element("#product_variant_unit_name").val()
      $scope.unit_price = UnitPrices.displayableUnitPrice(price, scale, unit_type, unit_value, variant_unit_name)

  $scope.scale = angular.element('#product_variant_unit_scale').val()

  $scope.updateValue = ->
    unit_value_human = angular.element('#unit_value_human').val()
    $scope.unit_value = unlocalizeCurrencyFilter(unit_value_human) * $scope.scale

  variant_unit_value = angular.element('#variant_unit_value').val()
  $scope.unit_value_human = variant_unit_value / $scope.scale

  $timeout -> $scope.processUnitPrice()
  $timeout -> $scope.updateValue()

Use our unlocalizeCurrencyFilter to parse unit value field

- More tolerant (can handle `,` or `.` as decimal separator, remove thousands separator) to return a `number`


BodyParser = require '../lib/snippet-body-parser.coffee'

describe "Snippet Body Parser", ->
  it "breaks a snippet body into lines, with each line containing tab stops at the appropriate position", ->
    bodyTree = BodyParser.parse """
      the quick brown $1fox ${2:jumped ${3:over}
      }the ${4:lazy} dog
    """

    expect(bodyTree).toEqual [
      "the quick brown ",
      { index: 1, content: [] },
      "fox ",
      {
        index: 2,
        content: [
          "jumped ",
          { index: 3, content: ["over"]},
          "\n"
        ],
      }
      "the "
      { index: 4, content: ["lazy"] },
      " dog"
    ]

  it "removes interpolated variables in placeholder text (we don't currently support it)", ->
    bodyTree = BodyParser.parse """
      module ${1:ActiveRecord::${TM_FILENAME/(?:\\A|_)([A-Za-z0-9]+)(?:\\.rb)?/(?2::\\u$1)/g}}
    """

    expect(bodyTree).toEqual [
      "module ",
      {
        "index": 1,
        "content": ["ActiveRecord::", ""]
      }
    ]

BodyParser = require '../lib/snippet-body-parser'

describe "Snippet Body Parser", ->
  it "breaks a snippet body into lines, with each line containing tab stops at the appropriate position", ->
    bodyTree = BodyParser.parse """
      the quick brown $1fox ${2:jumped ${3:over}
      }the ${4:lazy} dog
    """

    expect(bodyTree).toEqual [
      "the quick brown ",
      { index: 1, content: [] },
      "fox ",
      {
        index: 2,
        content: [
          "jumped ",
          { index: 3, content: ["over"]},
          "\n"
        ],
      }
      "the "
      { index: 4, content: ["lazy"] },
      " dog"
    ]

  it "removes interpolated variables in placeholder text (we don't currently support it)", ->
    bodyTree = BodyParser.parse """
      module ${1:ActiveRecord::${TM_FILENAME/(?:\\A|_)([A-Za-z0-9]+)(?:\\.rb)?/(?2::\\u$1)/g}}
    """

    expect(bodyTree).toEqual [
      "module ",
      {
        "index": 1,
        "content": ["ActiveRecord::", ""]
      }
    ]

Remove .coffee extension from require path

Refs atom/atom#4884


fs      = require 'fs'
gulp    = require 'gulp'
shell   = require 'gulp-shell'

module.exports = (version) ->

  folders  = (folder for folder in fs.readdirSync('./') when fs.statSync(folder).isDirectory())
  sites    = folders.filter (folder) -> folder.search(/^site\./) is 0 and folder isnt 'site.boilerplate'
  commands = ("gulp --gulpfile ./#{siteDir}/gulpfile.coffee build --uglify" for siteDir in sites)

  gulp.src ''
    .pipe shell commands

fs      = require 'fs'
gulp    = require 'gulp'
shell   = require 'gulp-shell'

module.exports = (version) ->

  folders  = (folder for folder in fs.readdirSync('./') when fs.statSync(folder).isDirectory())
  sites    = folders.filter (folder) ->
    siteDir = folder.search(/^site\./) is 0 and folder isnt 'site.boilerplate'
    return no  unless siteDir
    try
      fs.statSync "#{folder}/gulpfile.coffee"
      return yes
    return no
  commands = ("gulp --gulpfile ./#{siteDir}/gulpfile.coffee build --uglify" for siteDir in sites)

  gulp.src ''
    .pipe shell commands

Check existence of gulpfile in landing site directory


# Your init script
#
# Atom will evaluate this file each time a new window is opened. It is run
# after packages are loaded/activated and after the previous editor state
# has been restored.
#

path = require 'path'

oldWindowDimensions = {}
oldThemes = []

atom.commands.add 'atom-workspace',
  'custom:open-todo-list': ->
    todoList = path.join(process.env.HOME, 'Dropbox', 'todo', 'todo.txt')
    atom.workspace.open(todoList)

  'custom:screenshot-prep': ->
    oldWindowDimensions = atom.getWindowDimensions()
    oldThemes = atom.config.get('core.themes')

    atom.setWindowDimensions('width': 1024, 'height': 768)
    atom.config.restoreDefault('core.themes')

  'custom:screenshot-restore': ->
    atom.config.set('core.themes', oldThemes)
    atom.setWindowDimensions(oldWindowDimensions)

# Your init script
#
# Atom will evaluate this file each time a new window is opened. It is run
# after packages are loaded/activated and after the previous editor state
# has been restored.
#

path = require 'path'

oldWindowDimensions = {}

atom.commands.add 'atom-workspace',
  'custom:open-todo-list': ->
    todoList = path.join(process.env.HOME, 'Dropbox', 'todo', 'todo.txt')
    atom.workspace.open(todoList)

  'custom:screenshot-prep': ->
    oldWindowDimensions = atom.getWindowDimensions()
    atom.setWindowDimensions('width': 1366, 'height': 768)

  'custom:screenshot-restore': ->
    atom.setWindowDimensions(oldWindowDimensions)

Add command for opening todo list

Add command for opening todo list


app = require('../app')
test_server = null
url = require('url')

before( (done) ->
  app.start 3001, (err, server) ->
    test_server = server
    done()
)

after( (done) ->
  test_server.close () -> done()
)

beforeEach( (done) ->
  global.sequelize.sync({force: true}).success(() -> done())
)

exports.appurl = (path) ->
  url.resolve('http://localhost:3001', path)

app = require('../app')
test_server = null
url = require('url')

before( (done) ->
  app.start 3001, (err, server) ->
    test_server = server
    done()
)

after( (done) ->
  test_server.close () -> done()
)

dropDatabase = (connection, done) ->
  connection.db.dropDatabase (err) ->
    if err?
      console.log 'ERROR'
      console.log err
    else
      done()

beforeEach( (done) ->
  connection = mongoose.connection
  state = connection.readyState

  if state == 2
    connection.on 'open', -> dropDatabase(connection, done)
  else if state == 1
    dropDatabase(connection, done)
)

exports.appurl = (path) ->
  url.resolve('http://localhost:3001', path)

Drop mongodb database between tests

Drop mongodb database between tests


checkOuterPages = (url) =>
  outerPages = ["docs", "about", "privacy", "pricing"]
  for page in outerPages
    if (url.match "^/#{page}.*")
      return "/"
  return url

CI.github =
  # we encore each parammeter separately (one of them twice!) to get the right format
  authUrl: (scope=["user", "repo"]) =>
    destination = window.location.pathname
    destination = checkOuterPages(destination)
    destination = encodeURIComponent(destination)

    path = "https://github.com/login/oauth/authorize"
    client_id = window.renderContext.githubClientId
    scope = scope.join ","
    scope = encodeURIComponent(scope)

    redirect = "#{window.location.origin}/auth/github?return-to=#{destination}"
    redirect = encodeURIComponent(redirect)
    "#{path}?client_id=#{client_id}&redirect_uri=#{redirect}&scope=#{scope}"

checkOuterPages = (url) =>
  outerPages = ["docs", "about", "privacy", "pricing"]
  for page in outerPages
    if (url.match "^/#{page}.*")
      return "/"
  return url

CI.github =
  # we encore each parammeter separately (one of them twice!) to get the right format
  authUrl: (scope=["user", "repo"]) =>
    destination = window.location.pathname
    destination = checkOuterPages(destination)
    destination = encodeURIComponent(destination)

    path = "https://github.com/login/oauth/authorize"
    client_id = window.renderContext.githubClientId
    scope = scope.join ","
    scope = encodeURIComponent(scope)

    redirect = "#{window.location.href}/auth/github?return-to=#{destination}"
    redirect = encodeURIComponent(redirect)
    "#{path}?client_id=#{client_id}&redirect_uri=#{redirect}&scope=#{scope}"

Fix login problems on firefox

Fix login problems on firefox


LocalBranch = require './local-branch'

{git} = require '../../git'

module.exports =
class CurrentBranch extends LocalBranch
  initialize: ->
    @reload()

  reload: ->
    git.branch (head) =>
      @set head

    git.gitNoChange "log @{u}..", (output) =>
      @set unpushed: (output != "")

  head: ->
    "HEAD"

  delete: -> null

  checkout: -> null

LocalBranch = require './local-branch'

{git} = require '../../git'

module.exports =
class CurrentBranch extends LocalBranch
  initialize: ->
    @reload()

  reload: ->
    git.branch (head) =>
      @set head

    # git.gitNoChange "log @{u}..", (output) =>
    #   @set unpushed: (output != "")

  head: ->
    "HEAD"

  delete: -> null

  checkout: -> null

Remove pushed/unpushed status for now.

Remove pushed/unpushed status for now.

# Compose your commit message. Press `cmd-alt-c` to commit. Close to cancel.


express = require 'express'
passport = require 'passport'

router = express.Router()

router.post '/login', passport.authenticate 'local',
  successRedirect: '/app'
  failureRedirect: '/'
  failureFlash: 'Invalid username or password!'

module.exports = router

express = require 'express'
passport = require 'passport'

router = express.Router()

router.post '/login', passport.authenticate 'local',
  successRedirect: '/admin'
  failureRedirect: '/'
  failureFlash: 'Invalid username or password!'

module.exports = router

Fix wrong redirect after logging in

Fix wrong redirect after logging in


React = require 'react'
Nav = React.createFactory require 'antwar-default-theme/Nav'
Paths = require('antwar-core/PathsMixin')
require 'antwar-default-theme/scss/main.scss'

require 'react-ghfork/gh-fork-ribbon.ie.css' # ie support
require 'react-ghfork/gh-fork-ribbon.css'
Fork = React.createFactory(require 'react-ghfork')

{ div, main, script, link } = require 'react-coffee-elements'

config = require 'config'
if config.theme.customStyles?
  require 'customStyles/' + config.theme.customStyles

module.exports = React.createClass

    displayName: 'Body'

    mixins: [
        Paths
    ]

    render: ->
        sectionName = @getSectionName()

        itemTitle = @getItem().title;

        div { },
            if sectionName and sectionName != '/'
                Nav()
                Fork { className: 'right ribbon', project: "survivejs/webpack_react/issues/new?title=#{itemTitle} - ", text: 'Submit feedback', style: {backgroundColor: 'black'}}
            main { role: 'main' }, @props.children

React = require 'react'
Nav = React.createFactory require 'antwar-default-theme/Nav'
Paths = require('antwar-core/PathsMixin')
require 'antwar-default-theme/scss/main.scss'

require 'react-ghfork/gh-fork-ribbon.ie.css' # ie support
require 'react-ghfork/gh-fork-ribbon.css'
Fork = React.createFactory(require 'react-ghfork')

{ div, main, script, link } = require 'react-coffee-elements'

config = require 'config'
if config.theme.customStyles?
  require 'customStyles/' + config.theme.customStyles

module.exports = React.createClass

    displayName: 'Body'

    mixins: [
        Paths
    ]

    render: ->
        sectionName = @getSectionName()

        itemTitle = @getItem().title;

        div { },
            if sectionName and sectionName != '/'
                Nav()
                Fork { className: 'right ribbon', project: "survivejs/webpack_react/issues/new?title=#{itemTitle} - ", text: 'Submit feedback', style: {backgroundColor: 'black'}, target: '_blank'}
            main { role: 'main' }, @props.children

Set `target: _blank` on submit feedback

Set `target: _blank` on submit feedback

Better ux.


Template.loginLayout.rendered = ->
	$('html').addClass("scroll").removeClass "noscroll"
	window.pJSDom = []
	particlesJS.load 'particles-js', '/scripts/particles.json', ->

Template.loginLayout.rendered = ->
	$('html').addClass("scroll").removeClass "noscroll"
	if not Meteor.isCordova
		window.pJSDom = []
		particlesJS.load 'particles-js', '/scripts/particles.json', ->

Disable particles in mobile login

Disable particles in mobile login


#= require cmsimple/panels/images/panel
class CMSimple.Panels.ImageLibrary.List extends Spine.Controller
  events:
    'click .media-actions > .info' : 'toggleInfo'
    'click .media-info > .close' : 'toggleInfo'
    'click [data-full-url]' : 'triggerImage'
    'click .delete' : 'deleteImage'

  constructor: (el)->
    super el: $(el)

    CMSimple.Image.bind 'refresh change', => @render()
    CMSimple.Image.fetch()

  render: ->
    @html('')
    @addImage image for image in CMSimple.Image.all()

  addImage: (image)->
    @append JST['cmsimple/views/image_library_item'](image)

  toggleInfo: (e) ->
    e.preventDefault()
    info = $(e.target).parents('li').first().find('.media-info')[0]
    $(info).toggleClass('active')

  triggerImage: (e)->
    img = $(e.target)
    @trigger 'image:selected', src: img.data('full-url'), 'image-id': img.data('id')

  deleteImage: (e)->
    e.preventDefault()
    link = $(e.target)
    if confirm 'Are you sure you would like to delete this image?'
      id = link.parents('[data-id]').data('id')
      image = CMSimple.Image.find(id)
      image.destroy()

#= require cmsimple/panels/images/panel
class CMSimple.Panels.ImageLibrary.List extends Spine.Controller
  events:
    'click .media-actions > .info' : 'toggleInfo'
    'click .media-info > .close' : 'toggleInfo'
    'click [data-full-url]' : 'triggerImage'
    'click .delete' : 'deleteImage'

  constructor: (el)->
    super el: $(el)

    CMSimple.Image.bind 'refresh change', => @render()
    CMSimple.Image.fetch()

  render: ->
    @html('')
    @addImage image for image in CMSimple.Image.all()

  addImage: (image)->
    @append JST['cmsimple/views/image_library_item'](image)

  toggleInfo: (e) ->
    e.preventDefault()
    info = $(e.target).parents('li').first().find('.media-info')[0]
    $(info).toggleClass('active')

  triggerImage: (e)->
    img = $(e.target)
    image = CMSimple.Image.find(img.data('id'))
    @trigger 'image:selected',
        src: img.data('full-url'),
        alt: image.title,
        width: image.width,
        height: image.height,
        'image-id': image.id

  deleteImage: (e)->
    e.preventDefault()
    link = $(e.target)
    if confirm 'Are you sure you would like to delete this image?'
      id = link.parents('[data-id]').data('id')
      image = CMSimple.Image.find(id)
      image.destroy()

Set image properties when inserting an image.


# Import common modules.
module.exports = require '../../../../common/api/lib/exports/electron'

v8Util = process.atomBinding 'v8_util'
v8Util.setHiddenValue module.exports, 'electronModule', true

Object.defineProperties module.exports,
  # Browser side modules, please sort with alphabet order.
  app:
    enumerable: true
    get: -> require '../app'
  autoUpdater:
    enumerable: true
    get: -> require '../auto-updater'
  BrowserWindow:
    enumerable: true
    get: -> require '../browser-window'
  contentTracing:
    enumerable: true
    get: -> require '../content-tracing'
  dialog:
    enumerable: true
    get: -> require '../dialog'
  ipcMain:
    enumerable: true
    get: -> require '../ipc-main'
  globalShortcut:
    enumerable: true
    get: -> require '../global-shortcut'
  Menu:
    enumerable: true
    get: -> require '../menu'
  MenuItem:
    enumerable: true
    get: -> require '../menu-item'
  powerMonitor:
    enumerable: true
    get: -> require '../power-monitor'
  powerSaveBlocker:
    enumerable: true
    get: -> require '../power-save-blocker'
  protocol:
    enumerable: true
    get: -> require '../protocol'
  screen:
    enumerable: true
    get: -> require '../screen'
  tray:
    enumerable: true
    get: -> require '../tray'
  # The internal modules, invisible unless you know their names.
  NavigationController:
    get: -> require '../navigation-controller'
  webContents:
    get: -> require '../web-contents'

# Import common modules.
module.exports = require '../../../../common/api/lib/exports/electron'

v8Util = process.atomBinding 'v8_util'
v8Util.setHiddenValue module.exports, 'electronModule', true

Object.defineProperties module.exports,
  # Browser side modules, please sort with alphabet order.
  app:
    enumerable: true
    get: -> require '../app'
  autoUpdater:
    enumerable: true
    get: -> require '../auto-updater'
  BrowserWindow:
    enumerable: true
    get: -> require '../browser-window'
  contentTracing:
    enumerable: true
    get: -> require '../content-tracing'
  dialog:
    enumerable: true
    get: -> require '../dialog'
  ipcMain:
    enumerable: true
    get: -> require '../ipc-main'
  globalShortcut:
    enumerable: true
    get: -> require '../global-shortcut'
  Menu:
    enumerable: true
    get: -> require '../menu'
  MenuItem:
    enumerable: true
    get: -> require '../menu-item'
  powerMonitor:
    enumerable: true
    get: -> require '../power-monitor'
  powerSaveBlocker:
    enumerable: true
    get: -> require '../power-save-blocker'
  protocol:
    enumerable: true
    get: -> require '../protocol'
  screen:
    enumerable: true
    get: -> require '../screen'
  Tray:
    enumerable: true
    get: -> require '../tray'
  # The internal modules, invisible unless you know their names.
  NavigationController:
    get: -> require '../navigation-controller'
  webContents:
    get: -> require '../web-contents'

Fix typo, tray => Tray

Fix typo, tray => Tray


React = require 'react'

module.exports = React.createClass
  displayName: 'ChooseSubjectSet'

  getInitialState: ->
    subject_sets: []

  componentWillMount: ->
    @props.workflow?.get 'subject_sets', page_size: 40
      .then (subject_sets) =>
        @setState {subject_sets}

  render: ->

Choose a report to work on

        {
{subject_set.display_name}
{subject_set.metadata.BOROUGH}
{subject_set.metadata.Date}
 for subject_set in @state.subject_sets}

  update: (e) ->
    subject_set_id = e.currentTarget.href.split('/').pop()
    @props.onChange subject_set_id

React = require 'react'

module.exports = React.createClass
  displayName: 'ChooseSubjectSet'

  getInitialState: ->
    subject_sets: []

  componentWillMount: ->
    @props.workflow?.get 'subject_sets', page_size: 40
      .then (subject_sets) =>
        subject_sets.sort (a, b) ->
          return 1 if a.metadata.BOROUGH > b.metadata.BOROUGH
          return -1 if a.metadata.BOROUGH  b.metadata['File prefix']
          return -1 if a.metadata['File prefix']

Choose a report to work on

        {
{subject_set.display_name}
{subject_set.metadata.BOROUGH}
{subject_set.metadata.Date}
 for subject_set in @state.subject_sets}

  update: (e) ->
    subject_set_id = e.currentTarget.href.split('/').pop()
    @props.onChange subject_set_id

Sort subject sets by borough and file id


describe 'PodsList', ->
  subject = null
  beforeEach (done) ->
    subject = new SeedsStore('test')
    expect(subject.clear()).eventually.notify(done)
  it 'counts 0', (done) ->
    expect(subject.countForAll()).eventually.equal(0).notify(done)
  it 'counts n', (done) ->
    subject.update([{name: 1},{name: 2},{name: 3}])
    expect(subject.countForAll()).eventually.equal(3).notify(done)
  it 'readPod', (done) ->
    subject.update([{name: 1}, {name: 2}])
    expect(subject.readPod(1)).eventually.eql([{name: 1}]).notify(done)
  describe 'readsFromAll', ->
    beforeEach (done) ->
      list = [{name: 1}, {name: 2}, {name: 3}, {name: 4}]
      expect(subject.update(list))
        .eventually.notify(done)
    it 'readsFromAll asc', (done) ->
      expect(subject.readFromAll('name', true, 1, 2)).eventually
        .eql([{name: 2}, {name: 3}]).notify(done)
    it 'readsFromAll desc', (done) ->
      expect(subject.readFromAll('name', false, 1, 2)).eventually
        .eql([{name: 3}, {name: 2}]).notify(done)

describe 'PodsList', ->
  subject = null
  beforeEach (done) ->
    subject = new SeedsStore('test')
    expect(subject.clear()).eventually.notify(done)
  it 'counts 0', (done) ->
    expect(subject.countForAll()).eventually.equal(0).notify(done)
  it 'counts n', (done) ->
    subject.update([{name: 1},{name: 2},{name: 3}])
    expect(subject.countForAll()).eventually.equal(3).notify(done)
  it 'readPod', (done) ->
    subject.update([{name: 1}, {name: 2}])
    expect(subject.readPod(1)).eventually.eql([{name: 1}]).notify(done)
  describe 'readsFromAll', ->
    beforeEach (done) ->
      list = [{name: 1}, {name: 2}, {name: 3}, {name: 4}]
      expect(subject.update(list))
        .eventually.notify(done)
    it 'readsFromAll name,asc from the beginning', (done) ->
      expect(subject.readFromAll('name', true, 0, 1)).eventually
        .eql([{name: 1}]).notify(done)
    it 'readsFromAll name,asc in the middle', (done) ->
      expect(subject.readFromAll('name', true, 1, 2)).eventually
        .eql([{name: 2}, {name: 3}]).notify(done)
    it 'readsFromAll name,asc out of scope', (done) ->
      expect(subject.readFromAll('name', true, 3, 2)).eventually
        .eql([{name: 4}]).notify(done)

Add specs for normal scope.

Add specs for normal scope.


#
Tether = require 'tether/tether'
assign = require 'object-assign'
React = require 'react'
$ = React.createElement

class Attachment extends React.Component
  componentDidMount: =>
    @root = document.createElement 'DIV'
    document.body.appendChild @root

    document.addEventListener 'mousedown', @handleEvent
    document.addEventListener 'focus', @handleEvent, true

    @tether = new Tether
      element: @root
      target: @props.target
      attachment: @props.attachment || 'top left'
      constraints: @props.constraints
      targetAttachment: @props.targetAttachment || 'bottom left'

    @componentDidUpdate()

  componentDidUpdate: =>
    React.render @renderAttachment(), @root, => @tether?.position()

  componentWillUnmount: =>
    React.unmountComponentAtNode @root

    @tether.destroy()
    document.body.removeChild @root
    document.removeEventListener 'mousedown', @handleEvent
    document.removeEventListener 'focus', @handleEvent

  handleEvent: (e) =>
    node = e.target

    while node != null
      return true if node == @root || node == @props.target
      node = node.parentNode

    @props.onCloseRequest?()
    true

  render: =>
    null

  renderAttachment: =>
    props = assign {}, @props

    delete props.target
    delete props.attachment
    delete props.constraints
    delete props.onCloseRequest
    delete props.targetAttachment

    $ 'div', props

module.exports = Attachment

#
Tether = require 'tether/tether'
assign = require 'object-assign'
React = require 'react'
$ = React.createElement

class Attachment extends React.Component
  componentDidMount: =>
    @root = document.createElement 'DIV'
    document.body.appendChild @root

    document.addEventListener 'mousedown', @handleEvent
    document.addEventListener 'focus', @handleEvent, true

    @tether = new Tether
      element: @root
      target: @props.target
      attachment: @props.attachment || 'top left'
      constraints: @props.constraints
      targetAttachment: @props.targetAttachment || 'bottom left'

    @componentDidUpdate()

  componentDidUpdate: =>
    React.render @renderAttachment(), @root, => @tether?.position()

  componentWillUnmount: =>
    React.unmountComponentAtNode @root

    @tether.destroy()
    document.body.removeChild @root
    document.removeEventListener 'mousedown', @handleEvent
    document.removeEventListener 'focus', @handleEvent, true

  handleEvent: (e) =>
    node = e.target

    while node != null
      return true if node == @root || node == @props.target
      node = node.parentNode

    @props.onCloseRequest?()
    true

  render: =>
    null

  renderAttachment: =>
    props = assign {}, @props

    delete props.target
    delete props.attachment
    delete props.constraints
    delete props.onCloseRequest
    delete props.targetAttachment

    $ 'div', props

module.exports = Attachment

Fix Attachment not correctly cleaning up listener


StatusBarView = require './status-bar-view'
FileInfoView = require './file-info-view'
CursorPositionView = require './cursor-position-view'
GrammarView = require './grammar-view'
GitView = require './git-view'

module.exports =
  activate: ->
    @statusBar = new StatusBarView()
    @statusBar.attach()

    @fileInfo = new FileInfoView(@statusBar)
    @statusBar.appendLeft(@fileInfo)

    @cursorPosition = new CursorPositionView(@statusBar)
    @statusBar.appendLeft(@cursorPosition)

    @git = new GitView(@statusBar)
    @statusBar.appendRight(@git)

StatusBarView = require './status-bar-view'
FileInfoView = require './file-info-view'
CursorPositionView = require './cursor-position-view'
GitView = require './git-view'

module.exports =
  activate: ->
    @statusBar = new StatusBarView()
    @statusBar.attach()

    @fileInfo = new FileInfoView(@statusBar)
    @statusBar.appendLeft(@fileInfo)

    @cursorPosition = new CursorPositionView(@statusBar)
    @statusBar.appendLeft(@cursorPosition)

    @git = new GitView(@statusBar)
    @statusBar.appendRight(@git)

Remove ref to status bar

Remove ref to status bar


class Backbone.PushableCollection extends Backbone.Collection
  initialize: () ->
    window.FayeClient.subscribe "/sync/#{@channel()}", _.bind(@receive, @)

  receive: (message) ->
    @[message.event] message.object

  create: (attributes) ->
    model = new @model attributes
    model.fetch()
    @add model

  update: (attributes) ->
    model = @get attributes.id
    model.set attributes

  destroy: (attributes) ->
    @remove @get(attributes.id)

class Backbone.PushableCollection extends Backbone.Collection
  initialize: () ->
    window.FayeClient.subscribe "/sync/#{@channel()}", _.bind(@receive, @)

  receive: (message) ->
    @[message.event] message.object

  create: (attributes) ->
    model = new @model attributes
    @add model

  update: (attributes) ->
    model = @get attributes.id
    model.set attributes

  destroy: (attributes) ->
    @remove @get(attributes.id)

Remove Fetch from PushableCollection Create Event


###*
# @overview Registers the custom button tag.
#
# @module stout-ui/button
###
defaults   = require 'lodash/defaults'
Button     = require './Button'
ButtonView = require './ButtonView'
parser     = require 'stout-client/parser'

# Read the button custom HTML tag.
TAG_NAME = vars.readPrefixed 'button/button-tag'

# Register the button tag.
parser.register TAG_NAME, ButtonView, Button, {contentsMember: 'label'}

module.exports = (init) ->
  defaults init, {context: new Button}
  (new ButtonView init).context

###*
# @overview Registers the custom button tag.
#
# @module stout-ui/button
###
defaults   = require 'lodash/defaults'
Button     = require './Button'
ButtonView = require './ButtonView'
parser     = require 'stout-client/parser'

# Read the button custom HTML tag.
TAG_NAME = vars.readPrefixed 'button/button-tag'

# Register the button tag.
parser.register TAG_NAME, ButtonView, Button, {contentsMember: 'label'}

module.exports = (init) ->
  defaults init, {context: new Button}

  view = new ButtonView init

  # Configure event proxying.
  init.context.proxyEvents view, 'blur focus active hover click leave'

  view.context

Add button interactive event proxying.

Add button interactive event proxying.


module.exports =
  treeView: null

  activate: (@state={}) ->
    @createView() if @state.attached
    rootView.command 'tree-view:toggle', => @createView().toggle()
    rootView.command 'tree-view:reveal-active-file', => @createView().revealActiveFile()

  deactivate: ->
    @treeView?.deactivate()
    @treeView = null

  serialize: ->
    if @treeView?
      @treeView.serialize()
    else
      @state

  createView: ->
    unless @treeView?
      TreeView = require 'tree-view/lib/tree-view'
      @treeView = new TreeView(@state)
    @treeView

module.exports =
  treeView: null

  activate: (@state) ->
    @createView() if @state.attached
    rootView.command 'tree-view:toggle', => @createView().toggle()
    rootView.command 'tree-view:reveal-active-file', => @createView().revealActiveFile()

  deactivate: ->
    @treeView?.deactivate()
    @treeView = null

  serialize: ->
    if @treeView?
      @treeView.serialize()
    else
      @state

  createView: ->
    unless @treeView?
      TreeView = require 'tree-view/lib/tree-view'
      @treeView = new TreeView(@state)
    @treeView

Remove unneeded param defaults from activate methods


#     NoFlo - Flow-Based Programming for JavaScript
#     (c) 2014-2015 TheGrid (Rituwall Inc.)
#     NoFlo may be freely distributed under the MIT license
#
# Platform detection method
exports.isBrowser = ->
  if typeof process isnt 'undefined' and process.execPath and process.execPath.match /node|iojs/
    return false
  true

exports.warnDeprecated = (message) ->
  if exports.isBrowser()
    throw new Error message if window.NOFLO_FATAL_DEPRECATED
    console.warn message
    return
  if process.env.NOFLO_FATAL_DEPRECATED
    throw new Error message
  console.warn message

Add method for optionally-fatal deprecation warnings


define [
    'jquery'
    'underscore'
    'backbone'
    'marionette'
    '../base'
    '../charts'
    '../charts/utils'
    'tpl!templates/field/stats.html'
], ($, _, Backbone, Marionette, base, charts, utils, templates...) ->

    templates = _.object ['layout'], templates

    class FieldStatValue extends Marionette.ItemView
        tagName: 'li'

        template: (data) ->
            "#{ data.label }#{ data.value }"

    class FieldStatsValues extends Marionette.CollectionView
        tagName: 'ul'

        itemView: FieldStatValue

    class FieldStatsChart extends charts.FieldChart
        className: 'sparkline'

        chartOptions: Backbone.Sparkline::chartOptions

        getChartOptions: (resp) ->
            options =
                series: [utils.getSeries(resp.data)]

            $.extend true, options, @chartOptions
            options.chart.renderTo = @ui.chart[0]
            return options

    class FieldStats extends Marionette.Layout
        className: 'field-stats'

        template: templates.layout

        regions:
            values: '.stats-values'
            chart: '.stats-chart'

        onRender: ->
            if @model.stats?
                @values.show new FieldStatsValues
                    collection: @model.stats
                if not @model.stats.length
                    @model.stats.fetch(reset: true)

    { FieldStats }

define [
    'jquery'
    'underscore'
    'backbone'
    'marionette'
    '../base'
    '../charts'
    '../charts/utils'
    'tpl!templates/field/stats.html'
], ($, _, Backbone, Marionette, base, charts, utils, templates...) ->

    templates = _.object ['layout'], templates

    class FieldStatValue extends Marionette.ItemView
        tagName: 'li'

        # This is a map of data labels to display labels. For example, when
        # displaying data with a label of 'Distinct count', it will be
        # rendered as 'Unique values' when this field stat value is displayed
        # in the page. If a data label is not in this map, then the data
        # label itself will be used.
        labelMap:
            'Distinct count': 'Unique values'

        template: (data) =>
            "#{ @labelMap[data.label] or data.label }#{ data.value }"

    class FieldStatsValues extends Marionette.CollectionView
        tagName: 'ul'

        itemView: FieldStatValue

    class FieldStatsChart extends charts.FieldChart
        className: 'sparkline'

        chartOptions: Backbone.Sparkline::chartOptions

        getChartOptions: (resp) ->
            options =
                series: [utils.getSeries(resp.data)]

            $.extend true, options, @chartOptions
            options.chart.renderTo = @ui.chart[0]
            return options

    class FieldStats extends Marionette.Layout
        className: 'field-stats'

        template: templates.layout

        regions:
            values: '.stats-values'
            chart: '.stats-chart'

        onRender: ->
            if @model.stats?
                @values.show new FieldStatsValues
                    collection: @model.stats
                if not @model.stats.length
                    @model.stats.fetch(reset: true)

    { FieldStats }

Add map of labels for statistical values

Currently, the only mapping is "Distinct count" --> "Unique values"


#= require jquery/dist/jquery
#= require jquery-deparam/jquery-deparam
#= require jquery.transit/jquery.transit
#= require slow-ajax
#= require bootstrap/dist/js/bootstrap
#= require highstock-release/highstock
#= require highstock-release/modules/exporting
#= require leaflet/dist/leaflet
#= require leaflet-override
#= require json2/json2
#= require underscore/underscore
#= require backbone/backbone
#= require geocens-js-api/geocens
#= require geocens-js-api/geocens-chart
#
#= require workbench

$(document).on "click", "a:not([data-bypass])", (evt) ->
  href = { prop: $(this).prop("href"), attr: $(this).attr("href") }
  root = location.protocol + "//" + location.host + Backbone.history.options.root

  if (href.prop && href.prop.slice(0, root.length) is root)
    route = href.prop.slice(root.length, href.prop.length).split("?")[0]
    evt.preventDefault()
    appRouter.navigate(route, { trigger: true })

#= require jquery/dist/jquery
#= require jquery-deparam/jquery-deparam
#= require jquery.transit/jquery.transit
#= require slow-ajax
#= require bootstrap/dist/js/bootstrap
#= require highstock-release/highstock
#= require highstock-release/modules/exporting
#= require leaflet/dist/leaflet
#= require ./leaflet-override
#= require json2/json2
#= require underscore/underscore
#= require backbone/backbone
#= require geocens-js-api/geocens
#= require geocens-js-api/geocens-chart
#
#= require workbench

$(document).on "click", "a:not([data-bypass])", (evt) ->
  href = { prop: $(this).prop("href"), attr: $(this).attr("href") }
  root = location.protocol + "//" + location.host + Backbone.history.options.root

  if (href.prop && href.prop.slice(0, root.length) is root)
    route = href.prop.slice(root.length, href.prop.length).split("?")[0]
    evt.preventDefault()
    appRouter.navigate(route, { trigger: true })

Use relative path for leaflet-override

Use relative path for leaflet-override


_ = require 'underscore'
Q = require 'q'
Backbone = require 'backbone'
{ API_URL } = require('sharify').data
Relations = require './mixins/relations/collector_profile.coffee'

module.exports = class CollectorProfile extends Backbone.Model
  _.extend @prototype, Relations

  url: "#{API_URL}/api/v1/me/collector_profile"

  validHashFields: [
    'owner'
    'institutional_affiliations'
    'confirmed_buyer_at'
    'collector_level'
  ]

  findOrCreate: (options = {}) ->
    { success, error } = options

    options = _.omit options, 'success', 'error'

    Q.promise (resolve, reject) =>
      @fetch _.extend {}, options,
        success: ->
          resolve arguments...
          success? arguments...
        error: =>
          @save {},
            success: ->
              resolve arguments...
              success? arguments...
            error: ->
              reject arguments...
              error? arguments...

_ = require 'underscore'
Q = require 'q'
Backbone = require 'backbone'
{ API_URL } = require('sharify').data
Relations = require './mixins/relations/collector_profile.coffee'

module.exports = class CollectorProfile extends Backbone.Model
  _.extend @prototype, Relations

  url: "#{API_URL}/api/v1/me/collector_profile"

  # Temporary hack around API bug surrounding valid hash fields...
  validHashFields: [
    'institutional_affiliations'
    'confirmed_buyer_at'
    'collector_level'
  ]

  # Ibid.
  setWithValidAttributes: (attributes = {}) ->
    existing = _.extend id: @id, _.pick(@attributes, @validHashFields)
    @clear()
    @set _.extend existing, _.pick(attributes, @validHashFields)

  findOrCreate: (options = {}) ->
    { success, error } = options

    options = _.omit options, 'success', 'error'

    Q.promise (resolve, reject) =>
      @fetch _.extend {}, options,
        success: ->
          resolve arguments...
          success? arguments...
        error: =>
          @save {},
            success: ->
              resolve arguments...
              success? arguments...
            error: ->
              reject arguments...
              error? arguments...

Expand on hack for valid hash fields

Expand on hack for valid hash fields


_ = require 'underscore'
{ Cities, FeaturedCities } = require 'places'
PartnerShows = require '../../../../collections/partner_shows.coffee'
RelatedShowsView = require './view.coffee'

module.exports = (type, show) ->

  city = _.findWhere(Cities, name: show.formatCity())

  el = $('.js-related-shows')

  criteria =
    sort: 'end_at'
    size: 4
    displayable: true

  relatedShows = new PartnerShows

  switch type
    when 'fair'
      data =  _.extend criteria, fair_id: show.related().fair.get('_id')
      title = "More Booths from #{show.related().fair.get('name')}"
    when 'gallery'
      data = _.extend criteria, sort: '-end_at', size: '8'
      relatedShows.url = "#{show.related().partner.url()}/shows"
      title = "Other Shows from #{show.partnerName()}"
    when 'featured'
      data = _.extend criteria, featured: true, status: 'running'
      el = $('.js-featured-shows')
      title = "Featured Shows"
    when 'city'
      data = _.extend criteria, near: city.coords.toString(), sort: '-start_at'
      title = "Current Shows in #{show.formatCity()}"

  new RelatedShowsView
    collection: relatedShows
    title: title
    el: el

  relatedShows.fetch
    data: data
    success: ->
      relatedShows.getShowsRelatedImages()

_ = require 'underscore'
{ Cities, FeaturedCities } = require 'places'
PartnerShows = require '../../../../collections/partner_shows.coffee'
RelatedShowsView = require './view.coffee'

module.exports = (type, show) ->

  city = _.findWhere(Cities, name: show.formatCity())

  el = $('.js-related-shows')

  criteria =
    sort: 'end_at'
    size: 20
    displayable: true

  relatedShows = new PartnerShows

  switch type
    when 'fair'
      data =  _.extend criteria, {
        fair_id: show.related().fair.get('_id')
      }
      title = "More Booths from #{show.related().fair.get('name')}"
    when 'gallery'
      data = _.extend criteria, {
        sort: '-start_at'
        status: "upcoming"
      }
      relatedShows.url = "#{show.related().partner.url()}/shows"
      title = "Other Shows from #{show.partnerName()}"
    when 'featured'
      data = _.extend criteria, {
        sort: 'end_at'
        featured: true
        status: 'running'
        displayable: true
      }
      el = $('.js-featured-shows')
      title = "Featured Shows"
    when 'city'
      data = _.extend criteria, {
        near: city.coords.toString()
        sort: 'end_at'
        status: 'running'
        displayable: true
      }
      title = "Current Shows in #{show.formatCity()}"

  new RelatedShowsView
    collection: relatedShows
    title: title
    el: el

  relatedShows.fetch
    data: data
    success: ->
      relatedShows.getShowsRelatedImages()

Change parameters by which shows are selected


{div} = React.DOM

module.exports = React.createClass

  displayName: 'Modal'

  watchForEscape: (e) ->
    if e.keyCode is 27
      @props.close?()

  # shadow the entire viewport behind the dialog
  getDimensions: ->
    width: $(window).width() + 'px'
    height: $(window).height() + 'px'

  getInitialState: ->
    dimensions = @getDimensions()
    initialState =
      backgroundStyle: @getBackgroundStyle dimensions
      contentStyle: @getContentStyle dimensions

  getBackgroundStyle: (dimensions) ->
    if @props.zIndex
      { zIndex: @props.zIndex, width: dimensions.width, height: dimensions.height }
    else
      dimensions

  getContentStyle: (dimensions) ->
    if @props.zIndex
      { zIndex: @props.zIndex + 1, width: dimensions.width, height: dimensions.height }
    else
      dimensions

  updateStyles: ->
    dimensions = @getDimensions()
    @setState
      backgroundStyle: @getBackgroundStyle dimensions
      contentStyle: @getContentStyle dimensions

  # use bind/unbind for clients using older versions of jQuery
  componentDidMount: ->
    $(window).bind 'keyup', @watchForEscape
    $(window).bind 'resize', @updateStyles

  componentWillUnmount: ->
    $(window).unbind 'keyup', @watchForEscape
    $(window).unbind 'resize', @updateStyles

  render: ->
    (div {className: 'modal'},
      (div {className: 'modal-background', style: @state.backgroundStyle})
      (div {className: 'modal-content', style: @state.contentStyle}, @props.children)
    )

{div} = React.DOM

module.exports = React.createClass

  displayName: 'Modal'

  watchForEscape: (e) ->
    if e.keyCode is 27
      @props.close?()

  # shadow the entire viewport behind the dialog
  getDimensions: ->
    width: '100vw'
    height: '100vh'

  getInitialState: ->
    dimensions = @getDimensions()
    initialState =
      backgroundStyle: @getBackgroundStyle dimensions
      contentStyle: @getContentStyle dimensions

  getBackgroundStyle: (dimensions) ->
    if @props.zIndex
      { zIndex: @props.zIndex, width: dimensions.width, height: dimensions.height }
    else
      dimensions

  getContentStyle: (dimensions) ->
    if @props.zIndex
      { zIndex: @props.zIndex + 1, width: dimensions.width, height: dimensions.height }
    else
      dimensions

  updateStyles: ->
    dimensions = @getDimensions()
    @setState
      backgroundStyle: @getBackgroundStyle dimensions
      contentStyle: @getContentStyle dimensions

  # use bind/unbind for clients using older versions of jQuery
  componentDidMount: ->
    $(window).bind 'keyup', @watchForEscape
    $(window).bind 'resize', @updateStyles

  componentWillUnmount: ->
    $(window).unbind 'keyup', @watchForEscape
    $(window).unbind 'resize', @updateStyles

  render: ->
    (div {className: 'modal'},
      (div {className: 'modal-background', style: @state.backgroundStyle})
      (div {className: 'modal-content', style: @state.contentStyle}, @props.children)
    )

Change height and width calculations to just use Viewport Width and Height


window.Backbone ||= {}
window.Backbone.Views ||= {}

class Backbone.Views.IndicatorSelectorView extends Backbone.Diorama.NestingView
  template: Handlebars.templates['indicator_selector.hbs']
  className: 'modal indicator-selector'

  events:
    "click .close": "close"

  initialize: (options = {}) ->
    @currentIndicator  = options.currentIndicator
    @indicators = new Backbone.Collections.IndicatorCollection()
    @indicators.fetch(
      success: @render
    )

  render: =>
    $('body').addClass('stop-scrolling')

    @$el.html(@template(
      thisView: @
      currentIndicator: @currentIndicator
      indicators: @indicators.groupByType()
    ))
    @attachSubViews()

    @bindToIndicatorSelection()

    return @

  bindToIndicatorSelection: ->
    for key, subView of @subViews
      @listenTo(subView, 'indicatorSelected', @triggerIndicatorSelected)

  triggerIndicatorSelected: (indicator) =>
    @trigger('indicatorSelected', indicator)

  onClose: ->
    $('body').removeClass('stop-scrolling')

    @stopListening()
    @closeSubViews()

window.Backbone ||= {}
window.Backbone.Views ||= {}

class Backbone.Views.IndicatorSelectorView extends Backbone.Diorama.NestingView
  template: Handlebars.templates['indicator_selector.hbs']
  className: 'modal indicator-selector'

  events:
    "click .close": "close"

  initialize: (options = {}) ->
    @currentIndicator  = options.currentIndicator
    @indicators = new Backbone.Collections.IndicatorCollection([], withData: true)
    @indicators.fetch(
      success: @render
    )

  render: =>
    $('body').addClass('stop-scrolling')

    @$el.html(@template(
      thisView: @
      currentIndicator: @currentIndicator
      indicators: @indicators.groupByType()
    ))
    @attachSubViews()

    @bindToIndicatorSelection()

    return @

  bindToIndicatorSelection: ->
    for key, subView of @subViews
      @listenTo(subView, 'indicatorSelected', @triggerIndicatorSelected)

  triggerIndicatorSelected: (indicator) =>
    @trigger('indicatorSelected', indicator)

  onClose: ->
    $('body').removeClass('stop-scrolling')

    @stopListening()
    @closeSubViews()

Make the indicator selector only show indicators with data


{div} = React.DOM

@FeedView = React.createClass
  displayName: 'FeedView'

  componentWillMount: ->
    Screensmart.store.dispatch Screensmart.Actions.updateResponse()

  render: ->
    div
      className: 'feed'
      @props.children.map (child) ->
        div
          key: child.key
          className: 'item'
          child

{div} = React.DOM

@FeedView = React.createClass
  displayName: 'FeedView'

  render: ->
    div
      className: 'feed'
      @props.children.map (child) ->
        div
          key: child.key
          className: 'item'
          child

Fix response loading twice on fill_out start


class Lanes.Components.FieldSet extends Lanes.React.Component

    getDefaultProps: ->
        speed: 0.4

    propTypes:
        title: React.PropTypes.string.isRequired
        speed: React.PropTypes.number
        collapsed: React.PropTypes.bool

    getInitialState: ->
        state = {
            expanded: !@props.collapsed,
            icon: if @props.collapsed then 'plus' else 'minus'
        }
        state.height = 30 if @props.collapsed
        state

    getClientHeight: ->
        _.max(
            _.pluck(@refs.body.getDOMNode().children, 'clientHeight')
        ) + 45

    toggleExpanded: ->
        if @state.expanded
            if ! @state.hasExpanded
                @setState( hasExpanded: true, height: @getClientHeight() )
                _.defer @toggleExpanded
                return
            @setState expanded: false, height: 30
        else
            @setState expanded: true, height: @getClientHeight()

        _.delay( =>
            if @isMounted()
                @setState(icon: if @state.expanded then 'minus' else 'plus')
        , @props.speed * 1000)

    render: ->
        colProps = _.omit(@props, 'name')
        <BS.Col {...colProps}>
            <fieldset className={
                _.classnames("collapsible", @props.className, @state.icon
                {expanded: @state.expanded, collapsed: !@state.expanded})
            }
            style={
                maxHeight: @state.height
                transition: "max-height #{@props.speed}s ease-in-out";
            }>
                <legend onClick={@toggleExpanded}>
                    {@props.title}
                </legend>
                <div ref="body" className="fieldset-fields">
                    {@props.children}
                </div>
            </fieldset>
        </BS.Col>

class Lanes.Components.FieldSet extends Lanes.React.Component

    getDefaultProps: ->
        expanded: true

    propTypes:
        title: React.PropTypes.string.isRequired
        expanded: React.PropTypes.bool

    getInitialState: ->
        expanded: @props.expanded

    componentWillReceiveProps: (nextProps) ->
        @setState(expanded: nextProps.expanded) if nextProps.expanded?

    toggleExpanded: ->
        @setState(expanded: not @state.expanded)

    render: ->
        colProps = _.omit(@props, 'name')
        <BS.Col {...colProps}>
            <fieldset className={
                _.classnames("collapsible", @props.className, @state.icon
                    {expanded: @state.expanded, collapsed: !@state.expanded})
            }>
                <legend onClick={@toggleExpanded}>
                    {@props.title}
                </legend>
                <BS.Collapse in={@state.expanded}>
                    <div ref="body" className="fieldset-fields">
                        {@props.children}
                    </div>
                </BS.Collapse>
            </fieldset>
        </BS.Col>

Use Collapse component vs own logic

Use Collapse component vs own logic


module.exports = ->
  highlightSelectedPackage = atom.packages.getLoadedPackage('highlight-selected')

  highlightSelected = require (highlightSelectedPackage.path)
  HighlightedAreaView = require (highlightSelectedPackage.path + '/lib/highlighted-area-view')

  class FakeEditor
    constructor: (@minimap) ->

    getActiveMinimap: -> @minimap.getActiveMinimap()

    getActiveTextEditor: -> @getActiveMinimap()?.getTextEditor()

    ['markBufferRange', 'scanInBufferRange', 'getEofBufferPosition', 'getSelections', 'getLastSelection', 'bufferRangeForBufferRow', 'getTextInBufferRange'].forEach (key) ->
      FakeEditor::[key] = -> @getActiveTextEditor()[key](arguments...)

    ['decorateMarker'].forEach (key) ->
      FakeEditor::[key] = -> @getActiveMinimap()[key](arguments...)

  class MinimapHighlightSelectedView extends HighlightedAreaView
    constructor: (minimap) ->
      super
      @fakeEditor = new FakeEditor(minimap)

    getActiveEditor: -> @fakeEditor

    handleSelection: ->
      return unless atom.workspace.getActiveTextEditor()?
      return unless @fakeEditor.getActiveTextEditor()?
      super

module.exports = ->
  highlightSelectedPackage = atom.packages.getLoadedPackage('highlight-selected')

  highlightSelected = require (highlightSelectedPackage.path)
  HighlightedAreaView = require (highlightSelectedPackage.path + '/lib/highlighted-area-view')

  class FakeEditor
    constructor: (@minimap) ->

    getActiveMinimap: -> @minimap.getActiveMinimap()

    getActiveTextEditor: -> @getActiveMinimap()?.getTextEditor()

    ['markBufferRange', 'scanInBufferRange', 'getEofBufferPosition', 'getSelections', 'getLastSelection', 'bufferRangeForBufferRow', 'getTextInBufferRange', 'onDidChangeSelectionRange'].forEach (key) ->
      FakeEditor::[key] = -> @getActiveTextEditor()[key](arguments...)

    ['decorateMarker'].forEach (key) ->
      FakeEditor::[key] = -> @getActiveMinimap()[key](arguments...)

  class MinimapHighlightSelectedView extends HighlightedAreaView
    constructor: (minimap) ->
      @fakeEditor = new FakeEditor(minimap)
      super

    getActiveEditor: -> @fakeEditor

    handleSelection: ->
      return unless atom.workspace.getActiveTextEditor()?
      return unless @fakeEditor.getActiveTextEditor()?
      super

:bug: Fix broken plugin since highlight-selected update

Fixes #5


_ = require 'underscore'
Backbone = require 'backbone'

router = new Backbone.Router
href = null

module.exports = ($el) ->
  $el.on 'click', 'a[href]', onClick
  # Make sure history is started to use our internal router
  Backbone.history.start(pushState: true) unless Backbone.History.started

onClick = (e) ->
  e.preventDefault()
  _.defer =>
    href = $(this).attr('href')
    return unless href?.length
    # Don't iframe if it might be an offsite link
    return if href.indexOf('http') > -1
    setIframe()
    router.route location.pathname.replace(/^\//, ''), removeIframe
    router.navigate href

setIframe = ->
  $('#iframe-popover').html "<iframe src='#{href}'>"
  $('body').addClass('body-iframe-popover')

removeIframe = ->
  $('#iframe-popover').html ''
  $('body').removeClass('body-iframe-popover')

# To keep our router state from getting out of wack we'll do a full redirect after the first page
# in the iframe. We trigger this parent event inside the main_layout/templates/head.jade to make
# sure our route changes right away.
addEventListener? 'message', (e) ->
  return unless e.data.href
  return if e.data.href is @location.href
  $('body').remove()
  @location = e.data.href

_ = require 'underscore'
Backbone = require 'backbone'

router = new Backbone.Router
href = null

module.exports = ($el) ->
  $el.on 'click', 'a[href]', onClick
  # Make sure history is started to use our internal router
  Backbone.history.start(pushState: true) unless Backbone.History.started

onClick = (e) ->
  return if e.metaKey or e.ctrlKey

  e.preventDefault()
  _.defer =>
    href = $(this).attr('href')
    return unless href?.length
    # Don't iframe if it might be an offsite link
    return if href.indexOf('http') > -1
    setIframe()
    router.route location.pathname.replace(/^\//, ''), removeIframe
    router.navigate href

setIframe = ->
  $('#iframe-popover').html "<iframe src='#{href}'>"
  $('body').addClass('body-iframe-popover')

removeIframe = ->
  $('#iframe-popover').html ''
  $('body').removeClass('body-iframe-popover')

# To keep our router state from getting out of wack we'll do a full redirect after the first page
# in the iframe. We trigger this parent event inside the main_layout/templates/head.jade to make
# sure our route changes right away.
addEventListener? 'message', (e) ->
  return unless e.data.href
  return if e.data.href is @location.href
  $('body').remove()
  @location = e.data.href

Allow cmd and ctrl clicks to open links in new tabs


{CompositeDisposable} = require 'event-kit'
[Minimap, MinimapElement] = []

module.exports =
class V4Main
  @includeInto: (base) ->
    for k,v of @prototype
      base::[k] = v

  activateV4: ->
    @editorsMinimaps = {}
    @subscriptions = new CompositeDisposable
    MinimapElement ?= require './minimap-element'

    MinimapElement.registerViewProvider()

  deactivate: ->
    minimap.destroy() for id,minimap of @editorsMinimaps
    @subscriptions.dispose()
    @editorsMinimaps = {}
    @toggled = false

  toggle: ->
    if @toggled
      @toggled = false
      @subscriptions.dispose()
    else
      @toggled = true
      @initSubscriptions()

  minimapForEditor: (editor) -> @editorsMinimaps[editor.id]

  initSubscriptions: ->
    Minimap ?= require './minimap'

    @subscriptions.add atom.workspace.observeTextEditors (textEditor) =>
      minimap = new Minimap({textEditor})
      @editorsMinimaps[textEditor.id] = minimap

      editorElement = atom.views.getView(textEditor)
      minimapElement = atom.views.getView(minimap)

      minimapElement.attach()

{CompositeDisposable} = require 'event-kit'
[Minimap, MinimapElement] = []

module.exports =
class V4Main
  @includeInto: (base) ->
    for k,v of @prototype
      base::[k] = v

  activateV4: ->
    @editorsMinimaps = {}
    @subscriptions = new CompositeDisposable
    MinimapElement ?= require './minimap-element'

    MinimapElement.registerViewProvider()

  deactivate: ->
    minimap.destroy() for id,minimap of @editorsMinimaps
    @subscriptions.dispose()
    @editorsMinimaps = {}
    @toggled = false

  toggle: ->
    if @toggled
      @toggled = false
      @subscriptions.dispose()
    else
      @toggled = true
      @initSubscriptions()

  minimapForEditor: (editor) -> @editorsMinimaps[editor.id]

  observeMinimaps: (iterator) ->
    return unless iterator?
    iterator({view: minimap}) for id,minimap of @editorsMinimaps
    createdCallback = (minimap) -> iterator(minimap)
    disposable = @onDidCreateMinimap(createdCallback)
    disposable.off = ->
      deprecate('Use Disposable::dispose instead')
      disposable.dispose()
    disposable

  initSubscriptions: ->
    Minimap ?= require './minimap'

    @subscriptions.add atom.workspace.observeTextEditors (textEditor) =>
      minimap = new Minimap({textEditor})
      @editorsMinimaps[textEditor.id] = minimap

      editorElement = atom.views.getView(textEditor)
      minimapElement = atom.views.getView(minimap)

      @emitter.emit('did-create-minimap')

      minimapElement.attach()

Implement minimap creation observer method for v4


Template.displayIcon.userIconUrl = ->
  # TODO: We should specify default URL to the image of an avatar which is generated from name initials
  "https://secure.gravatar.com/avatar/#{ Meteor.person()?.gravatarHash }?s=25"

Template._loginButtonsLoggedInDropdownActions.personSlug = ->
  Meteor.person()?.slug

# To close login buttons dialog box when clicking or focusing somewhere outside
$(document).click (e) ->
  Accounts._loginButtonsSession.closeDropdown() unless e.originalEvent.dialogBoxEvent
  return # Make sure CoffeeScript does not return anything

$(document).focus (e) ->
  Accounts._loginButtonsSession.closeDropdown() unless e.originalEvent.dialogBoxEvent
  return # Make sure CoffeeScript does not return anything

# But if clicked inside, we mark the event so that dialog box is not closed
Template._loginButtons.events
  'click #login-buttons': (e, template) ->
    e.dialogBoxEvent = true
    return # Make sure CoffeeScript does not return anything

  'focus #login-buttons': (e, template) ->
    e.dialogBoxEvent = true
    return # Make sure CoffeeScript does not return anything

Template.displayIcon.userIconUrl = ->
  # TODO: We should specify default URL to the image of an avatar which is generated from name initials
  "https://secure.gravatar.com/avatar/#{ Meteor.person()?.gravatarHash }?s=25"

Template._loginButtonsLoggedInDropdownActions.personSlug = ->
  Meteor.person()?.slug

# To close login buttons dialog box when clicking or focusing somewhere outside
$(document).click (e) ->
  Accounts._loginButtonsSession.closeDropdown() unless e.originalEvent?.dialogBoxEvent
  return # Make sure CoffeeScript does not return anything

$(document).focus (e) ->
  Accounts._loginButtonsSession.closeDropdown() unless e.originalEvent?.dialogBoxEvent
  return # Make sure CoffeeScript does not return anything

# But if clicked inside, we mark the event so that dialog box is not closed
Template._loginButtons.events
  'click #login-buttons': (e, template) ->
    e.dialogBoxEvent = true
    return # Make sure CoffeeScript does not return anything

  'focus #login-buttons': (e, template) ->
    e.dialogBoxEvent = true
    return # Make sure CoffeeScript does not return anything

Check if originalEvent is defined

Check if originalEvent is defined


_ = require 'underscore-plus'
{View} = require 'atom-space-pen-views'

module.exports =
class IncompatiblePackagesStatusView extends View
  @content: ->
    @div class: 'incompatible-packages-status inline-block text text-error', =>
      @span class: 'icon icon-bug'
      @span outlet: 'countLabel', class: 'incompatible-packages-status'

  initialize: (statusBar, incompatibleCount) ->
    @countLabel.text(incompatibleCount)
    @tooltipSubscription = atom.tooltips.add(@element, title: _.pluralize(incompatibleCount, 'incompatible package'))
    statusBar.appendRight(this)

    @on 'click', =>
      atom.commands.dispatch(atom.views.getView(atom.workspace), 'incompatible-packages:view')
      @destroy()

  destroy: ->
    @tooltipSubscription.dispose()
    @remove()

_ = require 'underscore-plus'
{View} = require 'atom-space-pen-views'

module.exports =
class IncompatiblePackagesStatusView extends View
  @content: ->
    @div class: 'incompatible-packages-status inline-block text text-error', =>
      @span class: 'icon icon-bug'
      @span outlet: 'countLabel', class: 'incompatible-packages-status'

  initialize: (statusBar, incompatibleCount) ->
    @countLabel.text(incompatibleCount)
    @tooltipSubscription = atom.tooltips.add(@element, title: _.pluralize(incompatibleCount, 'incompatible package'))
    statusBar.addRightTile(item: this)

    @on 'click', =>
      atom.commands.dispatch(atom.views.getView(atom.workspace), 'incompatible-packages:view')
      @destroy()

  destroy: ->
    @tooltipSubscription.dispose()
    @remove()

Use new status bar tile API

Use new status bar tile API


# modules
Sequelize = require 'sequelize'
db = require './db'
Team = require './team'

# custom validation constraints
checkUnique = (value, next) ->
    User.find
        where: $or:
                nickname: value
                email: value
    .then (user) ->
        if user then return next 'Ce nom d\'utilisateur ou cet e-mail ont déjà été choisis.'
        return next()
    .catch (err) ->
        return next err

checkNotNull = (value, next) ->
    if value.length == 0
        throw new Error 'Valeur nulle non autorisée'
    else
        next()

notNull:
    msg: "Valeur nulle"

# def model
User = db.orm.define 'User',
    id:
        type: Sequelize.INTEGER
        primaryKey: true
        autoIncrement: true
    nickname:
        type: Sequelize.STRING 25
        unique: true
        allowNull: false
        validate:
            len: [3, 25]
            isUnique: checkUnique
            isNotNull: checkNotNull
    email:
        type: Sequelize.STRING 25
        unique: true
        allowNull: false
        validate:
            len: [3, 25]
            isUnique: checkUnique
            isNotNull: checkNotNull
    password:
        type: Sequelize.STRING
        allowNull: false
        validate:
            isNotNull: checkNotNull
            len: [6,100]

# def model assocs
User.belongsTo Team,
    foreignKey: 'teamId'
    as: 'team'

#export
module.exports = User

# modules
Sequelize = require 'sequelize'
db = require './db'
Team = require './team'

# custom validation constraints
checkUnique = (value, next) ->
    User.find
        where: $or:
                nickname: value
                email: value
    .then (user) ->
        if user then return next 'Ce nom d\'utilisateur ou cet e-mail ont déjà été choisis.'
        return next()
    .catch (err) ->
        return next err

checkNotNull = (value, next) ->
    if value.length == 0
        throw new Error 'Valeur nulle non autorisée'
    else
        next()

# def model
User = db.orm.define 'User',
    id:
        type: Sequelize.INTEGER
        primaryKey: true
        autoIncrement: true
    nickname:
        type: Sequelize.STRING 25
        unique: true
        allowNull: false
        validate:
            len: [3, 25]
            isUnique: checkUnique
            isNotNull: checkNotNull
    email:
        type: Sequelize.STRING 25
        unique: true
        allowNull: false
        validate:
            len: [3, 25]
            isUnique: checkUnique
            isNotNull: checkNotNull
    password:
        type: Sequelize.STRING
        allowNull: false
        validate:
            isNotNull: checkNotNull

# def model assocs
User.belongsTo Team,
    foreignKey: 'teamId'
    as: 'team'

#export
module.exports = User

Delete length validation for password

Delete length validation for password


label = (fontSize, options = {}) ->

  options.font = _.extend {}, options.font or {},
    fontSize: fontSize

  _.extend {}, options,
    height: Ti.UI.SIZE
    width: Ti.UI.FILL
    color: '#333'
    bottom: options.font.fontSize * 0.5 # Similar to bottom margin of 0.5em

heading = (fontSize) ->
  label fontSize,
    font:
      fontWeight: 'bold'

module.exports =

  h1: heading 20

  h2: heading 18

  h3: heading 16

  h4: heading 14

  h5: heading 12

  h6: heading 10

  p: label 14

  combined:

    view:
      height: 0
      #layout: 'vertical'

    primary:
      top: 0
      height: Ti.UI.SIZE
      width: Ti.UI.FILL
      color: '#333'
      font:
        fontSize: 15

    meta:
      bottom: 0
      height: Ti.UI.SIZE
      width: Ti.UI.FILL
      color: '#999'
      font:
        fontSize: 11

label = (fontSize, options = {}) ->

  options.font = _.extend {}, options.font or {},
    fontSize: fontSize

  _.extend {}, options,
    height: Ti.UI.SIZE
    width: Ti.UI.FILL
    color: '#333'
    bottom: options.font.fontSize * 0.5 # Similar to bottom margin of 0.5em

heading = (fontSize) ->
  label fontSize,
    font:
      fontWeight: 'bold'

module.exports =

  h1: heading 20

  h2: heading 18

  h3: heading 16

  h4: heading 14

  h5: heading 12

  h6: heading 10

  p: label 14

  combined:

    view:
      height: Ti.UI.SIZE
      layout: 'vertical'

    primary:
      top: 0
      height: Ti.UI.SIZE
      width: Ti.UI.FILL
      color: '#333'
      font:
        fontSize: 15

    meta:
      bottom: 0
      height: Ti.UI.SIZE
      width: Ti.UI.FILL
      color: '#999'
      font:
        fontSize: 11

Set label height to Ti.UI.SIZE

Set label height to Ti.UI.SIZE


# handle background tiles
backgroundTile = undefined
tileImg = new Image()
tileImg.onload = ->
  backgroundTile = cq().context.createPattern(tileImg,'repeat')
tileImg.src = '/img/tile.png'
drawBackgroundTiles = (ctx) ->
  if backgroundTile?
    ctx
    .rect(0,0, ctx.canvas.width,ctx.canvas.height)
    .fillStyle(backgroundTile)
    .fill()

reset = ->
  imageSelector =
    color : '#de683c'
    zoom  : 1
  imageSelection =
    color: '#29a4d3'

  imageMouseCoords =
    x: imageCanvas.innerWidth/2
    y: imageCanvas.innerHeight/2
  zoomedMouseCoords =
    x: 0
    y: 0

# listen for scroll events
imageCanvas.on 'mousewheel', (e) ->
  e.preventDefault()
  if e.deltaY
    imageSelector.zoom += zoomSpeed*(if e.deltaY < 1 then 1 else -1)
    if imageSelector.zoom < 0.1 then imageSelector.zoom = 0.1
    if imageSelector.zoom > 1 then imageSelector.zoom = 1

# load new image on file select
fileSelect.on 'change', (e) ->
  selectedFile = e.target.files[0]
  reader = new FileReader()
  reader.onload = (e) ->
    scope.$apply ->
      scope.imagedata = e.target.result
  reader.readAsDataURL selectedFile

# handle background tiles
backgroundTile = undefined
tileImg = new Image()
tileImg.onload = ->
  backgroundTile = cq().context.createPattern(tileImg,'repeat')
tileImg.src = './img/tile.png'
drawBackgroundTiles = (ctx) ->
  if backgroundTile?
    ctx
    .rect(0,0, ctx.canvas.width,ctx.canvas.height)
    .fillStyle(backgroundTile)
    .fill()

reset = ->
  imageSelector =
    color : '#de683c'
    zoom  : 1
  imageSelection =
    color: '#29a4d3'

  imageMouseCoords =
    x: imageCanvas.innerWidth/2
    y: imageCanvas.innerHeight/2
  zoomedMouseCoords =
    x: 0
    y: 0

# listen for scroll events
imageCanvas.on 'mousewheel', (e) ->
  e.preventDefault()
  if e.deltaY
    imageSelector.zoom += zoomSpeed*(if e.deltaY < 1 then 1 else -1)
    if imageSelector.zoom < 0.1 then imageSelector.zoom = 0.1
    if imageSelector.zoom > 1 then imageSelector.zoom = 1

# load new image on file select
fileSelect.on 'change', (e) ->
  selectedFile = e.target.files[0]
  reader = new FileReader()
  reader.onload = (e) ->
    scope.$apply ->
      scope.imagedata = e.target.result
  reader.readAsDataURL selectedFile

Make tile path work in GH

Make tile path work in GH