Profile: createContentDisplay method structure is updated

--- client/Social/Members/AppController.coffee
+++ client/Social/Members/AppController.coffee
@@ -15,8 +15,7 @@
   {externalProfiles} = KD.config

   constructor:(options = {}, data)->
-
-    options.view    = new MembersMainView
+    options.view    = new KDView
       cssClass      : 'content-page members'
     options.appInfo =
       name          : 'Members'
@@ -27,31 +26,47 @@

     @on "LazyLoadThresholdReached", => @feedController?.loadFeed()

-  createContentDisplay:(account, callback=->)->
+  createContentDisplay:(model, callback=->)->
     KD.singletons.appManager.setFrontApp this
     contentDisplay = new KDView
       cssClass : 'member content-display'
       type     : 'profile'
+
     contentDisplay.on 'handleQuery', (query)=>
       @ready => @feedController?.handleQuery? query

     contentDisplay.once 'KDObjectWillBeDestroyed', ->
       KD.singleton('appManager').tell 'Activity', 'resetProfileLastTo'

-    {JAccount} = KD.remote.api
-    if account instanceof JAccount
-      @addProfileView contentDisplay, account
-      @addActivityView contentDisplay, account
-    else
-      @addActivityView contentDisplay, KD.whoami()
-    @showContentDisplay contentDisplay
-    @utils.defer -> callback contentDisplay
-
-  addActivityView:(view, account)->
-    view.$('div.lazy').remove()
+    KD.getSingleton('groupsController').ready =>
+      contentDisplay.$('div.lazy').remove()
+      {JAccount} = KD.remote.api
+      if model instanceof JAccount
+        @createProfileView contentDisplay, model
+      else
+        @createGroupMembersView contentDisplay
+      @showContentDisplay contentDisplay
+      @utils.defer -> callback contentDisplay
+
+  createProfileView: (contentDisplay, model)->
+    @prepareProfileView model, (profileView)=>
+      contentDisplay.addSubView profileView
+      @prepareFeederView model, (feederView)->
+        contentDisplay.addSubView feederView
+        contentDisplay.setCss minHeight : window.innerHeight
+
+  createGroupMembersView: (contentDisplay)->
+    contentDisplay.addSubView new HeaderViewSection
+      title    : "Members"
+      type     : "big"
+    @prepareFeederView KD.whoami(), (feederView)->
+      contentDisplay.addSubView feederView
+      contentDisplay.setCss minHeight : window.innerHeight
+
+  prepareFeederView:(account, callback)->
     windowController = KD.getSingleton('windowController')

-    if KD.whoami().getId() is account.getId()
+    if KD.isMine account
       owner   = "you"
       auxVerb =
         have : "have"
@@ -74,9 +89,8 @@
         statuses            :
           noItemFoundText   : "#{owner} #{auxVerb.have} not shared any posts yet."
           dataSource        : (selector, options = {}, callback)=>
-            KD.getSingleton('groupsController').ready ->
-              options.originId = account.getId()
-              KD.getSingleton("appManager").tell 'Activity', 'fetchActivitiesProfilePage', options, callback
+            options.originId = account.getId()
+            KD.getSingleton("appManager").tell 'Activity', 'fetchActivitiesProfilePage', options, callback
         followers           :
           loggedInOnly      : yes
           itemClass         : GroupMembersPageListItemView
@@ -113,6 +127,7 @@
           listControllerClass: MembersListViewController
           listCssClass       : "member-related"
           dataSource         : (selector, options, callback)=>
+            group = KD.getGroup()
             group.fetchMembers selector, options, (err, res)=>
               KD.mixpanel "Load member list, success"  unless err
               callback err, res
@@ -138,26 +153,19 @@
           direction         : 1
     }, (controller)=>
       @feedController = controller
-      view.addSubView controller.getView()
-      view.setCss minHeight : windowController.winHeight
+      callback controller.getView()
       @emit 'ready'

-  addProfileView:(view, member)->
+  prepareProfileView:(member, callback)->
     options      =
       cssClass   : "profilearea clearfix"
-      delegate   : view

     if KD.isMine member
       options.cssClass = KD.utils.curry "own-profile", options.cssClass
     else
       options.bind = "mouseenter" unless KD.isMine member

-    return view.addSubView memberProfile = new ProfileView options, member
-
-  loadView:(mainView, firstRun = yes, loadFeed = no)->
-    if firstRun
-      mainView.createCommons()
-    @createFeed mainView, loadFeed
+    callback new ProfileView options, member

   showContentDisplay:(contentDisplay)->


remove rogue @show call

remove rogue @show call

--- src/share.coffee
+++ src/share.coffee
@@ -97,8 +97,6 @@
     button   = instance.getElementsByClassName("social")[0]
     networks = instance.getElementsByTagName('li')

-    @show(button)
-
     ## Add listener to activate buttons
     label.addEventListener "click", => @event_toggle(button)


Remove duplicated problem

Remove duplicated problem

--- server/materials/data/topics/dp_bayans.coffee
+++ server/materials/data/topics/dp_bayans.coffee
@@ -20,7 +20,6 @@
         advancedProblems: [
             problem(217),
             problem(1095),
-            problem(1106),
             problem(3001),
         ]
     }


payment: add "used" as an action enum to `JPaymentFulfillmentNonce`

--- workers/social/lib/social/models/payment/nonce.coffee
+++ workers/social/lib/social/models/payment/nonce.coffee
@@ -17,6 +17,7 @@
                    [
                      'debit'
                      'credit'
+                     'used'
                    ]]
     relationships  :
       owner        :


Sprites sorted by their vertical positions

--- app/assets/javascripts/controllers/game_animator.js.coffee
+++ app/assets/javascripts/controllers/game_animator.js.coffee
@@ -44,6 +44,7 @@
       @controller.updateState()

       @.updateSpriteStates()
+      @.sortSpritesByLayers()

     super

@@ -75,6 +76,9 @@
         else
           speedX == 0 and (speedY == 1 or speedY == 0)

+  sortSpritesByLayers: ->
+    for sprite, index in _.sortBy(@object_layer.children, (c)-> c.position.y)
+      @object_layer.setChildIndex(sprite, index) unless @object_layer.getChildIndex(sprite) == index

   createSnowmanSprite: ->
     container = new PIXI.DisplayObjectContainer()


increasing waitForSelector-timeout to 10s

--- app/assets/javascripts/test/helpers/waitForSelector.coffee
+++ app/assets/javascripts/test/helpers/waitForSelector.coffee
@@ -1,7 +1,7 @@
 EC = protractor.ExpectedConditions

-waitForSelector = (selector, condition = "presenceOf", timeout = 5000) ->
+waitForSelector = (selector, condition = "presenceOf", timeout = 10000) ->

   if not EC[condition]
     throw new Error("'#{condition}' is not a valid condition")


fix erb

fix erb

--- lib/generators/marionette/view/templates/app/views/item_view.js.coffee
+++ lib/generators/marionette/view/templates/app/views/item_view.js.coffee
@@ -1,4 +1,4 @@
 @Backbone.app.module "Views.<%= @module.capitalize %>", (<%= @module.capitalize %>, App, Backbone, Marionette, $, _) ->

   class <%= @module.capitalize %>.<%= title.capitalize %> extends App.Views.ItemView
-    template: '#{ @module.underscore }/<%= title.underscore %>'
+    template: '<%= @module.underscore %>/<%= title.underscore %>'


syntax adjustment for the temp static config.

--- app/assets/javascripts/habberdash/habberdash.js.coffee
+++ app/assets/javascripts/habberdash/habberdash.js.coffee
@@ -41,7 +41,7 @@

-Habberdash.staticConfiguration =
+Habberdash.staticConfiguration = {
   readonly: false
   dashboards: [
     {
@@ -74,3 +74,4 @@
       widgets: []
     }
   ]
+}


Abort XHR requests that will be rejected once complete

--- app/assets/javascripts/models/data/xhr_model.js.coffee
+++ app/assets/javascripts/models/data/xhr_model.js.coffee
@@ -12,6 +12,7 @@
       @error = ko.observable(null)
       @isLoaded = ko.observable(false)
       @loadTime = ko.observable(null)
+      @currentRequest = null

       @hits = ko.observable(0)
       @hasNextPage = ko.computed(@_computeHasNextPage, this, deferEvaluation: true)
@@ -40,12 +41,16 @@
         @results(results)

     _load: (params, current, callback) =>
+      if @currentRequest? && @currentRequest.readystate != 4
+        @currentRequest.abort()
+        console.log "Aborted (#{@pendingRequestId})"
       requestId = ++@pendingRequestId
       @isLoading(@pendingRequestId != @completedRequestId)
       console.log("Request (#{requestId}): #{@path}?#{$.param(params)}")
       start = new Date()
-      xhr = getJSON @path, params, (data, status, xhr) =>
+      @currentRequest = xhr = getJSON @path, params, (data, status, xhr) =>
         if requestId > @completedRequestId
+          @currentRequest = null
           @isLoaded(true)
           @completedRequestId = requestId
           @error(null)
@@ -57,11 +62,13 @@
             results = current.concat(results)

           @loadTime(((new Date() - start) / 1000).toFixed(1))
+          @currentRequest = null
           callback?(results)
         else
           console.log("Rejected out-of-sequence request: #{@path}", requestId, params, data)
         @isLoading(@pendingRequestId != @completedRequestId)
       xhr.fail (response, type, reason) =>
+        @currentRequest = null
         if requestId > @completedRequestId
           @completedRequestId = requestId
           @_onFailure(response)


Use trim() instead of own regexp.

Use trim() instead of own regexp.

--- app/assets/javascripts/moebooru/related_tags.js.coffee
+++ app/assets/javascripts/moebooru/related_tags.js.coffee
@@ -77,7 +77,7 @@
       else
         newVal = "#{currentTags} #{tagName}"

-      newVal = "#{newVal.replace(/^\s+|\s+$/g, "").replace(/\s\s+/g, " ")} "
+      newVal = "#{newVal.trim().replace(/\s\s+/g, " ")} "
       newVal = "" if newVal == " "

       @source().val(newVal)


hide inputcatchers when starting in arbitrary mode # 1126

--- app/assets/javascripts/oxalis/view/tracing_view.coffee
+++ app/assets/javascripts/oxalis/view/tracing_view.coffee
@@ -1,4 +1,5 @@
 Marionette = require("backbone.marionette")
+Constants  = require("../constants")

 class TracingView extends Marionette.LayoutView

@@ -29,6 +30,8 @@
   events :
     "contextmenu" : "disableContextMenu"

+  ui :
+    "inputcatchers" : "#inputcatchers"

   initialize : ->

@@ -44,4 +47,11 @@
     event.preventDefault()
     return

+
+  onRender : ->
+
+    # Hide the input catchers arbitrary model
+    if @model.get("mode") in Constants.MODES_ARBITRARY
+      @ui.inputcatchers.hide()
+
 module.exports = TracingView


fix when I click on the conversations for “Charter Schools”, “Gay Marriage” or Marijuana” and then I select browse all comments on either the pro or con side.  If I then click “Popularity” or  “Newness” and then scroll to the bottom, the button says “Browse all X Comments” instead of “Stop Browsing”.

Former-commit-id: cbf5f388fceaa80246d8694da483a9e3da88a023 [formerly 298f291c119a61192d4a495bdf2838590ff4a007] [formerly 7a7b4b1575d81e3f385ec87f423781d6b4caefc3 [formerly 7a7b4b1575d81e3f385ec87f423781d6b4caefc3 [formerly c0716de2cad7dfe96630a9d88ca315cc99819298]]]
Former-commit-id: bcd21b4fc7c38699b9ae464a0b7150b30ee8f525 [formerly e148d5f2bdfe039801caf605c72e5a260b9262cb]
Former-commit-id: 06641ad5434d11dec66539b1378ba781d0c96d1d
Former-commit-id: 85746ac66e6496be162a1ff24346efe6cd8b4113

--- app/assets/javascripts/views_list/pointlistview.coffee
+++ app/assets/javascripts/views_list/pointlistview.coffee
@@ -161,7 +161,8 @@
       @collection.setSort('created_at', 'desc')

     @collection.pager()
-
+    @$browse_el.find('.m-pointlist-browse-toggle').text "Stop browsing"
+
   toggle_browse_ev : (ev) ->
     @toggle_browse(!@browsing)
     ev.stopPropagation()


sort by reverse chrono for archive

sort by reverse chrono for archive

--- docpad.coffee
+++ docpad.coffee
@@ -76,7 +76,8 @@
 			@site.keywords.concat(@document.keywords or []).join(', ')

 		getMeetups: ->
-			JSON.parse(@include('../data/meetups.json'))
+			meetups = JSON.parse(@include('../data/meetups.json')).sort((a, b)-> b.num - a.num)
+			#sort reverse chronologically

 		gravaturl: (email) ->
 			#MD5.digest(email)


Make sure that two drop-downs can't be open at once.

