Use the correct linkedFileData var

Use the correct linkedFileData var

--- services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee
+++ services/web/app/coffee/Features/LinkedFiles/LinkedFilesController.coffee
@@ -23,7 +23,7 @@

 		linkedFileData = Agent.sanitizeData(data)
 		linkedFileData.provider = provider
-		Agent.checkAuth project_id, data, user_id, (err, allowed) ->
+		Agent.checkAuth project_id, linkedFileData, user_id, (err, allowed) ->
 			return Agent.handleError(err, req, res, next) if err?
 			return res.sendStatus(403) if !allowed
 			Agent.writeIncomingFileToDisk project_id, linkedFileData, user_id, (error, fsPath) ->


Execute cells immediately when mode is changed to markup

--- h2o-web/src/main/steam/scripts/flow.coffee
+++ h2o-web/src/main/steam/scripts/flow.coffee
@@ -658,15 +658,16 @@
         (iterate tasks) (results) -> go null, results

 Flow.Repl = (_) ->
+  _sandbox =
+    context: {}
+    routines: Flow.Routines _
+    results: {}
+
   _cells = nodes$ []
   _selectedCell = null
   _selectedCellIndex = -1
   _clipboardCell = null
   _lastDeletedCell = null
-  _sandbox =
-    context: {}
-    routines: Flow.Routines _
-    results: {}

   _renderers =
     h1: -> Flow.HtmlTag _, 'h1'
@@ -810,13 +811,20 @@
     _selectedCell.isActive yes
     no

-  convertCellToCode = -> _selectedCell.type 'cs'
-
-  convertCellToHeading = (level) -> -> _selectedCell.type "h#{level}"
-
-  convertCellToMarkdown = -> _selectedCell.type 'md'
-
-  convertCellToRaw = -> _selectedCell.type 'raw'
+  convertCellToCode = ->
+    _selectedCell.type 'cs'
+
+  convertCellToHeading = (level) -> ->
+    _selectedCell.type "h#{level}"
+    _selectedCell.execute()
+
+  convertCellToMarkdown = ->
+    _selectedCell.type 'md'
+    _selectedCell.execute()
+
+  convertCellToRaw = ->
+    _selectedCell.type 'raw'
+    _selectedCell.execute()

   copyCell = ->
     _clipboardCell = cloneCell _selectedCell


hide follow / unfollow button from guests

--- client/app/Applications/Topics.kdapplication/ContentDisplays/Topic.coffee
+++ client/app/Applications/Topics.kdapplication/ContentDisplays/Topic.coffee
@@ -79,35 +79,38 @@

   constructor:(options, data)->

-    @followButton = new KDToggleButton
-      style           : if data.followee then "kdwhitebtn following-topic" else "kdwhitebtn"
-      title           : "Follow"
-      dataPath        : "followee"
-      defaultState    : if data.followee then "Following" else "Follow"
-      loader          :
-        color         : "#333333"
-        diameter      : 18
-        top           : 11
-      states          : [
-        title         : "Follow"
-        callback      : (callback)->
-          data.follow (err, response)=>
-            data.followee = yes
-            @hideLoader()
-            unless err
-              @setClass 'following-btn following-topic'
-              callback? null
-      ,
-        title         : "Following"
-        callback      : (callback)->
-          data.unfollow (err, response)=>
-            data.followee = no
-            @hideLoader()
-            unless err
-              @unsetClass 'following-btn following-topic'
-              callback? null
-      ]
-    , data
+    if KD.whoami().type is 'unregistered'
+      @followButton = new KDView
+    else
+      @followButton = new KDToggleButton
+        style           : if data.followee then "kdwhitebtn following-topic" else "kdwhitebtn"
+        title           : "Follow"
+        dataPath        : "followee"
+        defaultState    : if data.followee then "Following" else "Follow"
+        loader          :
+          color         : "#333333"
+          diameter      : 18
+          top           : 11
+        states          : [
+          title         : "Follow"
+          callback      : (callback)->
+            data.follow (err, response)=>
+              data.followee = yes
+              @hideLoader()
+              unless err
+                @setClass 'following-btn following-topic'
+                callback? null
+        ,
+          title         : "Following"
+          callback      : (callback)->
+            data.unfollow (err, response)=>
+              data.followee = no
+              @hideLoader()
+              unless err
+                @unsetClass 'following-btn following-topic'
+                callback? null
+        ]
+      , data

     super
     unless data.followee


fixed Most Activity and Latest Activity sort for topics

--- client/landing/app/Applications/Topics.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Topics.kdapplication/AppController.coffee
@@ -73,7 +73,7 @@
         'meta.modifiedAt'   :
           title             : "Latest activity"
           direction         : -1
-        'counts.tagged'     :
+        'counts.post'     :
           title             : "Most activity"
           direction         : -1
     }, (controller)=>


Add most of the remaining delete* inputType handlers

--- src/trix/controllers/level_2_input_controller.coffee
+++ src/trix/controllers/level_2_input_controller.coffee
@@ -27,32 +27,49 @@

   # https://www.w3.org/TR/input-events-2/#interface-InputEvent-Attributes

-  # deleteByComposition: (event) ->
-  #
-  # deleteByCut: (event) ->
-  #
+  deleteByComposition: (event) ->
+    @responder?.deleteInDirection("backward")
+
+  deleteByCut: (event) ->
+    @delegate?.inputControllerWillPerformTyping()
+    @responder?.deleteInDirection("backward")
+
   # deleteByDrag: (event) ->

   deleteCompositionText: (event) ->
     @responder?.deleteInDirection("backward")

-  # deleteContent: (event) ->
+  deleteContent: (event) ->
+    @delegate?.inputControllerWillPerformTyping()
+    @responder?.deleteInDirection("backward")

   deleteContentBackward: (event) ->
     @delegate?.inputControllerWillPerformTyping()
     @responder?.deleteInDirection("backward")

-  # deleteContentForward: (event) ->
-  #
-  # deleteEntireSoftLine: (event) ->
-  #
-  # deleteHardLineBackward: (event) ->
-  #
-  # deleteHardLineForward: (event) ->
-  #
-  # deleteSoftLineBackward: (event) ->
-  #
-  # deleteSoftLineForward: (event) ->
+  deleteContentForward: (event) ->
+    @delegate?.inputControllerWillPerformTyping()
+    @responder?.deleteInDirection("forward")
+
+  deleteEntireSoftLine: (event) ->
+    @delegate?.inputControllerWillPerformTyping()
+    @responder?.deleteInDirection("forward")
+
+  deleteHardLineBackward: (event) ->
+    @delegate?.inputControllerWillPerformTyping()
+    @responder?.deleteInDirection("backward")
+
+  deleteHardLineForward: (event) ->
+    @delegate?.inputControllerWillPerformTyping()
+    @responder?.deleteInDirection("forward")
+
+  deleteSoftLineBackward: (event) ->
+    @delegate?.inputControllerWillPerformTyping()
+    @responder?.deleteInDirection("backward")
+
+  deleteSoftLineForward: (event) ->
+    @delegate?.inputControllerWillPerformTyping()
+    @responder?.deleteInDirection("forward")

   deleteWordBackward: (event) ->
     @delegate?.inputControllerWillPerformTyping()


MemberRemoved: simplify machine users updater helper with corresponding data

--- workers/social/lib/social/models/computeproviders/handlers/memberremoved.coffee
+++ workers/social/lib/social/models/computeproviders/handlers/memberremoved.coffee
@@ -17,16 +17,17 @@
   return owner

-changeOwnershipOfMachine = (machine, newOwner) ->
+setOwnerOfMachine = (machine, { account, user }) ->

   # Move machine ownership to the admin who kicked the member
   machine.addUsers {
-    targets: [ newOwner ], asOwner: yes
+    targets: [ user ], asOwner: yes, sudo: yes
   }, (err) ->
-    log 'Failed to change ownership:', err  if err
+    log 'Failed to change ownership of machine:', err  if err

+updateMachineUsers = ({ machines, user, requester, reason }) ->

-updateMachineUsers = (machines, user, requester, reason) ->
+  return  unless reason is 'kick'

   machines.forEach (machine) ->
     # Check if the user is owner of the machine
@@ -36,11 +37,10 @@
       log "Couldn't remove user from users:", err  if err

       # if not owner this machine we leave it to existing owner
-      # if user is left on by own we leave the users list as is
-      return  if not owner or reason is 'leave'
+      return  if not owner

       # otherwise we move the ownership of the machine to the requester
-      changeOwnershipOfMachine machine, requester
+      setOwnerOfMachine machine, requester

 module.exports = memberRemoved = ({ group, member, requester }) ->
@@ -95,7 +95,16 @@
         queue.next()

     ->
-      updateMachineUsers memberMachines, memberJUser, requesterJUser, reason
+      updateMachineUsers {
+        user      : memberJUser
+        machines  : memberMachines
+        requester :
+          user    : requesterJUser
+          account : requester
+        reason
+      }
+      queue.next()
+
       queue.next()

   ]


Cleanup code

Cleanup code

--- src/scripts/helpers/handlers/analytics.coffee
+++ src/scripts/helpers/handlers/analytics.coffee
@@ -26,8 +26,7 @@

     # Wrapper functions to add analytics events
     # ga: () -> window.ga?.apply(@, arguments) # analytics.js
-    gaq: () ->
-      window._gaq?.push(arguments[0], arguments[1]) # ga.js
+    gaq: () -> window._gaq?.push(arguments[0], arguments[1]) # ga.js

     # Send the current page to every analytics service
     send: (account, fragment = Backbone.history.fragment) ->


Fixes issue #2734 - Enhance postmaster filters to be able ignoring vacation mails (out of office).

--- app/assets/javascripts/app/controllers/_ui_element/postmaster_match.coffee
+++ app/assets/javascripts/app/controllers/_ui_element/postmaster_match.coffee
@@ -126,6 +126,10 @@
           {
             value:    'x-loop'
             name:     'X-Loop'
+          },
+          {
+            value:    'x-zammad-out-of-office'
+            name:     'X-Zammad-Out-Of-Office'
           },
         ]


EDSC-572: Fix issues switching back to non-granule views

--- app/assets/javascripts/modules/map/leaflet-plugins/granule_layer.js.coffee
+++ app/assets/javascripts/modules/map/leaflet-plugins/granule_layer.js.coffee
@@ -170,7 +170,7 @@
         this._url = config.gibsSitUrl || this._originalUrl;
         date = granule.time_start
       else
-        this._url = this._originalUrl;
+        this._url = this._originalUrl || this._url;

       L.TileLayer.prototype.getTileUrl.call(this, tilePoint) + "&time=#{date}" if matched


Don't need to add a new Layer, Sinan can u check this.

--- client/app/Applications/Activity.kdapplication/widgets/statuswidget.coffee
+++ client/app/Applications/Activity.kdapplication/widgets/statuswidget.coffee
@@ -77,7 +77,7 @@

   switchToLargeView:->

-    @parent.unsetClass "no-shadow"
+    @parent.unsetClass "no-shadow" if @parent # monkeypatch when loggedout this was giving an error
     @smallInput.hide()
     @$('>div.large-input, >div.formline').show()

@@ -85,8 +85,9 @@
       @largeInput.$().trigger "focus"
       @largeInput.setHeight 72

-    tabView = @parent.getDelegate()
-    @getSingleton("windowController").addLayer tabView
+    # Do we really need this? Without that it works great.
+    # tabView = @parent.getDelegate()
+    # @getSingleton("windowController").addLayer tabView

   switchToEditView:(activity)->
     {tags, body} = activity
@@ -109,7 +110,6 @@
     super

   viewAppended:->
-
     @setTemplate @pistachio()
     @template.update()
     @switchToSmallView()


"suspress" console methods :)

"suspress" console methods :)

--- client/landing/app/Applications/Feeder.kdapplication/FeedController.coffee
+++ client/landing/app/Applications/Feeder.kdapplication/FeedController.coffee
@@ -51,13 +51,11 @@
 #      @resultsCOntroller.emit 'NewFeedItemsFromFeeder', items

   highlightFacets:->
-    console.log 'highlight facets', arguments, this
     filterName  = @selection.name
     sortName    = @selection.activeSort or @defaultSort.name
     @facetsController.highlight filterName, sortName

   handleQuery:({filter, sort})->
-    console.log 'handle query', {filter, sort}
     @selectFilter filter      if filter?
     @changeActiveSort sort    if sort?
     @highlightFacets()


There is no member

There is no member

--- client/landing/app/Applications/Members.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Members.kdapplication/AppController.coffee
@@ -72,6 +72,7 @@
       itemClass             : MembersListItemView
       listControllerClass   : MembersListViewController
       limitPerPage          : 10
+      noItemFoundText       : "There is no member."
       # singleDataSource      : (selector, options, callback)=>
         # filterFunc selector, options, callback
       help                  :


also support collection urls on user

also support collection urls on user

