hiding menu on non-child clicks/taps

hiding menu on non-child clicks/taps

--- app/assets/javascripts/mobile/_mobile.js.coffee
+++ app/assets/javascripts/mobile/_mobile.js.coffee
@@ -5,11 +5,18 @@
     if like_count is 1 then 'like' else 'likes'

 $ ->
+    window.$window = ($ window)
+    window.$html = ($ 'html')
     window.$mobile_header = ($ '#mobile_header')
     window.$menu = ($ '#menu')
     window.$menu_button = ($ '#menu_button')
-    window.has_touch_events = !($ 'html').hasClass('no-touch')
+    window.has_touch_events = !$html.hasClass('no-touch')
     window.toggle_menu = -> $menu.toggle()
+    window.menu_is_visible = -> $menu.css('display') is 'block'
+    window.hide_menu_on_non_child_event = ($target) ->
+        if !$target.closest('.mobile-header').length and menu_is_visible()
+            toggle_menu()
+
     window.forceReflow = (elem = document.documentElement) ->
         #http://stackoverflow.com/a/11478853/382982
         hack = document.createElement("div")
@@ -29,12 +36,18 @@
             ).blur(->
                 $mobile_header.removeClass('absolute')
             )
-        ($ window).scroll -> forceReflow()
-
+        $window.scroll -> forceReflow()
+
+        # hide/show menu
+        $html.tap (e) -> hide_menu_on_non_child_event(($ e.target))
+        $window.scroll -> $menu.hide()
         $menu_button.tap((e) ->
             e.preventDefault()
             toggle_menu())
+
     else
+        # hide/show menu
+        $html.click (e) -> hide_menu_on_non_child_event(($ e.target))
         $menu_button.click((e) ->
             e.preventDefault()
             toggle_menu())


