remove log statements

remove log statements

--- src/webcomponents/cmi-dropdown-menu/cmi-dropdown-menu.coffee
+++ src/webcomponents/cmi-dropdown-menu/cmi-dropdown-menu.coffee
@@ -51,12 +51,10 @@

   open: ->
     @.$.menuButton.open()
-    console.log 'OPEN'
     @fire 'paper-dropdown-open'

   close: ->
     @.$.menuButton.close()
-    console.log 'CLOSE'
     @fire 'paper-dropdown-close'

   _onIronActivate: (event) ->


DomainCreationForm: Do not try to walk on domain list if there isn’t

--- client/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
+++ client/app/Applications/Environments.kdapplication/views/domains/domaincreationform.coffee
@@ -149,9 +149,12 @@
     KD.whoami().fetchDomains (err, userDomains)=>
       warn err  if err
       domainList = []
-      for domain in userDomains
-        if not domain.regYears > 0
-          domainList.push {title:".#{domain.domain}", value:domain.domain}
+
+      if userDomains
+        for domain in userDomains
+          if not domain.regYears > 0
+            domainList.push {title:".#{domain.domain}", value:domain.domain}
+
       {domains, domainName} = @form.inputs
       domainName.setValue ""
       domains.removeSelectOptions()


send attribute default value with proper type when metamodel is exported. value is currently converted from string because ui inspector is not capable of displaying input fields depending of the type of a selection

--- server/app/assets/metaModelEditor/ext/exportMetaModel/Graph.coffee
+++ server/app/assets/metaModelEditor/ext/exportMetaModel/Graph.coffee
@@ -90,13 +90,20 @@
 # Returns the attributes of the cell.
   getAttributes: (cell) ->
     mAttributes = []
-
     if cell.attributes[Constants.field.ATTRIBUTES]?
       for attributes in cell.attributes[Constants.field.ATTRIBUTES]
         mAttributes.push({});
         for key, value of attributes
-          mAttributes[mAttributes.length - 1][key] = value
-
+          if key == 'default'
+            switch attributes.type
+              when 'Bool'
+                mAttributes[mAttributes.length - 1][key] = value == 'true'
+              when 'Int'
+                mAttributes[mAttributes.length - 1][key] = parseInt(value)
+              when 'Double'
+                mAttributes[mAttributes.length - 1][key] = parseFloat(value)
+              else mAttributes[mAttributes.length - 1][key] = value
+          else mAttributes[mAttributes.length - 1][key] = value
     mAttributes


activity: Fixed saving code snippets.

activity: Fixed saving code snippets.

--- client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemCodeSnippet.coffee
+++ client/app/Applications/Activity.kdapplication/ListItems/ActivityListItemCodeSnippet.coffee
@@ -116,29 +116,23 @@
       tooltip   :
         title   : 'Save'
       callback  : ->
-        {nickname} = KD.whoami().profile
-        rootPath   = "/home/#{nickname}/Documents/CodeSnippets"
+        rootPath   = "Documents/CodeSnippets"
         fileName   = "#{@utils.slugify title}.#{__aceSettings.syntaxAssociations[syntax][1].split('|')[0]}"
         fullPath   = "#{rootPath}/#{fileName}"

-        KD.getSingleton('kiteController').run "mkdir -p #{rootPath}", (err, res) ->
-          file    = FSHelper.createFileFromPath fullPath
+        FSHelper.createRecursiveFolder path : rootPath , =>
+          file    = FSHelper.createFileFromPath "#{fullPath}"
           content = Encoder.htmlDecode content
           file.save content, (err) ->
-
             notificationTitle = new KDView
-              partial : "Your file is saved."
+              partial : "Your file is saved into Documents/CodeSnippets"

             notificationTitle.addSubView link = new KDCustomHTMLView
               tagName  : "a"
               partial  : "Click here to open."
               cssClass : "code-share-open"
               click    : ->
-                KD.getSingleton('appManager').openFile file
-                {treeController} = KD.getSingleton('finderController')
-                treeController.refreshFolder treeController.nodes["/Users/#{nickname}"], ->
-                  treeController.navigateTo rootPath, ->
-                    treeController.selectNode treeController.nodes[fullPath]
+                KD.getSingleton("appManager").openFile file

             new KDNotificationView
               title     : notificationTitle


Sort active nodes

Sort active nodes

--- web/source/javascripts/angular-app.js.coffee
+++ web/source/javascripts/angular-app.js.coffee
@@ -99,8 +99,9 @@
       hull = d3.geom.hull().x((node) -> node.x).y((node) -> node.y)
       hullArea = d3.svg.line().x((n) -> n.x).y((n) -> n.y).interpolate('basis-closed')
       updateActive = ->
-        node.classed('active', (d) -> d.active)
+        node.sort((d, o) -> +d.active * 2 - 1) # map true, false to 1 and -1
         voronoiPatches.classed('active', (d) -> d.active)
+        _.delay -> node.classed('active', (d) -> d.active) # delay to ensure css animations still work

       # link = svg.selectAll('.link').data(links).enter().append('line').attr('class', 'link')
       node = svg.selectAll('.node').data(nodes).enter().append('g').attr('class', (d) -> 'node ' + d.predictedLabel).call(force.drag)


Update results only for submit that we are submitting

--- server/testSystems/Informatics.coffee
+++ server/testSystems/Informatics.coffee
@@ -217,7 +217,7 @@
                 informaticsData = await informaticsUser.submitWithObject(informaticsProblemId, data)
                 await sleep(1000)
             finally
-                await downloadSubmits.runForUser(user.informaticsId, 5, 1)
+                await downloadSubmits.runForUserAndProblem(user.informaticsId, problemId)
         catch e
             logger.info "Error submitting #{user.username}, #{user.informaticsId} #{problemId}: ", e.message
         newSubmits = await Submit.findByUserAndProblem(user.informaticsId, problemId)


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/number_extensions.coffee
+++ test/number_extensions.coffee
@@ -19,7 +19,7 @@
 test "#clamp", ->
   equals 5.clamp(0, 3), 3
   equals 5.clamp(0, 0), 0
-  equals
+  equals

 test "#floor", ->
   equals 4.9.floor(), 4, "(4.9).floor() equals 4"


now, ModelBackedView implements #tagName, #actionText and #submitButtonText

defaults tagName to form, to handle submit buttons
methods return:
- “Nuevo”, “Editar” (a record)
- “Crear”, “Actualizar” (a record)

--- app/assets/javascripts/classes/model_backed_view.js.coffee
+++ app/assets/javascripts/classes/model_backed_view.js.coffee
@@ -1,6 +1,8 @@
 Bandango.ModelBackedView = Ember.View.extend
   raw_errors: {}
   errors: {}
+
+  tagName: "form"

   errors_messages: (->
     messages = []
@@ -8,6 +10,14 @@
       messages.push "#{key}: #{value.join(", ")}"
     messages
   ).property("raw_errors")
+
+  actionText: (->
+    if not @get("model") or @get("model").get("isNew") then "Nuevo" else "Editar"
+  ).property("model")
+
+  submitButtonText: (->
+    if not @get("model") or @get("model").get("isNew") then "Crear" else "Actualizar"
+  ).property("model")

   emptyErrors: ->
     @setProperties


refactor conditional logic

refactor conditional logic

--- app/assets/javascripts/hanuman/conditional-logic.js.coffee
+++ app/assets/javascripts/hanuman/conditional-logic.js.coffee
@@ -1,36 +1,38 @@
 class ConditionalLogic
+
+  self = ConditionalLogic.prototype

   #scan page and find all objects with conditional logic rules
   findRules: ->
     $("[data-rule]").each ->
       rule = $.parseJSON($(this).attr("data-rule")).rule
       $(rule.conditions).each ->
-        bindConditions(rule.question_id, this.question_id, this.operator, this.answer)
+        self.bindConditions(rule.question_id, this.question_id, this.operator, this.answer)

   #TODO: need to write default state check for edit
   #could we actually do this by evaluating the question itself, if it has an answer show, if not hide?
   #is there some other way?

   #bind conditions to question
-  bindConditions = (ancestor_id, question_id, operator, answer) ->
+  bindConditions: (ancestor_id, question_id, operator, answer) ->
     $("[data-question-id=" + question_id + "]").on "change", ->
-      hideShowQuestions(evaluateRules(operator, answer, $(this).val()), ancestor_id)
+      self.hideShowQuestions(self.evaluateRules(operator, answer, $(this).val()), ancestor_id)

   #hide or show questions
-  hideShowQuestions = (hide_questions, ancestor_id) ->
+  hideShowQuestions: (hide_questions, ancestor_id) ->
     container = $("[data-question-id=" + ancestor_id + "],[data-ancestor=" + ancestor_id + "]").closest(".form-entry-item-container")
     if hide_questions
       container.addClass("conditional-logic-hidden")
-      clearQuestions(container)
+      self.clearQuestions(container)
     else
       container.removeClass("conditional-logic-hidden")

   #clear questions
-  clearQuestions = (container) ->
+  clearQuestions: (container) ->
     container.find("input[type!=hidden]").val("")

   #evaluate conditional logic rules
-  evaluateRules = (operator, answer, value) ->
+  evaluateRules: (operator, answer, value) ->
     hide_questions = true
     switch operator
       when "is equal to"


Refactor logic to add shipping rate to params

--- app/assets/javascripts/sprangular/services/checkout.coffee
+++ app/assets/javascripts/sprangular/services/checkout.coffee
@@ -37,9 +37,7 @@
           ship_address_attributes: order.actualShippingAddress().serialize()
           bill_address_attributes: order.billingAddress.serialize()

-      if order.shippingRate
-        params['order[shipments_attributes][][id]'] = order.shipment.id
-        params['order[shipments_attributes][][selected_shipping_rate_id]'] = order.shippingRate.id
+      @_addShippingRate(params, order)

       @put(params)

@@ -53,6 +51,8 @@
         'order[payments_attributes][][payment_method_id]': paymentMethodId
         order: {}
         payment_source: {}
+
+      @_addShippingRate(params, order)

       if card.id
         params.order.existing_card = card.id
@@ -111,6 +111,11 @@
         .error (response) ->
           Cart.errors(response.errors || response.exception)

+    _addShippingRate: (params, order) ->
+      if order.shippingRate
+        params['order[shipments_attributes][][id]'] = order.shipment.id
+        params['order[shipments_attributes][][selected_shipping_rate_id]'] = order.shippingRate.id
+
     _findPaymentMethodId: ->
       paymentMethod = _.find Env.config.payment_methods, (method) -> method.name == 'Credit Card'


added a factory method KD.create as a way of to avoid importing every constructor

--- client/Framework/core/KD.coffee
+++ client/Framework/core/KD.coffee
@@ -34,6 +34,8 @@

 @KD = $.extend (KD), do ->

+  create:(constructorName, options, data)->
+    new @classes[constructorName] options, data
   # private member for tracking z-indexes
   zIndexContexts  = {}
   debugStates     : {}


builder: more string interpolation

builder: more string interpolation

--- client/builder/lib/index.coffee
+++ client/builder/lib/index.coffee
@@ -70,7 +70,7 @@

     if opts.revId
       opts.outdir = path.join opts.outdir, opts.rev
-      opts.baseurl = [ opts.baseurl, opts.rev ].join '/'
+      opts.baseurl = "#{opts.baseurl}/#{opts.rev}"

     opts.spriteTmpCssOutdir = @_resolve SPRITES_TMPDIR
     opts.spriteImgOutdir = defined opts.spriteImgOutdir, opts.outdir
@@ -203,7 +203,7 @@
         name       : name
         routes     : manifest.routes
         shortcuts  : manifest.shortcuts
-        style      : opts.baseurl + '/' + manifest.name + '.css'
+        style      : "#{opts.baseurl}/#{manifest.name}.css"
       }

     transforms = [ coffeeify, pistachioify ]
@@ -225,7 +225,7 @@
         #}
       } ]

-    aceBasePath = [ opts.baseurl, THIRDPARTY_OUTDIR, 'ace' ].join '/'
+    aceBasePath = "#{opts.baseurl}/#{THIRDPARTY_OUTDIR}/ace"

     opts_ =
       basedir    : opts.basedir
@@ -273,41 +273,49 @@
           if not opts.watchJs
             throw err
           else
-            src = 'console.error(' + JSON.stringify(String(err)) + ')'
+            errString = JSON.stringify String err
+            src = "console.error('#{errString}')"
             fs.writeFile outfile, src, (err) ->
               if err
                 console.error err # wtf
               else
-                console.log 'written error to ' + outfile
+                console.log "written error to #{outfile}"
         else
+
           if opts.extractJsSourcemaps
             s = fs.createWriteStream outfile
             asStream(src).pipe(exorcist(opts.jsSourcemapsOutfile)).pipe(s)
