mobile tabs management em

mobile tabs management em

--- app/assets/javascripts/em.js.coffee
+++ app/assets/javascripts/em.js.coffee
@@ -6,8 +6,6 @@
 	]

 	showActive reports
-
-	window.onhashchange = -> showActive reports

 	$('.em-quick-guide').hide()

@@ -26,4 +24,22 @@
 			$('.alert-info h3').text(response.title)
 			$('.alert-info p').text(response.text)
 	)
+
+	mobileSections = [
+		{ href: '#map' },
+		{ href: '#quick-guide' },
+		{ href: '#updates' }
+	]
+
+	showMobileTab = (sections) ->
+		urlHash = window.location.hash || sections[0].href
+		$(urlHash).show()
+		_(_(sections).filter((elem) -> elem.href != urlHash)).each (section) -> $(section.href).hide()
+
+	showMobileTab mobileSections
+
+	window.onhashchange = ->
+		showActive reports
+		showMobileTab mobileSections
+
 )


Made factwheels touch-friendly

Made factwheels touch-friendly

--- app/assets/javascripts/blog_fact_graph.coffee
+++ app/assets/javascripts/blog_fact_graph.coffee
@@ -468,7 +468,8 @@
 class BaseFactWheelView extends Marionette.ItemView
   className: "blog-fact-graph-wheel"
   defaults:
-    showsTooltips: true
+    useHover: !('ontouchstart' of document)
+    showsTooltips: !('ontouchstart' of document)
     showsAuthorityTooltip: true
     radius: 16

@@ -554,8 +555,9 @@
       opacity: opacity

     # Bind Mouse Events on the path
-    path.mouseover _.bind(@mouseoverOpinionType, this, path, opinionType.type)
-    path.mouseout _.bind(@mouseoutOpinionType, this, path, opinionType.type)
+    if @options.useHover
+      path.mouseover _.bind(@mouseoverOpinionType, this, path, opinionType.type)
+      path.mouseout _.bind(@mouseoutOpinionType, this, path, opinionType.type)
     path.click _.bind(@clickOpinionType, this, opinionType.type)

     @opinionTypeRaphaels[opinionType.type] = path


Fixed typo

Fixed typo

--- app/assets/javascripts/blog_fact_graph.coffee
+++ app/assets/javascripts/blog_fact_graph.coffee
@@ -739,7 +739,7 @@
     disbelieve: 1
     doubt: 1
     evidenceBelieve: ->
-      Math.min factWheelZ3.get('believe') - factWheelZ3.get('disbelieve'), factWheelZ3.get('believe') - factWheelZ3.get('disbelieve')
+      Math.min factWheelZ2.get('believe') - factWheelZ2.get('disbelieve'), factWheelZ3.get('believe') - factWheelZ3.get('disbelieve')

   factWheelZ2 = new FactWheelModel
     believe: 5


Fix signup flow for new accounts created via enroll link

--- app/assets/javascripts/components/course.cjsx
+++ app/assets/javascripts/components/course.cjsx
@@ -167,7 +167,7 @@

{I18n.t("courses.invitation", title: @state.course.title)}

                {I18n.t("application.log_in_extended")}
-               {I18n.t("application.sign_up_extended")}
+               {I18n.t("application.sign_up_extended")}

         )


Update editor.js.coffee

Update editor.js.coffee

Add whitelist exceptions for ICE track changes classes.