added catch for plural uppercase acronyms (#295)

--- src/string/title.coffee
+++ src/string/title.coffee
@@ -14,19 +14,20 @@
   locale = if "locale" of this then @locale.value else defaultLocale
   smalls = locale.lowercase.map (b) -> b.toLowerCase()
   bigs   = locale.uppercase
+  bigs   = bigs.concat(bigs.map (b) -> b + "s")
   biglow = bigs.map (b) -> b.toLowerCase()

   text.replace /\S*/g, (txt, i) ->

     if txt

-      bigindex = biglow.indexOf(txt.toLowerCase())
-
       if /^[^\W\s]/.test(txt)
         prefix = ""
       else
         prefix = txt.charAt(0)
         txt = txt.slice(1)
+
+      bigindex = biglow.indexOf(txt.toLowerCase())

       if bigindex >= 0
         new_txt = bigs[bigindex]


Add delayWithSelector operator

Add delayWithSelector operator

--- assets/javascripts/descriptors/operators.coffee
+++ assets/javascripts/descriptors/operators.coffee
@@ -158,6 +158,8 @@
 recursiveFunctionOperators = R.mapObj(R.merge(recursiveFunctionOperatorsDefaults))(
   flatMap: {}
   flatMapLatest: {}
+  delayWithSelector:
+    getDefaultObservable: R.compose(createSimpleObservable('timer'), R.add("1000 * "), getClosedOverArgName)
   buffer:
     getDefaultObservable: R.compose(createSimpleObservable('timer'), R.always("1000"))
   concatMap:


今ココスタンプが反応しないことがあったので修正。

今ココスタンプが反応しないことがあったので修正。

--- src/robot-direct.coffee
+++ src/robot-direct.coffee
@@ -5,7 +5,7 @@

 _map = (msg, callback) ->
   text = msg.match[1].replace(/[\n\r]/g, " ")
-  m = text.match(/^今ココ[:：] (.*) (http:\/\/.*)$/)
+  m = text.match(/^今ココ[:：] (.*) (https?:\/\/.*)$/)
   if m?
     place = m[1].replace(/\ ?\(近辺\)$/, "").replace(/^緯度 [:：].*$/, "")
     url = m[2]


li destroy was broken; fixed

li destroy was broken; fixed

--- code/linode.coffee
+++ code/linode.coffee
@@ -140,7 +140,7 @@
   # Returns an instance given its name.
   # TODO: put err in to config
   @get: (name, callback) ->
-    @list (err, list) ->
+    @list no, (err, list) ->
       k = _.find list, (n) ->
         n.name == name
       throw "instance not found" unless k?
@@ -190,7 +190,7 @@

   @_update_linode_label: (res, callback) =>
       @linode_id = res['LinodeID']
-      @list (err, l) =>
+      @list no, (err, l) =>
         instances = _.filter l, (x) =>
           instance_config = x.name.match(/.*(?=-\d+$)/)
           instance_config? and instance_config[0] == @config.name


fix indentation

fix indentation

--- src/ui/models/convsettings.coffee
+++ src/ui/models/convsettings.coffee
@@ -17,8 +17,8 @@
         id = entity.id?.chat_id or entity # may pass id directly
         exists = (e for e in @selectedEntities when e.id.chat_id == id).length != 0
         if not exists
-          @selectedEntities.push entity
-          updated 'selectedEntities'
+            @selectedEntities.push entity
+            updated 'selectedEntities'

     removeSelectedEntity: (entity) ->
         id = entity.id?.chat_id or entity # may pass id directly
@@ -32,26 +32,26 @@
     setSearchQuery: (query) -> @searchQuery = query

     loadConversation: (c) ->
-      c.participant_data.forEach (p) =>
-        id = p.id.chat_id or p.id.gaia_id
-        if entity.isSelf id then return
-        p = entity[id]
-        @selectedEntities.push
-          id: chat_id: id
-          properties:
-            photo_url: p.photo_url
-            display_name: p.display_name or p.fallback_name
-      @id = c.conversation_id or c.id
-      @name = c.name or ""
-      updated 'convsettings'
+        c.participant_data.forEach (p) =>
+            id = p.id.chat_id or p.id.gaia_id
+            if entity.isSelf id then return
+            p = entity[id]
+            @selectedEntities.push
+                id: chat_id: id
+                properties:
+                    photo_url: p.photo_url
+                    display_name: p.display_name or p.fallback_name
+        @id = c.conversation_id or c.id
+        @name = c.name or ""
+        updated 'convsettings'

     reset: ->
-      @searchedEntities = []
-      @selectedEntities = []
-      @searchQuery = ""
-      @name = ""
-      @id = null
-      updated 'convsettings'
+        @searchedEntities = []
+        @selectedEntities = []
+        @searchQuery = ""
+        @name = ""
+        @id = null
+        updated 'convsettings'

 }


Clear info if no targetd data

Clear info if no targetd data

--- static/coffee/v2_locations.coffee
+++ static/coffee/v2_locations.coffee
@@ -93,10 +93,10 @@
               "
" + props.count.set + "
"
           else
             this._div.innerHTML = "
" + props.name + "
"
-      #   else
-      #     this._div.innerHTML = ""
-      # else
-      #   this._div.innerHTML = ""
+        else
+         this._div.innerHTML = ""
+      else
+        this._div.innerHTML = ""

     # rollover treatment
     highlight = (e) ->


+1 missing

+1 missing

--- basicAI.coffee
+++ basicAI.coffee
@@ -788,7 +788,7 @@

   # Do you want to gain a copper from Ill-Gotten Gains? Yes, we want if that improves our buy
   gainCopperPriority: (state, my) ->
-    if my.ai.coinGainMargin(state) <= my.countInHand("Ill-Gotten Gains")
+    if my.ai.coinGainMargin(state) <= my.countInHand("Ill-Gotten Gains")+1
       [yes]
     else
       [no]


myteam: renamed first and last name selectors

--- client/home/lib/myteam/components/hometeamsendinvites/view.coffee
+++ client/home/lib/myteam/components/hometeamsendinvites/view.coffee
@@ -23,8 +23,8 @@

       <input type='text' className='kdinput text user-email' placeholder='mail@example.com' value={inviteInput.get 'email'} onChange={@props.onInputChange.bind(this, rowIndex, 'email')} />
-      <input type='text' className='kdinput text firstname' placeholder='Optional' value={inviteInput.get 'firstname'} onChange={@props.onInputChange.bind(this, rowIndex, 'fistname')}/>
-      <input type='text' className='kdinput text lastname' placeholder='Optional' value={inviteInput.get 'lastname'} onChange={@props.onInputChange.bind(this, rowIndex, 'lastname')}/>
+      <input type='text' className='kdinput text firstname' placeholder='Optional' value={inviteInput.get 'firstName'} onChange={@props.onInputChange.bind(this, rowIndex, 'firstName')}/>
+      <input type='text' className='kdinput text lastname' placeholder='Optional' value={inviteInput.get 'lastName'} onChange={@props.onInputChange.bind(this, rowIndex, 'lastName')}/>

         <input type='checkbox' className='kdinput checkbox' checked={checked} onChange={@props.onInputChange.bind(this, rowIndex, 'role')}/>


Fix game launching on windows

Fix game launching on windows

--- metal/downloader.coffee
+++ metal/downloader.coffee
@@ -69,7 +69,7 @@
               exe.on 'exit', (code) ->
                 notify "Done playing! (darwin)"
             when "win32"
-              exe = childProcess.exec("'#{exePath}'")
+              exe = childProcess.exec("\"#{exePath}\"")
               exe.on 'exit', (code) ->
                 notify "Done playing! (win32)"
             else


changed the default timeout

changed the default timeout

--- src/zombie/browser.coffee
+++ src/zombie/browser.coffee
@@ -1239,7 +1239,7 @@
   language: "en-US"

   # Default time to wait (visit, wait, etc).
-  waitDuration: "5s"
+  waitDuration: "20s"

   # Indicates whether or not to validate and execute JavaScript, default true.
   runScripts: true


Added "cancel" button, removed autofocus on "Delete" button

--- client/app/Applications/Activity.kdapplication/views/activityitemchild.coffee
+++ client/app/Applications/Activity.kdapplication/views/activityitemchild.coffee
@@ -150,6 +150,13 @@
                 type     : "mini"
                 cssClass : "error editor"
                 title     : "Error, please try again later!"
+        Cancel       :
+          style      : "modal-cancel"
+          title      : "cancel"
+          callback   : ->
+            modal.destroy()
+
+    modal.buttons.Delete.blur()

   click: KD.utils.showMoreClickHandler


Re-design the new app dialog

Re-design the new app dialog

--- client/app/MainApp/kodingappscontroller.coffee
+++ client/app/MainApp/kodingappscontroller.coffee
@@ -542,11 +542,11 @@

   makeNewApp:(callback)->

-    return callback?() if newAppModal
+    return callback? yes if newAppModal

     newAppModal = new KDModalViewWithForms
       title                       : "Create a new Application"
-      # content                   : "
Please select the application type you want to start with.
"
+      content                     : "
Please select the application type you want to start with.
"
       overlay                     : yes
       width                       : 400
       height                      : "auto"
@@ -555,34 +555,49 @@
         forms                     :
           form                    :
             buttons               :
-              "Blank Application" :
+              Create              :
                 cssClass          : "modal-clean-gray"
+                loader            :
+                  color           : "#444444"
+                  diameter        : 12
                 callback          : =>
-                  name = newAppModal.modalTabs.forms.form.inputs.name.getValue()
-                  @prepareApplication {isBlank : yes, name}, (err, response)->
-                    callback? err
-                  newAppModal.destroy()
-              "Sample Application":
-                cssClass          : "modal-clean-gray"
-                callback          : =>
-                  name = newAppModal.modalTabs.forms.form.inputs.name.getValue()
-                  @prepareApplication {isBlank : no, name}, (err, response)->
-                    callback? err
-                  newAppModal.destroy()
+                  name        = newAppModal.modalTabs.forms.form.inputs.name.getValue()
+                  type        = newAppModal.modalTabs.forms.form.inputs.type.getValue()
+                  manifestStr = defaultManifest type, name
+                  manifest    = JSON.parse manifestStr
+                  appPath     = getAppPath manifest
+
+                  FSItem.doesExist appPath, (err, exists)=>
+                    newAppModal.modalTabs.forms.form.buttons.Create.hideLoader()
+                    if exists
+                      new KDNotificationView
+                        type      : "mini"
+                        cssClass  : "error"
+                        title     : "App folder with that name is already exists, please choose a new name."
+                        duration  : 3000
+                    else
+                      @prepareApplication {isBlank : type is "blank", name}, (err, response)->
+                        callback? err
+                      newAppModal.destroy()
             fields                :
+              type                :
+                label             : "Type"
+                itemClass         : KDSelectBox
+                type              : "select"
+                name              : "type"
+                defaultValue      : "sample"
+                selectOptions     : [
+                  { title : "Sample Application", value : "sample" }
+                  { title : "Blank Application",  value : "blank"  }
+                ]
               name                :
                 label             : "Name:"
                 name              : "name"
                 placeholder       : "name your application..."
-                validate          :
-                  rules           :
-                    required      : yes
-                  messages        :
-                    required      : "application name is required!"

     newAppModal.once "KDObjectWillBeDestroyed", ->
       newAppModal = null
-      callback? null
+      callback? yes

   prepareApplication:({isBlank, name}, callback)->


sidebar: fix react key problem

sidebar: fix react key problem

--- client/app/lib/components/sidebar/index.coffee
+++ client/app/lib/components/sidebar/index.coffee
@@ -167,10 +167,9 @@
     @state.drafts?.toList().toJS().map (template) =>
       id = template._id
       title = _.unescape template.title
-

+

             <Link href="/Stack-Editor/#{id}" onClick={@onDraftTitleClick.bind this, id}>{title}</Link>


Environment: Actions: checkGroupStacks on load

--- client/app/lib/flux/environment/actions.coffee
+++ client/app/lib/flux/environment/actions.coffee
@@ -62,6 +62,7 @@
   { reactor, computeController } = kd.singletons

   computeController.ready ->
+
     computeController.on 'StackRevisionChecked', (stack) ->
       return  if _revisionStatus?.error? and not stack._revisionStatus.status

@@ -73,6 +74,8 @@

     computeController.on 'GroupStacksConsistent', ->
       reactor.dispatch actions.GROUP_STACKS_CONSISTENT
+
+    computeController.checkGroupStacks()

 handleMemberWarning = (message) ->


Improved: guest addition

Improved: guest addition

--- client/app/views/popover_screens/guests.coffee
+++ client/app/views/popover_screens/guests.coffee
@@ -11,6 +11,7 @@
     events:
         "click .add-new-guest": "onNewGuest"
         "click .guest-delete": "onRemoveGuest"
+        'keyup input[name="guest-name"]': "onKeyup"

     getRenderData: ->
@@ -64,3 +65,13 @@
             # never be a big list.
             @afterRender()

+            # Reset form field.
+            @$('input[name="guest-name"]').val ''
+            @$('input[name="guest-name"]').focus()
+
+
+    onKeyup: (event) ->
+        key = event.keyCode
+        if key is 13 # enter
+            @onNewGuest()
+


recover route should not have been removed

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -216,6 +216,8 @@
         requireLogout -> mainController.loginScreen.animateToForm 'register'
       '/:name?/Join'      : ({params:{name}})->
         requireLogout -> mainController.loginScreen.animateToForm 'join'
+      '/:name?/Recover'   : ({params:{name}})->
+        requireLogout -> mainController.loginScreen.animateToForm 'recover'

       # section
       # TODO: nested groups are disabled.


Rename `namespace.delta` to `namespace.deltas`

--- models/namespace.coffee
+++ models/namespace.coffee
@@ -40,7 +40,7 @@
     @calendars = new RestfulModelCollection(Calendar, @connection, @id)
     @events = new RestfulModelCollection(Event, @connection, @id)
     @tags = new RestfulModelCollection(Tag, @connection, @id)
-    @delta = new Delta(@connection, @id)
+    @deltas = new Delta(@connection, @id)
     @

   me: ->


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/active_bounds.coffee
+++ test/active_bounds.coffee
@@ -29,11 +29,11 @@

   destroySpy = false

-  obj.bind 'destroy', ->
+  obj2.bind 'destroy', ->
     destroySpy = true

-  obj.I.x = 10000
-  obj.I.y = 50
+  obj2.I.x = 10000
+  obj2.I.y = 50

   obj.update()


Update Atom config

Update Atom config

--- atom.cson
+++ atom.cson
@@ -53,6 +53,9 @@
     zoomFontWhenCtrlScrolling: false
   "exception-reporting":
     userId: "51ccaaae-04bc-1ed3-3445-f9bd1a2f3a71"
+  linter:
+    errorPanelHeight: 116
+  "linter-eslint": {}
   minimap:
     displayPluginsControls: false
     plugins:


dont throw error while stoping non installed hue


robust remove

robust remove

--- src/dt-jquery.coffee
+++ src/dt-jquery.coffee
@@ -8,8 +8,12 @@
 # TODO mit canvas tag kommt man direkt auf die browser render ticks.

+removed = (el) ->
+    el.closed is "removed"
+
 # delay or invoke job immediately
 delay = (job) ->
+    return if removed this
     # only when tag is ready
     if @_jquery?
         do job
@@ -44,7 +48,7 @@
 #                 parent._jquery.data('dt-jquery', parent)
             else
                 nextAnimationFrame ->
-                    parent._jquery.append(el._jquery)
+                    parent._jquery?.append(el._jquery)

     tpl.on 'close', (el) ->
         el._jquery ?= $(el.toString())
@@ -64,7 +68,7 @@
     tpl.on 'raw', (el, html) ->
         delay.call el, ->
             nextAnimationFrame ->
-                el._jquery.html(html)
+                el._jquery?.html(html)

     tpl.on 'show', (el) ->
         delay.call el, ->
@@ -85,6 +89,7 @@
     tpl.on 'replace', (el, tag) ->
         delay.call el, ->
             nextAnimationFrame ->
+                return if removed el
                 _jquery = tag._jquery ? tag
                 return unless _jquery?.length > 0
                 el._jquery.replaceWith(_jquery)
@@ -94,7 +99,9 @@
                     el.jquery = _jquery

     tpl.on 'remove', (el) ->
-        el._jquery?.remove()
+        delay.call el.parent, ->
+            el._jquery?.remove()
+            delete el._jquery

     tpl.on 'end', ->
         tpl.xml._jquery = $()


Providers: Azure: region, storage options added, provider enabled, 'beta'

--- client/app/lib/providers/config.coffee
+++ client/app/lib/providers/config.coffee
@@ -163,18 +163,70 @@
     title                  : 'Azure Credential'
     color                  : '#ec06be'
     supported              : yes
-    enabled                : no
+    enabled                : 'beta'
     defaultTemplate        : require './templates/azure'
     description            : 'Azure'
     instanceTypes          : require './instance-types/azure'
     credentialFields       :
-      accountId            :
-        label              : 'Account Id'
-        placeholder        : 'account id in azure'
-      secret               :
-        label              : 'Secret'
-        placeholder        : 'azure secret'
-        type               : 'password'
+      publish_settings     :
+        label              : 'Publish Settings'
+        placeholder        : 'publish settings for azure'
+        type               : 'textarea'
+      subscription_id      :
+        label              : 'Subscription ID'
+        placeholder        : 'subscription id of azure account'
+      location             :
+        label              : 'Location'
+        type               : 'selection'
+        placeholder        : 'location / region'
+        defaultValue       : 'East US 2'
+        values             : [
+          { title: 'West US 2 (west-us-2)',             value: 'West US 2' }
+          { title: 'West Central US (west-central-us)', value: 'West Central US' }
+          { title: 'Quebec City (canada-east)',         value: 'Canada East' }
+          { title: 'Sao Paulo State (brazil-south)',    value: 'Brazil South' }
+          { title: 'Tokyo, Saitama (japan-east)',       value: 'Japan East' }
+          { title: 'Virginia (east-us)',                value: 'East US' }
+          { title: 'Virginia (east-us-2)',              value: 'East US 2' }
+          { title: 'Iowa (central-us)',                 value: 'Central US' }
+          { title: 'Illinois (north-central-us)',       value: 'North Central US' }
+          { title: 'Texas (south-central-us)',          value: 'South Central US' }
+          { title: 'California (west-us)',              value: 'West US' }
+          { title: 'Virginia (us-gov-virginia)',        value: 'US Gov Virginia' }
+          { title: 'Iowa (us-gov-iowa)',                value: 'US Gov Iowa' }
+          { title: 'Toronto (canada-central)',          value: 'Canada Central' }
+          { title: 'Arizona (us-gov-arizona)',          value: 'US Gov Arizona' }
+          { title: 'Texas (us-gov-texas)',              value: 'US Gov Texas' }
+          { title: 'Ireland (north-europe)',            value: 'North Europe' }
+          { title: 'Netherlands (west-europe)',         value: 'West Europe' }
+          { title: 'Frankfurt (germany-central)',       value: 'Germany Central' }
+          { title: 'Magdeburg (germany-northeast)',     value: 'Germany Northeast' }
+          { title: 'Cardiff (uk-west)',                 value: 'UK West' }
+          { title: 'London (uk-south-)',                value: 'UK South ' }
+          { title: 'Singapore (southeast-asia)',        value: 'Southeast Asia' }
+          { title: 'Kong (east-asia-hong)',             value: 'East Asia Hong' }
+          { title: 'New South, Wales (australia-east)', value: 'Australia East' }
+          { title: 'Victoria (australia-southeast)',    value: 'Australia Southeast' }
+          { title: 'Pune (central-india)',              value: 'Central India' }
+          { title: 'Mumbai (west-india)',               value: 'West India' }
+          { title: 'Chennai (south-india)',             value: 'South India' }
+          { title: 'Osaka (japan-west)',                value: 'Japan West' }
+          { title: 'Shanghai (china-east)',             value: 'China East' }
+          { title: 'Beijing (china-north)',             value: 'China North' }
+          { title: 'Seoul (korea-central)',             value: 'Korea Central' }
+        ]
+      storage              :
+        label              : 'Storage Replication'
+        type               : 'selection'
+        placeholder        : 'storage replication type'
+        defaultValue       : 'Standard_LRS'
+        values             : [
+          { title: 'Locally redundant storage (LRS)',            value: 'Standard_LRS' }
+          { title: 'Zone-redundant storage (ZRS)',               value: 'Standard_ZRS' }
+          { title: 'Geo-redundant storage (GRS)',                value: 'Standard_GRS' }
+          { title: 'Read-access geo-redundant storage (RA-GRS)', value: 'Standard_RAGRS' }
+          { title: 'Premium Locally redundant storage (P_LRS)',  value: 'Premium_LRS' }
+        ]

   rackspace                :
     name                   : 'Rackspace'


legal: add styled lists to user policy

legal: add styled lists to user policy

--- client/legal/lib/userpolicyview.coffee
+++ client/legal/lib/userpolicyview.coffee
@@ -10,7 +10,7 @@
   pistachio : ->
     """

-
(last modified on July 21th, 2014)

+
(last modified on May 5th, 2015)

         Your use of Koding (the “Service”) is subject to the following
@@ -30,7 +30,7 @@
         types of content:

-

+

           Content that infringes a third party’s rights (e.g., copyright)
           according to applicable law;
@@ -123,12 +123,12 @@
         End Users, to:

-

+

           Generate or facilitate unsolicited commercial email (“spam”).
           Such activity includes, but is not limited to:

-

+

               sending email in violation of the CAN-SPAM Act or any other
               applicable anti-spam law
@@ -255,21 +255,27 @@
         accounts that generate sustained high levels of load or use provided
         resources in a way that deteriorates the experience for other users.

-
Disk: 3GB per VM (or what your paid account comes with)

-
Ram: 1GB per VM

-
Network output: 7GB/week (free accounts), 14GB/week (paid accounts)

-

-
-      Koding reserves the right to suspend or terminate accounts found in violation of these items with or without prior notice given and without liability.
-

-      In addition, Koding reserves the right to terminate unused VMs after a period of inactivity (Usually 45-60 days). Inactive accounts will
-      be notified before any such action is taken.
-

-
-

-        (This document is an adaptation of the Google App Engine Program Policies
-        and the original work has been modified. Google, Inc. is not connected
-        with and does not sponsor or endorse Koding or its use of the work.)
+

+
Disk: 3GB per VM (or what your paid account comes with)

+
Ram: 1GB per VM

+
Network output: 7GB/week (free accounts), 14GB/week (paid accounts)

+

+

+
+      Koding reserves the right to suspend or terminate accounts found in
+      violation of these items with or without prior notice given and without
+      liability.
+

+        In addition, Koding reserves the right to terminate unused VMs after a
+        period of inactivity (Usually 45-60 days). Inactive accounts will be
+        notified before any such action is taken.
+

+
+

+        (This document is an adaptation of the Google App Engine Program
+        Policies and the original work has been modified. Google, Inc. is not
+        connected with and does not sponsor or endorse Koding or its use of the
+        work.)


Tests: Helpers: Move VMHeaderButton helper.

--- client/test/lib/helpers/helpers.coffee
+++ client/test/lib/helpers/helpers.coffee
@@ -245,15 +245,22 @@
     webPath       = '/home/' + user.username + '/' + folderName
     webSelector   = "span[title='" + webPath + "']"

+    @clickVMHeaderButton(browser)
+
+    browser
+      .click                   '.context-list-wrapper .refresh'
+      .waitForElementVisible   webSelector, 50000
+      .click                   webSelector
+      .click                   webSelector + ' + .chevron'
+
+
+  clickVMHeaderButton: (browser) ->
+
     browser
       .pause                   5000 # wait for filetree load
       .waitForElementVisible   '.vm-header', 50000
       .click                   '.vm-header .buttons'
       .waitForElementPresent   '.context-list-wrapper', 50000
-      .click                   '.context-list-wrapper .refresh'
-      .waitForElementVisible   webSelector, 50000
-      .click                   webSelector
-      .click                   webSelector + ' + .chevron'

   createFile: (browser, user, selector, folderName) ->


try relative pathnames for travis

try relative pathnames for travis

--- test/register-coffee-coverage.coffee
+++ test/register-coffee-coverage.coffee
@@ -1,6 +1,6 @@
 # register the coffee coverage function
 require('coffee-coverage').register {
-  path: 'abbr'
+  path: 'relative'
   basePath: require('path').join __dirname, '..'
   exclude: ['test', 'lib', 'dist', 'bin', 'node_modules', '.git']
   initAll: true


TAP5-2463: fix t5/core/dom:ResponseWrapper constructor

--- tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
+++ tapestry-core/src/main/preprocessed-coffeescript/org/apache/tapestry5/t5-core-dom.coffee
@@ -657,10 +657,10 @@

     constructor: (@jqxhr, data) ->

-      @status = jqxhr.status
-      @statusText = jqxhr.statusText
+      @status = @jqxhr.status
+      @statusText = @jqxhr.statusText
       @json = data # Mostly right?  Need a content type check?
-      @text = jqxhr.responseText
+      @text = @jqxhr.responseText

     # Retrieves a response header by name
     header: (name) ->


Sort class list by name

Sort class list by name

--- src/generator.coffee
+++ src/generator.coffee
@@ -333,7 +333,7 @@

     @templater.render 'class_list', {
       path: ''
-      classes: classes
+      classes: _.sortBy classes, 'name'
     }, 'class_list.html'

     @templater.render 'mixin_list', {


following feed private content remove fix

--- workers/social/lib/social/models/graph/activity.coffee
+++ workers/social/lib/social/models/graph/activity.coffee
@@ -91,6 +91,7 @@
       @getCurrentGroup options.client, (err, currentGroup)=>
         requestOptions = @generateOptions options
         requestOptions.group = {groupName: currentGroup.slug, groupId: currentGroup._id}
+        requestOptions.client = options.client
         facet = @generateFacets options.facet
         timeQuery = @generateTimeQuery options.to
         query = QueryRegistry.activity.following facet, timeQuery, exemptClause


Mark dirty when updating webhook url. Fix for rapidpro/rapidpro/issues/110.

--- static/coffee/flows/controllers.coffee
+++ static/coffee/flows/controllers.coffee
@@ -683,6 +683,7 @@
     ruleset.webhook_action = $scope.ruleset.webhook_action
     ruleset.webhook = $scope.ruleset.webhook
     ruleset.operand = $scope.ruleset.operand
+    Flow.markDirty()
     $modalInstance.close ""

   $scope.cancel = ->


New default position for marble

New default position for marble

XXX: Marble is now positioned outside of the map

--- src/js/Marble.coffee
+++ src/js/Marble.coffee
@@ -1,14 +1,13 @@
 # This class manages the marble.
 class Marble
   # Creates a new marble
-  constructor: (@radius = 8) ->
-    [@x, @y, @z]             = [  25, 255, 200]
-    [@x_V, @y_V, @z_V]       = [   0,  -5,   0]
+  constructor: (@radius = 7) ->
+    [@x, @y, @z]             = [-5000, -5000, 0] # XXX: Hide marble outside of map
+    [@x_V, @y_V, @z_V]       = [0, 0, 0]

   setCoordinates: (x, y, z) ->
     throw new Error "Missing parameter" unless (x? and y? and z?)

-    [@x_old, @y_old, @z_old] = [@x, @y, @z]
     [@x, @y, @z] = [x, y, z]

   getCoordinates: -> [@x, @y, @z]


incrementing version

incrementing version

--- oriDomi.coffee
+++ oriDomi.coffee
@@ -3,7 +3,7 @@
 # #### by [Dan Motzenbecker](http://oxism.com)
 # Fold up the DOM like paper.

-# `0.1.4`
+# `0.1.5`

 # Copyright 2012, MIT License

@@ -956,7 +956,7 @@

   # Set a version flag for easy external retrieval.
-  @VERSION = '0.1.4'
+  @VERSION = '0.1.5'

   # External function to enable `devMode`.


added tests for mirror api and backend behavior

Signed-off-by: Dominik Richter <b7323add517e187efe0283b76511b7ed762bfe13@gmail.com>

--- test/spec/controllers/main.coffee
+++ test/spec/controllers/main.coffee
@@ -134,7 +134,7 @@
   it 'should have the default host pointing to <HOST>/api', () ->
     expect(scope.ponyExpressHost).toBe( window.location.host + "/api" )

-  ## Querying
+  ## Querying Nodes and Package

   it 'should paginate /nodes if it supports pagination', ()->
     paginateResponse @httpBackend, '/v1/nodes', allNodes1, () -> scope.fetchNodes()
@@ -286,3 +286,34 @@
     scope.updatePackageSelection()
     expect( scope.packages.length ).toBe( 1 )
     expect( scope.packages[0].name ).toBe( allPackages1[0].name )
+
+
+  ## Querying Mirrors
+
+  it 'should be able to [C]reate a new mirror', () ->
+    callResponse @httpBackend, '/v1/mirrors', 'POST', 201, allMirrors1[0], () -> scope.addMirror(allMirrors1[0])
+    expect(scope.mirrors[0]).toBe(allMirrors1[0])
+
+  it 'should [R]ead all mirrors the server has available', () ->
+    paginateResponse @httpBackend, '/v1/mirrors', allMirrors1, () -> scope.fetchMirrors()
+    expect(scope.mirrors.length).toBe(allMirrors1.length)
+
+  it 'should be able to [U]pdate an existing mirror', () ->
+    # TODO: maybe remove the creation and expect it to exist already
+    callResponse @httpBackend, '/v1/mirrors', 'POST', 201, allMirrors1[0], () -> scope.addMirror(allMirrors1[0])
+    expect(scope.mirrors[0]).toBe(allMirrors1[0])
+    # update the name of an existing mirror
+    mirrorUpdate = {
+        'name': 'Minus Monor'
+      }
+    updatedMirror = _.merge( allMirrors1[0], mirrorUpdate)
+    callResponse @httpBackend, '/v1/mirrors', 'PATCH', 200, allMirrors1[0], () -> scope.updateMirror(allMirrors1[0]['id'], mirrorUpdate)
+    expect(scope.mirrors[0]).toBe(updatedMirror)
+
+  it 'should be able to [D]elete an existing mirror', () ->
+    # TODO: maybe remove the creation and expect it to exist already
+    callResponse @httpBackend, '/v1/mirrors', 'POST', 201, allMirrors1[0], () -> scope.addMirror(allMirrors1[0])
+    expect(scope.mirrors[0]).toBe(allMirrors1[0])
+    # update the name of an existing mirror
+    callResponse @httpBackend, '/v1/mirrors', 'DELETE', 204, null, () -> scope.deleteMirror(allMirrors1[0]['id'])
+    expect(scope.mirrors.length).toBe(0)


detect preserve-3d support

detect preserve-3d support

--- oridomi.coffee
+++ oridomi.coffee
@@ -173,6 +173,13 @@
     supportWarning value
     break

+p3d = 'preserve-3d'
+if isSupported and css.transformStyle
+  testEl.style[css.transformStyle] = p3d
+  unless testEl.style[css.transformStyle] is p3d
+    isSupported = false
+    supportWarning p3d
+
 # CSS3 gradients are used for shading.
 # Testing for them is different because they are prefixed values, not properties.
 # This invokes an anonymous function to loop through vendor-prefixed linear-gradients.
@@ -268,7 +275,7 @@
   transform:      'translate3d(-9999px, 0, 0)'
   margin:         '0'
   padding:        '0'
-  transformStyle: 'preserve-3d'
+  transformStyle: p3d

 for k, v of {Left: '0% 50%', Right: '100% 50%', Top: '50% 0%', Bottom: '50% 100%'}
   addStyle elClasses['stage' + k], perspectiveOrigin: v
@@ -309,7 +316,7 @@
   position:           'relative'
   transitionProperty: css.transformProp
   transformOrigin:    'left'
-  transformStyle:     'preserve-3d'
+  transformStyle:     p3d
   backfaceVisibility: 'hidden'

 addStyle elClasses.panelH, transformOrigin: 'top'


removed showOnStart option

removed showOnStart option

--- oridomi.coffee
+++ oridomi.coffee
@@ -357,9 +357,6 @@
   # This option allows you to supply the name of a custom easing method defined in one
   # of your stylesheets. It defaults to a blank string which is interpreted as `ease`.
   easingMethod: ''
-  # To prevent a possible "flash of unstyled content" you can hide your target elements
-  # and pass this setting as `true` to show them immediately after initializing them with oriDomi.
-  showOnStart: false
   # Currently, Firefox doesn't handle edge anti-aliasing well and oriDomi edges look jagged.
   # This setting forces Firefox to smooth edges, but usually results in poor performance,
   # so it's not recommended for animation-heavy use of oriDomi until Firefox's transform performance improves.


Removed logging

Removed logging

--- test/tests/LayerStatesTest.coffee
+++ test/tests/LayerStatesTest.coffee
@@ -195,7 +195,6 @@

 			count = 0
 			ready = (animation, layer) ->
-				console.log count
 				if count == 4
 					done()
 					return


Remove package.coffee.

Remove package.coffee.

--- package.coffee
+++ package.coffee
@@ -1,40 +0,0 @@
-# npm install courier -g
-# courier
-
-name: "jumpstart"
-description: "Quickly build modules based on templates."
-keywords: []
-version: "0.0.1"
-author: "Meryn Stol <merynstol@gmail.com>"
-homepage: "https://github.com/stellarpad/jumpstart"
-repository:
-  type: "git"
-  url: "git://github.com:stellarpad/jumpstart.git"
-
-directories:
-  lib: "./lib"
-main: "lib/jumpstart.js"
-dependencies:
-  async: "0.2.x"
-  optimist: "0.3.x"
-  commander: "1.1.x"
-  ncp: "0.4.x"
-  "recursive-readdir": "0.0.1",
-  "easy-table": "0.2.x"
-  "fs.extra": "1.2.x"
-
-devDependencies:
-  "coffee-script": "1.6.x"
-optionalDependencies: {}
-
-engines:
-  node: "0.10.x"
-  npm: "1.2.x"
-
-bin:
-  jumpstart: "./bin/jumpstart"
-
-scripts:
-  prepublish: "npm test"
-  pretest: "make build"
-  test: "make test"


Reintroduce 2c7bebb5f2c873850c2b2d82013cab4eb3d4913c

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -436,15 +436,13 @@
         keyChar = "<" + keyChar + ">"

   if (isInsertMode() && KeyboardUtils.isEscape(event))
-    # Note that we can't programmatically blur out of Flash embeds from Javascript.
-    if (!isEmbed(event.srcElement))
+    if isEditable(event.srcElement) or isEmbed(event.srcElement)
       # Remove focus so the user can't just get himself back into insert mode by typing in the same input
       # box.
-      if (isEditable(event.srcElement))
-        event.srcElement.blur()
-      exitInsertMode()
-      DomUtils.suppressEvent event
-      KeydownEvents.push event
+      event.srcElement.blur()
+    exitInsertMode()
+    DomUtils.suppressEvent event
+    handledKeydownEvents.push event

   else if (findMode)
     if (KeyboardUtils.isEscape(event))


Ensure that slashes are grouped in pairs in order for find mode queries

This ensures that \\\r is interpreted as {escaped-\}{escaped-r} rather
than \{escaped-\}r.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -718,7 +718,8 @@
   # character. here we grep for the relevant escape sequences.
   findModeQuery.isRegex = settings.get 'regexFindMode'
   hasNoIgnoreCaseFlag = false
-  findModeQuery.parsedQuery = findModeQuery.rawQuery.replace /(\\{1,2})([rRI])/g, (match, slashes, flag) ->
+  findModeQuery.parsedQuery = findModeQuery.rawQuery.replace /(\\{1,2})([rRI]?)/g, (match, slashes, flag) ->
+    return match if flag == ""
     if slashes.length == 2
       # The escape code is double-escaped (ie. \\r rather than \r). Strip the extra slash.
       "\\#{flag}"


Avoid trapping non-tab keypresses in focusInput mode.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -314,6 +314,7 @@
       else unless event.keyCode == KeyboardUtils.keyCodes.shiftKey
         DomUtils.removeElement hintContainingDiv
         @remove()
+        return true

       false


Activate vomnibar in window.top; fix dropped line.

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -242,6 +242,7 @@
   if event.target == window
     # Settings may have changed since the frame last had focus.
     settings.load()
+    checkIfEnabledForUrl()
     # Don't register frameset containers; focusing them is no use.
     unless document.body?.tagName.toLowerCase() == "frameset"
       chrome.runtime.sendMessage handler: "frameFocused", frameId: frameId


improved test

improved test

--- example/neat-ui.coffee
+++ example/neat-ui.coffee
@@ -1,7 +1,7 @@
 React = require './react'
 document = require './dom'

-RadComponent = require './rad-component.cjsx'
+RadComponent = require './rad-component'

 React.renderComponent RadComponent(rad: 'mos def'),
 	document.getElementById 'container'


update to parse5@2.0.2

update to parse5@2.0.2


Clarify docs

Clarify docs

--- picksel.coffee
+++ picksel.coffee
@@ -139,6 +139,7 @@

     # On success.
     if isSuccessful error, body
+
       # Get URL of image at correct resolution.
       url = body.hits[0][resolutions[resolution]]

@@ -281,9 +282,10 @@

 # Walks the user through initializing their user file.
+#
 auth = () ->

-  # Check we're not going to overwrite an existing project file.
+  # Check we're not going to overwrite an existing user file.
   if existsFile.sync userPath
     log.warning 'Looks like authentication is already set up for this project.'
     return false


Improve guarding for chartClickEvent

Improve guarding for chartClickEvent

- prevent reset zoom button firing event.
- prevent empty values from out of range chart selections being
passed to createKpi method.

--- src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee
+++ src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee
@@ -167,8 +167,12 @@
   chartClickEvent = (event)->
     # Currently only one kpi per widget is supported in the front-end
     return if w.kpis && w.kpis.length > 0
-    selectedValue = event.yAxis[0].value.toFixed(2)
-    $scope.settingAttachKpiApi.createKpi(selectedValue)
+    # Check whether click event fired is from the 'reset zoom' button
+    return if event.srcElement.textContent == 'Reset zoom'
+    value = event.yAxis[0].value
+    # Gaurd for click events fired outside of the yAxis values range
+    if !value || _.isNaN(value) then return else value = value.toFixed(2)
+    $scope.settingAttachKpiApi.createKpi(value)

   # TODO: move to helper method for reusability across widgets
   getThresholdTarget = ->


move translate section up above the w.format method

--- src/components/widgets/accounts-profit-and-loss/accounts-profit-and-loss.directive.coffee
+++ src/components/widgets/accounts-profit-and-loss/accounts-profit-and-loss.directive.coffee
@@ -191,6 +191,13 @@
   # Chart formating function
   # --------------------------------------
   $scope.drawTrigger = $q.defer()
+
+  periodName = if ($scope.widget.metadata.hist_parameters && $scope.widget.metadata.hist_parameters.period) then $scope.widget.metadata.hist_parameters.period.toLowerCase() else 'monthly'
+  $translate('impac.widget.settings.time_period.period.' + periodName).then(
+    (translation) ->
+      $scope.period_translation = _.capitalize(translation.toLowerCase())
+  )
+
   w.format = ->
     if $scope.isDataFound && $scope.selectedElements? && $scope.selectedElements.length > 0
       all_values_are_positive = true
@@ -252,13 +259,6 @@
   # Widget is ready: can trigger the "wait for settigns to be ready"
   # --------------------------------------
   $scope.widgetDeferred.resolve(settingsPromises)
-
-  periodName = if ($scope.widget.metadata.hist_parameters && $scope.widget.metadata.hist_parameters.period) then $scope.widget.metadata.hist_parameters.period.toLowerCase() else 'monthly'
-  $translate('impac.widget.settings.time_period.period.' + periodName).then(
-    (translation) ->
-      $scope.period_translation = _.capitalize(translation.toLowerCase())
-  )
-
 )

 module.directive('widgetAccountsProfitAndLoss', ->


Using elapsed time in delayed events

Using elapsed time in delayed events

--- src/timed_events.coffee
+++ src/timed_events.coffee
@@ -23,7 +23,7 @@
       (event.delay -= elapsedTime) >= 0

     firingEvents.each (event) ->
-      self.sendOrApply event.fn()
+      self.sendOrApply(event.fn)

   ###*
   Execute fn every n frames.


Maybe fix webdev in BR

Maybe fix webdev in BR

--- server_setup.coffee
+++ server_setup.coffee
@@ -191,9 +191,9 @@

 exports.setupMiddleware = (app) ->
   setupPerfMonMiddleware app
+  setupDomainFilterMiddleware app
   setupCountryRedirectMiddleware app, "china", "CN", "zh", config.chinaDomain
   setupCountryRedirectMiddleware app, "brazil", "BR", "pt-BR", config.brazilDomain
-  setupDomainFilterMiddleware app
   setupMiddlewareToSendOldBrowserWarningWhenPlayersViewLevelDirectly app
   setupExpressMiddleware app
   setupPassportMiddleware app


atom parinfer

atom parinfer

--- files/atom/config.cson
+++ files/atom/config.cson
@@ -2,7 +2,19 @@
   "atom-beautify":
     general:
       _analyticsUserId: "ca3b458a-9279-4470-91ff-ab6f2bfeba74"
-  "bracket-matcher": {}
+  "autocomplete-plus":
+    enableAutoActivation: false
+  "bracket-matcher":
+    autocompleteCharacters: [
+      "()"
+      "[]"
+      "{}"
+      "\"\""
+      "“”"
+      "‘’"
+      "«»"
+      "‹›"
+    ]
   core:
     customFileTypes:
       "source.ini": [
@@ -20,45 +32,56 @@
     disabledPackages: [
       "deprecation-cop"
     ]
-    openEmptyEditorOnStart: false
+    openEmptyEditorOnStart: true
+    packagesWithKeymapsDisabled: []
     telemetryConsent: "no"
   editor:
+    autoIndentOnPaste: false
     fontFamily: "Source Code Pro"
     invisibles: {}
     preferredLineLength: 90
     scrollPastEnd: true
   "exception-reporting":
     userId: "0dacece5-6c28-aa5c-7949-423cff26188c"
-  nuclide:
-    installRecommendedPackages: true
-    "nuclide-code-format": {}
-    "nuclide-datatip": {}
-    "nuclide-distraction-free-mode": {}
-    "nuclide-file-tree":
-      showOpenFiles: false
-      showUncommittedChanges: false
-    "nuclide-flow": {}
-    "nuclide-format-js": {}
-    "nuclide-health": {}
-    "nuclide-home":
-      showHome: false
-    "nuclide-working-sets": {}
-    use:
-      "nuclide-adb-logcat": false
-      "nuclide-arcanist": false
-      "nuclide-buck": false
-      "nuclide-clang": false
-      "nuclide-debugger": false
-      "nuclide-hg-conflict-resolver": false
-      "nuclide-hg-repository": false
-      "nuclide-ios-simulator-logs": false
-      "nuclide-objc": false
-      "nuclide-ocaml": false
-      "nuclide-remote-atom": false
-      "nuclide-remote-projects": false
-      "nuclide-swift": false
-      "nuclide-working-sets": false
+  "lisp-paredit":
+    indentationForms: [
+      "try"
+      "catch"
+      "finally"
+      "/^let/"
+      "are"
+      "/^def/"
+      "fn"
+      "cond"
+      "condp"
+      "/^if.*/"
+      "/.*\\/for/"
+      "for"
+      "for-all"
+      "/^when.*/"
+      "testing"
+      "doseq"
+      "dotimes"
+      "ns"
+      "routes"
+      "GET"
+      "POST"
+      "PUT"
+      "DELETE"
+      "extend-protocol"
+      "loop"
+      "do"
+      "case"
+      "with-bindings"
+      "checking"
+      "with-open"
+    ]
+    strict: false
   "one-dark-ui": {}
+  "proto-repl":
+    autoPrettyPrint: true
+    bootPath: "/usr/local/bin/boot"
+    leinPath: "/usr/local/bin/lein"
   "terminal-plus":
     core: {}
   "tree-view":
@@ -73,6 +96,11 @@
     scrollPastEnd: false
     softWrap: false
     softWrapAtPreferredLineLength: false
+".clojure.source":
+  editor:
+    autoIndent: false
+    autoIndentOnPaste: false
+    nonWordCharacters: "()\"':,;~@#$%^&{}[]`"
 ".hack.html.text":
   editor:
     preferredLineLength: 9


Restore PaneView::getContainer. Turns out it's actually public.

--- src/pane-view.coffee
+++ src/pane-view.coffee
@@ -195,6 +195,10 @@

   splitDown: (items...) -> @model.splitDown({items})._view

+  # Public:
+  getContainer: ->
+    @closest('.panes').view()
+
   beforeRemove: ->
     @model.destroy() unless @model.isDestroyed()


Remove color, is defined in parent as alias already

--- framer/SVGGroup.coffee
+++ framer/SVGGroup.coffee
@@ -56,7 +56,6 @@
 	@defineGroupProxyProp "stroke"
 	@defineGroupProxyProp "strokeWidth", _.isNumber, parseInt
 	@defineGroupProxyProp "strokeWidthMultiplier", _.isNumber, parseInt
-	@defineGroupProxyProp "color", Color.validColorValue, Color.toColor
 	# coffeelint: disable=prefer_english_operator
 	@defineGroupProxyProp "ignoreEvents", _.isBoolean, (value) -> !!value
 	# coffeelint: enable=prefer_english_operator


testing retrieve

testing retrieve

--- src/quad_tree.coffee
+++ src/quad_tree.coffee
@@ -16,6 +16,7 @@

       self =
         I: I
+        root: -> root

         clear: -> root.clear()

@@ -68,6 +69,8 @@
         return index

       self =
+        I: I
+
         clear: ->
           I.children.clear()

@@ -84,6 +87,7 @@
           I.children.push(item)

           if (I.depth >= I.maxDepth) && (I.children.length > I.maxChildren)
+            log "got here"
             self.subdivide()

             I.children.each (child) ->


Fix word separation in Atom

Fix word separation in Atom

--- atom.cson
+++ atom.cson
@@ -6,7 +6,7 @@
     softWrap: true
     invisibles: {}
     zoomFontWhenCtrlScrolling: false
-    nonWordCharacters: "^*\"`'/|\\?!;:,.%#@(){}[]<>=+~_"
+    nonWordCharacters: "^*\"`'/|\\?!;:,.%#@(){}[]<>=+-~_"
   core:
     disabledPackages: [
       "language-objective-c"


debug

debug

--- JSKit/04_JSMenuView.coffee
+++ JSKit/04_JSMenuView.coffee
@@ -7,7 +7,7 @@
     constructor:(frame = JSRectMake(0, 0, 200, 0))->
         super(frame)
         @_textSize = 10
-        @_backgroundColor = JSColor("clearColor")
+        @_bgColor = JSColor("clearColor")
         @_clipToBounds = false
         @_containment = false


:memo: Add docs for current public methods

--- src/react-editor-view.coffee
+++ src/react-editor-view.coffee
@@ -4,7 +4,33 @@
 TextBuffer = require 'text-buffer'
 Editor = require './editor'
 EditorComponent = require './editor-component'
-
+{deprecate} = require 'grim'
+
+# Public: Represents the entire visual pane in Atom.
+#
+# The EditorView manages the {Editor}, which manages the file buffers.
+#
+# ## Requiring in packages
+#
+# ```coffee
+# {EditorView} = require 'atom'
+#
+# miniEditorView = new EditorView(mini: true)
+# ```
+#
+# ## Iterating over the open editor views
+#
+# ```coffee
+# for editorView in atom.workspaceView.getEditorViews()
+#   console.log(editorView.getModel().getPath())
+# ```
+#
+# ## Subscribing to every current and future editor
+#
+# ```coffee
+# atom.workspace.eachEditorView (editorView) ->
+#   console.log(editorView.getModel().getPath())
+# ```
 module.exports =
 class EditorView extends View
   @configDefaults:
@@ -33,6 +59,13 @@

   focusOnAttach: false

+  # The constructor for setting up an `EditorView` instance.
+  #
+  # editorOrParams - Either an {Editor}, or an object with one property, `mini`.
+  #                  If `mini` is `true`, a "miniature" `Editor` is constructed.
+  #                  Typically, this is ideal for scenarios where you need an Atom editor,
+  #                  but without all the chrome, like scrollbars, gutter, _e.t.c._.
+  #
   constructor: (editorOrParams, props) ->
     super

@@ -81,8 +114,13 @@
       else
         @focusOnAttach = true

-  getEditor: -> @editor
-
+  getEditor: ->
+    deprecate("Use EditorView::getModel instead")
+    @editor
+
+  # Public: Get the underlying editor model for this view.
+  #
+  # Returns an {Editor}.
   getModel: -> @editor

   Object.defineProperty @::, 'lineHeight', get: -> @editor.getLineHeightInPixels()
@@ -122,12 +160,23 @@
     else
       @editor.getScrollLeft()

+  # Public: Scrolls the editor to the bottom.
   scrollToBottom: ->
     @editor.setScrollBottom(Infinity)

+  # Public: Scrolls the editor to the given screen position.
+  #
+  # screenPosition - An object that represents a buffer position. It can be either
+  #                  an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
+  # options - A hash matching the options available to {::scrollToScreenPosition}
   scrollToScreenPosition: (screenPosition, options) ->
     @editor.scrollToScreenPosition(screenPosition, options)

+  # Public: Scrolls the editor to the given buffer position.
+  #
+  # bufferPosition - An object that represents a buffer position. It can be either
+  #                  an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
+  # options - A hash matching the options available to {::scrollToBufferPosition}
   scrollToBufferPosition: (bufferPosition, options) ->
     @editor.scrollToBufferPosition(bufferPosition, options)

@@ -138,9 +187,21 @@
     screenPosition = screenPositionForPixelPosition(pixelPosition)
     @editor.scrollToScreenPosition(screenPosition)

+  # Public: Converts a buffer position to a pixel position.
+  #
+  # position - An object that represents a buffer position. It can be either
+  #            an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
+  #
+  # Returns an object with two values: `top` and `left`, representing the pixel positions.
   pixelPositionForBufferPosition: (bufferPosition) ->
     @editor.pixelPositionForBufferPosition(bufferPosition)

+  # Public: Converts a screen position to a pixel position.
+  #
+  # position - An object that represents a screen position. It can be either
+  #            an {Object} (`{row, column}`), {Array} (`[row, column]`), or {Point}
+  #
+  # Returns an object with two values: `top` and `left`, representing the pixel positions.
   pixelPositionForScreenPosition: (screenPosition) ->
     @editor.pixelPositionForScreenPosition(screenPosition)

@@ -175,6 +236,9 @@
     pane = @getPane()
     pane?.splitDown(pane?.copyActiveItem()).activeView

+  # Public: Get this view's pane.
+  #
+  # Returns a {Pane}.
   getPane: ->
     @parent('.item-views').parents('.pane').view()

@@ -199,36 +263,72 @@
   pageUp: ->
     @editor.pageUp()

+  # Public: Retrieves the number of the row that is visible and currently at the
+  # top of the editor.
+  #
+  # Returns a {Number}.
   getFirstVisibleScreenRow: ->
     @editor.getVisibleRowRange()[0]

+  # Public: Retrieves the number of the row that is visible and currently at the
+  # bottom of the editor.
+  #
+  # Returns a {Number}.
   getLastVisibleScreenRow: ->
     @editor.getVisibleRowRange()[1]

+  # Public: Gets the font family for the editor.
+  #
+  # Returns a {String} identifying the CSS `font-family`.
   getFontFamily: ->
     @component?.getFontFamily()

+  # Public: Sets the font family for the editor.
+  #
+  # fontFamily - A {String} identifying the CSS `font-family`.
   setFontFamily: (fontFamily) ->
     @component?.setFontFamily(fontFamily)

+  # Public: Retrieves the font size for the editor.
+  #
+  # Returns a {Number} indicating the font size in pixels.
   getFontSize: ->
     @component?.getFontSize()

+  # Public: Sets the font size for the editor.
+  #
+  # fontSize - A {Number} indicating the font size in pixels.
   setFontSize: (fontSize) ->
     @component?.setFontSize(fontSize)

   setWidthInChars: (widthInChars) ->
     @component.getDOMNode().style.width = (@editor.getDefaultCharWidth() * widthInChars) + 'px'

+  # Public: Sets the line height of the editor.
+  #
+  # Calling this method has no effect when called on a mini editor.
+  #
+  # lineHeight - A {Number} without a unit suffix identifying the CSS
+  # `line-height`.
   setLineHeight: (lineHeight) ->
     @component.setLineHeight(lineHeight)

+  # Public: Sets whether you want to show the indentation guides.
+  #
+  # showIndentGuide - A {Boolean} you can set to `true` if you want to see the
+  #                   indentation guides.
   setShowIndentGuide: (showIndentGuide) ->
     @component.setShowIndentGuide(showIndentGuide)

+  # Public: Enables/disables soft wrap on the editor.
+  #
+  # softWrap - A {Boolean} which, if `true`, enables soft wrap
   setSoftWrap: (softWrap) ->
     @editor.setSoftWrap(softWrap)

+  # Public: Set whether invisible characters are shown.
+  #
+  # showInvisibles - A {Boolean} which, if `true`, show invisible characters.
   setShowInvisibles: (showInvisibles) ->
     @component.setShowInvisibles(showInvisibles)

@@ -261,6 +361,11 @@

   redraw: ->               # No-op shim

+  # Public: Set the text to appear in the editor when it is empty.
+  #
+  # This only affects mini editors.
+  #
+  # placeholderText - A {String} of text to display when empty.
   setPlaceholderText: (placeholderText) ->
     if @component?
       @component.setProps({placeholderText})


Deprecate no-op’d things

Deprecate no-op’d things

--- src/react-editor-view.coffee
+++ src/react-editor-view.coffee
@@ -345,13 +345,17 @@
   setInputEnabled: (inputEnabled) ->
     @component.setInputEnabled(inputEnabled)

-  requestDisplayUpdate: -> # No-op shim for find-and-replace
-
-  updateDisplay: ->        # No-op shim for package specs
-
-  resetDisplay: ->         # No-op shim for package specs
-
-  redraw: ->               # No-op shim
+  requestDisplayUpdate: ->
+    deprecate('Please remove from your code. ::requestDisplayUpdate no longer does anything')
+
+  updateDisplay: ->
+    deprecate('Please remove from your code. ::updateDisplay no longer does anything')
+
+  resetDisplay: ->
+    deprecate('Please remove from your code. ::resetDisplay no longer does anything')
+
+  redraw: ->
+    deprecate('Please remove from your code. ::redraw no longer does anything')

   # Public: Set the text to appear in the editor when it is empty.
   #


removed one more debug statement from spec.

--- spec/IntegrationSpec.coffee
+++ spec/IntegrationSpec.coffee
@@ -52,8 +52,6 @@
     """

   it "loads site.js from another server", (done) ->
-    console.log "running spec"
-
     widget = new TestWidget(el: $j(".epages-shop-widget:first"))

     widgetLoaded = ->


[Server][keyboard_control] fix jumping after last page and before first page

--- lib/Epuber/server/keyboard_control.coffee
+++ lib/Epuber/server/keyboard_control.coffee
@@ -1,3 +1,6 @@

-key 'right', -> window.location.assign('/toc/' + $next_path)
-key 'left',  -> window.location.assign('/toc/' + $previous_path)
+goToPage = (path) ->
+    window.location.assign('/toc/' + path) if path?
+
+key 'right', -> goToPage($next_path)
+key 'left',  -> goToPage($previous_path)


Refactor logical operator tests to use array.

--- spec/powershell-spec.coffee
+++ spec/powershell-spec.coffee
@@ -119,27 +119,13 @@
         it "should highlight 'for'", ->
           expect(tokens[0]).toEqual value: "for", scopes: ["source.powershell","keyword.control.flow.powershell"]

-    describe "Logical operators", ->
-      tokens = null
+    describe "Highlighting logical operators", ->
+      logicalOperators = [ "-and", "-or", "-xor", "-not", "!"]

-      beforeEach ->
-        {tokens} = grammar.tokenizeLine("-and -andor -or -xor -not !$true")
-
-      it "should highlight '-and'", ->
-        expect(tokens[0]).toEqual value: "-and", scopes: ["source.powershell","keyword.operator.logical.powershell"]
-        expect(tokens[2]).toEqual value: "-", scopes: ["source.powershell","keyword.operator.arithmetic.powershell"]
-
-      it "should highlight '-or'", ->
-        expect(tokens[5]).toEqual value: "-or", scopes: ["source.powershell","keyword.operator.logical.powershell"]
-
-      it "should highlight '-xor'", ->
-        expect(tokens[7]).toEqual value: "-xor", scopes: ["source.powershell","keyword.operator.logical.powershell"]
-
-      it "should highlight '-not'", ->
-        expect(tokens[9]).toEqual value: "-not", scopes: ["source.powershell","keyword.operator.logical.powershell"]
-
-      it "should highlight '!'", ->
-        expect(tokens[11]).toEqual value: "!", scopes: ["source.powershell","keyword.operator.logical.powershell"]
+      it "tokenizes logical operators", ->
+        for operator in logicalOperators
+          {tokens} = grammar.tokenizeLine operator
+          expect(tokens[0]).toEqual value: operator, scopes: ["source.powershell","keyword.operator.logical.powershell"]

   describe "Highlighting automatic variables", ->
     automaticVariables = [


removed a log

removed a log

--- lib/assets/javascripts/ajaxspin.js.coffee
+++ lib/assets/javascripts/ajaxspin.js.coffee
@@ -13,7 +13,6 @@
     element.spin false if count == 0

   @each ->
-    console.log($(this))
     $e = $(this)
     $(document).on opts.showEvents, (event) ->
       loadState $e, event


Test incorrect email too.

Test incorrect email too.

--- test/integration/password_reset.coffee
+++ test/integration/password_reset.coffee
@@ -65,6 +65,18 @@
         it 'it shows me that the username was wrong', (done) ->
           wd40.waitForText 'That username could not be found', done

+      context 'when I enter an incorrect email address', ->
+        before (done) ->
+          browser.get "#{base_url}/set-password/", ->
+            browser.waitForElementByCss '#query', 4000, done
+
+        before (done) ->
+          wd40.fill '#query', 'bademail@example.com', ->
+            wd40.click '#go', done
+
+        it 'it shows me that the username was wrong', (done) ->
+          wd40.waitForText 'That username could not be found', done
+
       context 'when I cause some sort of weird error', ->
         before (done) ->
           browser.get "#{base_url}/set-password/", ->


indentation fixez

indentation fixez

--- client/Social/Activity/views/inputwidget.coffee
+++ client/Social/Activity/views/inputwidget.coffee
@@ -49,9 +49,6 @@
     createdTags    = {}
     feedType       = ""
     { app }        = @getOptions()
-
-
-

     for token in @input.getTokens()
       {data, type} = token


activity: define `MessagePane::appendMessage` method

--- client/Social/Activity/views/messagepane.coffee
+++ client/Social/Activity/views/messagepane.coffee
@@ -34,6 +34,11 @@
   removeMessage: (message) ->

     @listController.removeItem message
+
+
+  appendMessage: (message) ->
+
+    @listController.addItem message, @listController.getItemCount()

   viewAppended: ->


Client: Activity: added  default limit option

--- client/activity/lib/flux/actions/channel.coffee
+++ client/activity/lib/flux/actions/channel.coffee
@@ -99,6 +99,8 @@
 ###
 loadFollowedPrivateChannels = (options = {}) ->

+  options.limit ?= 25
+
   { LOAD_FOLLOWED_PRIVATE_CHANNELS_BEGIN
     LOAD_FOLLOWED_PRIVATE_CHANNELS_FAIL
     LOAD_FOLLOWED_PRIVATE_CHANNEL_SUCCESS } = actionTypes
@@ -122,6 +124,8 @@
  * @param {object=} options
 ###
 loadFollowedPublicChannels = (options = {}) ->
+
+  options.limit ?= 25

   { LOAD_FOLLOWED_PUBLIC_CHANNELS_BEGIN
     LOAD_FOLLOWED_PUBLIC_CHANNELS_FAIL


Client: Activity: Increased threshold defaultProps of waypoint

--- client/app/lib/components/scroller/index.coffee
+++ client/app/lib/components/scroller/index.coffee
@@ -6,7 +6,7 @@

   @defaultProps =
     hasMore               : no
-    threshold             : 0.1
+    threshold             : 1
     onThresholdReached    : kd.noop
     onTopThresholdReached : kd.noop


[pagerduty] cleanup

[pagerduty] cleanup

--- src/scripts/pagerduty.coffee
+++ src/scripts/pagerduty.coffee
@@ -198,7 +198,6 @@

   withPagerDutyUser = (msg, cb) ->
-
     email  = msg.message.user.pagerdutyEmail || msg.message.user.email_address
     unless email
       msg.send "Sorry, I can't figure out your email address :( Can you tell me with `#{robot.name} pager me as you@yourdomain.com`?"
@@ -409,47 +408,50 @@

   generateIncidentString = (incident, hookType) ->
     console.log "hookType is " + hookType
+    assigned_user   = getUserForIncident(incident)
+    incident_number = incident.incident_number
+
     if hookType == "incident.trigger"
       """
-      Incident # #{incident.incident_number} :
-      #{incident.status} and assigned to #{getUserForIncident(incident)}
-       #{incident.html_url}
-      To acknowledge: @#{robot.name} pager me ack #{incident.incident_number}
-       To resolve: @#{robot.name} pager me resolve #{incident.incident_number}
+      Incident # #{incident_number} :
+      #{incident.status} and assigned to #{assigned_user}
+       #{incident.html_url}
+      To acknowledge: @#{robot.name} pager me ack #{incident_number}
+      To resolve: @#{robot.name} pager me resolve #{}
       """
     else if hookType == "incident.acknowledge"
       """
-      Incident # #{incident.incident_number} :
-      #{incident.status} and assigned to #{getUserForIncident(incident)}
-       #{incident.html_url}
-      To resolve: @#{robot.name} pager me resolve #{incident.incident_number}
+      Incident # #{incident_number} :
+      #{incident.status} and assigned to #{assigned_user}
+       #{incident.html_url}
+      To resolve: @#{robot.name} pager me resolve #{incident_number}
       """
     else if hookType == "incident.resolve"
       """
-      Incident # #{incident.incident_number} has been resolved by #{getUserForIncident(incident)}
+      Incident # #{incident_number} has been resolved by #{assigned_user}
        #{incident.html_url}
       """
     else if hookType == "incident.unacknowledge"
       """
-      #{incident.status} , unacknowledged and assigned to #{getUserForIncident(incident)}
-       #{incident.html_url}
-      To acknowledge: @#{robot.name} pager me ack #{incident.incident_number}
-       To resolve: @#{robot.name} pager me resolve #{incident.incident_number}
+      #{incident.status} , unacknowledged and assigned to #{assigned_user}
+       #{incident.html_url}
+      To acknowledge: @#{robot.name} pager me ack #{incident_number}
+       To resolve: @#{robot.name} pager me resolve #{incident_number}
       """
     else if hookType == "incident.assign"
       """
-      Incident # #{incident.incident_number} :
-      #{incident.status} , reassigned to #{getUserForIncident(incident)}
-       #{incident.html_url}
-      To resolve: @#{robot.name} pager me resolve #{incident.incident_number}
+      Incident # #{incident_number} :
+      #{incident.status} , reassigned to #{assigned_user}
+       #{incident.html_url}
+      To resolve: @#{robot.name} pager me resolve #{incident_number}
       """
     else if hookType == "incident.escalate"
       """
-      Incident # #{incident.incident_number} :
-      #{incident.status} , was escalated and assigned to #{getUserForIncident(incident)}
-       #{incident.html_url}
-      To acknowledge: @#{robot.name} pager me ack #{incident.incident_number}
-       To resolve: @#{robot.name} pager me resolve #{incident.incident_number}
+      Incident # #{incident_number} :
+      #{incident.status} , was escalated and assigned to #{assigned_user}
+       #{incident.html_url}
+      To acknowledge: @#{robot.name} pager me ack #{incident_number}
+      To resolve: @#{robot.name} pager me resolve #{incident_number}
       """

   parseIncidents = (messages) ->


isLoading is in adapter now

isLoading is in adapter now

--- src/scripts/ui-scroll.coffee
+++ src/scripts/ui-scroll.coffee
@@ -64,6 +64,7 @@
 							throw new Error "#{datasourceName} is not a valid datasource" unless isDatasource datasource

 						adapterAttr = getValueChain($scope, $attr.adapter, true) if $attr.adapter
+						isLoadingAttr = getValueChain($scope, $attr.isLoading, true) if $attr.isLoading

 						bufferSize = Math.max(3, +$attr.bufferSize || 10)
 						bufferPadding = -> viewport.outerHeight() * Math.max(0.1, +$attr.padding || 0.1) # some extra space to initate preload
@@ -72,7 +73,6 @@
 							elem[0].scrollHeight ? elem[0].document.documentElement.scrollHeight

 						builder = null
-						adapter = {}

 						# Calling linker is the only way I found to get access to the tag name of the template
 						# to prevent the directive scope from pollution a new scope is created and destroyed
@@ -143,13 +143,10 @@
 							topVisibleScope(item.scope) if topVisibleScope
 							datasource.topVisible(item) if datasource.topVisible

-						if angular.isDefined ($attr.isLoading)
-							loading = (value) ->
-								viewportScope[$attr.isLoading] = value
-								datasource.loading(value) if datasource.loading
-						else
-							loading = (value) ->
-								datasource.loading(value) if datasource.loading
+						loading = (value) ->
+							adapter.isLoading = value
+							isLoadingAttr = value if $attr.isLoading
+							datasource.loading(value) if typeof datasource.loading is 'function'

 						ridActual = 0
 						first = 1
@@ -158,7 +155,6 @@
 						pending = []
 						eof = false
 						bof = false
-						isLoading = false

 						#removes items from start (including) through stop (excluding)
 						removeFromBuffer = (start, stop)->
@@ -239,8 +235,7 @@
 								#log "clipped off top #{overage} top padding #{builder.topPadding()}"

 						enqueueFetch = (rid, direction)->
-							if (!isLoading)
-								isLoading = true
+							if (!adapter.isLoading)
 								loading(true)
 							if pending.push(direction) == 1
 								fetch(rid)
@@ -308,7 +303,7 @@
 									rowTop = itemTop
 									itemHeight = item.element.outerHeight(true) if newRow
 									if newRow and (builder.topDataPos() + topHeight + itemHeight < topVisiblePos())
-											topHeight += itemHeight
+										topHeight += itemHeight
 									else
 										topVisible(item) if newRow
 										break
@@ -334,7 +329,6 @@
 							adjustBuffer rid, newItems, ->
 								pending.shift()
 								if pending.length == 0
-									isLoading = false
 									loading(false)
 								else
 									fetch(rid)
@@ -381,8 +375,11 @@
 											#log "prepended: requested #{bufferSize} received #{result.length} buffer size #{buffer.length} first #{first} next #{next}"
 										finalize(rid, newItems)

+
+						# events and bindings
+
 						resizeAndScrollHandler = ->
-							if !$rootScope.$$phase && !isLoading
+							if !$rootScope.$$phase && !adapter.isLoading
 								adjustBuffer()
 								$scope.$apply()

@@ -410,6 +407,11 @@
 							viewport.unbind 'resize', resizeAndScrollHandler
 							viewport.unbind 'scroll', resizeAndScrollHandler
 							viewport.unbind 'mousewheel', wheelHandler
+
+
+						# adapter initializing
+
+						adapter = {}

 						applyUpdate = (wrapper, newItems) ->
 							inserted = []
@@ -454,10 +456,14 @@
 									throw new Error "applyUpdates - #{arg1} is not a valid index or outside of range"
 							adjustBuffer(ridActual, inserted)

-						angular.extend(adapterAttr, adapter) if adapterAttr
-
-
-						# update events are deprecated since v1.1.0
+						adapter.isLoading = false
+
+						if $attr.adapter # so we have an adapter on $scope
+							angular.extend(adapterAttr, adapter)
+							adapter = adapterAttr
+
+
+						# update events (are deprecated since v1.1.0)

 						doUpdate = (locator, newItem) ->
 							if angular.isFunction locator


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/animated.coffee
+++ test/animated.coffee
@@ -427,70 +427,68 @@
   equals animation.I.activeAnimation.frames.first(), 20, "Animation should be on first frame after transition"

 test "should fire Complete event after updating past the last frame", ->
-  window.completeFired = false
+  completeFired = false

   animation = GameObject
     data: animationData
     includedModules: ["Animated"]

   animation.bind "Complete", ->
-    window.completeFired = true
+    completeFired = true

   animation.I.activeAnimation.frames.length.times ->
     animation.update()

-  ok window.completeFired, "Complete event fired"
+  ok completeFired, "Complete event fired"

 test "should advance to next state after last frame", ->
   animation = GameObject
     data: animationData
-
-  animation.include(Animated)
-
-  (animation.I.activeAnimation.frames.length).times ->
+    includedModules: ["Animated"]
+
+  animation.I.activeAnimation.frames.length.times ->
     animation.update()

-  equals animation.I.activeAnimation.name, "Idle1", "After the bite cycle, we should end up in the Idle1 state"
+  equals animation.I.activeAnimation.name, "Idle1", "After the bite cycle we should end up in the Idle1 state"

   50.times -> animation.update()

   equals animation.I.activeAnimation.name, "Idle1", "The idle1 state loops, so after any number of updates we should still be there"

 test "should fire frame specific event on the proper frame", ->
-  window.whiteParticlesFired = window.blueParticlesFired = greenParticlesFired = chompSoundFired = false
+  whiteParticlesFired = blueParticlesFired = greenParticlesFired = chompSoundFired = false

   animation = GameObject
     data: animationData
+    includedModules: ["Animated"]

   animation.bind "whiteParticles", ->
-    window.whiteParticlesFired = true
+    whiteParticlesFired = true

   animation.bind "blueParticles", ->
-    window.blueParticlesFired = true
+    blueParticlesFired = true

   animation.bind "greenParticles", ->
-    window.greenParticlesFired = true
+    greenParticlesFired = true

   animation.bind "chompSound", ->
-    window.chompSoundFired = true
-
-  animation.include(Animated)
-
-  animation.update()
-
-  ok window.whiteParticlesFired, "White particle effect fired"
-
-  animation.update()
-  animation.update()
-  animation.update()
-  animation.update()
-
-  ok window.blueParticlesFired, "Blue particle effect fired"
-  ok window.greenParticlesFired, "Green particle effect fired"
-
-  animation.update()
-
-  ok window.chompSoundFired, "Chomp sound effect fired"
+    chompSoundFired = true
+
+  animation.update()
+
+  ok whiteParticlesFired, "White particle effect fired"
+
+  animation.update()
+  animation.update()
+  animation.update()
+  animation.update()
+
+  ok blueParticlesFired, "Blue particle effect fired"
+  ok greenParticlesFired, "Green particle effect fired"
+
+  animation.update()
+
+  ok chompSoundFired, "Chomp sound effect fired"

 module()


Style matching on matcher.

Style matching on matcher.

--- app/assets/javascripts/drops_calculator/index.js.coffee
+++ app/assets/javascripts/drops_calculator/index.js.coffee
@@ -2,22 +2,16 @@
   return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")

 monsterMatcher = (strs) ->
-  return (q, cb) ->
-    # an array that will be populated with substring matches
+  (query, callback) ->
     matches = [];
+    substrRegex = new RegExp(escapeRegExp(query), 'i')

-    # regex used to determine if a string contains the substring `q`
-    substrRegex = new RegExp(escapeRegExp(q), 'i')
-
-    # iterate through the pool of strings and for any string that
-    # contains the substring `q`, add it to the `matches` array
     $.each(strs, (i, str) ->
       if (substrRegex.test(str['name']))
-        # the typeahead jQuery plugin expects suggestions to a
-        # JavaScript object, refer to typeahead docs for more info
         matches.push(str)
     )
-    cb(matches)
+
+    callback(matches)

 updateDropNumberInputs = (e) ->
   checked = $('.drop-group-boxes', e).is(':checked')


better syntax for #972

better syntax for #972

--- src/smc-webapp/editor.coffee
+++ src/smc-webapp/editor.coffee
@@ -1624,12 +1624,6 @@
                 evaluate_key = "Shift-Enter"
             extraKeys[evaluate_key] = (editor)   => @action_key(execute: true, advance:true, split:false)

-        # turn off autoCloseBrackets for haskell files SMC #972
-        if misc.filename_extension_notilde(filename) == "hs" || misc.filename_extension_notilde(filename) == "lhs"
-            acb = false
-        else
-            acb = opts.auto_close_brackets
-
         make_editor = (node) =>
             options =
                 firstLineNumber         : opts.first_line_number
@@ -1643,7 +1637,7 @@
                 electricChars           : opts.electric_chars
                 undoDepth               : opts.undo_depth
                 matchBrackets           : opts.match_brackets
-                autoCloseBrackets       : acb
+                autoCloseBrackets       : opts.auto_close_brackets and (misc.filename_extension_notilde(filename) not in ['hs', 'lhs']) #972
                 autoCloseTags           : opts.auto_close_xml_tags
                 lineWrapping            : opts.line_wrapping
                 readOnly                : opts.read_only


Change tooltip wording on files toolbar

Change tooltip wording on files toolbar

closes CNVS-24686

Test Plan:
  - Go to files
  - The tooltip in the toolbar for restricted access should say
    manage access instead

Change-Id: Ie6d304a08dfd83c1d911319d4822a3ea79abfef8
Reviewed-on: https://gerrit.instructure.com/66197
Tested-by: Jenkins
Reviewed-by: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
QA-Review: Jahnavi Yetukuri <ed2b2672ccc2e59e56c0615df7f01b579202e014@instructure.com>
Product-Review: Cosme Salazar <d37f5e06cd46b8fd23ce5553334e09ede5394232@instructure.com>

--- app/coffeescripts/react_files/components/Toolbar.coffee
+++ app/coffeescripts/react_files/components/Toolbar.coffee
@@ -156,8 +156,8 @@
                 disabled: !showingButtons
                 className: 'ui-button btn-restrict',
                 onClick: @openRestrictedDialog
-                title: I18n.t('restrict_access', 'Restrict Access')
-                'aria-label': I18n.t('restrict_access', 'Restrict Access')
+                title: I18n.t('restrict_access', 'Manage Access')
+                'aria-label': I18n.t('restrict_access', 'Manage Access')
                 'data-tooltip': ''
               },
                 i className: 'icon-cloud-lock'


Implement shift+tab for suggestion

Implement shift+tab for suggestion

--- admin/static/coffee/dataexplorer.coffee
+++ admin/static/coffee/dataexplorer.coffee
@@ -391,9 +391,14 @@
                     event.preventDefault()
                     if event.type isnt 'keydown'
                         return true
-                    @current_highlighted_suggestion++
-                    if @current_highlighted_suggestion >= @current_suggestions.length
-                        @current_highlighted_suggestion = 0
+                    if event.shiftKey
+                        @current_highlighted_suggestion--
+                        if @current_highlighted_suggestion < 0
+                            @current_highlighted_suggestion = @current_suggestions.length-1
+                    else
+                        @current_highlighted_suggestion++
+                        if @current_highlighted_suggestion >= @current_suggestions.length
+                            @current_highlighted_suggestion = 0

                     if @current_suggestions[@current_highlighted_suggestion]?
                         @highlight_suggestion @current_highlighted_suggestion


* Doc typo

* Doc typo

--- js/Adapters/Abstract.coffee
+++ js/Adapters/Abstract.coffee
@@ -98,7 +98,7 @@

 	#
-	# Set preview, or thumb for embaddable media
+	# Set preview, or thumb for embeddable media
 	# @param function thumbCallback Callback to set thumbnail image
 	#
 	setThumb: (thumbCallback) ->


Select 'unable to attend' by default for all options

--- client/angular/components/poll/meeting/vote_form/poll_meeting_vote_form.coffee
+++ client/angular/components/poll/meeting/vote_form/poll_meeting_vote_form.coffee
@@ -15,7 +15,9 @@
       choices = $scope.stance.stanceChoices()

       # create the map referenced from the view which requires has an integer for each
-      $scope.stanceValuesMap = _.fromPairs(_.map( choices, (choice)-> ([choice.pollOptionId, choice.score||0])))
+      $scope.stanceValuesMap = _.fromPairs _.map $scope.stance.poll().pollOptions(), (option) ->
+        stanceChoice = $scope.stance.stanceChoices().find((sc) -> sc.pollOptionId == option.id) or {}
+        [option.id, stanceChoice.score or 0]

       $scope.canRespondMaybe = $scope.stance.poll().customFields.can_respond_maybe
       $scope.stanceValues = if $scope.canRespondMaybe then [2,1,0] else [2, 0]


Add features to the user object in ide.

Add features to the user object in ide.

--- services/web/app/coffee/Features/Project/ProjectController.coffee
+++ services/web/app/coffee/Features/Project/ProjectController.coffee
@@ -248,6 +248,7 @@
 						subscription :
 							freeTrial: {allowed: allowedFreeTrial}
 						featureSwitches: user.featureSwitches
+						features: user.features
 					}
 					userSettings: {
 						mode  : user.ace.mode


Add ImageProcessor.isolateSprite for creating Images from a sprite in a sheet.  Use this for tiling screen sprites.

--- src/ui/imageProcessor.coffee
+++ src/ui/imageProcessor.coffee
@@ -26,12 +26,26 @@
   constructor : (@canvas, @ctx, @icons) ->
     # No-op

-  drawIcon : (icon) =>
-    x = 2;
-    y = 2;
+  drawIcon : (icon, x=2,y=2) =>
     coords = Data.sprites[icon];
+    throw new Error "Cannot find sprite sheet for : #{icon}" if not coords
     @ctx.drawImage(@icons[coords.source], coords.x, coords.y, SceneView.UNIT, SceneView.UNIT, x, y, SceneView.UNIT, SceneView.UNIT)

+  # Pick a single sprite out of a sheet, and return an image that contains only that sprite.
+  isolateSprite: (icon) ->
+    saveW = @canvas.width
+    saveH = @canvas.height
+    @canvas.width = SceneView.UNIT
+    @canvas.height = SceneView.UNIT
+    @ctx.clearRect(0, 0, SceneView.UNIT, SceneView.UNIT)
+    @drawIcon(icon,0,0)
+    src = @canvas.toDataURL()
+    result = new Image()
+    result.src = src
+    @canvas.width = saveW
+    @canvas.height = saveH
+
+    result
   drawRotated : (icon, degrees) =>
     @ctx.save();
     t = (Screen.HALF_UNIT + 2)


Update banner.js.coffee

Update banner.js.coffee

--- app/assets/javascripts/banner.js.coffee
+++ app/assets/javascripts/banner.js.coffee
@@ -10,8 +10,8 @@
 fill_banner = (data) ->
   $('#banner-placeholder').html(data);
   setTimeout((->
-    get_banner()), 10000000)
+    get_banner()), 10000)

 window.banner.toggle_pause = (pause) ->
   window.banner.pause = pause