--- app/assets/javascripts/postings.js.coffee
+++ app/assets/javascripts/postings.js.coffee
@@ -105,16 +105,19 @@

     # Show drop-down filters
     $(".dropdown button").click (event) ->
-      console.log $(this).parent()
       $(this).parent().find("ul").slideToggle(400)
       $(this).expanderSwap()
+      $sibling = $(this).parent().siblings(".dropdown").find("ul")
+      if $sibling.is(":visible")
+        $sibling.slideUp(400)
+        $sibling.parent().find("button").expanderSwap()

     # Close drop-down when clicking outside the menu
     $(document).on "click", (event) ->
-      if !$(event.target).closest(".filter-buttons").length
-        if $(".filter-buttons ul").is(":visible")
-          $(".filter-buttons ul").slideUp(400)
-          $(".filter-buttons button").expanderSwap()
+      if !$(event.target).closest(".dropdown").length
+        if $(".dropdown ul").is(":visible")
+          $(".dropdown ul").slideUp(400)
+          $(this).parent().find("button").expanderSwap()

     # Show and hide postings according to user's filter
     $(".filter-buttons a").click (event) ->


fix 'more options' url if clicked from sidebar, fixes #8335

test plan:

* go to calendar 2
* click the 'add event' in the cog menu of a course
  in the right sidebar
* click more options
* make sure that it takes you to
  /courses/x/calendar_events/new where x is the
  id of the course you clicked 'add event' for

Change-Id: Ieb9216b81c844d1b2bba3d5af666385e35f48777
Reviewed-on: https://gerrit.instructure.com/10462
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Cameron Matheson <1d572acbfa68c7c6e541c7b840d6b622e5c0dc91@instructure.com>

--- app/coffeescripts/calendar/sidebar.coffee
+++ app/coffeescripts/calendar/sidebar.coffee
@@ -91,5 +91,5 @@
         new EditEventDetailsDialog(event).show()
         # TODO, codesmell: we should get rid of these next 2 lines and let EditEventDetailsDialog
         # take care of that behaviour
-        $('select[class="context_id"]').val context
+        $('select[class="context_id"]').val(context).triggerHandler('change')
         $('a[href="#edit_assignment_form"]').click() if action == 'add_assignment'


fixing some comments

fixing some comments

--- drawer.coffee
+++ drawer.coffee
@@ -18,6 +18,7 @@
 		@paperWidth = 600
 		@paperHeight = 400

+		# customizable settings
 		@textFontName = "Shadows Into Light Two"
 		@textFontSize = "15px"

@@ -71,7 +72,7 @@
 		textWidth = Math.max(t.getBBox().width, @rectangleWidth)
 		textHeight = Math.max(t.getBBox().height, @rectangleHeight)

-		# if it doesn't fit in amax width box, split it into words and wrap them around
+		# if it doesn't fit in a max width box, split it into words and wrap them around
 		if (textWidth > @rectangleMaxWidth)
 			t.attr("text", "")
 			words = content.split(" ")
@@ -90,7 +91,7 @@
 			textWidth = Math.max(t.getBBox().width, @rectangleWidth)
 			textHeight = Math.max(t.getBBox().height, @rectangleHeight)