--- core/app/backbone/models/user.coffee
+++ core/app/backbone/models/user.coffee
@@ -8,7 +8,9 @@
   setChannels: (channels) -> @channels = channels

   url: (forProfile) ->
-    if (forProfile)
+    if @collection?
+      super
+    else if (forProfile)
       '/' + this.get('username') + ".json"
     else
       '/' + this.get('username')


Removes unneeded require from test/query.coffee

--- test/query.coffee
+++ test/query.coffee
@@ -1,5 +1,4 @@
 async     = require 'async'
-fs        = require 'fs'
 assert    = require 'assert'
 _         = require 'underscore'
 Clever    = require "#{__dirname}/../index"


always show the dot when "Comment" is shown

--- client/landing/app/Applications/Activity.kdapplication/views/discussionactivityactions.coffee
+++ client/landing/app/Applications/Activity.kdapplication/views/discussionactivityactions.coffee
@@ -4,10 +4,6 @@
     super

     activity = @getData()
-
-    # @opinionCount?.destroy()
-
-    log "this is the data",activity.repliesCount, activity.opinionCount

     @opinionCountLink  = new ActivityActionLink
       partial     : "Answer"
@@ -76,7 +72,7 @@
     """
       {{> @loader}}
       {{> @opinionCountLink}} {{> @opinionCount}} #{if @getData()?.opinionCount > 0 then " ·" else "" }
-      {{> @commentCountLink}} {{> @commentCount}} #{if @getData()?.repliesCount > 0 then " ·" else "" }
+      {{> @commentCountLink}} {{> @commentCount}} #{if @getData()?.repliesCount > 0 then " ·" else " ·" }
       <span class='optional'>
       {{> @shareLink}} ·
       </span>


[Client][Activity] change konfig to a function

--- workers/social/lib/social/models/graph/bucket.coffee
+++ workers/social/lib/social/models/graph/bucket.coffee
@@ -3,7 +3,7 @@

 module.exports = class Bucket extends Graph

-  @activityFetchCount = KONFIG.client.runtimeOptions.activityFetchCount
+  @activityFetchCount =-> KONFIG.client.runtimeOptions.activityFetchCount

   ###############################################
   ##############  new members  ##################
@@ -13,7 +13,7 @@
     options =
       groupId     : groupId
       to          : to
-      limitCount  : @activityFetchCount
+      limitCount  : @activityFetchCount()

     query = QueryRegistry.bucket.newMembers
     @queryMembers query, options, callback
@@ -42,7 +42,7 @@
     options =
       groupId     : groupId
       to          : to
-      limitCount  : @activityFetchCount
+      limitCount  : @activityFetchCount()

     query = QueryRegistry.bucket.newInstallations
     @fetch query, options, (err, results) =>
@@ -71,7 +71,7 @@
     options =
       groupId     : groupId
       to          : to
-      limitCount  : @activityFetchCount
+      limitCount  : @activityFetchCount()

     query = QueryRegistry.bucket.newUserFollows
     @fetchFollows query, options, callback
@@ -85,7 +85,7 @@
       groupId     : groupId
       groupName   : groupName
       to          : to
-      limitCount  : @activityFetchCount
+      limitCount  : @activityFetchCount()

     query = QueryRegistry.bucket.newTagFollows
     @fetchFollows query, options, callback


payment: JPaymentPlan: group property is required

--- workers/social/lib/social/models/payment/plan.coffee
+++ workers/social/lib/social/models/payment/plan.coffee
@@ -82,6 +82,7 @@
       feeAmount
       feeInitial  : 0
       feeInterval : 1
+      group
     }

     plan.save (err) ->


Consolidate rules related to too-strict float specifiers.

--- services/web/public/coffee/ide/human-readable-logs/HumanReadableLogsRules.coffee
+++ services/web/public/coffee/ide/human-readable-logs/HumanReadableLogsRules.coffee
@@ -41,13 +41,7 @@
 			You have used the same label more than once. Check that each \\label{...} labels only one item.
 		"""
 	,
-		regexToMatch: /`!h' float specifier changed to `!ht'/
-		extraInfoURL: "https://www.sharelatex.com/learn/Errors:%60!h%27_float_specifier_changed_to_%60!ht%27."
-		humanReadableHint: """
-			The float specifier '!h' is too strict of a demand for LaTeX to place your float in a nice way here. Try relaxing it by using 'ht', or even 'htbp' if necessary. If you want to try to keep the float here anyway, check out the [float package](https://www.sharelatex.com/learn/Errors:%60!h%27_float_specifier_changed_to_%60!ht%27.).
-		"""
-	,
-		regexToMatch: /`h' float specifier changed to `ht'/
+		regexToMatch: /`!?h' float specifier changed to `!?ht'/
 		extraInfoURL: "https://www.sharelatex.com/learn/Errors:%60!h%27_float_specifier_changed_to_%60!ht%27."
 		humanReadableHint: """
 			The float specifier 'h' is too strict of a demand for LaTeX to place your float in a nice way here. Try relaxing it by using 'ht', or even 'htbp' if necessary. If you want to try keep the float here anyway, check out the [float package](https://www.sharelatex.com/learn/Positioning_of_Figures).


Cleanup comments

Cleanup comments

--- client/landing/app/Applications/WebTerm.kdapplication/AppController.coffee
+++ client/landing/app/Applications/WebTerm.kdapplication/AppController.coffee
@@ -23,33 +23,4 @@

     super options, data

-  # TODO: the below was pasted in here during a merge.  fixme C.T.
-  # bringToFront: ->
-  #   appStorage = new AppStorage 'WebTerm', '1.0'
-  #   appStorage.fetchStorage =>
-  #     data = new WebTermView appStorage
-  #     data.on "WebTerm.terminated", =>
-  #       @propagateEvent
-  #         KDEventType : "ApplicationWantsToClose"
-  #         globalEvent : yes
-  #       , data: data
-
-  #     data.on 'ViewClosed', =>
-  #       @propagateEvent
-  #         KDEventType : 'ApplicationWantsToClose'
-  #         globalEvent : yes
-  #       ,
-  #         data : data
-
-  #     options =
-  #       name         : "Terminal"
-  #       hiddenHandle : no
-  #       type         : "application"
-  #       cssClass     : "webterm"
-
-  #     @propagateEvent
-  #       KDEventType  : "ApplicationWantsToBeShown"
-  #       globalEvent  : yes
-  #     , {options, data}
-
 WebTerm = {}


fixed pretty print removal oversight

fixed pretty print removal oversight

--- client/app/CommonViews/opinions/opinionlistitemview.coffee
+++ client/app/CommonViews/opinions/opinionlistitemview.coffee
@@ -143,7 +143,7 @@
   render:->
     super()

-    @$("pre").addClass "prettyprint"
+    # @$("pre").addClass "prettyprint"
     @$("p.opinion-body span.data pre").each (i,element)=>
       element = hljs.highlightBlock element

@@ -160,7 +160,7 @@
       @markup.css {maxHeight}
       @larger.show()

-    @$("pre").addClass "prettyprint"
+    # @$("pre").addClass "prettyprint"
     # prettyPrint()

     @$("p.opinion-body span.data pre").each (i,element)=>


Revert machine assignment

Revert machine assignment

--- client/app/lib/providers/machinesettingsgeneralview.coffee
+++ client/app/lib/providers/machinesettingsgeneralview.coffee
@@ -125,7 +125,7 @@
         nickEdit.hide()
         nickname.show()

-      nickEdit.setValue Encoder.htmlDecode machine.label
+      nickEdit.setValue Encoder.htmlDecode @machine.label
       nickEdit.show()

       kd.utils.defer -> nickEdit.setFocus()
@@ -205,4 +205,4 @@
           label         : 'Build logs'
           cssClass      : if isAws then 'custom-link-view' else 'hidden'
           itemClass     : KDView
-          partial       : logsMessage+          partial       : logsMessage


Fixed underscores vs dashes in notification settings.

--- core/app/backbone/views/users/notification_settings.coffee
+++ core/app/backbone/views/users/notification_settings.coffee
@@ -3,8 +3,8 @@
   template: 'users/notification_settings'

   modelBindings:
-    "change input.js-receives-mailed-notifications" : 'receives-mailed-notifications'
-    "change input.js-receives-digest" : 'receives-digest'
+    "change input.js-receives-mailed-notifications" : 'receives_mailed_notifications'
+    "change input.js-receives-digest" : 'receives_digest'

   onRender: -> @bind()


server: use source param only when creating customer

Signed-off-by: Umut Sirin <4055abbc0e40a1254e715b952ccd414607e0b365@gmail.com>

--- servers/lib/server/handlers/createpaymentplan.coffee
+++ servers/lib/server/handlers/createpaymentplan.coffee
@@ -20,9 +20,11 @@

   params.trialEnd ?= getDefaultTrialEnd()

-  { sessionToken } = params
+  { sessionToken, source } = params

-  createCustomer { sessionToken }, (err, customer) ->
+  delete params.source
+
+  createCustomer { sessionToken, source }, (err, customer) ->
     return callback err  if err

     params.customer = customer.id


Fix broken test

Fix broken test

--- services/web/test/UnitTests/coffee/Subscription/RecurlyWrapperTests.coffee
+++ services/web/test/UnitTests/coffee/Subscription/RecurlyWrapperTests.coffee
@@ -728,7 +728,7 @@
 			describe 'when the account does not exist', ->

 				beforeEach ->
-					@apiRequest.callsArgWith(1, new Error('not found'), {statusCode: 404}, '')
+					@apiRequest.callsArgWith(1, null, {statusCode: 404}, '')

 				it 'should not produce an error', (done) ->
 					@call (err, result) =>


IMPROVED: removed some object-creation in flex-layout ALL 731 TESTS PASSING

--- source/Art/Engine/Core/EpochLayout/FlexLayout.coffee
+++ source/Art/Engine/Core/EpochLayout/FlexLayout.coffee
@@ -26,12 +26,6 @@
     sizeWithPadding x, y, currentPadding
   else
     point x, y
-
-addFinalPassSizeLayoutChild = (finalPassProps, child) ->
-  if finalPassProps.finalPassSizeLayoutChildren
-    finalPassProps.finalPassSizeLayoutChildren.push child
-  else
-    finalPassProps.finalPassSizeLayoutChildren = [child]

 module.exports = class FlexLayout

@@ -84,8 +78,7 @@
     # FIRST FLEX PASS - Fixed inFlowChildren layout
     ###########################################
     lastChildsNextMargin = 0
-    finalPassProps =
-      finalPassSizeLayoutChildren: null
+    finalPassSizeLayoutChildren = null

     for child, i in inFlowChildren
       if child.getPendingSize()[mainAxisRelativeTestFunction]()
@@ -102,7 +95,7 @@
         spaceForFlexChildren -= mainSize

         if child.getPendingLayoutSizeParentCircular()
-          addFinalPassSizeLayoutChild finalPassProps, child
+          (finalPassSizeLayoutChildren||=[]).push child
           if (!isRowLayout && child._pendingState._size.xChildrenRelative) || (isRowLayout && child._pendingState._size.yChildrenRelative)
             maxCrossSize = max maxCrossSize, currentSize[crossCoordinate]
         else
@@ -145,7 +138,7 @@
       mainSize = currentSize[mainCoordinate]

       if child.getPendingLayoutSizeParentCircular()
-        addFinalPassSizeLayoutChild finalPassProps, child
+        (finalPassSizeLayoutChildren||=[]).push child
       else
         crossSize = currentSize[crossCoordinate]
         maxCrossSize = max maxCrossSize, crossSize
@@ -177,7 +170,7 @@
     ####################
     # FINAL PASS
     ####################
-    if finalPassSizeLayoutChildren = finalPassProps.finalPassSizeLayoutChildren
+    if finalPassSizeLayoutChildren
       oldMaxCrossSize = maxCrossSize
       secondPassSizeForChildren = toPoint isRowLayout, mainElementSizeForChildren, crossElementSizeForChildren


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- source/javascripts/_cornerstone/array_extensions.js.coffee
+++ source/javascripts/_cornerstone/array_extensions.js.coffee
@@ -32,11 +32,11 @@

     a = ["a", "b", "c"]
     b = a.copy()
-
+
     # their elements are equal
     a[0] == b[0] && a[1] == b[1] && a[2] == b[2]
     # => true
-
+
     # but they aren't the same object in memory
     a === b
     # => false
@@ -70,7 +70,7 @@

     [[1, 2], [3, 4], 5].flatten()
     # => [1, 2, 3, 4, 5]
-
+
     # won't flatten twice nested arrays. call
     # flatten twice if that is what you want
     [[1, 2], [3, [4, 5]], 6].flatten()
@@ -90,7 +90,7 @@

     [1.1, 2.2, 3.3, 4.4].invoke("floor")
     # => [1, 2, 3, 4]
-
+
     ['hello', 'world', 'cool!'].invoke('substring', 0, 3)
     # => ['hel', 'wor', 'coo']

@@ -124,7 +124,7 @@
     a = [1, 1, "a", "b"]
     a.remove(1)
     # => 1
-
+
     a
     # => [1, "a", "b"]

@@ -146,7 +146,7 @@

     ["a", "b", "c"].include("c")
     # => true
-
+
     [40, "a"].include(700)
     # => false

@@ -160,7 +160,7 @@

 ###*
 Call the given iterator once for each element in the array,
-passing in the element as the first argument, the index of
+passing in the element as the first argument, the index of
 the element as the second argument, and this array as the
 third argument.

@@ -169,12 +169,12 @@
     ["r", "a", "d"].each (letter, index) ->
       word += letter
       indices.push(index)
-
+
     # => ["r", "a", "d"]
-
+
     word
     # => "rad"
-
+
     indices
     # => [0, 1, 2]

@@ -194,8 +194,8 @@
   return this

 ###*
-Call the given iterator once for each element in the array,
-passing in the element as the first argument, the index of
+Call the given iterator once for each element in the array,
+passing in the element as the first argument, the index of
 the element as the second argument, and `this` array as the
 third argument.

@@ -276,7 +276,7 @@
     [1, 2, 3, 4].eachSlice 2, (slice) ->
       results.push(slice)
     # => [1, 2, 3, 4]
-
+
     results
     # => [[1, 2], [3, 4]]

@@ -321,10 +321,10 @@
 Returns a new array with the elements all shuffled up.

     a = [1, 2, 3]
-
+
     a.shuffle()
     # => [2, 3, 1]
-
+
     a # => [1, 2, 3]

 @name shuffle
@@ -375,7 +375,7 @@
 @methodOf Array#
 @param {Function} [fn] An optional funtion used to evaluate each element to calculate its value for determining extremes.
 @returns {Object} {min: minElement, max: maxElement}
-###
+###
 Array::extremes = (fn) ->
   fn ||= (n) -> n

@@ -405,16 +405,16 @@
   max: max

 ###*
-Pretend the array is a circle and grab a new array containing length elements.
-If length is not given return the element at start, again assuming the array
+Pretend the array is a circle and grab a new array containing length elements.
+If length is not given return the element at start, again assuming the array
 is a circle.

     [1, 2, 3].wrap(-1)
     # => 3
-
+
     [1, 2, 3].wrap(6)
     # => 1
-
+
     ["l", "o", "o", "p"].wrap(0, 16)
     # => ["l", "o", "o", "p", "l", "o", "o", "p", "l", "o", "o", "p", "l", "o", "o", "p"]

@@ -430,6 +430,7 @@
     i = start
     result = []

+
     result.push(this[i.mod(this.length)]) while i++ < end

     return result
@@ -442,10 +443,10 @@

     [evens, odds] = [1, 2, 3, 4].partition (n) ->
       n.even()
-
+
     evens
     # => [2, 4]
-
+
     odds
     # => [1, 3]

@@ -508,7 +509,7 @@

 ###*
 Combines all elements of the array by applying a binary operation.
-for each element in the arra the iterator is passed an accumulator
+for each element in the arra the iterator is passed an accumulator
 value (memo) and the element.

 @name inject
@@ -560,7 +561,7 @@
 @returns {Array} Array groupings whose values are arranged by their positions in the original input arrays.
 ###
 Array::zip = (args...) ->
-  this.map (element, index) ->
+  this.map (element, index) ->
     output = args.map (arr) ->
       arr[index]


ProviderInterface: a helper method for fetching credentials

--- workers/social/lib/social/models/computeproviders/providerinterface.coffee
+++ workers/social/lib/social/models/computeproviders/providerinterface.coffee
@@ -23,3 +23,17 @@
   @fetchAvailable = NOT_IMPLEMENTED

   @postCreate     = PASS_THROUGH
+
+  @fetchCredentialData  = (credential, callback)->
+
+    unless credential
+      return callback null, {}
+
+    credential.fetchData (err, credData)->
+
+      if err?
+        callback new KodingError "Failed to fetch credential"
+      else if credData?
+        callback null, credData.meta
+      else
+        callback null, {}


add log

add log

--- lib/pushservices/apns.coffee
+++ lib/pushservices/apns.coffee
@@ -25,13 +25,16 @@

     push: (subscriber, subOptions, payload) ->
+        logger.verbose "APNS push: " + JSON.stringify(payload)
         subscriber.get (info) =>
             note = new apns.Notification()
             device = new apns.Device(info.token)
             device.subscriberId = subscriber.id # used for error logging
             if subOptions?.ignore_message isnt true and alert = payload.localizedMessage(info.lang)
                 note.alert = alert
-            note.badge = badge if not isNaN(badge = parseInt(info.badge) + 1)
+            #note.badge = badge if not isNaN(badge = parseInt(info.badge) + 1)
+            if (info.badge)
+                note.badge = info.badge
             note.sound = payload.sound
             if @payloadFilter?
                 for key, val of payload.data
@@ -40,6 +43,6 @@
                 note.payload = payload.data
             @driver.pushNotification note, device
             # On iOS we have to maintain the badge counter on the server
-            subscriber.incr 'badge'
+            #subscriber.incr 'badge'

 exports.PushServiceAPNS = PushServiceAPNS


Added loader, pagination, close button to new member activity.

--- client/app/Applications/Activity.kdapplication/views/newmemberbucket.coffee
+++ client/app/Applications/Activity.kdapplication/views/newmemberbucket.coffee
@@ -22,55 +22,66 @@
     @lastFetchedDate      = null
     @lastFetchedItemCount = 0
     @isUserViewCreated    = no
+    @listViews            = []

     @group.on "moreLinkClicked", =>
+      groupLoader = new KDLoaderView size: width: 24
+      @group.addSubView groupLoader
+      groupLoader.show()
+
+      count = 10
+
       if not @isUserViewCreated
-        @addSubView new KDView
-          cssName : "close-button"
-          click   : =>
+        @createCloseButton()
+        @createShowMore count
         @isUserViewCreated = yes

-      count = 10
-
-      @fetchUsers count, (teasers) =>
+      options =
+        limit: count
+        from : @lastFetchedDate or @getData().createdAtTimestamps[0]
+        to   : @getData().createdAtTimestamps[1]
+
+      appManager.tell "Activity", "fetchQuery", options, (teasers, activities) =>
         @getData().anchors = @getData().anchors.concat teasers.map (item)-> item.anchor
         @group.setData @getData().anchors
-        # @group.visibleCount += 10
-        # @group.render()
-        # @group.loader.hide()
+        @group.loader.hide()

         items = @getData().anchors.slice @lastFetchedItemCount, @lastFetchedItemCount + count

-        @newMembersList = new KDListViewController
+        newMembersList = new KDListViewController
           view        : new NewMemberList
           wrapper     : no
           scrollView  : no
         , items: items

-        @group.addSubView @newMembersList.getView()
+        @listViews.push newMembersList
+        @group.addSubView newMembersList.getView()
         @lastFetchedItemCount = @lastFetchedItemCount + count
-
-  fetchUsers: (count, callback) ->
-    # @group.loader.show()
-
-    selector    =
-      type      : { $in : ['CNewMemberBucketActivity'] }
-      createdAt :
-        $gt     : @lastFetchedDate or @getData().createdAtTimestamps[0]
-        $lt     : @getData().createdAtTimestamps[1]
-
-    options     =
-      limit     : count
-
-    KD.remote.api.CActivity.some selector, options, (err, activities)=>
-      return if err or activities.length is 0
-
-      activities = ActivityAppController.clearQuotes activities
-      @lastFetchedDate = activities.last.createdAt
-      KD.remote.reviveFromSnapshots activities, (err, teasers)=>
-        return warn err if err
-
-        callback? teasers
+        @showMore.hide() if @getData().count <= @lastFetchedItemCount
+        @lastFetchedDate = activities.last.createdAt
+        groupLoader.destroy()
+
+  createCloseButton: ->
+    @addSubView @closeButton = new KDView
+      cssClass : "close-button"
+      partial  : "Close"
+      click    : =>
+        list.getView().destroy() for list in @listViews
+        @closeButton.destroy()
+        @showMore.destroy()
+        @lastFetchedItemCount = 0
+        @isUserViewCreated    = no
+        @lastFetchedDate      = null
+        @listViews            = []
+
+  createShowMore: (count) ->
+    return if @getData().count < @lastFetchedItemCount + count
+    @addSubView @showMore = new KDView
+      cssClass : "show-more-link"
+      partial  : "Show More"
+      click    : =>
+        @group.emit "moreLinkClicked"
+        @showMore.hide() if @getData().count <= @lastFetchedItemCount + count

   pistachio:->
     """