-  $.ajax( {url: "/sessions/set_pause_refresh", type: "PUT", data: "pause=" + pause, complete: get_banner} )+  $.ajax( {url: "/sessions/set_pause_refresh", type: "PUT", data: "pause=" + pause, complete: get_banner} )


No fallar js cuando no se encuentra el objeto

--- app/assets/javascripts/cartas.js.coffee
+++ app/assets/javascripts/cartas.js.coffee
@@ -8,7 +8,7 @@
   )

   # Siempre hay un sólo input.supertipo
-  if $('input.supertipo')[0].value != 'Demonio'
+  if $('input.supertipo')[0] && $('input.supertipo')[0].value != 'Demonio'
     $('.linea-de-arte.terrenal').hide()

 # TODO bindear 36 = inicio y 35 = fin para primera y última carta


Change use of extension underscore method

--- Framework/Framework.coffee
+++ Framework/Framework.coffee
@@ -38,7 +38,7 @@
     if moduleName in @unloadedModules
       Ti.API.info("Loading Dynamic Module ..... [#{moduleName}]")
       @includeModule moduleName
-      @unloadedModules = @unloadedModules.without moduleName
+      @unloadedModules = _.without @unloadedModules, moduleName

   include: (file) =>
     if @includedFiles.indexOf(file) == -1