--- app/assets/javascripts/dante/editor.js.coffee
+++ app/assets/javascripts/dante/editor.js.coffee
@@ -1025,7 +1025,7 @@
         a: { href: ['http', 'https', 'mailto'] }

       transformers: [(input)->
-                      if (input.node_name == "span" && $(input.node).hasClass("defaultValue") )
+                      if (input.node_name == "span" && ($(input.node).hasClass("defaultValue") || $(input.node).hasClass("del") $(input.node).hasClass("add")) )
                         return whitelist_nodes: [input.node]
                       else
                         return null


remove alert

remove alert

--- app/assets/javascripts/users_gather.js.coffee
+++ app/assets/javascripts/users_gather.js.coffee
@@ -1,5 +1,4 @@
 $(".users.gather").ready ->
-	alert "I should only show in info page!"

 	showMsg = (msg) ->
 		$('#main-content').empty()


Don't assign to choice object itself

Don't assign to choice object itself

--- app/partials/field-guide-choice.cjsx
+++ app/partials/field-guide-choice.cjsx
@@ -21,10 +21,10 @@

     task = @props.workflow.tasks[@props.workflow.first_task]
     task.images = _.mapKeys task.images, (value, key) -> key.toLowerCase()
-    choice = task.choices[key]
+    sourceChoice = task.choices[key]

-    if localChoice && choice
-      Object.assign choice, localChoice
+    if localChoice && sourceChoice
+      choice = Object.assign {}, sourceChoice, localChoice
     else
       return


Ui: global event popover behaviours

Ui: global event popover behaviours

This commit make popover behaviours (close on ESC, validate on ENTER)
global, so it works whatever the user focus is inside the popover
(even on footer buttons).

--- client/app/views/calendar_popover_event.coffee
+++ client/app/views/calendar_popover_event.coffee
@@ -31,7 +31,7 @@

     events:
-        'keyup input':                           'onKeyUp'
+        'keyup':                                 'onKeyUp'
         'change select':                         'onKeyUp'
         'change input':                          'onKeyUp'

@@ -138,7 +138,7 @@
     # Loop over controls elements w/o exiting the popover scope
     onTab: (ev) =>
         # Early return if the key pressed isn't `tab` (keyCode == 9)
-        return unless ev.keyCode == 9
+        return unless ev.keyCode is 9
         # Find if the element has an explicit next/prev control, and if it fits
         # w/ loop direction (forward/backward over controls)
         $this = $(ev.target)


work from home

work from home

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -118,10 +118,9 @@
       '/:name?/Apps'      : ({name})-> go 'Apps'      , name
       '/:name?/Account'   : ({name})-> go 'Account'   , name

+      # content displays:
       '/:name?/Topics/:topicSlug'       : @createContentDisplayHandler 'Topics'
-
       '/:name?/Activity/:activitySlug'  : @createContentDisplayHandler 'Activity'
-
       '/:name?/Apps/:appSlug'           : @createContentDisplayHandler 'Apps'

       '/recover/:recoveryToken': ({recoveryToken})->
@@ -182,10 +181,10 @@
           if err
             throw err
             new KDNotificationView
-              title     : "Something went wrong, please try again later!"
+              title: "Something went wrong, please try again later!"
           else
             new KDNotificationView
-              title     : "Thanks for confirming your email address!"
+              title: "Thanks for confirming your email address!"

       '/member/:username': ({username})->
           KD.remote.api.JAccount.one "profile.nickname" : username, (err, account)->
@@ -193,6 +192,7 @@
             else if account
               appManager.tell "Members", "createContentDisplay", account

+      # top level names:
       '/:name': (params)->
         status_404 = => @handleNotFound params.name
         KD.remote.cacheable params.name, (err, model, name)->


added unsubscribe feature for emailSender emails (similar to emailWorker but with a blacklist in the DB)

--- client/landing/app/MainApp/kodingrouter.coffee
+++ client/landing/app/MainApp/kodingrouter.coffee
@@ -292,12 +292,15 @@
       '/member/:username': ({params:{username}})->
         @handleRoute "/#{username}", replaceState: yes

-      '/:name?/Unsubscribe/:unsubscribeToken/:opt?':
-        ({params:{unsubscribeToken, opt}})->
-          opt              = decodeURIComponent opt
-          unsubscribeToken = decodeURIComponent unsubscribeToken
-          KD.remote.api.JMailNotification.unsubscribeWithId \
-          unsubscribeToken, opt, (err, content)=>
+      '/:name?/Unsubscribe/:token/:opt?':
+        ({params:{token, opt}})->
+          opt   = decodeURIComponent opt
+          token = decodeURIComponent token
+          (
+            if opt is 'email'
+            then KD.remote.api.JMail
+            else KD.remote.api.JMailNotification
+          ).unsubscribeWithId token, opt, (err, content)=>
             if err or not content
               title   = 'An error occured'
               content = 'Invalid unsubscribe token provided.'


JDomain: fix customDomain create

JDomain: fix customDomain create

--- workers/social/lib/social/models/domain.coffee
+++ workers/social/lib/social/models/domain.coffee
@@ -162,7 +162,7 @@
       return callback new KodingError \
         "Cannot resolve #{domain}", "RESOLVEFAILED"  if err

-      baseDomain = 'kd.io'
+      baseDomain = 'RANDOM3MGQvnuLpU97.kd.io'
       dns.resolve baseDomain, (err, baseIps)->
         return callback err  if err


GroupsGroups: fixed regex.test condition

--- workers/social/lib/social/models/domain.coffee
+++ workers/social/lib/social/models/domain.coffee
@@ -165,8 +165,8 @@

     [rest..., prefix, slug] = match

-    unless /^shared|vm[\-]?([0-9]+)?/.test prefix
-      return callback new KodingError("Domain name must be started with shared|vm", "INVALIDDOMAIN")
+    if /^shared|vm[\-]?([0-9]+)?/.test prefix
+      return callback new KodingError("Domain name cannot start with shared|vm", "INVALIDDOMAIN")

     callback null, slug


fix(notifications): Fix notification removal [Sentry 8957]

--- internal_packages/notifications/lib/notifications-store.coffee
+++ internal_packages/notifications/lib/notifications-store.coffee
@@ -44,7 +44,7 @@
     # your package should listen to notificationActionTaken and check the
     # notification and action objects.
     @listenTo Actions.notificationActionTaken, ({notification, action}) =>
-      @_removeNotification(notification)() if action.dismisses
+      @_removeNotification(notification) if action.dismisses
     @listenTo Actions.postNotification, (data) =>
       @_postNotification(new Notification(data))
     @listenTo Actions.dismissNotificationsMatching, (criteria) =>
@@ -75,14 +75,16 @@
     @_notifications[notification.tag] = notification
     if notification.expiry?
       timeoutVal = Math.max(0, notification.expiry - Date.now())
-      timeoutId = setTimeout(@_removeNotification(notification), timeoutVal)
+      timeoutId = setTimeout =>
+        @_removeNotification(notification)
+      , timeoutVal
       notification.timeoutId = timeoutId

     @trigger()

   # Returns a function for removing a particular notification. See usage
   # above in setTimeout()
-  _removeNotification: (notification) -> =>
+  _removeNotification: (notification) =>
     console.log "Removed #{notification}" if VERBOSE

     clearTimeout(notification.timeoutId) if notification.timeoutId


Fixes and adds tests

Fixes and adds tests

--- components/contact/test/contact_partner.coffee
+++ components/contact/test/contact_partner.coffee
@@ -31,6 +31,7 @@
       sinon.stub ContactPartnerView.prototype, 'open'
       sinon.stub ContactPartnerView.prototype, 'updatePosition'
       sinon.stub(ContactPartnerView.prototype, 'displayAfterInquiryFlow').returns false
+      ContactPartnerView.__set__ 'SESSION_ID', '1111'
       @view = new ContactPartnerView artwork: @artwork, partner: @partner, el: $('body')
       _.last(Backbone.sync.args)[2].complete [fabricate('location')]
       done()
@@ -66,13 +67,16 @@
         attributes.contact_gallery.should.be.ok # Should contact gallery

       it 'tracks the correct event', ->
-        events = _.last(@analytics.track.funnel.args, 3)
+        events = _.last(@analytics.track.funnel.args, 4)
         events[0][0].should.equal 'Sent artwork inquiry'
         events[1][0].should.equal 'Contact form submitted'
+        events[2][0].should.equal 'Changed default message'
+        events[3][1].should.equal '1111'

     describe 'Logged in', ->
       beforeEach ->
         @view.user = (@user = new Backbone.Model fabricate 'user')
+        @view.user.isLoggedIn = -> true
         @view.$el.html @view.formTemplate @view.templateData
         @view.$('textarea[name="message"]').val('My message')
         @view.$('form').submit()
@@ -84,6 +88,13 @@
         attributes.message.should.equal 'My message'
         attributes.artwork.should.equal @view.artwork.id
         attributes.contact_gallery.should.be.ok # Should contact gallery
+
+      it 'tracks the correct event', ->
+        events = _.last(@analytics.track.funnel.args, 4)
+        events[0][0].should.equal 'Sent artwork inquiry'
+        events[1][0].should.equal 'Contact form submitted'
+        events[2][0].should.equal 'Changed default message'
+        events[3][1].should.equal 'craigspaeth@gmail.com'

   describe '#events', ->


Use better signature match in deprecation message

--- atom/common/api/lib/crash-reporter.coffee
+++ atom/common/api/lib/crash-reporter.coffee
@@ -28,11 +28,11 @@
     extra._version ?= app.getVersion()

     unless companyName?
-      deprecate.log('companyName is now a required option to CrashReporter::start')
+      deprecate.log('companyName is now a required option to crashReporter.start')
       return

     unless submitURL?
-      deprecate.log('submitURL is now a required option to CrashReporter::start')
+      deprecate.log('submitURL is now a required option to crashReporter.start')
       return

     start = => binding.start @productName, companyName, submitURL, autoSubmit, ignoreSystemCrashHandler, extra


Improve Hive check

Improve Hive check

--- actions/hdp_hive_client.coffee
+++ actions/hdp_hive_client.coffee
@@ -99,7 +99,7 @@
     return next err, if configured then ctx.OK else ctx.PASS

 module.exports.push (ctx, next) ->
-  @name 'HDP Hive & HCat client # Kerberos Keytabs'
+  @name 'HDP Hive & HCat client # Kerberos'
   {hive_user, hadoop_group} = ctx.config.hdp
   {realm, kadmin_principal, kadmin_password, kadmin_server} = ctx.config.krb5_client
   ctx.krb5_addprinc
@@ -138,17 +138,18 @@
   @name 'HDP Hive & HCat client # Check'
   ctx.execute
     cmd: mkcmd.test ctx, """
-    if hadoop fs -test -f /user/test/hive_#{ctx.config.host}; then exit 2; fi
+    if hdfs dfs -test -d /user/test/hive_#{ctx.config.host}/check_hive_tb; then exit 2; fi
     hive -e "
-      CREATE DATABASE check_hive_db  LOCATION '/user/test/hive_#{ctx.config.host}'; \\
+      CREATE DATABASE IF NOT EXISTS check_hive_db  LOCATION '/user/test/hive_#{ctx.config.host}'; \\
       USE check_hive_db; \\
-      CREATE TABLE check_hive_tb(col1 STRING, col2 INT);" || exit 1
+      CREATE TABLE IF NOT EXISTS check_hive_tb(col1 STRING, col2 INT);" || exit 1
     echo "a,1\\nb,2\\nc,3" > /tmp/check_hive;
-    hadoop fs -put /tmp/check_hive /user/test/hive_#{ctx.config.host}/check_hive_tb/data || exit 1
+    hdfs dfs -mkdir -p /user/test/hive_#{ctx.config.host}/check_hive_tb
+    hdfs dfs -put /tmp/check_hive /user/test/hive_#{ctx.config.host}/check_hive_tb/data || exit 1
     hive -e "SELECT SUM(col2) FROM check_hive_db.check_hive_tb;" || exit 1
     hive -e "DROP TABLE check_hive_db.check_hive_tb; DROP DATABASE check_hive_db;" || exit 1
     rm -rf /tmp/check_hive
-    hadoop fs -touchz /user/test/hive_#{ctx.config.host}
+    hdfs dfs -touchz /user/test/hive_#{ctx.config.host}
     """
     code_skipped: 2
   , (err, executed, stdout) ->


Remove unnecessary null check

Remove unnecessary null check

--- src/scripts/modules/media/tabs/metadata/metadata.coffee
+++ src/scripts/modules/media/tabs/metadata/metadata.coffee
@@ -51,7 +51,7 @@
         value: 'keywords'
         type: 'select2'
         select2: () ->
-          @$el?.find('.keywords > input').val(@getProperty('keywords') or [])
+          @$el.find('.keywords > input').val(@getProperty('keywords') or [])
           _.extend({}, s2Multi, tags: @getProperty('keywords') or [])

       '.authors > input':


whitespace fix

whitespace fix

--- src/scripts/modules/media/tabs/metadata/metadata.coffee
+++ src/scripts/modules/media/tabs/metadata/metadata.coffee
@@ -24,7 +24,7 @@
       model.url = linksHelper.getModelPath(model)
       model.printStyles =
         {
-          null: 'Default' ,
+          null: 'Default' ,
           'ccap-physics' : 'CCAP Physics',
           'ccap-sociology' : 'CCAP Sociology',
           'ccap-biology' : 'CCAP Biology',


Remove whitespace

Remove whitespace

--- src/scripts/modules/media/tabs/metadata/metadata.coffee
+++ src/scripts/modules/media/tabs/metadata/metadata.coffee
@@ -82,7 +82,6 @@
             licensors.push(licensorsCollection.get(licensor).toJSON())
           return licensors

-
       '.publishers > input':
         value: 'publishers'
         type: 'select2'
@@ -144,8 +143,6 @@
       else
         return id

-
-
     initialize: () ->
       super()
       @listenTo @model, 'change change:currentPage', (model, options) =>


More delay

More delay

--- resources/assets/coffee/_classes/account-edit-playstyle.coffee
+++ resources/assets/coffee/_classes/account-edit-playstyle.coffee
@@ -20,7 +20,7 @@
   checkboxFields: document.getElementsByClassName('js-account-edit-playstyle')

   constructor: ->
-    @debouncedUpdate = _.debounce @update, 200
+    @debouncedUpdate = _.debounce @update, 500
     $(document).on 'change', '.js-account-edit-playstyle', @change


I though I deleted you ಠ_ಠ

I though I deleted you ಠ_ಠ

--- resources/assets/coffee/react/_components/bbcode-editor.coffee
+++ resources/assets/coffee/react/_components/bbcode-editor.coffee
@@ -57,7 +57,7 @@

   _reset: =>
     @refs.body.value = @props.rawValue
-    @setState dirty: false, rawValue: @props.rawValue
+    @setState rawValue: @props.rawValue
     @props.onChange(type: 'reset', value: @props.rawValue) if @props.onChange


FIX: Fix comments from not being submitted

--- src/app/tasks/task-comments-viewer/task-comments-viewer.coffee
+++ src/app/tasks/task-comments-viewer/task-comments-viewer.coffee
@@ -43,7 +43,7 @@

     # Checks for enter keydown
     $scope.enterDown = (editor) ->
-
+      $scope.addComment()
       return CodeMirror.Pass

     # Submits a new comment


Failing modal test

Failing modal test

--- test/modal.coffee
+++ test/modal.coffee
@@ -77,3 +77,8 @@
         modal.opened.should.be.false
         fireEvent el, 'click'
         modal.opened.should.be.true
+
+    it 'should have closer element that closing modal propely', ->
+        modal.opened.should.be.true
+        fireEvent modal.closers[0], 'click'
+        modal.opened.should.be.false


copy merge code into concat...

copy merge code into concat...

--- concat.coffee
+++ concat.coffee
@@ -7,14 +7,49 @@

 # read in the list of gist metadata
-gistMeta = JSON.parse fs.readFileSync(__dirname + '/data/gist-meta.json').toString()
-latest = JSON.parse fs.readFileSync(__dirname + '/data/latest.json').toString()
-console.log gistMeta.length
-console.log latest.length
-console.log gistMeta[0]
-console.log latest[0]
+#gistMeta = JSON.parse fs.readFileSync(__dirname + '/data/gist-meta.json').toString()
+#latest = JSON.parse fs.readFileSync(__dirname + '/data/latest.json').toString()
+#console.log gistMeta.length
+#console.log latest.length
+#console.log gistMeta[0]
+#console.log latest[0]

-merged = gistMeta.concat latest
+#merged = gistMeta.concat latest
+#outFile = __dirname + '/data/gist-meta.json';
+#fs.writeFileSync outFile, JSON.stringify(merged)

-outFile = __dirname + '/data/gist-meta.json';
-fs.writeFileSync outFile, JSON.stringify(merged)+saveGistMeta = (newGists) ->
+  try
+    blocksList = JSON.parse(fs.readFileSync(__dirname + '/data/gist-meta.json').toString() || "[]")
+  catch e
+    blocksList = []
+  allGists = combine(blocksList, newGists)
+  console.log "writing #{allGists.length} blocks to data/gist-meta.json"
+  fs.writeFileSync __dirname + '/data/gist-meta.json', JSON.stringify(allGists)
+  return
+
+# this function combines the new gist meta-data with what we may have already
+# gotten before. This allows us to accumulate new blocks incrementally
+combine = (oldGists, newGists) ->
+  console.log "combining #{newGists.length} with #{oldGists.length} existing blocks"
+  blocks = {}
+  oldGists.forEach (block) ->
+    blocks[block.id] = block
+
+  newGists.forEach (gist) ->
+    blocks[gist.id] = gist
+
+  ids = Object.keys(blocks)
+  newBlockList = []
+  ids.forEach (id) ->
+    newBlockList.push blocks[id]
+  return newBlockList
+
+infile = process.argv[2] || "data/new.json"
+try
+  inblocks = JSON.parse(fs.readFileSync(__dirname + '/' + infile).toString() || "[]")
+catch e
+  inblocks = []
+
+saveGistMeta(inblocks)
+


DE21556:found more spots where firefox was vulnerable on these tests

--- test/spec/roadmapplanningboard/PlanningBoardSpec.coffee
+++ test/spec/roadmapplanningboard/PlanningBoardSpec.coffee
@@ -219,11 +219,13 @@
     describe 'deleting all of the columns', ->

       beforeEach ->
-        @createCardboard(isAdmin: true).then =>
-          _.times @planStore.count(), => @deleteColumn(1)
+        if !Ext.isGecko
+          @createCardboard(isAdmin: true).then =>
+            _.times @planStore.count(), => @deleteColumn(1)

       it 'should contain a single timeframe column', ->
-        expect(@getTimeframePlanningColumns().length).toBe 1
+        if !Ext.isGecko
+          expect(@getTimeframePlanningColumns().length).toBe 1

       it 'should add a new empty timeframe column', ->
         if !Ext.isGecko
@@ -232,28 +234,30 @@
     describe 'deleting newly added columns', ->

       beforeEach ->
-        @createCardboard(isAdmin: true).then =>
-          @cardboard._addNewColumn().then =>
+        if !Ext.isGecko
+          @createCardboard(isAdmin: true).then =>
             @cardboard._addNewColumn().then =>
               @cardboard._addNewColumn().then =>
-                expect(@planStore.count()).toBe 7
-                # 0: backlog, 1-4: existing columns, 5-7: new columns
-                # delete the 'middle' new column, then the last new column, then the first
-                @deleteColumn(6).then =>
+                @cardboard._addNewColumn().then =>
+                  expect(@planStore.count()).toBe 7
+                  # 0: backlog, 1-4: existing columns, 5-7: new columns
+                  # delete the 'middle' new column, then the last new column, then the first
                   @deleteColumn(6).then =>
-                    @deleteColumn(5)
+                    @deleteColumn(6).then =>
+                      @deleteColumn(5)

       it 'should remove the new plans from the plan store', ->
         if !Ext.isGecko
           expect(@planStore.count()).toBe 4

       describe 'when the remaining columns are deleted', ->
-
-        beforeEach ->
-          _.times @planStore.count(), => @deleteColumn(1)
-
-        it 'should contain a single timeframe column', ->
-          expect(@getTimeframePlanningColumns().length).toBe 1
+          beforeEach ->
+            if !Ext.isGecko
+              _.times @planStore.count(), => @deleteColumn(1)
+
+          it 'should contain a single timeframe column', ->
+            if !Ext.isGecko
+              expect(@getTimeframePlanningColumns().length).toBe 1

   describe 'permissions', ->


This fix allows compression of JS.

This fix allows compression of JS.

--- lib/assets/javascripts/loco/models/base.coffee
+++ lib/assets/javascripts/loco/models/base.coffee
@@ -13,6 +13,7 @@
   #       remoteName: "updated_at"
   #       validations:
   #         presence: true
+  @identity = "Base"

   constructor: (data = {}) ->
     @id = null


Drop the minimum Serrano version to >= 2.0.18

--- src/coffee/cilantro.coffee
+++ src/coffee/cilantro.coffee
@@ -16,7 +16,7 @@
     # the version number received from the server, the user will be warned if
     # no version number is found or if it is less than this minimum to
     # prepare them in the case of missing or broken functionality.
-    c.minimumSerranoVersion = [2, 0, 24]
+    c.minimumSerranoVersion = [2, 0, 18]

     c.data =
         concepts: new models.ConceptCollection


add a go_forward function to js

add a go_forward function to js

it toggles the next link

--- assets/scripts/mandrill_merge.coffee
+++ assets/scripts/mandrill_merge.coffee
@@ -26,6 +26,9 @@

   go_back: (caller)->
     caller.parents('.accordion-navigation').prev().find('a').click()
+
+  go_forward: (caller)->
+    caller.parents('.accordion-navigation').next().find('a').click()

   mandrill_connect_response: (response)->
     $('#mandrill-connection-status').html response.message


root_pathに飛ぶときにturbolinkをoffにする

--- app/assets/javascripts/components/navbar/navbar.js.cjsx
+++ app/assets/javascripts/components/navbar/navbar.js.cjsx
@@ -15,7 +15,7 @@

   render: ->

-
+
         ☆12参考表


(doc) Commented on visiblity hack. Chrome dev says we have to wait at least a year...

--- src/more_markdown.coffee
+++ src/more_markdown.coffee
@@ -20,6 +20,9 @@

 # swaps the current buffer with the currently processed one
 swap = (active, buffer) ->
+  # due to missing font metrics the "backbuffer" has to be visible
+  # according to a chrome dev there are people working on at
+  # https://github.com/w3c/css-houdini-drafts
   active.removeAttribute "activeBuffer"
   active.setAttribute "invisibleBuffer", ""
   active.style.position = "absolute";


test(utils): add test for `min` function.

--- test/utils.coffee
+++ test/utils.coffee
@@ -8,4 +8,14 @@
     utils.min([-1, 0, 1]).should.be.equal(-1)
     utils.min([1, 0, -1]).should.be.equal(-1)
     utils.min([5, 0, -5, 10, -10]).should.be.equal(-10)
+    utils.min([1, undefined]).should.be.equal(1)
+    utils.min([undefined, 1]).should.be.equal(1)
+    utils.min([1, 'a']).should.be.equal(1)
+    utils.min(['a', 1]).should.be.equal(1)
+    utils.min([1, 1]).should.be.equal(1)
     done()
+
+describe 'min', ->
+  it 'should work', (done) ->
+    utils.min([1, 10, 100]).should.be.equal(1)
+    done()


Fix invincible enemy

Fix invincible enemy

--- app/scripts/components/Enemy.coffee
+++ app/scripts/components/Enemy.coffee
@@ -20,6 +20,7 @@
     this

   absorbDamage: (damage) ->
+    return unless damage?
     @health -= damage
     @updatedHealth?()
     if @health <= 0


Consistencia

Consistencia

--- app/assets/javascripts/layout.js.coffee
+++ app/assets/javascripts/layout.js.coffee
@@ -16,8 +16,8 @@
 jQuery ->

   # muestra el botón para cerrar la flash si hay js
-  $(".alert button.close").show()
-  $(".alert").alert()
+  $('.alert button.close').show()
+  $('.alert').alert()

   $('input.fecha').datepicker({
     language: 'es',


Fixed missing JS dependency on mobile

Fixed missing JS dependency on mobile

--- app/assets/javascripts/mobile.js.coffee
+++ app/assets/javascripts/mobile.js.coffee
@@ -7,6 +7,7 @@

 #= require vendor/jquery.libraries
 #= require vendor/jquery.timeago
+#= require vendor/jquery.filedrop
 #= require vendor/to-markdown

 #= require backbone/sugar


photo upload with sort_order

photo upload with sort_order

--- app/assets/javascripts/photos.js.coffee
+++ app/assets/javascripts/photos.js.coffee
@@ -12,7 +12,7 @@

   bindForm: ->
     @$form.on 'submit', ->
-      alert("no")
+      alert("Regular submit disabled.")
       return false

   enableUpload: ->


Remove console logging of GET requests

Remove console logging of GET requests

--- app/assets/javascripts/utils/api.coffee
+++ app/assets/javascripts/utils/api.coffee
@@ -20,7 +20,6 @@
         type: 'GET',
         url: "/lookups/#{model}.json",
         success: (data) ->
-          console.log "Received '#{model}' lookups"
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -32,7 +31,6 @@
         type: 'GET',
         url: '/wizards.json',
         success: (data) ->
-          console.log 'Received wizard index'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -45,7 +43,6 @@
         type: 'GET',
         url: url
         success: (data) ->
-          console.log 'Received revisions'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -57,7 +54,6 @@
         type: 'GET',
         url: "/revision_analytics/dyk_eligible.json?scoped=#{opts.scoped || false}",
         success: (data) ->
-          console.log 'Received DYK'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -69,7 +65,6 @@
         type: 'GET',
         url: "/revision_analytics/suspected_plagiarism.json?scoped=#{opts.scoped || false}",
         success: (data) ->
-          console.log 'Received suspected plagiarism'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -81,7 +76,6 @@
         type: 'GET',
         url: "/revision_analytics/recent_edits.json?scoped=#{opts.scoped || false}",
         success: (data) ->
-          console.log 'Received recent edits'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -93,7 +87,6 @@
         type: 'GET',
         url: "/revision_analytics/recent_uploads.json?scoped=#{opts.scoped || false}",
         success: (data) ->
-          console.log 'Received recent uploads'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -117,7 +110,6 @@
         type: 'GET',
         url: '/cohorts.json',
         success: (data) ->
-          console.log 'Received cohorts'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -129,7 +121,6 @@
         type: 'GET',
         url: '/wizards/' + wizard_id + '.json',
         success: (data) ->
-          console.log 'Received wizard configuration'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -141,7 +132,6 @@
         type: 'GET',
         url: "/courses_users.json?user_id=#{userId}"
         success: (data) ->
-          console.log 'Received user courses'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -193,7 +183,6 @@
         type: 'GET',
         url: '/courses/' + course_id + '/' + endpoint + '.json',
         success: (data) ->
-          console.log 'Received ' + endpoint
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -205,7 +194,6 @@
         type: 'GET'
         url: "/training_modules.json"
         success: (data) ->
-          console.log 'Received training modules'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)
@@ -217,7 +205,6 @@
         type: 'GET'
         url: "/training_module.json?module_id=#{opts.module_id}"
         success: (data) ->
-          console.log 'Received training module'
           res data
       .fail (obj, status) ->
         logErrorMessage(obj)


server.batch to get a promise for each target

--- app/server.coffee
+++ app/server.coffee
@@ -211,6 +211,9 @@

   fn 'execute', 'Executes a DSL expression on the server', (ctx, args...) ->
     Context.value server.execute(args_to_server_params ctx, args)
+
+  fn 'batch', 'Executes a batch of DSL expressions with a promise for each', (ctx) ->
+    Context.value(server.batch(ctx.options()))

   init: ->
     if settings.get('type') == 'lead'
@@ -367,6 +370,30 @@
     promise.fail (response) ->
       Q.reject new ServerError(server.parse_error_response response)

+  batch: (default_options) ->
+    items = []
+
+    add: (target) ->
+      deferred = Q.defer()
+      items.push {deferred, target}
+      deferred.promise
+
+    execute: (params) ->
+      targets = _.pluck(items, 'target')
+
+      args = [targets]
+      if arguments.length == 1
+        args.push(params)
+
+      server.execute(server.args_to_params({args, default_options}).server)
+      .fail (e) ->
+        _.each items, ({deferred}) ->
+          deferred.reject(e)
+      .then (result) ->
+        _.each result.results, (targetResult, i) ->
+          items[i].deferred.resolve(targetResult.result)
+        result
+
   # returns a promise
   complete: (query) ->
     server.find(query + '*')


Refactor survey questions existence check (#5765)

--- app/classifier/tasks/survey/editor.cjsx
+++ app/classifier/tasks/survey/editor.cjsx
@@ -99,7 +99,7 @@
                 {@state.confusionsName}}

-              <FileButton className="major-button column" accept=".csv, .tsv" disabled={@checkAdd()} onSelect={@handleFiles.bind this, 'questionsName', @addQuestion, @cleanQuestions}>{if @state.task.questionsOrder.length is 0 then "Add" else "Replace"} questions</FileButton>
+              <FileButton className="major-button column" accept=".csv, .tsv" disabled={@checkAdd()} onSelect={@handleFiles.bind this, 'questionsName', @addQuestion, @cleanQuestions}>{if @state.task.questions.keys?.length is 0 then "Add" else "Replace"} questions</FileButton>
               <TriggeredModalForm trigger={

@@ -665,7 +665,7 @@
       contentWarnings.push {source: 'confusions', message: 'No confusions added.'}

     #questions
-    if @state.task.questionsOrder.length is 0
+    if @state.task.questions.keys?.length is 0
       contentWarnings.push {source: 'questions', message: 'No questions added.'}

     #images-choices


Ensure beta is detected from path

Ensure beta is detected from path

--- src/main-process/win-shell.coffee
+++ src/main-process/win-shell.coffee
@@ -3,7 +3,8 @@

 exeName = Path.basename(process.execPath)
 appPath = "\"#{process.execPath}\""
-appName = exeName.replace('atom', 'Atom').replace('beta', 'Beta').replace('.exe', '')
+isBeta = appPath.includes(' Beta')
+appName = exeName.replace('atom', (if isBeta then 'Atom Beta' else 'Atom' )).replace('.exe', '')

 class ShellOption
   constructor: (key, parts) ->


description rtl support

description rtl support

--- app/modules/components/wysiwyg/wysiwyg.directive.coffee
+++ app/modules/components/wysiwyg/wysiwyg.directive.coffee
@@ -56,6 +56,23 @@

         wysiwygCodeHightlighterService.addCodeLanguageSelectors(elm)

+
+    AlignRightButton = MediumEditor.extensions.button.extend({
+        name: 'rtl',
+        init: () ->
+            this.button = this.document.createElement('button')
+            this.button.classList.add('medium-editor-action')
+            this.button.innerHTML = 'RTL'
+            this.button.title = 'RTL'
+            this.on(this.button, 'click', this.handleClick.bind(this))
+
+        getButton: () ->
+            return this.button
+        handleClick: (event) ->
+            document.execCommand('justifyRight', false)
+
+    })
+
     # MediumEditor extension to add
     CodeButton = MediumEditor.extensions.button.extend({
         name: 'code',
@@ -294,12 +311,14 @@
                         'h3',
                         'quote',
                         'removeFormat',
+                        'rtl',
                         'code'
                     ]
                 },
                 extensions: {
                     code: new CodeButton(),
                     autolist: new AutoList(),
+                    alignright: new AlignRightButton(),
                     mediumMention: new MentionExtension({
                         getItems: (mention, mentionCb) ->
                             wysiwygMentionService.search(mention).then(mentionCb)


Edit hare text

Edit hare text

Misc text edits

--- app/lib/field-guide-content/hare.coffee
+++ app/lib/field-guide-content/hare.coffee
@@ -1,6 +1,6 @@
 module.exports =
   description: '''
-    There are two hare species in Gorongosa: savanna hare (Lepus microtis) and scrub hare (Lepus saxatilis). The savanna hare is usually darker in color than other hares, with a grayish-brown body, reddish-brown flanks and limbs, and white underparts. Scrub hares have thick, soft fur that is brown to gray in color with a black flecking, which gives their coat a grizzled appearance on their upper parts, contrasting with their under parts, which are white. Their head is whitish with a buff color on the sides of the face and around the eyes. Most individuals have a distinct white patch on the forehead just above the eyes.
+    Two hare species live in Gorongosa: the savanna hare (Lepus microtis) and the scrub hare (Lepus saxatilis). The savanna hare is usually darker in color than other hares, with a grayish-brown body, reddish-brown flanks and limbs, and white underparts. Scrub hares have thick, soft fur that is brown to gray in color with a black flecking, which gives their coat a grizzled appearance on their upper parts, contrasting with their under parts, which are white. Their head is whitish with a buff color on the sides of the face and around the eyes. Most individuals have a distinct white patch on the forehead just above the eyes.
   '''

   scientificName: ''
@@ -19,7 +19,7 @@
     value: '12 years'
   }, {
     label: 'Gestation'
-    value: '1-2 months'
+    value: 'About 42 days'
   }, {
     label: 'Avg. number of offspring'
     value: '1-3'
@@ -30,7 +30,7 @@
     content: 'Savanna hares are found throughout wooded savannas. Scrub hares are primarily found in scrub, tall grasslands, and savanna woodlands. They avoid forests and deserts.'
   }, {
     title: 'Diet'
-    content: 'Mostly green grass; also leaves, stems, dry grass, and bark.'
+    content: 'Mostly green grass; also leaves, stems, dry grass, and bark'
   }, {
     title: 'Predators'
     content: 'Birds of prey, caracal, jackal, and humans'
@@ -38,14 +38,14 @@
     title: 'Behavior'
     content: '''

Savanna hares are solitary, nocturnal animals. If they see a predator, they freeze and rely on camouflage to stay hidden. If a predator approaches, however, they quickly bolt and dash away in a zigzag pattern. They spend most of the day lying in depressions in the ground covered by brush or grass.

-
Scrub hares are nocturnal, starting to forage at dusk and continuing through the night. They travel alone unless a female is accompanied by courting males or her offspring. During the day, they generally lie in a shallow depression on the ground, concealed under bushes or grass. When threatened, scrub hares will remain motionless in an attempt to blend in with their background. However, if a predator advances or the hare continues to feel threatened, it will bolt suddenly, relying on its speed to escape. If caught, they emit a loud squealing sound and will kick with their back feet in an attempt to free themselves.

+
Scrub hares are nocturnal, starting to forage at dusk and continuing through the night. They travel alone unless a female is accompanied by courting males or her offspring. During the day, they generally lie in a shallow depression in the ground, concealed under bushes or grass. When threatened, scrub hares will remain motionless in an attempt to blend in with their background. However, if a predator advances or the hare continues to feel threatened, it will bolt suddenly, relying on its speed to escape. If caught, they emit a loud squealing sound and will kick with their back feet in an attempt to free themselves.

     '''
   }, {
     title: 'Breeding'
     content: '''
-
Little is known definitively about the breeding behavior of  savanna hares. They appear to reproduce throughout the year and give birth to multiple litters a year, with an average litter size of 1.6.

-
Scrub hares breed year-round. After a gestation period of 42 days, females will give birth to one to three “leverets” per litter. A single female can have as many as four litters per year. Mothers invest little time in parenting their young. The young are born fully haired, open eyed, and are essentially developed enough to take care of themselves.

+
Little is known definitively about the breeding behavior of savanna hares. They appear to reproduce throughout the year and give birth to multiple litters a year, with an average litter size of 1.6.

+
Scrub hares breed year-round. After a gestation period of 42 days, females will give birth to one to three “leverets” per litter. A single female can have as many as four litters per year. Mothers invest little time in parenting their young. The young are born fully haired and open-eyed, and are essentially developed enough to take care of themselves.

     '''
   }, {
     title: 'Fun Facts'


Remove exemplar/project urls from course schema (#558)

These have been moved to level schema

--- app/schemas/models/course.schema.coffee
+++ app/schemas/models/course.schema.coffee
@@ -37,10 +37,6 @@
         totalTimeRange: { type: 'string', title: 'Total class time (range)', description: 'Relevant for curriculum guides hover tooltip'}
       }}
       lessonSlidesUrl: c.url { title: 'Lesson Slides URL' }
-      # TODO remove these after changing the curr guides and projects page to read from capstone level
-      exemplarProjectUrl: c.url { title: 'Exemplar Project URL', description: 'Only relevant for capstone module' }
-      exemplarCodeUrl: c.url { title: 'Exemplar Code URL', description: 'Only relevant for capstone module' }
-      projectRubricUrl: c.url { title: 'Project Rubric URL', description: 'Only relevant for capstone module' }
     }} # TODO move module name from utils.coffee to schema
   }


Improved default district selection when district_map route is for a senator.

--- app/scripts/controllers/district.coffee
+++ app/scripts/controllers/district.coffee
@@ -174,7 +174,11 @@
         console.log $routeParams.bioguide_id
         ApiGet.congress "legislators?bioguide_id=#{$routeParams.bioguide_id}", (error, data) ->
           if not error
-            if !data[0].district then data[0].district = "0"
+            if not data[0].district
+              for state in ["AK", "DE", "MT", "ND", "SD", "VT", "WY"]
+                if data[0].state is state
+                  data[0].district = "0"
+              if not data[0].district then data[0].district = "1"
             $scope.state_district = {state: data[0].state, district: data[0].district}
           else console.log "Error, Senator/Rep not found."
       else console.log "No parameter"


riorganizzato codice

riorganizzato codice

--- app/scripts/controllers/register.coffee
+++ app/scripts/controllers/register.coffee
@@ -62,7 +62,6 @@
     # default values
     $scope.u =
       gender: 'M'
-
     $scope.phonePrefix = '+39'
     $scope.server = 'freeluna'


chore (env) Set elections open by default until the end of 2016

--- app/scripts/services/environment.coffee
+++ app/scripts/services/environment.coffee
@@ -11,10 +11,10 @@
       moment('2015-12-14 17:00', 'YYYY-MM-DD HH:mm').utcOffset('+0200')

     @electionSignInStartsAt = do ->
-      moment('2015-12-16 09:00', 'YYYY-MM-DD HH:mm').utcOffset('+0200')
+      moment('2016-02-16 09:00', 'YYYY-MM-DD HH:mm').utcOffset('+0200')

     @electionSignInEndsAt = do ->
-      moment('2015-12-16 17:00', 'YYYY-MM-DD HH:mm').utcOffset('+0200')
+      moment('2016-12-16 17:00', 'YYYY-MM-DD HH:mm').utcOffset('+0200')

     @isEligibilityActive = ->
       moment().isAfter(@eligibilitySignInStartsAt) &&


bugfix

bugfix

--- src/runr.coffee
+++ src/runr.coffee
@@ -12,8 +12,8 @@
 }

 exports.up = (name, args, callback) ->
-  runr[name].isRunning (err, isRunning) ->
+  exports[name].isRunning (err, isRunning) ->
     return callback(err) if err?
     return callback() if isRunning
-    runr[name].run(args, callback)
+    exports[name].run(args, callback)


Fixed Single-mode toolbar bug

Fixed Single-mode toolbar bug

--- muleview/app/view/SingleGraphChartsView.coffee
+++ muleview/app/view/SingleGraphChartsView.coffee
@@ -77,16 +77,17 @@
       store: store
   createChartContainerToolbar: ->
     toolbar = this.callParent()
-    toolbar.splice(2,0,[
-        "-",
+    toolbar.splice(2,0,
+      "-",
         xtype: "button"
         text: "Edit Alerts"
         handler: =>
           @showAlertsEditor()
-      , "-",
+    , "-",
         xtype: "button"
         text: "Select Subkeys"
         disabled: @subKeys.length == 0
         handler: =>
           @showSubkeysSelector()
-      ])
+        )
+    toolbar


fixing a bug that was causing the page to scroll / cursor movement on focus:frame.

--- vendor/assets/javascripts/mercury/regions/markupable.js.coffee
+++ vendor/assets/javascripts/mercury/regions/markupable.js.coffee
@@ -34,7 +34,7 @@

   bindEvents: ->
     Mercury.on 'mode', (event, options) => @togglePreview() if options.mode == 'preview'
-    Mercury.on 'focus:frame', => @focus() unless @previewing && Mercury.region != @
+    Mercury.on 'focus:frame', => @focus() if !@previewing && Mercury.region == @

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


make alt-k/alt-j to move up/down in advanced-open-file

--- backup/keymap.cson
+++ backup/keymap.cson
@@ -30,6 +30,10 @@
   'alt-h': 'core:move-left'
   'alt-l': 'core:move-right'

+'.advanced-open-file':
+  'alt-k': 'advanced-open-file:move-cursor-up'
+  'alt-j': 'advanced-open-file:move-cursor-down'
+
 'atom-text-editor.vim-mode:not(.insert-mode)':
   # unset vim-mode to enable find & replace in current pane
   'ctrl-f': 'unset!'


Added file extension for exports.

Added file extension for exports.

--- JavaApacheHttpClientFluentAPICodeGenerator.coffee
+++ JavaApacheHttpClientFluentAPICodeGenerator.coffee
@@ -2,12 +2,12 @@

 addslashes = (str) ->
     ("#{str}").replace(/[\\"]/g, '\\$&')
-
+
 multiLinesToSingleLine = (str) ->
     ("#{str}").replace(/[\n"]/g, '\\n')

 JavaApacheHttpClientFluentAPICodeGenerator = ->
-
+
     @url = (request) ->
         return {
             "fullpath": request.url
@@ -42,7 +42,7 @@
             }

         multipart_body = request.multipartBody
-        if multipart_body
+        if multipart_body
             return {
                 "has_multipart_body":true
                 "multipart_body": ({
@@ -82,7 +82,7 @@

     @generate = (context) ->
         request = context.getCurrentRequest()
-
+
         view =
             "request": context.getCurrentRequest()
             "method": request.method[0].toUpperCase() + request.method[1..-1].toLowerCase()
@@ -97,8 +97,9 @@

 JavaApacheHttpClientFluentAPICodeGenerator.identifier =
-    "com.luckymarmot.PawExtensions.JavaApacheHttpClientFluentAPICodeGenerator";
+    "com.luckymarmot.PawExtensions.JavaApacheHttpClientFluentAPICodeGenerator"
 JavaApacheHttpClientFluentAPICodeGenerator.title =
-    "Java (Apache HttpClient via Fluent API)";
+    "Java (Apache HttpClient via Fluent API)"
+JavaApacheHttpClientFluentAPICodeGenerator.fileExtension = "java"

 registerCodeGenerator JavaApacheHttpClientFluentAPICodeGenerator


Return book instead of ecosystem

Return book instead of ecosystem

--- src/flux/ecosystems.coffee
+++ src/flux/ecosystems.coffee
@@ -40,7 +40,7 @@
       _.first @_ecosystems

     getBook: (ecosystemId) ->
-      _.findWhere(@_ecosystems, id: parseInt(ecosystemId, 10))
+      _.first( _.findWhere(@_ecosystems, id: parseInt(ecosystemId, 10)).books )

 module.exports = {EcosystemsActions, EcosystemsStore}


Fixing the print percentage

Fixing the print percentage

--- src/tegh.coffee
+++ src/tegh.coffee
@@ -118,6 +118,8 @@
     stdout.write "Connecting to #{service.address}/#{service.serviceName}..."
     @client = new ConstructClient(service.address, port, service.path)
       .on("initialized", @_onInit)
+      .on("add", @_onAdd)
+      .on("rm", @_onRm)
       .on("change", @_onChange)
       .on("ack", @_onAck)
       .on("construct_error", @_onError)
@@ -128,12 +130,22 @@
     @printer = data
     @tempDevices = Object.findAll @printer, (k, v) -> k.startsWith /e[0-9]+$|b$/
     @cli = new CliConsole(@)
+    @cli.render()
+
+  _onAdd: (data, target) =>
+    @printer[target] = data
+
+  _onRm: (data, target) =>
+    delete @printer[target]

   _onChange: (data, target) =>
     @_renderProgressBar(data) if target == 'job_upload_progress'
     # Finding the target from it's path, updating it and re-rendering

-    Object.merge @printer[target], data
+    if Object.isObject data
+      Object.merge @printer[target], data
+    else
+      @printer[target] = data
     @_onJobStarted @printer[target] if target.startsWith('job') and data.status?
     @cli.render()

@@ -158,6 +170,7 @@
     @cli.render()

   _onJobStarted: (job) =>
+    console.log job
     stdout.write "\r" + "Printing #{job.file_name}".green
     console.log()
     @cli.rl.prompt()
@@ -213,10 +226,11 @@
     return status if @printer.status != "printing"
     total = 0
     current = 0
-    for k, job of @printer.jobs when job.status == "printing"
-      total += job.total_lines
-      current += job.current_line
-    return status + "( #{(current / total).format(2)}% ) "
+    for job in @printer.jobs
+      continue unless job.status == "printing"
+      total += job.total_lines || 0
+      current += job.current_line || 0
+    return status + "( #{((current / total) || 0).format(2)}% ) "

   _append: (s, prefix = "") ->
     stdout.write(prefix + s + "\n")


no need for incremented z index

no need for incremented z index

--- src/tour.coffee
+++ src/tour.coffee
@@ -125,7 +125,7 @@
     if el.css('position') == 'static'
       el.css('position', 'relative')

-    el.css('z-index', @activeStep.zIndex + 1 || 1001 )
+    el.css('z-index', @activeStep.zIndex  || 1000 )

   leave: () =>
     el = @getController(@lastStep).element


Improved the performance of bindEvent, unbindEvent, getInputValue on Rivets.Util.

--- src/util.coffee
+++ src/util.coffee
@@ -1,40 +1,30 @@
 # Rivets.Util
 # -----------

-# Houses common utility functions used internally by Rivets.js.
-Rivets.Util =
-  # Create a single DOM event binding.
-  bindEvent: (el, event, handler) ->
-    if window.jQuery?
-      el = jQuery el
-      if el.on? then el.on event, handler else el.bind event, handler
-    else if window.addEventListener?
-      el.addEventListener event, handler, false
-    else
-      event = 'on' + event
-      el.attachEvent event, handler
+if 'jQuery' of window
+  [bindMethod, unbindMethod] = if 'on' of jQuery then ['on', 'off'] else ['bind', 'unbind']
+
+  Rivets.Util =
+    bindEvent: (el, event, handler) -> jQuery(el)[bindMethod] event, handler
+    unbindEvent: (el, event, handler) -> jQuery(el)[unbindMethod] event, handler
+    getInputValue: (el) ->
+      $el = jQuery el

-  # Remove a single DOM event binding.
-  unbindEvent: (el, event, handler) ->
-    if window.jQuery?
-      el = jQuery el
-      if el.off? then el.off event, handler else el.unbind event, handler
-    else if window.removeEventListener?
-      el.removeEventListener event, handler, false
-    else
-      event = 'on' + event
-      el.detachEvent  event, handler
+      if $el.attr('type') is 'checkbox' then $el.is ':checked'
+      else do $el.val
+else
+  Rivets.Util =
+    bindEvent: do ->
+      if 'addEventListener' of window then return (el, event, handler) ->
+        el.addEventListener event, handler, false

-  # Get the current value of an input node.
-  getInputValue: (el) ->
-    if window.jQuery?
-      el = jQuery el
-
-      switch el[0].type
-        when 'checkbox' then el.is ':checked'
-        else el.val()
-    else
-      switch el.type
-        when 'checkbox' then el.checked
-        when 'select-multiple' then o.value for o in el when o.selected
-        else el.value
+      (el, event, handler) -> el.attachEvent 'on' + event, handler
+    unbindEvent: do ->
+      if 'removeEventListener' of window then return (el, event, handler) ->
+        el.removeEventListener event, handler, false
+
+      (el, event, handler) -> el.detachEvent 'on' + event, handler
+    getInputValue: (el) ->
+      if el.type is 'checkbox' then el.checked
+      else if el.type is 'select-multiple' then o.value for o in el when o.selected
+      else el.value


Fix bug with top-left corner beveling interacting with dedupe()

--- src/view.coffee
+++ src/view.coffee
@@ -1752,6 +1752,8 @@
           @addTab right, new @view.draw.Point @bounds[@lineLength - 1].x + @view.opts.tabOffset,
             @bounds[@lineLength - 1].bottom()

+      topLeftPoint = left[0]
+
       # Reverse the left and concatenate it with the right
       # to make a counterclockwise path
       path = dedupe left.reverse().concat right
@@ -1763,7 +1765,7 @@
           newPath.push point
           continue

-        if i is (left.length - 1) and not @bevels.top
+        if (not @bevels.top) and point.almostEquals(topLeftPoint)
           newPath.push point
           continue


Only schedule atom.setFullScreen() when set in state

--- src/root-view.coffee
+++ src/root-view.coffee
@@ -126,7 +126,8 @@
     @command 'pane:reopen-closed-item', =>
       @panes.reopenItem()

-    _.nextTick => atom.setFullScreen(@state.get('fullScreen'))
+    if @state.get('fullScreen')
+      _.nextTick => atom.setFullScreen(true)

   # Private:
   serialize: ->


Add more snippets (#59)

Add more snippets (#59)

--- snippets/language-restructuredtext.cson
+++ snippets/language-restructuredtext.cson
@@ -1,10 +1,148 @@
 '.text.restructuredtext':
-  'image':
+
+  # Directives
+  'admonition directive':
+    'prefix': 'admonition'
+    'body': '.. admonition:: ${1:title}\n\n\t$0'
+  'attention directive':
+    'prefix': 'attention'
+    'body': '.. attention::\n\n\t'
+  'bokeh-plot directive':
+    'prefix': 'bokeh-plot'
+    'body': '.. bokeh-plot::\n\n\t'
+  'caution directive':
+    'prefix': 'caution'
+    'body': '.. caution::\n\n\t'
+  'code directive':
+    'prefix': 'Code'
+    'body': '.. code:: ${1:language}\n\n\t${2:<code>}'
+  'code-block directive':
+    'prefix': 'code-block'
+    'body': '.. code-block:: ${1:language}\n\n\t${2:<code>}'
+  'compound directive':
+    'prefix': 'compound'
+    'body': '.. compound::\n\n\t'
+  'container directive':
+    'prefix': 'container'
+    'body': '.. container:: ${1:class}\n\n\t$0'
+  'contents directive':
+    'prefix': 'contents'
+    'body': '..contents:: ${1:title}\n\t:depth: ${2:2}'
+  'csv-table directive':
+    'prefix': 'csv-table'
+    'body': '.. csv-table:: ${1:title}\n\n\t$0'
+  'danger directive':
+    'prefix': 'danger'
+    'body': '.. danger::\n\n\t'
+  'epigraph directive':
+    'prefix': 'epigraph'
+    'body': '.. epigraph::\n\n\t${1:citation}\n\n\t-- ${2:author}'
+  'error directive':
+    'prefix': 'error'
+    'body': '.. error::\n\n\t'
+  'highlights directive':
+    'prefix': 'highlights'
+    'body': '.. highlights::\n\n\t'
+  'hint directive':
+    'prefix': 'hint'
+    'body': '.. hint::\n\n\t'
+  'include directive':
+    'prefix': 'include'
+    'body': '.. include:: ${1:file}'
+  'figure directive':
+    'prefix': 'figure'
+    'body': '.. figure:: ${1:path}\n$0'
+  'image directive':
     'prefix': 'image'
     'body': '.. image:: ${1:path}\n$0'
+  'important directive':
+    'prefix': 'important'
+    'body': '.. important::\n\n\t'
+  'ipython directive':
+    'prefix': 'ipython'
+    'body': '.. ipython:: ${1:python}\n\n\t$0'
+  'line-block directive':
+    'prefix': 'line-block'
+    'body': 'line-block::\n\n\t'
+  'list-table directive':
+    'prefix': 'list-table'
+    'body': '.. list-table:: ${1:title}\n\n\t$0'
+  'math directive':
+    'prefix': 'Math'
+    'body': '.. math::\n\n\t'
+  'note directive':
+    'prefix': 'note'
+    'body': '.. note::\n\n\t'
+  'parsed-literal directive':
+    'prefix': 'parsed-literal'
+    'body': '.. parsed-literal::\n\n\t'
+  'plot directive':
+    'prefix': 'plot'
+    'body': '.. plot::\n\n\t'
+  'pull-quote directive':
+    'prefix': 'pull-quote'
+    'body': '.. pull-quote::\n\n\t'
+  'replace directive':
+    'prefix': 'replace'
+    'body': '.. |${1:text}| replace:: ${2:replacement}'
+  'rubric directive':
+    'prefix': 'rubric'
+    'body': '.. rubric:: '
+  'sidebar directive':
+    'prefix': 'sidebar'
+    'body': '.. sidebar:: ${1:title}\n\n\t$0'
+  'table directive':
+    'prefix': 'table'
+    'body': '.. table:: ${1:title}\n\n\t$0'
+  'tip directive':
+    'prefix': 'tip'
+    'body': '.. tip::\n\n\t'
+  'toctree directive':
+    'prefix': 'toctree'
+    'body': '.. toctree::\n\t:maxdepth: ${1:2}\n\n\t$0'
+  'topic directive':
+    'prefix': 'topic'
+    'body': '.. topic:: ${1:title}'
+  'warning directive':
+    'prefix': 'warning'
+    'body': '.. warning::\n\n\t'
+
+
+  # Roles
+  'abbr role':
+    'prefix': 'abbr'
+    'body': ':abbr:`$0`'
+  'code role':
+    'prefix': 'code'
+    'body': ':code:`$0`'
+  'download role':
+    'prefix': 'download'
+    'body': ':download:`${1:/path/to/file}`'
+  'file role':
+    'prefix': 'file'
+    'body': ':file:`${1:/path/to/file}`'
+  'guilabel role':
+    'prefix': 'guilabel'
+    'body': ':guilabel:`${1:&Cancel}`'
+  'math role':
+    'prefix': 'math'
+    'body': ':math:`$0`'
+  'ref role':
+    'prefix': 'ref'
+    'body': ':ref:`$0`'
+  'menuselection role':
+    'prefix': 'menuselection'
+    'body': ':menuselection:`${1:menu item} --> ${2:submenu item}`'
+  'program role':
+    'prefix': 'program'
+    'body': ':program:${1:<executable file>}'
+
+
   'link':
     'prefix': 'link'
-    'body': '\\`${1:Title} <${2:http://link}>\\`_$0'
+    'body': '`${1:Title} <${2:http://link}>`_$0'
+
+  # Sectioning
   'section 1':
     'prefix': 'sec'
     'body': '${1:subsection name}\n================$0\n'
@@ -14,6 +152,3 @@
   'section 3':
     'prefix': 'sss'
     'body': '${1:subsection name}\n----------------$0\n'
-  'code block':
-    'prefix': 'code'
-    'body': '.. code-block:: ${1:language}\n\n\t${2:<code>}'


Return Vegan slideshow

Return Vegan slideshow

--- source/assets/javascripts/app.js.coffee
+++ source/assets/javascripts/app.js.coffee
@@ -69,15 +69,40 @@

     timeout = setTimeout restart, restartDelay

-    elementToMove.mouseover ->
-      clearTimeout(timeout)
-      title.attr { opacity: 0, transform: 'translate('+item.final+') scale('+scale.final+')'  }
-      title.animate { opacity: 1 }, 150, mina.linear
+    elementToMove.click ->
+      Snap.load '/assets/images/vegan-sans-show-room.svg', (canvas) ->
+        snap.clear()

-    title.mouseout ->
-      timeout = setTimeout restart, 1000
-      title.stop()
-      title.attr { opacity: 0, transform: 'translate('+item.final+') scale('+scale.final+')' }
+        show = canvas.select 'g#VeganSans'
+        snap.append show
+
+        slide = show.selectAll('g#canvas > g#slide-1').attr(transform: 'translate(-'+width+', 0)')
+        show.selectAll('g#canvas > g#slide-2').attr(transform: 'translate(80, '+height+')')
+
+        hideSlide = ->
+          show.select('g#canvas > g#slide-1').animate { transform: 'translate(80, -'+height+')' }, 750, mina.easein
+          show.select('g#canvas > g#slide-2').animate { transform: 'translate(80, 120)' }, 750, mina.easein, ->
+            setTimeout(
+              ->
+                show.selectAll('g#slide-2 path')[1].animate { transform: 'translate(80, '+height+')' }, 350
+                show.selectAll('g#slide-2 path')[0].animate { transform: 'scale(2)' }, 350
+              , 350)
+
+        showSlide = ->
+          slide.animate { transform: 'translate(80 0)' }, 1000, mina.easeout
+
+        setTimeout showSlide, 50
+        setTimeout hideSlide, 2950
+
+    # elementToMove.mouseover ->
+    #   clearTimeout(timeout)
+    #   title.attr { opacity: 0, transform: 'translate('+item.final+') scale('+scale.final+')'  }
+    #   title.animate { opacity: 1 }, 150, mina.linear
+
+    # title.mouseout ->
+    #   timeout = setTimeout restart, 1000
+    #   title.stop()
+    #   title.attr { opacity: 0, transform: 'translate('+item.final+') scale('+scale.final+')' }

   returnButtons = (element, item, callback) ->
     element.animate { transform: 'translate('+item.initial+') scale('+scale.initial+')' }, item.speed/2, mina.easeout, ->
@@ -104,30 +129,6 @@
     styles.addClass('visible')
     $.scrollTo(styles, 'max')
   $('.fonts').css { opacity: 1 }
-    # elementToMove.click ->
-    #   Snap.load '/assets/images/vegan-sans-show-room.svg', (canvas) ->
-    #     snap.clear()
-
-    #     show = canvas.select 'g#VeganSans'
-    #     snap.append show
-
-    #     slide = show.selectAll('g#canvas > g#slide-1').attr(transform: 'translate(-'+width+', 0)')
-    #     show.selectAll('g#canvas > g#slide-2').attr(transform: 'translate(80, '+height+')')
-
-    #     hideSlide = ->
-    #       show.select('g#canvas > g#slide-1').animate { transform: 'translate(80, -'+height+')' }, 750, mina.easein
-    #       show.select('g#canvas > g#slide-2').animate { transform: 'translate(80, 120)' }, 750, mina.easein, ->
-    #         setTimeout(
-    #           ->
-    #             show.selectAll('g#slide-2 path')[1].animate { transform: 'translate(80, '+height+')' }, 350
-    #           , 300)
-
-    #     showSlide = ->
-    #       slide.animate { transform: 'translate(80 0)' }, 1000, mina.easeout
-
-    #     setTimeout showSlide, 50
-    #     setTimeout hideSlide, 2950
-

 showFontList()


Update hall output

Update hall output

--- plugins/hall/index.coffee
+++ plugins/hall/index.coffee
@@ -16,16 +16,28 @@
   # Gets the body of the chat message
   @messageBody: Handlebars.compile(
     '{{#if error.message}}' +
-      '{{error.message}} (details)' +
+      '   {{error.exceptionClass}}: {{error.message}} (details)' +
+      '{{#if stack_trace_line}}
   {{stack_trace_line}}{{/if}}' +
     '{{else}}' +
       '{{trigger.message}} from {{project.name}}' +
     '{{/if}}'
   )

+  @messageTitle: Handlebars.compile(
+    '{{trigger.message}} in {{error.releaseStage}} from {{project.name}}' +
+    '{{#if error}}' +
+      ' in {{error.context}}' +
+    '{{/if}}'
+  )
+
   # Build the request body
   @messagePayload = (config, event) ->
-    title: @title event
-    message: @messageBody event
+    title: @messageTitle event
+    message: @messageBody
+      error: event.error
+      stack_trace_line: event.error.stacktrace && @firstStacktraceLine(event.error.stacktrace)
+      trigger: event.trigger
+      project: event.project
     picture: BUGSNAG_AVATAR

   # Fire the event
@@ -39,4 +51,4 @@
       .end (res) ->
         callback res.error if res.error or null

-module.exports = Hall+module.exports = Hall


Require mongo, so command actually works

--- server/lib/tasks/import-gdoc-indicator.coffee
+++ server/lib/tasks/import-gdoc-indicator.coffee
@@ -1,3 +1,4 @@
+require('../../initializers/mongo')()
 GDocIndicatorImporter = require '../gdoc_indicator_importer'
 readline = require('readline')


return recurring events as single events

--- src/google-calendar.coffee
+++ src/google-calendar.coffee
@@ -85,6 +85,7 @@
         timeMin: now
         timeMax: in24
         calendarId: gcal[userId].calendarId
+        singleEvents: true
       callback: (err, data)->
         return console.log(err) if err
         console.log data.items


Don't build a profile for no user

Don't build a profile for no user

--- app/controllers/profile.coffee
+++ app/controllers/profile.coffee
@@ -22,6 +22,7 @@
     @opts =
       per_page: 12
     User.bind 'sign-in', =>
+      return unless User.current
       @pages =
         recents: Math.ceil (User.current.classification_count / @opts.per_page) or 1
         favorites: Math.ceil (User.current.favorites / @opts.per_page) or 1


Use zoolib profile

Use zoolib profile

--- app/controllers/profile.coffee
+++ app/controllers/profile.coffee
@@ -1,112 +1,13 @@
 {Controller} = require 'spine'
-template = require '../views/profile'
-LoginForm = require 'zooniverse/controllers/login-form'
-User = require 'zooniverse/models/user'
-Favorite = require 'zooniverse/models/favorite'
-Recent = require 'zooniverse/models/recent'
-itemTemplate = require '../views/profile_item'
+Profile = require 'zooniverse/controllers/profile'

-class Profile extends Controller
+class ProfilePage extends Controller
   className: 'profile'
-
-  itemPages: null
-
-  events:
-    'click button[name="turn-page"]': 'onClickPageButton'
-    'click button[name="delete"]': 'onClickDelete'
-    'click button[name="load-more"]': 'onClickLoadMore'
-
-  elements:
-    '.sign-in': 'signInContainer'
-    'nav button': 'navButtons'
-    '.page': 'pages'
-    '.favorites ul': 'favoritesList'
-    '.recents ul': 'recentsList'

   constructor: ->
     super

-    @html template
-    @loginForm = new LoginForm el: @signInContainer
+    @profile ?= new Profile
+    @html @profile.el

-    User.on 'sign-in', @onUserSignIn
-
-    Favorite.on 'create destroy', @onItemCreateDestroy
-    Favorite.on 'send', @onCreateItem
-    Favorite.on 'is-new', @onMarkNew
-
-    Recent.on 'create destroy', @onItemCreateDestroy
-    Recent.on 'send', @onCreateItem
-    Recent.on 'is-new', @onMarkNew
-
-    @navButtons.first().click()
-    @onUserSignIn()
-
-  onClickPageButton: ({currentTarget}) ->
-    @navButtons.add(@pages).removeClass 'active'
-
-    value = $(currentTarget).val()
-    page = @pages.filter ".#{value}"
-    button = @navButtons.filter "[value='#{value}']"
-
-    button.add(page).addClass 'active'
-
-  onClickDelete: ({currentTarget}) ->
-    item = $(currentTarget).parent("[data-item]")
-    id = item.attr 'data-item'
-    Favorite.find(id).unfavorite()
-
-  onClickLoadMore: ({currentTarget}) ->
-    ItemClass = switch $(currentTarget).val()
-      when 'favorite' then Favorite
-      when 'recent' then Recent
-
-    @loadMore ItemClass
-
-  onUserSignIn: =>
-    @el.toggleClass 'signed-in', !!User.current
-
-    for ItemClass in [Favorite, Recent]
-      ItemClass.first().destroy() until ItemClass.count() is 0
-
-    @itemPages = {}
-
-    if User.current
-      @loadMore Favorite
-      @loadMore Recent
-
-  onItemCreateDestroy: (item) =>
-    ItemClass = item.constructor
-    className = ItemClass.className.toLowerCase()
-    hasItems = ItemClass.count() isnt 0
-
-    @el.toggleClass "has-#{className}s", hasItems
-
-    loadMoreButton = @el.find "button[name='load-more'][value='#{className}']"
-    loadMoreButton.attr disabled: not hasItems
-
-  onCreateItem: (item) =>
-    #TODO what is item, use bind() or on()
-
-    list = @["#{item.constructor.className.toLowerCase()}sList"]
-    return unless list.find("[data-item='#{item.id}']").length is 0
-
-    item = $(itemTemplate item)
-    item.bind 'destroy', -> item.remove()
-    item.appendTo list
-
-  onMarkNew: (item) =>
-    item = @el.find "[data-item='#{item.id}']"
-    item.prependTo item.parent()
-    item.addClass 'new'
-
-  loadMore: (ItemClass) ->
-    @itemPages[ItemClass.className] ?= 0
-    @itemPages[ItemClass.className] += 1
-    fetch = ItemClass.fetch(page: @itemPages[ItemClass.className], per_page: 8).deferred
-    fetch.done => @onFetchItems ItemClass
-
-  onFetchItems: (ItemClass) =>
-    @onCreateItem item for item in ItemClass.all()
-
-module.exports = Profile+module.exports = ProfilePage


cancel sort event if a module is offscreen

--- app/static/scripts/room.coffee
+++ app/static/scripts/room.coffee
@@ -245,6 +245,12 @@
     sortableMod         : () =>
         $('#modArea').sortable({
             containment: '#modArea',
+            receive: (event, ui) ->
+                $('.module').each () ->
+                    pos = { t: (do $(this).offset).top, l: (do $(this).offset).left, h: do $(this).height, w: do $(this).width, docH: do $(window).height, docW: do $(window).width }
+                    visible = (pos.t > 0 && pos.l > 0 && pos.t + pos.h < pos.docH && pos.l + pos.w < pos.docW)
+                    if !visible
+                        $(ui.sender).sortable 'cancel'
             stop: (event, ui) ->
                 draggedItemId = '#' + ui.item.attr 'id'
                 prevItem = do ui.item.prev


set fictional 100x100 value

set fictional 100x100 value

--- app/utils/connector-rfb.coffee
+++ app/utils/connector-rfb.coffee
@@ -30,6 +30,10 @@
         true

     @rfb.connect ENV.deviceFarmHost, ENV.deviceFarmPort, '1234', "#{ENV.deviceFarmPath}?token=#{@deviceToken}"
+    if @rfb.get_display
+      display = @rfb.get_display
+      scaleRatio = display.autoscale 100, 100, true
+      @rfb.get_mouse().set_scale scaleRatio

   disconnect: ->
     @rfb.disconnect()


extract and name callbacks in db module

extract and name callbacks in db module

--- backend/db.coffee
+++ backend/db.coffee
@@ -34,30 +34,38 @@
                 all:
                     map: map

-        db.get id, (err, currentDesignDoc) ->
+        checkCreation = (err, res) ->
+            if err?
+                if err.status is 409
+                    callback null
+                else
+                    callback err
+            else
+                if not currentDesignDoc?
+                    log.info "Design document created: #{id}"
+                callback null
+
+        createDesignDoc = (err, currentDesignDoc) ->
             if currentDesignDoc?
                 newDesignDoc._rev = currentDesignDoc._rev
-            db.put newDesignDoc, (err, res) ->
-                if err?
-                    if err.status is 409
-                        callback null
-                    else
-                        callback err
-                else
-                    if not currentDesignDoc?
-                        log.info "Design document created: #{id}"
-                    callback null
+            db.put newDesignDoc, checkCreation
+
+        db.get id, createDesignDoc

     removeFilter: (docType, callback) ->
         id = "_design/#{docType.toLowerCase()}"

-        db.get id, (err, currentDesignDoc) ->
+        checkRemove = (err, res) ->
+            if err?
+                callback err
+            else
+                callback null
+
+        removeDesignDoc = (err, currentDesignDoc) ->
             if currentDesignDoc?
-                db.remove id, currentDesignDoc._rev, (err, res) ->
-                    if err?
-                        callback err
-                    else
-                        callback null
+                db.remove id, currentDesignDoc._rev, checkRemove
             else
                 log.info "Design document does not exist: #{id}"
                 callback null
+
+        db.get id, removeDesignDoc


Update batman.coffee

Update batman.coffee

removed test on bat signal

--- src/scripts/batman.coffee
+++ src/scripts/batman.coffee
@@ -51,7 +51,6 @@
       msg.send "#{url}"

   robot.hear /call batman!/i, (msg) ->
-    msg.reply 'bat signal test'
     batsignal = "bat signal"
     imageMe msg, batsignal, (url) ->
       msg.send "#{url}"


[Boyscouting] Fixed whitespaces and indentation

--- src/scripts/routes.coffee
+++ src/scripts/routes.coffee
@@ -1,10 +1,10 @@
 angular.module('app').config ['$routeProvider', ($routeProvider) ->
-	$routeProvider
-	.when '/1',
-    templateUrl: '/views/visual1.html'
-    controller: 'tweetController'
-  .when '/2',
-    templateUrl: '/views/visual2.html'
+  $routeProvider
+    .when '/1',
+      templateUrl: '/views/visual1.html'
+      controller: 'tweetController'
+    .when '/2',
+      templateUrl: '/views/visual2.html'
 #	.when '/people/:id',
 #		controller: 'personDetailsController'
 #		reloadOnSearch: true


:clap: Forgot to remove old code

:clap: Forgot to remove old code

--- app/assets/js/shared.coffee
+++ app/assets/js/shared.coffee
@@ -1,20 +1,3 @@
-#$ ->
-#  # Display javascript only tags
-#  $('.javascript-only').removeClass('javascript-only')
-#
-#  # Remove noscript tags for the lulz
-#  $('noscript').remove()
-
-#(function(d){
-#	var a = d.getElementsByClassName('javascript-only');
-#	for(var i=0; i<a.length; ++i){
-#		a[i].className = a[i].className.replace('javascript-only', '');
-#	}
-#	a = document.getElementsByTagName('noscript');
-#	for(i=0; i<a.length; ++i){
-#		(a[i].parentNode || a[i].parentElement).removeChild(a[i]);
-#	}
-#})(document);
 ((d) ->
   a = d.getElementsByClassName('javascript-only')
   i = 0


fix(web): Fixing manifest files

fix(web): Fixing manifest files

--- apps/actor-web/gulpfile.coffee
+++ apps/actor-web/gulpfile.coffee
@@ -108,7 +108,7 @@
     .pipe connect.reload()

 gulp.task 'manifest', ->
-  gulp.src ['./dist/*']
+  gulp.src ['./dist/**/*']
     .pipe manifest {
       hash: true,
       preferOnline: true,


Avoid highlighting leading digits in date strings


Dedupe reference to LilyPond grammar

Dedupe reference to LilyPond grammar

References: github/linguist#3924, yrammos/AtLilyPond#7.

--- grammars/roff.cson
+++ grammars/roff.cson
@@ -2731,10 +2731,7 @@
 				1: name: "punctuation.definition.macro.roff"
 				2: name: "entity.function.name.roff"
 				3: name: "constant.language.embedding-control.roff"
-			patterns: [
-				{include: "source.AtLilyPond"}
-				{include: "source.lilypond"}
-			]
+			patterns: [include: "source.lilypond"]
 		},{
 			# Pinyin (GNU)
 			begin: "^([.'])[ \t]*(pinyin)[ \t]+(begin|start)(?=\\s|\\\\[\"#])(.*)$"


Radio: Code styling.

Radio: Code styling.

--- src/tests/components/inputs/test_radio.coffee
+++ src/tests/components/inputs/test_radio.coffee
@@ -24,4 +24,4 @@

   it 'should be type radio', ->
-    expect(radio.getAttribute('type')).toBe 'radio'+    expect(radio.getAttribute('type')).toBe 'radio'


add a max width

add a max width

--- app/lib/canvas-graph.coffee
+++ app/lib/canvas-graph.coffee
@@ -98,6 +98,7 @@

 class Mark
   MIN_WIDTH = 10
+  MAX_WIDTH = 150

   constructor: (e, @canvasGraph) ->
     #TODO: make an active state
@@ -128,10 +129,12 @@
     markLeftX = Math.min @startingPoint, e.x
     markRightX = Math.max @startingPoint, e.x

+    width = (Math.min (Math.max (Math.abs markRightX - markLeftX), MIN_WIDTH), MAX_WIDTH)
+
     @element.style.left = (Math.min markLeftX, markRightX) + "px"
-    @element.style.width = (Math.max (Math.abs markRightX - markLeftX), MIN_WIDTH) + "px"
+    @element.style.width = width + "px"

-    @save(markLeftX, markRightX)
+    @save(markLeftX, markLeftX+width)

   move: (e) ->
     leftXPos = (e.x-@pointerOffset)


... Added autofetch support on the server

--- src/server/session.coffee
+++ src/server/session.coffee
@@ -190,15 +190,26 @@
             callback null, {a:'ack'}

       when 'q'
+        autoFetch = query.f
         agent.query query.c, query.q, (err, results) ->
           callback err if err

           id = query.id
           # Results.data contains the initial query result set
+          for doc, data of results.data
+            if autoFetch
+              # The data object has the snapshot called 'data'. I need to make this consistent.
+              data.snapshot = data.data
+            delete data.data
+
           callback null, id:id, data:results.data

           results.on 'add', (docName) ->
-            send a:'q', id:id, add:docName
+            data = results.data[docName]
+            data.doc = docName
+            data.snapshot = data.data if autoFetch
+            delete data.data
+            send a:'q', id:id, add:data
           results.on 'remove', (docName) ->
             send a:'q', id:id, rm:docName


image preview fix

image preview fix

--- app/assets/javascripts/app/gallery/popup.coffee
+++ app/assets/javascripts/app/gallery/popup.coffee
@@ -61,7 +61,7 @@

   _centerImage : () =>
     heightWithouImage = @$window.height() - @$galleryPopup.find('.popup-gallery-img').outerHeight()
-    @$galleryPopup.find('.popup-gallery-item').css 'margin-top', heightWithouImage / 2 - @$galleryPopup.position().top
+    @$galleryPopup.find('.popup-gallery-item').css 'margin-top', Math.max(0, heightWithouImage / 2 - @$galleryPopup.position().top)

   close : (e) ->
     e.preventDefault()


Make sure input field containing svg annotation is updated before form submit

--- app/assets/javascripts/image_question.js.coffee
+++ app/assets/javascripts/image_question.js.coffee
@@ -46,11 +46,14 @@

     @$done_button.click =>
-      hidden = $("#{@form_sel} [name=\"embeddable_image_question_answer[image_url]\"]")
-      hidden.val(@current_src)
-      @$done_button.parents("form:first").submit()
-      @hide()
-      @save()
+      svgCanvas.embeddable_image_question_answer_annotation.getSvgString() (data, error) =>
+        $input = $('#embeddable_image_question_answer_annotation')
+        $input.attr("value", sketchily_encode64("<?xml version=\"1.0\"?>\n" + data));
+        hidden = $("#{@form_sel} [name=\"embeddable_image_question_answer[image_url]\"]")
+        hidden.val(@current_src)
+        @$done_button.parents("form:first").submit()
+        @hide()
+        @save()

     @$delete_button.click =>
       @delete_image()


commenting out missing image alert

commenting out missing image alert

--- app/assets/javascripts/mobile/_mobile.js.coffee
+++ app/assets/javascripts/mobile/_mobile.js.coffee
@@ -68,7 +68,7 @@
                 store_slug: store_slug
             success: (response) =>
                 if response.status is 'error'
-                    alert 'i don\'t know what to do yet'
+                    #alert 'i don\'t know what to do yet'
                 else
                     callback($self, response.product_images)


cliente now includes PersonImagen

cliente now includes PersonImagen

--- app/assets/javascripts/models/cliente.js.coffee
+++ app/assets/javascripts/models/cliente.js.coffee
@@ -1,4 +1,4 @@
-Bandango.Cliente = DS.Model.extend
+Bandango.Cliente = DS.Model.extend Bandango.PersonImagen,
   tipoId: DS.attr()
   identificacion: DS.attr()
   nombres: DS.attr()


fix: Retrieving coordinates of path

fix: Retrieving coordinates of path

--- app/assets/javascripts/widgets/direction.coffee
+++ app/assets/javascripts/widgets/direction.coffee
@@ -150,12 +150,12 @@

     while (k = keys.pop()) isnt undefined

-      if patterns.push.test k
+      if patterns.push.test k
         re = new RegExp("\\[#{k}\\]$")
         reverse_key = reverse_key.replace re, ''
         merge = @build [], @push_counter(reverse_key), merge

-      else if patterns.fixed.test k
+      else if patterns.fixed.test k
         merge = @build [], k, merge

       else if patterns.named.test k
@@ -181,7 +181,7 @@
     if status == google.maps.DirectionsStatus.OK
       FOUND_ROUTE = route = result.routes[0]
       route.path = route.overview_path.map (o) ->
-        latitude: o.Ya, longitude: o.Za
+        latitude: o.kb, longitude: o.lb

       gmap.directionsRenderer.setDirections(result)
       gmap.onNextMovement -> callback(route)


added reactive state property to the upload instance object returned by files.insert()

--- files.coffee
+++ files.coffee
@@ -781,8 +781,10 @@
           continueFrom: []
           pause: () ->
             @onPause.set true
+            @state.set "paused"
           continue: () ->
             @onPause.set false
+            @state.set "active"
             func.call null for func in @continueFrom
             @continueFrom = []
           toggle: () ->
@@ -792,8 +794,10 @@
             window.removeEventListener "beforeunload", beforeunload, false
             onAbort and onAbort.call file, fileData
             @pause()
+            @state.set "aborted"
             Meteor.call self.methodNames.MeteorFileAbort, randFileName, streams, file
             delete upload
+          state: new ReactiveVar "active"

         result.progress.set = _.throttle result.progress.set, 250

@@ -844,6 +848,8 @@
           console.timeEnd('insert') if self.debug
           window.removeEventListener "beforeunload", beforeunload, false
           result.progress.set 0
+          if !error
+            result.state.set "completed"
           onUploaded and onUploaded.call self, error, data

         if onBeforeUpload and _.isFunction onBeforeUpload


fix grouping

fix grouping

--- collections/feed.coffee
+++ collections/feed.coffee
@@ -62,10 +62,41 @@
       model.user? && model.item?

     groups = _.groupBy items, (model) ->
-      if model.action is 'commented on' or model.action is 'mentioned you'
-        "#{model.user?.id}_#{model.target?.id}_#{model.item.id}"
+      if model.action is 'commented on'
+        "#{model.user?.id}_#{model.target?.id}_#{model.created_at}"
       else
         "#{model.user?.id}_#{model.target?.id}_#{model.action}"
+
+    # Split group into multiple groups if there is a gap
+    # of more than an hour between the creation of any
+    # two items when ordered by date
+    splitGroups = []
+    _.each groups, (group)->
+
+      # Sort group by date internally
+      group = _.sortBy group, (model)->
+        - new Date model.created_at
+
+      # Iterate over each element, checking for big gaps
+      workingGroup = []
+      prevDateVal = null
+      _.each group, (model)->
+        dateVal = new Date model.created_at
+
+        # Split the group if there's a big gap between items
+        if prevDateVal and (dateVal - prevDateVal) > (60 * 60)
+          splitGroups.push workingGroup
+          workingGroup = []
+        workingGroup.push model
+        prevDateVal = dateVal
+
+      splitGroups.push workingGroup
+
+    groups = _.sortBy splitGroups, (group)=>
+      group = _.sortBy group, (model)->
+        - new Date model.created_at
+
+      - new Date group[0].created_at

     groups = _.map groups, (group) ->
       _.map group, (item) -> new FeedItem(item)


Break excerpt on blockquotes too

Break excerpt on blockquotes too

--- collections/post.coffee
+++ collections/post.coffee
@@ -42,7 +42,7 @@

   @excerpt: (html) ->
     # Find 1st non-empty paragraph
-    matches = html.split /<\/div>|<\/p>|

|\\n\\n|\\r\\n\\r\\n/m
+    matches = html.split /<\/div>|<\/p>|<\/blockquote>|

|\\n\\n|\\r\\n\\r\\n/m

     i = 0
     ret = ''


Footer: jobs fixed

Footer: jobs fixed

--- client/Main/CommonViews/footerview.coffee
+++ client/Main/CommonViews/footerview.coffee
@@ -26,12 +26,11 @@

COMPANY

-        ABOUT KODING
-        JOBS
         KODING UNIVERSITY
+        JOBS
+        TERMS AND CONDITIONS
+        PRIVACY POLICY
         CONTACT US
-        TERMS AND CONDITIONS
-        PRIVACY POLICY
         STATUS


add locaiton to payments

add locaiton to payments

--- client/skr/screens/payments/Payments.cjsx
+++ client/skr/screens/payments/Payments.cjsx
@@ -36,11 +36,12 @@
                     commands={@state.commands} model={@category}
                     label='Payment ID' name='visible_id' model={@payment} query={@query}
                 />
-                <SC.BankAccountFinder smOffset=1 selectField name='bank_account'
+                <SC.LocationChooser hideSingle label='Location' sm=2 model={@payment} />
+                <SC.BankAccountFinder selectField name='bank_account'
                     model={@payment} />
                 <SC.PaymentCategoryFinder selectField name='category' labelField='code'
                     model={@payment} />
-                <LC.DateTime smOffset=1 name='date' format='ddd, MMM Do YYYY'
+                <LC.DateTime name='date' format='ddd, MMM Do YYYY'
                     sm=3 model={@payment} />
             </BS.Row>
             <BS.Row>


TravisCI: testing success

TravisCI: testing success

--- src/knockback_utils.coffee
+++ src/knockback_utils.coffee
@@ -101,9 +101,9 @@
   kb.utils.legacyWarning('kb.vmRelease', '0.16.0', 'Please use kb.utils.release instead')
   return kb.utils.release(view_model)

-# kb.vmReleaseObservable = (observable) ->
-#   kb.utils.legacyWarning('kb.vmReleaseObservable', '0.16.0', 'Please use kb.utils.release instead')
-#   return kb.utils.release(observable)
+kb.vmReleaseObservable = (observable) ->
+  kb.utils.legacyWarning('kb.vmReleaseObservable', '0.16.0', 'Please use kb.utils.release instead')
+  return kb.utils.release(observable)

 kb.utils.optionsCreateClear = (options) ->
   delete options['create']


fix: stop execution on error (expl. return)

--- src/queues/ironmq.coffee
+++ src/queues/ironmq.coffee
@@ -92,7 +92,7 @@
         if err
           logger.warn "IVY_WARNING Cannot decrypt task from IronMQ", err
           @manager.emit 'mqError', err
-          cb(err)
+          return cb(err)

         if decryptedBody
           try
@@ -101,13 +101,13 @@
             logger.error "IVY_IRONMQ_ERROR Can't JSON.parse decryptedBody in parseEncryptedTask", e
         else
           return cb new Error "IVY_IRONMQ_ERROR Missing encryptionKey"
-        cb()
+        return cb()
     else
       try
         scheduledTasks[task.id] = JSON.parse task.body
       catch e
         logger.error "IVY_IRONMQ_ERROR Can't JSON.parse body in parseEncryptedTask", e
-      cb()
+      return cb()

   getScheduledTasks: (options, cb) ->
     if typeof options is 'function'


PLATEFORM increase embed preview height

PLATEFORM increase embed preview height

--- app/assets/javascripts/platform/views/embed_form_view.js.coffee
+++ app/assets/javascripts/platform/views/embed_form_view.js.coffee
@@ -31,7 +31,7 @@
     params = ""
     params += "/?tagIds=#{tagIds.join(',')}" if tagIds

-    iframeCode = ""
+    iframeCode = ""

     @$('#preview').html @templates.preview(iframeCode: iframeCode)


Add comment

Add comment

--- src/scripts/models/content.coffee
+++ src/scripts/models/content.coffee
@@ -64,7 +64,7 @@
           # Determine if the item is a subcollection or a page
           if item.contents
             item.subcollection = true
-            delete item.id
+            delete item.id # Get rid of the 'subcol' id so the subcollection is unique
             depth++
             traverse(item)
           else
@@ -80,7 +80,7 @@
       return response

     initialize: (options = {}) ->
-      @set('toc', new Backbone.Collection())
+      @set('toc', [])
       @fetch
         success: () => @load(options.page)


Fixing probable memory leak

Fixing probable memory leak

--- gulp/server.coffee
+++ gulp/server.coffee
@@ -62,6 +62,7 @@
       cp.kill('SIGINT')
       # cp = null
       callback() if callback
+      process.removeListener 'SIGINT', fullStop

     fullStop = ->
       cp.stop() if cp


Removed splice call from hound slash command parsing

--- src/scripts/hound.coffee
+++ src/scripts/hound.coffee
@@ -152,7 +152,7 @@
           comps = [comps.join(' ')]
         comps.push(comps[0])
         comps[0] = 'self'
-      action = comps[1]?.splice() || 'info'
+      action = comps[1] || 'info'
       console.log scope
       console.log action


Don't add/remove roles for empty names.

Don't add/remove roles for empty names.

trim() name before checking if it matches '', and check on role
removal as well as add.

--- src/scripts/roles.coffee
+++ src/scripts/roles.coffee
@@ -35,7 +35,7 @@
         msg.send "#{name}? Never heard of 'em"

   robot.respond /@?([\w .-_]+) is (["'\w: -_]+)[.!]*$/i, (msg) ->
-    name    = msg.match[1]
+    name    = msg.match[1].trim()
     newRole = msg.match[2].trim()

     unless name in ['', 'who', 'what', 'where', 'when', 'why']
@@ -59,10 +59,10 @@
           msg.send "I don't know anything about #{name}."

   robot.respond /@?([\w .-_]+) is not (["'\w: -_]+)[.!]*$/i, (msg) ->
-    name    = msg.match[1]
+    name    = msg.match[1].trim()
     newRole = msg.match[2].trim()

-    unless name in ['who', 'what', 'where', 'when', 'why']
+    unless name in ['', 'who', 'what', 'where', 'when', 'why']
       users = robot.usersForFuzzyName(name)
       if users.length is 1
         user = users[0]


Social: remove optional slug param for first /Activity/slug clause

--- client/Social/Activity/routes.coffee
+++ client/Social/Activity/routes.coffee
@@ -49,7 +49,7 @@
     '/:name?/Activity/Chat/:slug?' : ({params:{name, slug}, query}) ->
       handleChannel 'chat', slug

-    '/:name?/Activity/:slug?' : ({params:{name, slug}, query}) ->
+    '/:name?/Activity/:slug' : ({params:{name, slug}, query}) ->
       handleChannel 'post', slug

     '/:name?/Activity' : ({params:{name, slug}, query}) ->


Terminal: AppController: Remove preCondition logic from AppController, AppView will handle this

--- client/Terminal/AppController.coffee
+++ client/Terminal/AppController.coffee
@@ -21,33 +21,6 @@
         {title: "customViewAdvancedSettings"}
       ]
     behavior     : "application"
-    preCondition :
-      condition  : (options, cb)->
-        {vmName} = options
-
-        KD.mixpanel "Click open Webterm", vmName
-
-        vmController = KD.getSingleton 'vmController'
-        vmController.fetchDefaultVmName (defaultVmName)->
-          vmName or= defaultVmName
-          return cb no  unless vmName
-          vmController.info vmName, KD.utils.getTimedOutCallback (err, vm, info)->
-            cb  info?.state is 'RUNNING', {vmName, info}
-            KD.mixpanel "Opened Webterm", vmName
-          , ->
-            cb no
-            unless KD.isGuest()
-              KD.logToExternal "failed to fetch vminfo, couldn't open terminal"
-          , 2500
-
-      failure     : (options, cb)->
-        {vmName} = options
-        KD.mixpanel "Can't open Webterm", {vmName}
-        KD.getSingleton("vmController").askToTurnOn
-          appName : 'Terminal'
-          vmName  : options.vmName
-          state   : options.info.state
-        , cb

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


Client: All links must be its own word.

Client: All links must be its own word.

--- client/app/js/views/chat_view.coffee
+++ client/app/js/views/chat_view.coffee
@@ -143,7 +143,8 @@
   # Escapes all HTML, but also converts links to clickable links.
   sanitize: (message) =>
     sanitizedMessage = $('
').text(message).html()
-    sanitizedMessage = sanitizedMessage.replace(/(https?:\/\/\S+\.\S+)/g,
+    sanitizedMessage = sanitizedMessage.replace(
+      /\b(https?:\/\/\S+\.\S+)\b/g,
       """$1""")
     sanitizedMessage


support: add kd.impersonate for impersonator flag owners

--- client/app/lib/maincontroller.coffee
+++ client/app/lib/maincontroller.coffee
@@ -150,6 +150,7 @@
       kd.registerSingleton 'onboardingController',    new OnboardingController

       @emit 'AppIsReady'
+      @prepareSupportShortcuts()

       console.timeEnd 'Koding.com loaded'

@@ -357,6 +358,11 @@
     idleDetector = new IdleUserDetector { threshold }
     @forwardEvents idleDetector, ['userIdle', 'userBack']

+  prepareSupportShortcuts: ->
+
+    return  unless checkFlag ['super-admin']
+
+    kd.impersonate = require './util/impersonate'

   startCachingAssets:->


Refer to location property of global object

--- client/app/lib/maincontroller.coffee
+++ client/app/lib/maincontroller.coffee
@@ -275,7 +275,7 @@
       cookieMatches     = cookie is (kookies.get 'clientId')

       if not cookieExists or (cookieExists and not cookieMatches)
-        location.reload '/'
+        global.location.reload '/'

       kd.utils.wait 1000, cookieChangeHandler


Submit login attempt when enter key is pressed

--- client/lanes/access/LoginDialog.cjsx
+++ client/lanes/access/LoginDialog.cjsx
@@ -19,7 +19,7 @@
                     onCancel: onCancel, onOk: onOk, show: true,
                     buttons: [{ title: 'Ok', style: 'primary'}]
                     body: Lanes.u.withReactContext({viewport: viewport}, ->
-                        <Lanes.Access.LoginDialog model={session} />
+                        <Lanes.Access.LoginDialog model={session} attemptLogin={onOk} />
                     )
                 )
             )
@@ -27,8 +27,7 @@
                 session.save(ignoreErrors: true).then ->
                     if session.user
                         Lanes.current_user.setLoginData(session.user, session.access)
-                    else
-                        dlg.setState(show:true)
+                    _.extend(viewport.modalProps, {show: !session.user})

     mixins: [
         Lanes.React.Mixins.RelayEditingState
@@ -54,6 +53,7 @@

                     <LC.Input
                         model={@model}
+                        onEnter={@props.attemptLogin}
                         autoFocus writable
                         name="login"
                         label='Username'
@@ -63,6 +63,7 @@
                     <LC.Input
                         writable
                         model={@model}
+                        onEnter={@props.attemptLogin}
                         name="password"
                         type='password'
                         label='Password'


Change messagePopup regex to accept all non-whitespace

Addresses #1141

--- client/views/app/messagePopup.coffee
+++ client/views/app/messagePopup.coffee
@@ -44,13 +44,13 @@
 	template.suffix = val(template.data.suffix, ' ')

 	if template.triggerAnywhere is true
-		template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^| )#{template.trigger}[A-Za-z0-9-_.]*$")
+		template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^| )#{template.trigger}[^\s]*$")
 	else
-		template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^)#{template.trigger}[A-Za-z0-9-_.]*$")
-
-	template.selectorRegex = val(template.data.selectorRegex, new RegExp "#{template.trigger}([A-Za-z0-9-_.]*)$")
-
-	template.replaceRegex = val(template.data.replaceRegex, new RegExp "#{template.trigger}[A-Za-z0-9-_.]*$")
+		template.matchSelectorRegex = val(template.data.matchSelectorRegex, new RegExp "(?:^)#{template.trigger}[^\s]*$")
+
+	template.selectorRegex = val(template.data.selectorRegex, new RegExp "#{template.trigger}([^\s]*)$")
+
+	template.replaceRegex = val(template.data.replaceRegex, new RegExp "#{template.trigger}[^\s]*$")

 	template.getValue = val template.data.getValue, (_id) -> return _id


「gulpfile.coffee」を生成する処理を追加

「gulpfile.coffee」を生成する処理を追加

--- bin/lamjet.coffee
+++ bin/lamjet.coffee
@@ -65,5 +65,35 @@
   console.log gitignore
   console.log gitignorePath
   fs.writeFileSync(gitignorePath, gitignore + "\n", encoding: "utf8", flag: "w")
+
+  gulpfileCoffee = """
+    gulp        = require "gulp"
+    coffee      = require "gulp-coffee"
+    gutil       = require "gulp-util"
+    jasmine     = require "gulp-jasmine"
+    lambduhGulp = require "lambduh-gulp"
+
+    lambduhGulp gulp
+
+    gulp.task "js", ->
+      gulp.src("./src/*.coffee")
+        .pipe(coffee()).on("error", gutil.log)
+        .pipe(gulp.dest("./dist"))
+
+    gulp.task "test", ->
+      gulp.src("./dist/*_spec.js")
+        .pipe(jasmine({includeStackTrace: false}))
+
+    gulp.task "auto-test", ->
+      gulp.watch("./src/*.coffee", ["default"])
+      gulp.start("default")
+
+    gulp.task "default", ["js"], ->
+      gulp.start("test")
+  """
+  gulpfileCoffeePath = path.join(path.resolve(), "gulpfile.coffee")
+  console.log gulpfileCoffee
+  console.log gulpfileCoffeePath
+  fs.writeFileSync(gulpfileCoffeePath, gulpfileCoffee + "\n", encoding: "utf8", flag: "w")
 else
   console.log "Usage: lamjet init"


Fix for https://github.com/spine/spine/issues/597.

--- app/assets/javascripts/app/lib/spine/spine.coffee
+++ app/assets/javascripts/app/lib/spine/spine.coffee
@@ -367,7 +367,7 @@
     records[id] = records[@id]
     delete records[@id] unless @cid is @id
     @id = id
-    @save()
+    #@save()

   remove: (options = {}) ->
     # Remove record from model


enable turbolink site change for table row click

--- app/assets/javascripts/clickable_table_row.coffee
+++ app/assets/javascripts/clickable_table_row.coffee
@@ -1,6 +1,6 @@
 class ClickableTableRow
   constructor: ->
     $('table tr[data-href] td:not(.controls)').on 'click', ->
-      window.location.href = $(this).parent().attr('data-href')
+      Turbolinks.visit($(this).parent().attr('data-href'))

 window.ClickableTableRow = ClickableTableRow


fix: remove js debug mode

fix: remove js debug mode

--- app/assets/javascripts/dashing/dashing-src.coffee
+++ app/assets/javascripts/dashing/dashing-src.coffee
@@ -84,7 +84,7 @@

 Dashing.widgets = widgets = {}
 Dashing.lastEvents = lastEvents = {}
-Dashing.debugMode = true # false
+Dashing.debugMode = false

 source = new EventSource('/dashing/events')
 source.addEventListener 'open', (e) ->


Fixing multi-prepending expander bug

Fixing multi-prepending expander bug

--- app/assets/javascripts/modules/filter_form.coffee
+++ app/assets/javascripts/modules/filter_form.coffee
@@ -9,10 +9,13 @@
     expandLabel = 'Mehr Filter anzeigen'
     collapseLabel = 'Weniger Filter anzeigen'

+
     $filterForm
             .addClass 'filter-form--isCollapsed'
             .height startHeight
-            .prepend '
' + expandLabel + '
'
+
+    if !$('.filter-form__expander').length
+      $filterForm.prepend '
' + expandLabel + '
'

     $expander = $('.filter-form__expander')

@@ -34,4 +37,5 @@

 $(document).ready initFilterForm
-$(document).on 'page:load', initFilterForm+$(document).on 'page:load', initFilterForm
+#$(window).on 'resize', initFilterForm


Implement text serialization and populate the hidden input field

--- src/mentions-kinder.coffee
+++ src/mentions-kinder.coffee
@@ -45,6 +45,9 @@
     # abort if the cursor left the temp mention
     @abortAutocomplete() if !@_isCaretInTempMention()

+    # set plaintext to our hidden field
+    @populateInput()
+
   startAutocomplete: (triggerChar)->
     console.log "Start autocomplete for #{triggerChar}"
     @_current = {
@@ -56,6 +59,7 @@
     @_current.autocompleter = new @_current.triggerOptions.autocompleter
     @_current.autocompleter.done(@handleAutocompleteDone)
     @_current.autocompleter.fail(@handleAutocompleteFail)
+    @_current.autocompleter.always(@populateInput)
     @_current.autocompleter.search('')

     textNode = document.createTextNode(' ')
@@ -98,6 +102,18 @@
     @_setCaretPosition(@$editable[0], placeCaret, textNode) if placeCaret

     @_current = null
+
+  populateInput: =>
+    @$input?.val(@getSerializedText())
+
+  getSerializedText: ->
+    textNodes = []
+    for node in @$editable[0].childNodes
+      if node.nodeType == 3
+        textNodes.push node.data
+      else if serializedMention = $(node).data('serializedMention')
+        textNodes.push serializedMention
+    textNodes.join('')

   _ensureInput: (element)->
     @$originalInput = $(element)


Only start crash service on Windows.

Only start crash service on Windows.

--- common/api/lib/crash-reporter.coffee
+++ common/api/lib/crash-reporter.coffee
@@ -22,9 +22,7 @@

     start = -> binding.start productName, companyName, submitUrl, autoSubmit, ignoreSystemCrashHandler, extra

-    if process.platform is 'darwin'
-      start()
-    else
+    if process.platform is 'win32'
       args = [
         "--reporter-url=#{submitUrl}"
         "--application-name=#{productName}"
@@ -34,5 +32,7 @@

       spawn process.execPath, args, {env, detached: true}
       start()
+    else
+      start()

 module.exports = new CrashReporter


Bug fixes regarding multiple simultaneous themes with firefox and opera

--- js/foundation/thememanager/thememanager.coffee
+++ js/foundation/thememanager/thememanager.coffee
@@ -22,8 +22,9 @@
     for _componentName of @themeCSSTemplates[_themeName]
       _cssText += @buildCSSTemplate(@, _themeName, _componentName)
     _style = @useCSS( _cssText )
-    _cssTitle = 'rsence/'+_themeName
-    _style.title = _cssTitle
+    # Causes issues in Firefox:
+    # _cssTitle = 'rsence/'+_themeName
+    # _style.title = _cssTitle

   setupThemePath: (_themeName)->
     return unless @currentThemePath?
@@ -48,7 +49,7 @@

   # Set the theme data, this is called by the serverside client_pkg suite
   installThemeData: (_themeName, _themeCSS, _themeHTML)->
-    @themes << _themeName unless ~@themes.indexOf(_themeName)
+    @themes.push(_themeName) unless ~@themes.indexOf(_themeName)
     @setThemeCSSTemplates(_themeName, _themeCSS)
     @setThemeHTMLTemplates(_themeName, _themeHTML)
     @setupThemePath(_themeName)
@@ -204,13 +205,13 @@
       _style.media  = 'all'

       _head = document.getElementsByTagName('head')[0]
-
-      if BROWSER_TYPE.safari
+      _head.appendChild(_style)
+
+      if BROWSER_TYPE.safari or BROWSER_TYPE.firefox or BROWSER_TYPE.opera
         # This is how to do it in KHTML browsers
         _style.appendChild( document.createTextNode(_cssText) )
       else
-        # This works for others (add more checks, if problems with new browsers)
+        # This works for many others (add more checks, if problems with new browsers)
         _style.textContent = _cssText
-      _head.appendChild(_style)

       _style