-		# we know we're going to put this on a rectangle of that size, so let's center the text in it
+		# we know we're going to put this on a rectangle of that size (+padding), so let's center the text in it
 		t.attr(
 			{"x": topX + (textWidth+@rectangleTextPadding)/2,
 			"y": topY + textHeight/2
@@ -107,9 +108,9 @@
 		drawn = @drawRectangle topPoint, block, 0

 		# arrow
-		connector = previousRectangle.getConnectorForDirection direction
-		myConnector = drawn.rectangle.getConnectorForDirection "up"
-		@drawLine connector, myConnector, arrow
+		parentConnectr = previousRectangle.getConnectorForDirection direction
+		childConnector = drawn.rectangle.getConnectorForDirection "up"
+		@drawLine parentConnector, childConnector, arrow

 		return drawn


environments: don't put overlay for modals

--- client/Environments/views/environmentsmainscene.coffee
+++ client/Environments/views/environmentsmainscene.coffee
@@ -75,7 +75,6 @@
         title          : "Add Domain"
         view           : domainCreateForm
         width          : 700
-        overlay        : yes
         buttons        :
           createButton :
             title      : "Create"
@@ -111,7 +110,6 @@
         title        : 'Add Virtual Machine'
         cssClass     : 'add-vm-modal'
         view         : @getVmSelectionView()
-        overlay      : yes
         width        : 786
         buttons      :
           create     :


client: add follow button next to active members, topics

--- client/Social/Activity/views/activitytickeritem.coffee
+++ client/Social/Activity/views/activitytickeritem.coffee
@@ -111,9 +111,19 @@

     @actor    = new ProfileLinkView null, data

+    unless KD.whoami().getId() == data.getId()
+      @followButton = new FollowButton
+        stateOptions   :
+          unfollow     :
+            cssClass   : 'following-account'
+        dataType       : 'JAccount'
+      , data
+
   viewAppended:->
     @addSubView @avatar
     @addSubView @actor
+
+    @addSubView @followButton  if @followButton

 class ActiveTopicItemView extends KDListItemView
   constructor: (options = {}, data) ->
@@ -121,5 +131,13 @@
     super options, data

     @tag = new TagLinkView null, data
+    @followButton = new FollowButton
+      stateOptions   :
+        unfollow     :
+          cssClass   : 'following-topic'
+      dataType       : 'JTag'
+    , data

-  viewAppended:-> @addSubView @tag
+  viewAppended:->
+    @addSubView @tag
+    @addSubView @followButton


StacksCustomViews: DEFAULT_TEMPLATE for initial template

--- client/admin/lib/views/stacks/stackscustomviews.coffee
+++ client/admin/lib/views/stacks/stackscustomviews.coffee
@@ -12,6 +12,27 @@

 module.exports = class StacksCustomViews extends CustomViews
+
+  # This will be used if stack template is not defined yet
+  DEFAULT_TEMPLATE = """
+  {
+    "provider": {
+      "aws": {
+        "access_key": "${var.access_key}",
+        "secret_key": "${var.secret_key}",
+        "region": "eu-central-1"
+      }
+    },
+    "resource": {
+      "aws_instance": {
+        "example": {
+          "instance_type": "t2.micro",
+          "ami": "ami-936d9d93"
+        }
+      }
+    }
+  }
+  """

   setStack = (options, callback) ->


Workspace: Using nickname in chat instead of firstName + lastName.

--- client/app/CommonViews/workspace/panes/chatitem.coffee
+++ client/app/CommonViews/workspace/panes/chatitem.coffee
@@ -21,7 +21,7 @@

     @messageList.addSubView @header = new KDCustomHTMLView
       cssClass   : "username"
-      partial    : if ownMessage then "Me" else "#{user.firstName} #{user.lastName}"
+      partial    : if ownMessage then "Me" else "#{user.nickname}"

     @header.addSubView @timeAgo = new KDTimeAgoView
       cssClass   : "time-ago"


client/redux: update creditcard module selectors

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

--- client/app/lib/redux/modules/payment/creditcard.coffee
+++ client/app/lib/redux/modules/payment/creditcard.coffee
@@ -30,6 +30,29 @@
       return state

+valueSelector = (state) -> (key, fn = _.identity) -> fn state.creditCard[key]
+
+values = (state) ->
+
+  return null  unless state.creditCard
+
+  selector = valueSelector(state)
+
+  brand = selector 'brand', (brand) -> brand.toLowerCase()
+  number = selector 'last4', (last4) ->
+    if brand is 'amex'
+    then "•••• •••••• •#{last4}"
+    else "•••• •••• •••• #{last4}"
+
+  return immutable {
+    brand: brand
+    number: number
+    name: selector 'name'
+    exp_month: selector 'exp_month'
+    exp_year: selector 'exp_year'
+  }
+
+
 remove = ->
   return {
     types: [ REMOVE.BEGIN, REMOVE.SUCCESS, REMOVE.FAIL ]
@@ -40,6 +63,9 @@
 module.exports = _.assign reducer, {
   namespace: withNamespace()
   reducer
+
+  values
+
   remove
   REMOVE
 }


Mark preloaded entries as read when marking all as read. Fixes feedbin/support#402.

--- app/assets/javascripts/_site.js.coffee
+++ app/assets/javascripts/_site.js.coffee
@@ -240,6 +240,11 @@

       $(document).on 'click', '[data-behavior~=mark_all_as_read]', ->
         unless $(@).attr('disabled')
+          $('.entries li').map ->
+            entry_id = $(@).data('entry-id') * 1
+            if entry_id of feedbin.entries
+              feedbin.entries[entry_id].read = true
+
           if feedbin.data.markAsReadConfirmation
             result = confirm(feedbin.markReadData.message)
             if result


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- test/animation.coffee
+++ test/animation.coffee
@@ -11,7 +11,7 @@
   milliseconds = 300

   setTimeout ->
-    ok(animation.active, "")
+    ok(animation.active, "Animation has active property")

     start()
   , milliseconds


flux/teams: add Member to store

flux/teams: add Member to store

--- client/app/lib/flux/teams/stores/teammembersidstore.coffee
+++ client/app/lib/flux/teams/stores/teammembersidstore.coffee
@@ -15,6 +15,7 @@

     @on actions.FETCH_TEAM_MEMBERS_SUCCESS, @load
     @on actions.DELETE_TEAM_MEMBER, @deleteTeamMember
+    @on actions.ADD_MEMBER_TO_TEAM, @addMember

   load: (memberIds, { users } ) ->
@@ -25,3 +26,6 @@

   deleteTeamMember: (memberIds, memberId) ->
     memberIds.delete memberId
+
+  addMember: (memberIds, { id }) ->
+    memberIds.set id, id


Use a fetchQueue to avoid multiple kite calls for same reason

--- client/landing/app/MainApp/kodingappscontroller.coffee
+++ client/landing/app/MainApp/kodingappscontroller.coffee
@@ -28,6 +28,7 @@
     mainController  = KD.getSingleton "mainController"
     @manifests      = KodingAppsController.manifests
     @publishedApps  = {}
+    @_fetchQueue    = []

     @getPublishedApps()
     @createExtensionToAppMap()
@@ -67,14 +68,18 @@
         else
           callback? err, apps

-  fetchAppsFromFs:(callback)->
+  fetchAppsFromFs:(cb)->
+
+    @_fetchQueue.push cb  if cb
+    return if @_fetchQueue.length > 1

     path   = "/home/#{KD.whoami().profile.nickname}/Applications"
     appDir = FSHelper.createFileFromPath path, 'folder'
     appDir.fetchContents KD.utils.getTimedOutCallback (err, files)=>
       if err or not Array.isArray files or files.length is 0
         @putAppsToAppStorage {}
-        callback()
+        callback() for callback in @_fetchQueue
+        @_fetchQueue = []
       else
         apps  = []
         stack = []
@@ -101,12 +106,13 @@
               catch e
                 console.warn "Manifest file is broken", e
           @putAppsToAppStorage manifests
-          callback? null, manifests
+          callback null, manifests  for callback in @_fetchQueue
+          @_fetchQueue = []
     , ->
-      msg = "Timeout reached for kite request"
+      warn msg = "Timeout reached for kite request"
       KD.logToExternal msg
-      log msg
-      callback()
+      callback() for callback in @_fetchQueue
+      @_fetchQueue = []

   fetchAppsFromDb:(callback)->
     return unless @appStorage


Removed resizeTabHandles method in MainTabView. Now MainTabView uses parent's method.

--- client/landing/app/MainApp/maintabs/maintabview.coffee
+++ client/landing/app/MainApp/maintabs/maintabview.coffee
@@ -151,33 +151,3 @@
     for handle in @handles
       unless handle.getOptions().hidden
         @visibleHandles.push handle
-
-  resizeTabHandles:(event)->
-
-    return if event.type is "PaneAdded" and event.pane.hiddenHandle
-    return if @handlesHidden
-
-    containerSize   = @tabHandleContainer.getWidth()
-    {plusHandle}    = @tabHandleContainer
-
-    if event.type in ['PaneAdded','PaneRemoved']
-      @totalSize    = 0
-      @rearrangeVisibleHandlesArray()
-      for handle in @visibleHandles
-        @totalSize += handle.$().outerWidth(no)
-
-    plusHandleWidth = plusHandle.$().outerWidth(no)
-    containerSize -= plusHandleWidth
-
-    handleSize = if containerSize < @totalSize
-      containerSize / @visibleHandles.length
-    else
-      if containerSize / @visibleHandles.length > 130
-        130
-      else
-        containerSize / @visibleHandles.length
-
-    for handle in @visibleHandles
-      handle.$().css width : handleSize
-      subtractor = if handle.$('span').length is 1 then 25 else 25 + (handle.$('span:not(".close-tab")').length * 25)
-      handle.$('> b').css width : (handleSize - subtractor)


teams: creation: route to /Teams if there is no such step

--- client/landing/site.landing/coffee/team/AppView.coffee
+++ client/landing/site.landing/coffee/team/AppView.coffee
@@ -21,6 +21,7 @@

   showTab: (step, query) ->

+    return KD.singletons.router.handleRoute '/Teams'  unless TABS[step]

     if tab = @tabView.getPaneByName step
     then @tabView.showTab tab


Fix comment highlighting in syntax command

Was coloring
syntax, [test] // comment
incorrectly


Don't log

Don't log

--- app/controllers/interactive/graphs.coffee
+++ app/controllers/interactive/graphs.coffee
@@ -39,8 +39,6 @@

     @options = new Object
     @headingText.html '
Construct Your Question
'
-
-    console.log @graphType

     if @graphType is 'histogram'
       @setPressed $('[data-variables="histogram"]')


added click handler to button

added click handler to button

--- app/assets/javascripts/index.js.coffee
+++ app/assets/javascripts/index.js.coffee
@@ -9,3 +9,7 @@
     $nav_list.find('li').not('.nav-header').remove()
     $nav_list.append(element) for element in ($(element) for element in $(this).find('.sidelinks li'))
     $nav_list.find('li.nav-header').text($(this).find('h4').text())
+
+$ ->
+  $('#language-submit').click ->
+    $(this).closest('form').trigger 'submit'


#DEV43: Adjust in "description" text tools (remove unnecessary)

--- app/assets/javascripts/items.js.coffee
+++ app/assets/javascripts/items.js.coffee
@@ -127,11 +127,26 @@

     descriptionTextTools: ->
       $("#js-item-description").jqte
+        center: false
+        color: false
+        fsize: false
+        funit: false
+        format: false
+        indent: false
+        left: false
+        right: false
+        outdent: false
+        rule: false
+        source: false
+        sub: false
+        sup: false
         focus: ->
-          $(".jqte_editor").height(450)
+          $(".jqte_editor").animate
+            'height': 360
           return
         blur: ->
-          $(".jqte_editor").height(100)
+          $(".jqte_editor").animate
+            'height': 100
           return
       return


Enable and disable address fields in checkout form according to radio button option.

--- app/assets/javascripts/order.js.coffee
+++ app/assets/javascripts/order.js.coffee
@@ -56,3 +56,13 @@
   ).live('ajax:complete', (xhr, data, status) ->
     $.fancybox.hideActivity()
   )
+
+  address_ids = ['#order_address_street_1', '#order_address_street_2', '#order_address_city', '#order_address_state', '#order_address_zip', '#order_address_phone']
+
+  $('#same_info_Yes').live 'click', (event) ->
+    for address_id in address_ids
+      $(address_id).attr 'disabled', 'disabled'
+
+  $('#same_info_No').live 'click', (event) ->
+    for address_id in address_ids
+      $(address_id).removeAttr 'disabled'


test for addition node

test for addition node

--- test/evaluator.coffee
+++ test/evaluator.coffee
@@ -70,3 +70,21 @@
         }
         assert.equal f.params.length, 1
         assert.equal f.params[0].value, 5
+
+      it 'builds additions', ->
+        f = e.build {
+          expression: 'add'
+          left:
+            {
+              expression: 'integer'
+              value: 5
+            }
+          right:
+            {
+              expression: 'integer'
+              value: 3
+            }
+        }
+        assert.equal f.left.value, 5
+        assert.equal f.right.value, 3
+        assert.equal f.evaluate({}), 8


added automatic checking of twitter/github

--- test/files/5_dir.iced
+++ test/files/5_dir.iced
@@ -49,17 +49,16 @@
       T.assert err?, "expected an error in home dir signature"
     cb()

-  proof_ids: (T, who, whom, cb) ->
-    await who.keybase {args: ['id', whom]}, defer err, out
-    T.no_error err, "failed to id"
-    T.assert out, "failed to id"
-    github  = /// \"([^\s\n]+)\"\son\sgithub ///
-    twitter = /// \"([^\s\n]+)\"\son\stwitter ///
-    res = { }
-    if (gh = github.exec s)?
-      res.github = gh[1]
-    if (tw = twitter.exec s)?
-      res.twitter = tw[1]
+  proof_ids: (T, who, cb) ->
+
+    args = ["status"]
+    await who.keybase {args}, defer err, out
+    T.no_error err, "failed to status"
+    T.assert out,   "failed to status"
+
+    res = null
+    if (not err) and out?.toString()
+      res = JSON.parse(out.toString()).user.proofs
     cb res

   verify_home_dir: (T, who, expect_success, cb) -> act.__verify_home_dir T, who, expect_success, false, cb
@@ -119,8 +118,9 @@

 exports.assertions = (T, cb) ->
   await act.sign_home_dir          T, charlie,        defer()
-  await act.verify_with_assertions T, alice, charlie, ["twitter:tacovontaco", "github:tacoplusplus"],   true, defer()
-  await act.verify_with_assertions T, alice, charlie, ["twitter:tacovontaco", "github:evil_wrongdoer"], false, defer()
+  await act.proof_ids              T, charlie,        defer proof_ids
+  await act.verify_with_assertions T, alice, charlie, ["twitter:#{proof_ids.twitter}", "github:#{proof_ids.github}"],   true, defer()
+  await act.verify_with_assertions T, alice, charlie, ["twitter:evil_wrongdoer", "github:wrong_evildoer"],             false, defer()
   cb()

 exports.alice_wrong_item_types = (T, cb) ->


必要なファイルにfeed parserが入っていたのを削除

必要なファイルにfeed parserが入っていたのを削除

--- gitlab.coffee
+++ gitlab.coffee
@@ -3,7 +3,6 @@
 #
 # Dependencies:
 #   "request":     "2.34.0"
-#   "feedparser":  "0.16.6"
 #   "url" :        ""
 #   "querystring": ""
 #


bugfix — each developer has his own auth exchange now, and his client.auth messages will be routed correctly

--- client/landing/app/MainApp/mq.config.coffee
+++ client/landing/app/MainApp/mq.config.coffee
@@ -50,4 +50,8 @@

   mq: do->
     {broker} = KD.config
-    broker = new KDBroker.Broker broker.sockJS, autoReconnect: yes+    options =
+      autoReconnect   : yes
+      authChannelName : KD.config.authResourceName
+    console.log {options}
+    broker = new KDBroker.Broker broker.sockJS, options


Tests: Teams: Added Check that you cannot delete the stack template that's in use test.

--- client/test/lib/helpers/teamshelpers.coffee
+++ client/test/lib/helpers/teamshelpers.coffee
@@ -625,14 +625,16 @@
       .waitForElementNotPresent  finalizeStepsButton, 20000
       .waitForElementVisible     envMachineStateModal, 20000

-    @checkStackTemplateTags(browser)
-
-
-  checkStackTemplateTags: (browser) ->
-
-    inUseTag   = "#{stackCatalogModal} [testpath=StackInUseTag]"
-    defaultTag = "#{stackCatalogModal} [testpath=StackDefaultTag]"
-    accessTag  = "#{stackCatalogModal} [testpath=StackAccessLevelTag]"
+    @checkStackTemplateTags(browser, yes)
+
+
+  checkStackTemplateTags: (browser, deleteStack) ->
+
+    inUseTag              = "#{stackCatalogModal} [testpath=StackInUseTag]"
+    defaultTag            = "#{stackCatalogModal} [testpath=StackDefaultTag]"
+    accessTag             = "#{stackCatalogModal} [testpath=StackAccessLevelTag]"
+    stackSettingsMenuIcon = '.stacktemplates .stack-template-list .stack-settings-menu .chevron'
+    deleteMenuItem        = ".kdbuttonmenu .context-list-wrapper .delete"

     @openStackCatalog(browser, no)

@@ -642,6 +644,18 @@
       .waitForElementVisible  defaultTag, 20000
       .waitForElementVisible  accessTag, 20000
       .assert.containsText    accessTag, 'GROUP'
+
+    if deleteStack
+      browser
+        .waitForElementVisible    stackSettingsMenuIcon, 20000
+        .click                    stackSettingsMenuIcon
+        .pause                    2000
+        .waitForElementVisible    deleteMenuItem, 20000
+        .click                    deleteMenuItem
+        .assert.containsText      '.kdnotification.main', 'This template currently in use by the Team'
+        .waitForElementNotVisible '.kdnotification.main', 30000
+
+    browser
       .waitForElementVisible  stackModalCloseButton, 20000
       .click                  stackModalCloseButton


fix(reporter) fix to string format for log

Added unit tests to confirm fix

--- test/unit/reporters/base.spec.coffee
+++ test/unit/reporters/base.spec.coffee
@@ -31,4 +31,19 @@

       expect(adapter).to.have.been.calledWith 'Success: 10 Failure: 20'

+    it 'should format log messages correctly for single browser', ->
+      writeSpy = sinon.spy reporter, 'writeCommonMsg'

+      reporter._browsers = ['Chrome']
+      reporter.onBrowserLog 'Chrome', 'Message', 'LOG'
+
+      expect(writeSpy).to.have.been.calledWith 'LOG: Message\n'
+
+    it 'should format log messages correctly for multi browsers', ->
+      writeSpy = sinon.spy reporter, 'writeCommonMsg'
+
+      reporter._browsers = ['Chrome', 'Firefox']
+      reporter.onBrowserLog 'Chrome', 'Message', 'LOG'
+
+      expect(writeSpy).to.have.been.calledWith 'Chrome LOG: Message\n'
+


Clean up success logic

Clean up success logic

--- vendor/assets/javascripts/brainstem/data-loader.coffee
+++ vendor/assets/javascripts/brainstem/data-loader.coffee
@@ -37,7 +37,7 @@

     return false

-  load: (loadOptions) ->
+  loadCollection: (loadOptions) ->
     @_parseLoadOptions(loadOptions)

     # Check the cache
@@ -79,9 +79,11 @@
       @storageManager.getCollectionDetails(@loadOptions.name).cache[@loadOptions.cacheKey] = results

     if @loadOptions.only?
-      @_success @loadOptions, @collection, _.map(@loadOptions.only, (id) => @cachedCollection.get(id))
-    else
-      @_success @loadOptions, @collection, _(results).map (result) -> base.data.storage(result.key).get(result.id)
+      data = _.map(@loadOptions.only, (id) => @cachedCollection.get(id))
+    else
+      data = _(results).map (result) -> base.data.storage(result.key).get(result.id)
+
+    @_success @loadOptions, @collection, data

   _buildSyncOptions: ->
     syncOptions =
@@ -105,6 +107,8 @@

     syncOptions.data.search = @loadOptions.search if @loadOptions.search
     syncOptions
+
+####################################

 class Brainstem.DataLoader
   constructor: (options = {}) ->
@@ -174,7 +178,7 @@

   _loadCollectionWithFirstLayer: (options) =>
     cl = new Brainstem.CollectionLoader(storageManager: @storageManager, successFunction: @_success)
-    cl.load(options)
+    cl.loadCollection(options)

   _handleNextLayer: (options) =>
     # Collection is a fully populated collection of tasks whose first layer of associations are loaded.


Hide test HTML on teardown, fix tests

Hide test HTML on teardown, fix tests

--- test/spec.coffee
+++ test/spec.coffee
@@ -2,16 +2,20 @@

 $ = Rye

+setup ->
+    document.getElementById('test').style.display = 'block'
+
+teardown ->
+    document.getElementById('test').style.display = 'none'
+
 suite 'Basic functionality', ->

     test 'Rye()', ->
-        assert.instanceof Rye('div'), Rye, 'returns instance of Rye'
+        assert.instanceOf Rye('div'), Rye, 'returns instance of Rye'

 suite 'Querying', ->

     test 'ID query', ->

         el = $('#hello')
-        assert.lengthOf el, 1, 'result has length 1'
-
-        +        assert.lengthOf el.elements, 1, 'result has length 1'


Test for array methods

Test for array methods

--- test/spec.coffee
+++ test/spec.coffee
@@ -38,15 +38,66 @@

 suite 'Collection methods', ->

-    lis = '.list li'
+    list_items = -> $('.list li')

     test 'get', ->
-        el = $(lis)
-        assert.lengthOf el, 3
-        assert el.get(1).className is 'b'
+        list = list_items()
+        assert.lengthOf list, 3
+        assert list.get(1).className is 'b'

     test 'forEach', ->
-        el = $(lis)
-        i = 0
-        el.forEach -> i++
-        assert.equal i, 3
+        list = list_items()
+        count = 0
+        list.forEach (el, i) ->
+            assert.strictEqual el, list.get(i)
+            count++
+        assert.equal count, 3
+
+    test 'map', ->
+        list = list_items()
+        res = list.map (el) -> el.className
+        assert.deepEqual res, ['a', 'b', 'c'], "list of classnames should match"
+
+    test 'reduce', ->
+        list = list_items()
+        res = list.reduce (p, c, i) ->
+            p + c.className
+        , 'ø'
+        assert.strictEqual res, 'øabc', "concat classnames"
+
+    test 'reduceRight', ->
+        list = list_items()
+        res = list.reduceRight (p, c, i) ->
+            p + c.className
+        , 'ø'
+        assert.strictEqual res, 'øcba', "reverse concat"
+
+    test 'push', ->
+        list = list_items()
+        list.push(document.createElement('div'))
+        assert list.length is 4, "list has 4 elements"
+        assert list.get(3).tagName is 'DIV', "list[3] is a div"
+
+    test 'push accepts only elements', ->
+        list = list_items()
+        list.push 'bacon'
+        assert list.length is 3, "list still has 3 elements"
+        assert list.get(3) is undefined, "element at 3 doesn't exist"
+
+    test 'sort', ->
+        list = list_items()
+        # reverse alphabetical order
+        list.sort (a, b) -> a.className < b.className
+        assert list.get(0).className is 'c', ".c is first in the list"
+
+    test 'indexOf', ->
+        list = list_items()
+        for el, i in list.get()
+            assert list.indexOf(el) is i, "indexes must match"
+
+    test 'concat', ->
+        list = list_items()
+        other = [document.createElement('div')]
+        list2 = list.concat other
+        assert list2.length is 4, "list length should increase by 1"
+        assert list2.get(3).tagName is 'DIV'


Move collection initialization to hook

Move collection initialization to hook

--- test/test.coffee
+++ test/test.coffee
@@ -7,24 +7,25 @@
 describe 'Backbone Typeahead', ->
   describe 'Readme Tests', ->
     class Albums extends Backbone.TypeaheadCollection
-      typeaheadAttributes: ['band', 'name']
+        typeaheadAttributes: ['band', 'name']

-    albums = new Albums([
-      { band: 'A Flock of Seagulls', name: 'A Flock of Seagulls' }
-      { band: 'Rick Astley', name: 'Whenever You Need Somebody' }
-      { band: 'Queen', name: 'A Day at the Races' }
-      { band: 'Queen', name: 'Tie Your Mother Down' }
-    ])
+    beforeEach ->
+      @albums = new Albums([
+        { band: 'A Flock of Seagulls', name: 'A Flock of Seagulls' }
+        { band: 'Rick Astley', name: 'Whenever You Need Somebody' }
+        { band: 'Queen', name: 'A Day at the Races' }
+        { band: 'Queen', name: 'Tie Your Mother Down' }
+      ])

     it 'should handle simple search', ->
       expected = ['Whenever You Need Somebody', 'Tie Your Mother Down']
-      actual = _.map albums.typeahead('you'), (a) -> a.get('name')
+      actual = _.map @albums.typeahead('you'), (a) -> a.get('name')

       actual.should.eql expected

     it 'should handle simple facet', ->
       expected = ['A Day at the Races']
-      actual = _.map albums.typeahead('ra', band: 'Queen'), (a) -> a.get('name')
+      actual = _.map @albums.typeahead('ra', band: 'Queen'), (a) -> a.get('name')

       actual.should.eql expected


NewStatusUpdate: add checks for exempt status updates and comments

--- workers/social/lib/social/models/messages/newstatusupdate/index.coffee
+++ workers/social/lib/social/models/messages/newstatusupdate/index.coffee
@@ -163,6 +163,22 @@
       JComment = require '../comment'
       JPost::reply.call this, client, JComment, comment, callback

+  @getExemptUserIdsIfNeeded: (client, options, callback=->)->
+    unless options.withExempt
+      {delegate} = client.connection
+      return callback null, []  unless delegate
+
+      JAccount = require '../../account'
+      JAccount.getExemptUserIds (err, ids)->
+        return callback err, null if err
+        index = ids.indexOf(delegate.getId().toString())
+        if index > -1
+          ids.splice(index, 1)
+
+        callback null, ids
+    else
+      callback null, []
+
   @getCurrentGroup: (client, callback)->
     groupName = client.context.group or "koding"
     JGroup = require '../../group'
@@ -182,21 +198,44 @@
         else callback null, group

+  @checkForTrollMode = (delegate, options) ->
+    # if delegate is set and  user is exempt
+    # display exempt posts/comments
+    if delegate and delegate.isExempt
+      return yes
+    # if options.withExempt is not set or
+    # it is set to false set it to false again
+    else if not options.withExempt
+      return no
+
+    return options.withExempt
+
+
+
   @fetchGroupActivity$ = secure (client, options = {}, callback)->
     @fetchGroupActivity client, options, callback

   @fetchGroupActivity = (client, options = {}, callback)->
+    {connection:{delegate}} = client
+    showExemptComments = @checkForTrollMode delegate, options
     @getCurrentGroup client, (err, group)=>
       if err then return callback err
       {to} = options
       to = if to then new Date(to)  else new Date()
-      selector = {'meta.createdAt' : "$lt" : to }
-
-      options.sort = 'meta.createdAt' : -1
-      options.limit or= 20
-      @some selector, options, (err, data)=>
-        return callback err if err
-        @decorateResults data, callback
+
+      @getExemptUserIdsIfNeeded client, options, (err, ids)=>
+        return callback err  if err
+
+        selector = 'meta.createdAt': "$lt" : to
+        # remove exempts from result set
+        selector.originId = $nin : ids if ids.length > 0
+
+        options.sort = 'meta.createdAt' : -1
+        options.limit or= 20
+
+        @some selector, options, (err, data)=>
+          return callback err if err
+          @decorateResults data, showExemptComments, callback

   @fetchProfileFeed = secure (client, options = {}, callback)->
     {connection:{delegate}, context:{group}} = client
@@ -216,11 +255,10 @@

     @some selector, feedOptions, (err, data)=>
       return callback err if err
-      @decorateResults data, callback
+      @decorateResults data, yes, callback

   @fetchTopicFeed = secure (client, options = {}, callback)->
-
-    {context:{group}} = client
+    {connection:{delegate}, context:{group}} = client

     JTag = require '../../tag'
     JTag.one { slug : options.slug, group }, (err, tag)=>
@@ -234,15 +272,27 @@
         sort : {'timestamp': -1}
         limit: options.limit or 20

-      tag.fetchContents {
-        targetName: 'JNewStatusUpdate'
-        "timestamp": "$lt": to
-      }, fetchOptions, (err, posts)=>
-        return callback err if err
-        @decorateResults posts, callback
+      @getExemptUserIdsIfNeeded client, options, (err, ids)=>
+        return callback err  if err
+
+        query =
+          targetName: 'JNewStatusUpdate'
+          "timestamp": "$lt": to
+
+        showExempt = @checkForTrollMode delegate, options
+        # add isExempt query if necessary
+        query['data.flags.isLowQuality'] = $ne: yes unless showExempt
+
+        tag.fetchContents query, fetchOptions, (err, posts)=>
+          return callback err if err
+          @decorateResults posts, showExempt, callback

   @fetchFollowingFeed = secure (client, options = {}, callback)->
     {Activity} = require "../../graph"
+
+    {connection:{delegate}} = client
+    showExemptComments = @checkForTrollMode delegate, options
+
     options.client = client
     Activity.fetchFolloweeContentsForNewKoding options, (err, ids)=>
       return callback err  if err
@@ -251,19 +301,9 @@
         _id : "$in" : activityIds
       @some selector, {}, (err, activities)=>
         return callback err  if err
-        @decorateResults activities, callback
-
-  @fetchActivitiesWithRels = ({selector, options, relSelector, relOptions}, callback)->
-    Relationship.some relSelector, relOptions, (err, rels)=>
-      return callback err  if err
-      return callback null, [] if not rels or rels.length < 1
-      activityIds = rels.map (rel)-> rel.targetId
-      selector._id = "$in" : activityIds
-      @some selector, options, (err, activities)=>
-        return callback err  if err
-        @decorateResults activities, callback
-
-  @decorateResults = (posts, callback) ->
+        @decorateResults activities, showExemptComments, callback
+
+  @decorateResults = (posts, showExempt, callback) ->
     return callback null, [] if not posts or posts.length < 1
     teasers = []
     collectTeasers = race (i, root, fin)->
@@ -274,5 +314,6 @@
         else
           teasers[i] = teaser
           fin()
+      , showExempt
     , -> callback null, teasers
     collectTeasers post for post in posts


Add hero setup for escort duty

Add hero setup for escort duty

--- app/views/play/level/PlayLevelView.coffee
+++ app/views/play/level/PlayLevelView.coffee
@@ -161,7 +161,7 @@
       not e.level.isType('course-ladder')

       # TODO: Add a general way for standalone levels to be accessed by students, teachers
-      e.level.get('slug') isnt 'peasants-and-munchkins'
+      e.level.get('slug') isnt 'peasants-and-munchkins'
     ])
       return _.defer -> application.router.redirectHome()

