add tour anchors for builder controls

add tour anchors for builder controls

--- tutor/src/components/task-plan/footer/index.cjsx
+++ tutor/src/components/task-plan/footer/index.cjsx
@@ -11,6 +11,7 @@
 BackButton   = require './back-button'
 DraftButton  = require './save-as-draft'
 DeleteLink   = require './delete-link'
+{ default: TourAnchor } = require '../../tours/anchor'

 PlanFooter = React.createClass
   displayName: 'PlanFooter'
@@ -70,44 +71,61 @@
     isPublished = TaskPlanStore.isPublished(id)

     <div className='builder-footer-controls'>
-      <SaveButton
-        onSave={@onSave}
-        onPublish={@onPublish}
-        isWaiting={isWaiting}
-        isSaving={@state.saving}
-        isEditable={@state.isEditable}
-        isPublishing={@state.publishing}
-        isPublished={isPublished}
-        hasError={hasError}
-      />
-      <DraftButton
-        onClick={@onSave}
-        isWaiting={isWaiting and @state.saving}
-        isPublishing={@state.publishing}
-        isFailed={isFailed}
-        hasError={hasError}
-        isPublished={isPublished}
-      />
-      <CancelButton
-        isWaiting={isWaiting}
-        onClick={@props.onCancel}
-        isEditable={@state.isEditable}
-      />
-      <BackButton
-        isEditable={@state.isEditable}
-        getBackToCalendarParams={@props.getBackToCalendarParams}
-      />
+
+      <TourAnchor id="builder-save-button">
+        <SaveButton
+          onSave={@onSave}
+          onPublish={@onPublish}
+          isWaiting={isWaiting}
+          isSaving={@state.saving}
+          isEditable={@state.isEditable}
+          isPublishing={@state.publishing}
+          isPublished={isPublished}
+          hasError={hasError}
+        />
+      </TourAnchor>
+
+      <TourAnchor id="builder-draft-button">
+        <DraftButton
+          onClick={@onSave}
+          isWaiting={isWaiting and @state.saving}
+          isPublishing={@state.publishing}
+          isFailed={isFailed}
+          hasError={hasError}
+          isPublished={isPublished}
+        />
+      </TourAnchor>
+
+      <TourAnchor id="builder-cancel-button">
+        <CancelButton
+          isWaiting={isWaiting}
+          onClick={@props.onCancel}
+          isEditable={@state.isEditable}
+        />
+      </TourAnchor>
+
+      <TourAnchor id="builder-back-button">
+        <BackButton
+          isEditable={@state.isEditable}
+          getBackToCalendarParams={@props.getBackToCalendarParams}
+        />
+      </TourAnchor>
+
       <HelpTooltip
         isPublished={isPublished}
       />
-      <DeleteLink
-        isNew={TaskPlanStore.isNew(id)}
-        onClick={@onDelete}
-        isFailed={isFailed}
-        isVisibleToStudents={@props.isVisibleToStudents}
-        isWaiting={TaskPlanStore.isDeleting(id)}
-        isPublished={isPublished}
-      />
+
+      <TourAnchor id="builder-delete-button">
+        <DeleteLink
+          isNew={TaskPlanStore.isNew(id)}
+          onClick={@onDelete}
+          isFailed={isFailed}
+          isVisibleToStudents={@props.isVisibleToStudents}
+          isWaiting={TaskPlanStore.isDeleting(id)}
+          isPublished={isPublished}
+        />
+      </TourAnchor>
+
     </div>

 module.exports = PlanFooter


allowing non-editable operators to be deleted

--- vendor/assets/javascripts/token-text-area.coffee
+++ vendor/assets/javascripts/token-text-area.coffee
@@ -65,6 +65,13 @@
             @addItem(result)
           else if @resultList.find("li").length == 1
             @addItem(@resultList.find("li").first())
+
+        when 8 # Backspace
+          if @options.operators
+            @range = @getRange()
+            parent = @range.commonAncestorContainer.parentElement
+            if parent.classList.contains('operator')
+              parent.parentNode.removeChild(parent)

         when 40 # Down arrow
           if @resultList.find("li").length > 0
@@ -299,7 +306,8 @@
       try
         @range = @getRange()
         operator = @range.startContainer.data.trim() if @range.startContainer.data
-        if operator && @options.operators.map((op) -> op.toLowerCase()).includes(operator.toLowerCase())
+        operatorIsPicked = @range.commonAncestorContainer.parentElement.classList.contains('operator')
+        if operator && @options.operators.map((op) -> op.toLowerCase()).includes(operator.toLowerCase()) && !operatorIsPicked
           @word = [@range.startContainer.data] #TODO: Make this not a hack
           @addItem($(''+operator.toUpperCase()+''), true)


fix(lint): Whitespace issue

fix(lint): Whitespace issue

--- src/flux/stores/workspace-store.coffee
+++ src/flux/stores/workspace-store.coffee
@@ -18,7 +18,7 @@
 Sheet =
   Global: defineSheet 'Global'

-  Root: defineSheet 'Root',
+  Root: defineSheet 'Root',
     list: [Location.RootSidebar, Location.RootCenter]
     split: [Location.RootSidebar, Location.RootCenter, Location.MessageList, Location.MessageListSidebar]


Add disabled state for modal

Add disabled state for modal

--- _source/client/templates/components/modal.coffee
+++ _source/client/templates/components/modal.coffee
@@ -17,8 +17,11 @@
     self.data().verticalAlign is "top"

   destroy: (event) ->
-    event?.preventDefault()
-    Blaze.remove @._internals.templateInstance.view
+    self = @
+
+    unless Session.get("Apollos.modal.disabled")
+      event?.preventDefault()
+      Blaze.remove @._internals.templateInstance.view

   closeIfOverlay: (event) ->
     if $(event.currentTarget).hasClass("overlay--solid-dark")


Fixed update account ledger reference

Fixed update account ledger reference