+
             s.once 'finish', ->
               secs = ((Date.now() - start)/1000).toFixed 2
-              msg = 'written ' + outfile + ' (' + secs + ')'
+              msg = "written #{outfile} (#{secs})"
               console.log msg
-              console.log 'extracted source maps to ' + opts.jsSourcemapsOutfile
+              console.log "extracted source maps to #{opts.jsSourcemapsOutfile}"
               if not opts.watchJs
                 done()
               else
                 notify 'scripts', msg
+
             s.on 'error', (err) ->
               if not opts.watchJs
                 throw err
               else
                 console.error err
+
           else
+
             fs.writeFile outfile, src, (err, res) ->
               if err
                 if not opts.watchJs
                   throw err
                 else
                   console.error err
+
               else
                 secs = ((Date.now() - start)/1000).toFixed 2
-                msg = pretty(src.length) + ' written to ' + outfile + ' (' + secs + ')'
+                msg = "#{pretty(src.length)} written to #{outfile} (#{secs})"
                 console.log msg
+
                 if not opts.watchJs
                   done()
                 else
@@ -387,10 +395,12 @@

       ws.on 'finish', ->
         timeEnd 'styles: write ' + outfile
+
         if --pending is 0
           secs = ((Date.now() - start)/1000).toFixed 2
-          msg = 'written styles to ' + opts.stylesOutdir + ' (' + secs + ')'
+          msg = "written styles to #{opts.stylesOutdir} (#{secs})"
           console.log msg
+
           if not opts.watchCss
             done()
           else
@@ -402,6 +412,7 @@

       manifest.styles.forEach (basename) ->
         dir = path.join manifest.basedir, basename
+
         globs = [ path.join dir, '**', '*.' + STYLES_EXTENSION ]
         globs.push "!#{commons}"

@@ -412,7 +423,7 @@
           w.on 'ready', ->
             w.on 'raw', (e, file) ->
               if e is 'modified' or e is 'deleted'
-                console.log e + ' ' + file
+                console.log "#{e} file"
                 start = Date.now()
                 styl manifest, globs

@@ -511,12 +522,12 @@

       entities = [1, 2].map (ratio) ->

-        rname = ratio + 'x'
-
-        dir = path.join basedir, rname, '**', '*.' + SPRITESMITH_IMG_EXTENSION
-
-        imgName = manifest.name + '@' + rname + '.' + SPRITESMITH_IMG_EXTENSION
-        cssName = SPRITESMITH_CSS_NAME_PREFIX + rname + '.' + SPRITESMITH_CSS_EXTENSION
+        rname = "#{ratio}x"
+
+        files = path.join basedir, rname, '**', "*.#{SPRITESMITH_IMG_EXTENSION}"
+
+        imgName = "#{manifest.name}@#{rname}.#{SPRITESMITH_IMG_EXTENSION}"
+        cssName = "#{SPRITESMITH_CSS_NAME_PREFIX}#{rname}.#{SPRITESMITH_CSS_EXTENSION}"

         opts_ =
           algorithm : SPRITESMITH_ALGORITHM
@@ -533,7 +544,7 @@
             sprite.name = "#{rname}_#{manifest.name}_#{sprite.name}"
             return sprite