@@ -416,6 +416,27 @@
         "left-hand": "54eb528449fa2d5c905ddf12",
         "right-hand": "544d86318494308424f564e8"
       }}
+    else if e.level.get('slug') in ['escort-duty']
+      potionmaster = '52fd1524c7e6cf99160e7bc9'
+      e.session.set 'heroConfig', {"thangType":potionmaster,"inventory":{
+        "eyes": "546941fda2b1f53ce794441d",
+        "feet": "546d4d8e9df4a17d0d449acd",
+        "programming-book": "557871261ff17fef5abee3ee",
+        "head": "546d4ca19df4a17d0d449abf",
+        "torso": "546d4a549df4a17d0d449a97",
+        "left-ring": "5441c35c4e9aeb727cc9711d",
+        "minion": "54eb5d1649fa2d5c905ddf52",
+        "neck": "54693363a2b1f53ce79443d1",
+        "wrists": "54693830a2b1f53ce79443f1",
+        "left-hand": "546376ea3839c6e02811d320",
+        "right-hand": "54eab92b2b7506e891ca720a",
+        "waist": "54694af7a2b1f53ce7944441",
+        "right-ring": "54692d2aa2b1f53ce794438f",
+        "pet": "5744e3683af6bf590cd27371"
+      }}
+
+
+
     else if e.level.get('slug') is 'the-battle-of-sky-span'
       wizard = '52fc1460b2b91c0d5a7b6af3'
       e.session.set 'heroConfig', {"thangType":wizard,"inventory":{}}
@@ -736,13 +757,13 @@
     return if @headless
     scripts = @world.scripts  # Since these worlds don't have scripts, preserve them.
     @world = e.world
-
+
     # without this check, when removing goals, goals aren't updated properly. Make sure we update
     # the goals once the first frame is finished.
     if @world.age > 0 and @willUpdateStudentGoals
       @willUpdateStudentGoals = false
       @updateStudentGoals()
-
+
     @world.scripts = scripts
     thangTypes = @supermodel.getModels(ThangType)
     startFrame = @lastWorldFramesLoaded ? 0
@@ -768,7 +789,7 @@
     @updateStudentGoals()
     @onWindowResize()
     @realTimePlaybackWaitingForFrames = true
-
+
   updateStudentGoals: ->
     return unless @level.isType('game-dev')
     @studentGoals = @world.thangMap['Hero Placeholder'].stringGoals


Add Italian and Chinese translations

Add Italian and Chinese translations

--- project.coffee
+++ project.coffee
@@ -15,6 +15,8 @@
     # ru: label: "русский", strings: './translations/ru.json'
     cs: label: 'Čeština', strings: './translations/cs.json'
     el: label: 'Ελληνικά', strings: './translations/el.json'
+    it: label: 'Italiano', strings: './translations/it.json'
+    zh_tw: label: '繁體中文', strings: './translations/zh-tw.json'
   }
 })


groups: navbar makes the page scroll now

--- components/list/KDListViewController.coffee
+++ components/list/KDListViewController.coffee
@@ -78,10 +78,7 @@
         @showLazyLoader no
       scrollView.on 'LazyLoadThresholdReached', @showLazyLoader.bind @

-
-    # {items} = @getData()
-    log @getData(), "zikkimin kökü"
-    # @instantiateListItems(items or [])
+    @instantiateListItems(@getData()?.items or [])

     @getSingleton("windowController").on "ReceivedMouseUpElsewhere", (event)=> @mouseUpHappened event


cover attachChild with a couple more specs