--- app/assets/javascripts/app/account_ledger.coffee
+++ app/assets/javascripts/app/account_ledger.coffee
@@ -42,7 +42,7 @@
       alert 'Exisitio un error al actualizar la referencia de' + txt

 $(->
-  $('.account_ledger').on('click', '.edit-ledger-reference-link', ->
+  $('body').on('click', '.account_ledger .edit-ledger-reference-link', ->
     new AccountLedgerReference(this)
   )
 )
@@ -51,7 +51,7 @@
 <form>
   <textarea id='reference' rows='3' cols='35'>{{reference}}</textarea>

-  <button class='btn btn-small btn-primary'>Actualizar referencia</button>
+  <button class='btn btn-small btn-primary' title='Actualizar referencia'>Act. referencia</button>
   Cancelar
 </form>
 """


now have a scrolling stop button

now have a scrolling stop button

--- app/assets/javascripts/components/song.js.coffee
+++ app/assets/javascripts/components/song.js.coffee
@@ -5,6 +5,10 @@
 $(document).on "click", "#play", ->
   console.log("scrolling!!")
   pageScroll()
+
+$(document).on "click", "#stop", ->
+  console.log("stop!!")
+  $('.tabs').stop()

 @Song = React.createClass
@@ -33,6 +37,10 @@
         className: 'small-1 columns skinny-font'
         id: 'play'
         "play!"
+      React.DOM.h3
+        className: 'small-1 columns skinny-font'
+        id: 'stop'
+        "stop!"
       React.DOM.h2
         className: 'tabs small-8 large-8 columns'
         for i in @state.song.lyrics_tabs.split("|")


add link to DHLab

add link to DHLab

--- app/assets/javascripts/partials/yale-header.cjsx
+++ app/assets/javascripts/partials/yale-header.cjsx
@@ -16,9 +16,9 @@

-        <Link to="/" activeClassName="selected" className="main-header-item logo">
+

-        </Link>
+


fix assignment group re-rendering on initial load

don't render on add until the collection is loaded

test plan:
* create a course with over 10 assignment groups
* it should work (and also load much better)

closes #CNVS-24118

Change-Id: I7c12e43042a2e0b0587e2a86fd4a9813c6cade28
Reviewed-on: https://gerrit.instructure.com/66096
Tested-by: Jenkins
Reviewed-by: Jeremy Stanley <b3f594e10a9edcf5413cf1190121d45078c62290@instructure.com>
QA-Review: Michael Hargiss <59e3fde81b8d9a4f5e0cc016a3c2695591912604@instructure.com>
Product-Review: Jason Sparks <542e620f0c6c3447ce6e2e8c83a97102b99f89c6@instructure.com>

--- app/coffeescripts/views/assignments/AssignmentGroupListView.coffee
+++ app/coffeescripts/views/assignments/AssignmentGroupListView.coffee
@@ -62,9 +62,13 @@
       super
       @itemViewOptions = course: @course
       @collection.on 'render', @render
-      @collection.on 'add', @render
+      @collection.on 'add', @renderIfLoaded
       @collection.on 'remove', @render
       @collection.on 'change:groupWeights', @render
+
+    renderIfLoaded: =>
+      if @collection.loadedAll
+        @render()

     renderOnReset: =>
       @firstResetLanded = true


Make sure we still show the device commit, despite API changes

--- lib/actions/device.coffee
+++ lib/actions/device.coffee
@@ -94,6 +94,7 @@
 				device.status = status
 				device.dashboard_url = resin.models.device.getDashboardUrl(device.uuid)
 				device.application_name = device.belongs_to__application[0].app_name
+				device.commit = device.is_on__commit

 				console.log visuals.table.vertical device, [
 					"$#{device.device_name}$"


Use Strict Directive

Use Strict Directive

--- unicode_eastasianwidth.coffee
+++ unicode_eastasianwidth.coffee
@@ -1,3 +1,6 @@
+"use strict"
+
+
 if exports?
   unicodeEastAsianWidth = exports
 else


abstract watcher events to use methods

abstract watcher events to use methods

adds to the readability of the watcher file

--- lib/commands/watch.coffee
+++ lib/commands/watch.coffee
@@ -9,8 +9,20 @@
   project = new Roots(dir)

   process.stdout.write('compiling... '.grey)
-
-  project.watch()
-    .on('start', -> process.stdout.write('compiling... '.grey))
-    .on('error', console.error.bind(console))
-    .on('done', -> process.stdout.write('done!\n'.green))
+
+  w = project.watch()
+
+  w.on 'start', onStart
+  w.on 'error', onError
+  w.on 'done', onDone
+
+  w
+
+onError = (err) ->
+  process.stdout.write JSON.stringify(err).red
+
+onStart = ->
+  process.stdout.write 'compiling... '.grey
+
+onDone = ->
+  process.stdout.write 'done!\n'.green


remove outdated documentation from observe method

--- chrome/src/gmailr.coffee
+++ chrome/src/gmailr.coffee
@@ -196,14 +196,6 @@

     ###
     Subscribe to a specific event in Gmail
-    name                arguments passed to callback
-    'archive'         - count
-    'numUnreadChange' - currentVal, previousVal
-    'delete'          - count
-    'spam'            - count
-    'compose'
-    'viewChanged'
-    'applyLabel'
     ###
     observe: (type, cb) ->
       (@observers[type] ?= []).push cb


onboarding: selectbox instead of textbox for group name

--- client/dashboard/lib/views/onboarding/onboardingsectionform.coffee
+++ client/dashboard/lib/views/onboarding/onboardingsectionform.coffee
@@ -10,19 +10,23 @@

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

-    apps = []
-    apps.push { title: app, value: app }  for app of globals.config.apps
+    groups = [
+      title: 'IDE', value: 'IDE'
+    ]

     options.cssClass      = "section-form"
     @jCustomPartial       = data
     formData              = data?.partial or {}
     options.fields        =
-      name                :
-        placeholder       : "Name of your set"
-        name              : "name"
-        cssClass          : "thin"
-        label             : "Name"
-        defaultValue      : data?.name or ""
+      type                :
+        name              : "type"
+        label             : "Type"
+        type              : 'hidden'
+        nextElement       :
+          type            :
+            itemClass     : KDSelectBox
+            defaultValue  : data?.name
+            selectOptions : groups

     options.buttons       =
       Save                :
@@ -45,7 +49,7 @@
         visibility    : no
         overlay       : yes
         items         : @jCustomPartial?.partial.items   or []
-      name            : @inputs.name.getValue()          or ""
+      name            : @inputs.type.getValue()          or ""
       viewInstance    : @jCustomPartial?.viewInstance    or ""
       isActive        : @jCustomPartial?.isActive        or no
       isPreview       : @jCustomPartial?.isPreview       or no


remove spurious log

remove spurious log

--- bokehjs/src/coffee/server/usercontext/usercontext.coffee
+++ bokehjs/src/coffee/server/usercontext/usercontext.coffee
@@ -25,7 +25,6 @@
       "click .bokehdelete" : "deldoc"

     deldoc : (e) ->
-      console.log('foo')
       e.preventDefault()
       @model.destroy()
       return false


KDFramework: lazy callback fix on KDTabPaneView

--- client/Framework/components/tabs/KDTabPaneView.coffee
+++ client/Framework/components/tabs/KDTabPaneView.coffee
@@ -10,10 +10,11 @@

     @name = options.name

-    @on "KDTabPaneActive",   @becameActive
-    @on "KDTabPaneInactive", @becameInactive
-    @on "KDTabPaneDestroy",  @aboutToBeDestroyed
-    @on "KDTabPaneActive",   @bound "setMainView"
+    @on "KDTabPaneActive",        @becameActive
+    @on "KDTabPaneInactive",      @becameInactive
+    @on "KDTabPaneDestroy",       @aboutToBeDestroyed
+    @on "KDTabPaneActive",        @bound "setMainView"
+    @on "KDTabPaneLazyViewAdded", @bound "fireLazyCallback"

   becameActive: noop
   becameInactive: noop
@@ -43,12 +44,25 @@
     @getDelegate().hideCloseIcon @

   setMainView:->
-    {view} = @getOptions()
-    return if @mainView or not view
+    {view, viewOptions} = @getOptions()
+    return if @mainView

-    {itemClass, options, data} = view
-    @mainView = @addSubView if itemClass then new itemClass options, data else view
-    @emit "KDTabPaneLazyViewAdded", @mainView
+    if view instanceof KDView
+      @mainView = @addSubView view
+    else if viewOptions
+      {viewClass, options, data} = viewOptions
+      @mainView = @addSubView new viewClass options, data
+    else
+      return warn "probably you set a weird lazy view!"
+
+    @emit "KDTabPaneLazyViewAdded", this, @mainView
     return @mainView

   getMainView:-> @mainView
+
+  fireLazyCallback:(pane, view)->
+    {viewOptions} = @getOptions()
+    return  unless viewOptions
+    {callback} = viewOptions
+    return  unless callback
+    callback.call this, pane, view


Remove confirm spies since dialog is no longer shown

--- spec/metrics-spec.coffee
+++ spec/metrics-spec.coffee
@@ -3,12 +3,11 @@
 describe "Metrics", ->
   describe "when metrics are enabled", ->
     beforeEach ->
-      spyOn(atom, 'confirm').andReturn(0)
+      atom.config.set('metrics.sendData', true)

     it "reports activation events", ->
       spyOn(Reporter, 'request')
       atom.packages.activatePackage('metrics')
-      expect(atom.confirm).toHaveBeenCalled()
       expect(Reporter.request).toHaveBeenCalled()

       requestArgs = Reporter.request.calls[0].args[0]
@@ -36,12 +35,11 @@

   describe "when metrics are disabled", ->
     beforeEach ->
-      spyOn(atom, 'confirm').andReturn(1)
+      atom.config.set('metrics.sendData', false)

     it "reports activation events", ->
       spyOn(Reporter, 'request')
       atom.packages.activatePackage('metrics')
-      expect(atom.confirm).toHaveBeenCalled()
       expect(Reporter.request).not.toHaveBeenCalled()

     it "reports deactivation events", ->


 Merge branch 'master.cenk' into 'master'

Master.Cenk

--- client/About/team.coffee
+++ client/About/team.coffee
@@ -43,7 +43,7 @@
         username  : 'burakcan'
         title     : 'CSS Wizard'
       ,
-        username  : 'cenk6'
+        username  : 'cenk'
         title     : 'Software Engineer'
       ,
         username  : 'emred'


no new lines in transform string

no new lines in transform string

--- oridomi.coffee
+++ oridomi.coffee
@@ -682,12 +682,12 @@
     # Rotate on every axis in fracture mode.
     x = y = z = angle if fracture

-    el.style[css.transform] = """
+    el.style[css.transform] = "
                               rotateX(#{ x }deg)
                               rotateY(#{ y }deg)
                               rotateZ(#{ z }deg)
                               translate#{ translate }px)
-                              """
+                              "

   # This validates a given angle by making sure it's a float and by


Removed buggy line in router

Removed buggy line in router

--- app.coffee
+++ app.coffee
@@ -144,7 +144,7 @@
 app.get "/api/linkedin", passportConf.isAuthenticated, passportConf.isAuthorized, apiController.getLinkedin
 app.get "/mobile/areas", mobileController.getAreas
 app.get "/mobile/listings", mobileController.getListings
-app.post "/mobile/listing", express.multipart, mobileController.postListing
+app.post "/mobile/listing", mobileController.postListing
 app.post "/mobile/listing/buy", mobileController.postBuy
 app.post "/mobile/listing/relist", mobileController.postRelist
 app.post "/mobile/listing/message", mobileController.postMessage


Update interface tests to use forEach

Update interface tests to use forEach

--- specsrc/interface.coffee
+++ specsrc/interface.coffee
@@ -14,8 +14,8 @@
         expect(backburner.while).toBeAFunction()
     it 'should provide for', ->
         expect(backburner.for).toBeAFunction()
-    it 'should provide each', ->
-        expect(backburner.each).toBeAFunction()
+    it 'should provide forEach', ->
+        expect(backburner.forEach).toBeAFunction()
     it 'should provide map', ->
         expect(backburner.map).toBeAFunction()
     it 'should provide reduce', ->


Change port to 8080

Change port to 8080

--- app.coffee
+++ app.coffee
@@ -6,7 +6,7 @@
 TodoTxt = require "./app/todo.txt"
 TodoHtml = require "./app/todo.html"

-port = process.env.PORT || 5000
+port = 8080

 app = express()


Local package require

Local package require

--- app.coffee
+++ app.coffee
@@ -1,5 +1,5 @@
 express = require 'express'
-info = require 'package'
+info = require './package'
 http = require 'http'

 app = express()


fix trim

fix trim

--- app.coffee
+++ app.coffee
@@ -44,7 +44,7 @@

 io.sockets.on 'connection', (socket) ->
   client.lrange 'posts', 0, -1, (err, posts) ->
-    p = posts[0..-2]
+    p = posts[1..-1]
     posts = []
     for post in p
       posts.push JSON.parse post


Fix overwriting of configuration options

--- app.coffee
+++ app.coffee
@@ -66,8 +66,8 @@
 config.ip ?= '0.0.0.0'
 config.packageFolder ?= "#{__dirname}/packages/"
 config.packageFolder += '/' unless /\/$/.test config.packageFolder
-config.enableManualUpdate = on
-config.enableStatistics = on
+config.enableManualUpdate ?= on
+config.enableStatistics ?= on

 # initialize express
 app = do express


Fix fun run

Fix fun run

--- app.coffee
+++ app.coffee
@@ -72,4 +72,4 @@

 exports.run = (image, args) ->
   # body...
-  return runImage(image, args)
+  return run(image, args)


reordered static content and routes loading

--- app.coffee
+++ app.coffee
@@ -5,11 +5,8 @@
 logger       = require 'morgan'
 cookieParser = require 'cookie-parser'
 bodyParser   = require 'body-parser'
-
 passport     = require 'passport'

-routes       = require './routes/index'
-buckets      = require './routes/buckets'

 RedisStore =  require('connect-redis')(session);

@@ -37,15 +34,19 @@
 app.set('view engine', 'jade')

 app.use(favicon())
+app.use(require('stylus').middleware(path.join(__dirname, 'public')))
+app.use(express.static(path.join(__dirname, 'public')))
 app.use(logger('dev'))
 app.use(bodyParser.json())
 app.use(bodyParser.urlencoded())
 app.use(cookieParser())
-app.use(require('stylus').middleware(path.join(__dirname, 'public')))
-app.use(express.static(path.join(__dirname, 'public')))
 app.use(session(sessionOptions))
 app.use(passport.initialize())
 app.use(passport.session())
+
+routes       = require './routes/index'
+buckets      = require './routes/buckets'
+
 app.use('/', routes)
 app.use('/', buckets)


Fixed bug on unexisting wiki pages

Fixed bug on unexisting wiki pages

--- app/coffee/modules/wiki/main.coffee
+++ app/coffee/modules/wiki/main.coffee
@@ -112,7 +112,6 @@
             return prom.then null, (xhr) =>
                 ctx = {project: @params.pslug, slug: @params.slug}
                 @location.path(@navUrls.resolve("project-wiki-page-edit", ctx))
-                return @q.reject()

         return promise.then(=> @.loadProject())
                       .then(=> @.loadUsersAndRoles())


Fix cardLink prop type

Fix cardLink prop type

--- app/components/owned-card-list.cjsx
+++ app/components/owned-card-list.cjsx
@@ -13,7 +13,7 @@
   propTypes:
     imagePromise: React.PropTypes.func.isRequired
     listPromise: React.PropTypes.object.isRequired
-    cardLink: React.PropTypes.string.isRequired
+    cardLink: React.PropTypes.func.isRequired
     translationObjectName: React.PropTypes.string.isRequired
     ownerName: React.PropTypes.string
     heroClass: React.PropTypes.string


enhance: notifications for remove team

enhance: notifications for remove team

--- app/components/team-overview.coffee
+++ app/components/team-overview.coffee
@@ -9,20 +9,18 @@
   actions:
     deleteTeam: ->
       team = @get "team"
-      teamName = team.get("name").toLowerCase()
-      deletedName = prompt("Enter the team name which you want to delete ", "").toLowerCase()
-      if deletedName isnt teamName
+      deletedTeam = team.get("name")
+      teamName = deletedTeam.toLowerCase()
+      promptedItem = prompt("Enter the team name which you want to delete ", "").toLowerCase()
+      if promptedItem isnt teamName
         return @get("notify").error "Enter the right team name to delete it"
+      that = @
       team.destroyRecord()
-      ###
-      # @yashwin implemnt `then` & `catch`
-      @get("ajax").delete ENV.endpoints.teams, data: data
-      .then (data)->
-        that.get("notify").success "Team - #{teamName} has been deleted successfully"
+      .then ()->
+        that.get("notify").success "Team - #{deletedTeam} has been deleted successfully"
       .catch (error) ->
         that.get("notify").error error.payload.message
         for error in error.errors
           that.get("notify").error error.detail?.message
-      ###

 `export default TeamOverviewComponent`


fix can't send msgs to new livechat rooms

--- packages/rocketchat-ui/lib/RoomManager.coffee
+++ packages/rocketchat-ui/lib/RoomManager.coffee
@@ -94,10 +94,10 @@
 					query =
 						t: type

-					if type in ['c', 'p']
+					if type is 'd'
+						query.usernames = $all: [Meteor.user()?.username, name]
+					else
 						query.name = name
-					else if type is 'd'
-						query.usernames = $all: [Meteor.user()?.username, name]

 					room = ChatRoom.findOne query, { reactive: false }


expiration redirection only for candiature urls fix

--- app/scripts/app.coffee
+++ app/scripts/app.coffee
@@ -161,8 +161,8 @@
                 if(response.data && response.data.candidature)
                   # candidature expired
                   if (response.data.candidature == "expired")
-                    # user candidate
-                    if($state.$current!=undefined && $state.$current.name.indexOf("candidature.")!=-1)
+                    # user candidate (url candidature)
+                    if($state.$current.name.indexOf("candidature.")!=-1)
                       # go to expiration page
                       $state.go("candidature.expired")
                 return $q.reject(response);


Fix URL being incorrectly overridden when selecting a preset

--- app/scripts/app.coffee
+++ app/scripts/app.coffee
@@ -93,7 +93,9 @@
     catch e
       return

+    @undelegateEvents()
     @$loop.iCheck(if options.loop then "check" else "uncheck")
+    @delegateEvents @events

     @playAnimation bounceObject: bounce, fromURL: true
     @preferences.setFromBounceObject bounce


switch order of args in auth -- should be login, signup not signup, login

--- apps/auth/index.coffee
+++ apps/auth/index.coffee
@@ -18,7 +18,7 @@
 app.post loginPath, routes.submitLogin
 app.post signupPath, routes.submitLogin
 app.get '/force/log_in_to_artsy', routes.loginToArtsy
-app.get twitterCallbackPath, routes.submitEmailForTwitter, routes.loginToArtsy
+app.get twitterCallbackPath, routes.loginToArtsy, routes.submitEmailForTwitter
 app.get facebookCallbackPath, routes.loginToArtsy

 # Twitter "One last Step" UI to enter email and login


#309 - cosmetic details

#309 - cosmetic details

--- jsapp/xlform_model_view/view.surveyApp.coffee
+++ jsapp/xlform_model_view/view.surveyApp.coffee
@@ -144,11 +144,11 @@
           if @expand_all_multioptions
             @expand_all_multioptions = false
             $(".card.card--selectquestion").removeClass("card--expandedchoices")
-            $expand_multioptions.text("Expand All Questions")
+            $expand_multioptions.html($expand_multioptions.html().replace("Colapse", "Expand"));
           else
             @expand_all_multioptions = true
             $(".card.card--selectquestion").addClass("card--expandedchoices")
-            $expand_multioptions.text("Colapse All Questions")
+            $expand_multioptions.html($expand_multioptions.html().replace("Expand", "Colapse"));

       @


jupyter: make normal tab work, when nothing to complete

--- src/smc-webapp/jupyter/codemirror-editor.cjsx
+++ src/smc-webapp/jupyter/codemirror-editor.cjsx
@@ -127,10 +127,14 @@
             @tab_nothing_selected()

     tab_nothing_selected: ->
-        pos  = @cm.cursorCoords(@cm.getCursor(), 'local')
+        cur  = @cm.getCursor()
+        if cur.ch == 0 or /\s/.test(@cm.getLine(cur.line)[cur.ch - 1])  # whitespace before cursor
+            CodeMirror.commands.defaultTab(@cm)
+            return
+        pos  = @cm.cursorCoords(cur, 'local')
         top  = pos.bottom - @cm.getScrollInfo().height
         left = pos.left
-        @props.actions.complete(@cm.getValue(), @cm.getCursor(), @props.id, {top:top, left:left})
+        @props.actions.complete(@cm.getValue(), cur, @props.id, {top:top, left:left})

     init_codemirror: (options, value, cursors) ->
         @_cm_destroy()


Change atom theme

Change atom theme

--- atom/.atom/config.cson
+++ atom/.atom/config.cson
@@ -4,13 +4,13 @@
       abaseColor: "#607d8b"
       predefinedColor: "Blue Grey"
     fonts:
-      fontSize: 12
+      fontSize: 14
     tabs:
       compactTabs: true
       tintedTabBar: true
     treeView:
       blendTabs: true
-      compactList: true
+      compactList: false
     ui: {}
   core:
     autoHideMenuBar: true
@@ -20,7 +20,7 @@
     packagesWithKeymapsDisabled: []
     telemetryConsent: "limited"
     themes: [
-      "atom-material-ui"
+      "one-dark-ui"
       "atom-material-syntax"
     ]
   editor:
@@ -39,8 +39,11 @@
     autoIndentJSX: true
   linter: {}
   "linter-ui-default":
-    panelHeight: 58
-    showPanel: true
+    panelHeight: 41
+  "one-dark-ui":
+    fontSize: 12
+  "one-light-ui":
+    fontSize: 12
   "split-diff":
     diffWords: true
     ignoreWhitespace: true
@@ -48,8 +51,7 @@
     rightEditorColor: "green"
     scrollSyncType: "Vertical + Horizontal"
     syncHorizontalScroll: true
-  "tree-view":
-    hideVcsIgnoredFiles: true
+  "tree-view": {}
   "vim-mode-plus": {}
   welcome:
     showOnStartup: false


fix bug with check not prefixed by env.utilities in presentation layer.

--- src/presentationLayer/api/index.coffee
+++ src/presentationLayer/api/index.coffee
@@ -52,7 +52,7 @@
 				env.data.apps.remove req.params.key, (e, r) =>
 					return next(e) if e
 					env.events.emit 'app.remove', req.user, app
-					res.send check.nullv
+					res.send env.utilities.check.nullv
 					next()

 		# reset the public key of an app


fix https://github.com/sagemathinc/smc/issues/333 -- don't allow account creation token if there are any configured single sign on passports

--- src/smc-webapp/r_account.cjsx
+++ src/smc-webapp/r_account.cjsx
@@ -1042,7 +1042,14 @@
         if @state.state == 'save'
             <Saving />

-    render : ->
+    render_unsupported: ->  # see https://github.com/sagemathinc/smc/issues/333
+

+            Not supported since some passport strategies are enabled.
+

+
+    render : ->
+        if STRATEGIES.length > 1
+            return @render_unsupported()

              {@render_control()}
              {@render_save()}


fix interval

fix interval

--- src/scripts/backlog-watch-users.coffee
+++ src/scripts/backlog-watch-users.coffee
@@ -108,7 +108,7 @@

   watch = ->
     next = ->
-      setTimeout (-> watch()), INTERVAL
+      setTimeout (-> watch()), interval
     displayUsers()
       .then next, next


replacing double quotes with single quotes, fixing spacing

--- src/scripts/helpers/socialmedia.coffee
+++ src/scripts/helpers/socialmedia.coffee
@@ -3,7 +3,7 @@
   _ = require('underscore')

   return new class SocialMedia
-    locationOriginPolyFillForIe: () ->
+    locationOrigin: () ->
       # Polyfill for location.origin since IE doesn't support it
       port = if location.port then ":#{location.port}" else ''
       location.origin = location.origin or "#{location.protocol}//#{location.hostname}#{port}"
@@ -11,12 +11,12 @@

     socialMediaInfo: (description,title) ->
       url = window.location.href
-      image = location.origin + "/images/logo.png"
+      image = location.origin + '/images/logo.png'
       share =
         url: url
-        source:'OpenStax CNX'
-        via:'cnxorg'
-        summary:description
+        source: 'OpenStax CNX'
+        via: 'cnxorg'
+        summary: description
         title: title
         image: image
         # Encode all of the shared values for a URI


Don't define the legacy url when viewing content

--- src/scripts/modules/media/media.coffee
+++ src/scripts/modules/media/media.coffee
@@ -44,10 +44,11 @@
         if currentPage
           moduleID = currentPage?.get('legacy_id')
           moduleVersion = currentPage?.get('legacy_version')
-          headerView.setLegacyLink("content/#{moduleID}/#{moduleVersion}/?collection=#{id}/#{version}")
-          return
+          if moduleID and moduleVersion
+            headerView.setLegacyLink("content/#{moduleID}/#{moduleVersion}/?collection=#{id}/#{version}")
+        return

-      headerView.setLegacyLink("content/#{id}/#{version}")
+      headerView.setLegacyLink("content/#{id}/#{version}") if id and version

     onRender: () ->
       @regions.media.append(new MediaEndorsedView({model: @model}))


Slight changes to settings post route

Slight changes to settings post route

--- src/server/routes/post/settings.coffee
+++ src/server/routes/post/settings.coffee
@@ -11,11 +11,16 @@
 		service.request "post", "/settings"
 			.then complete, error
 		###
+		b = req.body
+		user =
+			username: b.username
+			token: b.token
+		settings =
+			name: b.name
+			surname: b.surname
+			email: b.email
 		json =
-			data:
-				name: req.body.name
-				surname: req.body.surname
-				email: req.body.email
+			data: settings
 		res.status(200).json json

 module.exports = routes


fix issue with changing editor and leaving tab quickly

--- src/smc-webapp/code-editor/editor.cjsx
+++ src/smc-webapp/code-editor/editor.cjsx
@@ -43,6 +43,7 @@

     componentWillUnmount: ->
         @props.actions.disable_key_handler()
+        @props.actions.set_syncstring_to_codemirror()

     render_button_bar: ->
         <ButtonBar


update

update


new implementation to fix typography for TeX

--- src/tex-writer-typofix.coffee
+++ src/tex-writer-typofix.coffee
@@ -74,169 +74,217 @@
 # @_get_cjk_interchr_glue = ( options ) => options[ 'tex' ]?[ 'cjk-interchr-glue' ] ? '\ue080'

+# #-----------------------------------------------------------------------------------------------------------
+# @fix_typography_for_tex = ( text, options, send = null ) =>
+#   ### An improved version of `XELATEX.tag_from_chr` ###
+#   ### TAINT should accept settings, fall back to `require`d `options.coffee` ###
+#   glyph_styles                  = options[ 'tex' ]?[ 'glyph-styles'             ] ? {}
+#   ### Legacy mode: force one command per non-latin character. This is OK for Chinese texts,
+#   but a bad idea for all other scripts; in the future, MKTS's TeX formatting commands like
+#   `\cn{}` will be rewritten to make this setting superfluous. ###
+#   advance_each_chr              = options[ 'tex' ]?[ 'advance-each-chr'         ] ? no
+#   tex_command_by_rsgs           = options[ 'tex' ]?[ 'tex-command-by-rsgs'      ]
+#   last_command                  = null
+#   R                             = []
+#   chunk                         = []
+#   last_rsg                      = null
+#   remark                        = if send? then @_get_remark() else null
+#   this_is_cjk                   = no
+#   last_was_cjk                  = no
+#   this_is_whitespace            = no
+#   last_was_whitespace           = no
+#   whitespace_cache              = []
+#   replacement                   = null
+#   has_cjk_glue                  = no
+#   #.........................................................................................................
+#   unless tex_command_by_rsgs?
+#     throw new Error "need setting 'tex-command-by-rsgs'"
+#   #.........................................................................................................
+#   advance_whitespace = =>
+#     chunk.splice chunk.length, 0, whitespace_cache...
+#     debug '©92451', 'advance_whitespace', chunk
+#     whitespace_cache.length = 0
+#   #.........................................................................................................
+#   advance = =>
+#     if chunk.length > 0
+#       # debug '©zDJqU', last_command, JSON.stringify chunk.join '.'
+#       R.push chunk.join ''
+#       R.push "}" unless last_command in [ null, 'latin', 'cn', ]
+#     chunk.length = 0
+#     return null
+#   #.........................................................................................................
+#   for chr in XNCHR.chrs_from_text text
+#     ### Treat whitespace specially ###
+#     if ( this_is_whitespace = chr in [ '\x20', '\n', '\r', '\t', ] )
+#       whitespace_cache.push chr
+#       continue
+#     #.......................................................................................................
+#     { chr
+#       uchr
+#       fncr
+#       rsg   }   = XNCHR.analyze chr
+#     #.......................................................................................................
+#     switch rsg
+#       when 'jzr-fig'  then chr = uchr
+#       when 'u-pua'    then rsg = 'jzr-fig'
+#       when 'u-latn'   then chr = @escape_for_tex chr
+#     #.......................................................................................................
+#     this_is_cjk = @is_cjk_rsg rsg, options
+#     if ( not last_was_cjk ) and ( this_is_cjk )
+#       advance_whitespace()
+#       # advance()
+#       chunk.push "{\\cjk{}"
+#       has_cjk_glue = yes
+#     else if ( last_was_cjk ) and ( not this_is_cjk )
+#       chunk.push "}"
+#       has_cjk_glue = yes # implicitly true
+#       advance_whitespace()
+#     else if whitespace_cache.length > 0
+#       advance_whitespace()
+#     last_was_cjk = this_is_cjk
+#     #.......................................................................................................
+#     ### TAINT if chr is a TeX active ASCII chr like `$`, `#`, then it will be escaped at this point
+#     and no more match entries in `glyph_styles` ###
+#     # debug '©53938-1', chr, rsg, tex_command_by_rsgs[ rsg ]
+#     if ( replacement = glyph_styles[ chr ] )?
+#       # debug '©44340', rpr chr
+#       # debug '©44340', chunk
+#       advance()
+#       ### TAINT duplication from below: ###
+#       command   = tex_command_by_rsgs[ rsg ] ? null
+#       rpl       = []
+#       # rpl.push '\\cjkgGlue' unless has_cjk_glue
+#       rpl.push '{'
+#       rpl_push  = replacement[ 'push'   ] ? null
+#       rpl_raise = replacement[ 'raise'  ] ? null
+#       rpl_chr   = replacement[ 'glyph'  ] ? chr
+#       rpl_cmd   = replacement[ 'cmd'    ] ? command
+#       rpl_cmd   = null if rpl_cmd is 'cn'
+#       if      rpl_push? and rpl_raise?  then rpl.push "\\tfPushRaise{#{rpl_push}}{#{rpl_raise}}"
+#       else if rpl_push?                 then rpl.push "\\tfPush{#{rpl_push}}"
+#       else if               rpl_raise?  then rpl.push "\\tfRaise{#{rpl_raise}}"
+#       if rpl_cmd?                       then rpl.push "\\#{rpl_cmd}{}"
+#       rpl.push rpl_chr
+#       R.push rpl.join ''
+#       has_cjk_glue  = yes
+#       last_command  = null
+#       continue
+#     #.......................................................................................................
+#     else
+#       has_cjk_glue = no
+#     #.......................................................................................................
+#     unless ( command = tex_command_by_rsgs[ rsg ] )?
+#       command = tex_command_by_rsgs[ 'fallback' ] ? null
+#       message = "unknown RSG #{rpr rsg}: #{fncr} #{chr} (using fallback #{rpr command})"
+#       if send? then send remark 'warn', message, {}
+#       else          warn message
+#     #.......................................................................................................
+#     unless command?
+#       advance()
+#       chunk.push chr
+#       continue
+#     #.......................................................................................................
+#     # debug '©53938-2', chr, rsg, tex_command_by_rsgs[ rsg ]
+#     debug '©46011', ( rpr chr ), command, R
+#     if advance_each_chr or last_command isnt command
+#       advance()
+#       last_command = command
+#       ### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ###
+#       unless command in [ 'latin', 'cn', ]
+#         chunk.push "{\\#{command}{}"
+#       ### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ###
+#     #.......................................................................................................
+#     chunk.push chr
+#   #.........................................................................................................
+#   advance_whitespace() if whitespace_cache.length > 0
+#   chunk.push "}" if this_is_cjk
+#     # if has_cjk_glue then  chunk.push "}"
+#     # else                  chunk.push "\\cjkgGlue}"
+#   advance()
+#   return R.join ''
+
+#-----------------------------------------------------------------------------------------------------------
+@_analyze_chr = ( S, chr ) ->
+    #.......................................................................................................
+    R = XNCHR.analyze chr
+    #.......................................................................................................
+    switch R.rsg
+      when 'jzr-fig'  then R.chr = R.uchr
+      when 'u-pua'    then R.rsg = 'jzr-fig'
+      when 'u-latn'   then R.chr = @escape_for_tex chr
+    #.......................................................................................................
+    ### OBS `chr` has still the value this method was called with, so styling should work even for `u-latn`
+    characters ###
+    R.styled_chr    = @_style_chr S, R.rsg, chr
+    R.is_cjk        = R.rsg in S.cjk_rsgs
+    R.is_whitespace = chr   in S.whitespace
+    return R
+
+#-----------------------------------------------------------------------------------------------------------
+@_style_chr = ( S, rsg, chr ) ->
+  rsg_command         = S.tex_command_by_rsgs[ rsg ]
+  rsg_command         = null if rsg_command in [ 'latin', 'cn', ]
+  style               = S.glyph_styles[ chr ]
+  #.........................................................................................................
+  return null if ( not rsg_command? ) and ( not style? )
+  #.........................................................................................................
+  if style?
+    R         = []
+    R.push "\\cjkgGlue{"
+    rpl_push  = style[ 'push'   ] ? null
+    rpl_raise = style[ 'raise'  ] ? null
+    rpl_chr   = style[ 'glyph'  ] ? chr
+    rpl_cmd   = style[ 'cmd'    ] ? rsg_command
+    rpl_cmd   = null if rpl_cmd is 'cn'
+    if      rpl_push? and rpl_raise?  then R.push "\\tfPushRaise{#{rpl_push}}{#{rpl_raise}}"
+    else if rpl_push?                 then R.push "\\tfPush{#{rpl_push}}"
+    else if               rpl_raise?  then R.push "\\tfRaise{#{rpl_raise}}"
+    if rpl_cmd?                       then R.push "\\#{rpl_cmd}{}"
+    R.push rpl_chr
+    R.push "\\cjkgGlue}"
+    R = R.join ''
+  #.........................................................................................................
+  else
+    ### TAINT does not collect glyphs with same RSG ###
+    ### TAINT glue necessary? ###
+    R = "{\\#{rsg_command}{}#{chr}}"
+    # return "\\cjkgGlue{\\#{rsg_command}#{chr}\\cjkgGlue}"
+    # if S.last_rsg_command is rsg_command
+    #   R = chr
+    # else
+    #   if S.last_rsg_command?
+    #     R = "}{\\#{rsg_command}{}#{chr}}"
+    # else
+    #   R = chr
+  #.........................................................................................................
+  S.last_rsg_command = rsg_command
+  return R
+
+#-----------------------------------------------------------------------------------------------------------
+@_move_whitespace = ( S ) ->
+  S.collector.splice S.collector.length, 0, S.ws_collector...
+  S.ws_collector.length = 0
+  return null
+
+#-----------------------------------------------------------------------------------------------------------
+@_push = ( S, chr, postpone_ws = no ) ->
+  @_move_whitespace S unless postpone_ws
+  S.collector.push chr if chr?
+  @_move_whitespace S if     postpone_ws
+  return null
+
+#-----------------------------------------------------------------------------------------------------------
+@_push_whitespace = ( S, chr ) ->
+  S.ws_collector.push chr
+  return null
+
 #-----------------------------------------------------------------------------------------------------------
 @fix_typography_for_tex = ( text, options, send = null ) =>
-  ### An improved version of `XELATEX.tag_from_chr` ###
-  ### TAINT should accept settings, fall back to `require`d `options.coffee` ###
-  glyph_styles                  = options[ 'tex' ]?[ 'glyph-styles'             ] ? {}
-  ### Legacy mode: force one command per non-latin character. This is OK for Chinese texts,
-  but a bad idea for all other scripts; in the future, MKTS's TeX formatting commands like
-  `\cn{}` will be rewritten to make this setting superfluous. ###
-  advance_each_chr              = options[ 'tex' ]?[ 'advance-each-chr'         ] ? no
-  tex_command_by_rsgs           = options[ 'tex' ]?[ 'tex-command-by-rsgs'      ]
-  last_command                  = null
-  R                             = []
-  chunk                         = []
-  last_rsg                      = null
-  remark                        = if send? then @_get_remark() else null
-  this_is_cjk                   = no
-  last_was_cjk                  = no
-  this_is_whitespace            = no
-  last_was_whitespace           = no
-  whitespace_cache              = []
-  replacement                   = null
-  has_cjk_glue                  = no
-  #.........................................................................................................
-  unless tex_command_by_rsgs?
-    throw new Error "need setting 'tex-command-by-rsgs'"
-  #.........................................................................................................
-  advance_whitespace = =>
-    chunk.splice chunk.length, 0, whitespace_cache...
-    debug '©92451', 'advance_whitespace', chunk
-    whitespace_cache.length = 0
-  #.........................................................................................................
-  advance = =>
-    if chunk.length > 0
-      # debug '©zDJqU', last_command, JSON.stringify chunk.join '.'
-      R.push chunk.join ''
-      R.push "}" unless last_command in [ null, 'latin', 'cn', ]
-    chunk.length = 0
-    return null
-  #.........................................................................................................
-  for chr in XNCHR.chrs_from_text text
-    ### Treat whitespace specially ###
-    if ( this_is_whitespace = chr in [ '\x20', '\n', '\r', '\t', ] )
-      whitespace_cache.push chr
-      continue
-    #.......................................................................................................
-    { chr
-      uchr
-      fncr
-      rsg   }   = XNCHR.analyze chr
-    #.......................................................................................................
-    switch rsg
-      when 'jzr-fig'  then chr = uchr
-      when 'u-pua'    then rsg = 'jzr-fig'
-      when 'u-latn'   then chr = @escape_for_tex chr
-    #.......................................................................................................
-    this_is_cjk = @is_cjk_rsg rsg, options
-    debug '©24032', ( rpr chr ), this_is_cjk
-    if ( not last_was_cjk ) and ( this_is_cjk )
-      debug '©1', 'advance_whitespace'
-      advance_whitespace()
-      # advance()
-      chunk.push "\\cjkgGlue{\\cjk{}"
-      has_cjk_glue = yes
-    else if ( last_was_cjk ) and ( not this_is_cjk )
-      if has_cjk_glue then  chunk.push "}"
-      else                  chunk.push "\\cjkgGlue}"
-      has_cjk_glue = yes
-      debug '©2', 'advance_whitespace', rpr chr
-      advance_whitespace()
-    else if whitespace_cache.length > 0
-      debug '©3', 'advance_whitespace'
-      advance_whitespace()
-    last_was_cjk = this_is_cjk
-    #.......................................................................................................
-    ### TAINT if chr is a TeX active ASCII chr like `$`, `#`, then it will be escaped at this point
-    and no more match entries in `glyph_styles` ###
-    # debug '©53938-1', chr, rsg, tex_command_by_rsgs[ rsg ]
-    if ( replacement = glyph_styles[ chr ] )?
-      # debug '©44340', rpr chr
-      # debug '©44340', chunk
-      advance()
-      ### TAINT duplication from below: ###
-      command   = tex_command_by_rsgs[ rsg ] ? null
-      rpl       = []
-      rpl.push '\\cjkgGlue' unless has_cjk_glue
-      rpl.push '{'
-      rpl_push  = replacement[ 'push'   ] ? null
-      rpl_raise = replacement[ 'raise'  ] ? null
-      rpl_chr   = replacement[ 'glyph'  ] ? chr
-      rpl_cmd   = replacement[ 'cmd'    ] ? command
-      rpl_cmd   = null if rpl_cmd is 'cn'
-      if      rpl_push? and rpl_raise?  then rpl.push "\\tfPushRaise{#{rpl_push}}{#{rpl_raise}}"
-      else if rpl_push?                 then rpl.push "\\tfPush{#{rpl_push}}"
-      else if               rpl_raise?  then rpl.push "\\tfRaise{#{rpl_raise}}"
-      if rpl_cmd?                       then rpl.push "\\#{rpl_cmd}{}"
-      rpl.push rpl_chr
-      rpl.push '\\cjkgGlue}'
-      R.push rpl.join ''
-      has_cjk_glue  = yes
-      last_command  = null
-      continue
-    #.......................................................................................................
-    else
-      has_cjk_glue = no
-    #.......................................................................................................
-    unless ( command = tex_command_by_rsgs[ rsg ] )?
-      command = tex_command_by_rsgs[ 'fallback' ] ? null
-      message = "unknown RSG #{rpr rsg}: #{fncr} #{chr} (using fallback #{rpr command})"
-      if send? then send remark 'warn', message, {}
-      else          warn message
-    #.......................................................................................................
-    unless command?
-      advance()
-      chunk.push chr
-      continue
-    #.......................................................................................................
-    # debug '©53938-2', chr, rsg, tex_command_by_rsgs[ rsg ]
-    debug '©46011', ( rpr chr ), command, R
-    if advance_each_chr or last_command isnt command
-      advance()
-      last_command = command
-      ### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ###
-      unless command in [ 'latin', 'cn', ]
-        chunk.push "{\\#{command}{}"
-      ### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ###
-    #.......................................................................................................
-    chunk.push chr
-  #.........................................................................................................
-  advance_whitespace() if whitespace_cache.length > 0
-  if this_is_cjk
-    if has_cjk_glue then  chunk.push "}"
-    else                  chunk.push "\\cjkgGlue}"
-  advance()
-  return R.join ''
-
-#-----------------------------------------------------------------------------------------------------------
-@_test_whitespace = ( S, chr ) -> chr in S.whitespace
-
-#-----------------------------------------------------------------------------------------------------------
-@_analyze_chr = ( S, chr ) ->
-    #.......................................................................................................
-    R = XNCHR.analyze chr
-    #.......................................................................................................
-    switch R.rsg
-      when 'jzr-fig'  then chr = uchr
-      when 'u-pua'    then rsg = 'jzr-fig'
-      when 'u-latn'   then chr = @escape_for_tex chr
-    #.......................................................................................................
-    R.is_cjk = R.rsg in S.cjk_rsgs
-    return R
-
-#-----------------------------------------------------------------------------------------------------------
-@_style_chr = ( S, chr ) -> S.glyph_styles[ chr ] ? null
-
-#-----------------------------------------------------------------------------------------------------------
-@fix_typography_for_tex_2 = ( text, options, send = null ) =>
-  # last_command                  = null
+  # last_rsg_command                  = null
   # R                             = []
   # chunk                         = []
   # last_rsg                      = null
   # remark                        = if send? then @_get_remark() else null
-  # this_is_cjk                   = no
-  # last_was_cjk                  = no
   # this_is_whitespace            = no
   # last_was_whitespace           = no
   # whitespace_cache              = []
@@ -246,29 +294,48 @@
     cjk_rsgs:                     options[ 'tex' ]?[ 'cjk-rsgs' ] ? null
     glyph_styles:                 options[ 'tex' ]?[ 'glyph-styles'             ] ? {}
     tex_command_by_rsgs:          options[ 'tex' ]?[ 'tex-command-by-rsgs'      ]
+    ws_collector:                 []
     collector:                    []
     whitespace:                   '\x20\n\r\t'
+    this_is_cjk:                  no
+    last_was_cjk:                 no
+    last_rsg_command:             null
     R:                            null
   #.........................................................................................................
   throw new Error "need setting 'tex-command-by-rsgs'" unless S.tex_command_by_rsgs?
   throw new Error "need setting 'cjk-rsgs'" unless S.cjk_rsgs?
   #.........................................................................................................
   for chr in XNCHR.chrs_from_text text
-    debug '©84762', rpr chr
-    #.......................................................................................................
-    if this_is_whitespace = @_test_whitespace S, chr
-      null
-    #.......................................................................................................
     A = @_analyze_chr S, chr
-    unless ( chr_style = @_style_chr S, chr )?
-      chr = @escape_for_tex chr
-    #.......................................................................................................
+    #.......................................................................................................
+    ### Whitespace is ambiguous; it is treated as CJK when coming between two unambiguous CJK characters and
+    as non-CJK otherwise; to decide between these cases, we have to wait for the next non-whitespace
+    character: ###
+    if A.is_whitespace
+      @_push_whitespace S, chr
+      continue
+    #.......................................................................................................
+    S.last_was_cjk  = S.this_is_cjk
+    S.this_is_cjk   = A.is_cjk
+    #.......................................................................................................
+    ### In case we're entering a region of CJK characters, we have to start a group and issue a `\cjk`
+    command; before we do that, any cached whitespace will be moved into the result. If we're leaving a
+    CJK region, the group must be closed first and followed by any cached whitespace: ###
+    if ( not S.last_was_cjk ) and ( S.this_is_cjk )
+      @_push S, "{\\cjk{}"
+    else if ( S.last_was_cjk ) and ( not S.this_is_cjk )
+      @_push S, "}", yes
+    #.......................................................................................................
+    if A.styled_chr?
+      # @_push "\\cjkGlue" if S.this_is_cjk
+      @_push S, A.styled_chr
     else
-      null
-    debug '©78697', chr_style if chr_style?
-    #.......................................................................................................
-    S.collector.push chr
-  #.........................................................................................................
+      @_push S, A.chr
+  #.........................................................................................................
+  ### TAINT here we should keep state across text chunks to decide on cases like
+  `國 **b** 國` vs `國 **國** 國` ###
+  @_push S
+  @_push S, '}' if S.this_is_cjk
   return S.collector.join ''


Return result of element filter.

Return result of element filter.

--- create-input.coffee
+++ create-input.coffee
@@ -53,5 +53,6 @@
   field = extend_field_type field
   e = (INPUTCONSTRUCTORS[field.type] || create_text_input) field
   if f = field.filter
-     f field, e
-  e
+    f field, e
+  else
+    e


Use findChildIndexOfNode helper

Use findChildIndexOfNode helper

--- src/trix/models/location_mapper.coffee
+++ src/trix/models/location_mapper.coffee
@@ -52,7 +52,8 @@

     else
       container = node.parentNode
-      offset = [node.parentNode.childNodes...].indexOf(node) + (if location.offset is 0 then 0 else 1)
+      offset = findChildIndexOfNode(node)
+      offset++ unless location.offset is 0

     [container, offset]


Remove username field

Remove username field

--- assets/javascripts/models.js.coffee
+++ assets/javascripts/models.js.coffee
@@ -1,5 +1,4 @@
 App.User = DS.Model.extend
-  username: DS.attr("string")
   firstName: DS.attr("string")
   lastName: DS.attr("string")


Cosmetic changes to payment method list items.

--- client/app/Applications/Account.kdapplication/account/accSettingsPaymentMethods.coffee
+++ client/app/Applications/Account.kdapplication/account/accSettingsPaymentMethods.coffee
@@ -113,7 +113,7 @@
             type         : res.cardType
             cardNumber   : res.cardNumber
             cardExpiry   : res.cardMonth + '/' + res.cardYear
-            cardAddress  : res.address1 + '
' + res.address2
+            cardAddress  : res.address1 + ' ' + res.address2
             cardCity     : res.city
             cardState    : res.state
             cardZip      : res.zip
@@ -287,7 +287,7 @@
   partial:(data)->
     """

-
#{data.type}

+
#{data.title} - #{data.type}

#{data.cardNumber} - #{data.cardExpiry}

           #{data.cardAddress}


Add new query parameter parsing

Add new query parameter parsing

--- coffee/collection.coffee
+++ coffee/collection.coffee
@@ -18,10 +18,13 @@

 exports.get = (req, res, next) ->
   query = {}
+  query.endret = {$gte:req.query.after} if req.query.after
+
   fields = {navn: true}
+
   options =
-    limit: req.query.limit or 20
-    skip: req.query.skip or 0
+    limit: Math.min((parseInt(req.query.limit) or 20), 100)
+    skip: parseInt(req.query.skip) or 0
     sort: 'endret'

   req.col.find(query, fields, options).toArray (err, docs) ->


Added getTracksId which returns an array of ids.

--- app/lib/soundcloud.coffee
+++ app/lib/soundcloud.coffee
@@ -23,4 +23,13 @@
         console.log("Got an error: ", e)
     )

+    getTracksId: ( trackID ) ->
+      response = jetJSON(trackID)
+      trackArray = []
+      for i in resp.collection.length
+        trackArray.push(response.collection[i].user_id)
+      return trackArray
+
+
+
 }


Update zh-HANS.coffee

Update zh-HANS.coffee

Some words about "Ambassador" have been translated. :D

--- app/locale/zh-HANS.coffee
+++ app/locale/zh-HANS.coffee
@@ -469,9 +469,9 @@
     more_about_diplomat: "了解成为外交官的方法"
     diplomat_subscribe_desc: "接受有关国际化开发和翻译情况的邮件"
     ambassador_summary: "我们要建立一个社区，而当社区遇到麻烦的时候，就要支持人员出场了。我们运用 IRC、电邮、社交网站等多种平台帮助玩家熟悉游戏。如果你想帮人们参与进来，学习编程，然后玩的开心，那这个职业属于你。"
-#    ambassador_introduction: "This is a community we're building, and you are the connections. We've got Olark chats, emails, and social networks with lots of people to talk with and help get acquainted with the game and learn from. If you want to help people get involved and have fun, and get a good feel of the pulse of CodeCombat and where we're going, then this class might be for you."
-#    ambassador_attribute_1: "Communication skills. Be able to identify the problems players are having and help them solve them. Also, keep the rest of us informed about what players are saying, what they like and don't like and want more of!"
-#    ambassador_join_desc: "tell us a little about yourself, what you've done and what you'd be interested in doing. We'll go from there!"
+    ambassador_introduction: "这是一个正在成长的社区，而你将成为我们与世界的联结点。大家可以通过Olark即时聊天、邮件、参与者众多的社交网络来认识了解讨论我们的游戏。如果你想帮助大家尽早参与进来、获得乐趣、感受CodeCombat的脉搏、与我们同行，那么这将是一个适合你的职业。"
+    ambassador_attribute_1: "有出色的沟通能力。能够辨识出玩家遇到的问题并帮助他们解决这些问题。与此同时，和我们保持联系，及时反馈玩家的喜恶和愿望！"
+    ambassador_join_desc: "介绍一下你自己：你做过什么？你喜欢做什么？我们将从这里开始了解你！"
 #    ambassador_join_note_strong: "Note"
 #    ambassador_join_note_desc: "One of our top priorities is to build multiplayer where players having difficulty solving levels can summon higher level wizards to help them. This will be a great way for ambassadors to do their thing. We'll keep you posted!"
     more_about_ambassador: "了解成为使节的方法"


eh just find some typos

eh just find some typos

--- app/locale/zh-HANT.coffee
+++ app/locale/zh-HANT.coffee
@@ -1078,7 +1078,7 @@
     tournament_blurb: "寫下程式碼, 收集金幣, 建立軍隊, 粉碎敵人, 贏得獎項,在我們價值$40,000的Greed錦標賽中升級您的職業! 查看"
     tournament_blurb_criss_cross: "贏得競賽, 建造道路, 智勝對手, 收集寶石, 在我們的Criss-Crossand錦標賽中升級您的職業! 查看"
     tournament_blurb_zero_sum: "在紅方法師和藍方法師的山峰對決中，同時在收集金幣和戰術上發揮你的代碼創造力。競賽在3月27日開始，在4月6日（星期一）的下午5點（PDT太平洋時區）結束。為樂趣和榮耀競賽吧！瀏覽了解更多"
-    tournament_blurb_ace_of_coders: "我的主場我主宰，在天寒地凍的冰山上來自己鏡像大戰一場吧！本次比賽將由9月16日星期三開辦到10月14日下午5點PDT。詳情請查看"
+    tournament_blurb_ace_of_coders: "我的主場我主宰，在寒天雪地的冰原上和自己鏡像大戰一場吧！本次比賽將由9月16日星期三開辦到10月14日下午5點PDT。詳情請查看"
     tournament_blurb_blog: "我們的部落格"
     rules: "規則"
     winners: "贏家"


Update domready.js.coffee

Update domready.js.coffee

- Add Accordion behavior
- Add Input Select behavior
- Add comment headings
- Improve developer notes

--- app/assets/javascripts/domready.js.coffee
+++ app/assets/javascripts/domready.js.coffee
@@ -5,19 +5,50 @@
 #    requested via Turbolinks
 #-------------------------------------

-# TODO: Modularize clickout behavior
 jQuery ($) ->

   domready = ->

-    # Event listeners
+    #---------------------------------
+    #
+    #  Dropdown
+    #  -> Contextual menus
+    #
+    #---------------------------------
+
     $('.js-dropdown-btn').on 'click', (e) ->
-      e.stopPropagation()
+      e.stopPropagation() # NOTE: Needed to prevent trigger click event on document
       $(@).closest('.js-dropdown').toggleClass('is-active')

+    # TODO: Modularize clickout behavior
     $(document).on 'click', ->
       $('.js-dropdown').removeClass('is-active')

+    #---------------------------------
+    #
+    #  Accordion
+    #  -> Collapsable container
+    #
+    #---------------------------------
+
+    # Collapse accordion content on DOM Ready
+    $('.js-accordion-content').hide()
+
+    $('.js-accordion-btn').on 'click', (e) ->
+      console.log 'hello'
+      $(@).closest('.js-accordion').find('.js-accordion-content').slideToggle()
+
+    #---------------------------------
+    #
+    #  Input Select
+    #  -> Automatically select input text
+    #
+    #---------------------------------
+
+    $('.js-input-select').on 'click', ->
+      $(@).focus().select()
+
   # Bind behavior to document load/reload
+  # NOTE: Needed for Turbolinks compatibility
   $(document).ready domready
   $(document).on 'page:load', domready


Disable Label update when no issues are selected

--- app/assets/javascripts/issuable.js.coffee
+++ app/assets/javascripts/issuable.js.coffee
@@ -68,12 +68,15 @@
     Turbolinks.visit(issuesUrl);

   initChecks: ->
+    @issuableBulkActions = $('.bulk-update').data('bulkActions')
+
     $('.check_all_issues').off('click').on('click', ->
       $('.selected_issue').prop('checked', @checked)
       Issuable.checkChanged()
     )

-    $('.selected_issue').off('change').on('change', Issuable.checkChanged)
+    $('.selected_issue').off('change').on('change', Issuable.checkChanged.bind(@))
+

   checkChanged: ->
     checked_issues = $('.selected_issue:checked')
@@ -88,3 +91,6 @@
       $('#update_issues_ids').val []
       $('.issues_bulk_update').hide()
       $('.issues-other-filters').show()
+      @issuableBulkActions.disableWillUpdate()
+
+    return true


remove deprecation warning for momentjs

remove deprecation warning for momentjs

--- app/assets/javascripts/moment_init.coffee
+++ app/assets/javascripts/moment_init.coffee
@@ -1,5 +1,5 @@
 window.initMoment = ->
-  moment.lang I18n.locale,
+  moment.locale I18n.locale,
     months: I18n.t('date.dp_month_names')
     monthsShort: I18n.t('date.dp_abbr_month_names')
     weekdays: I18n.t('date.day_names')


Don’t always return decals dr2, part deux

--- app/models/subject.coffee
+++ app/models/subject.coffee
@@ -81,7 +81,6 @@
   # stop working until a user of the app informs the developer and the developer then has time to fix the error.
   # For iPhone apps there will also be a delay until the updated App is approved.
   @randomSurveyId: ->
-    return @::surveys.decals_dr2.id
     n = Math.random()
     if n <= (1/3)
       @::surveys.decals_dr2.id


Highlight current nav item with some jQuery

Signed-off-by: Max Fierke <0706025b2bbcec1ed8d64822f4eccd96314938d0@maxfierke.com>

--- app/assets/javascripts/projects.js.coffee
+++ app/assets/javascripts/projects.js.coffee
@@ -5,6 +5,10 @@
 jQuery ($) ->
   "use strict"
   resumis =
+    selectors:
+      nav:
+        active: "active"
+        current: ".nav li:has(a[href=\"" + window.location.pathname + "\"])"
     populateLatestProject: ->
       $lp = $("#latest-project")
       if $lp.length > 0
@@ -13,6 +17,8 @@
           $lp.find(".project-title a").text(proj.name).prop "href", "/projects/#project_" + proj.id
           $lp.find(".project-shortdesc").text proj.short_description
     init: ->
+      # Highlight current nav item
+      $(resumis.selectors.nav.current).addClass "active"
       resumis.populateLatestProject()

   resumis.init()


opinion loader style adjusted

opinion loader style adjusted

--- client/app/CommonViews/opinions/opinionviewheader.coffee
+++ client/app/CommonViews/opinions/opinionviewheader.coffee
@@ -53,7 +53,7 @@
     @loader = new KDLoaderView
       cssClass      : "opinion-loader hidden"
       size          :
-        width       : 18
+        width       : 20
       loaderOptions :
         color       : "#FD7E09"
         shape       : "spiral"


SidebarMachineBox: Removed deprecated comment block.

--- client/app/lib/activity/sidebar/sidebarmachinebox.coffee
+++ client/app/lib/activity/sidebar/sidebarmachinebox.coffee
@@ -196,10 +196,3 @@
       @machine.status.state = state # FIXME: why it is not setting the state itself?

       switch state
-        when Stopping then @deselect()
-        # it was selecting koding-vm-0 my workspace if koding-vm-1 is
-        # turned off and navigated to /IDE/koding-vm-1/my-workspace
-        # when Running
-        #   { frontApp } = kd.singletons.appManager
-        #   if frontApp instanceof IDEAppController
-        #     @selectWorkspace frontApp.workspaceData.slug


Bugfix (cherry pick to 0.3) — reliance on function.length is incorrect because of ES5 default parameters.

--- packages/redux-components/src/subtree.coffee
+++ packages/redux-components/src/subtree.coffee
@@ -65,11 +65,8 @@
 		component.getSubtree = (-> descriptor)
 		component
 	else if typeof(descriptor) is 'function'
-		if descriptor.length > 0 # this is a raw reducer
-			component = new ReducerNonce()
-			component.getReducer = (-> descriptor)
-			component
-		else # this is a function which will produce a descriptor
-			throw new Error("pure reducer: descriptor function should be a reducer (must have at least one argument)")
+		component = new ReducerNonce()
+		component.getReducer = (-> descriptor)
+		component
 	else
 		throw new Error("invalid component descriptor")


history opts

history opts

--- packages/tower-command/server/console.coffee
+++ packages/tower-command/server/console.coffee
@@ -10,6 +10,9 @@
       .option('-e, --environment [value]')
       .option('-j, --javascript')
       .option('-s --synchronous')
+      # @todo so you can login to your heroku console or whatever without having to do it separately:
+      #   tower console -s -r heroku
+      .option('-r --remote')
       .option '-h, --help', '''
 \ \ Usage:
 \ \   tower console [options]
@@ -180,20 +183,22 @@

       backlog = ''

-      historyWriteStream.write(code.trim() + '\n')
-
       Fiber(->
         try
           $_ = global.$_
           _ = Tower._
-          returnValue = CoffeeScript.eval "$_=(#{code}\n)", {
+          returnValue = CoffeeScript.eval "$_ = __ = (#{code}\n)", {
             filename: 'repl'
             modulename: 'repl'
           }
           if returnValue is undefined
-            global.$_ = $_
+            global.$_ = global.__ = $_
           process.stdout.write inspect(returnValue, no, 2, enableColours)
           pressEnter()
+          # write history only if it's been successful
+          code = code.trim()
+          if repl.history[repl.history.length - 1] != code
+            historyWriteStream.write(code + '\n')
         catch err
           error err
       ).run()


WIP: Fixed a bunch of bugs in conversion script

--- platform/tools/convert_from_directory.coffee
+++ platform/tools/convert_from_directory.coffee
@@ -1,7 +1,6 @@
 #!/usr/bin/env coffee

-OUTPUT_VERSION = 0.1
-
+# IMPORTS
 escodegen = require("escodegen")
 esprima = require("esprima")
 fs = require("fs.extra")
@@ -9,6 +8,36 @@
 util = require("util")

+# CONSTANTS
+OUTPUT_VERSION = 0.1
+
+# 2-space indent
+CODE_GENERATION_OPTIONS =
+  indent: "  "
+
+
+# FUNCTIONS
+toJson = (obj) -> JSON.stringify(obj, null, 2)
+
+parsedToObj = (parsed) ->
+  switch parsed.type
+    when "Literal"
+      return parsed.value
+    when "ObjectExpression"
+      obj = {}
+      for property in parsed.properties
+        propertyName = property.key.name || property.key.value
+        obj[propertyName] = parsedToObj(property.value)
+      return obj
+    when "FunctionExpression"
+      # Don't include the upper-level BlockStatement
+      return (escodegen.generate(body, CODE_GENERATION_OPTIONS) for body in parsed.body.body).join("\n")
+    else
+      util.error("How do I handle parsed type #{parsed.type}?")
+      process.exit(2)
+
+
+# MAIN
 if process.argv.length < 4
   util.error("Usage: coffee convert_from_directory.coffee <input_dir> <output_dir>")
   process.exit(1)
@@ -28,32 +57,17 @@
   version: OUTPUT_VERSION

 # Actions are a JS file that needs to be parsed
-# TODO: literals such as objects or strings should be returned as such, without string quoiting
-# TODO: functions should be returned without the braces
-# TODO: quoted action names such as "if" are returned as undefined
-parsedActions = esprima.parse(fs.readFileSync(path.join(inputDir, "/actions.js"), { encoding: "utf8" }))
-for action in parsedActions.body[0].expression.properties
-  actionName = action.key.name
-  outputObj.actions[actionName] = {}
-  for property in action.value.properties
-    propertyName = property.key.name || propery.key.value
-    switch property.value.type
-      when "ObjectExpression", "Literal"
-        outputObj.actions[actionName][propertyName] = escodegen.generate(property.value)
-      when "FunctionExpression"
-        outputObj.actions[actionName][propertyName] = escodegen.generate(property.value.body)
-      else
-        util.error("Action #{actionName} has unrecognized type #{property.value.type}")
-        process.exit(2)
+parsedActions = esprima.parse(fs.readFileSync(path.join(inputDir, "actions.js"), { encoding: "utf8" }))
+outputObj.actions = parsedToObj(parsedActions.body[0].expression)

 # Copy over layout JSON
-outputObj.layout = JSON.parse(fs.readFileSync(path.join(inputDir, "/layout.json"), { encoding: "utf8" }))
+outputObj.layout = JSON.parse(fs.readFileSync(path.join(inputDir, "layout.json"), { encoding: "utf8" }))

 # Copy over model JSON
-outputObj.model = JSON.parse(fs.readFileSync(path.join(inputDir, "/model.json"), { encoding: "utf8" }))
+outputObj.model = JSON.parse(fs.readFileSync(path.join(inputDir, "model.json"), { encoding: "utf8" }))

 # Copy over asset JSON
-outputObj.assets = JSON.parse(fs.readFileSync(path.join(inputDir, "/assets.json"), { encoding: "utf8" }))
+outputObj.assets = JSON.parse(fs.readFileSync(path.join(inputDir, "assets.json"), { encoding: "utf8" }))

 # TODO: create base64 version of all assets

@@ -67,6 +81,4 @@
       if err?
         util.error("WARNING: Cannot copy #{filename}: #{err}")

-
-# TODO: pretty-print JSON output
-fs.writeFileSync(path.join(outputDir, "/game.json"), JSON.stringify(outputObj))
+fs.writeFileSync(path.join(outputDir, "game.json"), toJson(outputObj))


Remove parenthesis

Remove parenthesis

--- src/ScrollAppear.coffee
+++ src/ScrollAppear.coffee
@@ -13,10 +13,10 @@
       if element.dataset.appearOffset
         @elements.push
           node: element
-          offset: parseInt(element.dataset.appearOffset)
+          offset: parseInt element.dataset.appearOffset
           toggleClass: element.dataset.appearToggleClass || @defaultToggleClass
       else
-        console.warn("Please set a data-appear-offset for #{element.outerHTML}")
+        console.warn "Please set a data-appear-offset for #{element.outerHTML}"

   onScroll: =>
     @lastScrollY = window.scrollY
@@ -33,6 +33,6 @@

   toggleAppearClass: (element) ->
     if window.scrollY >= element.offset
-      element.node.classList.remove(element.toggleClass)
+      element.node.classList.remove element.toggleClass
     else
-      element.node.classList.add(element.toggleClass)
+      element.node.classList.add element.toggleClass


fix daily mail

fix daily mail

--- src-public/daily-report/models/daily-report.coffee
+++ src-public/daily-report/models/daily-report.coffee
@@ -5,8 +5,11 @@

     @getByProject = (project) ->
       @query(
-        equalTo:
-          project: project
+        where:
+          project:
+            __type: "Pointer"
+            className: "Project"
+            objectId: project.objectId
       ).then (response) ->
         if response.length > 0
           return response[0]


removing claimsTable coffee script

removing claimsTable coffee script

--- casa/app/assets/javascripts/claimsTable.coffee
+++ casa/app/assets/javascripts/claimsTable.coffee
@@ -1,123 +0,0 @@
-window.constructClaimsTable = (claimsList, claimsListSize) ->
-
-
-    claimsTable = $('#main').find("table")
-
-    table = $("#claimsTable")
-
-    caption = $('<caption/>')
-    $(caption).append("List of claims")
-
-
-    $(table).append(caption)
-
-    thead = $('<thead/>')
-    trHeader = $('<tr/>')
-    thBlank = $('<th/>')
-    th1 = $('<th/>' )
-    th2 = $('<th/>').attr('class', 'view' )
-    th3 = $('<th/>').attr('class', 'ni' ).append("NI Number")
-    th4 = $('<th/>').attr('class', 'view' ).append("Claim type")
-    th5 = $('<th/>').attr('class', 'view' ).append("Submit Date")
-    th6 = $('<th/>').attr('class', 'view' ).append("Status")
-
-    thIdLink = $('<a/>' ).attr('href','#').attr('id', 'thId').attr('class', 'thId' ).attr('style', 'color:white').append('Transaction Id')
-    thNameLink = $('<a/>' ).attr('href','#').attr('id', 'thNameId').attr('class', 'thName' ).attr('style', 'color:white').append('Name')
-
-    $(thIdLink).on "click", ->
-      sort('thIdLink')
-
-    $(thIdLink).on "hover", ->
-      $(thIdLink).color = '#fff'
-
-    $(thNameLink).on "click", ->
-      sort('thNameLink')
-
-
-    $(th1).append(thIdLink)
-    $(th2).append(thNameLink)
-
-    $(trHeader).append(thBlank).append(th1).append(th2).append(th3).append(th4).append(th5).append(th6)
-
-    $(thead ).append(trHeader)
-
-    table.append(thead)
-
-    tBody = $('<tbody/>')
-
-    tr = []
-    completedCheckboxes = []
-
-    for i in [0..claimsList.length-1] by 1
-      claim = claimsList[i]
-      trId = claim.transactionId
-      trIdRow = "row_"+trId;
-
-      tr[i] = $('<tr/>' ).attr('id', trIdRow)
-
-      td1 = $('<td/>').attr('class', 'transactionId' )
-      td2 = $('<td/>').attr('class', 'name' )
-      td3 = $('<td/>').attr('class', 'ni' )
-      td4 = $('<td/>').attr('class', 'view' )
-      td5 = $('<td/>').attr('class', 'view' )
-      td6 = $('<td/>').attr('class', 'status' )
-
-      trIdHref = "/render/"+trId
-      trIdLink = $('<a/>' ).attr('href', trIdHref ).attr('target',trId)
-
-      $(trIdLink).append( claim.transactionId )
-      $(td1).append( trIdLink )
-      $(td2).append( claim.surname + " " + claim.forename)
-      $(td3).append( claim.nino )
-      $(td4).append( claim.claimType )
-
-      theDate = new Date(claim.claimDateTime)
-
-      $(td5).append( theDate )
-      $(td6).append( claim.status )
-
-
-      tdCheck = $('<td/>')
-
-      labelTrId = $('<label/>')
-      $(labelTrId).attr('for',trId)
-      $(labelTrId).append('Claim')
-
-      inputTrIdCheck = $('<input/>')
-      $(inputTrIdCheck).attr('type','checkbox')
-      inputTrIdCheck.attr('name', completedCheckboxes[i])
-      inputTrIdCheck.attr('id', trId)
-      inputTrIdCheck.attr('value', trId)
-
-      if (claim.status == "viewed")
-        tdCheck.append(labelTrId)
-        tdCheck.append(inputTrIdCheck)
-
-      $(tr[i]).append(tdCheck).append(td1).append(td2).append(td3).append(td4).append(td5).append(td6)
-
-      $(tBody).append(tr[i])
-
-      $(table).append(tBody)
-
-sort = (elem) ->
-    sorted = elem
-    table = $("#claimsTable")
-    rows = table.find('tr:gt(0)').toArray().sort(comparer($(elem).index()))
-    elem.asc = !elem.asc
-    if (!elem.asc)
-      rows = rows.reverse()
-    for i in [0..rows.length] by 1
-      table.append(rows[i])
-
-comparer = (index) ->
-  sortRows = (a,b) ->
-    valA = getCellValue(a, index)
-    valB = getCellValue(b, index)
-    $.isNumeric(valA) && $.isNumeric(valB) ? valA - valB : valA.localeCompare(valB)
-
-getCellValue = (row, index) ->
-  $(row).children('td').eq(index).html()
-
-formatDate = (date) -> date.toLocaleDateString()
-
-


Replace all the links, not just the first one.

--- packages/pixelboy/apps/components/conversation/conversation.coffee
+++ packages/pixelboy/apps/components/conversation/conversation.coffee
@@ -37,7 +37,7 @@
     escapedText = div.innerHTML

     # Replace urls with links.
-    urlRegex = /(https?):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?/
+    urlRegex = /(https?):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?/g

     formattedText = escapedText.replace urlRegex, (url, protocol, domain, path) =>
       urlText = domain


add scope var recording to show appropriate action buttons

--- www/js/controllers/msg.coffee
+++ www/js/controllers/msg.coffee
@@ -74,6 +74,7 @@
 				collection.add msg
 				$ionicScrollDelegate.scrollTop true
 				msg
+			recording: false
 			copy: (msg) ->
 				if env.isNative()
 					$cordovaClipboard.copy(msg.body)
@@ -98,11 +99,13 @@
 				$scope.$apply 'collection.models'
 				$ionicScrollDelegate.scrollTop true

-		recorded = ->
+		audioService.recorder.on 'start', ->
+			$scope.recording = true
+		audioService.recorder.on 'stop', ->
 			$scope.addFile [audioService.recorder.file]
-		audioService.recorder.on 'stop', recorded
+			$scope.recording = false
 		$scope.$on '$destroy', ->
-			audioService.recorder.removeListener 'stop', recorded
+			audioService.recorder.removeAllListeners()

 	.controller 'msgCtrl', ($scope, resource, $cordovaFileOpener2, $http, fileService, $log) ->
 		fs = fileService.fs


more event subscription for tidier disposal

--- lib/code-annotation-manager.coffee
+++ lib/code-annotation-manager.coffee
@@ -276,8 +276,7 @@

         # TODO: what happens if a TextEditor's file is moved into another project (with another code-annotations folder)??
         # when an editor is renamed the data must be associated with the editor's new path
-        # TODO: dispose the handler when deactivating
-        editor.onDidChangePath () =>
+        @subscriptions.add editor.onDidChangePath () =>
             newEditorPath = editor.getPath()
             @initializedEditors[newEditorPath] = @initializedEditors[editorPath]
             @_uninitEditor(editor)
@@ -285,7 +284,7 @@
             editorPath = newEditorPath
             return @

-        editor.onDidDestroy () =>
+        @subscriptions.add editor.onDidDestroy () =>
             @_uninitEditor(editor)
             return @


Add analytics events to Artist Signup CTA

--- src/desktop/components/artist_page_cta/view.coffee
+++ src/desktop/components/artist_page_cta/view.coffee
@@ -39,7 +39,7 @@
     mediator.on 'clickHeaderAuth', @fullScreenOverlay

   maybeShowOverlay: (e) =>
-    @fullScreenOverlay() if @$window.scrollTop() > @desiredScrollPosition and not @alreadyDismissed
+    @fullScreenOverlay(e) if @$window.scrollTop() > @desiredScrollPosition and not @alreadyDismissed

   triggerLoginModal: (e) ->
     e.stopPropagation()
@@ -55,10 +55,12 @@
     qs.parse(location.search.replace(/^\?/, ''))

   fullScreenOverlay: (e) =>
+    contextModule = "Footer" if e.currentTarget.className?.includes("artist-page-cta")
     return if @$el.hasClass 'fullscreen'
     @$overlay.fadeIn 300
     @$banner.fadeOut 300
     fragment = qs.stringify @currentParams()
+    @trackImpression(e.type, contextModule)
     # This handles the redirect for the new onboarding flow
     @afterAuthPath += "?redirectTo=#{@artist.get('href')}"
     @afterAuthPath += "?#{fragment}" if fragment
@@ -91,7 +93,12 @@
     @$el.removeClass 'fullscreen'
     setTimeout (=> @reenableScroll()), 400
     @alreadyDismissed = true
-    analyticsHooks.trigger 'artist_page:cta:hidden'
+    analytics.track("Click", {
+      context_module: "artist page signup prompt",
+      type: "dismiss",
+      flow: "auth",
+      label: "dismiss auth modal",
+    })

   submit: (e) ->
     return unless @validateForm()
@@ -132,3 +139,14 @@

   initializeMailcheck: ->
     Mailcheck.run('#js-mailcheck-input-modal', '#js-mailcheck-hint-modal', false)
+
+  trackImpression:(triggerType, contextModule) ->
+    console.log('artist:', @artist)
+    analytics.track("Auth Impression", {
+      modal_copy: "Join Artsy to discover new works by #{@artist.get('name')} and more artists you love",
+      onboarding: true,
+      trigger: if triggerType == "scroll" then "trigger" else triggerType,
+      type: "signup",
+      intent: "signup",
+      context_module: contextModule
+    })


Update Google Analytics script to reflect location of the user

--- app/assets/javascripts/google-analytics.js.coffee
+++ app/assets/javascripts/google-analytics.js.coffee
@@ -1,5 +1,11 @@
-$(document).on 'page:change', ->
-  if window._gaq?
-    _gaq.push ['_trackPageview']
-  else if window.pageTracker?
-    pageTracker._trackPageview()+if window.history?.pushState and window.history.replaceState
+  document.addEventListener 'page:change', (event) =>
+
+  # Google Analytics
+  if window.ga != undefined
+    ga('set', 'location', location.href.split('#')[0])
+    ga('send', 'pageview', {"title": document.title})
+  else if window._gaq != undefined
+    _gaq.push(['_trackPageview'])
+  else if window.pageTracker != undefined
+    pageTracker._trackPageview();


Small readability refactoring

Small readability refactoring

--- app/assets/javascripts/modules/filter_form.coffee
+++ app/assets/javascripts/modules/filter_form.coffee
@@ -1,96 +1,90 @@
-filterExpand = ->
+initFilterForm = ->
+  filterExpand = ->

-  $filterForm = $('.filter-form')
-  startHeight = $('.col-form-inner:first').find('.radio_buttons').height() * 2.5
-  expandLabel = I18n.t 'js.more_filter_options'
-  collapseLabel = I18n.t 'js.less_filter_options'
-  offer_filter_open = sessionStorage.getItem("offer_filter_open")
+    $filterForm = $('.filter-form')
+    startHeight = $('.col-form-inner:first').find('.radio_buttons').height() * 2.5
+    expandLabel = I18n.t 'js.more_filter_options'
+    collapseLabel = I18n.t 'js.less_filter_options'
+    offer_filter_open = sessionStorage.getItem("offer_filter_open")

-  unless offer_filter_open == "true"
-    $filterForm
-            .addClass 'filter-form--isCollapsed'
-            .height startHeight
-    $('.filter-form__expander').attr 'aria-expanded', true
+    unless offer_filter_open == "true"
+      $filterForm
+              .addClass 'filter-form--isCollapsed'
+              .height startHeight
+      $('.filter-form__expander').attr 'aria-expanded', true

-    sessionStorage.setItem("offer_filter_open", "false")
+      sessionStorage.setItem("offer_filter_open", "false")

-  if !$('.filter-form__expander').length
-    $filterForm.prepend '
' + expandLabel + '
'
+    if !$('.filter-form__expander').length
+      $filterForm.prepend '
' + expandLabel + '
'

-    if offer_filter_open == "true"
-      $('.filter-form__expander')
-        .html collapseLabel
-        .attr 'aria-expanded', true
-
-  $expander = $('.filter-form__expander')
-
-  $expander.on 'click', ->
-
-    if $filterForm.hasClass('filter-form--isCollapsed')
-      $expander
+      if offer_filter_open == "true"
+        $('.filter-form__expander')
           .html collapseLabel
           .attr 'aria-expanded', true

-      $filterForm
-          .css 'height', 'auto'
-          .removeClass 'filter-form--isCollapsed'
+    $expander = $('.filter-form__expander')

-      sessionStorage.setItem("offer_filter_open", "true")
+    $expander.on 'click', ->
+
+      if $filterForm.hasClass('filter-form--isCollapsed')
+        $expander
+            .html collapseLabel
+            .attr 'aria-expanded', true
+
+        $filterForm
+            .css 'height', 'auto'
+            .removeClass 'filter-form--isCollapsed'
+
+        sessionStorage.setItem("offer_filter_open", "true")
+
+      else
+        $expander
+            .html expandLabel
+            .attr 'aria-expanded', false
+
+        $filterForm
+              .css 'height', startHeight
+              .addClass 'filter-form--isCollapsed'
+
+        sessionStorage.setItem("offer_filter_open", "false")
+
+  fieldsetHeadlineClickHandler = ->
+
+    if ($(window).width() <= 440)
+
+      $('.filter-form')
+        .removeClass 'filter-form--isCollapsed'
+        .css 'height', 'auto'
+        .find('.col-form-inner .input').addClass 'is--hidden'
+
+      $('.filter-form').find('.filter-form__fieldset__headline').attr 'aria-collapsed', true
+
+      $('.filter-form__fieldset__headline').on 'click', ->
+
+        that = $(this)
+
+        that.next(".input").toggleClass 'is--hidden'
+
+        if that.attr('aria-collapsed') == 'true'
+          that.attr('aria-collapsed', 'false')
+        else
+          that.attr('aria-collapsed', 'true')

     else
-      $expander
-          .html expandLabel
-          .attr 'aria-expanded', false
+      $('.filter-form')
+        .find('.col-form-inner .input').removeClass 'is--hidden'
+      .find('filter-form__fieldset__headline').attr 'aria-collapsed', 'true'

-      $filterForm
-            .css 'height', startHeight
-            .addClass 'filter-form--isCollapsed'
-
-      sessionStorage.setItem("offer_filter_open", "false")
-
-fieldsetHeadlineClickHandler = ->
-
-  if ($(window).width() <= 440)
-
-    $('.filter-form')
-      .removeClass 'filter-form--isCollapsed'
-      .css 'height', 'auto'
-      .find('.col-form-inner .input').addClass 'is--hidden'
-
-    $('.filter-form').find('.filter-form__fieldset__headline').attr 'aria-collapsed', true
-
-    $('.filter-form__fieldset__headline').on 'click', ->
-
-      that = $(this)
-
-      that.next(".input").toggleClass 'is--hidden'
-
-      if that.attr('aria-collapsed') == 'true'
-        that.attr('aria-collapsed', 'false')
-      else
-        that.attr('aria-collapsed', 'true')
-
-  else
-    $('.filter-form')
-      .find('.col-form-inner .input').removeClass 'is--hidden'
-    .find('filter-form__fieldset__headline').attr 'aria-collapsed', 'true'
-
-
-
-
-$(document).ready ->
   filterExpand()
   fieldsetHeadlineClickHandler()

-$(document).on 'ajax_replaced', ->
-  filterExpand()
-  fieldsetHeadlineClickHandler()

-$(document).on 'page:load', ->
-  filterExpand()
-  fieldsetHeadlineClickHandler()
+$(document).ready -> initFilterForm()

-$(window).on 'resize', ->
-  filterExpand()
-  fieldsetHeadlineClickHandler()
+$(document).on 'ajax_replaced', -> initFilterForm()
+
+$(document).on 'page:load', -> initFilterForm()
+
+$(window).on 'resize', -> initFilterForm()


EDSC-315: force contentHeightChanged after each ajax request

--- app/assets/javascripts/modules/spinners.js.coffee
+++ app/assets/javascripts/modules/spinners.js.coffee
@@ -32,3 +32,4 @@

   $(document).ajaxComplete (event, xhr, settings) ->
     spinner.remove() for spinner in spinners when spinner.matchesRequest(settings)
+    $('.master-overlay').masterOverlay('contentHeightChanged')


fix encoding issue, fixes #31

fix encoding issue, fixes #31

--- app/assets/javascripts/s3_direct_upload.js.coffee
+++ app/assets/javascripts/s3_direct_upload.js.coffee
@@ -70,25 +70,20 @@
           name: "Content-Type"
           value: fileType

-        data[1].value = settings.path + data[1].value
-
+        data[1].value = settings.path + data[1].value #the key
         data

   build_content_object = ($uploadForm, file, result) ->
-    domain = $uploadForm.attr('action')
     content = {}
     if result # Use the S3 response to set the URL to avoid character encodings bugs
-      path             = $('Key', result).text()
-      split_path       = path.split('/')
-      content.url      = domain + path
-      content.filename = split_path[split_path.length - 1]
-      content.filepath = split_path.slice(0, split_path.length - 1).join('/')
-    else # IE8 and IE9 return a null result object so we use the file object instead
-      path             = settings.path + $uploadForm.find('input[name=key]').val().replace('/${filename}', '')
-      content.url      = domain + path + '/' + file.name
-      content.filename = file.name
-      content.filepath = path
+      content.url      = $(result).find("Location").text()
+      content.filepath = $('<a />').attr('href', content.url)[0].pathname
+    else # IE <= 9 return a null result object so we use the file object instead
+      domain           = $uploadForm.attr('action')
+      content.filepath = settings.path + $uploadForm.find('input[name=key]').val().replace('/${filename}', '')
+      content.url      = domain + content.filepath + '/' + file.name

+    content.filename   = file.name
     content.filesize   = file.size if 'size' of file
     content.filetype   = file.type if 'type' of file
     content = $.extend content, settings.additional_data if settings.additional_data


fix buildSettings()

fix buildSettings()

--- app/assets/javascripts/uploadcare/utils.js.coffee
+++ app/assets/javascripts/uploadcare/utils.js.coffee
@@ -71,15 +71,15 @@
       else
         settings[key] = !!settings[key]

+    if settings.multiple
+      settings.crop = 'disabled'
+
     settings.__cropParsed = {
       enabled: true
       scale: false
       upscale: false
       preferedSize: null
     }
-
-    if settings.multiple
-      settings.crop = 'disabled'

     # disabled 300x200 → disabled
     # 300x200 3:2 → 3:2


Build a custom drag helper when sorting personal ranking.

Also attach it to dom.

--- app/assets/javascripts/views/question_page.coffee
+++ app/assets/javascripts/views/question_page.coffee
@@ -84,6 +84,8 @@

     removeItem = null
     @personalVote.sortable(
+      appendTo: 'body'
+      helper: (e, item) -> item.view().buildDragHelper()
       receive: -> removeItem = 0
       over: -> removeItem = 0
       out: -> removeItem = 1


ClampBounds docs

ClampBounds docs

--- src/clamp_bounds.coffee
+++ src/clamp_bounds.coffee
@@ -20,7 +20,7 @@

   # x, y position is based on the center point so
   # the position the player is set to is based on
-  # half thei
+  # half their width and
   player.I.x
   # => 2.5
 </pre></code>


Ensure we whitelist everything we want to get compared.

--- src/coffee/import.coffee
+++ src/coffee/import.coffee
@@ -125,8 +125,13 @@
   update: (product, existingProduct, types, header, rowIndex) ->
     deferred = Q.defer()
     allSameValueAttributes = types.id2SameForAllAttributes[product.productType.id]
-    config = []
-    # TODO: add all groups!
+    config = [
+      { type: 'base', group: 'white' }
+      { type: 'references', group: 'white' }
+      { type: 'attributes', group: 'white' }
+      { type: 'variants', group: 'white' }
+      { type: 'metaAttributes', group: 'white' }
+    ]
     config.push { type: 'prices', group: 'black' } unless header.has(CONS.HEADER_PRICES)
     config.push { type: 'images', group: 'black' } unless header.has(CONS.HEADER_IMAGES)


unclear if this fixed the file drop problem, i have a suspicion the user (manifest) needs to be refreshed

--- apps/channel/client/channel_file_drop_view.coffee
+++ apps/channel/client/channel_file_drop_view.coffee
@@ -12,7 +12,7 @@
     @channel = options.channel
     @blocks = options.blocks

-    @setupFileDrop() if mediator.shared.current_user.has('manifest')
+    @setupFileDrop()

   handleDrag: (e)->
     @$('.channel--drop-zone').addClass('is-droppable')


Add parens so the functions are called

Add parens so the functions are called

--- src/coffee/glide.coffee
+++ src/coffee/glide.coffee
@@ -280,9 +280,9 @@
         when 'touchstart'
           @onTouchStart e
         when 'touchmove'
-          @removePressed
+          @removePressed()
         when 'touchend'
-          @removePressed
+          @removePressed()
     else
       switch e.type
         when 'mousedown'


work to get embed to default to bootstrap or not depending on what is available in page, as well as considering possible config settings that might get delivered later, and possible config settings that might be delivered at startup, and possible in-page css overrides as well... to be continued

--- static/embed/oab_embed.coffee
+++ static/embed/oab_embed.coffee
@@ -204,9 +204,8 @@
   this.data ?= {} # the data obj to send to backend
   this.f ?= {} # the result of the find/ill/permission request to the backend
   this.template ?= _oab[this.plugin + '_template'] # template or css can be passed in or are as defined below
+
   this.css ?= _oab.css
-  this.bootstrap ?= true # if true then bootstrap classes will be added to buttons and form elements
-
   this._loading = false # tracks when loads are occurring
   this.submit_after_metadata = false # used by instantill to track if metadata has been provided by user
   this.file = false # used by syp to store the file for sending to backend
@@ -1047,6 +1046,12 @@
   if this.bootstrap isnt false and this.config.bootstrap is true
     this.bootstrap = false
     build = true
+  if not this.bootstrap? and not this.css
+    # if bootstrap css is already present on the page, and bootstrap value is not set,
+    # and css has not been set either, then use bootstrap
+    _L.append 'body', '

'
+    this.bootstrap = _L.css('#_oab_bootstrap_test', 'height') not in ['','0px']
+    #_L.remove '_#oab_bootstrap_test'
   if build isnt false
     this.element ?= '#' + this.plugin
     _L.remove '#_oab_css'


Fix missing double quote mark

Fix missing double quote mark

--- atom/dot-atom/config.cson
+++ atom/dot-atom/config.cson
@@ -7,7 +7,7 @@
       }
     '''
     startDir: "projectDirOfFile"
-    startupCode: "{\"Python 3\": \"%matplotlib inline\\n%config InlineBackend.figure_format = 'svg'"}"
+    startupCode: "{\"Python 3\": \"%matplotlib inline\\n%config InlineBackend.figure_format = 'svg'\"}"
   "atom-beautify":
     bash:
       beautify_on_save: true


Set doc to null to clean up memmory

Set doc to null to clean up memmory

--- coffee/document.coffee
+++ coffee/document.coffee
@@ -22,7 +22,10 @@
 exports.get = (req, res, next) ->
   req.col.findOne _id: req.id, (err, doc) ->
     return next err if err
-    return res.json 200, doc if doc
+    if doc
+      res.json 200, doc
+      doc = null
+      return
     return res.json 404, error: 'Document Not Found'

 exports.put = (req, res, next) ->


player sprite changes directions

player sprite changes directions

--- coffee/renderer.coffee
+++ coffee/renderer.coffee
@@ -13,11 +13,18 @@
         startRow: 9
         endRow: 9
         endCol: 8
+      'down':
+        startRow: 10
+        endRow: 10
+        endCol: 8
+      'right':
+        startRow: 11
+        endRow: 11
+        endCol: 8
       }, {
         frameW: 64
         frameH: 64
         postInitCallback: =>
-          @spriteMap_.use 'up'
           @spriteMap_.start()
           @loadedAllSprites_ = true
       }
