Add xml fixes according to new schema xdd

--- src/coffee/export/orderexport.coffee
+++ src/coffee/export/orderexport.coffee
@@ -13,9 +13,6 @@
 class OrderExport

   constructor: (@_options = {}) ->
-    throw new Error "XML file 'output' path argument to write orders is required" unless @_options.output
-    throw new Error 'Product import attributes mapping (Brickfox -> SPHERE) file path argument is required' unless @_options.mapping
-    throw new Error 'OrderExport SyncInfo channel id argument is required.' unless @_options.channelid
     @rest = new Rest @_options
     @logger = @_options.appLogger

@@ -141,18 +138,30 @@
     @logger.debug "[OrderExport] Processing order with id: '#{order.id}'"
     orderXML.e('OrderId').t(order.id)
     orderXML.e('OrderDate').t(order.createdAt)
+    #<xs:element ref="OrderStatus" minOccurs="0"/>
+    #<xs:element ref="PaymentStatus" minOccurs="0"/>
+    #<xs:element ref="CustomerId" minOccurs="0"/>
+    #<xs:element ref="TotalAmountProducts" minOccurs="0"/>
     orderXML.e('TotalAmountProductsNetto').t(@_toAmount(order.taxedPrice.totalNet.centAmount))
     orderXML.e('TotalAmountVat').t(@_toAmount(order.taxedPrice.taxPortions[0].amount.centAmount))
+    shippingInfo = order.shippingInfo
+    throw new Error "Can not export order as it does not contain shipping info; order id: '#{order.id}'" if not shippingInfo
+    shippingCost = @_toAmount(shippingInfo.price.centAmount)
+    orderXML.e('ShippingCost').t(shippingCost)
+    #<xs:element ref="PaymentCost" minOccurs="0"/>
     orderXML.e('TotalAmount').t(@_toAmount(order.taxedPrice.totalGross.centAmount))
-
-    shippingInfo = order.shippingInfo
-    if shippingInfo
-      shippingCost = @_toAmount(shippingInfo.price.centAmount)
-      orderXML.e('ShippingCost').t(shippingCost)
-      orderXML.e('ShippingMethod').t(shippingInfo.shippingMethodName)
-
+    #<xs:element ref="Comment" minOccurs="0"/>
+    #<xs:element ref="CostsChangings" minOccurs="0"/>
+    # TODO use real data for PaymentMethod
+    orderXML.e('PaymentMethod').t('test')
+    pmValues = orderXML.ele("PaymentMethodValues")
+    # TODO use real data for PaymentMethodValue
+    pmValue = pmValues.ele("PaymentMethodValue", {key: 'testKey', value: 'testValue'})
+    orderXML.e('ShippingMethod').t(shippingInfo.shippingMethodName)
+    billingAddress = if order.billingAddress then order.billingAddress else order.shippingAddress
+    @_addressToXML(billingAddress, orderXML, 'BillingParty')
     @_addressToXML(order.shippingAddress, orderXML, 'DeliveryParty')
-    @_addressToXML(order.billingAddress, orderXML, 'BillingParty') if order.billingAddress
+    #<xs:element ref="Coupons" minOccurs="0"/>

     lineItemsXML = orderXML.ele("OrderLines", {'count': order.lineItems.length})
     _.each order.lineItems, (lineItem, index, list) =>
@@ -164,12 +173,13 @@
     productId = utils.getVariantAttValue(@mappings, 'ProductId', lineItem.variant)
     variationId = utils.getVariantAttValue(@mappings, 'VariationId', lineItem.variant)
     lineItemXML.e('ProductId').t(productId)
+    name = _.values(lineItem.name)[0]
+    lineItemXML.e('ProductName').t(name)
     lineItemXML.e('ItemNumber').t(lineItem.variant.sku)
     lineItemXML.e('VariationId').t(variationId)
-    name = _.values(lineItem.name)[0]
-    lineItemXML.e('ProductName').t(name)
     lineItemXML.e('QuantityOrdered').t(lineItem.quantity)
     lineItemXML.e('ProductsPriceTotal').t(@_toAmount(lineItem.price.value.centAmount))
+    lineItemXML.e('ProductsPrice').t(@_toProductPriceFromTotal(lineItem.price.value.centAmount, lineItem.quantity))
     lineItemXML.e('TaxRate').t(@_toTax(lineItem.taxRate.amount))

   _toAmount: (centAmount) ->
@@ -177,6 +187,9 @@

   _toTax: (rate) ->
     rate = _s.numberFormat(_s.toNumber(rate * 100), 2)
+
+  _toProductPriceFromTotal: (centAmount, quantity) ->
+    amount = _s.numberFormat(_s.toNumber(centAmount / quantity / 100), 2)

   _addressToXML: (address, xml, name) ->
     el = xml.ele(name)


also check type

also check type

