only set unsaved if xhr is not present

only set unsaved if xhr is not present

If it is, that indicates that it was a fetch

--- client/lanes/data/Model.coffee
+++ client/lanes/data/Model.coffee
@@ -1,8 +1,8 @@
 class DataModel
     isModel: true

-    constructor: (attrs,options)->
-        this._unsaved = if attrs then _.keys(attrs) else []
+    constructor: (attrs,options={})->
+        this._unsaved = if attrs and !options.xhr then _.keys(attrs) else []
         super
         this.on('change', this._recordUnsaved )


Bugfix: Editor keeps autosaving even when not typing.

 - I did some tests and found that every time the autosave runs,
  somehow it's firing a `keyup` event, which causes the autosave to run
  again and again inifinitely. I haven't figured out what's causing that,
  but for now I changed the event map to autosave on `keydown` instead of
  `keyup` which fixes the issue.

--- client/views/admin/edit.coffee
+++ client/views/admin/edit.coffee
@@ -149,7 +149,7 @@
     $html.height($editable.height())

   # Autosave
-  'input .editable, keyup .editable, keyup .html-editor': _.debounce (e, tpl) ->
+  'input .editable, keydown .editable, keydown .html-editor': _.debounce (e, tpl) ->
     save tpl, (id, err) ->
       if err
         return Notifications.error '', err.message


Update atom snippets.cson

Update atom snippets.cson

--- atom/snippets.cson
+++ atom/snippets.cson
@@ -35,7 +35,7 @@
     'prefix': 'huto'
     'body': '$1'
   'oomozi':
-    'prefix': 'huto'
+    'prefix': 'oomozi'
     'body': '$1'
 #
 # Atom Flight Manual:


Better variable

Better variable

--- stuff/atom/language-ublu/grammars/ublu.cson
+++ stuff/atom/language-ublu/grammars/ublu.cson
@@ -407,11 +407,11 @@
     name: 'keyword2.as400.ublu'
   }
 {
-  match: '\\b\\@\\@\\w\+\\b'
+  match: '\\@\\@\\w\+\\b'
   name: 'variable.as400.ublu'
 }
   {
-    match: '\\b\\@\\w\+\\b'
+    match: '\\@\\w\+\\b'
     name: 'variable.as400.ublu'
   }
 ]


Only convert data type when it is a valid integer

--- controls/mixins/DataTypeConversion.coffee
+++ controls/mixins/DataTypeConversion.coffee
@@ -15,7 +15,14 @@
           else
             null
       when "number"
-        parseInt(value, 10)
+        if value == ""
+          null
+        else
+          integer = parseInt(value, 10)
+          if integer.toString() == value
+            integer
+          else
+            value
       else
         value
 module.exports = DataTypeConversionMixin


Add js doc

Add js doc

--- src/coffee/import/products.coffee
+++ src/coffee/import/products.coffee
@@ -455,6 +455,13 @@
     if _.has(productImportMappings, key)
       @_addValue(product, variant, value, productImportMappings[key], mappings)

+  ###
+  # Transforms given value by transformer defined in the mapping.
+  #
+  # @param {Object} value Value to process
+  # @param {Object} mapping Mapping for the given value
+  # @param {Object} mappings Product import attribute mappings
+  ###
   _transformValue: (value, mapping, mappings) ->
     valueTransformers = mappings.productImport.valueTransformers
     return value if not valueTransformers or not _.isString(value)


不具合修正およびIE、Safariの検出を追加

不具合修正およびIE、Safariの検出を追加

--- src/coffee/jp/ceroan/Utils.coffee
+++ src/coffee/jp/ceroan/Utils.coffee
@@ -13,8 +13,21 @@
 				_isMobile = true
 		return _isMobile

+	@detectIe: () ->
+		_ua = navigator.userAgent.toLowerCase()
+		_isIe = false
+		if _ua.indexOf("msie") != -1 || _ua.indexOf("trident/7.0") != -1
+			_isIe = true
+		return _isIe
+
+	@detectSafari: () ->
+		_ua = navigator.userAgent.toLowerCase()
+		_isSafari = false
+		if _ua.indexOf("safari") != -1 && _ua.indexOf("chrome") == -1
+			_isSafari = true
+		return _isSafari
+
 	@detectIOs: () ->
-		@detectIOs()
 		_ua = navigator.userAgent.toLowerCase()
 		_isIOs = false
 		if _ua.indexOf("ipod") != -1 || _ua.indexOf("iphone") != -1 || _ua.indexOf("ipad") != -1
@@ -47,4 +60,4 @@
 			urlParams[decode(match[1])] = decode(match[2])
 		return urlParams

-module.exports = Utils+module.exports = Utils


Corrige chamada a função inexistente

Corrige chamada a função inexistente

--- src/coffee/portal-minicart.coffee
+++ src/coffee/portal-minicart.coffee
@@ -63,7 +63,7 @@
 					, 3000

 			else
-				@getData()
+				@updateCart()

 		$(window).on 'productAddedToCart', =>
 			@updateCart()
@@ -110,6 +110,7 @@
 				item.formattedPrice = _.intAsCurrency(item.price, @options)

 	render: () =>
+		console.log @cartData
 		dust.render 'minicart', @cartData, (err, out) =>
 			console.log 'Minicart Dust error: ', err if err
 			@context.html out


user_blocks takes pagination params

user_blocks takes pagination params

--- collections/user_blocks.coffee
+++ collections/user_blocks.coffee
@@ -6,9 +6,15 @@
 sd = require("sharify").data
 _ = require 'underscore'
 Block = require("../models/block.coffee")
+params = require 'query-params'

 module.exports = class UserBlocks extends SearchBlocks
+  defaultOptions:
+    page: 1
+    per: 20

-  url: -> "#{sd.API_URL}/user/#{@slug}/search"
+  url: -> "#{sd.API_URL}/user/#{@slug}/search?#{params.encode(@options)}"