No need second argument there

No need second argument there

--- client/landing/app/MainApp/filetree/controllers/findertreecontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/findertreecontroller.coffee
@@ -445,7 +445,7 @@
               @getSingleton('mainController').emit 'CreateNewActivityRequested', 'JCodeShare', CodeShares

   openTerminalFromHere: (nodeView) ->
-    appManager.open "WebTerm", yes, (appInstance) =>
+    appManager.open "WebTerm", (appInstance) =>
       path        = nodeView.getData().path
       webTermView = KD.getSingleton('mainView').mainTabView.getActivePane().mainView
       #TODO: webTermView != appInstance.getView() so should simplify the line above


Updated gist-async.js.coffee.

Updated gist-async.js.coffee.

--- _assets/javascripts/gist-async.js.coffee
+++ _assets/javascripts/gist-async.js.coffee
@@ -1,7 +1,7 @@
 # Load GitHub Gists asynchronously
 # and optionally specify which file to show.
 #
-# Requires yepnope and jQuery.
+# Requires jQuery and Modernizr.load or yepnope.
 #
 # Based on Mark Selby's async-gists.js:
 # https://gist.github.com/markselby/7209751
@@ -11,15 +11,24 @@
 # Source and usage instructions:
 # https://gist.github.com/razor-x/8288761
 #
-
 'use strict'
-
 $ ->
   GIST_HOST = 'https://gist.github.com'
   elements = $('div[data-gist]')
   gists = {}
   code = []
   stylesheets = []
+
+  # Set the asynchronous asset loader function.
+  loader =
+    if yepnope?
+      yepnope
+    else if Modernizr?
+      Modernizr.load if Modernizr.load?
+
+  unless loader?
+    elements.addClass('loading-failed')
+    return

   elements.addClass('loading')

@@ -42,7 +51,7 @@
       stylesheet = gist.data.stylesheet
       if stylesheets.indexOf(stylesheet) < 0
         stylesheets.push stylesheet
-        yepnope(GIST_HOST + stylesheet)
+        loader(stylesheet)

       div = gist.data.div
       gist.files = $(div).find('.gist-file')


Cleanup: mibor

Cleanup: mibor

--- client/Finder/filetree/itemviews/finderitem.coffee
+++ client/Finder/filetree/itemviews/finderitem.coffee
@@ -53,10 +53,10 @@
       delete @progressView

     @childView.show()
-    @beingDeleted = no
-    @beingEdited = no
+    @beingDeleted  = no
+    @beingEdited   = no
     @beingProgress = no
-    @callback = null
+    @callback      = null
     @unsetClass "being-deleted being-edited progress"
     @getDelegate().setKeyView()


fix for zepto

fix for zepto

--- public/views/variation_attribute_view.coffee
+++ public/views/variation_attribute_view.coffee
@@ -21,12 +21,12 @@
     @$el.html @template
       name: @model.name()
       displayName: @model.displayName()
-    @$el.find("select").html @model.get("values").map (option) =>
+    @$el.find("select").html(@model.get("values").map((option) =>
       @optionTemplate
         value: option.value
-        displayValue: option.displayValue
-    @$el.find("select").prepend =>
+        displayValue: option.displayValue).join(""))
+    @$el.find("select").prepend(
       @optionTemplate
         value: null
-        displayValue: "Choose"
+        displayValue: "Choose")
     this


If strict is false, ignore validating children for BranchNode

--- coffee/cilantro/models/context/nodes/branch.coffee
+++ coffee/cilantro/models/context/nodes/branch.coffee
@@ -67,7 +67,8 @@
             if options.strict and not attrs.children.length
                 return 'No children in branch'

-            if options.deep
+            # TODO deep may be redundant here
+            if options.deep and options.strict
                 for child in attrs.children
                     if child instanceof base.ContextNodeModel
                         if not child.isValid(options)


update replay download links

update replay download links

--- resources/assets/lib/play-detail-menu.coffee
+++ resources/assets/lib/play-detail-menu.coffee
@@ -1,5 +1,5 @@
 ###
-#    Copyright 2015-2018 ppy Pty. Ltd.
+#    Copyright 2015-2019 ppy Pty. Ltd.
 #
 #    This file is part of osu!web. osu!web is distributed with the hope of
 #    attracting more community contributions to the core ecosystem of osu!.
@@ -127,10 +127,9 @@
         if @props.score.replay
           a
             className: 'simple-menu__item js-login-required--click'