-        s = vfs.src(dir).pipe spritesmith opts_
+        s = vfs.src(files).pipe spritesmith opts_
         return {
           name   : manifest.name
           rname  : rname


IDE: Make status bar creation logic a separated method.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -91,10 +91,10 @@
       panel.once 'viewAppended', =>
         ideView = panel.getPaneByName 'editorPane'
         @setActiveTabView ideView.tabView
-        @registerIDEView ideView
+        @registerIDEView  ideView

         splitViewPanel = ideView.parent.parent
-        splitViewPanel.addSubView @statusBar = new IDE.StatusBar
+        @createStatusBar splitViewPanel

         appView.emit 'KeyViewIsSet'

@@ -377,6 +377,9 @@
       @contentSearch.once 'ViewNeedsToBeShown', (view) =>
         @activeTabView.emit 'ViewNeedsToBeShown', view

+  createStatusBar: (splitViewPanel) ->
+    splitViewPanel.addSubView @statusBar = new IDE.StatusBar
+
   doResize: ->
     @forEachSubViewInIDEViews_ 'editor', (editorPane) ->
       editorPane.aceView.ace.editor.resize()


IDE: add temporary fix for problems with resizing window when IDE is not shown.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -104,6 +104,14 @@

         appView.emit 'KeyViewIsSet'

+    KD.singletons.appManager.on 'AppIsBeingShown', (app) =>
+      # Temporary fix for IDE is not shown after
+      # opening pages which uses old SplitView.
+      # TODO: This needs to be fixed. ~Umut
+      if app instanceof IDEAppController
+        KD.singletons.windowController.notifyWindowResizeListeners()
+
+
   setActiveTabView: (tabView) ->
     @activeTabView = tabView


chat: reload sidebar messages when session ended

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -1353,6 +1353,7 @@
         @statusBar.emit 'CollaborationEnded'
         @chat.emit 'CollaborationEnded'
         @modal.destroy()
+        KD.singletons.mainView.activitySidebar.emit 'ReloadMessagesRequested'

       @rtm.deleteFile @getRealTimeFileName()


properly update button appearance on button_type (#4573)

@$el.empty() does not remove classes, so CSS classes for the type were
simply accumulating. Use @$el.removeClass() to properly remove all CSS
classes on start of render.

--- bokehjs/src/coffee/models/widgets/toggle.coffee
+++ bokehjs/src/coffee/models/widgets/toggle.coffee
@@ -22,6 +22,7 @@
         val.$el.detach()

     @$el.empty()
+    @$el.removeClass()
     @$el.addClass("bk-bs-btn")
     @$el.addClass("bk-bs-btn-" + @mget("button_type"))
     if @mget("disabled") then @$el.attr("disabled", "disabled")


AppController: Resurrect snapshot from localStorage.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -293,10 +293,25 @@
           @finderPane.addSubView @fakeFinderView, '.nfinder .jtreeview-wrapper'

         else
-          @createNewTerminal { machine }
-          @setActiveTabView @ideViews.first.tabView
-          @forEachSubViewInIDEViews_ (pane) ->
-            pane.isInitial = yes
+          snapshot = @localStorageController.getValue @getWorkspaceSnapshotName()
+
+          if snapshot
+            hasFile = no
+            for key, value of snapshot
+              { context } = value
+
+              if context.paneType is 'editor'
+                hasFile    = yes
+                isUntitled = context.file?.name is 'Untitled.txt'
+
+              @ideViews.first.createEditor()    unless hasFile
+              @createPaneFromChange value, yes  unless isUntitled
+          else
+            @ideViews.first.createEditor()
+            @ideViews.last.createTerminal { machine }
+            @setActiveTabView @ideViews.first.tabView
+            @forEachSubViewInIDEViews_ (pane) ->
+              pane.isInitial = yes

   getMountedMachine: (callback = noop) ->
@@ -904,7 +919,7 @@
       @listenPings()
       @rtm.isReady = yes
       @emit 'RTMIsReady'
-      @resurrectSnapshot()
+      # @resurrectSnapshot()

       unless @myWatchMap.values().length
         @listChatParticipants (accounts) =>


Collaboration: Handle session ended for participants.

--- client/ide/AppController.coffee
+++ client/ide/AppController.coffee
@@ -1285,19 +1285,49 @@
   showModal: (modalOptions = {}, callback = noop) ->
     return  if @modal

-    modalOptions.overlay = yes
-    modalOptions.buttons =
+    modalOptions.overlay  ?= yes
+    modalOptions.blocking ?= no
+    modalOptions.buttons or=
       Yes        :
         cssClass : 'modal-clean-green'
         callback : callback
       No         :
         cssClass : 'modal-cancel'
-        callback : => @confirmationModal.destroy()
-
-    @confirmationModal = new KDModalView modalOptions
+        callback : => @modal.destroy()
+
+    ModalClass = if modalOptions.blocking then KDBlockingModalView else KDModalView
+
+    @modal = new ModalClass modalOptions
     @modal.once 'KDObjectWillBeDestroyed', =>
       delete @modal

   handleBroadcastMessage: (data) ->
-    log data
+    {origin, type} = data
+
+    return  if origin is KD.nick()
+
+    switch type
+
+      when 'SessionEnded'
+
+        @showSessionEndedModal()
+
+
+  showSessionEndedModal: ->
+    {mainView, router} = KD.singletons
+
+    options        =
+      title        : 'Session Ended'
+      content      : "This session ended by session owner. You won't be able to access it anymore"
+      blocking     : yes
+      buttons      :
+        quit       :
+          title    : 'LEAVE'
+          callback : =>
+            @modal.destroy()
+            router.handleRoute '/IDE'
+
+
+    @showModal options
+    mainView.activitySidebar.removeMachineNode @mountedMachine


Fix test setup on node.js.

Fix test setup on node.js.

--- test/src/helpers/setup.coffee
+++ test/src/helpers/setup.coffee
@@ -9,7 +9,10 @@
   exports.sinon = require 'sinon'
   exports.sinonChai = require 'sinon-chai'

-  exports.authDriver = new Dropbox.AuthDriver.NodeServer port: 8912
+  tlsOptions = key: require('fs').readFileSync('test/ssl/cert.pem')
+  tlsOptions.cert = tlsOptions.key
+  exports.authDriver = new Dropbox.AuthDriver.NodeServer(
+      tls: tlsOptions, port: 8912)

   TokenStash = require './token_stash.js'
   stash = new TokenStash()


fixed claim of JName for user registration

--- workers/social/lib/social/models/user.coffee
+++ workers/social/lib/social/models/user.coffee
@@ -338,7 +338,13 @@
                   else unless session
                     callback createKodingError 'Could not restore your session!'
                   else
-                    JName.claim username, [username], 'JUser', 'username', (err)->
+                    slug = {
+                      slug: username,
+                      constructorName: 'JUser',
+                      usedAsPath: 'username',
+                      collectionName: 'jUsers'
+                    }
+                    JName.claim username, [slug], 'JUser', (err)->
                       if err then callback err
                       else
                         salt = createSalt()


time indicator masking issue, fix 19

time indicator masking issue, fix 19

--- src/scripts/graph/Header.coffee
+++ src/scripts/graph/Header.coffee
@@ -152,7 +152,7 @@
         .attr("class", "graph-mask")
         .attr("x", -self.margin.left)
         .attr("y", -self.margin.top)
-        .attr("width", self.margin.left - 20)
+        .attr("width", self.margin.left - 5)
         .attr("height", self.height)

     resize: (width) =>


Date formats match rails

Date formats match rails

--- app/assets/javascripts/admin.coffee
+++ app/assets/javascripts/admin.coffee
@@ -11,7 +11,7 @@
 #= require bootstrap
 #= require bootstrap-datepicker

-$.fn.datepicker.defaults.format = "dd/mm/yyyy";
+$.fn.datepicker.defaults.format = "yyyy-mm-dd";

 $(".js-select2").select2
   theme: "bootstrap"


Add some simple documentation/handover to JS

--- app/assets/javascripts/areas.coffee
+++ app/assets/javascripts/areas.coffee
@@ -1,6 +1,5 @@
 ready = ->
   chart = null
-
   supertabs = $(".super-tab-wrapper")

   # On click toggle classes
@@ -14,6 +13,7 @@
       t.siblings().addClass("unselected").removeClass("selected")
       t.trigger("selected")

+  # On select load views via AJAX
   supertabs.on "selected", (e) ->
     loadChart($(e.target).data("chart-url"), $("#chart-container"))
     loadCards($(e.target).data("details-url"), $("#card-wrapper"))
@@ -37,10 +37,13 @@
     line:
       connectNull: true

+  # Initialise chart
   initChart = (container) ->
     chart = c3.generate(chartOptions)

+  # Custom chart legend
   renderLegend = (data) ->
+    # Append li
     d3.select('.legend').selectAll('li').data(data["legend"])
       .enter().append 'li'
       .attr('class', 'key', 'data-id', (id) -> id)
@@ -67,6 +70,7 @@
       columns: data["columns"]
     renderLegend(data)

+  # Update chart header on load
   updateChartHeader = (data) =>
     $('#chart-container .chart-header').attr('id', "tab_" + data["title"][1])
     $('#chart-container .chart-header h2').text(data["title"][0])


only configure Suncalc if Suncalc is defined

--- source/javascripts/site/config.coffee
+++ source/javascripts/site/config.coffee
@@ -17,5 +17,6 @@

 $ ->
   moment.locale('en')
-  SunCalc.addTime(-8.5, 'small_stars_3', 'set_hakochabim')
-  SunCalc.addTime(-16.1, 'magen_abraham_dawn', 'magen_abraham_dusk')
+  if SunCalc?
+    SunCalc.addTime(-8.5, 'small_stars_3', 'set_hakochabim')
+    SunCalc.addTime(-16.1, 'magen_abraham_dawn', 'magen_abraham_dusk')


Adjust readability of some code

Adjust readability of some code

--- src/smc-webapp/course/main.cjsx
+++ src/smc-webapp/course/main.cjsx
@@ -484,35 +484,38 @@
         action_all_student_projects: (action) =>
             if action not in ['start', 'stop', 'restart']
                 throw Error("action must be start, stop or restart")
+            @action_shared_project(action)
+
             student_project_ids = get_store()?.get_students()
                 .filter (student) =>
                     not student.get('deleted') and student.get('project_id')?
                 .map (student) =>
                     student.get('project_id')
-                .toList()
-
-            if student_project_ids?
-                student_project_ids.map (project_id) =>
-                    redux.getActions('projects')[action+"_project"](project_id)
-
-                set_all_action_status = (status) =>
-                    @setState
-                        action_all_projects_status :
-                            action : action
-                            status : status
-
-                set_all_action_status("running")
-                opts =
-                    project_ids : student_project_ids.toJS()
-                    cb          : (err, res) => set_all_action_status(err ? "success")
-                    timeout     : 6 * student_project_ids.size
-
-                if action in ['start', 'restart']
-                    redux.getStore('projects').wait_until_projects_are_running(opts)
-                else if action == 'stop'
-                    redux.getStore('projects').wait_until_projects_are_stopped(opts)
-
-            @action_shared_project(action)
+                .toList().toJS()
+
+            if not student_project_ids?
+                return
+
+            for project_id in student_project_ids
+                redux.getActions('projects')[action+"_project"](project_id)
+
+            set_all_action_status = (status) =>
+                @setState
+                    action_all_projects_status :
+                        action : action
+                        status : status
+
+            set_all_action_status("running")
+            opts =
+                project_ids : student_project_ids
+                cb          : (err, res) => set_all_action_status(err ? "success")
+                timeout     : 6 * student_project_ids.size
+
+            if action in ['start', 'restart']
+                redux.getStore('projects').wait_until_projects_are_running(opts)
+            else if action == 'stop'
+                redux.getStore('projects').wait_until_projects_are_stopped(opts)
+

         set_all_student_project_titles: (title) =>
             actions = redux.getActions('projects')


activity/flux: batch sequential followed channel load dispatches

--- client/activity/lib/flux/actions/channel.coffee
+++ client/activity/lib/flux/actions/channel.coffee
@@ -87,8 +87,9 @@
       dispatch LOAD_FOLLOWED_PRIVATE_CHANNELS_FAIL, { err }
       return

-    channels.forEach (channel) ->
-      dispatch LOAD_FOLLOWED_PRIVATE_CHANNEL_SUCCESS, { channel, options }
+    kd.singletons.reactor.batch ->
+      channels.forEach (channel) ->
+        dispatch LOAD_FOLLOWED_PRIVATE_CHANNEL_SUCCESS, { channel, options }

 ###*
@@ -110,8 +111,9 @@
       dispatch LOAD_FOLLOWED_PUBLIC_CHANNELS_FAIL, { err }
       return

-    channels.forEach (channel) ->
-      dispatch LOAD_FOLLOWED_PUBLIC_CHANNEL_SUCCESS, { channel, options }
+    kd.singletons.reactor.batch ->
+      channels.forEach (channel) ->
+        dispatch LOAD_FOLLOWED_PUBLIC_CHANNEL_SUCCESS, { channel, options }

 ###*


remove console.logs

remove console.logs

--- src/smc-webapp/editor_chat.cjsx
+++ src/smc-webapp/editor_chat.cjsx
@@ -499,12 +499,9 @@
             account_name = "Unknown"

     close_edit_inputs: (current_message_date) ->
-        console.log("current message date", current_message_date)
         sorted_dates = @props.messages.keySeq().sort(misc.cmp_Date).toJS()
         for date in sorted_dates
-            console.log("date", date)
             if date != current_message_date
-                console.log("called")
                 @props.actions.set_editing(@props.messages.get(date), false)

     list_messages: ->


activity/flux: add createComment action

activity/flux: add createComment action

--- client/activity/lib/flux/actions/message.coffee
+++ client/activity/lib/flux/actions/message.coffee
@@ -213,13 +213,41 @@
       dispatch LOAD_COMMENT_SUCCESS, { messageId, comment }

+###*
+ * Adds comment to given message.
+ *
+ * @param {string} messageId
+ * @param {string} body
+ * @param {object=} payload
+###
+createComment = (messageId, body, payload = {}) ->
+
+  { socialapi } = kd.singletons
+  { CREATE_COMMENT_BEGIN
+    CREATE_COMMENT_FAIL
+    CREATE_COMMENT_SUCCESS } = actionTypes
+
+  clientRequestId = generateFakeIdentifier Date.now()
+
+  dispatch CREATE_COMMENT_BEGIN, { messageId, clientRequestId, body }
+
+  socialapi.message.reply { messageId, clientRequestId, body, payload }, (err, comment) ->
+    if err
+      dispatch CREATE_COMMENT_FAIL, { err, comment, clientRequestId }
+      return
+
+    dispatch CREATE_COMMENT_SUCCESS, { messageId, comment, clientRequestId }
+
+
 module.exports = {
   loadMessages
+  loadMessageBySlug
   createMessage
   likeMessage
   unlikeMessage
   removeMessage
   editMessage
   loadComments
+  createComment
 }


fix ie & Safari issue

fix ie & Safari issue

--- app/assets/javascripts/works.coffee
+++ app/assets/javascripts/works.coffee
@@ -2,10 +2,23 @@
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://coffeescript.org/

+decodeEntities = (encodedString)->
+  # required for IE and Safari
+  textArea = document.createElement('textarea')
+  textArea.innerHTML = encodedString
+  textArea.value
+
+
 lazy_load_image_in_noscript_wrapper = (noscript_tag)->
   fragment = noscript_tag.innerHTML
   parent = noscript_tag.parentElement
-  parent.innerHTML = fragment
+  parent.innerHTML = decodeEntities(fragment)
+
+process_intersection_observer_entry = (entry)->
+  if entry.intersectionRatio > 0
+    noscript_tag = entry.target.querySelector("noscript")
+    if noscript_tag
+      lazy_load_image_in_noscript_wrapper noscript_tag

 lazy_load_images = ->
   noscript_wrapped_images = document.querySelectorAll("noscript[data-lazy=\"lazy-load\"]")
@@ -13,14 +26,8 @@
   if supportsIntersectionObserver
     intersectionObsOptions =
       root_margin: "100px"
-      treshold: [0.0,  0.5, 1.0]
     intersectionObserver = new IntersectionObserver((entries)->
-      entries.forEach((entry)->
-        if entry.intersectionRatio > 0
-          noscript_tag = entry.target.querySelector("noscript")
-          if noscript_tag
-            lazy_load_image_in_noscript_wrapper noscript_tag
-      )
+      entries.forEach(process_intersection_observer_entry)
     , intersectionObsOptions)
     noscript_wrapped_images.forEach((e)->intersectionObserver.observe(e.parentElement))
   else


Remove newpage uploading

Remove newpage uploading

--- src/smc-webapp/project_new.cjsx
+++ src/smc-webapp/project_new.cjsx
@@ -364,33 +364,6 @@
     #console.log("unmount project_new")
     ReactDOM.unmountComponentAtNode(dom_node)

-FileUpload = rclass ({name}) ->
-    displayName : 'ProjectNew-FileUpload'
-
-    reduxProps :
-        "#{name}" :
-            current_path : rtypes.string
-
-    propTypes :
-        project_id : rtypes.string.isRequired
-
-    mixins : [ImmutablePureRenderMixin]
-
-    render: ->
-        {SMC_Dropzone} = require('./r_misc')
-
-        <Row>
-            <Col sm=3>
-
<Icon name='cloud-upload' /> Upload files from your computer

-            </Col>
-            <Col sm=8>
-                <SMC_Dropzone
-                    dropzone_handler     = {{}}
-                    project_id           = @props.project_id
-                    current_path         = @props.current_path />
-            </Col>
-        </Row>
-
 exports.ProjectNew = rclass ({name}) ->
     propTypes :
         project_id : rtypes.string
@@ -399,6 +372,4 @@
     render: ->

             <ProjectNewForm project_id={@props.project_id} name={@props.name} actions={@actions(name)} />
-

-            <FileUpload project_id={@props.project_id} name={@props.name} />


remote/machine: add Type constants

remote/machine: add Type constants

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

--- client/app/lib/remote-extensions/machine.coffee
+++ client/app/lib/remote-extensions/machine.coffee
@@ -36,6 +36,15 @@
                       # needs to be resolved manually
   }

+  @Type = {
+
+    Own: 'own'
+    Collaboration: 'collaboration'
+    Shared: 'shared'
+    Reassigned: 'reassigned'
+
+  }
+
   stop: ->
     kd.singletons.computeController.stop this


Removed comments and refactorized directive

--- app/coffee/directives/common.coffee
+++ app/coffee/directives/common.coffee
@@ -37,14 +37,8 @@
             for item, index in breadcrumb
                 items.push(angular.element('

').text(item))

-                #if index != total
-                #    items.push(angular.element(' › '))
-
             if not _.isEmpty(items)
                 first = items[0]
-                #first.css('font-weight', 'bold')
-                #first.css('color', 'black')
-                #first.css('curso', 'pointer')*/
                 first.addClass('first-breadcrumb').removeAttr('data-icon')

             for item in items


Don't need these specs

Don't need these specs

--- spec/background-tips-view-spec.coffee
+++ spec/background-tips-view-spec.coffee
@@ -1,17 +0,0 @@
-BackgroundTipsView = require '../lib/background-tips-view'
-{WorkspaceView} = require 'atom'
-
-describe "BackgroundTipsView", ->
-  backgroundTips = null
-
-  beforeEach ->
-    atom.workspaceView = new WorkspaceView
-    backgroundTips = atom.packages.activatePackage('backgroundTips', immediate: true)
-
-  describe "when the background-tips:toggle event is triggered", ->
-    it "attaches and then detaches the view", ->
-      expect(atom.workspaceView.find('.background-tips')).not.toExist()
-      atom.workspaceView.trigger 'background-tips:toggle'
-      expect(atom.workspaceView.find('.background-tips')).toExist()
-      atom.workspaceView.trigger 'background-tips:toggle'
-      expect(atom.workspaceView.find('.background-tips')).not.toExist()


Added jQuery copyright header

Added jQuery copyright header

--- src/tb/lib/ti/ajax/index.coffee
+++ src/tb/lib/ti/ajax/index.coffee
@@ -1,3 +1,25 @@
+# Portions copyright 2013 jQuery Foundation and other contributors
+# http://jquery.com/
+
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
 handlers = require './handlers'

 ajax_nonce = Date.now()


rabbitmq api opened to world for kites to connect

--- config/main.kontrol-prod.coffee
+++ config/main.kontrol-prod.coffee
@@ -117,7 +117,7 @@
   mq            :
     host        : 'internal-vpc-rabbit-721699402.us-east-1.elb.amazonaws.com'
     port        : 5672
-    apiAddress  : "internal-vpc-rabbit-721699402.us-east-1.elb.amazonaws.com"
+    apiAddress  : "ec2-rabbit-1302453274.us-east-1.elb.amazonaws.com"
     apiPort     : 15672
     login       : 'guest'
     componentUser: "guest"


css cleanup, preview switch initialisation class depending on showInitially

--- components/inputs/KDInputViewWithPreview.coffee
+++ components/inputs/KDInputViewWithPreview.coffee
@@ -50,6 +50,7 @@

     unless @showPreview
       @$("div.preview_content").addClass "hidden"
+      @$("div.preview_switch").addClass "content-hidden"
       @$("input.preview_checkbox").prop("checked",no)
     else
       @generatePreview()


Activity: new files included

Activity: new files included

--- client/Social/Activity/includes.coffee
+++ client/Social/Activity/includes.coffee
@@ -15,6 +15,8 @@
   "views/newmemberbucket.coffee",
   "views/activitytickeritem.coffee",
   "views/referalbox.coffee",
+  "views/activitylistcontainer.coffee",
+  "views/filterwarning.coffee",

   "views/embedbox.coffee",
   "views/embedboxwidget.coffee",


Client: Better check for timer.

Client: Better check for timer.

--- client/app/js/views/battle_view.coffee
+++ client/app/js/views/battle_view.coffee
@@ -951,7 +951,7 @@
     $frozenTimer = $info.find('.frozen-timer')
     timeRemaining = @timers[index] - $.now() + @timerUpdatedAt[index]

-    if !timeRemaining? || isNaN(timeRemaining)
+    if !timeRemaining && timeRemaining != 0  # Falsy, but not 0.
       $remainingTimer.addClass('hidden')
     else
       $remainingTimer.removeClass('hidden')


Add toggling on email advanced parameters

--- client/app/views/register/email.coffee
+++ client/app/views/register/email.coffee
@@ -5,3 +5,16 @@
     className: 'email'

     template: require 'views/templates/view_register_email'
+
+    ui:
+        legend: '.advanced legend'
+        adv: '.advanced .content'
+
+
+    initialize: ->
+        @showAdv = @$el.asEventStream 'click', @ui.legend
+                      .scan false, (visible) -> not visible
+
+
+    onRender: ->
+        @showAdv.not().assign @ui.adv, 'attr', 'aria-hidden'


add error handling to build logs page

add error handling to build logs page

--- client/home/lib/buildlogs/index.coffee
+++ client/home/lib/buildlogs/index.coffee
@@ -1,6 +1,9 @@
 kd = require 'kd'
 IDETailerPane = require 'ide/workspace/panes/idetailerpane'
 FSHelper = require 'app/util/fs/fshelper'
+IDEHelpers = require 'ide/idehelpers'
+showErrorNotification = require 'app/util/showErrorNotification'
+

 header = ->
   new kd.CustomHTMLView
@@ -11,9 +14,9 @@

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

-    { computeController } = kd.singletons
+    { computeController, router } = kd.singletons

-    path = kd.singletons.router.getCurrentPath()
+    path = router.getCurrentPath()

     machineUid = path.split('/').pop()

@@ -21,11 +24,30 @@

     machine = computeController.findMachineFromMachineUId machineUid

+    return router.handleNotFound path  unless machine
+
     @machineName = machine.label

     # Path of cloud-init-output log
     path = '/var/log/cloud-init-output.log'
     @file = FSHelper.createFileInstance { path, machine }
+
+
+    @file.fetchPermissions (err, result) =>
+
+      return showErrorNotification err  if err
+
+      { readable, writable, exists } = result
+
+      unless exists
+        new kd.NotificationView
+          title: 'Your build logs path is not exists'
+          duration: 2000
+        return router.handleRoute '/IDE'
+
+      if not readable
+        IDEHelpers.showFileAccessDeniedError()
+        return router.handleRoute '/IDE'

     super options, data
@@ -48,4 +70,4 @@

 /var/log/cloud-init-output.log

       """

-    @addSubView new IDETailerPane { cssClass: 'build-logs-view', file: @file, delegate: this }
+    @addSubView new IDETailerPane { cssClass: 'build-logs-view', @file, delegate: this }


Method for initializing empty definitions (main 'Class') added

--- types/basics/component.coffee
+++ types/basics/component.coffee
@@ -54,12 +54,20 @@
 			# @cacheItem = utils.bindFunctionContext @cacheItem, @
 		Object.preventExtensions @

+	initSignalArr = ->
+		@objectsOrderSignalArr = utils.clone(@objectsOrder)
+		@objectsOrderSignalArr.push null, null
+
+	initAsEmptyDefinition: ->
+		initSignalArr.call @
+		Object.freeze @
+		return
+
 	init: ->
 		assert.notOk @ready
 		assert.ok @isClone

-		@objectsOrderSignalArr = utils.clone(@objectsOrder)
-		@objectsOrderSignalArr.push null, null
+		initSignalArr.call @
 		@ready = true

 		# init objects


Removed unnecessary code

Removed unnecessary code

--- core/app/assets/javascripts/intermediate.coffee
+++ core/app/assets/javascripts/intermediate.coffee
@@ -32,8 +32,6 @@
   if last_created_text == text
     remote.highlightNewFactlink(text, id)

-window.onModalReady = ->
-
 showUrl = (url, successFn) ->
   window.onModalReady = ->
     window.onModalReady = ->


Use new listenToWindowMessages method.

Use new listenToWindowMessages method.

--- core/app/assets/javascripts/intermediate.coffee
+++ core/app/assets/javascripts/intermediate.coffee
@@ -20,7 +20,7 @@
       showUrl url
       last_created_text = text

-Factlink.listenToWindowMessages null, local
+Factlink.listenToWindowMessages local

 window.highlightLastCreatedFactlink = (id, text) ->
   if last_created_text == text


fixed messages being listed on showing inbox

--- client/app/Applications/Inbox.kdapplication/AppView.coffee
+++ client/app/Applications/Inbox.kdapplication/AppView.coffee
@@ -55,9 +55,11 @@
       cssClass  : "new-message-bar clearfix"
       delegate  : @inboxMessagesContainer

-    @newMessageBar.on "RefreshButtonClicked", =>
+    listMessages = =>
       inboxMessageListController.loadMessages =>
         @newMessageBar.refreshButton.hideLoader()
+    @newMessageBar.on "RefreshButtonClicked", listMessages
+    tab.on            "KDTabPaneActive",      listMessages

     @newMessageBar.disableMessageActionButtons()


virtualization controller: remove a console.trace()

--- client/landing/app/MainApp/VirtualizationController.coffee
+++ client/landing/app/MainApp/VirtualizationController.coffee
@@ -428,7 +428,6 @@
               modal.destroy()
               if appName
                 @once 'StateChanged', ->
-                  console.trace()
                   KD.getSingleton("appManager").open appName
         Cancel       :
           style      : "modal-clean-gray"


Use $log instead of console.

Use $log instead of console.

--- src/FileManager/FileSystemNode.coffee
+++ src/FileManager/FileSystemNode.coffee
@@ -1,11 +1,11 @@
 angular.module('fileManager').
-factory 'FileSystemNode', ($q, assert, crypto, DbDoc, CrypTree, session) ->
+factory 'FileSystemNode', ($q, assert, crypto, DbDoc, CrypTree, session, $log) ->
   class FileSystemNode
-    constructor: (doc, parentKey, parentId) ->
-      console.log "new File/Folder", doc, parentKey
+    constructor: (doc, parentKey, parentId = null) ->
+      $log.log "new File/Folder", doc, parentKey
       @_id              = doc._id
       @_rev             = doc._rev
-      @metadata         = doc.metadata || doc.data || {}
+      @metadata         = doc.metadata ? doc.data ? {}
       @content          = doc.content

       @dataKeyLink      = doc.dataKeyLink
@@ -15,15 +15,15 @@
       @subfolderKey     = doc.subfolderKey
       @dataKey          = doc.dataKey

-      @parentId         = doc.parentId or parentId
-      @keyDurty         = if doc.keyDurty? then doc.keyDurty else false
+      @parentId         = parentId ? doc.parentId
+      @keyDurty         = doc.keyDurty ? false

       if not @dataKey and parentKey?
         @generateReadCrypTreeKeys(parentKey)
         @generateWriteCrypTreeKeys()

     #
-    # Class methods
+    # Static method
     #
     @_getParent: (doc, parentFolder) ->
       deferred = $q.defer()
@@ -45,14 +45,14 @@
     @_getDataKeyLinkKey: (doc, parentFolder) ->
       @_getParent(doc, parentFolder)
       .then (parentFolder) =>
-        console.log "parentFolder", parentFolder
+        $log.log "parentFolder", parentFolder
         @_getParentKey(doc, parentFolder)
       .catch () =>
         throw "Impossible to open this file/folder"

     @_getKeys: (doc, parentFolder) ->
       @_getDataKeyLinkKey(doc, parentFolder).then (key) =>
-        console.log "parentKey", key
+        $log.log "parentKey", key
         CrypTree.resolveSymLink(doc.dataKeyLink, key).then (dataKey) =>
           return [dataKey, key]

@@ -64,7 +64,7 @@
     # TODO: clarify/simplify this!
     @get: (id, linkOrKey, parentFolder) ->
       _funcName = "File.get"
-      console.log _funcName, id
+      $log.log _funcName, id
       assert.defined id, "id", _funcName
       DbDoc.get(id).then (doc) =>
         if not crypto.isEncrypted(doc)
@@ -77,7 +77,7 @@
           else
             @_getParentKey(doc, parentFolder).then (parentKey) =>
               CrypTree.resolveSymLink(linkOrKey, parentKey).then (key) =>
-                console.log "dataOrSFKey", key
+                $log.log "dataOrSFKey", key
                 if not doc.isFolder
                   # dataKey
                   return key
@@ -90,7 +90,7 @@
         ).then (keys) =>
           if not angular.isArray(keys)
             keys = [keys]
-          console.log "keys", keys
+          $log.log "keys", keys
           dataKey = keys[0]
           if keys.length > 1
             subfolderKey = keys[1]
@@ -100,12 +100,14 @@
               doc.subfolderKey = subfolderKey
               new @(doc)
           catch
-            console.error "decrypt error"
-
+            $log.error "decrypt error"

     @getMetadata: (id, parentKey) ->
       @get(id, parentKey)

+    #
+    # no-Static method
+    #
     generateReadCrypTreeKeys: (parentKey) ->

     generateWriteCrypTreeKeys: (parentKey) ->
@@ -116,7 +118,7 @@
       #  return assert.tests.isAnArray(@content)

     getContent: (parentKey) ->
-      console.log "getContent", @_id
+      $log.log "getContent", @_id
       assert.defined @_id, "@_id", "getContent"
       if @_id == "shares"
         return $q.when(@content)
@@ -138,7 +140,7 @@

     saveMetadata: () ->
       _funcName = "saveMetadata"
-      console.log _funcName
+      $log.log _funcName

       DbDoc.encryptAndSave(@_createMetadataDoc(), @dataKey).then (result) =>
         @_id = result.id
@@ -147,7 +149,7 @@

     saveContent: () ->
       _funcName = "saveContent"
-      console.log _funcName
+      $log.log _funcName
       content = {
         data: {
           content: @content
@@ -165,12 +167,12 @@
           content._id = @_id
         if @_rev
           content._rev = @_rev
-      console.debug "saveContent", content, @dataKey
+      $log.debug "saveContent", content, @dataKey
       DbDoc.encryptAndSave(content, @dataKey)

     save: () ->
       _funcName = "save"
-      console.log _funcName
+      $log.log _funcName
       if @content?
         @saveContent().then (contentResult) =>
           unless @metadata?
@@ -188,7 +190,7 @@

     delete: ->
       _funcName = 'delete'
-      console.log _funcName
+      $log.log _funcName
       if @metadata.contentId?
         DbDoc.delete {_id: @metadata.contentId}, @dataKey
-      DbDoc.delete {_id: @_id}, @dataKey+      DbDoc.delete {_id: @_id}, @dataKey


Fix undefined function

Fix undefined function

--- coffee/subscriptions.controller.coffee
+++ coffee/subscriptions.controller.coffee
@@ -168,7 +168,7 @@

         @confirm.notify('success', message, '', 5000)

-        promise = @subscriptionsService.fetchMyPlans()
+        promise = @subscriptionsService.fetchPublicPlans()
         promise.then () =>
             @tgLoader.pageLoaded()


Look for block below falling block

Look for block below falling block

--- app/scripts/controllers/main.coffee
+++ app/scripts/controllers/main.coffee
@@ -23,6 +23,10 @@
     drop_unlocked_blocks = ->
       for block in $scope.blocks
         if block.x == rows - 1
+          block.locked = true
+          block.active = false
+        block_below = $scope.blocks.filter((b) -> b.x == block.x + 1 && b.y == block.y)[0]
+        if block_below
           block.locked = true
           block.active = false
         continue if block.locked


Call open on model instead of view

Call open on model instead of view

--- src/window-event-handler.coffee
+++ src/window-event-handler.coffee
@@ -29,7 +29,7 @@

     @subscribe $(window), 'window:open-path', (event, {pathToOpen, initialLine, initialColumn}) ->
       unless fs.isDirectorySync(pathToOpen)
-        atom.workspaceView?.open(pathToOpen, {initialLine, initialColumn})
+        atom.workspace?.open(pathToOpen, {initialLine, initialColumn})

     @subscribe $(window), 'beforeunload', =>
       confirmed = atom.workspaceView?.confirmClose()


Don't set a strange border on the button when getting an error

--- core/app/assets/javascripts/base/registration_forms.coffee
+++ core/app/assets/javascripts/base/registration_forms.coffee
@@ -59,9 +59,8 @@
     setErrorsOnFields formId, fieldErrors

   clearPreviousErrorsForForm = (form) ->
-    _.each (form.find "input"), (el) ->
-      # $(el).removeClass "error"
-      $(el).css border: "1px solid #ccc"
+    _.each (form.find "input.text"), (el) ->
+      $(el).removeClass 'error'
       $(el).popover "destroy"

 bindRegistrationForm "top_registration_form"


Framework: Moved example code to below.

Framework: Moved example code to below.

--- components/split/splitcomboview.coffee
+++ components/split/splitcomboview.coffee
@@ -1,3 +1,26 @@
+class KDSplitComboView extends KDView
+
+  constructor: (options = {}, data) ->
+
+    options.cssClass or= "kdsplitcomboview"
+
+    super options, data
+
+    @addSubView @createSplitView options.direction, options.sizes, options.views
+
+  createSplitView: (type, sizes, viewsConfig) ->
+    views = []
+
+    for config, index in viewsConfig
+      if config.type is "split"
+        {options} = config
+        views.push @createSplitView options.direction, options.sizes, config.views
+      else
+        views.push config
+
+    new KDSplitView { type, sizes, views }
+
+
 # Example Usage
 #
 # new KDSplitComboView
@@ -37,26 +60,3 @@
 #       ]
 #      }
 #     ]
-
-
-class KDSplitComboView extends KDView
-
-  constructor: (options = {}, data) ->
-
-    options.cssClass or= "kdsplitcomboview"
-
-    super options, data
-
-    @addSubView @createSplitView options.direction, options.sizes, options.views
-
-  createSplitView: (type, sizes, viewsConfig) ->
-    views = []
-
-    for config, index in viewsConfig
-      if config.type is "split"
-        {options} = config
-        views.push @createSplitView options.direction, options.sizes, config.views
-      else
-        views.push config
-
-    new KDSplitView { type, sizes, views }


fix off-by-one error in seeking

fix off-by-one error in seeking

--- VisualRunner.coffee
+++ VisualRunner.coffee
@@ -27,8 +27,8 @@
           @pause()
       @seekControl.on 'mouseup', =>
         if pausedForSeek
-          pausedForSeek = false
           @play()
+        pausedForSeek = false
       @seekControl.on 'input', =>
         @_setIndex(parseInt(@seekControl.val(), 10))

@@ -36,14 +36,13 @@
       .val(@_index)
       .attr('min', 0)
       .attr('step', 1)
-      .attr('max', (@_funcQueue?.length || 1) - 1)
+      .attr('max', (@_funcQueue?.length || 0))

   _setIndex: (i) ->
     runOneStep = (step) =>
       { name, args } = @_funcQueue[step]
       @exposedFuncs[name](args...)
     prevIndex = @_index
-    @seekControl.val(@_index)

     if prevIndex > i
       @loadInitialState()
@@ -51,6 +50,8 @@
     while @_index < i
       runOneStep(@_index)
       @_index++
+
+    @seekControl.val(@_index)

     @render()


Fix alternate title not being updated on switching between anime pages.

--- app/assets/javascripts/components/bootstrap-tooltip.js.coffee
+++ app/assets/javascripts/components/bootstrap-tooltip.js.coffee
@@ -1,6 +1,13 @@
 Hummingbird.BootstrapTooltipComponent = Ember.Component.extend
   tagName: 'a'
-  didInsertElement: ->
+
+  initializeTooltip: (->
     @$().tooltip
       placement: @get('placement')
       title: @get('title')
+  ).on('didInsertElement')
+
+  updateTooltip: (->
+    @$().tooltip 'destroy'
+    @initializeTooltip()
+  ).observes('title', 'placement')


Add relations styles implementation (solid, dotted, dashed)

--- app/frontend/javascripts/views/visualization-canvas.js.coffee
+++ app/frontend/javascripts/views/visualization-canvas.js.coffee
@@ -222,7 +222,7 @@
   drawNodeLabel: (d) =>
     @context.fillStyle = d.fontColor
     @context.font      = '300 '+d.fontSize+'px Montserrat'
-    if (@node_hovered or @node_active) and d.long_label
+    if (@parameters.showNodesLabelComplete or @node_hovered or @node_active) and d.long_label
       d.long_label.forEach (line, i) =>
         @context.strokeText line, d.x, d.y+d.size+(i*d.fontSize)+1
         @context.fillText   line, d.x, d.y+d.size+(i*d.fontSize)
@@ -232,14 +232,22 @@

   drawRelations: ->
     # make stroke color dynamic based on nodes state !!!
+    @context.save()
+    @context.lineWidth = 1
+    if @parameters.relationsLineStyle == 1
+      @context.lineCap = 'square'
+      @context.setLineDash [4, 3]
+    else if @parameters.relationsLineStyle == 2
+      @context.lineCap = 'round'
+      @context.setLineDash [0.25, 3]
     @data_relations_visibles.forEach (link) =>
       @context.strokeStyle = link.color
-      @context.lineWidth = 1
       @context.beginPath()
       @context.moveTo link.source.x, link.source.y
       @context.lineTo link.target.x, link.target.y
       @context.stroke()
       @context.closePath()
+    @context.restore()

   drawRelationsLabels: ->
     @context.textAlign    = 'center'


Fix #1: Phonetic form checkbox is shown in extended search even for non-speech corpora

--- app/assets/javascripts/rglossa/components/centre/search_inputs/cwb_multiword_term.jsx.coffee
+++ app/assets/javascripts/rglossa/components/centre/search_inputs/cwb_multiword_term.jsx.coffee
@@ -186,11 +186,13 @@

+                {this.props.hasPhoneticForm &&

                     <input type="checkbox" checked={term.isPhonetic} onChange={this.handleIsPhoneticChanged} /> Phonetic form

+                }


removed whitespace from taxons.js.coffee

--- backend/app/assets/javascripts/spree/backend/taxons.js.coffee
+++ backend/app/assets/javascripts/spree/backend/taxons.js.coffee
@@ -49,5 +49,4 @@
             if product.master.images[0] != undefined && product.master.images[0].small_url != undefined
               product.image = product.master.images[0].small_url
             el.append(productTemplate({ product: product }))
-          $('#sorting_explanation').show()
-
+          $('#sorting_explanation').show()


* minor changes

* minor changes

--- test/cache-factory-test.coffee
+++ test/cache-factory-test.coffee
@@ -6,7 +6,7 @@
 expect          = chai.expect
 chai.use(sinonChai)

-path            = require('path.js')
+path            = require('path.js/lib/path').path
 extend          = require('inherits-ex/lib/_extend')
 createCtor      = require 'inherits-ex/lib/createCtor'
 factory         = require 'custom-factory'


Simplify state change for zoom control

Simplify state change for zoom control


d3 charts adapt to container's width

d3 charts adapt to container's width

--- app/assets/javascripts/lib/views/d3_chart_view.coffee
+++ app/assets/javascripts/lib/views/d3_chart_view.coffee
@@ -35,8 +35,8 @@

   # override in derived class as needed
   outer_height: -> 300
-  # this can later be made dynamic
-  available_width: -> 600
+
+  available_width: -> @$el.width()

   # Builds a standard legend. Options hash:
   # - svg: SVG container (required)


uploader.__state didn't called at first pusher message (if first message was last it didn't called at all)

--- app/assets/javascripts/uploadcare/files/url.js.coffee
+++ app/assets/javascripts/uploadcare/files/url.js.coffee
@@ -90,8 +90,8 @@

       for ev in ['progress', 'success']
         do (ev) =>
-          @channel.bind ev, onStarted
           @channel.bind ev, (data) => @uploader.__state ev, data
+          @channel.bind ev, onStarted  # self-removed callback should be last!

       @channel.bind 'fail', (data) => @uploader.__state('error')


Track bid confirmation on the bid page

Track bid confirmation on the bid page

--- apps/auction/client/bid_form.coffee
+++ apps/auction/client/bid_form.coffee
@@ -37,6 +37,8 @@
       @saleArtwork.cleanBidAmount val

   placeBid: =>
+    analytics.track.click 'Clicked "Confirm Bid" on bid page'
+
     @timesPolledForBidPlacement = 0
     @$submit.addClass('is-loading')
     @clearErrors()
@@ -51,6 +53,7 @@
           _.delay =>
             @pollForBidPlacement(@saleArtwork.get('minimum_next_bid_cents'))
           , 1000
+          analytics.track.funnel 'Confirmed bid on bid page'
         error: (xhr) =>
           @showError 'Error placing your bid', xhr
     else


small refactor to make hotkey printing logic more readable

--- src/chat/help_message_renderer.coffee
+++ src/chat/help_message_renderer.coffee
@@ -30,7 +30,7 @@
   ##
   render: (commands) ->
     @_commands = commands
-    @_addWhitespace()
+    @_postMessage()
     @_printCommands()
     @_postMessage "Type '/help <command>' to see details about a specific command.",
         'notice help'
@@ -42,9 +42,9 @@
     for group in @_groupCommandsByCategory()
       @_postMessage "#{@_getCommandGroupName group.category} Commands:",
           HelpMessageRenderer.COMMAND_STYLE
-      @_addWhitespace()
+      @_postMessage()
       @_printCommandGroup group.commands.sort()
-      @_addWhitespace()
+      @_postMessage()

   _determineCommandDimentions: ->
     totalWidth = HelpMessageRenderer.TOTAL_WIDTH
@@ -125,17 +125,9 @@
   #     readableName: string}>} hotkeys
   ##
   renderHotkeys: (hotkeys) ->
-    @_addWhitespace()
+    @_postMessage()
     @_postMessage "Keyboard Shortcuts:", 'notice help'
-    @_addWhitespace()
-    @_printHotkeys hotkeys
-
-  ##
-  # Displays a list of hotkeys and their descriptions.
-  # @param {Object.<string: {description: string, group: string,
-  #     readableName: string}>} hotkeys
-  ##
-  _printHotkeys: (hotkeys) ->
+    @_postMessage()
     groupsVisited = {}
     for id, hotkeyInfo of hotkeys
       if hotkeyInfo.group
@@ -146,7 +138,4 @@
         name = hotkeyInfo.readableName
       @_postMessage "  #{name}: #{hotkeyInfo.description}", 'notice help'

-  _addWhitespace: ->
-    @_postMessage()
-
 exports.HelpMessageRenderer = HelpMessageRenderer


Formatação no Sku Selector

Formatação no Sku Selector

--- src/coffee/portal-sku-selector.coffee
+++ src/coffee/portal-sku-selector.coffee
@@ -4,23 +4,6 @@
 # dust

 $ = window.jQuery
-
-# SHARED STUFF
-$.skuSelector =
-	getAddUrlForSku: (sku, seller = 1, qty = 1, salesChannel = 1, redirect = true) ->
-		"/checkout/cart/add?qty=#{qty}&seller=#{seller}&sku=#{sku}&sc=#{salesChannel}&redirect=#{redirect}"
-
-	selectors:
-		listPriceValue: '.skuselector-list-price .value'
-		bestPriceValue: '.skuselector-best-price .value'
-		installment: '.skuselector-installment'
-		buyButton: '.skuselector-buy-btn'
-		confirmButton: '.skuselector-confirm-btn'
-		price: '.skuselector-price'
-		priceRange: '.skuselector-price-range'
-		warning: '.skuselector-warning'
-		warnUnavailable: '.skuselector-warn-unavailable'
-

 # DUST FILTERS
 _.extend dust.filters,
@@ -355,7 +338,7 @@

 		selectableSkus = selector.findSelectableSkus()
 		# Trigger event for interested scripts
-		$this.trigger 'vtex.sku.dimensionChanged', [dimensionName, dimensionValue, productData]
+		$this.trigger 'vtex.sku.dimensionChanged', [dimensionName, dimensionValue, productData.productId]
 		if selectableSkus.length == 1
 			$this.trigger 'vtex.sku.selected', [selectableSkus[0], productData.productId]
 			$this.trigger 'skuSelected', [selectableSkus[0], productData.productId]
@@ -406,6 +389,21 @@
 	warnUnavailablePost: (formElement) ->
 		$.post '/no-cache/AviseMe.aspx', $(formElement).serialize()

+# SHARED STUFF
+$.skuSelector =
+	getAddUrlForSku: (sku, seller = 1, qty = 1, salesChannel = 1, redirect = true) ->
+		"/checkout/cart/add?qty=#{qty}&seller=#{seller}&sku=#{sku}&sc=#{salesChannel}&redirect=#{redirect}"
+
+	selectors:
+		listPriceValue: '.skuselector-list-price .value'
+		bestPriceValue: '.skuselector-best-price .value'
+		installment: '.skuselector-installment'
+		buyButton: '.skuselector-buy-btn'
+		confirmButton: '.skuselector-confirm-btn'
+		price: '.skuselector-price'
+		priceRange: '.skuselector-price-range'
+		warning: '.skuselector-warning'
+		warnUnavailable: '.skuselector-warn-unavailable'

 # EVENTS (DEPRECATED!)
 $(document).on "vtex.sku.selected", (evt, sku, productData) ->


Client: Activity: Updated  channelThreadPane to render feed or channel by isFeedEnabled flag

--- client/activity/lib/components/channelthreadpane/index.coffee
+++ client/activity/lib/components/channelthreadpane/index.coffee
@@ -4,11 +4,14 @@
 ActivityFlux         = require 'activity/flux'
 immutable            = require 'immutable'
 ThreadSidebar        = require 'activity/components/threadsidebar'
-ThreadHeader         = require 'activity/components/threadheader'
+ChannelThreadHeader  = require 'activity/components/channelthreadheader'
+FeedThreadHeader     = require 'activity/components/feedthreadheader'
 ImmutableRenderMixin = require 'react-immutable-render-mixin'
 PublicChatPane       = require 'activity/components/publicchatpane'
+PublicFeedPane       = require 'activity/components/publicfeedpane'
 ChannelDropContainer = require 'activity/components/channeldropcontainer'
 getGroup             = require 'app/util/getGroup'
+isFeedEnabled        = require 'app/util/isFeedEnabled'

 module.exports = class ChannelThreadPane extends React.Component

@@ -60,13 +63,26 @@

     return  unless thread = @state.channelThread

-    <ThreadHeader
-      className="ChannelThreadPane-header"
-      thread={thread}
-      onInvitePeople={@bound 'invitePeople'}
-      onLeaveChannel={@bound 'leaveChannel'}
-      onShowNotificationSettings={@bound 'showNotificationSettingsModal'}>
-    </ThreadHeader>
+    if not isFeedEnabled()
+      <ChannelThreadHeader
+        className="ChannelThreadPane-header"
+        thread={thread}
+        onInvitePeople={@bound 'invitePeople'}
+        onLeaveChannel={@bound 'leaveChannel'}
+        onShowNotificationSettings={@bound 'showNotificationSettingsModal'}>
+      </ChannelThreadHeader>
+
+
+  renderPaneByTypeConstant: (thread) ->
+
+    if isFeedEnabled()
+

+        <PublicFeedPane ref='pane' thread={thread}/>
+

+    else
+

+        <PublicChatPane ref='pane' thread={thread}/>
+

   renderBody: ->
@@ -74,9 +90,7 @@
     return null  unless thread = @state.channelThread

-

-        <PublicChatPane ref='pane' thread={thread}/>
-

+      {@renderPaneByTypeConstant(thread)}


Client: Activity: Feed: Updated classNames

--- client/activity/lib/components/publicfeedpane/feeditem.coffee
+++ client/activity/lib/components/publicfeedpane/feeditem.coffee
@@ -67,6 +67,15 @@
     message.unsetMessageEditMode messageId, @props.channelId, yes

+  getClassNames: ->
+
+    { message } = @props
+
+    classnames
+      'FeedItem' : yes
+      'editing'  : message.get '__isEditing'
+      'edited'   : message.get('createdAt') isnt message.get('updatedAt')
+

   renderFeedItemMenu: ->

@@ -77,7 +86,7 @@
     { message } = @props
     likeText = if message.getIn ['interactions', 'like',  'isInteracted'] then 'Unlike' else 'Like'

-

+


Client: Activity: Feed: Added default states

--- client/activity/lib/components/publicfeedpane/feedpane.coffee
+++ client/activity/lib/components/publicfeedpane/feedpane.coffee
@@ -3,23 +3,28 @@
 ReactDOM             = require 'react-dom'
 FeedList             = require './feedlist'
 Scroller             = require 'app/components/scroller'
-Encoder              = require 'htmlencode'
-whoami               = require 'app/util/whoami'
 immutable            = require 'immutable'
 FeedInputWidget      = require './feedinputwidget'
 FeedPaneTabContainer = require './feedpanetabcontainer'
 FeedThreadHeader     = require './feedthreadheader'
 FeedThreadSidebar    = require 'activity/components/publicfeedpane/feedthreadsidebar'
+ActivityFlux         = require 'activity/flux'
+KDReactorMixin       = require 'app/flux/base/reactormixin'
+ImmutableRenderMixin = require 'react-immutable-render-mixin'
+ActivitySharePopup   = require 'activity/components/activitysharepopup'

 module.exports = class FeedPane extends React.Component

   @defaultProps =
-    title           : null
-    messages        : null
-    isDataLoading   : no
-    onInviteOthers  : kd.noop
-    showItemMenu    : yes
     popularChannels : immutable.List()
+    messages : null
+
+
+  getDataBindings: ->
+    return {
+      socialShareLinks        : ActivityFlux.getters.socialShareLinks
+      activeSocialShareLinkId : ActivityFlux.getters.activeSocialShareLinkId
+    }

   componentDidMount: ->


Update profile statusbar to include new time.

--- community/browser/app/scripts/controllers/CypherResult.coffee
+++ community/browser/app/scripts/controllers/CypherResult.coffee
@@ -114,7 +114,7 @@

         message = "Cypher version: #{root.version}, planner: #{root.planner}."
         if collectHits(root)
-          message += " #{collectHits(root)} total db hits in #{frame.runTime} ms."
+          message += " #{collectHits(root)} total db hits in #{frame.response.responseTime} ms."
         message

     # Listen for export events bubbling up the controller hierarchy


Revert "payment: stop refunding users since recurly does it automatically"

This reverts commit 872b4f7206d6bdbb2e4eb623f55444154cc3c3b1.

--- workers/social/lib/social/models/payment/subscription.coffee
+++ workers/social/lib/social/models/payment/subscription.coffee
@@ -145,19 +145,14 @@
         Refund for the remaining days of your current plan: #{ oldPlan.title }
         """

-      # There is a bug somewhere that's causing us to refund
-      # and charge less when upgrading, temporarily commenting
-      # this out: SA
-      #
-      # if applyRefund
-      #   @refund { amount, description }, (err) ->
-      #     return callback err  if err
-
-      #     callback null, amount
-      # else
-      #   callback null, 0
-
-      callback null, 0
+      if applyRefund
+        @refund { amount, description }, (err) ->
+          return callback err  if err
+
+          callback null, amount
+      else
+        callback null, 0
+

   resume: (callback) ->
     @fetchLinkedSubscription (err, subscription) =>


fix coffee grammer using coffeelint

fix coffee grammer using coffeelint

--- desktop/assets/analytics.coffee
+++ desktop/assets/analytics.coffee
@@ -12,13 +12,14 @@
 require '../analytics/before_ready.js'

 $ -> analytics.ready ->
-    $.ajax '//munchkin.marketo.net/munchkin.js',
-        dataType: 'script'
-        cache: true
-        success: (data, textStatus, jqXHR) -> $('body').append "Successful AJAX call: #{data}"
+  $.ajax '//munchkin.marketo.net/munchkin.js',
+      dataType: 'script'
+      cache: true
+      error: (jqXHR, textStatus, errorThrown) -> $('body').append "AJAX Error: #{textStatus}"
+      success: (data, textStatus, jqXHR) -> $('body').append "Successful AJAX call: #{data}"

   if sd.CURRENT_USER?.id
-    whitelist = ['collector_level', 'default_profile_id', 'email', 'id', 'name', 'phone', 'type'];
+    whitelist = ['collector_level', 'default_profile_id', 'email', 'id', 'name', 'phone', 'type']
     traits = _.extend _.pick(sd.CURRENT_USER, whitelist), session_id: sd.SESSION_ID
     analytics.identify sd.CURRENT_USER.id, traits, integrations: { 'Marketo': false }
     # clear analytics cache when user logs out


process includes on save

process includes on save

--- src/cs-resource/cs-resource.js.coffee
+++ src/cs-resource/cs-resource.js.coffee
@@ -169,7 +169,17 @@

       csRestApi.create(endpoint, entity).then(
         (data) =>  # successCallback
-          return @.$assign(data.data)
+          object = @.$assign(data.data)
+          included = _.map data.included, (i) =>
+            assoc = object.$datastore.get(i.type, i.id)
+            if assoc
+              assoc.$assign(i)
+              return assoc
+            else
+              resource = ResourceService.get(i.type)
+              return new resource(i, datastore: object.$datastore)
+          return object
+
         (reason) => # errorCallback
           return $q.reject(reason);
         (value) =>  # notifyCallback


ListView: Make "wheel" listener in Q2 smarter: Don't preventDefault is not needed.

--- src/elements/ListView/ListView.coffee
+++ src/elements/ListView/ListView.coffee
@@ -328,14 +328,27 @@
 				type: "wheel"
 				node: @quadrant[2]
 				call: (ev) =>
+					scroll_delta = 100
+
+					if ev.wheelDeltaY() > 0
+						if @quadrant[3].scrollTop == (@quadrant[3].scrollHeight - @quadrant[3].offsetHeight)
+							# at bottom
+							return
+
+						@quadrant[3].scrollTop += scroll_delta
+
+					else if ev.wheelDeltaY() < 0
+						if @quadrant[3].scrollTop == 0
+							# at top
+							return
+
+						@quadrant[3].scrollTop -= scroll_delta
+					else
+						return
+
 					ev.preventDefault()
-					if ev.wheelDeltaY() > 0
-						@quadrant[3].scrollTop += 100
-
-					if ev.wheelDeltaY() < 0
-						@quadrant[3].scrollTop -= 100
-
 					on_scroll()
+					return

 		Events.listen
 			type: "viewport-resize"


Enable string-typed model parameters

Enable string-typed model parameters

--- src/ext/components/model-input.coffee
+++ src/ext/components/model-input.coffee
@@ -214,7 +214,7 @@
       createListControl parameter
     when 'boolean'
       createCheckboxControl parameter
-    when 'Key<Model>', 'byte', 'short', 'int', 'long', 'float', 'double', 'byte[]', 'short[]', 'int[]', 'long[]', 'float[]', 'double[]'
+    when 'Key<Model>', 'string', 'byte', 'short', 'int', 'long', 'float', 'double', 'byte[]', 'short[]', 'int[]', 'long[]', 'float[]', 'double[]'
       createTextboxControl parameter, parameter.type
     else
       console.error 'Invalid field', JSON.stringify parameter, null, 2


Greater than sign error

Greater than sign error

--- app/assets/javascripts/static_pages.js.coffee
+++ app/assets/javascripts/static_pages.js.coffee
@@ -134,7 +134,7 @@
 		currentDistance = (if (startX is 0) then 0 else Math.abs(currentX - startX))
 		currentTime = e.timeStamp
 		if startTime != 0 && currentTime - startTime < maxTime && currentDistance > maxDistance
-			if($(window).width() > ResponsiveWindowWidth)
+			if($(window).width() <= ResponsiveWindowWidth)
 				if currentX < startX
 					console.log("Swipe Right")
 					if $(".menu").data("state") == "open"


remove useless comments

remove useless comments

--- app/assets/javascripts/uploadcare/boot.coffee
+++ app/assets/javascripts/uploadcare/boot.coffee
@@ -1,7 +1,6 @@
 import $ from 'jquery'
 import uploadcare from './namespace.coffee'
 import { version } from '../../../../package.json'
-# app/assets/javascripts/uploadcare/namespace.coffee

 uploadcare.version = version


remove authentication

remove authentication

--- app/controllers/application_controller.coffee
+++ app/controllers/application_controller.coffee
@@ -1,9 +1,3 @@
 # TODO debug forgery with singe page application
 #before 'protect from forgery', ->
 #    protectFromForgery '014bab01fb364db464d3f1c9a4c4fe8e4032ed0b'
-
-
-if app.settings.env == "production"
-    before 'check authentication', ->
-        if req.isAuthenticated() then next() else send 403
-


No es necesaria esta vista

No es necesaria esta vista

--- app/assets/javascripts/views/clientes/clientes_index_view.js.coffee
+++ app/assets/javascripts/views/clientes/clientes_index_view.js.coffee
@@ -1,2 +0,0 @@
-Bandango.ClientesIndexView = Ember.View.extend
-  templateName: "clientes/index"


list domains for subdomain creation

list domains for subdomain creation

--- client/landing/app/Applications/Environments.kdapplication/views/DomainRegisterModalFormView.coffee
+++ client/landing/app/Applications/Environments.kdapplication/views/DomainRegisterModalFormView.coffee
@@ -127,6 +127,11 @@

     paymentController = KD.getSingleton('paymentController')
     group             = KD.getSingleton("groupsController").getCurrentGroup()
+    domainOptions     = [
+      { title : "Create a #{nickname}.kd.io subdomain", value : "subdomain" }
+      { title : "I want to register a domain",          value : "new" }
+      { title : "I already have a domain",              value : "existing" }
+    ]

     super
       navigable                       : no
@@ -147,7 +152,7 @@
                 {createButton, billingButton} = form.buttons

                 billingButton.hideLoader()
-
+
                 paymentController.setBillingInfo 'user', group, (success)->
                   if success
                     billingButton.hide()
@@ -177,11 +182,7 @@
               itemClass               : KDRadioGroup
               cssClass                : "group-type"
               defaultValue            : "subdomain"
-              radios                  : [
-                { title : "Create a #{nickname}.kd.io subdomain", value : "subdomain" }
-                { title : "I want to register a domain",          value : "new" }
-                { title : "i already have a domain",              value : "existing" }
-              ]
+              radios                  : domainOptions
               change                  : =>
                 {DomainOption, domainName, domains, regYears} = @forms["Domain Address"].inputs
                 actionState = DomainOption.getValue()
@@ -204,6 +205,8 @@
                     regYears.hide()
                     @needBilling no
                     "#{KD.utils.slugify firstName}s-subdomain"
+
+
             domainName                :
               placeholder             : "#{KD.utils.slugify firstName}s-new-domain.com"
               validate                :
@@ -221,11 +224,6 @@
                 domains               :
                   cssClass            : "hidden"
                   itemClass           : KDSelectBox
-                  selectOptions       : [
-                      # wire this
-                      {title : "vm-0.#{nickname}.kd.io", value : "vm-0"}
-                      {title : "vm-1.#{nickname}.kd.io", value : "vm-1"}
-                    ]
                   validate            :
                     rules             :
                       required        : yes
@@ -240,6 +238,14 @@
     form.on "FormValidationFailed", createButton.bound 'hideLoader'
     @on "DomainCreationCancelled", createButton.bound 'hideLoader'

+  viewAppended:->
+    KD.whoami().fetchDomains (err, userDomains)=>
+      warn err  if err
+      domainList = []
+      for domain in userDomains
+        domainList.push {title:domain.domain, value:domain.domain}  unless domain.regYears > 0
+      @forms["Domain Address"].inputs.domains.setSelectOptions domainList
+
   needBilling:(paymentRequired)->
     form = @forms["Domain Address"]
     {createButton, billingButton} = form.buttons
@@ -253,7 +259,6 @@
     group             = KD.getSingleton("groupsController").getCurrentGroup()

     paymentController.getBillingInfo 'user', group, (err, account)->
-      console.log arguments
       need = err or not account or not account.cardNumber
       if need
         billingButton.show()
@@ -315,8 +320,24 @@
           return notifyUser "An error occured. Please try again later."
         else
           @showSuccess()
-    else
-      log "mengu please handle this case as well... - SY"
+    else if domainOptionValue is 'subdomain'
+      KD.remote.api.JDomain.createDomain
+        domain         : domainName.getValue()
+        regYears       : 0
+        hostnameAlias  : []
+        loadBalancer   :
+            mode       : "roundrobin"
+      , (err, domain)=>
+        createButton.hideLoader()
+        if err
+          warn err
+          return notifyUser "An error occured. Please try again later."
+        else
+          @showSuccess()
+
+    else # groupSubDomain
+
+

   clearSuggestions:-> @suggestionBox?.destroy()


add request_render function call on tile laod

--- bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
+++ bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
@@ -38,7 +38,7 @@
     tile_data.img = e.target
     tile_data.current = true
     @mget('tile_source').tiles[tile_data.cache_key] = tile_data
-    @request_render
+    @request_render()

   _on_tile_cache_load: (e) =>
     tile_data = e.target.tile_data
@@ -164,23 +164,19 @@
             parents.push(parent_key)
           need_load.push(t)

-    # draw stand-in parents
+    # draw stand-in parents ----------
     @_render_tiles(parents)

-    # draw cached
+    # draw cached ----------
     @_render_tiles(cached)
     for t in cached
       @mget('tile_source').tiles[t].current = true

-    # fetch missing
-    if Object.keys(@mget('tile_source').tiles).length == 0
-      @_fetch_tiles(need_load)
-    else
-
-      if @render_timer?
-        clearTimeout(@render_timer)
-
-      @render_timer = setTimeout((=> @_fetch_tiles(need_load)), 65)
+    # fetch missing -------
+    if @render_timer?
+      clearTimeout(@render_timer)
+
+    @render_timer = setTimeout((=> @_fetch_tiles(need_load)), 65)

     # prune cached tiles
     #@tile_source.prune_tiles()


Update cancellation survey link

Update cancellation survey link

--- services/web/app/coffee/Features/Email/EmailBuilder.coffee
+++ services/web/app/coffee/Features/Email/EmailBuilder.coffee
@@ -26,7 +26,7 @@
 	compiledTemplate: _.template '''

Hi <%= first_name %>,

-
I'm sorry to see you cancelled your ShareLaTeX premium account. Would you mind giving me some advice on what the site is lacking at the moment via this survey?

+
I'm sorry to see you cancelled your ShareLaTeX premium account. Would you mind giving me some advice on what the site is lacking at the moment via this survey?

Thank you in advance.


Whitelist folders path from core

Whitelist folders path from core

There are several folders bundled in the app that aren't needed in the
require cache list so it is simpler to opt-in the folders that should
be part of the cache.

--- build/tasks/generate-module-cache-task.coffee
+++ build/tasks/generate-module-cache-task.coffee
@@ -11,3 +11,19 @@
       ModuleCache.create(path.join(appDir, 'node_modules', packageName))

     ModuleCache.create(appDir)
+
+    metadata = grunt.file.readJSON(path.join(appDir, 'package.json'))
+
+    metadata._atomModuleCache.folders.forEach (folder) ->
+      if '' in folder.paths
+        folder.paths = [
+          ''
+          'exports'
+          'spec'
+          'src'
+          'src/browser'
+          'static'
+          'vendor'
+        ]
+
+    grunt.file.write(path.join(appDir, 'package.json'), JSON.stringify(metadata, null, 2))


corrects fetch_cart urls Fixes #5325

corrects fetch_cart urls
Fixes #5325

--- frontend/app/assets/javascripts/spree/frontend/cart.js.coffee
+++ frontend/app/assets/javascripts/spree/frontend/cart.js.coffee
@@ -10,6 +10,6 @@

 Spree.fetch_cart = ->
   $.ajax
-    url: Spree.pathFor("/cart_link"),
+    url: Spree.pathFor("cart_link"),
     success: (data) ->
       $('#link-to-cart').html data


Take the same approach to load all plugins

--- bokehjs/src/coffee/node_main.coffee
+++ bokehjs/src/coffee/node_main.coffee
@@ -32,12 +32,12 @@
 Bokeh = require './main'
 _ = Bokeh._

-APIs = require './api'
-_.extend(Bokeh, _.omit(APIs, "models"))
+load_plugin = (path) ->
+  plugin = require(path)
+  _.extend(Bokeh, _.omit(plugin, "models"))
+  Bokeh.Models.register_locations(plugin.models ? {})

-Bokeh.require_widgets = () ->
-  Widgets = require './models/widgets/main'
-  _.extend(Bokeh, _.omit(Widgets, "models"))
-  Bokeh.Models.register_locations(Widgets.models)
+load_plugin('./api')
+load_plugin('./models/widgets/main')

 module.exports = Bokeh


Remove unnecessary require

Remove unnecessary require

--- test/response-cache-test.coffee
+++ test/response-cache-test.coffee
@@ -1,5 +1,3 @@
-require 'coffee-script'
-
 assert = require 'assert'
 responseCache = require '../lib/response-cache.coffee'


Add failing test for time entries in a project

--- test/routes/time_entries.coffee
+++ test/routes/time_entries.coffee
@@ -114,3 +114,14 @@
         request (base "/time_entries/#{teb.id}"), _.clone(options), (e,r,b)->
           r.statusCode.should.be.equal 404
           done()
+
+  describe 'in a project', ->
+    it 'should have time entries associated with the project', (done)->
+      request.get (base "/projects/#{testProject.id}/time_entries"), _.clone(options), (e,r,b)->
+        r.statusCode.should.be.equal 200
+        b.should.have.propert 'length'
+        if b.length is 0
+          throw new Error 'No time_entries to test'
+        else
+          _.each b, (t)-> (new TimeEntry t).validate().should.be.true
+          done()


Corrige bug no roteamento quando em páginas que não a index ou profile

Agora usamos regexps para parsear a URL, ao invés de usar o tamanho e posição
da URL. Dessa forma, conseguimos diferenciar entre:

  /quem-somos
  /2012

--- app/assets/javascripts/angular_app/services/routing.js.coffee
+++ app/assets/javascripts/angular_app/services/routing.js.coffee
@@ -37,16 +37,25 @@
         else
           window.location.pathname = newUrl
     parseUrl: (entities) ->
-      path = window.location.pathname.substr(1)
-      parts = path.split('/')
-      id = if parts.length == 3
-             slugToId(parts[1]) # É uma unidade orçamentária
-           else if parts.length == 2
-             slugToId(parts[0]) # É um órgão
+      path = window.location.pathname
+      uoRegexp = /^\/(.+)\/(.+)\/([0-9]{4})$/
+      orgaoRegexp = /^\/(.+)\/([0-9]{4})$/
+      anoRegexp = /^\/([0-9]{4})$/
+
+      id = undefined
+      year = undefined
+
+      if match = uoRegexp.exec(path)
+        id = slugToId(match[2])
+        year = match[3]
+      else if match = orgaoRegexp.exec(path)
+        id = slugToId(match[1])
+        year = match[2]
+      else if match = anoRegexp.exec(path)
+        year = match[1]

       entity = if id
         (entities.filter (entity) -> parseInt(entity.id) == id)[0]
-      year = parts[parts.length-1] || undefined
       [entity, year]
     generateUrl: generateUrl
 ])


fix indentation

fix indentation

--- app/components/create-project-page/create-project-page.coffee
+++ app/components/create-project-page/create-project-page.coffee
@@ -11,4 +11,4 @@
     $scope.done = () ->
       if $scope.bucketForm.$valid
         $scope.bucket.save().then ->
-        $scope.cancel()+          $scope.cancel()


fixed chartjs redraw

fixed chartjs redraw

--- app/assets/javascripts/mno_enterprise/angular/directives/impac/widgets/common/chart.js.coffee
+++ app/assets/javascripts/mno_enterprise/angular/directives/impac/widgets/common/chart.js.coffee
@@ -41,7 +41,6 @@
         scope.$watch((-> scope.data)
           ,(value) ->
             if value?
-              scope.draw()
               $timeout((-> scope.draw()),100)
         ,true)
     }


refactor range tests

refactor range tests

--- tests/scripts/unit/range.coffee
+++ tests/scripts/unit/range.coffee
@@ -1,46 +1,43 @@
 describe('Range', ->
   describe('Position', ->
-    it('should correctly initialize position from index', ->
-      $('#test-container').html(Scribe.Utils.cleanHtml('
-

-          12
-          34
-

-

-          <s>56</s>
-          78
-

-

-

-
'))
-      expectedResults = [
-        { text: '12', offset: 0 }
-        { text: '12', offset: 1 }
-        { text: '34', offset: 0 }
-        { text: '34', offset: 1 }
-        { text: '34', offset: 2 }
-        { text: '56', offset: 0 }
-        { text: '56', offset: 1 }
-        { text: '78', offset: 0 }
-        { text: '78', offset: 1 }
-        { text: '78', offset: 2 }
-        { text: '', offset: 0 }
+    positionTests = new Scribe.Test.EditorTest(
+      initial: [
+        '
1234
'
+        '
<s>56</s>78
'
+        '

'
       ]
-      editor = new Scribe.Editor('test-container')
-      _.each(expectedResults, (result, i) ->
-        position = new Scribe.Position(editor, i)
-        expect(position.leafNode.textContent).to.equal(result.text)
-        expect(position.offset).to.equal(result.offset)
-      )
+      expected: [0, 1, 2]
+    )
+
+    positionTests.run('should correctly initialize position from index',
+      checker: (editor) ->
+        expectedResults = [
+          { text: '12', offset: 0 }
+          { text: '12', offset: 1 }
+          { text: '34', offset: 0 }
+          { text: '34', offset: 1 }
+          { text: '34', offset: 2 }
+          { text: '56', offset: 0 }
+          { text: '56', offset: 1 }
+          { text: '78', offset: 0 }
+          { text: '78', offset: 1 }
+          { text: '78', offset: 2 }
+          { text: '', offset: 0 }
+        ]
+        _.each(expectedResults, (result, i) ->
+          position = new Scribe.Position(editor, i)
+          expect(position.leafNode.textContent).to.equal(result.text)
+          expect(position.offset).to.equal(result.offset)
+        )
     )
   )

   describe('getText', ->
-    reset = ->
-      $('#test-container').html(Scribe.Utils.cleanHtml('
-

+    textTests = new Scribe.Test.EditorTest(
+      initial:
+        '

           abc
           def

@@ -61,113 +58,34 @@
           q
           <s>r</s>
           s
-
'))
-      editor = new Scribe.Editor('test-container')
-      return editor
-
+
'
+      expected: [0]
+    )
     text = "abcdef\nhijklmno\npqrs"

-    it('should identifiy single node', ->
-      editor = reset()
-      _.each(text.split(''), (char, index) ->
-        range = new Scribe.Range(editor, index, index + 1)
-        expect(range.getText()).to.equal(char)
-      )
-    )
-
-    it('should identifiy entire document', ->
-      editor = reset()
-      range = new Scribe.Range(editor, 0, text.length)
-      expect(range.getText()).to.equal(text)
+    textTests.run('should identifiy single node',
+      checker: (editor) ->
+        _.each(text.split(''), (char, index) ->
+          range = new Scribe.Range(editor, index, index + 1)
+          expect(range.getText()).to.equal(char)
+        )
+    )
+
+    textTests.run('should identifiy entire document',
+      checker: (editor) ->
+        range = new Scribe.Range(editor, 0, text.length)
+        expect(range.getText()).to.equal(text)
     )
   )

   describe('getFormats', ->
-    tests = [{
-      name: 'inside of node'
-      start: 1
-      end: 2
-      text: '2'
-      formats: { bold: true }
-    }, {
-      name: 'start of node'
-      start: 0
-      end: 1
-      text: '1'
-      formats: { bold: true }
-    }, {
-      name: 'end of node'
-      start: 2
-      end: 3
-      text: '3'
-      formats: { bold: true }
-    }, {
-      name: 'entire node'
-      start: 0
-      end: 3
-      text: '123'
-      formats: { bold: true }
-    }, {
-      name: 'cursor inside of node'
-      start: 1
-      end: 1
-      text: ''
-      formats: { bold: true }
-    }, {
-      name: 'cursor at start of node'
-      start: 0
-      end: 0
-      text: ''
-      formats: { bold: true }
-    }, {
-      name: 'cursor at end of node'
-      start: 3
-      end: 3
-      text: ''
-      formats: { italic: true }
-    }, {
-      name: 'node at end of document'
-      start: 19
-      end: 20
-      text: '8'
-      formats: { underline: true }
-    }, {
-      name: 'cursor at end of document'
-      start: 20
-      end: 20
-      text: ''
-      formats: { underline: true }
-    }, {
-      name: 'part of two nodes'
-      start: 8
-      end: 10
-      text: "89"
-      formats: { bold: true }
-    }, {
-      name: 'node with preceding newline'
-      start: 6
-      end: 9
-      text: "\n78"
-      formats: { bold: true, strike: true }
-    }, {
-      name: 'node with trailing newline'
-      start: 13
-      end: 16
-      text: "34\n"
-      formats: { bold: true, strike: true }
-    }, {
-      name: 'line with preceding and trailing newline'
-      start: 6
-      end: 16
-      text: "\n78901234\n"
-      formats: { bold: true }
-    }]
-
-    reset = ->
-      $('#test-container').html(Scribe.Utils.cleanHtml('
-

+
+
+    formatTests = new Scribe.Test.EditorTest(
+      initial:
+        '

           123
           456

@@ -188,85 +106,108 @@
           6
           <s>7</s>
           8
-
'))
-      editor = new Scribe.Editor('test-container')
-      return editor
-
-    _.each(tests, (test) ->
-      it(test.name, ->
-        editor = reset()
-        range = new Scribe.Range(editor, test.start, test.end)
-        expect(range.getText()).to.equal(test.text)
-        expect(range.getFormats()).to.eql(_.extend({}, Scribe.Leaf.DEFAULT_FORMATS, test.formats))
-      )
-    )
+
'
+      expected: [0]
+      checker: (testEditor, expectedEditor, start, end, text, formats) ->
+        range = new Scribe.Range(testEditor, start, end)
+        expect(range.getText()).to.equal(text)
+        expect(range.getFormats()).to.eql(_.extend({}, Scribe.Leaf.DEFAULT_FORMATS, formats))
+    )
+
+    formatTests.run('inside of node', {}, 1, 2, '2', { bold: true })
+    formatTests.run('start of node', {}, 0, 1, '1', { bold: true })
+    formatTests.run('end of node', {}, 2, 3, '3', { bold: true })
+    formatTests.run('entire node', {}, 0, 3, '123', { bold: true })
+    formatTests.run('cursor inside of node', {}, 1, 1, '', { bold: true })
+    formatTests.run('cursor at start of node', {}, 0, 0, '', { bold: true })
+    formatTests.run('cursor at end of node', {}, 3, 3, '', { italic: true })
+    formatTests.run('node at end of document', {}, 19, 20, '8', { underline: true })
+    formatTests.run('cursor at end of document', {}, 20, 20, '', { underline: true })
+    formatTests.run('part of two nodes', {}, 8, 10, '89', { bold: true })
+    formatTests.run('node with preceding newline', {}, 6, 9, '\n78', { bold: true, strike: true })
+    formatTests.run('node with trailing newline', {}, 13, 16, '34\n', { bold: true, strike: true })
+    formatTests.run('line with preceding and trailing newline', {}, 6, 16, "\n78901234\n", { bold: true })
   )

   describe('getLeafNodes', ->
     reset = ->
-      $('#test-container').html('
123456

<s>7</s>8<s>9</s>0
')
+      $('#test-container').html()
       editor = new Scribe.Editor('test-container', false)
       line1 = editor.root.firstChild
       line2 = editor.root.lastChild
       return [editor, editor.root, line1, line2]

-    it('should select a single node at boundaries', ->
-      [editor, container, line1, line2] = reset()
-      range = new Scribe.Range(editor, 0, 3)
-      nodes = range.getLeafNodes()
-      expect(nodes.length).to.equal(1)
-      expect(nodes[0]).to.equal(line1.firstChild)
-    )
-    it('should select multiple nodes at boundaries', ->
-      [editor, container, line1, line2] = reset()
-      range = new Scribe.Range(editor, 0, 6)
-      nodes = range.getLeafNodes()
-      expect(nodes.length).to.equal(2)
-      expect(nodes[0]).to.equal(line1.childNodes[0])
-      expect(nodes[1]).to.equal(line1.childNodes[1])
-    )
-    it('should select a single node inside boundaries', ->
-      [editor, container, line1, line2] = reset()
-      for i in [0..2]
-        range = new Scribe.Range(editor, i, i+1)
+    leafTests = new Scribe.Test.EditorTest(
+      initial: [
+        '
123456
'
+        '
<s>7</s>8<s>9</s>0
'
+      ]
+      expected: [0, 1]
+    )
+
+    leafTests.run('should select a single node at boundaries',
+      checker: (editor) ->
+        range = new Scribe.Range(editor, 0, 3)
         nodes = range.getLeafNodes()
         expect(nodes.length).to.equal(1)
-        expect(nodes[0]).to.equal(line1.firstChild)
-    )
-    it('should select multipe nodes inside boundaries', ->
-      [editor, container, line1, line2] = reset()
-      for i in [0..2]
-        range = new Scribe.Range(editor, i, i+4)
+        expect(nodes[0]).to.equal(editor.root.firstChild.firstChild)
+    )
+
+    leafTests.run('should select multiple nodes at boundaries',
+      checker: (editor) ->
+        range = new Scribe.Range(editor, 0, 6)
         nodes = range.getLeafNodes()
         expect(nodes.length).to.equal(2)
-        expect(nodes[0]).to.equal(line1.childNodes[0])
-        expect(nodes[1]).to.equal(line1.childNodes[1])
-    )
-    it('should select multiple nodes across lines within boundaries', ->
-      [editor, container, line1, line2] = reset()
-      range = new Scribe.Range(editor, 0, 6)
-      nodes = range.getLeafNodes()
-      expect(nodes.length).to.equal(2)
-      expect(nodes[0]).to.equal(line1.childNodes[0])
-      expect(nodes[1]).to.equal(line1.childNodes[1])
-    )
-    it('should select multiple nodes across lines outside boundaries', ->
-      [editor, container, line1, line2] = reset()
-      range = new Scribe.Range(editor, 5, 8)
-      nodes = range.getLeafNodes()
-      expect(nodes.length).to.equal(2)
-      expect(nodes[0]).to.equal(line1.lastChild)
-      expect(nodes[1]).to.equal(line2.firstChild)
-    )
-    it('should select node collapsed', ->
-      [editor, container, line1, line2] = reset()
-      for i in [0..2]
-        range = new Scribe.Range(editor, i, i)
-        nodes = range.getLeafNodes()
-        expect(nodes.length).to.equal(1)
-        expect(nodes[0]).to.equal(line1.firstChild)
+        expect(nodes[0]).to.equal(editor.root.firstChild.childNodes[0])
+        expect(nodes[1]).to.equal(editor.root.firstChild.childNodes[1])
+    )
+
+    leafTests.run('should select a single node inside boundaries',
+      checker: (editor) ->
+        for i in [0..2]
+          range = new Scribe.Range(editor, i, i+1)
+          nodes = range.getLeafNodes()
+          expect(nodes.length).to.equal(1)
+          expect(nodes[0]).to.equal(editor.root.firstChild.firstChild)
+    )
+
+    leafTests.run('should select multipe nodes inside boundaries',
+      checker: (editor) ->
+        for i in [0..2]
+          range = new Scribe.Range(editor, i, i+4)
+          nodes = range.getLeafNodes()
+          expect(nodes.length).to.equal(2)
+          expect(nodes[0]).to.equal(editor.root.firstChild.childNodes[0])
+          expect(nodes[1]).to.equal(editor.root.firstChild.childNodes[1])
+    )
+
+    leafTests.run('should select multiple nodes across lines within boundaries',
+      checker: (editor) ->
+        range = new Scribe.Range(editor, 0, 6)
+        nodes = range.getLeafNodes()
+        expect(nodes.length).to.equal(2)
+        expect(nodes[0]).to.equal(editor.root.firstChild.childNodes[0])
+        expect(nodes[1]).to.equal(editor.root.firstChild.childNodes[1])
+    )
+
+    leafTests.run('should select multiple nodes across lines outside boundaries',
+      checker: (editor) ->
+        range = new Scribe.Range(editor, 5, 8)
+        nodes = range.getLeafNodes()
+        expect(nodes.length).to.equal(2)
+        expect(nodes[0]).to.equal(editor.root.firstChild.lastChild)
+        expect(nodes[1]).to.equal(editor.root.lastChild.firstChild)
+    )
+
+    leafTests.run('should select node collapsed',
+      checker: (editor) ->
+        for i in [0..2]
+          range = new Scribe.Range(editor, i, i)
+          nodes = range.getLeafNodes()
+          expect(nodes.length).to.equal(1)
+          expect(nodes[0]).to.equal(editor.root.firstChild.firstChild)
     )
   )
 )


Tweak rust highlighting

Tweak rust highlighting

* Highlight ! in macro invocations the same color as the macro name
* Highlight crate and super the same everywhere

Refs atom/language-rust#1

--- packages/language-rust-bundled/grammars/tree-sitter-rust.cson
+++ packages/language-rust-bundled/grammars/tree-sitter-rust.cson
@@ -55,6 +55,7 @@

   '''
   macro_invocation > identifier,
+  macro_invocation > "!",
   macro_definition > identifier,
   call_expression > identifier,
   call_expression > field_expression > field_identifier,
@@ -69,13 +70,9 @@
   '''
   use_list > self,
   scoped_use_list > self,
-  scoped_identifier> self,
-  use_list > crate,
-  scoped_use_list > crate,
-  scoped_identifier> crate,
-  use_list > super,
-  scoped_use_list > super,
-  scoped_identifier> super
+  scoped_identifier > self,
+  crate,
+  super
   ''': 'keyword.control'

   '''


Client: Activity: Added updatePurpose method to show purpose input for editing

--- client/activity/lib/components/channelthreadpane/index.coffee
+++ client/activity/lib/components/channelthreadpane/index.coffee
@@ -35,6 +35,8 @@
     super props

     @state =
+      originalPurpose       : ''
+      editingPurpose        : no
       showDropTarget        : no
       isComingSoonModalOpen : no
       channelThread         : immutable.Map()
@@ -95,6 +97,12 @@

   updatePurpose: ->
+
+    @setState editingPurpose: yes
+    input = React.findDOMNode @refs.purposeInput
+
+    kd.utils.defer ->
+      kd.utils.moveCaretToEnd input

   showNotificationSettingsModal: ->


Client: Activity: Added new props to SideBarModalList component

--- client/app/lib/components/sidebarchannelssection/index.coffee
+++ client/app/lib/components/sidebarchannelssection/index.coffee
@@ -10,8 +10,9 @@
 module.exports = class SidebarChannelsSection extends React.Component

   @defaultProps =
+    selectedId : null
     threads    : immutable.Map()
-    selectedId : null
+    sidebarChannelsSection: immutable.Map()

   constructor: (props) ->

@@ -36,7 +37,10 @@
     <Modal className='ChannelList-Modal' isOpen={@state.isModalOpen} onClose={@bound 'onClose'}>
       <SidebarModalList
         title={title}
+        searchProp='name'
+        sidebarModalChannels={@props.sidebarModalChannels}
         threads={@props.threads}
+        onThresholdAction='loadFollowedPublicChannels'
         itemComponent={PublicChannelListItem}/>
     </Modal>