-  initialize: (models, options) -> @slug = options.user_slug+  initialize: (models, options) ->
+    super
+    @slug = options.user_slug


Fix ref

Fix ref

--- components/GetUserMedia.coffee
+++ components/GetUserMedia.coffee
@@ -65,7 +65,8 @@
       navigator.getUserMedia
         video: @video
         audio: @audio
-      , (@stream) =>
+      , (stream) =>
+        @stream = stream
         if @outPorts.url.isAttached()
           # Shim
           unless window.URL?
@@ -93,5 +94,4 @@
   shutdown: ->
     @stopStream()

-
 exports.getComponent = -> new GetUserMedia


Fix condition

Fix condition

--- components/LoadUserData.coffee
+++ components/LoadUserData.coffee
@@ -29,7 +29,7 @@
       'grid-user': 'flowhub-user'
     for key, newKey of deprecated
       val = localStorage.getItem key
-      continue unless key
+      continue unless val
       localStorage.setItem newKey, val
       localStorage.removeItem key


RequestStore: look more like groups/SendByGroups

--- components/RequestStore.coffee
+++ components/RequestStore.coffee
@@ -4,8 +4,8 @@
   description: 'Store IIPs using their group and outputs them when'
   constructor: ->
     @inPorts =
-      push: new noflo.Port 'object'
-      pop: new noflo.Port 'bang'
+      data: new noflo.Port 'object'
+      in: new noflo.Port 'bang'
     @outPorts =
       out: new noflo.Port 'object'
       # TODO : add loadgroup/loadiip ports
@@ -15,22 +15,22 @@
     @groupsReq = []

     # Push
-    @inPorts.push.on 'begingroup', (group) =>
+    @inPorts.data.on 'begingroup', (group) =>
       @groups.push group
-    @inPorts.push.on 'data', (iip) =>
+    @inPorts.data.on 'data', (iip) =>
       group = @groups[@groups.length - 1]
       return unless group?
       @iips[group] = [] unless @iips[group]?
-      @iips[group].push ipp
-    @inPorts.push.on 'endgroup', () =>
+      @iips[group].push iip
+    @inPorts.data.on 'endgroup', () =>
       @groups.pop()

     # Pop
-    @inPorts.pop.on 'begingroup', (group) =>
+    @inPorts.in.on 'begingroup', (group) =>
       @groupsReq.push group
       return unless @outPorts.out.isAttached()
       @outPorts.out.beginGroup(group)
-    @inPorts.pop.on 'data', () =>
+    @inPorts.in.on 'data', () =>
       group = @groupsReq[@groupsReq.length - 1]
       return unless group?
       return unless @iips[group]?
@@ -39,11 +39,11 @@
           iip = @iips[group].shift()
           @outPorts.out.send iip
       delete @iips[group]
-    @inPorts.pop.on 'endgroup', () =>
+    @inPorts.in.on 'endgroup', () =>
       @groupsReq.pop()
       return unless @outPorts.out.isAttached()
       @outPorts.out.endGroup()
-    @inPorts.pop.on 'disconnect', () =>
+    @inPorts.in.on 'disconnect', () =>
       return unless @outPorts.out.isConnected()
       @outPorts.out.disconnect()


Deployment: remove console.log

Deployment: remove console.log

--- deployment/grouptoenvmapping.coffee
+++ deployment/grouptoenvmapping.coffee
@@ -20,7 +20,6 @@
   "proxy"       : proxies

 module.exports.isAllowed = (group, env)->
-  console.log group, env
   # if group name is not in groupToEnv
   unless groupToEnv[group]
     console.error "#{group} is not defined in groupToEnv map"


Update in-game reviewing to match other reviewing

--- web/coffee/game_support.coffee
+++ web/coffee/game_support.coffee
@@ -1,8 +1,8 @@
 @renderProblemReview = _.template($("#problem-review-template").remove().text())

 @ratingMetrics = ["Difficulty", "Enjoyment", "Educational Value"]
-@ratingQuestion = {"Difficulty": "How difficult is this problem?", "Enjoyment": "Did you enjoy this problem?", "Educational Value": "How much did you learn by doing this problem?"}
-@ratingChoices = {"Difficulty": ["Very Easy", "", "Average", "", "Too Hard"], "Enjoyment": ["Hated it!", "", "Neutral", "", "Loved it!"], "Educational Value": ["Learned Nothing","", "Some New Things", "", "A Lot"]}
+@ratingQuestion = {"Difficulty": "How difficult is this problem?", "Enjoyment": "Did you enjoy this problem?", "Educational Value": "How much did you learn while solving this problem?"}
+@ratingChoices = {"Difficulty": ["Too easy", "", "A bit challenging", "", "Very hard"], "Enjoyment": ["Hated it!", "", "It was okay.", "", "Loved it!"], "Educational Value": ["Nothing at all","", "Something useful", "", "Learned a lot!"]}

 @timeValues = ["5 minutes or less", "10 minutes", "20 minutes", "40 minutes", "1 hour", "2 hours", "3 hours", "4 hours", "5 hours", "6 hours", "8 hours", "10 hours", "15 hours", "20 hours", "30 hours", "40 hours or more"]


About box text

About box text

--- web/scripts/referenceUI.coffee
+++ web/scripts/referenceUI.coffee
@@ -214,7 +214,7 @@
     refContainer = document.createElement("div")

     $(backFade).css({width:'100%',height:'100%',position:'absolute','z-index':'300','background-color':'#000000','opacity':'.5'})
-    $(refContainer).css({ width:'40%',height:'40%',left:'30%',top:'30%',position:'absolute','z-index':'301','background-color':'#FFFFFF'})
+    $(refContainer).css({ width:'60%',height:'60%',left:'30%',top:'30%',position:'absolute','z-index':'301','background-color':'#FFFFFF'})

     $("body").prepend(backFade)
     $(backFade).attr({id:'bF'})
@@ -224,14 +224,34 @@
     para = document.createElement("div")

     $(header).css({"position":"static","overflow":"auto","font-size":"26px","width":"100%","left":"25%","text-align":"center"})