-            href: laroute.route 'users.replay',
-                    beatmap: @props.score.beatmap.id
+            href: laroute.route 'scores.download',
                     mode: @props.score.beatmap.mode
-                    user: @props.score.user_id
+                    score: @props.score.id
             'data-turbolinks': false
             onClick: @toggle
             osu.trans 'users.show.extra.top_ranks.download_replay'


only listen for events if actually open

only listen for events if actually open

--- resources/assets/lib/play-detail-menu.coffee
+++ resources/assets/lib/play-detail-menu.coffee
@@ -32,18 +32,19 @@
       active: false

-  componentDidMount: =>
-    $(document).on "click.#{@uuid}", @hide
-    $(document).on "keyup.#{@uuid}", @hide
+  componentDidUpdate: (_prevProps, prevState) =>
+    return if prevState.active == @state.active

-
-  componentDidUpdate: (_prevProps, prevState) =>
-    if prevState.active != @state.active
-      if @state.active then @props.onShow?() else @props.onHide?()
+    if @state.active
+      $(document).on "click.#{@uuid} keydown.#{@uuid}", @hide
+      @props.onShow?()
+    else
+      $(document).off ".#{@uuid}"
+      @props.onHide?()

   componentWillUnmount: =>
-    $(document).off ".#{@uuid}", @hide
+    $(document).off ".#{@uuid}"

   hide: (e) =>


Disable for now, lets keep conversations with users own name.

--- client/app/Applications/Chat.kdapplication/Views/conversationlistitemtitle.coffee
+++ client/app/Applications/Chat.kdapplication/Views/conversationlistitemtitle.coffee
@@ -2,7 +2,7 @@

   constructor:(options = {}, data)->
     options.cssClass = 'chat-item'
-    data = [nick for nick in data when nick isnt KD.nick()].first
+    # data = [nick for nick in data when nick isnt KD.nick()].first
     super

   viewAppended:->


guest force reload fix

guest force reload fix

--- core/KDWindowController.coffee
+++ core/KDWindowController.coffee
@@ -111,25 +111,8 @@
         if href and not /^#/.test href
           KD.getSingleton('router').handleRoute href

-    window.addEventListener 'beforeunload', @bound "beforeUnload"
-
-    # TODO: this is a kludge we needed.  sorry for this.  Move it someplace better C.T.
-    @utils.wait 15000, =>
-      KD.remote.api.JSystemStatus.on 'forceReload', =>
-        window.removeEventListener 'beforeunload', @bound 'beforeUnload'
-        location.reload()
-
-    # async clientId change checking procedures causes
-    # race conditions between window reloading and post-login callbacks
-    @utils.repeat 1000, do (cookie = $.cookie 'clientId') => =>
-      if cookie? and cookie isnt $.cookie 'clientId'
-        window.removeEventListener 'beforeunload', @bound 'beforeUnload'
-        @emit "clientIdChanged"
-
-        # window location path is set to last route to ensure visitor is not
-        # redirected to another page
-        @utils.defer -> window.location.pathname = KD.getSingleton("router").visitedRoutes.first or "/"
-      cookie = $.cookie 'clientId'
+    unless location.hostname is 'localhost'
+      window.addEventListener 'beforeunload', @bound "beforeUnload"

     document.addEventListener getVisibilityEventName(), (event)=>
       @focusChange event, @isFocused()


multiple browsers can connect simultaneously

--- a.coffee
+++ a.coffee
@@ -5,8 +5,6 @@
 io = require 'socket.io'
 net = require 'net'
 https = require 'https'
-
-debug = 1

 jsFiles = [
   'node_modules/socket.io/node_modules/socket.io-client/socket.io.js'
@@ -25,7 +23,11 @@
 ]

 log = (s) -> console.info process.uptime().toFixed(3) + ' ' + s