--- src/coffee/validators/minsize.coffee
+++ src/coffee/validators/minsize.coffee
@@ -10,6 +10,7 @@
   factory('validatorMinSize', ->

     validator = (name, values, rule) ->
+      if !values[name]? or typeof values[name] != "string" then return false
       if values[name].length >= rule.options.size then true else false

     return {


Finally properly fixed the where compilation via topological sort

--- src/js/app/compilers/teascript/compiler.coffee
+++ src/js/app/compilers/teascript/compiler.coffee
@@ -664,7 +664,7 @@
     for def in compiledDefinitions when def.definedNames
       for defined in def.definedNames
         addToMap auxiliaries, defined,
-          deps: def.usedNames
+          deps: unique def.usedNames
           defines: def.definedNames
           definition: def
     @_scope().auxiliaries = auxiliaries
@@ -2378,21 +2378,18 @@

 findDeps = (ctx) -> (names) ->
   auxiliaries = ctx.auxiliaries()
-  depSet = newSet()
-  depList = []
-  auxiliaryDependencies auxiliaries, names, depSet, depList
-  arrayToSet reverse depList
-
-auxiliaryDependencies = (graph, names, allSet, allList) ->
-  for name in names
-    allList.push name
-    if not inSet allSet, name
-      addToSet allSet, name
-      auxiliaryDependencies graph, ((lookupInMap graph, name)?.deps or []), allSet, allList
-  return
-  # concat (for name in names
-  #   join (deps = ((lookupInMap graph, name)?.deps or [])),
-  #     auxiliaryDependencies graph, deps)
+  arrayToSet auxiliaryDependencies auxiliaries, names
+
+auxiliaryDependencies = (graph, names) ->
+  nameSet = newSet()
+  nameStack = map id, names
+  nodes = []
+  while name = nameStack.pop() when not inSet nameSet, name
+    addToSet nameSet, name
+    if node = (lookupInMap graph, name)
+      nodes.push name: name, deps: map ((name) -> {name}), node.deps
+      nameStack.push node.deps...
+  concat map setToArray, topologicallySortedGroups nodes

 ms.syntax = ms_syntax = (ctx, call) ->
   hasName = requireName ctx, 'Name required to declare a new syntax macro'


Hot fix in test/interfaceSpec.coffee

Hot fix in test/interfaceSpec.coffee

--- test/interfaceSpec.coffee
+++ test/interfaceSpec.coffee
@@ -5,7 +5,7 @@
   ArgsWrapperMock = undefined

   beforeEach ->
-    WrapperMock     = jasmine.createSpyObj 'WrapperMock', ['it', 'iit']
+    WrapperMock     = jasmine.createSpyObj 'WrapperMock', ['it']
     ArgsWrapperMock = jasmine.createSpy('ArgsWrapperMock').and.returnValue WrapperMock
     JasmineMock     = jasmine.createSpyObj 'JasmineMock', ['it', 'iit', 'fit', 'xit']
     subject         = new JasmineSugar.Interface(JasmineMock, ArgsWrapperMock)


Fix 55-spec

Fix 55-spec

--- spec/issues/55-spec.coffee
+++ spec/issues/55-spec.coffee
@@ -8,31 +8,29 @@

   describe "Issue 56", ->
     beforeEach ->
-      # Create a fake workspace and open a sample file
-      atom.workspaceView = new WorkspaceView
-      atom.workspaceView.openSync "issues/50.js"
-      atom.workspaceView.simulateDomAttachment()
+      runs ->
+        # Set to live completion
+        atom.config.set "autocomplete-plus.enableAutoActivation", true

-      # Set to live completion
-      atom.config.set "autocomplete-plus.enableAutoActivation", true
+        # Set the completion delay
+        completionDelay = 100
+        atom.config.set "autocomplete-plus.autoActivationDelay", completionDelay
+        completionDelay += 100 # Rendering delay
+        atom.workspaceView = new WorkspaceView()
+        atom.workspace = atom.workspaceView.model

-      # Set the completion delay
-      completionDelay = 100
-      atom.config.set "autocomplete-plus.autoActivationDelay", completionDelay
-      completionDelay += 100 # Rendering delay
+      waitsForPromise -> atom.workspace.open("issues/50.js").then (e) ->
+        editor = e
+        atom.workspaceView.simulateDomAttachment()

       # Activate the package
-      activationPromise = atom.packages.activatePackage "autocomplete-plus"
+      waitsForPromise -> atom.packages.activatePackage("autocomplete-plus").then (a) -> autocomplete = a

-      editorView = atom.workspaceView.getActiveView()
-      {editor} = editorView
-      autocomplete = new AutocompleteView editorView
+      runs ->
+        editorView = atom.workspaceView.getActiveView()
+        autocomplete = new AutocompleteView editorView

     it "it refocuses the editor after pressing enter", ->
-
-      waitsForPromise ->
-        activationPromise
-
       runs ->
         editorView.attachToDom()
         expect(editorView.find(".autocomplete-plus")).not.toExist()


Check for win32 directly instead of startsWith win

--- spec/tree-view-spec.coffee
+++ spec/tree-view-spec.coffee
@@ -1330,7 +1330,7 @@
         describe "when pasting a file with an asterisk char '*' in to different directory", ->
           it "should successfully move the file", ->
             # Files cannot contain asterisks on Windows
-            return if process.platform.startsWith("win")
+            return if process.platform is "win32"
             asteriskFilePath = path.join(dirPath, "test-file-**.txt")
             fs.writeFileSync(asteriskFilePath, "doesn't matter *")
             LocalStorage['tree-view:copyPath'] = JSON.stringify([asteriskFilePath])


Fix more failing tests on Windows

Fix more failing tests on Windows

--- spec/tree-view-spec.coffee
+++ spec/tree-view-spec.coffee
@@ -2557,7 +2557,7 @@
       it "squashes two dir names when the first only contains a single dir", ->
         if path.sep is '\\'
           # First escape the backslashes for Coffeescript, then escape them for jQuery
-          betaDir = findDirectoryContainingText(treeView.roots[0], "alpha\\\\beta")
+          betaDir = findDirectoryContainingText(treeView.roots[0], "alpha\\beta")
         else
           betaDir = findDirectoryContainingText(treeView.roots[0], "alpha#{path.sep}beta")
         betaDir.expand()
@@ -2569,7 +2569,7 @@
       it "squashes three dir names when the first and second only contain single dirs", ->
         if path.sep is '\\'
           # First escape the backslashes for Coffeescript, then escape them for jQuery
-          epsilonDir = findDirectoryContainingText(treeView.roots[0], "gamma\\\\delta\\\\epsilon")
+          epsilonDir = findDirectoryContainingText(treeView.roots[0], "gamma\\delta\\epsilon")
         else
           epsilonDir = findDirectoryContainingText(treeView.roots[0], "gamma#{path.sep}delta#{path.sep}epsilon")
         epsilonDir.expand()


Patching the print dialog so that it opens as expected if the same model is opened twice in a row

--- assets/js/app.coffee
+++ assets/js/app.coffee
@@ -67,7 +67,7 @@

     # Show the print dialog when a file is selected
     # TODO: allow multiple file uploads, add pagination to the modal
-    @$files.on "change", => @open()
+    @$modal.on "change", ".cad-files", => @open()

     # Model Scaling
     @$scaleSlider.slider
@@ -83,7 +83,7 @@
     @$download.on "click", @_onDownloadClick

     # Testing
-    @open ["/ultimaker_platform.stl"]
+    #@open ["/ultimaker_platform.stl"]

   _onScaleSliderChange: (e, val) =>
     @$scaleVal.val(val).change()
@@ -124,12 +124,19 @@
     return false

   open: (files = @$files[0].files) =>
+    console.log files
     return unless files.length > 0
     $("body").mask("Loading...")
     @$canvas.viewer "loadModel", files[0], @_onModelLoad

   _onModelLoad: (@p3d) =>
-    @$modal.find(".local-download-link").html "Download Stl"
+    # Repopulating the $files element so that we can catch change events even when the same
+    # file is selected twice in a row
+    fileHtml = @$files.clone().wrap('<div/>').parent().html()
+    @$files.remove()
+    @$files = $(fileHtml).prependTo @$modal
+
+    @$download.html "Download Stl"
     @$scaleVal.val(1)
     @$scaleVal.trigger "change"
     $("body").unmask()


Absolute movements

Absolute movements

--- src/config/turtles.coffee
+++ src/config/turtles.coffee
@@ -2,7 +2,7 @@

 draw_leg = (scale, offset, dir) ->
   arc = if dir < 1 then 0 else 1
-  "m#{offset*scale},0 l#{scale},#{dir*3*scale}
+  "M#{offset*scale},0 l#{scale},#{dir*3*scale}
    a1,2 0 1,#{arc} #{-1*scale},#{-1*dir*3*scale}z m#{-offset*scale},0"

 draw_legs = (scale) ->
@@ -10,14 +10,14 @@
   draw_leg(scale, -1, -1) + draw_leg(scale, -1, 1)

 draw_face = (scale) ->
-  "m#{2.5*scale},0
+  "M#{2.5*scale},0
    a3,2 0 0,0 #{2*scale},0
    a3,2 0 0,0 #{-2*scale},0
    z m#{-3.5*scale},0"

 draw_shell = (scale) ->
-  "m#{-3*scale},0 a3,2 0 1,0 #{6*scale},0
-   m0,0           a3,2 0 1,0 #{-6*scale},0z"
+  "M#{-3*scale},0 a3,2 0 1,0 #{6*scale},0
+                  a3,2 0 1,0 #{-6*scale},0z"

 exports.turtles = {
   _LABEL: "turtles"


Update snippets to always use async spec functions


updating pml, kinda dirty checks

updating pml, kinda dirty checks

--- src/scripts/drush.coffee
+++ src/scripts/drush.coffee
@@ -41,7 +41,7 @@

     drush_cc: (msg, command) ->
       output = ''
-      msg.send "This may take a minute..."
+      msg.send "This may take a moment..."
       clearcache = spawn("drush", [command.alias, "cc", "all"])
       clearcache.stdout.on "data", (data) ->
         output += data
@@ -52,12 +52,35 @@
           output += "Cache clear complete."
         msg.send output

-#   drush_pml: (msg, command) ->
-#     output = ''
-#     # @TODO loop through command.args and append args that appear in allowed_options
-#     allowed_options = ['--enabled', '--disabled', '--core', '--no-core']
-#     spawn_options = [command.alias, "pml", "--pipe"]
-#     pml = spawn("drush", [command.alias, "pml", "--status=enabled", "--no-core"])
+    drush_pml: (msg, command) ->
+      output = ''
+      modules_state = "--status=enabled"
+      modules_core = "--no-core"
+      unless command.args.indexOf("--disabled") is -1
+        modules_state = "--status=disabled"
+      unless command.args.indexOf("--core") is -1
+        modules_core = "--core"
+
+      msg.send "This may take a moment..."
+
+      # @TODO loop through command.args and append args that appear in allowed_options
+      spawn_options = [command.alias, "pml", "--pipe", modules_state, modules_core]
+      pml = spawn("drush", spawn_options)
+      pml.stdout.on "data", (data) ->
+        output += data
+      pml.stderr.on "data", (data) ->
+        output = "We've experienced and error fetching module list."
+      pml.on "exit", (code) ->
+        if code is 0
+          output += "Module list complete."
+        msg.send output
+
+  # verify alias before firing the command, saves us time on waiting for an err from drush
+  verify_alias = (check_alias) ->
+    if site_aliases.indexOf(check_alias) is -1
+      false
+    else
+      true

   # parsing the user input after "drush "
   parse_command = (user_command) ->
@@ -65,7 +88,10 @@
     site_alias = extra_args.shift()
     command_suff = ''
     if site_alias.charAt(0) is "@"
-      command_suff = extra_args.shift()
+      unless verify_alias(site_alias) is false
+        command_suff = extra_args.shift()
+      else
+        `undefined`
     else
       command_suff = site_alias
       site_alias = ''
@@ -95,5 +121,4 @@
 # Hook in with hobot
 module.exports = (robot) ->
   robot.respond /drush (.*)$/i, (msg) ->
-    msg.send "drush fired!"
     drush.execute(msg)


Respond to more rules queries

Respond to more rules queries

--- src/scripts/rules.coffee
+++ src/scripts/rules.coffee
@@ -16,7 +16,7 @@
 #
 # the rules - Make sure hubot still knows the rules.
 module.exports = (robot) ->
-  robot.respond /(the rules|the laws)/i, (msg) ->
+  robot.respond /(what are )?the (three |3 )?(rules|laws)/i, (msg) ->
     text = msg.message.text
     if text.match(/apple/i) or text.match(/dev/i)
       msg.send otherRules.join('\n')


Only beep when there is a workspace

Only beep when there is a workspace

Some specs might not create one.

--- src/atom.coffee
+++ src/atom.coffee
@@ -604,7 +604,7 @@
   # Essential: Visually and audibly trigger a beep.
   beep: ->
     shell.beep() if @config.get('core.audioBeep')
-    @__workspaceView.trigger 'beep'
+    @__workspaceView?.trigger 'beep'
     @emitter.emit 'did-beep'

   # Essential: A flexible way to open a dialog akin to an alert dialog.


:lipstick: Remove extra newline

:lipstick: Remove extra newline

--- src/atom.coffee
+++ src/atom.coffee
@@ -51,7 +51,6 @@
     @pasteboard = new Pasteboard()
     @keymap = new Keymap()
     @syntax = deserialize(@getWindowState('syntax')) ? new Syntax()
-

   getCurrentWindow: ->
     remote.getCurrentWindow()


ComicSansDale, but only when you want it

--- app/assets/javascripts/views/clouds/chat/message.js.coffee
+++ app/assets/javascripts/views/clouds/chat/message.js.coffee
@@ -79,18 +79,10 @@
       content = content.replace(/^\/me/i,message.user().get('name'))
     else
       content = content.replace(/\n$/ig,"").replace(/\n/ig,"
")
-
-    # Connor is Comic Sans
-    if @model.user().get('username') is 'Connorcpu'
+
+    # Why not a comic sans message? :3c
+    if /\#ComicSansDale$/.test(content)
       content = " #{content} "
-
-    # Chapien is Papyrus
-    if @model.user().get('username') is 'chapien'
-      content = " #{content} "
-
-    # Smoozie is Verdana
-    if @model.user().get('username') is 'LordSmooze'
-      content = " #{content} "

     elem = $("

")
     elem.html(content)


Event creation now allows blank date field for undated events

test plan:
 * Navigate to calendar
 * Press "+" to create new event
 * Clear out date field and submit
 * Notice that event now shows up in "undated items" list

Fixes CNVS-18542

Change-Id: I4a73faac22f3aca0e1356122bbabb1018f9f7f38
Reviewed-on: https://gerrit.instructure.com/49008
Reviewed-by: Matthew Wheeler <ce71fbafda91d6c8f12582e1837687d5fe592dd9@instructure.com>
Tested-by: Jenkins
QA-Review: Steven Shepherd <e794458448443812fb2685675aab3bbd1a3891bc@instructure.com>
Product-Review: Matthew Wheeler <ce71fbafda91d6c8f12582e1837687d5fe592dd9@instructure.com>

--- app/coffeescripts/calendar/EditCalendarEventDetails.coffee
+++ app/coffeescripts/calendar/EditCalendarEventDetails.coffee
@@ -46,7 +46,8 @@
       data = @$form.getFormData(object_name: 'calendar_event')
       data = _.omit(data, 'date', 'start_time', 'end_time')

-      date = @$form.find('input[name=date]').data('date')
+      # check if input box was cleared for explicitly undated
+      date = @$form.find('input[name=date]').data('date') if @$form.find('input[name=date]').val()
       if date
         start_time = @$form.find('input[name=start_time]').data('date')
         start_at = date.toString('yyyy-MM-dd')


Remove outdated options from datetimepicker call

--- app/assets/javascripts/butler.js.coffee
+++ app/assets/javascripts/butler.js.coffee
@@ -36,9 +36,6 @@

 $ ->
   $('.datepicker').datetimepicker
-    locale: 'de'
-    pick12HourFormat: false
-    minuteStepping: 15

   $('textarea').autoGrow()


Added bio-kerosene from dry biomass to sankey

--- app/assets/javascripts/d3/sankey.coffee
+++ app/assets/javascripts/d3/sankey.coffee
@@ -54,6 +54,7 @@
           {left: 'dry',                             right: 'bunkers',                     gquery: 'dry_biomass_to_bunkers_in_biomass_sankey', color: '#009432'},
           {left: 'dry',                             right: 'export',                      gquery: 'dry_biomass_to_export_in_biomass_sankey', color: '#009432'},
           {left: 'dry',                             right: 'losses',                      gquery: 'dry_biomass_to_losses_in_biomass_sankey', color: '#DCDCDC'},
+          {left: 'dry',                             right: 'biofuels',                    gquery: 'dry_biomass_to_biofuels_in_biomass_sankey', color: '#009432'},
           {left: 'oily',                            right: 'biofuels',                    gquery: 'oily_biomass_to_biofuels_in_biomass_sankey', color: '#f9ca24'},
           {left: 'oily',                            right: 'export',                      gquery: 'oily_biomass_to_export_in_biomass_sankey', color: '#f9ca24'},
           {left: 'biogenic_waste',                  right: 'electricity_prod',            gquery: 'biogenic_waste_to_electricity_prod_in_biomass_sankey', color: '#006266'},


sankey: refactoring

sankey: refactoring

--- app/assets/javascripts/d3/sankey.coffee
+++ app/assets/javascripts/d3/sankey.coffee
@@ -203,12 +203,13 @@
         append("svg:svg").
         attr("height", @height).
         attr("width", @width)
-
-      colors = d3.scale.category20()
-
+      @links = @draw_links()
+      @nodes = @draw_nodes()
+
+    draw_links: =>
       # links are treated as a group made of a link path and label text element
       #
-      @links = @svg.selectAll('g.link').
+      links = @svg.selectAll('g.link').
         data(@module.links.models, (d) -> d.cid).
         enter().
         append("svg:g").
@@ -218,7 +219,7 @@
         attr("data-cid", (d) -> d.cid) # unique identifier
       # link path
       #
-      @links.append("svg:path").
+      links.append("svg:path").
         style("stroke-width", (link) -> link.value()).
         style("stroke", (link, i) -> link.color()).
         style("fill", "none").
@@ -228,7 +229,7 @@
         on("mouseout", @node_mouseout)
       # link labels
       #
-      @links.append("svg:text").
+      links.append("svg:text").
       attr("class", "link_label").
       attr("x", (d) => @x d.left_x()).
       attr("y", (d) => @y d.left_y()).
@@ -237,12 +238,15 @@
       style("opacity", 0).
       text((d) => @format_value d.value())

+      return links
+
+    draw_nodes: =>
       # Node elements are grouped inside an svg element, so we can use relative
       # coordinates
       #
       # The container just stores the x and y coordinates
       #
-      @nodes = @svg.selectAll("svg.node").
+      nodes = @svg.selectAll("svg.node").
         data(@module.nodes.models, (d) -> d.get('id')).
         enter().
         append("svg").
@@ -253,7 +257,9 @@

       # The rectangle just cares about its size and color
       #
-      @nodes.append("svg:rect").
+      colors = d3.scale.category20()
+
+      nodes.append("svg:rect").
         attr("stroke", "gray").
         attr("fill", (datum, i) -> colors(i)).
         attr("width", @x @module.Node.width).
@@ -264,11 +270,13 @@
       # And here we have the label. We use a +svg:text+ element that will then
       # hold a +tspan+ element for each line
       #
-      @nodes.append("svg:text").
+      nodes.append("svg:text").
         attr("class", "label").
         attr("x", 5).
         attr("y", 10).
         each(@add_label) # call() passes the entire collection
+
+      return nodes

     # adding multiline labels is harder than you would expect, let's move this
     # logic to a separate method.


update end date only when already set

update end date only when already set

--- app/assets/javascripts/layout.js.coffee
+++ app/assets/javascripts/layout.js.coffee
@@ -40,7 +40,7 @@
         from_moment = moment(this.getDate(true))
         to_moment = moment(picker_to.data('pickadate').getDate(true))

-        if to_moment.isBefore(from_moment)
+        if to_moment.isBefore(from_moment) && picker_to.not(":empty")
           picker_to.data('pickadate').setDate(from_moment.year(), from_moment.months() + 1, from_moment.date())

     picker_to = $(picker_to_element).pickadate


remove field works

remove field works

--- app/assets/javascripts/panels.js.coffee
+++ app/assets/javascripts/panels.js.coffee
@@ -50,13 +50,14 @@
     new_fieldset.insertBefore($('.add_fields'))
     $('Remove panel').insertBefore($(event.target))

-  remove_fields = () ->
-    alert 'hello'
-    #$(this).closest('.nested_fields').css('border', '1px solid red')
+  remove_fields = (event) ->
+    $(event.target).prev('.nested_fields').hide()
+

   $(document).on 'click', '.add_fields', (event) ->
+    event.preventDefault()
     add_fields(event)

   $(document).on 'click', '.remove_fields', (event) ->
-    #add_fields(event)
-    remove_fields()
+    event.preventDefault()
+    remove_fields(event)


jQuery Google Map function has been added, using CoffeeScript. We have tested it with some hardcoded data

--- app/assets/javascripts/places.js.coffee
+++ app/assets/javascripts/places.js.coffee
@@ -1,6 +1,30 @@
 # Place all the behaviors and hooks related to the matching controller here.
 # All this logic will automatically be available in application.js.
 # You can use CoffeeScript in this file: http://coffeescript.org/
+#
+# Import the underscore and gmaps javascript source code.
+#
+#= require underscore
+#= require gmaps/google

-#= require underscore
-#= require gmaps/google+@googleMap = (content) ->
+  handler = Gmaps.build("Google")
+  handler.buildMap
+    provider: {}
+    internal:
+      id: "map"
+  , ->
+    markers = handler.addMarkers(content)
+    handler.bounds.extendWith markers
+    handler.fitMapToBounds()
+
+content = [
+  {lat:22.2626188, lng: 114.1301186,infowindow: "hello!", link: 'a'},
+  {lat:22.3907897, lng: 114.2022941,infowindow: "hello!", link:'b'}
+]
+
+$ ->
+  $.ajax
+    url: '/places.json'
+  .done (data) ->
+    googleMap content


Close share dropdown when clicked outside of

--- app/assets/javascripts/videos.js.coffee
+++ app/assets/javascripts/videos.js.coffee
@@ -1,3 +1,11 @@
 $ ->
-	$('.video a.share').click ->
-		$(this).next('.shareDropdown').toggle()+	itemOpened = 0
+	$('.video a.share').click (toggleClick) ->
+		itemOpened++
+		dropdown = $(this).next('.shareDropdown').toggle()
+		button = $(toggleClick.target)
+		$(document).bind 'click.' + itemOpened, {ns: itemOpened}, (evt) ->
+			target = $(evt.target)
+			if !dropdown.has(target).length and button.get(0) != target.get(0)
+				dropdown.hide()
+				$(document).unbind('.' + evt.data.ns)


Avoid relying on ::scrollTop to calculate logical height

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -352,8 +352,7 @@
     [startRow, endRow]

   getLogicalHeight: ->
-    [startRow, endRow] = @getVisibleRowRange()
-    endRow - startRow
+    Math.floor(@getHeight() / @getLineHeightInPixels())

   intersectsVisibleRowRange: (startRow, endRow) ->
     [visibleStart, visibleEnd] = @getVisibleRowRange()


No longer need this as the event method passes it through

--- src/display-buffer.coffee
+++ src/display-buffer.coffee
@@ -56,7 +56,6 @@
     @decorationMarkerDestroyedSubscriptions = {}
     @updateAllScreenLines()
     @createFoldForMarker(marker) for marker in @buffer.findMarkers(@getFoldMarkerAttributes())
-    @subscribe @tokenizedBuffer.onDidChangeGrammar (grammar) => @emit 'grammar-changed', grammar
     @subscribe @tokenizedBuffer, 'tokenized', => @emit 'tokenized'
     @subscribe @tokenizedBuffer, 'changed', @handleTokenizedBufferChange
     @subscribe @buffer.onDidUpdateMarkers @handleBufferMarkersUpdated


Move 'check' to top of 'isBlogAuthorized' to satisfy 'audit-arguments'. Closes #181.

- Inserted into middle of function before because 'isBlogAuthorized' optionally
  had no arguements. Now that we're satisfying checks with optional arguments
  (null, undefined values), we can move up top

--- collections/post.coffee
+++ collections/post.coffee
@@ -88,6 +88,8 @@
       !! Post.first slug: slug

     isBlogAuthorized: () ->
+      check arguments[0], Match.OneOf(Object, Number, String, null, undefined)
+
       if not Meteor.user()
         return false

@@ -114,8 +116,6 @@
       if Blog.settings.authorRole

         # Get the post
-        check arguments[0], Match.OneOf(Object, Number, String, null, undefined)
-
         if _.isObject arguments[0]
           post = arguments[0]
         else if _.isNumber(arguments[0]) or _.isString(arguments[0])


Modified in browser at pixie.strd6.com

Modified in browser at pixie.strd6.com

--- src/engine_tilemap.coffee
+++ src/engine_tilemap.coffee
@@ -35,7 +35,7 @@
   loadMap: (name, complete) ->
     clearObjects = updating

-    map = Tilemap.load
+    I.map = Tilemap.load
       name: name
       complete: complete
       entity: self.add


webapp/rmd: fix multiplex syntax highlighting for "``` {r}" blocks with one or more spaces, because they do also compile

--- src/smc-webapp/codemirror/custom-modes.coffee
+++ src/smc-webapp/codemirror/custom-modes.coffee
@@ -103,7 +103,7 @@
     # all engine modes: names(knitr::knit_engines$get())
     for name in  ['ruby', 'r', 'python', 'octave', 'fortran95', 'fortran',  'octave', 'bash', 'go', 'julia', 'perl']
         mode = modes[name]
-        open = new RegExp("```{#{name}[^}]*?}")
+        open = new RegExp("```\\s*{#{name}[^}]*?}")
         options.push
             open  : open
             close : "```"
@@ -111,7 +111,7 @@
             mode  : CodeMirror.getMode(config, mode)

     # ATTN: this case must come later, it is less specific
-    # inline, just `r ...` exists, no other languages.
+    # inline, just `r ...` exists, not for other languages.
     options.push
         open : '`r'
         close: '`'


Added textOverflow and whitespace support

--- framer/TextLayer.coffee
+++ framer/TextLayer.coffee
@@ -25,6 +25,8 @@
 		"textTransform"
 		"textIndent"
 		"textDecoration"
+		"textOverflow"
+		"whiteSpace"
 		"direction"
 		"font"
 		"borderWidth"
@@ -48,15 +50,15 @@
 		if not options.font? and not options.fontFamily?
 			options.fontFamily = @defaultFont()

+		# Keeps track if the width or height are explicitly set, so we shouldn't update it afterwards
+		@explicitWidth = options.width?
+		@explicitHeight = options.height?
+
 		super options

 		@font ?= @fontFamily
 		# Set padding
 		@padding = options.padding or Utils.rectZero()
-
-		# Keeps track if the width or height are explicitly set, so we shouldn't update it afterwards
-		@explicitWidth = options.width?
-		@explicitHeight = options.height?

 		# Reset width and height
 		@autoSize()
@@ -133,7 +135,7 @@
 			@style.padding =
 				"#{@_padding.top}px #{@_padding.right}px #{@_padding.bottom}px #{@_padding.left}px"

-	@define "fontFamily", layerProperty(@, "fontFamily", "fontFamily", null, _.isString, fontFamilyFromObject, (layer, value) -> layer.font = value)
+	@define "fontFamily", layerProperty(@, "fontFamily", "fontFamily", null, _.isString, fontFamilyFromObject, {}, (layer, value) -> layer.font = value)
 	@define "fontSize", layerProperty(@, "fontSize", "fontSize", null, _.isNumber)
 	@define "fontWeight", layerProperty(@, "fontWeight", "fontWeight")
 	@define "fontStyle", layerProperty(@, "fontStyle", "fontStyle", "normal", _.isString)
@@ -144,8 +146,35 @@
 	@define "textTransform", layerProperty(@, "textTransform", "textTransform", "none", _.isString)
 	@define "textIndent", layerProperty(@, "textIndent", "textIndent", null, _.isNumber)
 	@define "textDecoration", layerProperty(@, "textDecoration", "textDecoration", null, _.isString)
+	@define "textOverflow", layerProperty(@, "textOverflow", "textOverflow", null, _.isString, null, {}, (layer, value) ->
+		if value in ["ellipsis", "clip"]
+			layer.clip = true
+			if layer.explicitHeight
+				layer.multiLineOverflow = value is "ellipsis"
+			else
+				layer.whiteSpace = "nowrap"
+				layer.multiLineOverflow = false
+		else
+			layer.whiteSpace = null
+			layer.clip = false
+			layer.multiLineOverflow = false
+	)
+	@define "whiteSpace", layerProperty(@, "whiteSpace", "whiteSpace", null, _.isString)
 	@define "direction", layerProperty(@, "direction", "direction", null, _.isString)

+	@define "multiLineOverflow",
+		get: ->
+			@_multiLineOverFlow ? false
+		set: (value) ->
+			@_multiLineOverFlow = true
+			if value
+				@style["-webkit-line-clamp"] = Math.ceil(@height / (@fontSize*@lineHeight))
+				@style["-webkit-box-orient"] = "vertical"
+				@style["display"] = "-webkit-box"
+			else
+				@style["-webkit-line-clamp"] = null
+				@style["-webkit-box-orient"] = null
+				@style["display"] = "block"

 	@define "font", layerProperty @, "font", null, null, validateFont, null, {}, (layer, value) ->
 		if _.isObject(value)


Added local_time to application.js.coffee

--- app/assets/javascripts/application.js.coffee
+++ app/assets/javascripts/application.js.coffee
@@ -21,6 +21,7 @@
 #= require social-share-button
 #= require rails_confirm_dialog
 #= require jquery.scrollto
+#= require local_time

 # Add error class to .avatar images if they fail to load
 # See avatar.scss and _avatar.html.haml


hot fix

hot fix

--- app/assets/javascripts/cms_deploys.js.coffee
+++ app/assets/javascripts/cms_deploys.js.coffee
@@ -18,10 +18,10 @@
       @pusher = new Pusher('fdda70c3d83954241af5', { encrypted: true })
       @channel = @pusher.subscribe("#{@configs.channel}")

-    that = this
-    @channel.bind('my_event', (data) ->
-      that.taskCompleted(data)
-    )
+      that = this
+      @channel.bind('my_event', (data) ->
+        that.taskCompleted(data)
+      )

   taskCompleted: (data) ->
     appWrapper = $("li.#{data.app}")


merit order chart: prevent errors when rendering and data not available

--- app/assets/javascripts/d3/merit_order.coffee
+++ app/assets/javascripts/d3/merit_order.coffee
@@ -30,14 +30,14 @@
         gquery_key: "merit_order_#{k}_operating_costs_in_merit_order_table"
       D3.merit_order.series.push @gquery_y

-    value_x: => @gquery_x.future_value()
+    value_x: => @gquery_x.future_value() || 0
     value_y: =>
       if @get('key') == 'must_run'
         1
       else
         @original_y_value()

-    original_y_value: => @gquery_y.future_value()
+    original_y_value: => @gquery_y.future_value() || 0

     label: => @get('label') || @get('key')

@@ -108,10 +108,6 @@
         attr("class", "merit_order_node").
         attr("fill", (d) => d.get 'color').
         style("stroke", (d) => d3.rgb(d.get 'color').darker(1)).
-        attr("y", (d) => @height - @y(d.value_y()) - .5).
-        attr("x", (d, i) -> i * 30).
-        attr("height", (d) => @y d.value_y()).
-        attr("width", (d) => @x d.value_x()).
         on("mouseover", ->
           item = d3.select(this)
           item.transition().attr("fill", (d) -> d3.rgb(d.get("color")).brighter(1))


removed useless comment from ember task model.

--- app/assets/javascripts/models/task.js.coffee
+++ app/assets/javascripts/models/task.js.coffee
@@ -14,7 +14,6 @@

   isMetadataTask: false
   isMessage: Ember.computed.equal('type', 'MessageTask')
-  # paper: DS.belongsTo('paper')
   paper: DS.belongsTo('paper', async: true)
   litePaper: DS.belongsTo('litePaper')


Override iOS keyboard behaviour

Override iOS keyboard behaviour

--- app/assets/javascripts/site_search.js.coffee
+++ app/assets/javascripts/site_search.js.coffee
@@ -1,6 +1,5 @@
 $ ->
   if $('#full-search').length
-    $('#q').focus() unless $('#q').val().length

     # Load more results async
     $(".results").on "click", "#load-more-search-results a", (event) ->
@@ -9,56 +8,69 @@
         $('#load-more-search-results').replaceWith(data)
       $(this).text("Laddar fler...").addClass('disabled')

-  # Autocomplete
-  $searchField = $('#full-search #q')
-  if $searchField.length
-    $searchField.autocomplete
-      source: (request, response) ->
-        $.ajax
-          url: $searchField.attr("data-autocomplete-path")
-          data:
-            q: request.term.toLowerCase()
-            ilang: 'sv'
-          dataType: "jsonp"
-          jsonpCallback: "results"
-          success: (data) ->
-            if data.length
-              response $.map data, (item) ->
-                return {
-                  hits: item.nHits
-                  suggestionHighlighted: item.suggestionHighlighted
-                  value: item.suggestion
-                }
-      minLength: 2
-      select: (event, ui) ->
-        document.location = $("#full-search").attr('action') + '?q=' + unescape(ui.item.value)
-    .data( "ui-autocomplete" )._renderItem = (ul, item) ->
-      return $("

")
-      .data("ui-autocomplete-item", item)
-      .append("" + item.hits + "" + item.suggestionHighlighted + "")
-      .appendTo(ul)
+    $searchField = $('#full-search #q')

-  # Event tracking of details for selected link in the search results
-  if $("section.site-search").length
-    $('body').on "click", "section.site-search h2 a, section.site-search .ess-bestbets a, section.site-search ul.breadcrumb a, section.site-search .categories a", (event) ->
-      $a = $(this)
-      if typeof gaDelayEvent is "function" then gaDelayEvent($a, event)
-      link = $a.attr('href')
-      GAAction = $("#q").val()
-      GALabel = $.trim($a.text()) + " " + link
+    # Autocomplete
+    if $searchField.length
+      $searchField.autocomplete
+        source: (request, response) ->
+          $.ajax
+            url: $searchField.attr("data-autocomplete-path")
+            data:
+              q: request.term.toLowerCase()
+              ilang: 'sv'
+            dataType: "jsonp"
+            jsonpCallback: "results"
+            success: (data) ->
+              if data.length
+                response $.map data, (item) ->
+                  return {
+                    hits: item.nHits
+                    suggestionHighlighted: item.suggestionHighlighted
+                    value: item.suggestion
+                  }
+        minLength: 2
+        select: (event, ui) ->
+          document.location = $("#full-search").attr('action') + '?q=' + unescape(ui.item.value)
+      .data( "ui-autocomplete" )._renderItem = (ul, item) ->
+        return $("

")
+        .data("ui-autocomplete-item", item)
+        .append("" + item.hits + "" + item.suggestionHighlighted + "")
+        .appendTo(ul)

-      # Track all clicks in the results list
-      if $a.closest(".results").length > 0
-        _gaq.push(['_trackEvent', 'SearchClickPosition', GAAction, GALabel, $(".results > ul > li").index($a.closest("li")) + 1, 10])
+    # Event tracking of details for selected link in the search results
+    if $("section.site-search").length
+      $('body').on "click", "section.site-search h2 a, section.site-search .ess-bestbets a, section.site-search ul.breadcrumb a, section.site-search .categories a", (event) ->
+        $a = $(this)
+        if typeof gaDelayEvent is "function" then gaDelayEvent($a, event)
+        link = $a.attr('href')
+        GAAction = $("#q").val()
+        GALabel = $.trim($a.text()) + " " + link

-      # Track clicks on breadcrumbs in the results list
-      if $a.closest(".breadcrumb").length > 0
-        _gaq.push(['_trackEvent', 'SearchClickBreadcrumb', GAAction,  GALabel])
+        # Track all clicks in the results list
+        if $a.closest(".results").length > 0
+          _gaq.push(['_trackEvent', 'SearchClickPosition', GAAction, GALabel, $(".results > ul > li").index($a.closest("li")) + 1, 10])

-      # Track clicks on editors choich in the results list
-      if $a.closest(".editors_choice").length > 0
-        _gaq.push(['_trackEvent', 'SearchClickEditorsChoice', GAAction,  GALabel])
+        # Track clicks on breadcrumbs in the results list
+        if $a.closest(".breadcrumb").length > 0
+          _gaq.push(['_trackEvent', 'SearchClickBreadcrumb', GAAction,  GALabel])

-      # Track clicks on editors choich in the results list
-      if $a.closest(".categories").length > 0
-        _gaq.push(['_trackEvent', 'SearchClickCategory', GAAction,  GALabel])
+        # Track clicks on editors choich in the results list
+        if $a.closest(".editors_choice").length > 0
+          _gaq.push(['_trackEvent', 'SearchClickEditorsChoice', GAAction,  GALabel])
+
+        # Track clicks on editors choich in the results list
+        if $a.closest(".categories").length > 0
+          _gaq.push(['_trackEvent', 'SearchClickCategory', GAAction,  GALabel])
+
+    # Override user agents and scroll to search box on narrow devices
+    if $(document).width() <= 4568
+      newY = 75
+      $("body").css("min-height", $(document).height() + newY)
+      $searchField.focus ->
+        $searchField.css("font-size", "16px") # hack to prevent iOS from zooming
+        window.scrollTo(0, newY - 6)
+
+    else # set focus on field if not a narrow device and if no search field is empty
+      $searchField.focus() unless $searchField.val().length
+


prevent js error when the avatar input is empty

--- app/coffee/modules/user-settings/main.coffee
+++ app/coffee/modules/user-settings/main.coffee
@@ -138,8 +138,9 @@
             $el.find("#avatar-field").click()

         $el.on "change", "#avatar-field", (event) ->
-            $el.find('.overlay').show()
-            $rs.userSettings.changeAvatar($scope.avatarAttachment).then(onSuccess, onError)
+            if $scope.avatarAttachment
+                $el.find('.overlay').show()
+                $rs.userSettings.changeAvatar($scope.avatarAttachment).then(onSuccess, onError)

         # Use gravatar photo
         $el.on "click", "a.use-gravatar", (event) ->


make jscuke pass

make jscuke pass

--- lineman/features/step_definitions/discussion/comment_steps.coffee
+++ lineman/features/step_definitions/discussion/comment_steps.coffee
@@ -25,13 +25,14 @@
       callback()

   @Then /^the like button should say 'Unlike'$/, (callback) ->
-    @browser.findElement(@by.css('.like-comment-btn')).getText().then (text)=>
+    @browser.findElement(@by.css('.unlike-comment-btn')).getText().then (text)=>
       @assert.equal text, 'Unlike'
       callback()

   @Then /^I should see that I have liked the comment$/, (callback) ->
-    # express the regexp above with the code you wish you had
-    callback.pending()
+    @browser.findElement(@by.css('.liked-by')).getText().then (text)=>
+      @assert.equal text, 'Liked by You'
+      callback()

     #@browser.get('http://localhost:8000/discussions/1').then ->
       #done()


Fix full work of autocomplete from function's parameters

--- lib/providers/autocomplete-provider.coffee
+++ lib/providers/autocomplete-provider.coffee
@@ -87,7 +87,8 @@
           continue
         else
           className = parser.getVariableType(editor, bufferPosition, element)
-          break
+          loop_index++
+          continue

       # Last element
       if loop_index >= elements.length - 1


Automatically pop out sidebar on load

Automatically pop out sidebar on load

--- annotran/static/scripts/annotator/host.coffee
+++ annotran/static/scripts/annotator/host.coffee
@@ -57,6 +57,8 @@
         options.showHighlights = true
       this.setVisibleHighlights(options.showHighlights)

+      this.show()
+
       # Show the UI
       @frame.css('display', '')


Save caption state

Save caption state

--- app/assets/javascripts/tenon/features/tenon_content/caption_toggler.js.coffee
+++ app/assets/javascripts/tenon/features/tenon_content/caption_toggler.js.coffee
@@ -3,9 +3,9 @@
     $(document).on('click', '.image-controls .toggle-caption', @_toggleCaption)

   _toggleCaption: (e) =>
-    e.preventDefault();
-    $image = $(e.currentTarget).closest('.image-controls').data('image');
-    $image.find('.caption').toggle();
-    $input = $image.siblings('input[name$="[show_caption]"]')
+    e.preventDefault()
+    $image = $(e.currentTarget).closest('.image-controls').data('image')
+    $image.find('.caption').toggle()
+    $input = $image.find('input[name$="[show_caption]"]')
     $input.val(if $input.val() == "t" then "f" else "t")
     $image.trigger('tenon.content.column_resized')


Remove unused function

Remove unused function

--- app/javascript/src/legacy/common.coffee
+++ app/javascript/src/legacy/common.coffee
@@ -183,12 +183,6 @@
     container = document.createElement('div')
     container.innerHTML = this
     container.removeChild container.firstChild
-
-window.createElement = (type, className, html) ->
-  element = $(document.createElement(type))
-  element.className = className
-  element.innerHTML = html
-  element

 ### Prototype calls onSuccess instead of onFailure when the user cancelled the AJAX
 # request.  Fix that with a monkey patch, so we don't have to track changes inside


Fixed bug.

Fixed bug.

--- app/lib/collections/schemas/user.coffee
+++ app/lib/collections/schemas/user.coffee
@@ -6,6 +6,7 @@
     max: 32
   services:
     type: Object
+    optional: true
     blackbox: true
   emails:
     type: [Object]
@@ -15,6 +16,8 @@
     type: String
   'emails.$.verified':
     type: Boolean
+    optional: true
+    defaultValue: false
   profile:
     type: schemas.UserProfile
     label: 'Profile'


Refector: clean up code.

Refector: clean up code.

--- app/assets/javascripts/branch-graph.js.coffee
+++ app/assets/javascripts/branch-graph.js.coffee
@@ -131,7 +131,7 @@
     shortrefs = refs
     # Truncate if longer than 15 chars
     shortrefs = shortrefs.substr(0, 15) + "…"  if shortrefs.length > 17
-    text = r.text(x + 8, y, shortrefs).attr(
+    text = r.text(x + 4, y, shortrefs).attr(
       "text-anchor": "start"
       font: "10px Monaco, monospace"
       fill: "#FFF"
@@ -139,7 +139,7 @@
     )
     textbox = text.getBBox()
     # Create rectangle based on the size of the textbox
-    rect = r.rect(x, y - 7, textbox.width + 15, textbox.height + 5, 4).attr(
+    rect = r.rect(x, y - 7, textbox.width + 5, textbox.height + 5, 4).attr(
       fill: "#000"
       "fill-opacity": .5
       stroke: "none"
@@ -206,22 +206,19 @@

       # Build line shape
       if parent[1] is commit.space
-        d1 = [0, 5]
-        d2 = [0, 10]
-        arrow = "l-2,5,4,0,-2,-5"
+        offset = [0, 5]
+        arrow = "l-2,5,4,0,-2,-5,0,5"

       else if parent[1] < commit.space
-        d1 = [3, 3]
-        d2 = [7, 5]
-        arrow = "l5,0,-2,4,-3,-4"
+        offset = [3, 3]
+        arrow = "l5,0,-2,4,-3,-4,4,2"

       else
-        d1 = [-3, 3]
-        d2 = [-7, 5]
-        arrow = "l-5,0,2,4,3,-4"
+        offset = [-3, 3]
+        arrow = "l-5,0,2,4,3,-4,-4,2"

       # Start point
-      route = ["M", x + d1[0], y + d1[1]]
+      route = ["M", x + offset[0], y + offset[1]]

       # Add arrow if not first parent
       if i > 0
@@ -230,7 +227,6 @@
       # Circumvent if overlap
       if commit.space isnt parentCommit.space or commit.space isnt parent[1]
         route.push(
-          "L", x + d2[0], y + d2[1],
           "L", parentX2, y + 10,
           "L", parentX2, parentY - 5,
         )


Fixed multiple date pickers on a single page

--- app/assets/javascripts/bootstrap_builders/date-picker-input.coffee
+++ app/assets/javascripts/bootstrap_builders/date-picker-input.coffee
@@ -1,85 +1,59 @@
 (($, window, document) ->
-  $this = undefined
-  $text_ele = undefined
-  $form = undefined
-  $year_ele = undefined
-  $month_ele = undefined
-  $day_ele = undefined
-  $hour_ele = undefined
-  $min_ele = undefined
-
   methods = {
     # Constructor.
     init: (options) ->
-      $this = $(@)
-      throw "Invalid element given." if $this.length <= 0
-
       # The hidden Rails-inputs that will get the actual values like year, month, date, hour and minute.
-      $text_ele = $("input.bb_date_picker, input.bb_date_time_picker", $this)
-      $form = $(this).parents("form").first()
-      $year_ele = $(".bb-date-picker-input-year", $this).first()
-      $month_ele = $(".bb-date-picker-input-moth", $this).first()
-      $day_ele = $(".bb-date-picker-input-day", $this).first()
-      $hour_ele = $(".bb-date-picker-input-hour", $this).first()
-      $min_ele = $(".bb-date-picker-input-min", $this).first()
-
-      throw "Could not find the year element." if $year_ele.length <= 0
+      text_ele = $("input.bb_date_picker, input.bb_date_time_picker", $(@))
+      form = text_ele.parents("form").first()

       # Update values on form-submit.
-      if $form.length > 0 && $form.data("bb-date-picker-input") != "true"
-        $form.data("bb-date-picker-input", "true")
+      if form.length > 0 && form.data("bb-date-picker-input") != "true"
+        form.data("bb-date-picker-input", "true")

-        $form.submit ->
+        form.submit ->
           $(".bb-date-picker-input", this).each ->
             $(this).bbDatePickerInput("updateValues")
           return true

       # Update the values when the date is changed or upon blur
-      $text_ele.on "changeDate blur", ->
-        console.log "changeDate blur"
-        $(this).parents(".bb-date-picker-input").first().bbDatePickerInput("updateValues")
-
-      return $this
+      text_ele.on "changeDate blur", ->
+        parents = $(this).parents(".bb-date-picker")
+        throw "No parents were found" if parents.length <= 0
+        parents.first().bbDatePickerInput("updateValues")

     # Parses the date in the input-field and updates all the hidden Rails-inputs from the parsed values.
     updateValues: ->
-      # The hidden Rails-inputs that will get the actual values like year, month, date, hour and minute.
-      $text_ele = $("input.bb_date_picker, input.bb_date_time_picker", $this)
-      throw "No text element?" if $text_ele.length <= 0
+      text_ele = $("input.bb_date_picker, input.bb_date_time_picker", $(@))
+      year_ele = $(".bb-date-picker-input-year", $(@)).first()
+      month_ele = $(".bb-date-picker-input-moth", $(@)).first()
+      day_ele = $(".bb-date-picker-input-day", $(@)).first()
+      hour_ele = $(".bb-date-picker-input-hour", $(@)).first()
+      min_ele = $(".bb-date-picker-input-min", $(@)).first()

-      $form = $(this).parents("form").first()
-      $year_ele = $(".bb-date-picker-input-year", $this).first()
-      $month_ele = $(".bb-date-picker-input-month", $this).first()
-      $day_ele = $(".bb-date-picker-input-day", $this).first()
-      $hour_ele = $(".bb-date-picker-input-hour", $this).first()
-      $min_ele = $(".bb-date-picker-input-min", $this).first()
-
-      if $.trim($text_ele.val()) == ""
-        $year_ele.val("")
-        $month_ele.val("")
-        $day_ele.val("")
-        $hour_ele.val("")
-        $min_ele.val("")
-      else if match = $text_ele.val().match(/^\s*(\d+)-(\d+)-(\d+)\s+(\d+):(\d+)\s*$/)
-        $year_ele.val(match[1])
-        $month_ele.val(match[2])
-        $day_ele.val(match[3])
-        $hour_ele.val(match[4])
-        $min_ele.val(match[5])
-      else if match = $text_ele.val().match(/^\s*(\d+)-(\d+)-(\d+)\s*$/)
-        $year_ele.val(match[1])
-        $month_ele.val(match[2])
-        $day_ele.val(match[3])
-        $hour_ele.val(0)
-        $min_ele.val(0)
+      if $.trim(text_ele.val()) == ""
+        year_ele.val("")
+        month_ele.val("")
+        day_ele.val("")
+        hour_ele.val("")
+        min_ele.val("")
+      else if match = text_ele.val().match(/^\s*(\d+)-(\d+)-(\d+)\s+(\d+):(\d+)\s*$/)
+        year_ele.val(match[1])
+        month_ele.val(match[2])
+        day_ele.val(match[3])
+        hour_ele.val(match[4])
+        min_ele.val(match[5])
+      else if match = text_ele.val().match(/^\s*(\d+)-(\d+)-(\d+)\s*$/)
+        year_ele.val(match[1])
+        month_ele.val(match[2])
+        day_ele.val(match[3])
+        hour_ele.val(0)
+        min_ele.val(0)
       else
-        throw "Invalid date-format: '" + $text_ele.val() + "'."
+        throw "Invalid date-format: '" + text_ele.val() + "'."

       # Set the content to be a date, if this is a date-input-picker.
-      if match && $text_ele.hasClass("bb_date_picker")
-        $text_ele.val(match[1] + "-" + match[2] + "-" + match[3])
-
-      return $this
+      if match && text_ele.hasClass("bb_date_picker")
+        text_ele.val(match[1] + "-" + match[2] + "-" + match[3])
   }

   # Initialize the plugin.
@@ -93,5 +67,4 @@
 ) jQuery, window, document

 $ ->
-  $(".bb-date-picker").each ->
-    $(this).bbDatePickerInput()
+  $(".bb-date-picker").each -> $(this).bbDatePickerInput()


turned urlParams into a local variable

turned urlParams into a local variable

--- client/init.coffee
+++ client/init.coffee
@@ -12,10 +12,10 @@
 ide = require './ide'
 require './util'

-D.urlParams = {}
+urlParams = {}
 for kv in (location + '').replace(/^[^\?]*($|\?)/, '').split '&'
-  [_, k, v] = /^([^=]*)=?(.*)$/.exec kv; D.urlParams[unescape(k or '')] = unescape(v or '')
-if opener && (win = D.urlParams.win)? # are we running in a floating editor window?
+  [_, k, v] = /^([^=]*)=?(.*)$/.exec kv; urlParams[unescape(k or '')] = unescape(v or '')
+if opener && (win = urlParams.win)? # are we running in a floating editor window?
   $ ->
     wins = D.wins = opener.D.wins
     $('body').addClass('floating-window').html('

').layout


adding owner actions to product template

--- app/assets/javascripts/mobile/templates/product_template.js.coffee
+++ app/assets/javascripts/mobile/templates/product_template.js.coffee
@@ -36,9 +36,31 @@

-

-
-

+
+

+
+

+
+            {{#user_owns_store}}
+

+                    View
+

+

+                    Edit
+

+

+                    Delete
+

+

+

+                        {{product_status}}
+

+

+            {{/user_owns_store}}

 """


don't read vals from hidden inputs

don't read vals from hidden inputs

--- app/assets/javascripts/states/runbooks/views/run_command.js.coffee
+++ app/assets/javascripts/states/runbooks/views/run_command.js.coffee
@@ -23,9 +23,9 @@
         return

       command = command.clone()
-      args    = @$("div.args textarea").val()
-      stdin   = @$("div.stdin textarea").val()
-      env     = @$("div.env textarea").val()
+      args    = @$("div.args textarea").filter(":visible").val()
+      stdin   = @$("div.stdin textarea").filter(":visible").val()
+      env     = @$("div.env textarea").filter(":visible").val()

       @ui.run.addClass("disabled")
       @ui.spinner.show().addClass("fa-spin")


feat(home): update audio list once every 15 seconds

--- app/scripts/controllers/HomeCtrl.coffee
+++ app/scripts/controllers/HomeCtrl.coffee
@@ -107,5 +107,9 @@
 			$( "body" ).scrollspy target: "#menu"
 			window.scroll 0, $( "#remote" ).offset().top

+		setInterval ->
+			unless $scope.isSyncing
+				$scope.getList()
+		, 15 * 1000

 ]


kinetic_thingy_delegate: Suppress context menu when locked (override with shift).

--- Oghma/kinetic_thingy_delegate.coffee
+++ Oghma/kinetic_thingy_delegate.coffee
@@ -508,7 +508,7 @@
   # Is thingy context menuable?
   # @return [bool] Is thingy context menuable?
   is_context_menuable: ( event ) ->
-    event.evt.which == 3 && @is_drawn() && ( @is_owned() || event.evt.shiftKey )
+    event.evt.which == 3 && @is_drawn() && ( ( ! @is_locked() && @is_owned() ) || event.evt.shiftKey )

   # Is thingy controlled by grid mode.
   # @return [bool] Is thingy controlled by grid mode.


added order_item relationship

added order_item relationship

--- app/assets/javascripts/models/venta.js.coffee
+++ app/assets/javascripts/models/venta.js.coffee
@@ -9,5 +9,6 @@

   cliente:       DS.belongsTo("cliente")
   comprobante:   DS.belongsTo("comprobante")
+  orderItems:    DS.hasMany("orderItem")

 Ember.Inflector.inflector.irregular('venta', 'ventas');


Implement toggle button for score visualization

The score visualization can now be toggled on the repository map.
Another feature has been shipped.

Signed-off-by: Konrad Reiche <4ff0213f56e2082fcd8c882d04c546881c579ce4@gmail.com>

--- app/assets/javascripts/repositories.js.coffee
+++ app/assets/javascripts/repositories.js.coffee
@@ -40,6 +40,7 @@
       @map.addControl(scoreControl)

     initMarkers: () ->
+      @showScores = true
       markers = []

       for repository in gon.repositories
@@ -47,16 +48,25 @@
         latitude = repository['latitude']
         longitude  = repository['longitude']

-        marker = L.marker([latitude, longitude], {icon: @getScoreIcon(score)}).addTo(@map)
+        icon = @getScoreIcon(score)
+        options = { icon: icon, riseOnHover: true }
+
+        marker = L.marker([latitude, longitude], options).addTo(@map)
         marker.bindPopup(repository['name'])
-        markers.push(marker)
+        markers.push([marker, icon])

       return markers

     toggleMarkerIconsFunc: (markers) ->
       return () ->
-        for marker in markers
-          console.log marker
+        for markerIcon in markers
+          marker = markerIcon[0]
+          icon = markerIcon[1]
+
+          newIcon = if @showScores then icon else new L.Icon.Default()
+          marker.setIcon(newIcon)
+
+        @showScores = not @showScores

     getScoreIcon: (score) ->
       if score == null


Show notification when there is unsaved changes

--- client/main.coffee
+++ client/main.coffee
@@ -16,10 +16,14 @@

     @initAce()

-
     @model.bind "initialfetch",  =>
       console.log "settting HTML"
+      @removeUnsavedNotification()
       @setEditorContents @model.get "html"
+
+      @editor.getSession().on "change", =>
+        console.log "CHANGE"
+        @showUnsavedNotification()

     @model.bind "change", (slide) =>

@@ -37,9 +41,10 @@
     @editor = ace.edit "editor"
     @editor.setShowPrintMargin false
     HTMLmode = require("ace/mode/html").Mode
-    @editor.getSession().setTabSize(2);
-    # @editor.getSession().setUseWrapMode(true);
-    @editor.getSession().setMode(new HTMLmode())
+    session = @editor.getSession()
+    session.setTabSize(2);
+    # session.setUseWrapMode(true);
+    session.setMode(new HTMLmode())

     # Hide the line numbering, doesn't work perfectly
@@ -63,6 +68,10 @@
     @model.get "id"

+  showUnsavedNotification: ->
+    @saveButton.text "Save*"
+  removeUnsavedNotification: ->
+    @saveButton.text "Save"

   save: ->
     html = @editor.getSession().getValue()
@@ -70,6 +79,7 @@
     @model.save null,
       success: (e) =>
         @model.trigger "saved", @model
+        @removeUnsavedNotification()

         if not @hasEditUrl()
           window.location.hash = "#edit/#{ @model.get("id") }"


sort gradebook according to locale rules

not perfect, because the version that allows us to pass options like
specific locale or case insensivity only exists in Chrome, but still
much better than ASCII comparison even in older browsers

refs gh-319

test plan:
 * in a single course
 * name a student 'ñ'
 * name a student 'na'
 * name a student 'n'
 * in the latest version of Chrome
 * set your language to spanish on your profile page
 * go to gradebook2
 * it should be sorted as 'n', 'na', 'ñ'

Change-Id: I2b1f8e5f0071bfbaf8461697b4c663b06ca2f345
Reviewed-on: https://gerrit.instructure.com/21664
Tested-by: Jenkins <d95b56ce41a2e1ac4cecdd398defd7414407cc08@instructure.com>
Reviewed-by: Jon Jensen <44f878afe53efc66b76772bd845eb65944ed8232@instructure.com>
QA-Review: Jeremy Putnam <b030d6d6f199f844ec424882be473c2ab9adc93b@instructure.com>
Product-Review: Cody Cutrer <c4fe2b1d90ef8f2548c8aeabfa633434316f0305@instructure.com>

--- app/coffeescripts/gradebook2/Gradebook.coffee
+++ app/coffeescripts/gradebook2/Gradebook.coffee
@@ -55,7 +55,6 @@
       @chunk_start = 0
       @students = {}
       @rows = []
-      @sortFn = (student) -> student.sortable_name
       @assignmentsToHide = userSettings.contextGet('hidden_columns') || []
       @sectionToShow = userSettings.contextGet 'grading_show_only_section'
       @show_attendance = userSettings.contextGet 'show_attendance'
@@ -266,7 +265,6 @@
     # a full redraw
     buildRows: =>
       @rows.length = 0
-      sortables = {}

       for id, column of @gradeGrid.getColumns() when ''+column.object?.submission_types is "attendance"
         column.unselectable = !@show_attendance
@@ -278,12 +276,11 @@
         if @rowFilter(student)
           @rows.push(student)
           @calculateStudentGrade(student)
-          sortables[student.id] = @sortFn(student)

       @rows.sort (a, b) ->
-        if sortables[a.id] < sortables[b.id] then -1
-        else if sortables[a.id] > sortables[b.id] then 1
-        else 0
+        a.sortable_name.localeCompare(b.sortable_name,
+          window.I18n.locale,
+          { sensitivity: 'accent', ignorePunctuation: true, numeric: true})

       student.row = i for student, i in @rows
       @multiGrid.invalidate()


Fix long line in string-template

Fix long line in string-template

Trim down the linter warnings.

--- src/mixins/string-template.coffee
+++ src/mixins/string-template.coffee
@@ -17,8 +17,8 @@
       if tObj
         tObj
       else
-        errString = "The template file #{templatePath}/#{template} does not exist."
-        throw new Error errString
+        errStr = "The template file #{templatePath}/#{template} doesn't exist."
+        throw new Error errStr

   exports = (opts={}) ->
     # Reset between multiple calls.


Fixed bundle loading #355

Fixed bundle loading #355

--- src/goo/loaders/DynamicLoader.coffee
+++ src/goo/loaders/DynamicLoader.coffee
@@ -49,7 +49,7 @@
 	* @param {boolean} [parameters.ajax] If true, load resources from the server if not found in the cache. Defaults to true.
 	*###
 	class DynamicLoader
-		_jsonTest = /\.(shader|script|entity|material|scene|mesh|texture|skeleton|animation|clip)$/
+		_jsonTest = /\.(shader|script|entity|material|scene|mesh|texture|skeleton|animation|clip|bundle)$/

 		_texture_types = _.keys(ConfigHandler.getHandler('texture').loaders)

@@ -133,12 +133,11 @@
 		* mapping all loaded refs to their configuration, like so: <code>{sceneRef: sceneConfig, entity1Ref: entityConfig...}</code>.
 		*###
 		loadFromBundle: (ref, bundleName, options={})->
-			@_loader.load bundleName, (data)=>
-				bundleData = JSON.parse(data)
+			@_loadRef(bundleName).then (data)=>
 				if options.noCache
-					@_configs = bundleData
+					@_configs = data
 				else
-					_.extend @_configs, bundleData
+					_.extend @_configs, data

 				if not @_configs[ref]?
 					throw Error "#{ref} not found in bundle #{bundleName}. Available keys: \n#{_.keys(@_configs).join('\n')}"


HACK: Use stateb.us:3005 as state server

--- client/tawk.coffee
+++ client/tawk.coffee
@@ -6,9 +6,10 @@

 window.statebus_ready or= []
 window.statebus_ready.push(->
-  window.tawkbus = statebus()
-  tawkbus.sockjs_client("/*", "https://tawk.space")
-  window.tawk = tawkbus.sb
+  # HACK: Remove
+  window.tawkbus = window.bus
+  window.tawk = window.sb
+
   tawk.janus_initialized = false
   tawk.id = random_string(16)
   tawk.space = null # Will be filled in dom.TAWK


add Refer Teacher by Parent analytics (#4901)

--- app/views/core/ParentReferTeacherModal.coffee
+++ app/views/core/ParentReferTeacherModal.coffee
@@ -38,13 +38,14 @@
     @state.set({customContent: @$(e.currentTarget).val()})

   sendEmail: (e) ->
-    contact.sendParentTeacherSignup({
+    referMessage = {
       teacherEmail: @state.get('teacherEmail'),
       parentEmail: @state.get('parentEmail'),
       parentName: @state.get('parentName'),
       customContent: @state.get('customContent')
-    })
-
+    }
+    contact.sendParentTeacherSignup(referMessage)
+    window.tracker?.trackEvent 'Refer Teacher by Parent', message: referMessage
     true # Refreshes page


fix #225

fix #225

--- src/layout/sprites.coffee
+++ src/layout/sprites.coffee
@@ -47,6 +47,7 @@
     world.send 'inspect', child

   delete_sprite: (world, sprite) ->
+    world.send 'click'
     world.remove_child sprite

   # selection


added stack manipulation instructions

added stack manipulation instructions

--- grammars/intuicio4.cson
+++ grammars/intuicio4.cson
@@ -133,7 +133,7 @@
 		'name': 'constant.other.intuicio4'
 	}
 	{
-		'match': '\\b(call|async|parallel|join|ret|mov|add|sub|mul|div|and|or|xor|neg|lsh|rsh|eq|ls|gr|jif|goto|new|del|ptr|val|cast|vargs|vargr|mtxc|mtxd|lock|unlock)\\b'
+		'match': '\\b(call|async|parallel|join|ret|mov|add|sub|mul|div|and|or|xor|neg|lsh|rsh|eq|ls|gr|push|pop|drop|jif|goto|new|del|ptr|val|cast|vargs|vargr|mtxc|mtxd|lock|unlock)\\b'
 		'name': 'keyword.control.operation.intuicio4'
 	}
 	{


Track disposal of subscriptions made through deprecated ::on as well

--- src/file.coffee
+++ src/file.coffee
@@ -61,7 +61,7 @@
         Grim.deprecate("Use explictly-named event subscription methods instead")

     @willAddSubscription()
-    EmitterMixin::on.apply(this, arguments)
+    @trackUnsubscription(EmitterMixin::on.apply(this, arguments))

   onDidChange: (callback) ->
     @willAddSubscription()


Export CompositeUnsubscribe

Export CompositeUnsubscribe

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -1014,6 +1014,7 @@
   empty: =>
     @count() == 0

+Bacon.CompositeUnsubscribe = CompositeUnsubscribe

 class Some
   constructor: (@value) ->


remove internal ref to deprecated switch method

--- src/Bacon.coffee
+++ src/Bacon.coffee
@@ -437,7 +437,7 @@
     @flatMap (value) ->
       Bacon.later delay, value
   throttle: (delay) ->
-    @switch (value) ->
+    @flatMapLatest (value) ->
       Bacon.later delay, value
   bufferWithTime: (delay) ->
     values = []


Slave: Increase RPC timeout; Ensure we have a worker to give listeners to

* Increase RPC timeout to 5 seconds for our main channel (the one we use
  for handoffs)
* In `_landListener`, make sure we actually have a worker to send the
  listener to before just calling things

--- src/streammachine/modes/slave.coffee
+++ src/streammachine/modes/slave.coffee
@@ -37,7 +37,7 @@
         # -- Set up Internal RPC -- #

         if process.send?
-            @_rpc = new RPC process, functions:
+            @_rpc = new RPC process, timeout:5000, functions:
                 slave_port: (msg,handle,cb) =>
                     if @_lastAddress
                         cb null, @_lastAddress.port
@@ -154,10 +154,14 @@
     #----------

     _landListener: (obj,handle,cb) ->
-        # pick a worker randomly...
-        worker_id = _.sample(Object.keys(@lWorkers))
-        @lWorkers[worker_id].rpc.request "land_listener", obj, handle, (err) =>
-            cb err
+        worker_ids = Object.keys(@workers)
+
+        if worker_ids.length == 0
+            cb "No workers ready to receive listeners."
+        else
+            id = _.sample(worker_ids)
+            @workers[id].rpc.request "land_listener", obj, handle, (err) =>
+                cb err

     #----------


Preload a bunch of collections

Preload a bunch of collections

--- SingularityUI/app/application.coffee
+++ SingularityUI/app/application.coffee
@@ -2,9 +2,14 @@

 State = require 'models/State'

-Requests = require 'collections/Requests'
+RequestsActive = require 'collections/RequestsActive'
+RequestsPending = require 'collections/RequestsPending'
+RequestsCleaning = require 'collections/RequestsCleaning'
+
 TasksActive = require 'collections/TasksActive'
 TasksScheduled = require 'collections/TasksScheduled'
+
+Webhooks = require 'collections/Webhooks'

 class Application

@@ -40,8 +45,16 @@
             success: -> resolve()

         resources = [{
-            collection_key: 'requests'
-            collection: Requests
+            collection_key: 'requestsActive'
+            collection: RequestsActive
+            error_phrase: 'requests'
+        }, {
+            collection_key: 'requestsPending'
+            collection: RequestsPending
+            error_phrase: 'requests'
+        }, {
+            collection_key: 'requestsCleaning'
+            collection: RequestsCleaning
             error_phrase: 'requests'
         }, {
             collection_key: 'tasksActive'
@@ -51,6 +64,10 @@
             collection_key: 'tasksScheduled'
             collection: TasksScheduled
             error_phrase: 'scheduled tasks'
+        }, {
+            collection_key: 'webhooks'
+            collection: Webhooks
+            error_phrase: 'webhooks'
         }]

         _.each resources, (r) =>