-    $(para).css({"overflow":"auto","max-height":"60%","position":"static"})
+    $(para).css({"overflow":"auto","max-height":"75%","position":"static"})

     header.innerHTML = "Legal Terms and Attributions"
-    para.innerHTML = "Copyright (C) 2013 The Board of Trustees at the University of Illinois
Creative Commons Licenses from openclipart.org are
-    licensed under the creative commons 0 license
-    (Spiral Bound book, star icon, cow eat grass, treasure map)

-    Doppio Java Virtual Machine
Original Content is licensed under MIT Expat License
-
Creative Commons Licenses from findicons.com are licensed under Creative Commons Attributions no Derivatives"
+    para.innerHTML = "
+        Copyright (C) 2013 The Board of Trustees at the University of Illinois
+

+        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+

+        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+

+        THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+

+
+
+    Third-party open-source content

+    Sounds from freesound and images from openclipart.org are licensed under the creative commons 0 license
+    ('game over','level completed' sounds; Spiral Bound book, star icon, cow eat grass, treasure map icons)

+    Doppio Java Virtual Machine
+

+    The undo-yellow arrow image byJack Cai from findicons.com is licensed under Creative Commons Attributions no Derivatives
+

+
+    Acknowledgements

+    We wish to thank Holly, Maggie and Abby and the other participants at the 2013 UofI Computer Science Summer G.A.M.E.S Camp for their game ideas,feedback and testing.
+
+
+

+    "

 	$(refContainer).append(header)
 	$(refContainer).append(para)


Get rid of grouping(), use _doAtom()

Get rid of grouping(), use _doAtom()

--- src/dialects/sql-formatter.coffee
+++ src/dialects/sql-formatter.coffee
@@ -199,11 +199,9 @@
         return " WHERE #{(c.whereClause.toSql(@))}" if (c.whereClause?)
         return ""

-    groupBy: (c) -> @doList(c.groupings, @grouping, ', ', ' GROUP BY ')
+    groupBy: (c) -> @doList(c.groupings, @_doAtom, ', ', ' GROUP BY ')

     orderBy: (c) -> @doList(c.orderings, @ordering, ', ', ' ORDER BY ')
-
-    grouping: (atom) -> @_doAtom(atom)

     ordering: (o) ->
         s = @_doAtom(_.firstOrSelf(o))


Slider fix

Slider fix

--- src/elements/Slider/Slider.coffee
+++ src/elements/Slider/Slider.coffee
@@ -116,7 +116,7 @@

 	displayValue: ->
 		percent = @getValue() / @_max * 100
-		CUI.DOM.setStyle(@__handle, left: percent +'%')
+		CUI.DOM.setStyle(@__handle, left: percent + '%')
 		@_onUpdate?(@, @getValue())

 	checkValue: (v, flags) ->


Focus the root view when file finder closes, not an editor. Will test this when we extract it as an extenison.

--- src/extensions/file-finder.coffee
+++ src/extensions/file-finder.coffee
@@ -62,5 +62,5 @@
     fuzzyFilter(@paths, query, maxResults: @maxResults)

   remove: ->
-    $('#panes .editor.active').focus()
+    $('#root-view').focus()
     super


Changed testpie colors

Changed testpie colors


(feature) Pass test code when registering tests.