@@ -43,6 +50,8 @@
     x = player.getPos().x - @spriteMap_.sprite.frameW / 2
     y = player.getPos().y - @spriteMap_.sprite.frameH / 2
     if @loadedAllSprites_
+      if @spriteMap_.activeLoop isnt player.getDirection()
+        @spriteMap_.start player.getDirection()
       @spriteMap_.draw atom.context, x, y

   drawEnemies_: ->


Talk link Use penguin watch as a placeholder.

--- project.coffee
+++ project.coffee
@@ -64,6 +64,7 @@
   }]

   externalLinks:
+    Talk: 'http://talk.penguinwatch.org'
     Blog: 'http://blog.zooniverse.org'
     Twitter: 'http://twitter.com/the_zooniverse'


for some reason the HTML contents was not updated

--- src/scripts/helpers/backbone/views/editable.coffee
+++ src/scripts/helpers/backbone/views/editable.coffee
@@ -105,20 +105,15 @@

                     # Update the model if an event for this editable was triggered
                     Aloha.bind 'aloha-smart-content-changed.updatemodel', (evt, d) ->
-                      updateModel() if d.triggerType != 'blur' and \
+                      updateModel(d.editable.getContents()) if d.triggerType != 'blur' and \
                         (d.editable.obj.is($alohaEditable) or $.contains($alohaEditable[0], d.editable.obj[0]))

                 # Update the model by retrieving the XHTML contents
-                updateModel = () =>
-                  alohaId = $editable.attr('id')
-                  alohaEditable = Aloha.getEditableById(alohaId)
-
-                  if alohaEditable
-                    editableBody = alohaEditable.getContents()
-                    editableBody = editableBody.trim() # Trim for idempotence
-                    # Change the contents but do not update the Aloha editable area
-                    @model.set(value, editableBody) # TODO: Should we add a flag to not re-render the editable?
-                    setChanged(options.onEdit)
+                updateModel = (editableBody) =>
+                  editableBody = editableBody.trim() # Trim for idempotence
+                  # Change the contents but do not update the Aloha editable area
+                  @model.set(value, editableBody) # TODO: Should we add a flag to not re-render the editable?
+                  setChanged(options.onEdit)

             # Setup Select2
             when 'select2'