--- test/view_spec.coffee
+++ test/view_spec.coffee
@@ -205,15 +205,28 @@
       view.attachTo('

')
       view.insertChild({})

+    it "can map where to attach a child", ->
+      view.attachChild 'ChildView', 'kiddo'
+      childHTML= """
Fried Egg
"""
+      view.attachTo("""

#{childHTML}
""")
+      view.insertChild(childView)
+      expect( childView.toHTML() ).to.eql('
Fried Egg
')
+
     it "can find where to attach based on model data", ->
       view.attachChild 'ChildView', ({model, modelName}) -> [modelName, model.id].join(':')
-      html = '

Scrambled Egg

Fried Egg

'
+      html = '

Fried Egg

'
       view.attachTo(html)
       view.insertChild(childView, modelName: 'duck', model: { id: 2 })
-      expect( view.toHTML() ).to.eql(html)
       expect( childView.toHTML() ).to.eql('
Fried Egg
')

-    it "can set insert rules with class declarations", ->
+    it "can find where to attach based on id", ->
+      view.attachChild 'ChildView', ({id}) -> id
+      html = '

Fried Egg

'
+      view.attachTo(html)
+      view.insertChild(childView, id: 'doobie')
+      expect( childView.toHTML() ).to.eql('
Fried Egg
')
+
+    it "can set attach rules with class declarations", ->
       ParentView.attachChild 'ChildView', 'hello'
       view = new ParentView(attachTo: '

')
       view.insertChild(childView)


Workspace: Changed Invite box title.

Workspace: Changed Invite box title.

--- client/app/CommonViews/workspace/collaborativeworkspaceuserlist.coffee
+++ client/app/CommonViews/workspace/collaborativeworkspaceuserlist.coffee
@@ -10,7 +10,7 @@

     @header = new KDView
       cssClass : "inner-header"
-      partial  : """Users"""
+      partial  : """Participants"""

     @header.addSubView new KDCustomHTMLView
       tagName   : "span"


DevToolsEditorPane: use provided machine instance while loading a file

--- client/DevTools/views/codeeditor.coffee
+++ client/DevTools/views/codeeditor.coffee
@@ -8,7 +8,9 @@
     super options, data

     @_mode = @getOption 'editorMode'
+
     @_defaultTitle = @getOption 'defaultTitle'
+    @machine       = @getOption 'machine'

     @_lastFileKey = "lastFileOn#{@_mode}"
     @storage = KD.singletons.localStorageController.storage "DevTools"
@@ -18,7 +20,7 @@

   loadFile:(path, callback = noop)->

-    file = FSHelper.createFileInstance { path }
+    file = FSHelper.createFileInstance { @machine, path }

     kite = file.getKite()
     return  callback {message: "VM not found"}  unless kite


MachineSettingsModal: Update currentState field when state of machine changes

--- client/Main/machinesettingsmodal.coffee
+++ client/Main/machinesettingsmodal.coffee
@@ -162,11 +162,13 @@
     @unsetClass stateClasses
     @setClass status.toLowerCase()

-    { statusToggle } = @modalTabs.forms.Settings.inputs
+    { currentStatus, statusToggle } = @modalTabs.forms.Settings.inputs

     if status in [ Running, Starting ]
     then statusToggle.setOn no
     else statusToggle.setOff no
+
+    currentStatus.updatePartial status

     @machine.jMachine.setAt "status.state", status
     @machine.updateLocalData()


activity: don't remove current channel name from message

--- client/activity/lib/flux/getters.coffee
+++ client/activity/lib/flux/getters.coffee
@@ -238,12 +238,6 @@
       popularMessages = popularMessages or immutable.Map()
       thread = thread.set 'messages', popularMessages

-    thread = thread.update 'messages', (messages) ->
-      messages.map (msg) ->
-        msg.update 'body', (body) ->
-          # don't show channel name on post body.
-          body.replace(///\##{channel.get('name')}($|\s)///, '').trim()
-
     return thread
 ]


KlientKite: disconnect from kite if it's not available and not marked as Running [#107480008]

--- client/app/lib/kite/kites/klient.coffee
+++ client/app/lib/kite/kites/klient.coffee
@@ -46,6 +46,17 @@

     super

+    @on 'close', (reason) =>
+
+      if reason?.code is 1002
+
+        cc         = kd.singletons.computeController
+        machineUId = @getOption 'correlationName'
+        machine    = cc.findMachineFromMachineUId(machineUId)
+
+        if not machine or not machine.isRunning()
+          @disconnect()
+
     @terminalSessions = []


set FILE to dummy object

set FILE to dummy object

--- client/lanes/testing/TestObjects.coffee
+++ client/lanes/testing/TestObjects.coffee
@@ -1,5 +1,6 @@
 Lanes.Test.makeScreen = (props = {}, args = {}) ->
     class TestScreen
+        FILE: { path: ['test'] }
         render: -> React.createElement('div')
     _.extend(TestScreen.prototype, props)
     Screen = Lanes.React.Screen.extend(TestScreen)
@@ -8,6 +9,7 @@

 Lanes.Test.makeComponent = (props = {}, args = {}) ->
     class TestComponent
+        FILE: { path: ['test'] }
         render: -> React.createElement('div')
     _.extend(TestComponent.prototype, props)
     Component = Lanes.React.Component.extend(TestComponent)
@@ -15,6 +17,7 @@

 Lanes.Test.defineModel = (props = {}) ->
     class TestModel
+        FILE: { path: ['test'] }
         constructor: -> super
     _.extend(TestModel.prototype, props)
     Lanes.Models.Base.extend(TestModel)
@@ -29,6 +32,7 @@
     _.extend(TestCollection.prototype, props)
     unless TestCollection::model
         class TestModel
+            FILE: { path: ['test'] }
             constructor: -> super
         TestCollection::model = Lanes.Models.Base.extend(TestModel)
     Lanes.Models.Collection.extend(TestCollection)


Edge model has @state not @classes

Edge model has @state not @classes

--- app/scripts/alchemy/models/edge.coffee
+++ app/scripts/alchemy/models/edge.coffee
@@ -6,7 +6,9 @@
         # Works with undefined @edgeStyle
         conf = alchemy.conf
         @edgeStyle = _.merge(conf.edgeStyle, @edgeStyle)
-        @classes = {'active': true} #assign active class to edges by default
+
+        # Contains state of edge, used by renderers
+        @state = {'active': true}

         @_rawEdge = edge
         @_d3 = {


squash

squash

--- app/scripts/alchemy/utils/utils.coffee
+++ app/scripts/alchemy/utils/utils.coffee
@@ -96,9 +96,6 @@
         else
             20

-    neighbors: (node) ->
-        # return all nodes connected to an edge
-
     edgeNeib: (node) ->
         # return a d3 selection of all edges connected to node
         connections = alchemy.edge.filter (e) ->


Flip multiLine conditional to avoid starting with a negative conditional

--- framer/InputLayer.coffee
+++ framer/InputLayer.coffee
@@ -30,11 +30,11 @@
 			parent: @
 			name: "input"

-		if not @multiLine
-			@_inputElement = document.createElement("input")
-		else
+		if @multiLine
 			@_inputElement = document.createElement("textarea")
 			@input.y = 25
+		else
+			@_inputElement = document.createElement("input")

 		# The id serves to differentiate multiple input elements from one another.
 		# To allow styling the placeholder colors of seperate elements.


fix always showing the alternate

fix always showing the alternate

--- js/app.coffee
+++ js/app.coffee
@@ -59,7 +59,7 @@
           path[1]

     # outer
-    if @ab().alternate_home_page
+    if @ab().alternate_home_page()
       @home = new CI.outer.Home("welcome", "Continuous Integration and Deployment")
     else
       @home = new CI.outer.Home("home", "Continuous Integration and Deployment")


preventing blur from taking action after an 'enter' save

--- src/coffee/directives/edit_field_input.coffee
+++ src/coffee/directives/edit_field_input.coffee
@@ -12,6 +12,7 @@
         is_save = evt.keyCode == 13
         if is_save or evt.keyCode == 27
           editField.close is_save, model.$modelValue
+          original_value = null
           $rootScope.$digest()

       focus = () ->
@@ -19,7 +20,7 @@
         original_value = model.$modelValue

       blurOut = () ->
-        no_action = original_value == model.$modelValue
+        no_action = (original_value == model.$modelValue) || (original_value == null)
         editField.close false, original_value, no_action
         $rootScope.$digest()


Fetch all saved artworks at once. Infinite scrolling.

--- apps/following/client/favorites.coffee
+++ apps/following/client/favorites.coffee
@@ -3,20 +3,69 @@
 sd                      = require('sharify').data
 CurrentUser             = require '../../../models/current_user.coffee'
 ArtworkCollection       = require '../../../models/artwork_collection.coffee'
+Artworks                = require '../../../collections/artworks.coffee'
 artworkColumns  = -> require('../../../components/artwork_columns/template.jade') arguments...

 module.exports.FavoritesView = class FavoritesView extends Backbone.View
+  defaults:
+    numOfCols: 3
+    numOfRowsPerPage: 3
+    nextPage: 1 # page number of the next page to render

   initialize: (options) ->
+    { @numOfCols, @numOfRowsPerPage, @nextPage } = _.defaults options or {}, @defaults
+    @collection ?= new Artworks()
     @setupCurrentUser()
+    @fetchAllSavedArtworks success: =>
+      if @collection.length > @numOfCols * @numOfRowsPerPage
+        $(window).bind 'scroll.following', _.throttle(@infiniteScroll, 150)
+      @loadNextPage()

   setupCurrentUser: ->
     @currentUser = CurrentUser.orNull()
     @currentUser?.initializeDefaultArtworkCollection()
     @artworkCollection = @currentUser?.defaultArtworkCollection()
-    @currentUser.savedArtworks
-      success: (artworks) =>
-        @$('.favorite-artworks').html artworkColumns artworkColumns: artworks.groupByColumnsInOrder(3)
+
+  loadNextPage: =>
+    end = @numOfCols * @numOfRowsPerPage * @nextPage # 0-indexed, not including
+    start = end - @numOfCols * @numOfRowsPerPage
+    return unless @collection.length > start
+    console.log "Loading page ##{@nextPage} (#{start}, #{end}], @collection has #{@collection.length} artworks."
+    console.log "Rendering page ##{@nextPage}\n"
+    @renderArtworks(new Artworks(@collection.slice(start, end)))
+    ++@nextPage
+
+  infiniteScroll: =>
+    console.log "Infinite scrolling..."
+    $(window).unbind('.following') unless @numOfCols * @numOfRowsPerPage * (@nextPage - 1) < @collection.length
+    fold = $(window).height() + $(window).scrollTop()
+    $lastItem = @$('.favorite-artworks')
+    @loadNextPage() unless fold < $lastItem.offset()?.top + $lastItem.height()
+
+  # Fetch all saved artworks and save them to @collection
+  #
+  # @param {Object} options Provide `success` and `error` callbacks similar to Backbone's fetch
+  fetchAllSavedArtworks: (options) ->
+    url = "#{sd.ARTSY_URL}/api/v1/collection/saved-artwork/artworks"
+    data =
+      user_id: @currentUser.get('id')
+      private: true
+    @collection.fetchUntilEnd _.extend { url: url, data: data }, options
+
+  # Fetch the next page of saved artworks and (blindly) append them to @collection
+  #
+  # @param {Object} options Provide `success` and `error` callbacks similar to Backbone's fetch
+  fetchNextPageSavedArtworks: (options) ->
+    url = "#{sd.ARTSY_URL}/api/v1/collection/saved-artwork/artworks"
+    data =
+      user_id: @currentUser.get('id')
+      page: @nextPage
+      size: @numOfCols * @numOfRowsPerPage
+      private: true
+    @collection.fetch _.extend { url: url, data: data, add: true, remove: false, merge: false }, options
+
+  renderArtworks: (artworks) ->
+    @$('.favorite-artworks').append artworkColumns artworkColumns: artworks.groupByColumnsInOrder(3)

 module.exports.init = ->
   new FavoritesView el: $('body')


Fixes #4034 - Core Workflow: Stop after match is not saved.

--- app/assets/javascripts/app/models/core_workflow.coffee
+++ app/assets/javascripts/app/models/core_workflow.coffee
@@ -1,5 +1,5 @@
 class App.CoreWorkflow extends App.Model
-  @configure 'CoreWorkflow', 'name', 'object', 'preferences', 'condition_saved', 'condition_selected', 'perform', 'priority', 'active'
+  @configure 'CoreWorkflow', 'name', 'object', 'preferences', 'condition_saved', 'condition_selected', 'perform', 'stop_after_match', 'priority', 'active'
   @extend Spine.Model.Ajax
   @url: @apiPath + '/core_workflows'
   @configure_attributes = [


remove console.log

remove console.log

--- tasks/server/server.coffee
+++ tasks/server/server.coffee
@@ -22,8 +22,6 @@
 	.map (x) -> ".*\\#{x}"
 	.join '|'

-console.log 'expression', expression
-
 module.exports = ->
 	return if browserSync.active


updating shipping text

updating shipping text

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -326,7 +326,7 @@
         totalPrice = if totalPrice.length > 0 then "€ " + totalPrice.reduce (a,b) -> a + b
         $("h3[id='CartSum--label']").text("#{ label }")
         $("h3[id='CartSum--total']").text("#{ totalPrice }")
-        $("div[id='CartSum-label--container']").append("
(additional shipping and VAT may apply)
")
+        $("div[id='CartSum-label--container']").append("
(free worldwide shipping, additional VAT may apply)
")
       else
         $(".Cart-container").hide()


hotfix for country validation and autofill

--- assets/coffeescript/pupil_store.coffee
+++ assets/coffeescript/pupil_store.coffee
@@ -576,13 +576,13 @@
   countryValidator: ->
     if $(@cartPage).length > 0
       window.Parsley.addValidator('countryvalidator', ((value, requirement) ->
-        validity = value of countryList
-        if validity
+
+        update_country_dependents = (_val)->
           requirementIds = requirement.split("-")
           postalCodeId = requirementIds[0]
           stateId = requirementIds[1]

-          country = countryList[value]
+          country = countryList[_val]

           # if country US or CA force state abbreviations
           if country.countryISO is 'US' or country.countryISO is 'CA'
@@ -612,6 +612,23 @@
             .prop("required", false)
             .val("")
             .prop("disabled",true)
+
+        validity = value of countryList
+        if validity
+          update_country_dependents(value)
+        else
+          # check if 'United States' or 'USA' or 'US' or 'United States of America'
+          usa_alternates = ['United States', 'United States of America', 'USA', 'US']
+          if $("input[id='country_b']").val() == value && value in usa_alternates
+            _val = 'United States Of America'
+            $("input[id='country_b']").val(_val)
+            update_country_dependents(_val)
+            validity = true
+          if $("input[id='country_s']").val() == value && value in usa_alternates
+            _val = 'United States Of America'
+            $("input[id='country_b']").val(_val)
+            update_country_dependents(_val)
+            validity = true

         return validity
       )).addMessage 'en', 'countryvalidator', 'Please select a country from the list'


Adds "Ukoliko" as croatian alternative for "given"

--- grammars/gherkin_hr.cson
+++ grammars/gherkin_hr.cson
@@ -85,7 +85,7 @@
         ]
     }
     {
-        'match': '\\s*(Zadan |Zadani |Zadano )'
+        'match': '\\s*(Zadan |Zadani |Zadano |Ukoliko )'
         'name': 'support.class.gherkin.given'
     }
     {


feat(web): do nothing when same dialog selected;

--- apps/actor-web/app/shared/chats/chatsController.coffee
+++ apps/actor-web/app/shared/chats/chatsController.coffee
@@ -18,15 +18,15 @@
     console.log '[AW]ChatsController renderDialogs'
     console.log '[AW]ChatsController renderDialogs: dialogs:', dialogs
     @$timeout =>
-#      list.forEach (item) ->
-#        console.log item
-#        @getUnreadMessages (item.peer.id)
       @list = dialogs
       @$rootScope.$broadcast 'renderDialogs'

   selectChat: (peer) ->
     console.log '[AW]ChatsController selectChat'
     console.log '[AW]ChatsController selectChat: peer:', peer
+    if @actorService.currentPeer == peer
+      console.log '[AW]ChatsController selectChat: this peer already selected.'
+      return
     if @actorService.currentPeer
       console.log '[AW]ChatsController selectChat: conversation already opened: unbind...'
       @actorService.unbindChat @actorService.currentPeer


remove logging, fix query

remove logging, fix query

--- fixdangling.coffee
+++ fixdangling.coffee
@@ -30,14 +30,14 @@
 fixDangling = (doc_id, callback) ->
 	# look up project id from doc id
 	db.docs.find {_id:ObjectId(doc_id)}, {project_id:1}, (err, result) ->
-		console.log "doc_id", doc_id, "err", err, "result", result
+		#console.log "doc_id", doc_id, "err", err, "result", result
 		if err?
 			errored++
 			return callback()
 		if !result? or result.length == 0
 			missing++
 			return callback()
-		project_id = result[0]
+		project_id = result[0].project_id
 		console.log "found project_id", project_id, "for doc_id", doc_id
 		url = "http://localhost:#{options.port}/project/#{project_id}/doc/#{doc_id}/flush"
 		if options.force


Fixed issue #530  - Keyboard shortcuts dialog breaks url bar navigation.

--- app/assets/javascripts/app/controllers/widget/keyboard_shortcuts.coffee
+++ app/assets/javascripts/app/controllers/widget/keyboard_shortcuts.coffee
@@ -18,6 +18,10 @@
   exists: =>
     return true if @el.parents('html').length > 0
     false
+
+  onClosed: ->
+    return if window.location.hash isnt '#keyboard_shortcuts'
+    window.history.back()

 class App.KeyboardShortcutWidget extends Spine.Module
   @include App.LogInclude
@@ -143,6 +147,9 @@
               description: 'List of shortcuts'
               globalEvent: 'list-of-shortcuts'
               callback: =>
+                if window.location.hash is '#keyboard_shortcuts'
+                  App.Event.trigger('keyboard_shortcuts_close')
+                  return
                 if @dialog && @dialog.exists()
                   @dialog.close()
                   @dialog = false


add js namespace

add js namespace

--- BackofficeBundle/Resources/public/coffee/InternalLinkFormView.coffee
+++ BackofficeBundle/Resources/public/coffee/InternalLinkFormView.coffee
@@ -1,9 +1,21 @@
-InternalLinkFormView = OrchestraView.extend(
+###*
+ * @namespace OpenOrchestra:InternalLinkFormView
+###
+window.OpenOrchestra or= {}
+
+###*
+ * @class InternalLinkFormView
+###
+class OpenOrchestra.InternalLinkFormView extends OrchestraModalView
+
   events:
     'click .modalClose': 'closeModal'
     'hidden.bs.modal': 'closedModal'
     'click button[data-clone]': 'sendToTiny'

+  ###*
+   * @param {object} options
+  ###
   initialize: (options) ->
     @options = @reduceOption(options, [
       'selector'
@@ -16,6 +28,9 @@
     ]
     return

+  ###*
+   * Spin and render ajax call
+  ###
   render: ->
     @setElement @renderTemplate('OpenOrchestraBackofficeBundle:BackOffice:Underscore/internalLinkModalView',
       body: '
 Loading...
'
@@ -37,12 +52,21 @@
         activateForm(@, $('form', @$el))
     return

+  ###*
+   * @param {object} event
+  ###
   closeModal: (event) ->
     @$el.modal 'hide'

+  ###*
+   * @param {object} event
+  ###
   closedModal: (event) ->
     @$el.remove()

+  ###*
+   * @param {object} event
+  ###
   sendToTiny: (event) ->
     if $('.label-tinyMce', this.$el).val() != ''
       @closeModal()
@@ -52,7 +76,6 @@
         link.attr('data-' + element.data('key'), element.val())
       div = $('
').append(link)
       tinymce.get(@options.editor.id).insertContent(div.html())
-)

 jQuery ->
-  appConfigurationView.setConfiguration 'internalLink', 'showForm', InternalLinkFormView
+  appConfigurationView.setConfiguration 'internalLink', 'showForm', OpenOrchestra.InternalLinkFormView


metric: handle bln_euro unit

metric: handle bln_euro unit

--- app/assets/javascripts/lib/models/metric.coffee
+++ app/assets/javascripts/lib/models/metric.coffee
@@ -12,6 +12,9 @@
       when "mln_euro"
         u = "euro"
         power += 2
+      when "bln_euro"
+        u = "euro"
+        power += 3
       when "%" then return "%"
       when "MW"
         u = "watt"


send user to instagram with serialized form in params

--- app/assets/javascripts/mobile/_mobile.js.coffee
+++ app/assets/javascripts/mobile/_mobile.js.coffee
@@ -1,6 +1,6 @@
 window.templates = {}

-if gon.page is 'stores_show' or gon.page is 'products_show' or gon.page is 'products_index'
+if gon.page is 'stores_show' or gon.page is 'products_show' or gon.page is 'products_index' or gon.page is 'stores_new'
     # only reveal product gallery controls if there
     # is more than one product image
     render_product_gallery_controls = ->
@@ -77,6 +77,12 @@
         # products/show the header would stick
         # at the position it was set to at page unload
         header_fix = -> scrollTo(0, 0)
+
+        if gon.page is 'stores_new'
+            ($ '#sign_up_and_create_store').click ->
+                form_data = ($ '#new_store').serialize()
+                auth_url = gon.auth_url
+                window.location = "#{auth_url}?#{form_data}"

         if gon.page is 'stores_show'
             $('.product').each ->


#89 activate throttling

#89 activate throttling

--- app/assets/javascripts/oxalis/model/user.coffee
+++ app/assets/javascripts/oxalis/model/user.coffee
@@ -71,13 +71,14 @@

   push : ->

-    $.when(@pushImpl())
+    $.when(@pushThrottled())

   pushThrottled : ->

     saveFkt = @pushImpl
     @pushThrottled = _.throttle(_.mutexDeferred( saveFkt, -1), @push_throttle_time)
+    # @pushThrottled = _.throttle(saveFkt, @push_throttle_time)
     @pushThrottled()


add js setting to make flash messages persist

--- app/assets/javascripts/storytime/base.js.coffee
+++ app/assets/javascripts/storytime/base.js.coffee
@@ -9,7 +9,8 @@
 $ ()->
   initJS($("body").data("controller"), $("body").data("action"))

-  $(".flash").delay(4000).fadeOut() unless window.Storytime.test_env
+  debugger
+  $(".flash").delay(4000).fadeOut() unless window.Storytime.test_env || window.Storytime.persistent_flash_message

   $(".chosen").chosen()


Don't assign in conditionals

Don't assign in conditionals

The assignment operator can easily be mistaken with the equality
operator when used in a condition, making the code more difficult to
read.

--- app/assets/javascripts/tree_navigator.js.coffee
+++ app/assets/javascripts/tree_navigator.js.coffee
@@ -28,7 +28,9 @@
           elem.removeClass("closed").addClass("open")
           elem.siblings("ul").show()

-    if anchor = $(location).attr("hash")
+    anchor = $(location).attr("hash")
+
+    if anchor
       elem.find("a[href='#{anchor}']").parents("ul").each ->
         $(this).show()
         $(this).siblings("span").removeClass("closed").addClass("open")


this still isn't behaving properly, sigh

--- app/classifier/tasks/flexible-survey/index.cjsx
+++ app/classifier/tasks/flexible-survey/index.cjsx
@@ -30,8 +30,7 @@
       value: []

     isAnnotationComplete: (task, annotation) ->
-      annotation.value? annotation.value.length > 0 and not annotation._choiceInProgress
-      false
+      annotation.value?.length > 0 and not annotation._choiceInProgress

     testAnnotationQuality: (unknown, knownGood) ->
       # NOTE: Currently only choices (not answers) are compared.


Fixing admin browsing

Fixing admin browsing

--- app/coffee/modules/admin/project-profile.coffee
+++ app/coffee/modules/admin/project-profile.coffee
@@ -76,6 +76,7 @@
             @scope.severitiesList = _.sortBy(project.severities, "order")
             @scope.issueTypesList = _.sortBy(project.issue_types, "order")
             @scope.issueStatusList = _.sortBy(project.issue_statuses, "order")
+            @scope.$emit('project:loaded', project)
             return project

     loadInitialData: ->


Feature: bubbles option

Feature: bubbles option

I want be able to write ``{{bs-button bubbles=false}}`` as in http://emberjs.com/guides/templates/actions/#toc_stopping-event-propagation

--- app/scripts/components/BsButtonComponent.coffee
+++ app/scripts/components/BsButtonComponent.coffee
@@ -6,6 +6,7 @@
     block: null
     attributeBindings: ['disabled', 'dismiss:data-dismiss', '_type:type']
     _type: 'button'
+    bubbles: true

     init: ->
         @_super()
@@ -22,7 +23,8 @@
         if @block then "#{@classTypePrefix}-block" else null
     ).property('block').cacheable()

-    click: ->
+    click: (evt) ->
+        evt.stopPropagation() unless @get('bubbles')
         @sendAction('clicked')

     loadingChanged: (->


Updated router to support setting an extra object on Route

--- packages/http/src/router.coffee
+++ packages/http/src/router.coffee
@@ -18,20 +18,33 @@
 		@_scopedAction = null
 		@_scopedPrefix = ''

-	all: (path, action) ->
+	all: (all, action) ->
+		console.log 'Don’t use `all` routes. Offender: %s', path
 		return @app.all @_scopedPrefix + path, @_makeAction(action)

-	get: (path, action) ->
-		return @app.get @_scopedPrefix + path, @_makeAction(action)
+	get: (path, action, extra) ->
+		return @_add 'get', path, action, extra

-	post: (path, action) ->
-		return @app.post @_scopedPrefix + path, @_makeAction(action)
+	post: (path, action, extra) ->
+		return @_add 'post', path, action, extra

-	put: (path, action) ->
-		return @app.put @_scopedPrefix + path, @_makeAction(action)
+	put: (path, action, extra) ->
+		return @_add 'put', path, action, extra

-	delete: (path, action) ->
-		return @app.delete @_scopedPrefix + path, @_makeAction(action)
+	delete: (path, action, extra) ->
+		return @_add 'delete', path, action, extra
+
+	_add: (method, path, action, extra) ->
+		action = @_makeAction action
+
+		# WARNING: Prone to failure if ExpressJS changes this logic
+
+		@app.lazyrouter()
+		route = @app._router.route @_scopedPrefix + path
+		route = route[method].apply route, [ action ]
+		route.extra = extra or {}
+
+		return route

 	_makeAction: (action) ->
 		if typeof action is 'function'


Allow single-click video creation.

Allow single-click video creation.

--- cms/static/coffee/src/views/unit.coffee
+++ cms/static/coffee/src/views/unit.coffee
@@ -64,6 +64,9 @@
     event.preventDefault()

     type = $(event.currentTarget).data('type')
+    if type == 'video'
+      $('.new-component-video .new-component-template a').click()
+      return
     @$newComponentTypePicker.slideUp(250)
     @$(".new-component-#{type}").slideDown(250)
     $('html, body').animate({


Remove brainfart copy/paste.

Remove brainfart copy/paste.

--- mixirc/mixirc.coffee
+++ mixirc/mixirc.coffee
@@ -96,8 +96,6 @@
 		"comment[content]": comment
 		"comment[broadcaster_id]": channelId

-data = { "comment[content]": "testing things", "comment[broadcaster_id]": 27902 }
-
 xhrCommAddHeart = (commentId, user) ->
 	postMix user, "http://mixlr.com/comments/#{commentId}/heart"


feat(web): add missing methods to angular service;

--- apps/actor-web/app/services/actorService.coffee
+++ apps/actor-web/app/services/actorService.coffee
@@ -1,112 +1,125 @@
 class ActorService
+  isLoggedIn: false
   messenger: null
   currentPeer: null
-  isLoggedIn: false

-  constructor: (@$rootScope, @$sessionStorage) ->
+  constructor: (@$rootScope) ->
     console.log '[AW]ActorService constructor'
-    window.jsAppLoaded = =>
-      @initActor()
-      console.log '[AW]ActorService $broadcast: actorReady'
-      @$rootScope.$broadcast 'actorReady'
+    window.jsAppLoaded = => @initActor()

   initActor: ->
     console.log '[AW]ActorService initActor'
-    window.messenger = @messenger = new actor.ActorApp
-    @isLoggedIn = @messenger.isLoggedIn()
+    @messenger = new actor.ActorApp
+    window.messenger = @messenger
+    @setLoggedIn() if @messenger.isLoggedIn()
     console.log '[AW]ActorService initActor: @isLoggedIn:', @isLoggedIn
-    if @isLoggedIn then @setLoggedIn() else @setLoggedOut()
+    console.log '[AW]ActorService initActor: $broadcast: actorReady'
+    @$rootScope.$broadcast 'actorReady'

-  # isLoggedIn: ->
-  #   @messenger.isLoggedIn()
-
-  # checkAccess: (event, toState, toParams, fromState, fromParams) ->
-  #   console.log '[AW]ActorService checkAccess'
-  #   if toState.data != undefined
-  #     if toState.data.noLogin != undefined && toState.data.noLogin
-  #       console.log '[AW]ActorService checkAccess: before login'
-  #       return
-  #   else
-  #     if @isLoggedIn
-  #       console.log '[AW]ActorService checkAccess: authenticated'
-  #       @$rootScope.isLoggedIn = @$sessionStorage.isLoggedIn
-  #     else
-  #       console.log '[AW]ActorService checkAccess: redirect to login'
-  #       event.preventDefault()
-  #       @$rootScope.$state.go 'login'

   setLoggedIn: () =>
     console.log '[AW]ActorService setLoggedIn'
+    @isLoggedIn = true
     @$rootScope.$state.go 'home'
     @$rootScope.$broadcast 'actorLoggedIn'
-
   setLoggedOut: () =>
     console.log '[AW]ActorService setLoggedOut'
     localStorage.clear()
     @isLoggedIn = false
     @$rootScope.$state.go 'login'
     @$rootScope.$broadcast 'actorLoggedOut'
+  setCurrentPeer: (peer) ->
+    console.log '[AW]ActorService setCurrentPeer'
+    console.log '[AW]ActorService setCurrentPeer: peer:', peer
+    @currentPeer = peer
+
+  bindChat: (peer, callback) ->
+    console.log '[AW]ActorService bindChat'
+    console.log '[AW]ActorService bindChat: peer:', peer
+    @messenger.bindChat peer, callback
+  bindDialogs: (callback) ->
+    console.log '[AW]ActorService bindDialogs'
+    @messenger.bindDialogs (dialogs) ->
+      console.log '[AW]ActorService bindDialogs: dialogs:', dialogs
+      callback dialogs
+  bindGroup: (peer) ->
+    console.log '[AW]ActorService bindGroup'
+    console.log '[AW]ActorService bindGroup: peer:', peer
+  bindTyping: ->
+    console.log '[AW]ActorService bindTyping'
+  bindUser: (peer) ->
+    console.log '[AW]ActorService bindUser'
+    console.log '[AW]ActorService bindUser: peer:', peer
+
+  unbindChat: (peer, callback) ->
+    console.log '[AW]ActorService unbindChat'
+    console.log '[AW]ActorService unbindChat: peer:', peer
+    @messenger.unbindChat peer, callback
+  unbindDialogs: ->
+    console.log '[AW]ActorService unbindDialogs'
+  unbindGroup: ->
+    console.log '[AW]ActorService unbindGroup'
+  unbindTyping: ->
+    console.log '[AW]ActorService unbindTyping'
+  unbindUser: ->
+    console.log '[AW]ActorService unbindUser'
+
+  getAuthPhone: ->
+    console.log '[AW]ActorService getAuthPhone'
+  getAuthState: ->
+    console.log '[AW]ActorService getAuthState'
+  getGroup: ->
+    console.log '[AW]ActorService getGroup'
+  getTyping: ->
+    console.log '[AW]ActorService getTyping'
+  getUid: ->
+    console.log '[AW]ActorService getUid'
+    @messenger.getUid()
+  getUser: (uid) ->
+    console.log '[AW]ActorService getUser'
+    @messenger.getUser uid
+
+  clearChat: ->
+    console.log '[AW]ActorService clearChat'
+  deleteChat: ->
+    console.log '[AW]ActorService deleteChat'
+
+  # Draft
+  loadDraft: (peer) ->
+    console.log '[AW]ActorService loadDraft'
+    @messenger.loadDraft peer
+  saveDraft: (peer, draft) ->
+    console.log '[AW]ActorService saveDraft'
+    console.log '[AW]ActorService saveDraft: draft:', draft
+    if draft != null
+      @messenger.saveDraft peer, draft
+

   requestSms: (phone) ->
     console.log '[AW]ActorService requestSms'
     console.log '[AW]ActorService requestSms: phone:', phone
     @messenger.requestSms phone.toString(), (state) =>
       console.log '[AW]ActorService requestSms: state:', state
-      if state == 'code'
-        console.log '[AW]ActorService requestSms: state: code'
-        @$rootScope.$broadcast 'actorAuthCode'
+      switch state
+        when 'code'
+          console.log '[AW]ActorService requestSms: $broadcast actorAuthCode'
+          @$rootScope.$broadcast 'actorAuthCode'
     , (tag, message, canTryAgain, state) ->
-      console.log '[AW]ActorService requestSms: error'
+      console.log '[AW]ActorService requestSms: error: state:', state

   sendCode: (code) ->
     console.log '[AW]ActorService sendCode'
     @messenger.sendCode code, (state) =>
       console.log '[AW]ActorService sendCode: state:', state
-      if state == 'logged_in'
-        @setLoggedIn()
-      if state == 'signup'
-        @$rootScope.$broadcast 'actorSignUp'
-    , (tag, message, canTryAgain, state) =>
-      console.log '[AW]ActorService sendCode: error'
-      console.log '[AW]ActorService sendCode: tag, message, canTryAgain, state:', tag, message, canTryAgain, state
+      switch state
+        when 'logged_in'
+          @setLoggedIn()
+        when 'logged_in'
+          @$rootScope.$broadcast 'actorSignUp'
+    , (tag, message, canTryAgain, state) ->
+      console.log '[AW]ActorService sendCode: error: state:', state

-  bindDialogs: (callback) ->
-    console.log '[AW]ActorService bindDialogs'
-    @messenger.bindDialogs (items) ->
-      console.log '[AW]ActorService bindDialogs: items', items
-      callback items

-  onConversationClosed: (peer) ->
-    console.log '[AW]ActorService closeConversation'
-    console.log '[AW]ActorService closeConversation: peer:', peer
-    @messenger.onConversationClosed peer
-    @$rootScope.$broadcast 'onConversationClosed', peer
-
-  onConversationOpen: (peer) ->
-    console.log '[AW]ActorService openConversation'
-    console.log '[AW]ActorService openConversation: peer:', peer
-    @setCurrentPeer peer
-    @messenger.onConversationOpen peer
-    @$rootScope.$broadcast 'onConversationOpen', peer
-
-  bindChat: (peer, callback) ->
-    console.log '[AW]ActorService bindChat'
-    console.log '[AW]ActorService bindChat: peer:', peer
-    @messenger.bindChat peer, callback
-
-  unbindChat: (peer) ->
-    console.log '[AW]ActorService unbindChat'
-    console.log '[AW]ActorService unbindChat: peer:', peer
-    @messenger.unbindChat peer, ->
-
-  setCurrentPeer: (peer) ->
-    console.log '[AW]ActorService setCurrentPeer'
-    console.log '[AW]ActorService setCurrentPeer: peer:', peer
-    @currentPeer = peer
-
-  onTyping: ->
-    console.log '[AW]ActorService onTyping'
-    @messenger.onTyping @currentPeer

   sendMessage: (peer, message) ->
     console.log '[AW]ActorService sendMessage'
@@ -114,33 +127,35 @@
     # console.log '[AW]ActorService sendMessage: peer:', peer
     @messenger.sendMessage peer, message

-#  getAuthPhone: () ->
-#    console.log '[AW]ActorService getAuthPhone'
-#    @messenger.getAuthPhone()

-  loadDraft: (peer) ->
-    console.log '[AW]ActorService loadDraft'
-    @messenger.loadDraft peer
+  # Events
+  onAppHidden: ->
+    console.log '[AW]ActorService onAppHidden'
+  onAppVisible: ->
+    console.log '[AW]ActorService onAppVisible'
+  onConversationClosed: (peer) ->
+    console.log '[AW]ActorService onConversationClosed'
+    console.log '[AW]ActorService onConversationClosed: peer:', peer
+    @messenger.onConversationClosed peer
+    @$rootScope.$broadcast 'onConversationClosed', peer
+  onConversationOpen: (peer) ->
+    console.log '[AW]ActorService onConversationOpen'
+    console.log '[AW]ActorService onConversationOpen: peer:', peer
+    @messenger.onConversationOpen peer
+    @$rootScope.$broadcast 'onConversationOpen', peer
+  onDialogsClosed: ->
+    console.log '[AW]ActorService onDialogsClosed'
+  onDialogsOpen: ->
+    console.log '[AW]ActorService onDialogsOpen'
+  onProfileClosed: ->
+    console.log '[AW]ActorService onProfileClosed'
+  onProfileOpen: ->
+    console.log '[AW]ActorService onProfileOpen'
+  onTyping: ->
+    console.log '[AW]ActorService onTyping'
+    @messenger.onTyping @currentPeer

-  saveDraft: (peer, draft) ->
-    console.log '[AW]ActorService saveDraft'
-    console.log '[AW]ActorService saveDraft: draft:', draft
-    if draft != null
-      @messenger.saveDraft peer, draft
-
-  # onGroupOnline: () ->
-  #   console.log '[AW]ActorService onGroupOnline'
-  #   @$rootScope.$broadcast 'onGroupOnline'
-
-  getUid: ->
-    @messenger.getUid()
-
-  getUser: (uid) ->
-    console.log '[AW]ActorService getUser'
-    @messenger.getUser uid
-
-
-ActorService.$inject = ['$rootScope', '$sessionStorage']
+ActorService.$inject = ['$rootScope']

 angular
   .module 'actorWeb'


run jenkins, run

run jenkins, run

--- app/assets/javascripts/oxalis/view/settings/settings_tab_view.coffee
+++ app/assets/javascripts/oxalis/view/settings/settings_tab_view.coffee
@@ -13,6 +13,7 @@

   className : "col-sm-12"
   id : "lefttabbar"
+
   template : _.template("""


:lipstick:

:lipstick:

--- src/packages/command-logger/src/command-logger.coffee
+++ src/packages/command-logger/src/command-logger.coffee
@@ -55,7 +55,9 @@
       categoryName = _.humanizeEventName(eventName.substring(0, categoryStart))
       category = categories[categoryName]
       unless category
-        category = name: _.humanizeEventName(categoryName), children: []
+        category =
+          name: _.humanizeEventName(categoryName)
+          children: []
         categories[categoryName] = category
       category.children.push
         name: "#{_.humanizeEventName(eventName.substring(categoryStart + 1))} (#{details.count})"


turn off requiring every 3rd vote to be good

so that aaron can keep working through his list

need a better algorithm soon, lower scoring entries now have enough
exposure

--- models/person.coffee
+++ models/person.coffee
@@ -154,8 +154,8 @@
     next err if err

     # every third vote should be for something good
-    if votedOn.length % 3 is 0
-      filter['scores.overall'] = ($gt: 35)
+    # if votedOn.length % 3 is 0
+    #   filter['scores.overall'] = ($gt: 35)

     # not already voted on or skipped
     filter._id = $nin: votedOn.concat @skippedTeamIds


app-catalog: Renamed Update Available section to Updates and moved under All Apps link.

--- client/landing/app/Applications/Apps.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Apps.kdapplication/AppController.coffee
@@ -30,34 +30,8 @@
           title             : "All Apps"
           dataSource        : (selector, options, callback)=>
             KD.remote.api.JApp.someWithRelationship selector, options, callback
-        webApps             :
-          title             : "Web Apps"
-          dataSource        : (selector, options, callback)=>
-            selector['manifest.category'] = 'web-app'
-            KD.remote.api.JApp.someWithRelationship selector, options, callback
-        kodingAddOns        :
-          title             : "Add-ons"
-          dataSource        : (selector, options, callback)=>
-            selector['manifest.category'] = 'add-on'
-            KD.remote.api.JApp.someWithRelationship selector, options, callback
-        serverStacks        :
-          title             : "Server Stacks"
-          dataSource        : (selector, options, callback)=>
-            selector['manifest.category'] = 'server-stack'
-            KD.remote.api.JApp.someWithRelationship selector, options, callback
-        frameworks          :
-          title             : "Frameworks"
-          dataSource        : (selector, options, callback)=>
-            selector['manifest.category'] = 'framework'
-            KD.remote.api.JApp.someWithRelationship selector, options, callback
-            callback 'Coming soon!'
-        miscellaneous       :
-          title             : "Miscellaneous"
-          dataSource        : (selector, options, callback)=>
-            selector['manifest.category'] = 'misc'
-            KD.remote.api.JApp.someWithRelationship selector, options, callback
-        updateAvailable     :
-          title             : "Update Available"
+        updates             :
+          title             : "Updates"
           dataSource        : (selector, options, callback)=>
             appsController  = @getSingleton "kodingAppsController"
             {publishedApps} = appsController
@@ -70,6 +44,32 @@
               callback null, availableApps

               @addUpdateAllButton availableApps unless @isUpdateAllButtonAdded
+        webApps             :
+          title             : "Web Apps"
+          dataSource        : (selector, options, callback)=>
+            selector['manifest.category'] = 'web-app'
+            KD.remote.api.JApp.someWithRelationship selector, options, callback
+        kodingAddOns        :
+          title             : "Add-ons"
+          dataSource        : (selector, options, callback)=>
+            selector['manifest.category'] = 'add-on'
+            KD.remote.api.JApp.someWithRelationship selector, options, callback
+        serverStacks        :
+          title             : "Server Stacks"
+          dataSource        : (selector, options, callback)=>
+            selector['manifest.category'] = 'server-stack'
+            KD.remote.api.JApp.someWithRelationship selector, options, callback
+        frameworks          :
+          title             : "Frameworks"
+          dataSource        : (selector, options, callback)=>
+            selector['manifest.category'] = 'framework'
+            KD.remote.api.JApp.someWithRelationship selector, options, callback
+            callback 'Coming soon!'
+        miscellaneous       :
+          title             : "Miscellaneous"
+          dataSource        : (selector, options, callback)=>
+            selector['manifest.category'] = 'misc'
+            KD.remote.api.JApp.someWithRelationship selector, options, callback

       sort                  :
         'meta.modifiedAt'   :


chat: test and debug wildcard events

chat: test and debug wildcard events

--- client/landing/app/Applications/Chat.kdapplication/AppController.coffee
+++ client/landing/app/Applications/Chat.kdapplication/AppController.coffee
@@ -17,6 +17,8 @@

   handleChatOpen:({routingKey, bindingKey, publicName})->
     channel = KD.remote.mq.setP2PKeys publicName, { routingKey, bindingKey }, 'secret'
+    channel.on '*', ->
+      console.log @event, arguments

   create:(invitees, callback)->
     chatPanel = KD.getSingleton 'chatPanel'


Dont hide CV section just b/c theres no hometown/location data

--- desktop/apps/artist/client/views/cv.coffee
+++ desktop/apps/artist/client/views/cv.coffee
@@ -24,7 +24,5 @@
   render: (artist = {}) ->
     artistMetadata = artistHelpers.artistMeta @model.toJSON()
     @$el.html template _.extend { showHelpers, artistMetadata }, artist
-    if artistMetadata.length == 0
-      @$('#artist-cv-section').remove()
     super
     this


Add: Change from low res to high res image in slideshow

Signed-off-by: Christian Roth <396398d2f664a436582eed8a8cfb08dd7671c8d6@port17.de>

--- assets/coffee/views/picture/picture-view.coffee
+++ assets/coffee/views/picture/picture-view.coffee
@@ -15,10 +15,12 @@
     className:  'item'
     tagName:    'li'
     inlinescrolling: 160
+    loadThreshold: 400

     render: ->
       super
       $img = @$el.children('.image').first()
+      $img.data('loaded', no)

       highSource = $img.data('original');
       imageHeight = $img.data('height');
@@ -31,6 +33,15 @@

         position = (@inlinescrolling - @inlinescrolling / $('body').innerWidth() * imagePos) / -2
         if -@inlinescrolling <= position <= 0 then $img.css('background-position', "#{position}px 100%")
+
+        if imagePos - $('body').innerWidth() - @loadThreshold < 0 and not $img.data('loaded')
+          $img.data('loaded', yes)
+          $preloadImg = $('<img>').attr('src', highSource)
+          $preloadImg.appendTo('body').hide().on 'load', =>
+            $preloadImg.remove()
+            $img.fadeOut 'fast', ->
+              $img.css('background-image', "url('#{highSource}')").fadeIn 'fast'
+

       $(window).resizestop =>
         windowHeight = $('body').innerHeight()
@@ -54,8 +65,3 @@
         @$el.css('margin-top', (windowHeight - height) / 2)

       $(window).trigger 'resize'
-
-      $preloadImg = $('<img>').attr('src', highSource)
-      $preloadImg.appendTo('body').hide().on 'load', =>
-        $preloadImg.remove()
-        $img.css('background-image', "url('#{highSource}')")


Should pass along the current step when triggering the next event

--- components/branching_state/index.coffee
+++ components/branching_state/index.coffee
@@ -38,8 +38,9 @@
   next: ->
     @set('moves', (@get('moves') + 1))
     @set('position', @get('position') + 1) unless @isEnd()
-    @trigger 'next'
-    @current()
+    current = @current()
+    @trigger 'next', current
+    current

   total: ->
     offset = @get('moves') - @get('position')


Client: Activity: Created setChannelParticipantsInputQuery action. It dispatches SET_PARTICIPANT_USERS_QUERY and searchAccounts by query

--- client/activity/lib/flux/chatinput/actions/user.coffee
+++ client/activity/lib/flux/chatinput/actions/user.coffee
@@ -97,6 +97,17 @@
   dispatch SET_CHAT_INPUT_USERS_VISIBILITY, { stateId, visible }

+setChannelParticipantsInputQuery = (query) ->
+
+  if query
+    { SET_PARTICIPANT_USERS_QUERY } = actionTypes
+    dispatch SET_PARTICIPANT_USERS_QUERY, { query }
+    resetChannelParticipantsSelectedIndex()
+    appActions.user.searchAccounts query
+
+  else
+    unsetChannelParticipantsInputQuery()
+
 ###*
  * Action to increment users selected index
 ###
@@ -123,6 +134,7 @@
   moveToPrevIndex
   resetSelectedIndex
   setVisibility
+  setChannelParticipantsInputQuery
   moveToNextChannelParticipantIndex
   moveToPrevChannelParticipantIndex
 }


dashboard: button control is added

dashboard: button control is added

--- client/admin/lib/views/moderation/topicitemview.coffee
+++ client/admin/lib/views/moderation/topicitemview.coffee
@@ -8,7 +8,7 @@
 KDHitEnterInputView  = kd.HitEnterInputView

 TopicLeafItemView    = require './topicleafitemview'
-SimilarItemView      = require './similaritemview'
+SelectableItemView      = require './selectableitemview'

 module.exports = class TopicItemView extends KDListItemView

@@ -24,13 +24,16 @@

     super options, data

-    @typeLabel = new KDCustomHTMLView
-      cssClass : 'role'
+    @moderationLabel = new KDCustomHTMLView
+      cssClass : 'moderateRole'
       partial  : "Moderate "
       click    : =>
         @settings.toggleClass  'hidden'
-        @typeLabel.toggleClass 'active'
-
+        @moderationLabel.toggleClass 'active'
+
+    @typeLabel = new KDCustomHTMLView
+      cssClass : 'type-label'
+
     @createSettingsView(data)

   createLeafItemViews: (data) ->
@@ -63,10 +66,44 @@

     @settings  = new KDCustomHTMLView
       cssClass : 'settings hidden'
-
-    @settings.addSubView deleteButton = new KDButtonView
-      cssClass : 'solid compact outline'
-      title    : 'DELETE CHANNEL'
+
+    if data.typeConstant is "topic"
+      @settings.addSubView deleteButton = new KDButtonView
+        cssClass : 'solid compact outline'
+        title    : 'DELETE CHANNEL'
+        callback :=>
+          options =
+            rootId  : kd.singletons.groupsController.getCurrentGroup().socialApiChannelId
+            leafId  : data.id
+          console.log data.id
+          kd.singletons.socialapi.moderation.blacklist options, (err, data) =>
+            console.log arguments
+            if err
+              console.log "no leaf channel found for #{data.id}, #{data.name}"
+    else
+      options =
+        rootId  : kd.singletons.groupsController.getCurrentGroup().socialApiChannelId
+        leafId  : data.id
+      console.log data.id
+      kd.singletons.socialapi.moderation.fetchRoot options, (err, rootChannel) =>
+        console.log 123, arguments
+        if err
+          return console.log "err while fething root", err
+
+        if rootChannel
+          text = "Blacklisted"
+          if kd.singletons.groupsController.getCurrentGroup().socialApiChannelId isnt rootChannel.id
+            text = "linked to #{rootChannel.name}"
+
+        @typeLabel.setPartial "#{text}"
+
+        @settings.addSubView whitelistButton = new KDButtonView
+          cssClass : 'solid compact outline'
+          title    : 'WHITELIST CHANNEL'
+          callback : => console.log data
+
+
+

     @settings.addSubView @removeLabel = new KDCustomHTMLView
       cssClass: 'solid compact hidden'
@@ -81,11 +118,17 @@
       title    : 'REMOVE LINK'
       callback : =>
         listItems = @leafChannelsListController.getListItems()
-        console.log item for item in listItems
-        #listItems?.forEach (item)->
-          #console.log item
-        #console.log listItems
-
+        for item in listItems when item.switcher.getValue() is true
+          options =
+            rootId  :  data.id
+            leafId  : item.getData().id
+          console.log data.id
+          console.log item.getData().id
+          kd.singletons.socialapi.moderation.unlink options, (err, @item) =>
+            console.log arguments
+            if err
+              console.log "no leaf channel found for #{data.id}, #{data.name}"
+

     @settings.addSubView new KDCustomHTMLView
       cssClass: 'solid compact'
@@ -110,7 +153,19 @@
       title    : 'LINK CHANNEL'
       callback : =>
         listItems = @similarChannelsListController.getListItems()
-        console.log item.switcher.getValue() for item in listItems
+        for item in listItems when item.switcher.getValue() is true
+          options =
+            rootId  :  data.id
+            leafId  : item.getData().id
+          console.log data.id
+          console.log item.getData().id
+          kd.singletons.socialapi.moderation.link options, (err, @item) =>
+            console.log arguments
+            if err
+              console.log "no leaf channel found for #{data.id}, #{data.name}"
+
+        #if item.switcher.getValue() is true for item in listItems
+        #console.log "biseyler" for item in listItems when item.switcher.getValue() is true

   searchSimilarChannels: ->
@@ -147,8 +202,12 @@
       return @similarChannelsListController.hideLazyLoader()

     @skip += channels.length
+

     for channel in channels
+      if @getData().getId() is channel.getId()
+        @skip--
+        continue
       @similarChannelsListController.addItem channel

     @similarChannelsListController.hideLazyLoader()
@@ -161,7 +220,7 @@
     @leafChannelsListController       = new KDListViewController
       viewOptions         :
         wrapper           : yes
-        itemClass         : TopicLeafItemView
+        itemClass         : SelectableItemView
         cssClass          : 'leaf-channel-list'
         itemOptions       : {}
       noItemFoundWidget   : new KDCustomHTMLView
@@ -179,7 +238,7 @@
     @similarChannelsListController       = new KDListViewController
       viewOptions         :
         wrapper           : yes
-        itemClass         : SimilarItemView
+        itemClass         : SelectableItemView
         cssClass          : 'similar-item-list'
         itemOptions       : {}
       noItemFoundWidget   : new KDCustomHTMLView
@@ -192,14 +251,15 @@
     #@listController.on 'LazyLoadThresholdReached', @bound 'fetchChannels'

   pistachio: ->
-    data     = @getData()
-    type     = 'Type'
+    data          = @getData()
+    moderateRole  = 'Topic'

     return """

#{data.name}

       {{> @typeLabel}}
+      {{> @moderationLabel}}

       {{> @settings}}
     """