+b64 = (s) -> Buffer(s).toString 'base64'
+b64d = (s) -> '' + Buffer s, 'base64'
+getTag = (tagName, xml) -> (///^[^]*<#{tagName}>([^]*)</#{tagName}>[^]*$///.exec xml)?[1]

+# preload files into memory so we can serve them faster
 html = css = js = ''
 do prepareHTML = ->
   html = fs.readFileSync 'index.html', 'utf8'
@@ -39,12 +41,7 @@
 fs.watch 'index.html', prepareHTML
 jsFiles.forEach (f) -> fs.watch f, prepareJS
 cssFiles.forEach (f) -> fs.watch f, prepareCSS
-
 ttf = fs.readFileSync 'apl385.ttf'
-
-b64 = (s) -> Buffer(s).toString 'base64'
-b64d = (s) -> '' + Buffer s, 'base64'
-getTag = (tagName, xml) -> (///^[^]*<#{tagName}>([^]*)</#{tagName}>[^]*$///.exec xml)?[1]

 app = express()
 app.get '/',           (req, res) -> res.header('Content-Type', 'text/html'               ).send html
@@ -58,17 +55,22 @@
 server = https.createServer(httpsOptions, app).listen (httpsPort = 8443),
   -> log "HTTPS server listening on :#{httpsPort}"

+client = net.connect {host: '127.0.0.1', port: 4502}, -> log 'interpreter connected'
+
+toInterpreter = (s) ->
+  log 'to interpreter: ' + JSON.stringify(s)[..1000]
+  console.assert /[\x01-\x7f]*/.test s
+  b = Buffer s.length + 8
+  b.writeInt32BE b.length, 0
+  b.write 'RIDE' + s, 4
+  client.write b
+
+toInterpreter 'SupportedProtocols=1'
+toInterpreter 'UsingProtocol=1'
+toInterpreter '<?xml version="1.0" encoding="utf-8"?><Command><cmd>Identify</cmd><id>0</id><args><Identify><Sender><Process>RIDE.EXE</Process><Proxy>0</Proxy></Sender></Identify></args></Command>'
+
 io.listen(server).on 'connection', (socket) ->
   log 'browser connected'
-  client = net.connect {host: '127.0.0.1', port: 4502}, -> log 'interpreter connected'
-
-  toInterpreter = (s) ->
-    log 'to interpreter: ' + JSON.stringify(s)[..1000]
-    console.assert /[\x01-\x7f]*/.test s
-    b = Buffer s.length + 8
-    b.writeInt32BE b.length, 0
-    b.write 'RIDE' + s, 4
-    client.write b

   toBrowser = (m...) -> log 'to browser: ' + JSON.stringify(m)[..1000]; socket.emit m...

@@ -164,11 +166,7 @@
       </Command>
     """

-  # Send the first few packets immediately to reduce latency
-  toInterpreter 'SupportedProtocols=1'
-  toInterpreter 'UsingProtocol=1'
-  toInterpreter '<?xml version="1.0" encoding="utf-8"?><Command><cmd>Identify</cmd><id>0</id><args><Identify><Sender><Process>RIDE.EXE</Process><Proxy>0</Proxy></Sender></Identify></args></Command>'
   toInterpreter '<?xml version="1.0" encoding="utf-8"?><Command><cmd>Connect</cmd><id>0</id><args><Connect><Token /></Connect></args></Command>'

   client.on 'end', -> log 'interpreter disconnected'; socket.emit 'end'
-  socket.on 'disconnect', -> log 'browser disconnected'; client.end()
+  socket.on 'disconnect', -> log 'browser disconnected'


Fixing the regex in mentions.coffee

Fixing the regex in mentions.coffee

--- app/assets/javascripts/backbone/plugins/mentions.coffee
+++ app/assets/javascripts/backbone/plugins/mentions.coffee
@@ -1,8 +1,8 @@
-# The mentions plugin takes care of highlighting the @useranme and passing the users to the atwho plugin.
-# The show_activities addMessage method is the responsible of changing the look of a message body when a user is mentioned
+# The mentions plugin takes care of highlighting the @username and passing the users to the atwho plugin.
+# The show_activities addMessage method is responsible for changing the look of a message body when a user is mentioned
 class Kandan.Plugins.Mentions
   @options:
-    regex: /@\S*/g
+    regex: /(^|\s)@\S*/gm

     template: _.template '''<%= mention %>'''


[#2] Don't show the no-labels message unless we're pretty sure the user has exhausted them


fix was_source_address_set state & animate better

--- app/assets/javascripts/repository/edit_remote.js.coffee
+++ app/assets/javascripts/repository/edit_remote.js.coffee
@@ -30,6 +30,10 @@
       source_address_el.val().trim().length > 0

     was_source_address_set = is_source_address_set()
+
+    reset_was_source_address_set = () ->
+      was_source_address_set = is_source_address_set()
+
     change_options = (event) ->
       if !was_source_address_set && is_source_address_set()
         modify_access_list 'mirror'
@@ -40,9 +44,9 @@

     change_type_display = (event) ->
       if !was_source_address_set && is_source_address_set()
-        type_el.fadeIn()
+        type_el.stop(true,true).fadeIn({queue: false}).css({display: 'none'}).slideDown()
       else if was_source_address_set && !is_source_address_set()
-        type_el.fadeOut()
+        type_el.stop(true,true).fadeOut({queue: false}).slideUp()
       else if !was_source_address_set && !is_source_address_set()
         type_el.hide()
       else
@@ -53,4 +57,5 @@

     source_address_el.on('input', change_options)
     source_address_el.on('input', change_type_display)
+    source_address_el.on('input', reset_was_source_address_set)
   return


fast commit

fast commit

--- app/assets/javascripts/behaviors/sortable.js.coffee
+++ app/assets/javascripts/behaviors/sortable.js.coffee
@@ -2,9 +2,10 @@
   lastTodoItemPositionsUpdateData: {}

   constructor: ($list) ->
+    updateFunctionName = $list.data('position-update-function')
     $list.sortable(
       connectWith: $list.data('connect-sortable-with')
-      update: @updateTodoItemPositions
+      update: @[updateFunctionName]
       cursor: 'move'
       handle: behaviorSelector('sort_handle')
       axis: 'y'


fixes typo for CNVS-15738

fixes typo for CNVS-15738

Test plan:
- Ensure that " Better File Browsing" feature flag is enabled
- Select the course
- Click on Files from the left navigation panel
- Select Multiple files in the right hand pane
- Download Zip button is displayed in the top
- Verify hover over tool tip text on the button is' Download Zip'

Change-Id: I2ce5664a1dbf89e43d71de34116045692983df1c
Reviewed-on: https://gerrit.instructure.com/41861
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Jason Madsen <bcb5fff571a20f07c35d17ba9c364855c776dce7@instructure.com>
QA-Review: Clare Strong <40d6bb3ed7fef516c73274131d5a837c16de74fd@instructure.com>
Product-Review: Matt Fairbourn <5f353e1c97bb9cc046b9db20beca0b9392f6f1b2@instructure.com>

--- app/coffeescripts/react_files/components/Toolbar.coffee
+++ app/coffeescripts/react_files/components/Toolbar.coffee
@@ -65,7 +65,7 @@
       downloadTitle = if @props.selectedItems.length is 1
         I18n.t('download', 'Download')
       else
-        I18n.t('download_as_zip', 'Downlod as Zip')
+        I18n.t('download_as_zip', 'Download as Zip')

       header {
         className:'ef-header grid-row between-xs'


removed className for now

removed className for now

--- app/assets/javascripts/components/button/index.cjsx
+++ app/assets/javascripts/components/button/index.cjsx
@@ -12,10 +12,6 @@
     name: React.PropTypes.string
     type: React.PropTypes.string
     url: React.PropTypes.string
-    className
-
-  # getDefaultProps: ->
-

   handleClick: (event) ->
     event.preventDefault()
@@ -29,10 +25,10 @@
           console.log "Success, here is data: #{data}"
         error: (jqXHR, textStatus, errorThrown) ->
           console.log "Error in button action:", xhr, textStatus, errorThrown
-
+

   render: ->
-
+


minor enhances to `CierreCaja`

minor enhances to `CierreCaja`

on money-related properties

--- app/assets/javascripts/models/cierre_caja.js.coffee
+++ app/assets/javascripts/models/cierre_caja.js.coffee
@@ -32,7 +32,7 @@
   ).property("efectivoCompras", "ivaCompras", "iceCompras")

   descuadre: (->
-    @get("efectivoReal") - @get("efectivoTeorico")
+    @get("efectivoReal") - money(@get("efectivoTeorico"))
   ).property("efectivoReal")

   hasDescuadre: (->
@@ -48,7 +48,7 @@
     efectivoReal = @get("cashDenominationItems").reduce (prev, cashDenominationItem) ->
       prev + cashDenominationItem.get("totalPrice")
     , 0
-    @set "efectivoReal", efectivoReal
+    @set "efectivoReal", money(efectivoReal)
   ).observes("cashDenominationItems.@each.cantidad")

 # methods


#545 Let user set position [0,0,0]

#545 Let user set position [0,0,0]

--- app/assets/javascripts/oxalis/model/flycam2d.coffee
+++ app/assets/javascripts/oxalis/model/flycam2d.coffee
@@ -221,7 +221,7 @@
   setPositionSilent : (position) ->

     for i in [0..2]
-      if not position[i]
+      if not position[i]?
         position[i] = @position[i]

     @position = position


Show/hide arrows of chapters navigation in Story Info

Closes #127

--- app/frontend/javascripts/views/story-info.js.coffee
+++ app/frontend/javascripts/views/story-info.js.coffee
@@ -4,9 +4,12 @@

 class StoryInfo extends Backbone.View

-  el: '.story-info'
+  el:             '.story-info'
+  chaptersLength: null

   initialize: ->
+    # Get chapters list length
+    @chaptersLength = @$el.find('.chapters-list li').size()
     # Show panel when click story-info btn
     $('.visualization-graph-menu-actions .btn-story-info').click @onBtnStoryInfoClick
     # Hide panel when click close btn
@@ -29,10 +32,17 @@
         description:  @model.get('description')
         #image: if @node.get('image') then @node.get('image').huge.url else null
       }
+      index = parseInt @model.get('number')
       @$el.find('.panel-body .index-content, .panel-heading .index-header').addClass 'hide'
       @$el.find('.panel-body .chapter-content, .panel-heading .chapter-header').removeClass 'hide'
       @$el.find('.panel-body .chapter-content').html template
       @$el.find('.panel-heading .chapter-header .chapter-index').html @model.get('number')
+      # Show/hide prev/next arrows
+      @$el.find('.chapter-navigation').removeClass 'invisible'
+      if index == 1
+         @$el.find('.chapter-navigation-prev').addClass 'invisible'
+      else if index == @chaptersLength
+         @$el.find('.chapter-navigation-next').addClass 'invisible'
     else
       @$el.find('.panel-body .index-content, .panel-heading .index-header').removeClass 'hide'
       @$el.find('.panel-body .chapter-content, .panel-heading .chapter-header').addClass 'hide'
@@ -63,7 +73,6 @@
   onChapterNavigationClick: (e) =>
     e.preventDefault()
     index = if $(e.target).hasClass('chapter-navigation-next') then @model.get('number')+1 else @model.get('number')-1
-    console.log 'go to chapter', @model.get('number'), $(e.target).hasClass('chapter-navigation-next')
     @$el.find('.chapters-list li:nth-child('+index+') a').trigger 'click'

   onChapterNavigationChildrenClick: (e) ->


Use new sphere sprite for bomber

Use new sphere sprite for bomber

--- app/scripts/lazerscripts/stage1/player_clone.coffee
+++ app/scripts/lazerscripts/stage1/player_clone.coffee
@@ -17,11 +17,11 @@
       cooldown: 150
       sightAngle: 20
       projectile: (x, y, angle) =>
-        projectile = Crafty.e('Projectile, Color, Enemy').attr(
+        projectile = Crafty.e('Sphere').attr(
           w: 8
           h: 4
           speed: 600
-        ).color('#FFFF00')
+        )
         projectile.shoot(x, y, angle)
     p


StackTemplateListItem: Move all-backend logic to controller

--- client/app/lib/stacks/stacktemplatelistitem.coffee
+++ client/app/lib/stacks/stacktemplatelistitem.coffee
@@ -1,7 +1,6 @@
 kd                        = require 'kd'
 timeago                   = require 'timeago'
 showError                 = require 'app/util/showError'
-Tracker                   = require 'app/util/tracker'

 BaseStackTemplateListItem = require './basestacktemplatelistitem'
 ForceToReinitModal        = require './forcetoreinitmodal'
@@ -61,54 +60,6 @@
         new kd.NotificationView { title: 'Stack generated successfully' }

-  editStackTemplate: ->
-
-    stackTemplate = @getData()
-
-    if stackTemplate.isDefault
-
-      modal = new kd.ModalView
-        title          : 'Editing default stack template ?'
-        overlay        : yes
-        overlayOptions :
-          cssClass     : 'second-overlay'
-          overlayClick : yes
-        content        : '
-          This stack template is currently used by your team. If you continue
-          to edit, all of your changes will be applied to all team members directly.
-          We highly recommend you to clone this stack template
-          first and work on the cloned version. Once you finish your work,
-          you can easily apply your changes for all team members.
-        '
-        buttons      :
-
-          'Clone and Open Editor':
-            style    : 'solid medium green'
-            loader   : yes
-            callback : =>
-              stackTemplate.clone (err, cloneStackTemplate) =>
-                unless showError err
-                  @_itemCloned()
-                  @_itemSelected cloneStackTemplate
-                  Tracker.track Tracker.STACKS_CLONED_TEMPLATE
-                modal.destroy()
-
-          "I know what I'm doing, Open Editor":
-            style    : 'solid medium red'
-            callback : =>
-              @_itemSelected()
-              modal.destroy()
-              Tracker.track Tracker.STACKS_STARTED_EDIT_DEFAULT
-
-    else
-      @_itemSelected()
-      Tracker.track Tracker.STACKS_STARTED_EDIT
-
-
-  _itemCloned: (data) ->
-    @getDelegate().emit 'ItemCloned', data ? @getData()
-
-
   _itemSelected: (data) ->
     @getDelegate().emit 'ItemSelected', data ? @getData()

@@ -120,7 +71,7 @@

     if not stackTemplate.isDefault and stackTemplate.config.verified
       @addMenuItem 'Apply to Team', ->
-        listView.emit 'ItemSelectedAsDefault', stackTemplate
+        listView.emit 'ItemAction', { action : 'ItemSelectedAsDefault', item : this }

     # temporary comment until stack admin message design is ready
     # if stackTemplate.canForcedReinit


made syntax more readable

made syntax more readable

--- core/app/backbone/views/auto_completes_view.coffee
+++ core/app/backbone/views/auto_completes_view.coffee
@@ -34,7 +34,7 @@
     this.options.mainView.deActivateCurrent()
     key = this.fixKeyModulo(key)

-    if (key < @list.length && key >= 0)
+    if 0 <= key < @list.length
       @list[key].trigger('activate');

       if ( typeof scroll == "boolean")


composite view

composite view

--- lib/generators/marionette/view/templates/app/views/composite_view.js.coffee
+++ lib/generators/marionette/view/templates/app/views/composite_view.js.coffee
@@ -1,4 +1,4 @@
 @Backbone.app.module "Views.<%= @module.split('/').map{ |v| v.camelcase }.join('.') %>", (<%= @module.split('/').map{ |v| v.camelcase }.last.to_s %>, App, Backbone, Marionette, $, _) ->

-  class <%= @module.split('/').map{ |v| v.camelcase }.last.to_s %>.<%= @title.camelcase %> extends App.Views.CollectionView
+  class <%= @module.split('/').map{ |v| v.camelcase }.last.to_s %>.<%= @title.camelcase %> extends App.Views.CompositeView
     template: '<%= @module.underscore %>/<%= @titletemplate.underscore %>'


Fixed property typo in the Related US Controller

A reference to the `.length` property of `@.userstories` was originally misspelled.

--- app/modules/epics/related-userstories/related-userstories-controller.coffee
+++ app/modules/epics/related-userstories/related-userstories-controller.coffee
@@ -30,7 +30,7 @@
         @.showCreateRelatedUserstoriesLightbox = false

     showRelatedUserStoriesSection: () ->
-        return @projectService.hasPermission("view_epics") or @.userstories?.legth > 0
+        return @projectService.hasPermission("view_epics") or @.userstories?.length > 0

     userCanSort: () ->
         return @projectService.hasPermission("modify_epic")


* hasAndBelongsToMany is ordered as received * Include 'unless' option in hasOne relation * Correct progress element show

--- app/assets/javascripts/backbone.rails_store.js.coffee
+++ app/assets/javascripts/backbone.rails_store.js.coffee
@@ -719,7 +719,7 @@

   _doProgress: (xhr) ->
     @_requests.push(xhr)
-    if @_progressCounter <= 0 and @_progressElement
+    if @_progressCounter >= 0 and @_progressElement
       @_progressElement.show()
     @_progressCounter++
     xhr.always =>
@@ -1077,11 +1077,14 @@
       @_hasOneCache = {} unless @_hasOneCache
       @_hasOneCache[@cid] = {col: null, ids: []} unless @_hasOneCache[@cid]
       unless @_hasOneCache[@cid].col
+        if options.remoteRefresh == undefined
+          options.remoteRefresh = 'unless'
+
         if options.remoteRefresh
-          remoteRefresh = true
-        else if options.remoteRefresh == undefined
-          options.remoteRefresh = 'first'
-          remoteRefresh = true
+          if @_hasOneCache[@cid].ids.length and options.remoteRefresh == 'unless'
+            remoteRefresh = false
+          else
+            remoteRefresh = true
         else
           remoteRefresh = false
         relationModelType = _.result(@hasOne, attr)
@@ -1094,7 +1097,7 @@
           hasOneCache: @_hasOneCache
           relationModelType: relationModelType
           attribute: attr
-      else if options.remoteRefresh and options.remoteRefresh != 'first'
+      else if options.remoteRefresh and options.remoteRefresh != 'first' and options.remoteRefresh != 'unless'
         @_hasOneCache[@cid].col.remoteRefresh
           lazyLoad: options.lazyLoad
       else if _.isFunction(options.lazyLoad)
@@ -1222,7 +1225,7 @@
               throw "Valid not yet supported! Please consider reporting this bug with Object type"
           @_hasOneCache = {} unless @_hasOneCache
           @_hasOneCache[@cid] = {col: null, ids: []} unless @_hasOneCache[@cid]
-          @_hasOneCache[@cid].ids.push(id)
+          @_hasOneCache[@cid].ids = [id]
           @_hasOneCache[@cid].col.refresh() if @_hasOneCache[@cid].col
           @trigger("change:#{key}", @)

@@ -1571,6 +1574,8 @@
     @parent.on 'remove', (model) => @_onChildRemove(model)
     @child.on 'remove', (model) => @_onChildRemove(model)
     @child.clear = => @clear()
+    @child.comparator = (model) =>
+      return @relation.subset[@relatedModel.cid].ids.indexOf(model.cid)

   clear: ->
     modelsToRemove = []


WFGH: db controlled campaign status implemented

--- workers/social/lib/social/models/campaigns/wfgh.coffee
+++ workers/social/lib/social/models/campaigns/wfgh.coffee
@@ -1,10 +1,7 @@
-{Model} = require 'bongo'
+JCampaign = require './campaign'
+{Model}  = require 'bongo'

 module.exports = class JWFGH extends Model
-
-  CAP       = 50000
-  PRIZE     = 10000
-  DEADLINE  = new Date 1418626800000 # Mon, 15 Dec 2014 00:00:00 PDT

   {signature, secure} = require 'bongo'
   @share()
@@ -13,6 +10,9 @@
     indexes       :
       username    : 'unique'
       approved    : 'unique'
+    sharedMethods :
+      static      :
+        create    : (signature Object, Function)
     schema        :
       username    :
         type      : String
@@ -35,18 +35,21 @@

     return callback message : 'No username received!'  unless username

-    JWFGH.one {username}, (err, data)->
+    JCampaign.get 'WFGH', (err, campaign) ->

-      return callback err  if err
+      return callback message : 'expired'  if err or not campaign

-      return callback message : 'Already applied'  if data
+      JWFGH.one {username}, (err, data)->

-      application = new JWFGH {username}
+        return callback err  if err

-      application.save (err)->
-        return callback err if err
-        JWFGH.getStats account, callback
+        return callback message : 'Already applied'  if data

+        application = new JWFGH {username}
+
+        application.save (err)->
+          return callback err if err
+          JWFGH.getStats account, callback

   @leave = (account, callback) ->
@@ -56,34 +59,49 @@

   @getStats = (account, callback) ->

-    username = account?.profile?.nickname
+    JCampaign.get 'WFGH', (err, campaign) ->

-    unless username
-      callback null,
-        cap                : CAP
-        prize              : PRIZE
-        deadline           : DEADLINE
-        totalApplicants    : 0
-        approvedApplicants : 0
-        isApplicant        : no
+      return callback message : 'expired'  if err or not campaign

-    JWFGH.one {username}, (err, applied)->
-      return callback err  if err
+      username = account?.profile?.nickname

-      isApplicant = applied?
-      isApproved  = applied?.approved
-      isWinner    = applied?.winner
+      {cap, prize, deadline} = campaign

-      JWFGH.count {}, (err, totalApplicants)->
+      cap      ?= 50000
+      prize    ?= 10000
+      deadline ?= new Date 1418626800000 # Mon, 15 Dec 2014 00:00:00 PDT
+
+      unless username
+
+        callback null, {
+          totalApplicants    : 0
+          approvedApplicants : 0
+          isApplicant        : no
+          deadline
+          prize
+          cap
+        }
+
+      JWFGH.one {username}, (err, applied)->
+
         return callback err  if err

-        JWFGH.count approved : yes, (err, approvedApplicants)->
+        isApplicant = applied?
+        isApproved  = applied?.approved
+        isWinner    = applied?.winner
+
+        JWFGH.count {}, (err, totalApplicants)->
+
           return callback err  if err

-          callback err, {
-            cap      : CAP
-            prize    : PRIZE
-            deadline : DEADLINE
-            totalApplicants, approvedApplicants
-            isApplicant, isApproved, isWinner
-          }+          JWFGH.count approved : yes, (err, approvedApplicants)->
+
+            return callback err  if err
+
+            callback err, {
+              cap      : CAP
+              prize    : PRIZE
+              deadline : DEADLINE
+              totalApplicants, approvedApplicants
+              isApplicant, isApproved, isWinner
+            }


Handle undefined variable exception.

Handle undefined variable exception.

--- app/assets/javascripts/voluntary/dom_manipulation/competitive_list.js.coffee
+++ app/assets/javascripts/voluntary/dom_manipulation/competitive_list.js.coffee
@@ -170,7 +170,7 @@
     window.matchesWon[loserId] = window.matchesWon[loserId] - 1
     window.outmatchedCompetitorsByCompetitor[winnerId] ||= []
     window.outmatchedCompetitorsByCompetitor[winnerId] = window.Voluntary.DomManipulation.CompetitiveList.removeItemFromArray(window.outmatchedCompetitorsByCompetitor[winnerId], loserId)
-    window.defeatedCompetitorsByCompetitor[otherLoserId] = window.Voluntary.DomManipulation.CompetitiveList.removeItemFromArray(window.outmatchedCompetitorsByCompetitor[loserId], winnerId)
+    window.defeatedCompetitorsByCompetitor[loserId] = window.Voluntary.DomManipulation.CompetitiveList.removeItemFromArray(window.outmatchedCompetitorsByCompetitor[loserId], winnerId)

   @defeatedCompetitorsByCompetitor: (competitorId) ->
     window.defeatedCompetitorsByCompetitor[competitorId] ||= []


Don't allow to start collaboration when the mounted machine isn't running.

--- client/ide/lib/views/statusbar/idestatusbar.coffee
+++ client/ide/lib/views/statusbar/idestatusbar.coffee
@@ -16,8 +16,6 @@

     super options, data

-    {appManager} = kd.singletons
-
     @participantAvatars = {}

     @on 'ShowAvatars',          @bound 'showAvatars'
@@ -29,7 +27,7 @@
     @on 'ParticipantWatched',   @bound 'decorateWatchedAvatars'
     @on 'ParticipantUnwatched', @bound 'decorateUnwatchedAvatars'

-    { mainController, router } = kd.singletons
+    { mainController, router, appManager } = kd.singletons
     collabDisabled = mainController.isFeatureDisabled 'collaboration'

     @addSubView @status = new KDCustomHTMLView cssClass : 'status'
@@ -63,9 +61,11 @@
       href     : "#{kd.singletons.router.getCurrentPath()}/share"
       title    : 'Loading'
       cssClass : 'share fr hidden'
-      click    : (event) ->
+      click    : =>
         kd.utils.stopDOMEvent event
         return  if @hasClass 'loading'
+        return  unless appManager.frontApp.mountedMachine.isRunning()
+
         appManager.tell 'IDE', 'showChat'  unless collabDisabled

     @addSubView @avatars = new KDCustomHTMLView cssClass : 'avatars fr'


notification buckets; critic emails.

notification buckets; critic emails.

--- client/landing/app/CommonViews/messagesList.coffee
+++ client/landing/app/CommonViews/messagesList.coffee
@@ -45,8 +45,9 @@
     console.log 'im kule', currentDelegate
     currentDelegate.fetchActivityTeasers? {
       targetName: $in: [
-        'CReplierBucketActivity'
-        # 'CReplieeBucketActivity'
+        'CReplieeBucketActivity'
+        'CFolloweeBucketActivity'
+        'CLikeeBucketActivity'
       ]
     }, {
       options:
@@ -54,11 +55,10 @@
         sort:
           timestamp: -1
     }, (err, items)=>
-      console.log 'bitch please', arguments
       if err
         warn "There was a problem fetching notifications!",err
       else
-        @instantiateListItems items
+        #@instantiateListItems items
         @propagateEvent KDEventType : 'NotificationCountDidChange', {count : items.length}
         callback? items


Fix failing e2e

Fix failing e2e

--- angular/test/protractor/poll_spec.coffee
+++ angular/test/protractor/poll_spec.coffee
@@ -66,7 +66,7 @@
     page.fillIn '.poll-proposal-form__details', 'Some details'
     page.click '.poll-common-form__submit'

-    page.click '.poll-common-share-form__ok'
+    page.click '.modal-cancel'
     page.expectText '.poll-common-summary-panel__title', 'A new proposal'
     page.expectText '.poll-common-summary-panel__details', 'Some details'


activity feed: switch global vars to properties of appController

--- client/landing/app/Applications/Activity.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Activity.kdapplication/AppController.coffee
@@ -14,10 +14,8 @@
       # 'CCodeShareActivity'
     ]

-  lastTo    = null
-  lastFrom  = null
-  aRange    = 2*60*60*1000
-  isLoading = no
+  # unused
+  aRange = 2*60*60*1000

   @clearQuotes = clearQuotes = (activities)->

@@ -43,6 +41,7 @@

     super options

+    @isLoading         = no
     @currentFilter     = activityTypes
     @appStorage        = new AppStorage 'Activity', '1.0'
     activityController = @getSingleton('activityController')
@@ -62,8 +61,9 @@

   resetList:->

-    lastFrom = null
-    lastTo   = null
+    delete @lastTo   = null
+    delete @lastFrom = null
+
     @listController.removeAllItems()

   setFilter:(type) -> @currentFilter = if type? then [type] else activityTypes
@@ -106,19 +106,19 @@
   extractTeasersTimeStamps:(teasers)->

     teasers  = _.compact(teasers)
-    lastTo   = teasers.first.meta.createdAt
-    lastFrom = teasers.last.meta.createdAt
+    @lastTo   = teasers.first.meta.createdAt
+    @lastFrom = teasers.last.meta.createdAt

   # Store first & last cache activity timestamp.
   extractCacheTimeStamps: (cache)->

-    lastTo   = cache.to
-    lastFrom = cache.from
+    @lastTo   = cache.to
+    @lastFrom = cache.from

   populateActivity:(options = {})->

-    return if isLoading
-    isLoading = yes
+    return if @isLoading
+    @isLoading = yes
     @listController.showLazyLoader()
     @listController.noActivityItem.hide()

@@ -129,7 +129,7 @@
         options = to : options.to or Date.now()

         @fetchActivity options, (err, teasers)=>
-          isLoading = no
+          @isLoading = no
           @listController.hideLazyLoader()
           if err or teasers.length is 0
             warn err
@@ -140,7 +140,7 @@

       else
         @fetchCachedActivity options, (err, cache)=>
-          isLoading = no
+          @isLoading = no
           if err or cache.length is 0
             warn err
             @listController.hideLazyLoader()
@@ -219,7 +219,7 @@

   continueLoadingTeasers:->

-    lastTimeStamp = (new Date lastFrom).getTime()
+    lastTimeStamp = (new Date @lastFrom).getTime()
     @populateActivity {slug : "before/#{lastTimeStamp}", to: lastTimeStamp}

   teasersLoaded:->


white space removed

white space removed

--- client/landing/app/MainApp/filetree/controllers/findertreecontroller.coffee
+++ client/landing/app/MainApp/filetree/controllers/findertreecontroller.coffee
@@ -8,52 +8,52 @@
 class NFinderTreeController extends JTreeViewController

   constructor:->
-
-    super
-
+
+    super
+
     if @getOptions().contextMenu
       @contextMenuController = new NFinderContextMenuController

-      @listenTo
+      @listenTo
         KDEventTypes       : "ContextMenuItemClicked"
         listenedToInstance : @contextMenuController
         callback           : (pubInst, {fileView, contextMenuItem})=>
           @contextMenuItemSelected fileView, contextMenuItem
     else
       @getView().setClass "no-context-menu"
-
+
     @getSingleton('mainController').on "NewFileIsCreated", (newFile)=> @navigateToNewFile newFile
-
+

   addNode:(nodeData, index)->
-
+
     o = @getOptions()
     return if o.foldersOnly and nodeData.type is "file"
     # @setFileListeners nodeData if o.fsListeners
     item = super nodeData, index

   setItemListeners:(view, index)->
-
-    super
-
+
+    super
+
     @setFileListeners view.getData()
-    #
-    # view.on "folderNeedsToRefresh", (newFile)=>
-    #
+    #
+    # view.on "folderNeedsToRefresh", (newFile)=>
+    #
     #   @navigateTo newFile.parentPath, =>
     #     @selectNode @nodes[newFile.path]
     #     @openFile @nodes[newFile.path]
-
+
   listenedPaths: {}
-
+
   setFileListeners:(file)->
-
+
     unless @listenedPaths[file.path]
       file.on "folderNeedsToRefresh", (newFile)=>
         @navigateTo newFile.parentPath, =>
           @selectNode @nodes[newFile.path]
         @listenedPaths[file.path] = file.path
-
+

   navigateToNewFile:(newFile)=>

@@ -68,14 +68,14 @@
       #   @addNode newFile, index

       @selectNode @nodes[newFile.path]
-
-
-
-    # #
+
+
+
+    # #
     # # file.on "fs.saveAs.finished", (newFile, oldFile)=>
-    #
+    #
     #   log "fs.saveAs.finished", "+>>>>>"
-    #
+    #
     #   parentNode = @nodes[path]
     #   if parentNode
     #     if parentNode.expanded
@@ -84,11 +84,11 @@
     #     else
     #       @expandFolder @nodes[parentPath], =>
     #         @selectNode @nodes[path]
-
+
     # file.on "fs.remotefile.created", (oldPath)=>
     #   tc = @treeController
     #   parentNode = tc.nodes[file.parentPath]
-    #
+    #
     #   if parentNode
     #     if parentNode.expanded
     #       tc.refreshFolder tc.nodes[file.parentPath], ->
@@ -100,17 +100,17 @@
     #   delete @aceViews[oldPath]
     #   log "put", file.path
     #   @aceViews[file.path]
-
-
+
+
   ###
   FINDER OPERATIONS
   ###
-
+
   openItem:(nodeView, callback)->

     options  = @getOptions()
     nodeData = nodeView.getData()
-
+
     switch nodeData.type
       when "folder", "mount"
         @toggleFolder nodeView, callback
@@ -119,7 +119,7 @@
         @emit "file.opened", nodeData

   openFile:(nodeView, event)->
-
+
     return unless nodeView
     file = nodeView.getData()
     appManager.openFileWithApplication file, "Ace"
@@ -133,38 +133,38 @@
       appManager.notify "File must be under: /#{nickname}/Sites/#{nickname}.#{location.hostname}/website/"
     else
       appManager.openFileWithApplication publicPath, "Viewer"
-
+
   refreshFolder:(nodeView, callback)->
-
+
     @notify "Refreshing..."
     folder = nodeView.getData()
     folder.emit "fs.nothing.finished", [] # in case of refresh to stop the spinner
-
+
     @collapseFolder nodeView, =>
       @expandFolder nodeView, =>
         notification.destroy()
         callback?()
-
+
   toggleFolder:(nodeView, callback)->
-
+
     if nodeView.expanded then @collapseFolder nodeView, callback else @expandFolder nodeView, callback
-
+
   expandFolder:(nodeView, callback)->
-
+
     return unless nodeView
     return if nodeView.isLoading

     if nodeView.expanded
       callback? nodeView
       return
-
+
     cb = @utils.getCancellableCallback (files)=>
       @utils.killWait folder.failTimer
       nodeView.expand()
       @addNodes files
       callback? nodeView
       @emit "folder.expanded", nodeView.getData()
-
+
     folder = nodeView.getData()

     folder.failTimer = @utils.wait 5000, =>
@@ -173,15 +173,15 @@
       cb.cancel()

     folder.fetchContents cb
-
+
   collapseFolder:(nodeView, callback)->
-
+
     return unless nodeView
     nodeData = nodeView.getData()
     {path} = nodeData
-
+
     @emit "folder.collapsed", nodeData
-
+
     if @listControllers[path]
       @listControllers[path].getView().collapse =>
         @removeChildNodes path
@@ -190,11 +190,11 @@
     else
       nodeView.collapse()
       callback? nodeView
-
+
   navigateTo:(path, callback)->
-
+
     return unless path
-
+
     path = path.split('/')
     path.shift()  if path[0] is ''
     path.pop()    if path[path.length-1] is ''
@@ -210,17 +210,17 @@
         @refreshFolder @nodes[nextPath], =>
           callback?()
         return
-
-      @expandFolder @nodes[nextPath], =>
+
+      @expandFolder @nodes[nextPath], =>
         lastPath = nextPath
         _expand path

     _expand path

   confirmDelete:(nodeView, event)->
-
+
     if @selectedNodes.length > 1
-      new NFinderDeleteDialog {},
+      new NFinderDeleteDialog {},
         items     : @selectedNodes
         callback  : (confirmation)=>
           @deleteFiles @selectedNodes if confirmation
@@ -231,7 +231,7 @@
         @deleteFiles [nodeView] if confirmation
         @setKeyView()
         @beingEdited = null
-
+
   deleteFiles:(nodes, callback)->

     stack = []
@@ -249,7 +249,7 @@

   showRenameDialog:(nodeView)->
-
+
     @beingEdited = nodeView
     nodeData = nodeView.getData()
     oldPath = nodeData.path
@@ -261,19 +261,19 @@
           delete @nodes[oldPath]
           @nodes[nodeView.getData().path] = nodeView
           nodeView.childView.render()
-
+
       @setKeyView()
       @beingEdited = null
-
+
   createFile:(nodeView, type = "file")->
-
+
     @notify "creating a new #{type}!"
     nodeData = nodeView.getData()
     parentPath = if nodeData.type is "file"
       nodeData.parentPath
     else
       nodeData.path
-
+
     path = "#{parentPath}/New#{type.capitalize()}#{if type is 'file' then '.txt' else ''}"

     FSItem.create path, type, (err, file)=>
@@ -286,12 +286,12 @@

   moveFiles:(nodesToBeMoved, targetNodeView, callback)->
-
+
     targetItem = targetNodeView.getData()
     if targetItem.type is "file"
       targetNodeView = @nodes[targetNodeView.getData().parentPath]
       targetItem = targetNodeView.getData()
-
+
     stack = []
     nodesToBeMoved.forEach (node)=>
       stack.push (callback) =>
@@ -309,12 +309,12 @@
     async.parallel stack, callback

   copyFiles:(nodesToBeCopied, targetNodeView, callback)->
-
+
     targetItem = targetNodeView.getData()
     if targetItem.type is "file"
       targetNodeView = @nodes[targetNodeView.getData().parentPath]
       targetItem = targetNodeView.getData()
-
+
     stack = []
     nodesToBeCopied.forEach (node)=>
       stack.push (callback) =>
@@ -329,9 +329,9 @@
       @refreshFolder targetNodeView

     async.parallel stack, callback
-
+
   duplicateFiles:(nodes, callback)->
-
+
     stack = []
     nodes.forEach (node)=>
       stack.push (callback) =>
@@ -351,18 +351,18 @@
       @refreshFolder parentNode for parentNode in parentNodes

     async.parallel stack, callback
-
+
   compressFiles:(nodeView, type)->
-
+
     file = nodeView.getData()
     FSItem.compress file, type, (err, response)=>
       if err then @notify null, null, err
       else
         @notify "#{file.type.capitalize()} compressed!", "success"
         @refreshFolder @nodes[file.parentPath]
-
+
   extractFiles:(nodeView)->
-
+
     file = nodeView.getData()
     FSItem.extract file, (err, response)=>
       if err then @notify null, null, err
@@ -370,9 +370,9 @@
         @notify "#{file.type.capitalize()} extracted!", "success"
         @refreshFolder @nodes[file.parentPath], =>
           @selectNode @nodes[response.path]
-
+
   compileApp:(nodeView, callback)->
-
+
     folder = nodeView.getData()
     folder.emit "fs.compile.started"
     name = FSHelper.trimExtension folder.path
@@ -381,35 +381,35 @@
       folder.emit "fs.compile.finished"
       @notify "App compiled!", "success"
       callback?()
-      @utils.wait 500, =>
+      @utils.wait 500, =>
         @refreshFolder nodeView, =>
           @utils.wait =>
             @selectNode @nodes["#{folder.path}/index.js"]
-
+
   publishApp:(nodeView)->
-
+
     folder               = nodeView.getData()
     name                 = FSHelper.trimExtension folder.path
     kodingAppsController = @getSingleton('kodingAppsController')
     kiteController       = @getSingleton('kiteController')

     folder.emit "fs.publish.started"
-
+
     kodingAppsController.getApp name, (appScript)=>
-
+
       log "got the app", name
       manifest    = KodingAppsController.apps[name]
       {nickname}  = KD.whoami().profile
       publishPath = FSHelper.escapeFilePath "/opt/Apps/#{nickname}/#{manifest.name}/#{manifest.version}"
-
+
       log "trying to publish"
-      log options =
+      log options =
         toDo          : "publishApp"
         withArgs      :
           version     : manifest.version
           appName     : manifest.name
           userAppPath : "#{folder.path}/index.js"
-
+
       kiteController.run options, (err, res)=>
         log "publish finished", err, res
         if err then warn err
@@ -417,8 +417,8 @@
           log res
           folder.emit "fs.publish.finished"
           @notify "App published!", "success"
-
-
+
+

   ###
   CONTEXT MENU OPERATIONS
@@ -449,69 +449,69 @@
   ###
   CONTEXT MENU CREATE/MANAGE
   ###
-
+
   createContextMenu:(nodeView, event)->
-
+
     event.stopPropagation()
     event.preventDefault()
     return if nodeView.beingDeleted or nodeView.beingEdited
-
+
     if nodeView in @selectedNodes
       contextMenu = @contextMenuController.getContextMenu @selectedNodes, event
-    else
+    else
       @selectNode nodeView
       contextMenu = @contextMenuController.getContextMenu [nodeView], event
     no
-
+
   contextMenuItemSelected:(nodeView, contextMenuItem)->
-
+
     {action} = contextMenuItem.getData()
     if action
       # return false if you don't want contextmenu to disappear
       shouldDestroy = @["contextMenuOperation#{action.capitalize()}"]? nodeView, contextMenuItem
       if shouldDestroy isnt no
         @contextMenuController.destroyContextMenu()
-
+
   ###
   RESET STATES
   ###
-
+
   resetBeingEditedItems:->
-
+
     @beingEdited.resetView()
-
+
   organizeSelectedNodes:(listController, nodes, event = {})->
-
+
     @resetBeingEditedItems() if @beingEdited
     super

   ###
   DND UI FEEDBACKS
   ###
-
+
   showDragOverFeedback:(nodeView, event)-> super
-
+
   clearDragOverFeedback:(nodeView, event)-> super
-
+
   clearAllDragFeedback:-> super
-
+
   ###
   HANDLING MOUSE EVENTS
   ###
-
+
   click:(nodeView, event)->
-
+
     if $(event.target).is ".chevron-arrow"
       @contextMenu nodeView, event
       return no
     super
-
+
   dblClick:(nodeView, event)->

     @openItem nodeView

   contextMenu:(nodeView, event)->
-
+
     if @getOptions().contextMenu
       @createContextMenu nodeView, event

@@ -526,7 +526,7 @@

   lastEnteredNode = null
   dragEnter: (nodeView, event)->
-
+
     return nodeView if lastEnteredNode is nodeView or nodeView in @selectedNodes
     lastEnteredNode = nodeView
     clearTimeout @expandTimeout
@@ -534,18 +534,18 @@
       @expandTimeout = setTimeout (=> @expandFolder nodeView), 800
     @showDragOverFeedback nodeView, event
     e = event.originalEvent
-
+
     if @boundaries.top > e.pageY > @boundaries.top + 20
       log "trigger top scroll"

     if @boundaries.top + @boundaries.height < e.pageY < @boundaries.top + @boundaries.height + 20
       log "trigger down scroll"
-
+
     super

   dragLeave: (nodeView, event)->
-
+
     @clearDragOverFeedback nodeView, event
     super

@@ -556,13 +556,13 @@
     super

   drop: (nodeView, event)->
-
+
     return if nodeView in @selectedNodes
-
+
     sameParent = no
     @selectedNodes.forEach (selectedNode)->
       sameParent = yes if selectedNode.getData().parentPath is nodeView.getData().parentPath
-
+
     return if sameParent

     if event.altKey
@@ -579,9 +579,9 @@
   keyEventHappened:(event)->

     super
-
+
   performDownKey:(nodeView, event)->
-
+
     if event.altKey
       offset = nodeView.$('.chevron-arrow').offset()
       event.pageY = offset.top
@@ -589,28 +589,28 @@
       @contextMenu nodeView, event
     else
       super
-
+
   performBackspaceKey:(nodeView, event)->

     event.preventDefault()
     event.stopPropagation()
     @confirmDelete nodeView, event
     no
-
+
   performEnterKey:(nodeView, event)->

     @selectNode nodeView
     @openItem nodeView

   performRightKey:(nodeView, event)->
-
-    {type} = nodeView.getData()
+
+    {type} = nodeView.getData()
     if /mount|folder/.test type
       @expandFolder nodeView
-
+
   performUpKey:(nodeView, event)-> super
-  performLeftKey:(nodeView, event)->
-
+  performLeftKey:(nodeView, event)->
+
     if nodeView.expanded
       @collapseFolder nodeView
       return no
@@ -624,16 +624,16 @@
   notification = null

   notify:(msg, style, details)->
-
+
     return unless @getView().parent?

     notification.destroy() if notification
-
+
     if details and not msg? and /Permission denied/.test details
       msg = "Permission denied!"
-
+
     style or= 'error' if details
-
+
     notification = new KDNotificationView
       title     : msg or "Something went wrong"
       type      : "mini"
@@ -655,4 +655,4 @@
           details.on 'ReceivedClickElsewhere', =>
             @getSingleton('windowController').removeLayer @mainInputTabs
             details.destroy()
-
+


Destroy when tag deleted

Destroy when tag deleted

--- client/app/CommonViews/linkviews/taglinkview.coffee
+++ client/app/CommonViews/linkviews/taglinkview.coffee
@@ -11,6 +11,9 @@
         offset    : 1
     super options, data

+    data.on? "TagIsDeleted", =>
+      @destroy()
+
     @setClass "ttag expandable"
     @unsetClass "expandable" unless options.expandable


Sorts report tables by description

Sorts report tables by description

--- app/assets/javascripts/data-tables-init.coffee
+++ app/assets/javascripts/data-tables-init.coffee
@@ -30,7 +30,7 @@

     options =
       responsive: true
-      order: [[0, "desc"]]
+      order: [[0, "asc"]]
       pageLength: 25
       fnFooterCallback: fnFooterCallback


Better messaging for saving/deleting entries

--- client/source/controllers/buckets_controller.coffee
+++ client/source/controllers/buckets_controller.coffee
@@ -81,9 +81,9 @@

         @listenToOnce @entry, 'sync', (entry, newData) =>
           if newData._id
-            toastr.success 'Entry saved'
+            toastr.success "You saved “#{entry.get('title')}”"
           else
-            toastr.success 'Entry deleted'
+            toastr.success "You deleted “#{entry.get('title')}”"

           @redirectTo 'buckets#listEntries', slug: bucket.get('slug')


Fix bad merge

Fix bad merge

--- app/assets/javascripts/photo_overlay.js.coffee
+++ app/assets/javascripts/photo_overlay.js.coffee
@@ -83,14 +83,3 @@

   setCommentPaneHeight: =>
     @setMaskHeight()
-
-$ ->
-  $(".fancybox").fancybox
-    caption:
-      type: 'inside'
-    afterLoad: ->
-      @captionText = @title
-      @title = ''
-      loadPlusOneButton(this)
-      loadCaptionForm(this)
-      loadMessagesContainer()


Fixes container map display on animal show view.

--- app/assets/javascripts/visualization.js.coffee
+++ app/assets/javascripts/visualization.js.coffee
@@ -471,7 +471,7 @@
     mapElement.data("refreshTimeout", timeoutId)

   $(document).ready $.loadVisualizations
-  $(document).on "page:load cocoon:after-insert cell:load", $.loadVisualizations
+  $(document).on "page:load cocoon:after-insert cell:load dialog:show", $.loadVisualizations

 ) visualization, jQuery


chat: list fetched messages immediately [#78432058]

--- client/Social/Activity/views/privatemessage/pane.coffee
+++ client/Social/Activity/views/privatemessage/pane.coffee
@@ -207,6 +207,13 @@
       else nextSibling.unsetClass 'consequent'
     else if nextSibling
       nextSibling.unsetClass 'consequent'
+
+
+  appendMessageDeferred: (item) ->
+    # Super method defers adding list items to minimize page load
+    # congestion. This function is overrides super function to render
+    # all conversation messages to be displayed at the same time
+    @appendMessage item

   fetch: (options = {}, callback) ->


minor

minor

--- client/app/MainApp/maincontroller/maincontroller.coffee
+++ client/app/MainApp/maincontroller/maincontroller.coffee
@@ -32,7 +32,6 @@
     KD.registerSingleton "vmController",              new VirtualizationController
     KD.registerSingleton "contentDisplayController",  new ContentDisplayController
     KD.registerSingleton "notificationController",    new NotificationController
-    KD.registerSingleton "paymentController",         new NotificationController
     KD.registerSingleton "linkController",            new LinkController
     KD.registerSingleton 'router',           router = new KodingRouter location.pathname


cookie removal interval taken to main controller

--- client/app/MainApp/maincontroller/maincontroller.coffee
+++ client/app/MainApp/maincontroller/maincontroller.coffee
@@ -40,8 +40,7 @@
     KD.registerSingleton "paymentController",         new PaymentController
     KD.registerSingleton "linkController",            new LinkController
     KD.registerSingleton 'router',           router = new KodingRouter location.pathname
-
-    KD.registerSingleton "localStorageController", new LocalStorageController
+    KD.registerSingleton "localStorageController",    new LocalStorageController
     # KD.registerSingleton "fatih", new Fatih

     appManager.create 'Groups', (groupsController)->
@@ -52,9 +51,9 @@

     @ready =>
       router.listen()
-      KD.registerSingleton "activityController",   new ActivityController
-      KD.registerSingleton "appStorageController", new AppStorageController
-      KD.registerSingleton "kodingAppsController", new KodingAppsController
+      KD.registerSingleton "activityController",      new ActivityController
+      KD.registerSingleton "appStorageController",    new AppStorageController
+      KD.registerSingleton "kodingAppsController",    new KodingAppsController
       @showInstructionsBookIfNeeded()
       @emit 'AppIsReady'

@@ -106,6 +105,26 @@

     # @on 'pageLoaded.as.(loggedIn|loggedOut)', (account)=>
     #   log "pageLoaded", @isUserLoggedIn()
+
+    # TODO: this is a kludge we needed.  sorry for this.  Move it someplace better C.T.
+    wc = @getSingleton 'windowController'
+    @utils.wait 15000, ->
+      KD.remote.api?.JSystemStatus.on 'forceReload', ->
+        window.removeEventListener 'beforeunload', wc.bound 'beforeUnload'
+        location.reload()
+
+    # async clientId change checking procedures causes
+    # race conditions between window reloading and post-login callbacks
+    @utils.repeat 1000, do (cookie = $.cookie 'clientId') => =>
+      if cookie? and cookie isnt $.cookie 'clientId'
+        window.removeEventListener 'beforeunload', wc.bound 'beforeUnload'
+        @emit "clientIdChanged"
+
+        # window location path is set to last route to ensure visitor is not
+        # redirected to another page
+        @utils.defer -> window.location.pathname = KD.getSingleton("router").visitedRoutes.first or "/"
+      cookie = $.cookie 'clientId'
+

   # some day we'll have this :)


remove unused actions

remove unused actions

--- app/controllers/applications_controller.coffee
+++ app/controllers/applications_controller.coffee
@@ -32,41 +32,3 @@
             send rows: apps

-
-## Debug, to delete
-
-
-# Clear all DB data (development helper).
-action 'clean', ->
-    destroyApplications = () ->
-        Application.destroyAll (error) ->
-             if error
-                 send error: "Cleaning DB failed."
-             else
-               send success: "All applications are removed."
-
-    destroyUsers = ->
-        User.destroyAll (error) ->
-            if error
-                send error: "Cleaning DB failed."
-            else
-                destroyApplications()
-
-    destroyUsers()
-
-
-
-# Initialize DB data (development helper).
-action 'init', ->
-    create_app = ->
-        app = new Application(name: "Noty plus", state: "installed", index: 0, slug: "noty-plus")
-
-        app.save (error) ->
-            if error
-                send error: "Initialization failed."
-            else
-                send success: "Initialization succeeds."
-
-    create_app()
-
-


set right property and add attribution div to .bk-canvas-events instead of .bk-canvas-overlays for z-index issues

--- bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
+++ bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
@@ -38,8 +38,7 @@
       else
         border_width = @map_plot.get('outline_line_width').value
         bottom_offset = @map_plot.get('min_border_bottom') + border_width
-        right_offset = @map_plot.get('min_border_right') + border_width
-        right_offset = @map_plot.get('min_border_right') + border_width
+        right_offset = @map_frame.get('right') - @map_frame.get('width')
         max_width = @map_frame.get('width') - border_width
         @attributionEl = $('<div>')
           .html(attribution)
@@ -54,7 +53,7 @@
             'font-family': 'sans-serif'
           })

-        overlays = @plot_view.$el.find('div.bk-canvas-overlays')
+        overlays = @plot_view.$el.find('div.bk-canvas-events')
         @attributionEl.appendTo(overlays)

   _map_data: () ->


removed legacy 'self' code

removed legacy 'self' code

--- core/app/backbone/views/facts/fact_tabs_view.coffee
+++ core/app/backbone/views/facts/fact_tabs_view.coffee
@@ -11,19 +11,18 @@
     @initFactRelationsViews()

   renderAddToChannel: ->
-    self = this
     add_el = ".tab-content .add-to-channel .dropdown-container .wrapper .add-to-channel-container"
     if @$(add_el).length > 0 and typeof currentUser isnt "undefined" and ("addToChannelView" not of this)
       addToChannelView = new AutoCompletedAddToChannelView(el: @$(add_el)[0])
       _.each @model.getOwnContainingChannels(), (ch) ->
         addToChannelView.collection.add ch  if ch.get("type") is "channel"

-      addToChannelView.on "addChannel", (channel) ->
-        self.model.addToChannel channel, {}
+      addToChannelView.on "addChannel", (channel) =>
+        @model.addToChannel channel, {}

-      addToChannelView.on "removeChannel", (channel) ->
-        self.model.removeFromChannel channel, {}
-        self.model.collection.remove self.model  if window.currentChannel and currentChannel.get("id") is channel.get("id")
+      addToChannelView.on "removeChannel", (channel) =>
+        @model.removeFromChannel channel, {}
+        @model.collection.remove @model  if window.currentChannel and currentChannel.get("id") is channel.get("id")

       addToChannelView.render()
       @addToChannelView = addToChannelView


Remove debug logs

Remove debug logs

--- app/src/tasks/transaction_consumer_task.coffee
+++ app/src/tasks/transaction_consumer_task.coffee
@@ -217,9 +217,7 @@
       tx.inputs = inputs
       tx.outputs = outputs
       isSending = no
-      l transaction
       if _(inputs).chain().some((i) -> _(i.accounts).some((a) -> a?.index is account.getId())).value()
-        l "IS SENDING"
         isSending = yes
         operation = Operation.fromSend(tx, account)
         ledger.app.emit (if operation.isInserted() then 'wallet:operations:update' else 'wallet:operations:new'), [operation]
@@ -229,14 +227,11 @@
       isReception =
         _(outputs).chain().some(
           (o) ->
-            l "ITERATING ", o
             a = _(o.accounts).some((a) -> a?.index is account.getId()) and !_(o.nodes).chain().compact().every((n) -> n[1] is 1).value()
             b = !isSending and _(o.accounts).some((a) -> a?.index is account.getId())
-            l "RESULT FOR ", o, (a or b), a, b
             a or b
         ).value()
       if isReception
-        l "IS RECEPTION"
         operation = Operation.fromReception(tx, account)
         ledger.app.emit (if operation.isInserted() then 'wallet:operations:update' else 'wallet:operations:new'), [operation]
         operation.save()


refactoring for coffee

refactoring for coffee

--- app/assets/javascripts/components/base_component.coffee
+++ app/assets/javascripts/components/base_component.coffee
@@ -1,2 +1,2 @@
 class @BaseComponent extends React.Component
-  shouldComponentUpdate: (nextProps, nextState) -> CheckComponentUpdate(@props, nextProps, @state, nextState)
+  shouldComponentUpdate: (nextProps, nextState) -> CheckComponentUpdate @props, nextProps, @state, nextState


Fix class name

Fix class name

Not used anyway, but we might as well be precise

--- app/assets/javascripts/components/overview/details.cjsx
+++ app/assets/javascripts/components/overview/details.cjsx
@@ -122,7 +122,7 @@
       else 'None'

       subject = (
-

+

           Subject: {@props.course.subject}

       )


Time-selector for test_time

Time-selector for test_time

--- app/assets/javascripts/diabetic_toolbox/readings.coffee
+++ app/assets/javascripts/diabetic_toolbox/readings.coffee
@@ -1,3 +1,11 @@
 # Place all the behaviors and hooks related to the matching controller here.
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://coffeescript.org/
+
+$ ->
+  if $('#test-time-picker').length
+    $('#test-time-picker').datetimepicker format: 'LT'
+    $('#test-time-picker, #test-time-addon').on 'click', () ->
+      $('#test-time-picker').data('DateTimePicker').toggle()
+      true
+  true


have the static region gain focus

have the static region gain focus

--- app/assets/javascripts/mercury/regions/static.js.coffee
+++ app/assets/javascripts/mercury/regions/static.js.coffee
@@ -22,18 +22,20 @@
       @focus()

     Mercury.on 'action', (event, options) =>
-      return if @previewing
+      return if @previewing || Mercury.region != @
       @execCommand(options.action, options) if options.action

     @element.on 'mouseenter', (event) =>
-      return if @previewing
+      @focus()
+      return if @previewing || Mercury.region != @
+      Mercury.trigger('region:focused', {region: @})
       snippet = jQuery(event.target).closest('[data-snippet]')
       if snippet.length
         @snippet = snippet
         Mercury.trigger('show:staticToolbar', {type: 'snippet', snippet: @snippet}) if @snippet.data('snippet')

     @element.on 'mouseleave', (event) =>
-      return if @previewing
+      return if @previewing || Mercury.region != @
       Mercury.trigger('hide:staticToolbar', {type: 'snippet', immediately: false})

@@ -42,6 +44,11 @@
       @element.sortable('destroy')
       @element.removeClass('focus')
     super
+
+
+  focus: ->
+    Mercury.region = @
+    @element.addClass('focus')

   execCommand: (action, options = {}) ->


More docs for CS

More docs for CS

--- app/assets/javascripts/danthes.js.coffee
+++ app/assets/javascripts/danthes.js.coffee
@@ -1,9 +1,26 @@
+# Danthes Privat pub/sub Faye wrapper
+#
+# @example Howto enable debug
+#   Danthes.debug = true
+# @example reset all internal data
+#   Danthes.reset()
+# @example Howto sign and subscribe on channel with callback function
+#   Danthes.sign
+#     server: 'faye.example.com'
+#     channel: 'somechannel'
+#     signature: 'dc1c71d3e959ebb6f49aa6af0c86304a0740088d'
+#     timestamp: 1302306682972
+#     callback: (data) ->
+#       console.log(data)
+
 window.Danthes = class Danthes
+
   @debug: false

   @debugMessage: (message) ->
     console.log(message) if @debug

+  # Reset all
   @reset: ->
     @connecting = false
     @fayeClient = null
@@ -16,6 +33,7 @@
       retry: 5
       endpoints: {}

+  # Connect to faye
   @faye: (callback) =>
     if @fayeClient?
       callback(@fayeClient)
@@ -41,6 +59,7 @@
         @debugMessage 'faye already inited'
         @connectToFaye()

+  # Faye extension for incoming and outgoing messages
   @fayeExtension:
     incoming : (message, callback) =>
       @debugMessage "incomming message #{message}"
@@ -54,7 +73,8 @@
         message.ext.danthes_signature = subscription.signature
         message.ext.danthes_timestamp = subscription.timestamp
       callback(message)
-
+
+  # Initialize Faye client
   @connectToFaye: ->
     if @server && Faye?
       @debugMessage 'trying to connect faye'
@@ -65,6 +85,8 @@
       @debugMessage 'faye connected'
       callback(@fayeClient) for callback in @fayeCallbacks

+  # Sign to channel
+  # @param [Object] options for signing
   @sign: (options) ->
     @debugMessage 'sign to faye'
     @server = options.server unless @server
@@ -81,7 +103,9 @@
             @debugMessage "subscription for #{channel} is active now"
           subscription.errback (error) =>
             @debugMessage "error for #{channel}: #{error.message}"
-
+
+  # Handle response from Faye
+  # @param [Object] message from Faye
   @handleResponse: (message) ->
     if message.eval
       eval(message.eval)
@@ -89,7 +113,10 @@
     return unless @subscriptions[channel]?
     if callback = @subscriptions[channel]['callback']
       callback(message.data, channel)
-
+
+  # Subscribe to channel with callback
+  # @param channel [String] Channel name
+  # @param callback [Function] Callback function
   @subscribe: (channel, callback) ->
     @debugMessage "subscribing to #{channel}"
     if @subscriptions[channel]?
@@ -100,12 +127,15 @@
       return false
     true

+  # Unsubscribe from channel
+  # @param [String] Channel name
   @unsubscribe: (channel) ->
     @debugMessage "unsubscribing from #{channel}"
     if @subscriptions[channel]
       @subscriptions[channel]['sub'].cancel()
       delete @subscriptions[channel]

+  # Unsubscribe from all channels
   @unsubscribeAll: ->
     @unsubscribe(channel) for channel, _ of @subscriptions