--- src/flavors/it_style_tests.coffee
+++ src/flavors/it_style_tests.coffee
@@ -15,7 +15,7 @@
       it: """(function(){
         var __it_index = 0;
         return function(name, fn) {
-          registerTest(name);
+          registerTest(name, 'it("'+name+'", fn.toString() + ')';
           try {
             fn();
             pass(name);


simplify rerender on resize, fix #1

simplify rerender on resize, fix #1

--- src/scripts/graph/Timeline.coffee
+++ src/scripts/graph/Timeline.coffee
@@ -109,9 +109,9 @@
           .attr('width', INNER_WIDTH)
         @x.range([0, width])

-        @xGrid.call(@xAxisGrid)
-        @xAxisElement.call(@xAxis)
+        @isDirty = true
         @header.resize(INNER_WIDTH)
+        @render()

     onDurationChanged: (seconds) =>
       #@isDirty = true


Copy chats on move

Copy chats on move

--- src/smc-webapp/project_files.cjsx
+++ src/smc-webapp/project_files.cjsx
@@ -1174,6 +1174,7 @@
         @props.actions.move_files
             src           : @props.checked_files.toArray()
             dest          : @state.move_destination
+            include_chats : true
         @props.actions.set_file_action()
         @props.actions.set_all_files_unchecked()


consolidate `updateSearchResult`

consolidate `updateSearchResult`

--- resources/assets/coffee/_classes/store-supporter-tag.coffee
+++ resources/assets/coffee/_classes/store-supporter-tag.coffee
@@ -83,10 +83,10 @@
         osu.popup osu.trans('errors.logged_out'), 'danger'

     .always =>
+      @searching = false
       @setUserInteraction(@user?)
       @updateCart(@user)
-      @updateUserDisplay()
-      @searching = false
+      @updateSearchResult()

   calculate: (position) =>
     new StoreSupporterTagPrice(Math.floor(position / @RESOLUTION))
@@ -99,7 +99,7 @@
   onInput: (event) =>
     if !@searching
       @searching = true
-      @updateSearchResult(true)
+      @updateSearchResult()
       @setUserInteraction(false)
     @debouncedGetUser(event.currentTarget.value)

@@ -112,8 +112,18 @@
     $('.js-store-add-to-cart').prop 'disabled', disabled
     $('#product-form').data 'disabled', disabled

-  updateSearchResult: (searching) ->
-    @inputFeedback.textContent = 'searching' if searching
+  updateSearchResult: =>
+    return @inputFeedback.textContent = 'searching' if @searching
+
+    [avatarUrl, text] = if @user
+                          [@user.avatarUrl, '']
+                        else
+                          ['', "This user doesn't exist"]
+
+    @inputFeedback.textContent = text
+    $(@el.querySelectorAll('.js-avatar')).css(
+      'background-image': "url(#{avatarUrl})"
+    )

   updatePrice: (obj) =>
     @el.querySelector('input[name="item[cost]"').value = obj.price()
@@ -121,18 +131,6 @@
     @priceElement.textContent = "USD #{obj.price()}"
     @durationElement.textContent = obj.durationText()
     @discountElement.textContent = "save #{obj.discount()}%"
-
-  updateUserDisplay: =>
-    avatarUrl = if @user
-                  @inputFeedback.textContent = ''
-                  @user.avatarUrl
-                else
-                  @inputFeedback.textContent = "This user doesn't exist"
-                  ''
-
-    $(@el.querySelectorAll('.js-avatar')).css(
-      'background-image': "url(#{avatarUrl})"
-    )

   setUserInteraction: (enabled) =>
     $(@el).toggleClass('store-supporter-tag--disabled', !enabled)


Fixed undefined error for hourly tracks

Fixed undefined error for hourly tracks

--- resources/assets/scripts/app/controllers/track-stats.coffee
+++ resources/assets/scripts/app/controllers/track-stats.coffee
@@ -26,7 +26,7 @@

         statsLoaded = (stats) ->
             for key, value of stats.playStats
-                labelArray.push value.hour || value.days
+                labelArray.push value.hours || value.days
                 dailyArray.push value.plays

             i = 0


Retira chamada ao console da barra

Retira chamada ao console da barra

--- recipes/default/assets/barra-brasil.coffee
+++ recipes/default/assets/barra-brasil.coffee
@@ -40,14 +40,12 @@

   add_eselo = () ->
     response = JSON.parse @responseText
-    console.log response
     if response.valor
         eselo = document.getElementById "eselo"
         eselo.setAttribute 'href', response.urlResultado
         eselo.setAttribute 'title', 'Avaliado em: '+ new Date(response.dataAvaliacao).toLocaleString()
         eselo.setAttribute 'aria-label', 'Avaliação de acessibilidade do site' + window.location.href
         eselo.innerHTML = '\u267F '+response.valor
-
         document.getElementById("lista-barra-brasil").className += " list-eselo"
     return


Fix hashed file path for rich text

Fix hashed file path for rich text

--- services/web/app/coffee/infrastructure/ExpressLocals.coffee
+++ services/web/app/coffee/infrastructure/ExpressLocals.coffee
@@ -41,7 +41,7 @@
 	"#{jsPath}ide.js"
 	"#{jsPath}main.js"
 	"#{jsPath}libraries.js"
-	"#{jsPath}es/richText.js"
+	"#{jsPath}es/rich-text.js"
 	"/stylesheets/style.css"
 	"/stylesheets/ol-style.css"
 ]


use Url for lib name

use Url for lib name

--- services/web/app/coffee/infrastructure/ExpressLocals.coffee
+++ services/web/app/coffee/infrastructure/ExpressLocals.coffee
@@ -7,7 +7,7 @@
 SystemMessageManager = require("../Features/SystemMessages/SystemMessageManager")
 _ = require("underscore")
 Modules = require "./Modules"
-url = require "url"
+Url = require "url"

 fingerprints = {}
 Path = require 'path'
@@ -64,13 +64,13 @@

 	webRouter.use (req, res, next)->
 		res.locals.jsPath = jsPath
-		res.locals.fullJsPath = url.resolve(staticFilesBase, jsPath)
+		res.locals.fullJsPath = Url.resolve(staticFilesBase, jsPath)

 		imgPath = "/img/"
 		cssPath = "/stylesheets/"

 		res.locals.buildJsPath = (jsFile, opts = {})->
-			p = Path.join(jsPath, jsFile)
+			path = Path.join(jsPath, jsFile)

 			doFingerPrint = opts.fingerprint != false

@@ -80,21 +80,21 @@
 			if !opts.qs?.fingerprint? and doFingerPrint
 				opts.qs.fingerprint = getFingerprint(p)

-			p = url.resolve(staticFilesBase, p)
+			path = Url.resolve(staticFilesBase, p)
 			qs = querystring.stringify(opts.qs)

 			if qs? and qs.length > 0
-				p = p + "?" + qs
-			return p
+				path = path + "?" + qs
+			return path

 		res.locals.buildCssPath = (cssFile)->
-			p = Path.join(cssPath, cssFile)
-			return url.resolve(staticFilesBase, p) + "?fingerprint=" + getFingerprint(p)
+			path = Path.join(cssPath, cssFile)
+			return Url.resolve(staticFilesBase, path) + "?fingerprint=" + getFingerprint(path)

 		res.locals.buildImgPath = (imgFile)->
-			p = Path.join(imgPath, imgFile)
-			return url.resolve(staticFilesBase, p)
+			path = Path.join(imgPath, imgFile)
+			return Url.resolve(staticFilesBase, path)

 		next()


update atom settings

update atom settings

--- .atom/config.cson
+++ .atom/config.cson
@@ -5,12 +5,13 @@
     audioBeep: false
   editor:
     fontFamily: "Ricty Diminished"
-    fontSize: 13
     invisibles: {}
   "exception-reporting":
     userId: "c8108de1-b3b8-b018-6bc1-436050e572ef"
   linter:
     errorPanelHeight: 100
+  "linter-jscs":
+    esnext: true
   "one-dark-ui": {}
   react: {}
   "remote-edit": {}


atom: random config line

atom: random config line

(cherry picked from commit 25b60d6fc8f19c898f19e7bf0c79e9cf3ce8bc78)

--- .atom/config.cson
+++ .atom/config.cson
@@ -26,6 +26,7 @@
       "autocomplete-snippets"
       "snippets"
     ]
+    telemetryConsent: "no"
   editor:
     fontFamily: "inconsolata"
     fontSize: 21


Update config.cson

Update config.cson

--- .atom/config.cson
+++ .atom/config.cson
@@ -13,5 +13,15 @@
       opacity: 0.3
       cr: "↩"
       tab: "⇥"
+    showInvisibles: true
     fontSize: 15
-    showInvisibles: true
+  "atom-beautify":
+    _analyticsUserId: "68cc2295-e2bf-4599-8047-4d173e8b4e3b"
+  jshint: {}
+  "linter-jshint":
+    executablePath: "/usr/local/bin/jshint"
+    lintInlineJavaScript: true
+  linter:
+    showErrorPanel: false
+  minimap:
+    absoluteMode: true


Tests: Enable pricing test suite

Tests: Enable pricing test suite

--- scripts/test-instance/parallel-sets.coffee
+++ scripts/test-instance/parallel-sets.coffee
@@ -56,7 +56,7 @@

   [
     { name: 'ide terminal' }
-    # { name: 'pricing invalidcarddetails' }
+    { name: 'pricing invalidcarddetails' }
   ]

   [


Tests: disabled collab file tests.

Tests: disabled collab file tests.

--- scripts/test-instance/parallel-sets.coffee
+++ scripts/test-instance/parallel-sets.coffee
@@ -77,9 +77,9 @@
     { name: 'collaboration collaborationsession', NIGHTWATCH_OPTIONS: '--env host,participant' }
   ]

-  [
-    { name: 'collaboration collaborationfile', NIGHTWATCH_OPTIONS: '--env host,participant' }
-  ]
+  # [
+  #   { name: 'collaboration collaborationfile', NIGHTWATCH_OPTIONS: '--env host,participant' }
+  # ]

   [
     { name: 'vmsharing vmsharing', NIGHTWATCH_OPTIONS: '--env host,participant' }


StaticPage: Replace contentType with route parameter in getPagination

--- server/lib/crawler/staticpages/feed.coffee
+++ server/lib/crawler/staticpages/feed.coffee
@@ -60,7 +60,7 @@
         return callback null, fullPage
       daisy queue

-getPagination = (currentPage, numberOfItems, contentType)->
+getPagination = (currentPage, numberOfItems, route="")->
   # This is the number of adjacent link around current page.
   # E.g. let current page be 9, then pagination will look like this:
   # First Prev ... 4 5 6 7 8 9 10 11 12 13 14 ... Next Last
@@ -71,12 +71,12 @@
   firstLink = prevLink = nextLink = lastLink = ""

   if currentPage > 1
-    firstLink = getSinglePageLink 1, contentType, "First"
-    prevLink  = getSinglePageLink (currentPage - 1), contentType, "Prev"
+    firstLink = getSinglePageLink 1, "First", route
+    prevLink  = getSinglePageLink (currentPage - 1), "Prev", route

   if currentPage < numberOfPages
-    lastLink  = getSinglePageLink numberOfPages, contentType, "Last"
-    nextLink  = getSinglePageLink (currentPage + 1), contentType, "Next"
+    lastLink  = getSinglePageLink numberOfPages, "Last", route
+    nextLink  = getSinglePageLink (currentPage + 1), "Next", route

   pagination = firstLink + prevLink

@@ -92,7 +92,7 @@
     pagination += getNoHrefLink " ... "

   [start..end].map (pageNumber)=>
-    pagination += getSinglePageLink pageNumber, contentType
+    pagination += getSinglePageLink pageNumber, null, route

   if end < numberOfPages
     pagination += getNoHrefLink " ... "
@@ -105,8 +105,8 @@
 getNoHrefLink = (linkText)->
   "#{linkText}  "

-getSinglePageLink = (pageNumber, contentType, linkText=pageNumber)->
-  link = "#{linkText}  "
+getSinglePageLink = (pageNumber, linkText=pageNumber, route)->
+  link = "#{linkText}  "
   return link

 appendDecoratedTopic = (tag, queue)=>


remove unused confirmed field from user model

--- services/web/app/coffee/models/User.coffee
+++ services/web/app/coffee/models/User.coffee
@@ -19,7 +19,6 @@
 	institution       : {type : String, default : ''}
 	hashedPassword    : String
 	isAdmin           : {type : Boolean, default : false}
-	confirmed         : {type : Boolean, default : false}
 	signUpDate        : {type : Date, default: () -> new Date() }
 	lastLoggedIn      : {type : Date}
 	lastLoginIp       : {type : String, default : ''}


Fix direct navigation to main state in gallery module

--- site/modules/gallery/gallery.module.coffee
+++ site/modules/gallery/gallery.module.coffee
@@ -51,6 +51,10 @@
     ($state, $scope, stats) ->
         if $state.current.name is 'gallery'
             $state.go 'gallery.year', { year: moment().year() }
+
+        $scope.$on '$stateChangeStart', (event, toState, toParams) ->
+            if toState.name == 'gallery'
+                event.preventDefault()

         $scope.navtreeSettings =
             isActive: (branchState, uiState) ->


Remove console.log

Remove console.log

--- admin/static/coffee/servers/server.coffee
+++ admin/static/coffee/servers/server.coffee
@@ -135,7 +135,6 @@
                 model: @model

         render: =>
-            console.log 'render'
             #TODO Handle ghost?
             @$el.html @template.main()


machine -> server in server.coffee

machine -> server in server.coffee

--- admin/static/coffee/servers/server.coffee
+++ admin/static/coffee/servers/server.coffee
@@ -176,7 +176,7 @@
             # TODO: Implement when logs will be available
             #@logs = new LogView.Container
             #    route: "ajax/log/"+@model.get('id')+"?"
-            #    type: 'machine'
+            #    type: 'server'
             #@$('.recent-log-entries').html @logs.render().$el
             @

@@ -189,8 +189,8 @@
                 @rename_modal.remove()

     class @Title extends Backbone.View
-        className: 'machine-info-view'
-        template: Handlebars.templates['machine_view_title-template']
+        className: 'server-info-view'
+        template: Handlebars.templates['server_view_title-template']
         initialize: =>
             @listenTo @model, 'change:name', @render

@@ -204,8 +204,8 @@
             super()

     class @Profile extends Backbone.View
-        className: 'machine-info-view'
-        template: Handlebars.templates['machine_view_profile-template']
+        className: 'server-info-view'
+        template: Handlebars.templates['server_view_profile-template']
         initialize: =>
             @listenTo @model, 'change', @render
             @listenTo @collection, 'add', @render


minor code style

minor code style

--- workers/social/lib/social/render/loggedout/grouphome.coffee
+++ workers/social/lib/social/render/loggedout/grouphome.coffee
@@ -30,7 +30,7 @@

     <!--[if IE]><script>(function(){window.location.href='/unsupported.html'})();</script><![endif]-->

-    #{KONFIG.getConfigScriptTag { entryPoint: { slug : slug, type: "group" }, roles:['guest'], permissions:[] }}
+    #{KONFIG.getConfigScriptTag { entryPoint: { slug, type: "group" }, roles: ['guest'], permissions: [] }}
     <script>KD.isLoggedInOnLoad=false;</script>
     #{scripts}
     </body>


implemented closeAll method to monmon

implemented closeAll method to monmon

--- server/monmon.coffee
+++ server/monmon.coffee
@@ -316,8 +316,17 @@
                 callback? err, db
                 t.opening = false

-    close: ->
-        @db?.close(->)
+    close: (callback) ->
+        @db?.close callback

 exports.monmon = new MongoMonad()
+exports.closeAll = (callback) ->
+    closes = []
+    for k,c of conn_pool
+        do (c) ->
+            closes.push (cb) ->
+                c.close cb
+
+    async.parallel closes, callback
+


removing comment about pragma-no-cache

removing comment about pragma-no-cache

--- server/router.coffee
+++ server/router.coffee
@@ -31,7 +31,6 @@

       start = new Date
       res.render template, locals: data, app: req.rendrApp, req: req, (err, html) ->
-        # TODO! consider setting pragma-no-cache headers based on route!
         if (err)
           console.log("RENDER ERROR", err)
         return handleErr(err, req, res) if err


Turns out this isn't set in an environmental variable.

--- server_config.coffee
+++ server_config.coffee
@@ -3,7 +3,7 @@
 config.unittest = global.testing
 config.proxy = process.env.COCO_PROXY

-config.chinaDomain = "cn.codecombat.com"
+config.chinaDomain = "cn.codecombat.com;ccombat.cn"
 config.brazilDomain = "br.codecombat.com"
 config.port = process.env.COCO_PORT or process.env.COCO_NODE_PORT or process.env.PORT  or 3000
 config.ssl_port = process.env.COCO_SSL_PORT or process.env.COCO_SSL_NODE_PORT or 3443


ログを削除

ログを削除

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

   $(".feed_item_label").on "click", ->
     $(".edit_panel").remove()
-    console.log($(this)[0].innerText)
     $(this).after("

#{ $(this)[0].innerText }
#{ $(this).parent().find(".feed_item_content").val() }


better flash fadeout

better flash fadeout

--- app/assets/javascripts/views/flash.coffee
+++ app/assets/javascripts/views/flash.coffee
@@ -1,7 +1,8 @@
 class Lale.Flash
-  @fadeOut: ->
-    $('.flash-message').each (idx)->
-      $(this).delay(500*idx).fadeOut(500)
+  @fadeOut: (waitTime=2000)->
+    if $('.flash-message').length > 0
+      $('.flash-message').each (idx)->
+        $(this).delay(waitTime + 500*idx).fadeOut 500, ->

   @add: (level, message)=>
     $('.flash').append(HandlebarsTemplates['flash'](level: level, message: message))
@@ -23,4 +24,4 @@
     @add('', msg)

 $(document).on 'ready page:load', ->
-  setTimeout(Lale.Flash.fadeOut, 3000)
+  Lale.Flash.fadeOut()


fix: minor fix

fix: minor fix

--- app/components/project-preferences.coffee
+++ app/components/project-preferences.coffee
@@ -10,7 +10,7 @@
   i18n: Ember.inject.service()
   store: Ember.inject.service()
   selectedDeviceType: ENUMS.DEVICE_TYPE.NO_PREFERENCE
-  deviceTypes: ENUMS.DEVICE_TYPE.CHOICES[0...-1]
+  deviceTypes: ENUMS.DEVICE_TYPE.CHOICES[1...-1]

   tDeviceSelected: t("deviceSelected")
   tPleaseTryAgain: t("pleaseTryAgain")


Wait until logout has completed before redirecting to homeRoute

Fixed a bug where routing was happening too fast (before logout was finished processing) resulting with Router evaluating the homeRoute as if the user was still logged in.

Now the redirect to homeRoute only happens once logout() is finished processing.

--- shared/router.coffee
+++ shared/router.coffee
@@ -22,8 +22,8 @@
     before: ->
       Session.set('entryError', undefined)
       if AccountsEntry.settings.homeRoute
-        Meteor.logout()
-        Router.go AccountsEntry.settings.homeRoute
+        Meteor.logout () ->
+          Router.go AccountsEntry.settings.homeRoute
       @stop()

   @route 'entryResetPassword',


Fix bulk remove course count

Fix bulk remove course count

When removing multiple users from a course in the TeacherClassView,
display the actual number of members removed from the given course
instance.

--- app/views/courses/TeacherClassView.coffee
+++ app/views/courses/TeacherClassView.coffee
@@ -585,12 +585,14 @@
   removeCourse: (courseID, members) ->
     return unless me.id is @classroom.get('ownerID') # May be viewing page as admin
     courseInstance = null
-    numberRemoved = 0
+    membersBefore = 0

     return Promise.resolve()
     # Find the necessary course instance
     .then =>
       courseInstance = @courseInstances.findWhere({ courseID, classroomID: @classroom.id })
+      if courseInstance
+        membersBefore = courseInstance.get('members').length
       # if not courseInstance
       # TODO: show some message if no courseInstance?
       return courseInstance
@@ -605,11 +607,13 @@
         return courseInstance?.removeMembers(members)

     # Show a success/error notification
-    .then =>
+    .then (res) =>
+      membersAfter = courseInstance?.get('members').length or 0
+      numberRemoved = membersBefore - membersAfter
       course = @courses.get(courseID)
       lines = [
         $.i18n.t('teacher.removed_course_msg')
-          .replace('{{numberRemoved}}', members.length)
+          .replace('{{numberRemoved}}', numberRemoved)
           .replace('{{courseName}}', course.get('name'))
       ]
       noty text: lines.join('<br />'), layout: 'center', type: 'information', killer: true, timeout: 5000


config: add region and environment flags

--- config/workers.coffee
+++ config/workers.coffee
@@ -476,6 +476,7 @@
     tunnelserver        :
       group             : "proxy"
       supervisord       :
+        command         : "#{GOBIN}/tunnelserver -accesskey #{credentials.awsKeys.worker_tunnelproxymanager.accessKeyId} -secretkey #{credentials.awsKeys.worker_tunnelproxymanager.secretAccessKey} -port #{KONFIG.tunnelserver.port} -basevirtualhost #{KONFIG.tunnelserver.basevirtualhost} -hostedzone #{KONFIG.tunnelserver.hostedzone} -region #{options.region} -environment #{options.environment}"
         command         : "#{GOBIN}/tunnelserver -accesskey #{credentials.awsKeys.worker_tunnelproxymanager.accessKeyId} -secretkey #{credentials.awsKeys.worker_tunnelproxymanager.secretAccessKey} -port #{KONFIG.tunnelserver.port} -basevirtualhost #{KONFIG.tunnelserver.basevirtualhost} -hostedzone #{KONFIG.tunnelserver.hostedzone}"
       ports             :
         incoming        : "#{KONFIG.tunnelserver.port}"


Dont sync current user client side to avoid endless refresh

--- src/desktop/lib/global_client_setup.coffee
+++ src/desktop/lib/global_client_setup.coffee
@@ -27,7 +27,7 @@
   setupErrorReporting()
   setupJquery()
   setupReferrerTracking()
-  syncAuth()
+  # syncAuth()
   listenForInvert()
   listenForBounce()
   confirmation.check()


fix issue #188 -- make ajax reqs work when jumping steps via URL

--- app/assets/javascripts/hat-trick.js.coffee
+++ app/assets/javascripts/hat-trick.js.coffee
@@ -28,6 +28,7 @@
     console.log "Setting form action to #{methodLower} #{url}"
     @form.attr("action", url)
     @form.attr("method", "post")
+    @form.formwizard("option", remoteAjax: this.ajaxEvents())
     methodField = @form.find('input[name="_method"]')
     methodField.remove()
     if methodLower isnt "post"
@@ -45,10 +46,9 @@
   fieldsets: ->
     @form.find("fieldset")

-  ajaxEvents: (firstStep=false) ->
+  ajaxEvents: ->
     remoteAjax = {}
     $fieldsets = this.fieldsets()
-    $fieldsets = $fieldsets.filter(":first") if firstStep
     $fieldsets.each (index, element) =>
       stepId = $(element).attr("id")
       remoteAjax[stepId] = this.createAjaxEvent(stepId)
@@ -125,7 +125,7 @@
       disableUIStyles: true,
       inDuration: 0,
       linkClass: "_ht_link",
-      remoteAjax: this.ajaxEvents(true), # adds first Ajax event
+      remoteAjax: this.ajaxEvents(),
       formOptions:
         success: (data) =>
           console.log "Successful form POST"
@@ -219,10 +219,6 @@
       if buttons?
         this.setButton(name, label) for own name, label of buttons

-      if data.previousStep is data.firstStep
-        # adds additional Ajax events now that we have the update URL
-        @form.formwizard("option", remoteAjax: this.ajaxEvents())
-
     @form.bind "after_remote_ajax", (event, data) =>
       if hatTrick.metadata?.currentStep.buttons?
         stepId = hatTrick.metadata.currentStep.fieldset


for #323 - historypush only when browser supports it

--- app/assets/javascripts/modules/ajax.coffee
+++ app/assets/javascripts/modules/ajax.coffee
@@ -31,7 +31,7 @@

         # update URL & inform analytics
         if options.historyPush
-          history.pushState { turbolinks: true, url: targetURL }, '', targetURL
+          history.pushState? { turbolinks: true, url: targetURL }, '', targetURL
           Clarat.Analytics.pageView()

         # remove appropriate element from stack & finish


draw initial route

draw initial route

--- app/assets/javascripts/views/map.js.coffee
+++ app/assets/javascripts/views/map.js.coffee
@@ -29,10 +29,9 @@

   render: =>
     # route
-
     @map.addLayer(@from)
     @map.addLayer(@to)
-    #@plan(from, to)
+    @plan()
     this

@@ -65,7 +64,6 @@
     for leg in itinerary.legs
       @draw_polyline(leg.legGeometry.points, if leg.mode == 'BUS' then 'red' else 'black')

-
   draw_polyline: (points, color) =>
     points = decodeLine(points)
     latlngs = (new L.LatLng(point[0], point[1]) for point in points)


fix using the back button in the calendar

fixes CNVS-14475

test plan:
 - regress calendar functionality

 - from various places in canvas:
   - navigate to the calendar
   - change between calendar views (Week, Month, Agenda)
   - press back button to navigate to previous view
   - press back button to navigate to previous page (before calendar)

 - from anywhere in canvas
	 - navigate to the calendar
	 - change months several times
	 - press back button to navigate to previous page (before calendar)

Change-Id: I9b80864201b3c5215398fc703bb4fc16682938ee
Reviewed-on: https://gerrit.instructure.com/42611
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Brad Horrocks <7b5c5d1f2eba6c540b8e53f17d87a9bd7dbf604b@instructure.com>
QA-Review: Steven Shepherd <e794458448443812fb2685675aab3bbd1a3891bc@instructure.com>
Product-Review: Matthew Wheeler <ce71fbafda91d6c8f12582e1837687d5fe592dd9@instructure.com>

--- app/coffeescripts/calendar/Calendar.coffee
+++ app/coffeescripts/calendar/Calendar.coffee
@@ -55,7 +55,7 @@
       data = @dataFromDocumentHash()
       if not data.view_start and @options?.viewStart
         data.view_start = @options.viewStart
-        @updateFragment data
+        @updateFragment data, replaceState: true
       if data.view_start
         date = $.fullCalendar.parseISO8601(data.view_start)
       else
@@ -373,6 +373,9 @@
       (new EditEventDetailsDialog(event)).show()

     updateFragment: (opts) ->
+      replaceState = !!opts.replaceState
+      opts = _.omit(opts, 'replaceState')
+
       data = @dataFromDocumentHash()
       changed = false
       for k, v of opts
@@ -381,7 +384,13 @@
           data[k] = v
         else
           delete data[k]
-      location.href = "#" + $.param(data) if changed
+
+      if changed
+        fragment = "#" + $.param(data)
+        if replaceState || location.hash == ""
+          history.replaceState(null, "", fragment)
+        else
+          location.href = fragment

     viewDisplay: (view) =>
       @setDateTitle(view.title)
@@ -559,7 +568,11 @@
       @setCurrentDate(start)

     setCurrentDate: (d) ->
-      @updateFragment view_start: d.toISOString()
+      d.setHours(0, 0, 0, 0)
+      @updateFragment
+        view_start: d.toISOString()
+        replaceState: true
+
       $.publish('Calendar/currentDate', d)

     getCurrentDate: () ->
@@ -570,7 +583,10 @@
         $.fudgeDateForProfileTimezone(new Date)

     setCurrentView: (view) ->
-      @updateFragment view_name: view
+      @updateFragment
+        view_name: view
+        replaceState: !_.has(@dataFromDocumentHash(), 'view_name') # use replaceState if view_name wasn't set before
+
       @currentView = view
       userSettings.set('calendar_view', view)


Add annotations to deal with minification

--- app/components/oauth/oauth.provider.coffee
+++ app/components/oauth/oauth.provider.coffee
@@ -53,7 +53,7 @@

 		@isExpired = -> AccessToken.expired()

-		@$get = ($injector) ->
+		@$get = ['$injector', ($injector) ->
 			setup $injector

 			login: this.login
@@ -61,3 +61,4 @@
 			isAuthorized: this.isAuthorized
 			getAccessToken: this.getAccessToken
 			isExpired: this.isExpired
+		]


basic UITab

basic UITab

--- public/js/wireroom.coffee
+++ public/js/wireroom.coffee
@@ -161,6 +161,39 @@

   getMessage: -> @messageInput.val()

+class UITab
+  tabPanels: { }
+
+  constructor: (@el) ->
+    self = this
+    @ul = @el.find('ul')
+    @ul.find('a').each (i,e) ->
+      selector = $(this).attr('href')
+      panel = self.el.find(selector)
+      panel.addClass('tab-content')
+      panel.hide()
+      self.el.trigger('addtab', panel)
+
+  addTab: (tabId, label, cb) ->
+    ul = @el.find('ul')
+    li = $('<li/>')
+    a = $('<a/>').html(label).attr({ href: '#' + tabId })
+    a.addClass('ui-link')
+    a.appendTo(li)
+    li.appendTo(ul)
+
+    panel = $('<div/>')
+    panel.appendTo( @el ).addClass('tab-content')
+    @tabPanels[ tabId ] = { handle: li, panel: panel, a: a }
+    cb panel if cb
+
+  removeTab: (tabId) ->
+    o = @tabPanels[ tabId ]
+    if o
+      o.handle.remove()
+      o.panel.remove()
+      delete(@tabPanels[tabId])
+
 class WireRoom
   plugins: {}

@@ -183,6 +216,8 @@
       "reconnection delay": 500
       "max reconnection attempts": 10
     })
+
+    @tabs = new UITab($('#channelTabs'))

     @plugins.status = new WireRoomConnectionStatus(this, $('#connectionStatus') )
     @plugins.messageInput = new WireRoomMessageInput(this)
@@ -199,11 +234,7 @@
     # 3. Closing the browser window will cause the event to be triggered.
     # 4. Even a page reload will first create an unload event.
     $(window).bind "unload", () =>
-      @socket.emit "leave", {
-        roomt: room
-        ident: self.Identifier
-        nickname: self.plugins.messageInput.getNickname()
-      } for room in self.rooms
+      @leaveChannel(room) for room in self.rooms

     # a channel join event.
     @socket.on "join", (data) => console.log "join",data
@@ -213,11 +244,7 @@

     @socket.on "connect", =>
       console.info "socket.io connected."
-      @socket.emit("join",{
-        room: room
-        ident: self.Identifier
-        nickname: self.plugins.messageInput.getNickname()
-      }) for room in self.rooms
+      @joinChannel(room) for room in self.rooms

       # if we don't have logs, we should ask backlog
       # XXX: see if we can get backlogs from a snapshot?
@@ -229,13 +256,16 @@
     @socket.on "disconnect", =>
       console.warn "socket.io disconnected."

-  joinChannel: (channelName) ->
-    self = this
-    @socket.emit("join",{
-      room: channelName
-      ident: self.Identifier
-      nickname: self.plugins.messageInput.getNickname()
-    })
+  joinChannel: (room) ->
+    self = this
+
+    # create a new tab for the channel
+    @tabs.addTab room, room, (panel) =>
+      @socket.emit("join",{
+        room: room
+        ident: self.Identifier
+        nickname: self.plugins.messageInput.getNickname()
+      })

   leaveChannel: (channelName) ->
     self = this