save domain/name at localStorage

save domain/name at localStorage

--- app/Scrapbook.coffee
+++ app/Scrapbook.coffee
@@ -16,6 +16,9 @@
   componentDidMount: ->
     if not @props
       @loadScraps()
+
+    # get domain or name at localStorage
+    @refs.from.getDOMNode().value = localStorage.getItem 'domain/name'

   doShowNameInput: -> @setState showNameInput: true
   dontShowNameInput: -> @setState showNameInput: false
@@ -277,6 +280,9 @@
       return console.log err if err
       return console.log res.text unless JSON.parse(res.text).ok

+      # save domain or name at localStorage
+      localStorage.setItem 'domain/name', @refs.from.getDOMNode().value
+
       if location.search.indexOf('startkey') isnt -1
         # go to the first page
         location.href = @props.firstpage


sankey: clean-up

sankey: clean-up

--- app/assets/javascripts/d3/sankey.coffee
+++ app/assets/javascripts/d3/sankey.coffee
@@ -329,7 +329,7 @@
     # callbacks
     #
     node_mouseover: ->
-      klass = $(this).parent().attr('data-id')
+      klass = $(this).attr('data-id')
       d3.selectAll(".link").
         filter((d) -> !d.connects(klass)).
         transition().
@@ -370,15 +370,13 @@
         attr("title", (d) => Metric.autoscale_value d.value(), 'PJ', 2)

       # move the rectangles
-      @nodes.data(@node_list.models, (d) -> d.get('id')).
-        selectAll("rect").
+      @nodes.selectAll("rect").
         transition().duration(500).
         attr("height", (d) => @y d.value()).
         attr("y", (d) => @y(d.y_offset()))

       # then move the node label
-      @nodes.data(@node_list.models, (d) -> d.get('id')).
-        selectAll("text.label").
+      @nodes.selectAll("text.label").
         transition().duration(500).
         attr("y", (d) => @y(d.y_offset() + d.value() / 2) )

@@ -390,8 +388,7 @@
         style("stroke-width", (link) => @y(link.value()))

       # then move the link labels and update their value
-      @links.data(@link_list.models, (d) -> d.cid).
-        transition().duration(500).
+      @links.transition().duration(500).
         selectAll("text.link_label").
         attr("y", (link) => @y link.right_y()).
         text((d) => Metric.autoscale_value d.value(), 'PJ', 2)