code enhancements

code enhancements

--- app/coffee/drm-calendar/drm-calendar.coffee
+++ app/coffee/drm-calendar/drm-calendar.coffee
@@ -1,510 +1,513 @@
 ###############################################################################
 # Interactive JS Calendar
 ###############################################################################
-
+# needs support for events with start and end dates and times
+# needs support for events that recur a limited number of times
+# needs edit view
 "use strict"

 $ = jQuery
 class @DrmCalendar
     constructor: (@calendarClass = 'drm-calendar', @view = 'month', @addHolidays = yes) ->
         self = @
-        self.body = $ 'body'
-        self.daysPerWeek = 7
-        self.events = []
-        self.today = new Date()
-        self.currentMonth = self.today.getMonth()
-        self.currentYear = self.today.getFullYear()
-        self.currentDate = self.today.getDate()
-        self.calendarInnerClass = "drm-calendar-#{self.view}-view"
         self.calendar = $ ".#{self.calendarClass}"
-        self.calendarNav = $ '.drm-calendar-nav'
-        self.calendarSelect = $ '.drm-calendar-select'
-        self.calendarSelectButton = self.calendarSelect.find 'button[type=submit]'
-        self.addEventForm = self.calendar.find('form.drm-calendar-new-event').hide()
-        self.showEventFormButton = self.calendar.find 'button.drm-show-event-form'
-        self.calendarViewActiveButton = self.calendar.find(".drm-calendar-view-nav button[data-view=#{self.view}]").addClass 'active'
-        self.eventClass = 'drm-events'
-        self.classes =
-            weekend: 'drm-cal-weekend'
-            muted: 'drm-cal-muted'
-            holiday: 'drm-cal-holiday'
-            today: 'drm-cal-today'
-            month: 'drm-month'
-            week: 'drm-week'
-            date: 'drm-date'
-
-        self.months = [
-            'January'
-            'February'
-            'March'
-            'April'
-            'May'
-            'June'
-            'July'
-            'August'
-            'September'
-            'October'
-            'November'
-            'December']
-
-        self.days = [
-            'Sunday'
-            'Monday'
-            'Tuesday'
-            'Wednesday'
-            'Thursday'
-            'Friday'
-            'Saturday']
-
-        self.hours = [
-            {
-                name: 'All Day Event'
-                time: null
-            }
-            {
-                name: '12am'
-                time: 0
-            }
-            {
-                name: '1am'
-                time: 1
-            }
-            {
-                name: '2am'
-                time: 2
-            }
-            {
-                name: '3am'
-                time: 3
-            }
-            {
-                name: '4am'
-                time: 4
-            }
-            {
-                name: '5am'
-                time: 5
-            }
-            {
-                name: '6am'
-                time: 6
-            }
-            {
-                name: '7am'
-                time: 7
-            }
-            {
-                name: '8am'
-                time: 8
-            }
-            {
-                name: '9am'
-                time: 9
-            }
-            {
-                name: '10am'
-                time: 10
-            }
-            {
-                name: '11am'
-                time: 11
-            }
-            {
-                name: '12pm'
-                time: 12
-            }
-            {
-                name: '1pm'
-                time: 13
-            }
-            {
-                name: '2pm'
-                time: 14
-            }
-            {
-                name: '3pm'
-                time: 15
-            }
-            {
-                name: '4pm'
-                time: 16
-            }
-            {
-                name: '5pm'
-                time: 17
-            }
-            {
-                name: '6pm'
-                time: 18
-            }
-            {
-                name: '7pm'
-                time: 19
-            }
-            {
-                name: '8pm'
-                time: 20
-            }
-            {
-                name: '9pm'
-                time: 21
-            }
-            {
-                name: '10pm'
-                time: 22
-            }
-            {
-                name: '11pm'
-                time: 23
-            }
-        ]
-
-        self.holidays = [
-            {
-                name: "New Year's Day"
-                month: "January"
-                eventDate: 1
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Martin Luther King's Birthday"
-                month: "January"
-                day: ["Monday"]
-                dayNum: 3
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Groundhog Day"
-                month: "February"
-                eventDate: 2
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Valentine's Day"
-                month: "February"
-                eventDate: 14
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "President's Day"
-                month: "February"
-                day: ["Monday"]
-                dayNum: 3
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "St. Patrick's Day"
-                month: "March"
-                eventDate: 17
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "April Fool's Day"
-                month: "April"
-                eventDate: 1
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Earth Day"
-                month: "April"
-                eventDate: 22
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Arbor Day"
-                month: "April"
-                day: ["Friday"]
-                dayNum: "last"
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "May Day"
-                month: "May"
-                eventDate: 1
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Cinco De Mayo"
-                month: "May"
-                eventDate: 5
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Mother's Day"
-                month: "May"
-                day: ["Sunday"]
-                dayNum: 2
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Memorial Day"
-                month: "May"
-                day: ["Monday"]
-                dayNum: "last"
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Flag Day"
-                month: "June"
-                eventDate: 14
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Father's Day"
-                month: "June"
-                day: ["Sunday"]
-                type: "holiday"
-                recurrance: "yearly"
-                dayNum: 3
-            }
-            {
-                name: "Independence Day"
-                month: "July"
-                eventDate: 4
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Labor Day"
-                month: "September"
-                day: ["Monday"]
-                dayNum: 1
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Patroit Day"
-                month: "September"
-                eventDate: 11
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Columbus Day"
-                month: "October"
-                day: ["Monday"]
-                dayNum: 2
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Halloween"
-                month: "October"
-                eventDate: 31
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Veteran's Day"
-                month: "November"
-                eventDate: 11
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Thanksgiving"
-                month: "November"
-                day: ["Thursday"]
-                dayNum: 4
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Pearl Harbor Day"
-                month: "December"
-                eventDate: 7
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Festivus"
-                month: "December"
-                eventDate: 23
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Christmas Eve"
-                month: "December"
-                eventDate: 24
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Christmas"
-                month: "December"
-                eventDate: 25
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "Boxing Day"
-                month: "December"
-                eventDate: 26
-                type: "holiday"
-                recurrance: "yearly"
-            }
-            {
-                name: "New Year's Eve"
-                month: "December"
-                eventDate: 31
-                type: "holiday"
-                recurrance: "yearly"
-            }
-        ]
-
-        if self.addHolidays
-            $.each self.holidays, (key, value) ->
-                self.createEvent value
-
-        if self.calendar.length > 0
-            self.createCalendar self.currentMonth, self.currentDate, self.currentYear
-
-        self.calendar.on 'click', '.drm-calendar-date-prev, .drm-calendar-date-next', ->
-            # skip date forward or backward
-            direction = $(@).data 'dir'
-            self.advanceDate.call @, direction
-
-        self.calendar.on 'click', '.drm-calendar-week-prev, .drm-calendar-week-next', ->
-            # skip week forward or backward
-            direction = $(@).data 'dir'
-            self.advanceWeek.call @, direction
-
-        self.calendar.on 'click', '.drm-calendar-month-prev, .drm-calendar-month-next', ->
-            # skip month forward or backward
-            direction = $(@).data 'dir'
-            self.advanceMonth.call @, direction
-
-        self.calendar.on 'click', '.drm-calendar-year-prev, .drm-calendar-year-next', ->
-            # skip year forward or backward
-            direction = $(@).data 'dir'
-            self.advanceYear.call @, direction
-
-        self.calendar.on 'click', '.drm-calendar-current', ->
-            # go to today's date
-            self.changeCalendar.call @, self.currentMonth, self.currentDate, self.currentYear
-
-        self.calendar.on 'click', '.drm-calendar-select button[type=submit]', (e) ->
-            # go to a specific date
-            e.preventDefault()
-            that = $ @
-            fields = that.parent().find(':input').not 'button[type=submit]'
-            currentDate =
-                month: that.parent().find('#month').val()
-                date: that.parent().find('#date').val()
-                year: that.parent().find('#year').val()
-
-            # clear form
-            self.clearForm fields
-
-            # parse form data
-            $.each currentDate, (key, value) ->
-                value = parseInt value, 10
-                value
-
-            # change calendar view
-            self.changeCalendar.call self, currentDate.month, currentDate.date, currentDate.year
-
-        self.calendar.on 'click', 'button.drm-show-event-form', ->
-            # show add event form
-            that = $ @
-            if self.addEventForm.is(':hidden')
-                self.addEventForm.slideDown()
-                that.text 'Hide Form'
-            else
-                self.addEventForm.slideUp()
-                that.text 'Add New Event'
-
-        self.calendar.on 'click', '.drm-calendar-view-nav button', (e) ->
-            # change calendar view
-            e.preventDefault()
-            that = $ @
-            that.addClass 'active'
-            self.calendar.find(".drm-calendar-view-nav button.active").removeClass 'active'
-            view = that.data 'view'
-
-            self.changeCalendarView view
-
-        self.calendar.on 'click', 'form.drm-calendar-new-event button.addEvent', (e) ->
-            # add an new event to the events object
-            e.preventDefault()
-            currentMonth = $(".#{self.calendarInnerClass}").data 'month'
-            newEvent =
-                name: if self.addEventForm.find('#event-name').val() is '' then null else self.addEventForm.find('#event-name').val()
-                recurrance: if self.addEventForm.find('#recurrance').val() is '' then 'none' else self.addEventForm.find('#recurrance').val()
-                month: if self.addEventForm.find('#month').val() is '' then null else self.addEventForm.find('#month').val()
-                year: if self.addEventForm.find('#year').val() is '' then null else parseInt(self.addEventForm.find('#year').val(), 10)
-                eventDate: if self.addEventForm.find('#event-date').val() is '' then null else parseInt(self.addEventForm.find('#event-date').val(), 10)
-                time: if self.addEventForm.find('#time').val() is '' then null else self.addEventForm.find('#time').val()
-                day: []
-                dayNum: if self.addEventForm.find('#day-num').val() is '' then null else self.addEventForm.find('#day-num').val()
-                type: if self.addEventForm.find('#event-type').val() is '' then null else self.addEventForm.find('#event-type').val()
-                notes: if self.addEventForm.find('#event-notes').val() is '' then null else self.addEventForm.find('#event-notes').val()
-
-            self.addEventForm.find('input.day-checkbox:checked').each ->
-                newEvent.day.push $.trim($(@).val())
-            if newEvent.day.length is 0
-                newEvent.day = null
-
-            self.createEvent newEvent
-            newMonth = if newEvent.month? then $.inArray newEvent.month, self.months else self.currentMonth
-            if newMonth isnt currentMonth then self.changeCalendar.call @, newMonth, newEvent.eventDate, self.currentYear
-            # reset form
-            self.addEventForm.find(':input').not('button[type=submit]').val ''
-            self.addEventForm.find('input:checked').prop 'checked', false
-
-        self.calendar.on 'click', ".drm-date", ->
-            # show event form and fill out date infomation when a date is clicked
-            that = $ @
-
-            if self.addEventForm.is ':hidden'
-                self.addEventForm.slideDown()
-                self.showEventFormButton.text 'Hide Form'
-
-            month: self.addEventForm.find('#month').val self.months[that.data('month')]
-            year: self.addEventForm.find('#year').val that.data('year')
-            eventDate: self.addEventForm.find('#event-date').val that.data('date')
-            time: self.addEventForm.find('#time').val that.data('hour')
-
-        self.calendar.on 'click', "ul.#{self.eventClass} a", (e) ->
-            # show event details
-            that = $ @
-            day = that.closest '.drm-date'
-            eventId = that.data 'event'
-            fullDate =
-                month: self.months[day.data('month')]
-                date: day.data 'date'
-                year: day.data 'year'
-            e.preventDefault()
-            e.stopPropagation()
-            self.showEventDetails eventId, fullDate
-
-        self.body.on 'click', 'div.drm-calendar-event-details', (e) ->
-            e.stopPropagation()
-
-        self.body.on 'click', 'div.drm-calendar-event-details button.drm-event-delete', (e) ->
-            e.preventDefault()
-            that = $ @
-            eventId = that.data 'event'
-            index = self.getEventIndex eventId
-            self.removeCalendarEvent eventId, index
-            self.removeEventDetails e
-
-        self.body.on 'click', 'div.drm-calendar-event-details button.drm-event-close', self.removeEventDetails
+
+        if self.calendar isnt 0
+            self.body = $ 'body'
+            self.daysPerWeek = 7
+            self.events = []
+            self.today = new Date()
+            self.currentMonth = self.today.getMonth()
+            self.currentYear = self.today.getFullYear()
+            self.currentDate = self.today.getDate()
+            self.calendarInnerClass = "drm-calendar-#{self.view}-view"
+            self.calendarNav = $ '.drm-calendar-nav'
+            self.calendarSelect = $ '.drm-calendar-select'
+            self.calendarSelectButton = self.calendarSelect.find 'button[type=submit]'
+            self.addEventForm = self.calendar.find('form.drm-calendar-new-event').hide()
+            self.showEventFormButton = self.calendar.find 'button.drm-show-event-form'
+            self.calendarViewActiveButton = self.calendar.find(".drm-calendar-view-nav button[data-view=#{self.view}]").addClass 'active'
+            self.eventClass = 'drm-events'
+            self.classes =
+                weekend: 'drm-cal-weekend'
+                muted: 'drm-cal-muted'
+                holiday: 'drm-cal-holiday'
+                today: 'drm-cal-today'
+                month: 'drm-month'
+                week: 'drm-week'
+                date: 'drm-date'
+
+            self.months = [
+                'January'
+                'February'
+                'March'
+                'April'
+                'May'
+                'June'
+                'July'
+                'August'
+                'September'
+                'October'
+                'November'
+                'December']
+
+            self.days = [
+                'Sunday'
+                'Monday'
+                'Tuesday'
+                'Wednesday'
+                'Thursday'
+                'Friday'
+                'Saturday']
+
+            self.hours = [
+                {
+                    name: 'All Day Event'
+                    time: null
+                }
+                {
+                    name: '12am'
+                    time: 0
+                }
+                {
+                    name: '1am'
+                    time: 1
+                }
+                {
+                    name: '2am'
+                    time: 2
+                }
+                {
+                    name: '3am'
+                    time: 3
+                }
+                {
+                    name: '4am'
+                    time: 4
+                }
+                {
+                    name: '5am'
+                    time: 5
+                }
+                {
+                    name: '6am'
+                    time: 6
+                }
+                {
+                    name: '7am'
+                    time: 7
+                }
+                {
+                    name: '8am'
+                    time: 8
+                }
+                {
+                    name: '9am'
+                    time: 9
+                }
+                {
+                    name: '10am'
+                    time: 10
+                }
+                {
+                    name: '11am'
+                    time: 11
+                }
+                {
+                    name: '12pm'
+                    time: 12
+                }
+                {
+                    name: '1pm'
+                    time: 13
+                }
+                {
+                    name: '2pm'
+                    time: 14
+                }
+                {
+                    name: '3pm'
+                    time: 15
+                }
+                {
+                    name: '4pm'
+                    time: 16
+                }
+                {
+                    name: '5pm'
+                    time: 17
+                }
+                {
+                    name: '6pm'
+                    time: 18
+                }
+                {
+                    name: '7pm'
+                    time: 19
+                }
+                {
+                    name: '8pm'
+                    time: 20
+                }
+                {
+                    name: '9pm'
+                    time: 21
+                }
+                {
+                    name: '10pm'
+                    time: 22
+                }
+                {
+                    name: '11pm'
+                    time: 23
+                }
+            ]
+
+            self.holidays = [
+                {
+                    name: "New Year's Day"
+                    month: "January"
+                    eventDate: 1
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Martin Luther King's Birthday"
+                    month: "January"
+                    day: ["Monday"]
+                    dayNum: 3
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Groundhog Day"
+                    month: "February"
+                    eventDate: 2
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Valentine's Day"
+                    month: "February"
+                    eventDate: 14
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "President's Day"
+                    month: "February"
+                    day: ["Monday"]
+                    dayNum: 3
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "St. Patrick's Day"
+                    month: "March"
+                    eventDate: 17
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "April Fool's Day"
+                    month: "April"
+                    eventDate: 1
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Earth Day"
+                    month: "April"
+                    eventDate: 22
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Arbor Day"
+                    month: "April"
+                    day: ["Friday"]
+                    dayNum: "last"
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "May Day"
+                    month: "May"
+                    eventDate: 1
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Cinco De Mayo"
+                    month: "May"
+                    eventDate: 5
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Mother's Day"
+                    month: "May"
+                    day: ["Sunday"]
+                    dayNum: 2
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Memorial Day"
+                    month: "May"
+                    day: ["Monday"]
+                    dayNum: "last"
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Flag Day"
+                    month: "June"
+                    eventDate: 14
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Father's Day"
+                    month: "June"
+                    day: ["Sunday"]
+                    type: "holiday"
+                    recurrance: "yearly"
+                    dayNum: 3
+                }
+                {
+                    name: "Independence Day"
+                    month: "July"
+                    eventDate: 4
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Labor Day"
+                    month: "September"
+                    day: ["Monday"]
+                    dayNum: 1
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Patroit Day"
+                    month: "September"
+                    eventDate: 11
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Columbus Day"
+                    month: "October"
+                    day: ["Monday"]
+                    dayNum: 2
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Halloween"
+                    month: "October"
+                    eventDate: 31
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Veteran's Day"
+                    month: "November"
+                    eventDate: 11
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Thanksgiving"
+                    month: "November"
+                    day: ["Thursday"]
+                    dayNum: 4
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Pearl Harbor Day"
+                    month: "December"
+                    eventDate: 7
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Festivus"
+                    month: "December"
+                    eventDate: 23
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Christmas Eve"
+                    month: "December"
+                    eventDate: 24
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Christmas"
+                    month: "December"
+                    eventDate: 25
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "Boxing Day"
+                    month: "December"
+                    eventDate: 26
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+                {
+                    name: "New Year's Eve"
+                    month: "December"
+                    eventDate: 31
+                    type: "holiday"
+                    recurrance: "yearly"
+                }
+            ]
+
+            if self.addHolidays
+                $.each self.holidays, (key, value) ->
+                    self.createEvent value
+
+            if self.calendar.length > 0
+                self.createCalendar self.currentMonth, self.currentDate, self.currentYear
+
+            self.calendar.on 'click', '.drm-calendar-date-prev, .drm-calendar-date-next', ->
+                # skip date forward or backward
+                direction = $(@).data 'dir'
+                self.advanceDate.call @, direction
+
+            self.calendar.on 'click', '.drm-calendar-week-prev, .drm-calendar-week-next', ->
+                # skip week forward or backward
+                direction = $(@).data 'dir'
+                self.advanceWeek.call @, direction
+
+            self.calendar.on 'click', '.drm-calendar-month-prev, .drm-calendar-month-next', ->
+                # skip month forward or backward
+                direction = $(@).data 'dir'
+                self.advanceMonth.call @, direction
+
+            self.calendar.on 'click', '.drm-calendar-year-prev, .drm-calendar-year-next', ->
+                # skip year forward or backward
+                direction = $(@).data 'dir'
+                self.advanceYear.call @, direction
+
+            self.calendar.on 'click', '.drm-calendar-current', ->
+                # go to today's date
+                self.changeCalendar.call @, self.currentMonth, self.currentDate, self.currentYear
+
+            self.calendar.on 'click', '.drm-calendar-select button[type=submit]', (e) ->
+                # go to a specific date
+                e.preventDefault()
+                that = $ @
+                fields = that.parent().find(':input').not 'button[type=submit]'
+                currentDate =
+                    month: that.parent().find('#month').val()
+                    date: that.parent().find('#date').val()
+                    year: that.parent().find('#year').val()
+
+                # clear form
+                self.clearForm fields
+
+                # parse form data
+                $.each currentDate, (key, value) ->
+                    parseInt value, 10
+
+                # change calendar view
+                self.changeCalendar.call self, currentDate.month, currentDate.date, currentDate.year
+
+            self.calendar.on 'click', 'button.drm-show-event-form', ->
+                # show add event form
+                that = $ @
+                if self.addEventForm.is(':hidden')
+                    self.addEventForm.slideDown()
+                    that.text 'Hide Form'
+                else
+                    self.addEventForm.slideUp()
+                    that.text 'Add New Event'
+
+            self.calendar.on 'click', '.drm-calendar-view-nav button', (e) ->
+                # change calendar view
+                e.preventDefault()
+                that = $ @
+                that.addClass 'active'
+                self.calendar.find(".drm-calendar-view-nav button.active").removeClass 'active'
+                view = that.data 'view'
+
+                self.changeCalendarView view
+
+            self.calendar.on 'click', 'form.drm-calendar-new-event button.addEvent', (e) ->
+                # add an new event to the events object
+                e.preventDefault()
+                currentMonth = $(".#{self.calendarInnerClass}").data 'month'
+                newEvent =
+                    name: if self.addEventForm.find('#event-name').val() is '' then null else self.addEventForm.find('#event-name').val()
+                    recurrance: if self.addEventForm.find('#recurrance').val() is '' then 'none' else self.addEventForm.find('#recurrance').val()
+                    month: if self.addEventForm.find('#month').val() is '' then null else self.addEventForm.find('#month').val()
+                    year: if self.addEventForm.find('#year').val() is '' then null else parseInt(self.addEventForm.find('#year').val(), 10)
+                    eventDate: if self.addEventForm.find('#event-date').val() is '' then null else parseInt(self.addEventForm.find('#event-date').val(), 10)
+                    time: if self.addEventForm.find('#time').val() is '' then null else self.addEventForm.find('#time').val()
+                    day: []
+                    dayNum: if self.addEventForm.find('#day-num').val() is '' then null else self.addEventForm.find('#day-num').val()
+                    type: if self.addEventForm.find('#event-type').val() is '' then null else self.addEventForm.find('#event-type').val()
+                    notes: if self.addEventForm.find('#event-notes').val() is '' then null else self.addEventForm.find('#event-notes').val()
+
+                self.addEventForm.find('input.day-checkbox:checked').each ->
+                    newEvent.day.push $.trim($(@).val())
+                if newEvent.day.length is 0
+                    newEvent.day = null
+
+                self.createEvent newEvent
+                newMonth = if newEvent.month? then $.inArray newEvent.month, self.months else self.currentMonth
+                if newMonth isnt currentMonth then self.changeCalendar.call @, newMonth, newEvent.eventDate, self.currentYear
+                # reset form
+                self.addEventForm.find(':input').not('button[type=submit]').val ''
+                self.addEventForm.find('input:checked').prop 'checked', false
+
+            self.calendar.on 'click', ".drm-date", ->
+                # show event form and fill out date infomation when a date is clicked
+                that = $ @
+
+                if self.addEventForm.is ':hidden'
+                    self.addEventForm.slideDown()
+                    self.showEventFormButton.text 'Hide Form'
+
+                month: self.addEventForm.find('#month').val self.months[that.data('month')]
+                year: self.addEventForm.find('#year').val that.data('year')
+                eventDate: self.addEventForm.find('#event-date').val that.data('date')
+                time: self.addEventForm.find('#time').val that.data('hour')
+
+            self.calendar.on 'click', "ul.#{self.eventClass} a", (e) ->
+                # show event details
+                that = $ @
+                day = that.closest '.drm-date'
+                eventId = that.data 'event'
+                fullDate =
+                    month: self.months[day.data('month')]
+                    date: day.data 'date'
+                    year: day.data 'year'
+                e.preventDefault()
+                e.stopPropagation()
+                self.showEventDetails eventId, fullDate
+
+            self.body.on 'click', 'div.drm-calendar-event-details', (e) ->
+                e.stopPropagation()
+
+            self.body.on 'click', 'div.drm-calendar-event-details button.drm-event-delete', (e) ->
+                e.preventDefault()
+                that = $ @
+                eventId = that.data 'event'
+                index = self.getEventIndex eventId
+                self.removeCalendarEvent eventId, index
+                self.removeEventDetails e
+
+            self.body.on 'click', 'div.drm-calendar-event-details button.drm-event-close', self.removeEventDetails

     capitalize: (str) ->
         str.toLowerCase().replace /^.|\s\S/g, (a) ->
@@ -531,12 +534,11 @@

     getWeekNum: (dayNum, day, currentMonth, currentYear) =>
         # gets the week of the month which an event occurs
-        self = @
-        calendarInner = self.calendar.find "div.#{@calendarInnerClass}"
+        calendarInner = @calendar.find "div.#{@calendarInnerClass}"
         weeks = calendarInner.find '.drm-week'
-        firstDay = self.getDayOfWeek currentMonth, 1, currentYear
-        dayShift = if firstDay is self.daysPerWeek then 0 else firstDay
-        numberWeeks = self.getWeeksInMonth currentMonth, currentYear
+        firstDay = @getDayOfWeek currentMonth, 1, currentYear
+        dayShift = if firstDay is @daysPerWeek then 0 else firstDay
+        numberWeeks = @getWeeksInMonth currentMonth, currentYear
         lastWeekLength = weeks.eq(numberWeeks).length

         if dayNum is 'last' and dayShift <= day
@@ -546,8 +548,7 @@
         else
             eventWeekNum = parseInt(dayNum, 10) - 1

-        eventWeekNum = if dayShift <= day then eventWeekNum else eventWeekNum + 1
-        eventWeekNum
+        return if dayShift <= day then eventWeekNum else eventWeekNum + 1

     getDatesInWeek: (currentMonth, currentDate, currentYear) =>
         firstDay = @getDayOfWeek currentMonth, 1, currentYear
@@ -617,9 +618,9 @@
         weekNumber

     createEvent: (newEvent) =>
-        id = @events.length
+        _id = @events.length
         obj =
-            id: id
+            _id: _id
             name: if newEvent.name? then newEvent.name else null
             recurrance: if newEvent.recurrance? then newEvent.recurrance.toLowerCase() else 'none'
             month: if newEvent.month? then newEvent.month else null
@@ -631,7 +632,7 @@
             type: if newEvent.type? then newEvent.type.toLowerCase() else null
             notes: if newEvent.notes? then newEvent.notes else null
         @events.push obj
-        @addEventsToCalendar @events[obj.id]
+        @addEventsToCalendar @events[obj._id]

     removeCalendarEvent: (eventId, index) =>
         events = @calendar.find "ul.#{@eventClass} a[data-event=#{eventId}]"
@@ -641,8 +642,7 @@
     getEventIndex: (eventId) =>
         index = null
         $.each @events, (key, value) ->
-            if value.id is eventId
-                index = key
+            if value._id is eventId then index = key
             index
         index

@@ -653,18 +653,19 @@
         eventDate = "#{fullDate.month} #{fullDate.date}, #{fullDate.year}"

         eventFrequency = do ->
-            recurrance = events.recurrance
-            if recurrance is 'yearly' and events.dayNum?
+            if events.recurrance is 'yearly' and events.dayNum?
                 "Every #{events.dayNum} #{events.day} of #{events.month}"
-            else if recurrance is 'yearly'
+            else if events.recurrance is 'yearly'
                 "Every #{events.eventDate} of #{events.month}"
-            else if recurrance is 'monthly'
+            else if events.recurrance is 'monthly' and events.dayNum?
                 "Every #{events.dayNum} #{events.day} of the month"
-            else if recurrance is 'biweekly'
+            else if events.recurrance is 'monthly'
+                "Every #{events.eventDate} of the month"
+            else if events.recurrance is 'biweekly'
                 "Every other #{events.day}"
-            else if recurrance is 'weekly'
+            else if events.recurrance is 'weekly'
                 "Every #{events.day}"
-            else if recurrance is 'daily'
+            else if events.recurrance is 'daily'
                 "Every Day"
             else
                 "One Time Event"
@@ -686,12 +687,12 @@
             type: 'button'
         editButton = $ "<button></button>",
             class: 'drm-event-edit'
-            'data-event': events.id
+            'data-event': events._id
             text: 'Edit'
             type: 'button'
         deleteButton = $ "<button></button>",
             class: 'drm-event-delete'
-            'data-event': events.id
+            'data-event': events._id
             text: 'Delete'
             type: 'button'
         eventDetailList = $ '<ul></ul>',
@@ -835,7 +836,7 @@

             eventHtml = $ '<a></a>',
                 href: '#'
-                'data-event': events.id
+                'data-event': events._id
                 html: eventContent

             if length is 0


add prevent default in the save description

--- app/coffee/modules/common/components.coffee
+++ app/coffee/modules/common/components.coffee
@@ -536,7 +536,9 @@
             $el.find('.view-description').hide()
             $el.find('textarea').focus()

-        $el.on "click", ".save", ->
+        $el.on "click", ".save", (e) ->
+            e.preventDefault()
+
             description = $scope.item.description
             save(description)


force synchronicity

force synchronicity

--- app/components/admin-page/admin-page.coffee
+++ app/components/admin-page/admin-page.coffee
@@ -27,8 +27,9 @@
     $scope.updateGroup = () ->
       Records.groups.findOrFetchById(groupId).then (group) ->
         group.save()
-        Toast.show('You updated '+group.name)
-        $scope.cancel()
+          .then ->
+            Toast.show('You updated '+group.name)
+            $scope.cancel()

     $scope.viewGroup = (groupId) ->
       $location.path("/groups/#{groupId}")


currentMembership now defined on group-page reload

--- app/components/group-page/group-page.coffee
+++ app/components/group-page/group-page.coffee
@@ -9,8 +9,7 @@
     groupId = parseInt($stateParams.groupId)
     Records.groups.findOrFetchById(groupId).then (group) ->
       $scope.group = group
-      $scope.currentMembership = group.membershipFor(CurrentUser.get())
-      console.log('(group-page) currentMembership: ', $scope.currentMembership)
+      $scope.currentMembership = group.membershipFor(CurrentUser())
       Records.buckets.fetchByGroupId(group.id)
       Records.memberships.fetchByGroupId(group.id)


Fix tests syntax

Fix tests syntax

--- assets/scripts/spec/unit/log_chunks_spec.coffee
+++ assets/scripts/spec/unit/log_chunks_spec.coffee
@@ -57,7 +57,7 @@
     start()
   , 35

-test "it triggers downloading all available parts if there is no parts yet"
+test "it triggers downloading all available parts if there is no parts yet", ->
   expect(1)
   stop()


Adding missing function is_base2 to ticking.coffee

--- subtree/bokehjs/static/coffee/common/ticking.coffee
+++ subtree/bokehjs/static/coffee/common/ticking.coffee
@@ -24,6 +24,13 @@

     return Math.log(num) / Math.LN2

+is_base2 = (rng) ->
+  """ Returns True if rng is a positive multiple of 2 """
+  if rng <= 0
+    false
+  else
+    lg = log2(rng)
+    return ((lg > 0.0) and (lg == Math.floor(lg)))

 nice_2_5_10 = (x, round=false) ->
     """ if round is false, then use Math.ceil(range) """


Remove autofocus from embedded inquiry form

--- apps/artwork/components/contact/view.coffee
+++ apps/artwork/components/contact/view.coffee
@@ -33,12 +33,6 @@
     @$submit    = @$('button')
     @$textarea  = @$('textarea')

-    @focusTextarea() if @user
-
-  focusTextarea: =>
-    val = @$textarea.val()
-    @$textarea.focus().val('').val val
-
   submit: (e) ->
     e.preventDefault()


Only hide opinionaters

Only hide opinionaters

--- core/app/backbone/views/evidence/ndp_evidence_collection_view.coffee
+++ core/app/backbone/views/evidence/ndp_evidence_collection_view.coffee
@@ -10,13 +10,13 @@
       when 'disbelieves' then 'evidence-weakening'
       when 'doubts' then 'evidence-unsure'

-  shouldShow: -> @model.has('impact') && @model.get('impact') > 0.0
+  shouldShowOpinionaters: -> @model.has('impact') && @model.get('impact') > 0.0

   onRender: ->
-    @$el.toggle @shouldShow()
     @$el.addClass @typeCss()

     if @model instanceof OpinionatersEvidence
+      @$el.toggle @shouldShowOpinionaters()
       @contentRegion.show new InteractingUsersView model: @model
     else
       @contentRegion.show new TextView model: new Backbone.Model text: @model.id


login panel upgrades

login panel upgrades

--- app/coffee/loginpanel.coffee
+++ app/coffee/loginpanel.coffee
@@ -28,8 +28,13 @@
     @$signupPanel = @$container.find('.signupPanel') #expands
     @$loginPanel = @$container.find('.loginPanel') #submits

+    @$loginButton.unbind()
     @$loginButton.click => @showLogin()
+    @$joinButton.unbind()
     @$joinButton.click => @showSignup()
+
+    @bodyClickVisible = false
+
     $('.haveSeedcode').click => $('#user_seed_code').show()

   closePanel: ->
@@ -42,6 +47,7 @@
     @$signupPanel.slideUp()

   showLogin: ->
+    console.log @bodyClickVisible
     if !@bodyClickVisible
       @bodyClickVisible = true
       @displayBodyClick()


Every task has a priority!

Every task has a priority!

--- app/controllers/tasks.coffee
+++ app/controllers/tasks.coffee
@@ -55,8 +55,7 @@
         priority: (->
           if val.indexOf("#high") >= 0 then return 3
           if val.indexOf("#medium") >= 0 then return 2
-          if val.indexOf("#low") >= 0 then return 1
-          return 0
+          return 1
         )()
       @input.val ""


refactor: removed unnecessary $timeout from HomeCtrl

--- app/modules/home/home.coffee
+++ app/modules/home/home.coffee
@@ -2,7 +2,7 @@

 angular.module('NgBuildkit')

-  .controller('HomeCtrl', ['$scope', '$timeout', ($scope, $timeout) ->
+  .controller('HomeCtrl', ['$scope', ($scope) ->

     $scope.features = [
       {name: 'Dependency Management (npm, bower, browserify with browserify-shim)'}
@@ -22,9 +22,7 @@
     ]

     # execute non common-js vendor code
-    $timeout( ->
-      plugin()
-    , 30)
+    plugin()

   ])


[➠] Refactoring Booster.

[➠] Refactoring Booster.


actually reenable sortable

actually reenable sortable

--- app/assets/javascripts/kuhsaft/cms/application.js.coffee
+++ app/assets/javascripts/kuhsaft/cms/application.js.coffee
@@ -26,9 +26,9 @@
       handle: '.brick-item-header',
       axis: "y",
       update: (event, ui) ->
-         #$(this).find(".brick-item").each (idx, elem) ->
-            #$(this).find("input.position-field").val(idx+1)
-            #$(this).children('form').trigger('submit')
+         $(this).find(".brick-item").each (idx, elem) ->
+            $(this).find("input.position-field").val(idx+1)
+            $(this).children('form').trigger('submit')
       )

 $(document).ajaxSuccess ->


added dirty tracking on the model

added dirty tracking on the model

--- app/assets/javascripts/type_station/lib/models.js.coffee
+++ app/assets/javascripts/type_station/lib/models.js.coffee
@@ -9,6 +9,19 @@
       callback?(key, value)

 class window.TS.Model extends window.TS.Store
+
+  constructor: (@id = null) ->
+    super
+    @DIRTY = {}
+
+  set: (key, value) ->
+    super key, value
+    @DIRTY[key] = 1
+
+
+  changedKeys: -> Object.keys(@DIRTY)
+  isChanged: -> @changedKeys().length > 0
+
   save: (callback = ->) ->
     self = @
     data = []


CNS-567: Inbox message notification present even without a new message

--- app/coffeescripts/conversations/ConversationsList.coffee
+++ app/coffeescripts/conversations/ConversationsList.coffee
@@ -60,6 +60,19 @@
       @$empty.hide()

     updated: (conversation, $node) ->
+
+      # update inbox notification
+      current_unread = parseInt($("#identity .unread-messages-count").text(), 10) || 0
+      new_unread = $('.conversations li.unread').length
+      if(current_unread != new_unread)
+        if (new_unread <= 0)
+          $("#identity .unread-messages-count").remove()
+        else
+          if($("#identity .unread-messages-count").length > 0)
+            $("#identity .unread-messages-count").text(new_unread)
+          else
+            $("#identity .first a").append('<b class="unread-messages-count">'+new_unread+'</b>')
+
       @emptyCheck()
       if @isActive(conversation.id) and conversation.get('workflow_state') is 'unread'
         @markAsUnread = setTimeout =>


hide bpm on beatmaps that have silly bpm values

--- resources/assets/coffee/react/_components/beatmap-basic-stats.coffee
+++ resources/assets/coffee/react/_components/beatmap-basic-stats.coffee
@@ -44,7 +44,9 @@
           beatmap[stat]

       value =
-        if stat == 'total_length'
+        if stat == 'bpm'
+          if value > 1000 then '—' else osu.formatNumber(value)
+        else if stat == 'total_length'
           formatDuration value
         else
           osu.formatNumber(value)


#0 #done @bug 修复pool的的问题

#0 #done @bug 修复pool的的问题

--- biz/store.coffee
+++ biz/store.coffee
@@ -9,12 +9,15 @@
 _ = require 'underscore'
 _common = require '../common'
 require 'colors'
+_database = null

 exports.database = ->
-  _knex.initialize
+  return _database if _database
+  _database = _knex.initialize
     client: 'sqlite3',
     connection:
       filename: _common.sqlitePath
+

 #创建字段
 createField = (table, schema)->


engine data module

engine data module

--- src/engine_data.coffee
+++ src/engine_data.coffee
@@ -8,5 +8,7 @@
 @param {Object} self Reference to the engine
 ###
 Engine.Data = (I, self) ->
+  Object.reverse
+
   get: ->
   set: ->


Removed ckeditor from custom js coffee

Removed ckeditor from custom js coffee

--- app/assets/javascripts/admin/custom.js.coffee
+++ app/assets/javascripts/admin/custom.js.coffee
@@ -3,6 +3,5 @@
   $(".tooltip").tooltip()
   $("a[rel=tooltip]").tooltip()

-  $(".ckeditor").ckeditor()

   $("#sortable-table").tablesorter()


Draging network graph is replaced by vertical scrolling.

--- app/assets/javascripts/branch-graph.js.coffee
+++ app/assets/javascripts/branch-graph.js.coffee
@@ -122,22 +122,11 @@
   bindEvents: ->
     drag = {}
     element = @element
-    dragger = (event) ->
-      element.scrollLeft drag.sl - (event.clientX - drag.x)
-      element.scrollTop drag.st - (event.clientY - drag.y)
-
-    element.on mousedown: (event) ->
-      drag =
-        x: event.clientX
-        y: event.clientY
-        st: element.scrollTop()
-        sl: element.scrollLeft()
-      $(window).on "mousemove", dragger
+
+    $(element).scroll (event) =>
+      @renderPartialGraph()

     $(window).on
-      mouseup: =>
-        $(window).off "mousemove", dragger
-        @renderPartialGraph()
       keydown: (event) =>
         # left
         element.scrollLeft element.scrollLeft() - 50  if event.keyCode is 37


Go for simpler approach

Go for simpler approach

--- plugins/github-issues/index.coffee
+++ plugins/github-issues/index.coffee
@@ -10,7 +10,7 @@
       body: @markdownBody(event)
       # Regex removes surrounding whitespace around commas while retaining inner whitespace
       # and then creates an array of the strings
-      labels: (config?.labels || "bugsnag").match(/(?=\S)[^,]+?(?=\s*(,|$))/g).compact(true)
+      labels: (config?.labels || "bugsnag").split(/\s*,\s*/).compact(true)

     # Start building the request
     req = @request


Fix github

Fix github

--- plugins/github-issues/index.coffee
+++ plugins/github-issues/index.coffee
@@ -5,7 +5,7 @@
   DEFAULT_URL = "https://api.github.com"

   @githubUrl: (config) ->
-    if config.url?
+    if config.url
       url.resolve(config.url, "api/v3/")
     else
       DEFAULT_URL


Prevent nested help dialog iframes

Prevent nested help dialog iframes

--- content_scripts/vimium_frontend.coffee
+++ content_scripts/vimium_frontend.coffee
@@ -219,7 +219,7 @@
   # We only initialize the vomnibar in the tab's main frame, because it's only ever opened there.
   Vomnibar.init() if DomUtils.isTopFrame()
   HUD.init()
-  HelpDialog.init()
+  HelpDialog.init() unless document.location.toString() == chrome.extension.getURL "pages/help_dialog.html"

 registerFrame = ->
   # Don't register frameset containers; focusing them is no use.
@@ -782,7 +782,7 @@
     @helpUI = new UIComponent "pages/help_dialog.html", "vimiumHelpDialogFrame", (event) =>
       @helpUI.hide() if event.data == "hide"

-  isReady: -> true
+  isReady: -> @helpUI?

   show: (html) ->
     return if HelpDialog.showing or !@isReady()


Add support for CIELCH colorspace.

Add support for CIELCH colorspace.

--- colorspaces.coffee
+++ colorspaces.coffee
@@ -28,7 +28,7 @@
           ab[i].push dot_product get_row(a, i), get_col(b, j)
   return ab

-# Reference white point used for CIE Lab conversion
+# The D65 standard illuminant
 white_point = [95.047, 100.000, 108.883]

 # Functions for converting between CIE XYZ and other color spaces
@@ -38,10 +38,7 @@
     to: (tuple) -> tuple
     from: (tuple) -> tuple
   _sRGB:
-    to: (tuple) ->
-      _X = tuple[0]
-      _Y = tuple[1]
-      _Z = tuple[2]
+    to: (_X, _Y, _Z) ->
       from_linear = (c) ->
         a = 0.055
         if c <= 0.0031308
@@ -58,10 +55,7 @@
       _G = from_linear res[1][0]
       _B = from_linear res[2][0]
       [_R, _G, _B]
-    from: = (tuple) ->
-      _R = tuple[0]
-      _G = tuple[1]
-      _B = tuple[2]
+    from: (_R, _G, _B) ->
       to_linear = (c) ->
         a = 0.055
         if c <= 0.04045
@@ -79,24 +73,18 @@
       res = matrix_mult m, [[rl], [gl], [bl]]
       [res[0][0], res[1][0], res[2][0]]
   _CIExyY:
-    to: (tuple) ->
-      _X = tuple[0]
-      _Y = tuple[1]
-      _Z = tuple[2]
+    to: (_X, _Y, _Z) ->
       sum = _X + _Y + _Z
       [_X / sum, _Y / sum, _Y]
-    from: (tuple) ->
-      _x = tuple[0]
-      _y = tuple[1]
-      _Y = tuple[2]
+    from: (_x, _y, _Y) ->
       _X = _Y / _y * _x
       _Z = _Y / _y * (1 - _x - _y)
       [_X, _Y, _X]
   _CIELAB:
-    to: (tuple) ->
-      _X = tuple[0]
-      _Y = tuple[1]
-      _Z = tuple[2]
+    to: (_X, _Y, _Z) ->
+      _X = _X / white_point[0]
+      _Y = _Y / white_point[1]
+      _Z = _Z / white_point[2]
       f = (t) ->
         if t > Math.pow(6 / 29, 3)
           Math.pow(t, 1 / 3)
@@ -106,24 +94,32 @@
       _a = 500 * (f(_X) - f(_Y))
       _b = 200 * (f(_Y) - f(_Z))
       [_L, _a, _b]
-    from: (tuple) ->
-      _L = tuple[0]
-      _a = tuple[1]
-      _b = tuple[2]
+    from: (_L, _a, _b) ->
       f_inv = (t) ->
         if t > 6 / 29
           Math.pow(t, 3)
         else
           3 * Math.pow(6 / 29, 2) * (t - 4 / 29)
-      _Y = f_inv 1 / 116 * (_L + 16)
-      _X = f_inv 1 / 116 * (_L + 16) + 1 / 500 * _a
-      _Z = f_inv 1 / 116 * (_L + 16) - 1 / 200 * _b
+      _Y = white_point[1] * f_inv 1 / 116 * (_L + 16)
+      _X = white_point[0] * f_inv 1 / 116 * (_L + 16) + 1 / 500 * _a
+      _Z = white_point[2] * f_inv 1 / 116 * (_L + 16) - 1 / 200 * _b
       [_X, _Y, _Z]
+  _CIELCH:
+    to: (_X, _Y, _Z) ->
+      [_L, _a, _b] = conv._CIELAB.to([_X, _Y, _Z])
+      _C = Math.pow Math.pow(_a, 2) + Math.pow(_b, 2), 1 / 2
+      _h = Math.atan2 _b, _a
+      [_L, _C, _h]
+    from: (_L, _C, _h) ->
+      _h_rad = _h / 360 * 2 * Math.PI
+      _a = Math.cos(_h_rad) * _C
+      _b = Math.sin(_h_rad) * _C
+      conv._CIELAB.from([_L, _a, _b])

 get_color = (space, tuple) ->
-  color = conv["_" + space].from(tuple)
+  color = conv["_" + space].from(tuple...)
   as: (space) ->
-    conv["_" + space].to(color)
+    conv["_" + space].to(color...)

 if jQuery?
   exports =


Removing debug logging

Removing debug logging

--- app/assets/javascripts/reviewEditor.js.coffee
+++ app/assets/javascripts/reviewEditor.js.coffee
@@ -135,7 +135,6 @@
     @finishedText($('#review_feedback').val())

     finalGrade = $('#review_grade').val()
-    console.log "Load grade (#{finalGrade})"
     @finalGrade(finalGrade) if finalGrade != ''

     status = $('#review_status').val()
@@ -208,14 +207,11 @@

     # Set grade
     finalGrade = @finalGrade()
-    console.log "finalGrade (#{finalGrade})"

     if finalGrade? && finalGrade != false
       $('#review_grade').val(finalGrade)
-      console.log "setting finalGrade (#{finalGrade})"
     else
       $('#review_grade').val('')
-      console.log "setting finalGrade to empty string"

     # Set status
     if @finalizing()


client price validation (wip)

client price validation (wip)

--- app/assets/javascripts/transactions.js.coffee
+++ app/assets/javascripts/transactions.js.coffee
@@ -28,9 +28,42 @@
 #   window.prompt "Cash given (in EUR):"
 #   bind_overlay_hotkeys()

-handle_errors = ->
-  if $("#error_explanation").length
-    $("audio").trigger "play"
+mark_error = (element) ->
+  play_error_sound()
+  element.parent().addClass "field_with_errors"
+  setTimeout ( ->
+    $(document.activeElement).off "blur" ),
+    0
+  setTimeout ( ->
+    change_to_element = $(document.activeElement)
+    setTimeout (-> change_to_element.blur input_blur_handler), 0
+    element.focus() ),
+    0
+
+unmark_error = (element) ->
+  element.parent().removeClass "field_with_errors"
+
+is_valid_price = (element) ->
+  /^\d*[.,]?\d*$/.test element.val()
+
+seller_list =
+  1: "AL"
+  11: "NL"
+
+validate_seller = (element) ->
+  text = element.val()
+  if /^\d+$/.test text
+    number = parseInt text
+    seller_list[number]? && element.val seller_list[number] + number
+
+check_field = (element, test_function) ->
+  if test_function element
+    unmark_error element
+  else
+    mark_error element
+
+play_error_sound = ->
+  $("audio").trigger "play"

 set_focus = (focus_id) ->
   if $(".field_with_errors").length
@@ -41,15 +74,22 @@
     else
       $(".field input").filter(-> $(this).val() == "").first().focus()

+input_blur_handler = ->
+  field_name = /\[([^\]]*)\]$/.exec( $(this).attr('name') )[1]
+  switch field_name
+    when "price"
+      check_field $(this), is_valid_price
+    when "seller_code"
+      check_field $(this), validate_seller
+    else
+      $.ajax "/transactions/validate", { type: "POST", data: $("#transaction_form form").serialize(), timeout: 2000, success: replace_transaction_form }
+
 register_handler = ->
-  $(".field input").blur ->
-    if $(this).attr("size") == "7" && /^\s*$/.test $(this).val()
-      $(this).val("a")
-    $.ajax "/transactions/validate", { type: "POST", data: $("#transaction_form form").serialize(), timeout: 2000, success: replace_transaction_form }
+  $(".field input").blur input_blur_handler

 replace_transaction_form = (data, status, jqXHR) ->
-  focus_id = $(":focus").attr("id")
-  focus_value = $(":focus").val()
+  focus_id = $(document.activeElement).attr("id")
+  focus_value = $(document.activeElement).val()
 #   if focus_id != "transaction_submit"
   $("#transaction_form").html data
   $("#" + focus_id).val focus_value
@@ -59,25 +99,23 @@
   bind_hotkeys()
   if $("#transaction_form").length
     $(".field input").focus(-> $(this).select())
-    handle_errors()
     set_focus(focus_id)
     register_handler()
 #   bind_overlay_hotkeys()

 bind_hotkeys = ->
   $(document).keydown (event) ->
-    target = switch event.keyCode
+    target = switch event.which
       when 'L'.charCodeAt(0) then "/transactions"
       when 'N'.charCodeAt(0) then "/transactions/new"
-    if target
+    if target && !$(event.target).is "input"
       event.stopPropagation()
       window.location.href = target
   $("#transaction_form input").keydown (event) ->
     if event.keyCode == 27
+      event.stopPropagation()
       event.preventDefault()
-      event.stopPropagation()
       window.location.href = "/transactions"
-

 # bind_overlay_hotkeys = ->
 #   $(document).keyup (e) ->


première version fonctionnelle du deadlock en z

--- app/assets/jax/models/deadlock_core.js.coffee
+++ app/assets/jax/models/deadlock_core.js.coffee
@@ -191,9 +191,7 @@
     deadlocked_positions = @deadlocked_square(cell.box, cell.down, cell.down_left, cell.left,
                                               pos.box,  pos.down,  pos.down_left,  pos.left,
                                               deadlocked_positions)
-
-    return deadlocked_positions
-
+
     ###
     # Last push made a Z deadlock
     ###
@@ -205,13 +203,8 @@
     #  #####   #####

     # fig 1, upper box
-    if cell.left == '#' and cell.down_right == '#'
-      if (cell.box == '$' || cell.box == '*') and (cell.down == '$' || cell.down == '*')
-        if not (cell.box == '*' and cell.down == '*')
-          if not @position_in_array(cell.box, deadlocked_positions)
-            deadlocked_positions.push({ m:cell.box.m, n:cell.box.n })
-          if not @position_in_array()
-            deadlocked_positions.push({ m:cell.down.m, n:cell.down.n })
+    deadlocked_positions = @deadlocked_z(cell.box, cell.down, cell.left, cell.down_right,
+                                         pos.box,  pos.down,  deadlocked_positions)

 #    // fig 1, lower box
 #    if(posRight == -1 && posUpLeft == -1
@@ -256,7 +249,7 @@
 #        return true;
 #
 #
-#    return false;
+    return deadlocked_positions

   ###
     Test a specific deadlocked square and return the deadlocked positions
@@ -282,6 +275,17 @@
         deadlocked_positions.push({ m:pos3.m, n:pos3.n })

     return deadlocked_positions
+
+  deadlocked_z: (cell_box, cell_box2, cell_wall1, cell_wall2, pos_box, pos_box2, deadlocked_positions) ->
+    if cell_wall1 == '#' and cell_wall2 == '#'
+      if (cell_box == '$' || cell_box == '*') and (cell_box2 == '$' || cell_box2 == '*')
+        if not (cell_box == '*' and cell_box2 == '*')
+          if not @position_in_array(pos_box, deadlocked_positions)
+            deadlocked_positions.push({ m:pos_box.m, n:pos_box.n })
+          if not @position_in_array(pos_box2, deadlocked_positions)
+            deadlocked_positions.push({ m:pos_box2.m, n:pos_box2.n })
+
+    return deadlocked_positions

   ###
     return true if position is in a corner of level (corner with 2 walls)


Fix bug #1087

Fix bug #1087

--- app/coffee/modules/projects/lightboxes.coffee
+++ app/coffee/modules/projects/lightboxes.coffee
@@ -57,11 +57,10 @@
             promise.then(onSuccessSubmit, onErrorSubmit)

         $scope.$on "projects:create", ->
-            $scope.$apply ->
-                $scope.data = {
-                    total_story_points: 100
-                    total_milestones: 5
-                }
+            $scope.data = {
+                total_story_points: 100
+                total_milestones: 5
+            }

             if !$scope.templates.length
                 $rs.projects.templates().then (result) =>


update messages for saving comments

update messages for saving comments

fixes TALLY-555
flag = none

test plan:
 * Visit Gradebook
 * Open the Grade Detail Tray for a submission
 * Post a comment
 * Verify the success message reads:
   "Successfully saved the comment"

Change-Id: I70ff2e89cd3f9a4a409a6aef169a76729569477c
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/226795
Tested-by: Service Cloud Jenkins <9144042a601061f88f1e1d7a1753ea3e2972119d@instructure.com>
Reviewed-by: Spencer Olson <7cc0890d6f1f70810a023e7173eca5724d6c8e49@instructure.com>
Reviewed-by: Adrian Packel <9c6a39807293376f29cba17542b4cb1b663ecc4a@instructure.com>
QA-Review: Robin Kuss <0b206b54367b2de0334896ea45826f0e3194bd35@instructure.com>
Product-Review: Jonathan Fenton <5549b92428699b688d6c4f80786628c27e48a3e1@instructure.com>

--- app/coffeescripts/gradezilla/Gradebook.coffee
+++ app/coffeescripts/gradezilla/Gradebook.coffee
@@ -2486,9 +2486,9 @@

       SubmissionCommentApi.createSubmissionComment(@options.context_id, assignmentId, studentId, commentData)
         .then(@updateSubmissionComments)
-        .then(FlashAlert.showFlashSuccess I18n.t 'Successfully posted the comment')
+        .then(FlashAlert.showFlashSuccess I18n.t 'Successfully saved the comment')
         .catch(=> @setCommentsUpdating(false))
-        .catch(FlashAlert.showFlashError I18n.t 'There was a problem posting the comment')
+        .catch(FlashAlert.showFlashError I18n.t 'There was a problem saving the comment')

     apiUpdateSubmissionComment: (updatedComment, commentId) =>
       SubmissionCommentApi.updateSubmissionComment(commentId, updatedComment)


Python != Coffee

Python != Coffee

--- src/quest.coffee
+++ src/quest.coffee
@@ -56,7 +56,7 @@
             times -= 1
           else
             console.error "Out of lives... I give up.".red.underline
-            raise e
+            throw e

   sql: (queries, view={}, cb) ->
     if typeof(queries) != 'string'


Corrige cálculo de similaridade de deputado com ele próprio. Close #6.

--- app/scripts/directives/adjacencyMatrix.coffee
+++ app/scripts/directives/adjacencyMatrix.coffee
@@ -25,8 +25,6 @@

         data.links.forEach (link) ->
           matrix[link.source][link.target].z += link.value
-          matrix[link.source][link.source].z += link.value
-          matrix[link.target][link.target].z += link.value
           matrix[link.source].name = nodes[link.source].name
           nodes[link.source].count += link.value
           nodes[link.target].count += link.value


Correct transitonAnimation check to is true

--- js/flight.coffee
+++ js/flight.coffee
@@ -33,6 +33,7 @@
     transtionType = @currentPanel.getAttribute("data-transition")

     if @transitionAnimation
+    if @transitionAnimation is true

       switch transtionType
         when "slide" then @slideTransition('0.4s')


Testing

Testing

--- widgets/cusi_progress_bars/cusi_progress_bars.coffee
+++ widgets/cusi_progress_bars/cusi_progress_bars.coffee
@@ -41,7 +41,7 @@
         elem = rowsContainer.find("."+normalizedItemName+" .inner-progress-bar")
         if elem.length
           @animateProgressBarContent(elem[0], parseFloat(elem[0].style.width),
-                                    parseFloat(item.progress), item.value, 250)#1000)
+                                    parseFloat(item.progress), item.value, 100)#1000)
         ++counter

       # Remove any nodes that were not in the new data, these will be the rows


don't search the element when placing the video, since it may be outside the DOM


info panel to use ImpacUtilities to determine widget name

--- src/components/widgets-common/info-panel/info-panel.directive.coffee
+++ src/components/widgets-common/info-panel/info-panel.directive.coffee
@@ -1,6 +1,6 @@
 module = angular.module('impac.components.widgets-common.info-panel',[])

-module.directive('commonInfoPanel', ($templateCache) ->
+module.directive('commonInfoPanel', ($templateCache, ImpacUtilities) ->
   return {
     restrict: 'A'
     scope: {
@@ -19,9 +19,13 @@
         scope.onClose()

       scope.getWidgetTemplateName = ->
-        cat_array = (w.metadata.template || w.endpoint).split('/')
-        cat_array = cat_array.slice(cat_array.length - 2, cat_array.length)
-        result = "#{cat_array[0]} - #{cat_array[1].replace('_', ' ')}"
-        return result
+        cssClass = ImpacUtilities.fetchWidgetCssClass(w)
+        return "" unless cssClass
+
+        cssClassArray = cssClass.split('-')
+        widgetCategory = cssClassArray.slice(0,1)
+        widgetName = cssClassArray.slice(1, cssClassArray.length).join(' ')
+
+        return "#{widgetCategory} - #{widgetName}"
   }
 )


[Email Confirmation] Change referral list fetcher function

--- workers/social/lib/social/models/referral/index.coffee
+++ workers/social/lib/social/models/referral/index.coffee
@@ -148,24 +148,8 @@
       totalStep--

   @fetchReferredAccounts = secure (client, query, options, callback)->
-    @fetchOwnReferralsIds client, query, options, (err, allReferalIds) ->
-      return callback err if err
-
-      referredSelector = {
-        sourceName  : 'JAccount',
-        targetId    : { $in: allReferalIds },
-        targetName  : 'JReferral',
-        as          : 'referred'
-      }
-
-      # no need to add limit here, because in fetchOwnReferralsIds method there is limit,
-      # this is a subset of it, so this will be lte than ownReferralsIds
-      Relationship.some referredSelector, {}, (err, relationships)=>
-        return callback err if err
-
-        accSelector = { _id: $in: relationships.map (rel) -> rel.sourceId }
-        JAccount.some accSelector, {}, callback
-
+    username = client.connection.delegate.profile.nickname
+    JAccount.some { referrerUsername : username }, options, callback

   @redeem = secure (client, data, callback)->
     {vmName, size, type} = data


JCounter:Tests: move cleanup part to afterTests

--- workers/social/lib/social/models/counter.test.coffee
+++ workers/social/lib/social/models/counter.test.coffee
@@ -14,6 +14,10 @@
 { expect } = require 'chai'
 { generateRandomString, checkBongoConnectivity } = require '../../../testhelper'

+NAMESPACES           = []
+LIMIT_EXCEEDED_ERROR = 'Provided limit has been reached'
+
+
 # this function will be called once before running any test
 beforeTests = -> before (done) ->

@@ -21,9 +25,6 @@

 runTests = ->
-
-  LIMIT_EXCEEDED_ERROR = 'Provided limit has been reached'
-  NAMESPACES           = []

   describe 'workers.social.counter.increment', ->

@@ -181,20 +182,23 @@

       daisy queue

-    it 'should reset counters with namespaces', (done) ->
-
-      queue = [ ]
-
-      NAMESPACES.forEach (namespace) -> queue.push ->
-        JCounter.reset { namespace }, (err) ->
-          expect(err).to.not.exist
-          queue.next()
-
-      queue.push -> done()
-
-      daisy queue
+
+afterTests = -> after (done) ->
+
+    queue = [ ]
+
+    NAMESPACES.forEach (namespace) -> queue.push ->
+      JCounter.reset { namespace }, (err) ->
+        expect(err).to.not.exist
+        queue.next()
+
+    queue.push -> done()
+
+    daisy queue

 beforeTests()

 runTests()
+
+afterTests()


:bug: support case when draft is edited

:bug: support case when draft is edited


JSTextField update

JSTextField update

--- JSKit/04_JSTextField.coffee
+++ JSKit/04_JSTextField.coffee
@@ -14,6 +14,7 @@
 		@_editable = true
 		@_action = null
 		@_focus = false
+		@_placeholder = ""

 	getText:->
 		if (@_editable == true)
@@ -56,6 +57,9 @@
 		super(frame)
 		$(@_viewSelector+"_text").width(frame.size.width)
 		$(@_viewSelector+"_text").height(frame.size.height)
+
+	setPlaceHolder:(@_placeholder)->
+		$(@_viewSelector+"_text").attr("data-placeholder", @_placeholder)

 	setEditable:(editable)->
 		if (!$(@_viewSelector).length)
@@ -141,6 +145,7 @@
 		@setTextSize(@_textSize)
 		@setTextColor(@_textColor)
 		@setTextAlignment(@_textAlignment)
+		@setPlaceHolder(@_placeholder)
 		$(@_viewSelector).css("overflow", "")


fix for Opinion Count not being displayed correctly

--- client/landing/app/Applications/Activity.kdapplication/views/tutorialactivityactions.coffee
+++ client/landing/app/Applications/Activity.kdapplication/views/tutorialactivityactions.coffee
@@ -5,16 +5,14 @@

     activity = @getData()

-    @opinionCount?.destroy()
-
     @opinionCountLink  = new ActivityActionLink
       partial     : "Opinions"
       click     : (pubInst, event)=>
         @emit "TutorialActivityLinkClicked"

-    if activity.repliesCount is 0 then @opinionCountLink.hide()
+    if activity.opinionCount is 0 then @opinionCountLink.hide()

-    @opinionCount = new ActivityCommentCount {}, activity
+    @opinionCount = new ActivityOpinionCount {}, activity

     @opinionCount.on "countChanged", (count) =>
       if count > 0 then @opinionCountLink.show()
@@ -43,7 +41,7 @@
   pistachio:->
     """
       {{> @loader}}
-      {{> @opinionCountLink}} {{> @opinionCount}} #{if @getData()?.repliesCount > 0 then " ·" else "" }
+      {{> @opinionCountLink}} {{> @opinionCount}} #{if @getData()?.opinionCount > 0 then " ·" else "" }
       <span class='optional'>
       {{> @shareLink}} ·
       </span>


problem with rebase

problem with rebase

--- BackofficeBundle/Resources/public/coffee/table/tableviewLoader.coffee
+++ BackofficeBundle/Resources/public/coffee/table/tableviewLoader.coffee
@@ -22,8 +22,8 @@
             elementModel = new TableviewModel
             elementModel.set values
             if entityId is elementModel.get('id')
-              url = elementModel.get('links')._self_form
-              url = url + '?language=' + language if (typeof language != 'undefined')
+              language = elementModel.get('language') if (typeof language == 'undefined')
+              url = elementModel.get('links')._self_form + '?language=' + language
               $.ajax
                 url: url
                 method: "GET"


tab pane lazy view warning fix

tab pane lazy view warning fix

--- client/Framework/components/tabs/KDTabPaneView.coffee
+++ client/Framework/components/tabs/KDTabPaneView.coffee
@@ -44,8 +44,10 @@
     @getDelegate().hideCloseIcon @

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

     if view instanceof KDView
       @mainView = @addSubView view


fix comment submit

fix comment submit

--- app/assets/javascripts/frontend/posts.coffee
+++ app/assets/javascripts/frontend/posts.coffee
@@ -3,7 +3,8 @@
 # You can use CoffeeScript in this file: http://coffeescript.org/

 $(document).on 'ready page:load', () ->
-  $("#new_comment_submit").click ->
+  $("#new_comment").submit (e) ->
+    e.preventDefault()
     $("#new_comment_submit").attr("disabled", true)
     $.ajax
       url: $("#new_comment").attr("action"),


Handle autofocus on datatable render

Handle autofocus on datatable render

--- app/assets/javascripts/effective_datatables/initialize.js.coffee
+++ app/assets/javascripts/effective_datatables/initialize.js.coffee
@@ -200,6 +200,7 @@

     table.addClass('initialized')
     table.children('thead').trigger('effective-bootstrap:initialize')
+    $('input[autofocus]').first().focus()
     true

 destroyDataTables = ->


Onboarding: Replaced hardcoded app names with KD.config.apps.

--- client/Dashboard/views/onboarding/onboardingsectionform.coffee
+++ client/Dashboard/views/onboarding/onboardingsectionform.coffee
@@ -1,6 +1,9 @@
 class OnboardingSectionForm extends KDFormViewWithFields

   constructor: (options = {}, data) ->
+
+    apps = []
+    apps.push { title: app, value: app }  for app of KD.config.apps

     options.cssClass      = "section-form"
     @jCustomPartial       = data
@@ -22,14 +25,7 @@
             itemClass     : KDSelectBox
             cssClass      : "apps"
             defaultValue  : formData?.app
-            selectOptions : [
-              { title     : "Activity", value: "Activity" }
-              { title     : "Teamwork", value: "Teamwork" }
-              { title     : "Ace",      value: "Ace"      }
-              { title     : "Terminal", value: "Terminal" }
-              { title     : "Apps",     value: "Apps"     }
-              { title     : "Bugs",     value: "Bugs"     }
-            ]
+            selectOptions : apps
       visibility          :
         label             : "Show items together"
         itemClass         : KodingSwitch


Firewall: Passed rule item data to rule item form class.

--- client/Environments/views/firewall/addfirewallrulemodal.coffee
+++ client/Environments/views/firewall/addfirewallrulemodal.coffee
@@ -69,8 +69,8 @@

     @modalTabs.forms.Rules.buttonField.addSubView button, null, yes

-  createRuleWidget: (removable = yes) ->
-    widget = new FirewallFilterFormView { removable }
+  createRuleWidget: (removable = yes, data = null) ->
+    widget = new FirewallFilterFormView { removable }, data
     widget.on "FirewallFilterRemoved", =>
       @filterWidgets.splice @filterWidgets.indexOf(widget), 1


profile: handling of the static blog default item and non existing data fields

--- client/landing/app/MainApp/lazy/staticprofilecontroller.coffee
+++ client/landing/app/MainApp/lazy/staticprofilecontroller.coffee
@@ -49,9 +49,10 @@

       # HERE is the place to implement custom profile splash screens, reveal.js and such

+      @staticDefaultItem.show()
       @emit 'StaticProfileNavLinkClicked', 'CBlogPostActivity', yes, =>
         @showWrapper @staticListWrapper
-
+        @staticDefaultItem.show()

     @on 'ActivityLinkClicked', (path)=>
       unless @activityListWrapper?
@@ -233,6 +234,10 @@
         @profileContentWrapperView.$().css marginLeft : "50px"

     # reviving feed type selectors that will activate feed facets
+
+
+    @staticDefaultItem = new KDView
+      lazyDomId : 'profile-blog-default-item'

     @profileContentLinks = new KDView
       lazyDomId : 'profile-content-links'
@@ -461,6 +466,8 @@
   hideWrappers:->
     @profileContentView.$('.content-item.static').remove()

+    @staticDefaultItem.hide()
+
     @profileShowMoreView.hide()
     @staticListWrapper?.hide()
     @activityListWrapper?.hide()


StackTemplateListController: Remove event bindings while controller is destroying

--- client/app/lib/stacks/stacktemplatelistcontroller.coffee
+++ client/app/lib/stacks/stacktemplatelistcontroller.coffee
@@ -66,24 +66,30 @@
     @on 'FetchProcessFailed', ({ err }) ->
       showError err, { KodingError : 'Failed to fetch stackTemplates, try again later.' }

-    kd.singletons.computeController.on 'RenderStacks', (stacks) =>
-      listItems = @getListItems()
-
-      for stack in stacks
-        [item] = listItems.filter (i) -> i.getData()._id is stack.baseStackId
-        if item
-          item.getData().inUse = yes
-          item.inUseView.show()
-
-
-    groupsController.on 'StackTemplateChanged', (params) =>
-
-      stackTemplateId = params.contents
-      [item]  = @getListItems().filter (i) -> i.getData()._id is stackTemplateId
-
-      unless item
-        @fetch { _id : stackTemplateId }, (items) =>
-          @addListItems items
+    { computeController, groupsController } = kd.singletons
+
+    computeController.on  'RenderStacks',         @bound 'handleRenderStacks'
+    groupsController.on   'StackTemplateChanged', @bound 'handleStackTemplateChanged'
+
+
+  handleRenderStacks: (stacks) ->
+
+    listItems = @getListItems()
+
+    for stack in stacks
+      [item] = listItems.filter (i) -> i.getData()._id is stack.baseStackId
+      if item
+        item.getData().inUse = yes
+        item.inUseView.show()
+
+
+  handleStackTemplateChanged: (params) ->
+
+    stackTemplateId = params.contents
+    [item]  = @getListItems().filter (i) -> i.getData()._id is stackTemplateId
+
+    unless item
+      @fetch { _id : stackTemplateId }, (items) => @addListItems items

   applyToTeam: (item) ->
@@ -194,3 +200,13 @@
       stackTemplates = stackTemplates.filter (template) -> template.accessLevel is 'group'

     return stackTemplates
+
+
+  destroy: ->
+
+    { computeController, groupsController } = kd.singletons
+
+    computeController.off   'RenderStacks',         @bound 'handleRenderStacks'
+    groupsController.off    'StackTemplateChanged', @bound 'handleStackTemplateChanged'
+
+    super


* Call attributeModifier function on getter when set

--- app/assets/javascripts/backbone.rails_store.js.coffee
+++ app/assets/javascripts/backbone.rails_store.js.coffee
@@ -1019,6 +1019,8 @@
         modifier = @_store.getBuiltinModifierFormat('Boolean')
         return modifier[1] if @attributes[attr]
         return modifier[0] if not @attributes[attr] or @attributes[attr] == 'false'
+      else if _.isFunction(@attributeModifiers[attr].getConverter)
+        return @attributeModifiers[attr].getConverter(@attributes[attr])

     # If we have, deliver
     val = super


prevent JS errors

prevent JS errors

--- app/assets/javascripts/gmaps_search_results.js.coffee
+++ app/assets/javascripts/gmaps_search_results.js.coffee
@@ -61,12 +61,12 @@
 bindExternalEvents = ->
   $('.JS-trigger-marker').on 'mouseover', (event) ->
     marker = $(event.delegateTarget).data('marker')
-    if marker.getAnimation() == null
+    if marker and marker.getAnimation() == null
       marker.setAnimation google.maps.Animation.BOUNCE

   $('.JS-trigger-marker').on 'mouseout', (event) ->
     marker = $(event.delegateTarget).data('marker')
-    if marker.getAnimation() != null
+    if marker and marker.getAnimation() != null
       marker.setAnimation null

 google.maps.event.addDomListener window, 'load', initialize


Open basket after buy is copied to it to make the behavior identical

--- app/assets/javascripts/services/basket_service.coffee
+++ app/assets/javascripts/services/basket_service.coffee
@@ -77,6 +77,7 @@
       empty()
       search = $location.search()
       search.buyer = buy.buyer.username
+      search.basket = "true"
       for entry in buy.consistsOfProducts
         search[entry.product.name] = entry.amount
       $location.search(search).replace()


resolving conflict

resolving conflict

--- bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
+++ bokehjs/src/coffee/renderer/tile/tile_renderer.coffee
@@ -73,7 +73,7 @@
       x_coord : bounds[0]
       y_coord : bounds[3]

-    @mget('tile_source').tiles[tile.tile_data.cache_key] = tile_data
+    @mget('tile_source').tiles[tile.tile_data.cache_key] = tile.tile_data
     tile.src = @mget('tile_source').get_image_url(x, y, z)
     return tile


Added sticky option to KDModalView.

Added sticky option to KDModalView.

--- client/Framework/components/modals/KDModalView.coffee
+++ client/Framework/components/modals/KDModalView.coffee
@@ -14,6 +14,7 @@
     options.fx           or= no            # a Boolean
     options.view         or= null          # a KDView instance
     options.draggable    or= handle : ".kdmodal-title"
+    options.sticky       or= no
     # TO BE IMPLEMENTED
     options.resizable    or= no            # a Boolean

@@ -55,9 +56,11 @@
     $(window).one "keydown.modal",(e)=>
       @cancel() if e.which is 27

-    @on "childAppended", @setPositions.bind @
-
-    @listenWindowResize()
+    unless @getOptions().sticky
+      @on "childAppended", @setPositions.bind @
+      @listenWindowResize()
+
+    @setPositions()

   setDomElement:(cssClass)->

@@ -146,6 +149,7 @@
       @$().css opacity : 1

   _windowDidResize:->
+    return unless @getOptions().sticky
     @setPositions()
     {winHeight} = @getSingleton('windowController')
     @$('.kdmodal-content').css 'max-height', winHeight - 200


Social: remove unused function

Social: remove unused function

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -145,17 +145,6 @@
     return  unless channelMessage

     {typeConstant, id} = channelMessage
-
-    listController = @getListController typeConstant
-    item = listController.itemForId id
-    item.setUnreadCount unreadCount  if item?.unreadCount
-
-
-  setChannelUnreadCount: ({unreadCount, channel}) ->
-
-    return  unless channel
-
-    {typeConstant, id} = channel

     listController = @getListController typeConstant
     item = listController.itemForId id


social: fixed problem with wrong selection of workspace

--- client/Social/Activity/sidebar/activitysidebar.coffee
+++ client/Social/Activity/sidebar/activitysidebar.coffee
@@ -640,7 +640,6 @@
     @watchedMachines  or= {}
     computeController   = KD.getSingleton 'computeController'
     appManager          = KD.getSingleton 'appManager'
-    isSameMachineActive = appManager.getFrontApp().mountedMachineUId is machine.uid
     {Running}           = Machine.State

     return  if @watchedMachines[machine._id]
@@ -648,7 +647,7 @@
     callback = (state) =>
       if state.status is Running
         machine.status.state = Running
-        if isSameMachineActive
+        if appManager.getFrontApp().mountedMachineUId is machine.uid
           @selectWorkspace { workspace, machine }
           delete @watchedMachines[machine._id]


Activity: Activity Edit Button behaviour is bound

--- client/Social/Activity/views/activityitemchild.coffee
+++ client/Social/Activity/views/activityitemchild.coffee
@@ -68,6 +68,20 @@
       activityItem = @getDelegate()
       deleteActivity activityItem

+    @settingsButton.on 'ActivityEditIsClicked', =>
+      unless @editWidget
+        @editWidget = new ActivityInputWidget editMode: yes
+        reset = => @editWidget = null if @editWidget
+
+        @editWidget.on 'Submit', => do reset
+        @editWidget.on 'Cancel', => do reset
+
+        @editWidget.edit @getData()
+
+        @addSubView @editWidget, null, yes
+
+
+
     data.on 'PostIsDeleted', =>
       activityItem = @getDelegate()
       return unless activityItem.isInDom()


Client: Team Settings: Logs: Updated fetcherMethod to check error is exist or not

--- client/admin/lib/views/logs/logslistcontroller.coffee
+++ client/admin/lib/views/logs/logslistcontroller.coffee
@@ -12,8 +12,9 @@
     options.noItemFoundText     or= 'No logs found!'
     options.fetcherMethod         = (query, fetchOptions, callback) =>
       doXhrRequest @getXHROptions(), (err, res) ->
+        return callback err  if err
         { data: { logs } } = res
-        callback err, logs
+        callback null, logs

     super options, data


Cleaning up javascriptinput setup method

--- common/lib/xmodule/xmodule/js/src/capa/display.coffee
+++ common/lib/xmodule/xmodule/js/src/capa/display.coffee
@@ -214,11 +214,11 @@

       data = $(element).find(".javascriptinput_data")

-      params        = JSON.parse(data.attr("data-params"))
-      submission    = JSON.parse(data.attr("data-submission"))
-      evaluation    = JSON.parse(data.attr("data-evaluation"))
-      problemState  = JSON.parse(data.attr("data-problem_state"))
-      displayClass  = eval(data.attr("data-display_class"))
+      params        = data.data("params")
+      submission    = data.data("submission")
+      evaluation    = data.data("evaluation")
+      problemState  = data.data("problem_state")
+      displayClass  = window[data.data('display_class')]

       container = $(element).find(".javascriptinput_container")
       submissionField = $(element).find(".javascriptinput_input")


Make 'Explanation' CAPA header translatable.

CAPA <explanation> nodes get transformed into a HTML <div> block
that contains the word 'Explanation'.

This patch makes it translatable.

--- common/lib/xmodule/xmodule/js/src/problem/edit.coffee
+++ common/lib/xmodule/xmodule/js/src/problem/edit.coffee
@@ -505,7 +505,7 @@

       // replace explanations
       xml = xml.replace(/\[explanation\]\n?([^\]]*)\[\/?explanation\]/gmi, function(match, p1) {
-          var selectString = '<solution>\n
\nExplanation\n\n' + p1 + '\n
\n</solution>';
+          var selectString = '<solution>\n
\n' + gettext('Explanation') + '\n\n' + p1 + '\n
\n</solution>';

           return selectString;
       });


no message

no message

--- contentful.coffee
+++ contentful.coffee
@@ -4,8 +4,8 @@
   space_id: '7vfiut035ckb'
   content_types: {                  # remove these object braces once the config below is filled out
      topics:                          # data will be made available through this key on the `contentful` object in your templates
-       id: 'xxxx'                    # ID of your content type
+       id: 'topic'                    # ID of your content type
     #   filters: {}                   # passes filters to the call to contentful's API, see contentful's docs for more info
-       template: 'views/codepage.jade'  # if present a single page view will be created for each entry in the content type
+    #   template: 'views/codepage.jade'  # if present a single page view will be created for each entry in the content type
     #   path: (entry) ->              # override function for generating single page file path, passed in the entry object
 }


Better error handling

Better error handling

--- elaboratecharts/coffee/index.coffee
+++ elaboratecharts/coffee/index.coffee
@@ -175,6 +175,11 @@

 hideAlert = ->
   $('#alert').addClass('hidden')
+  $('#alert')
+    .removeClass('alert-success')
+    .removeClass('alert-info')
+    .removeClass('alert-warning')
+    .removeClass('alert-danger')

 showAlert = (type, reason, message) ->
@@ -197,7 +202,13 @@
   new Promise (resolve, reject) ->
     $.getJSON(url, params)
     .done (result) -> resolve(result)
-    .fail (jqxhr, textStatus, error) -> reject(jqxhr)
+    .fail (jqxhr, textStatus, reason) ->
+      message = jqxhr.responseJSON?.error ? reason
+      error = new Error(message)
+      error.jqxhr = jqxhr
+      error.textStatus = textStatus
+      error.reason = reason
+      reject(error)

 setDefaults = (params) ->
@@ -247,10 +258,13 @@
         fromDate: fromDate,
         toDate: toDate)
       .then (response) ->
+        if response.error?
+          console.error(new Error(response.error))
         progress += 1
         ladda.setProgress(progress / ranges.length)
         response
-      .catch ->
+      .catch (err) ->
+        console.error(err)
         showAlert('danger', 'Server Error', 'Failed to get weekly charts.')
         ladda.stop()
   .then (charts) ->
@@ -269,10 +283,8 @@
     unless failedWeeksArray.length > 0
       navbarCollapsedState('add')
   .catch (err) ->
-    # Failed to get user info or there were server-side errors while getting
-    # weekly charts.
-    message = err.responseJSON?.error ? ''
-    if message.indexOf('error code 6') > -1
+    console.error(err)
+    if err.message.indexOf('error code 6') > -1
       # No user with that name was found.
       $username = $('#username')
       $username.parent().addClass('has-error').addClass('has-feedback')


Redraw only after week has been processed

--- elaboratecharts/coffee/index.coffee
+++ elaboratecharts/coffee/index.coffee
@@ -12,6 +12,8 @@
     yAxis:
       title:
         text: 'Percent'
+    legend:
+      enabled: false
     plotOptions:
       area:
         stacking: 'percent'
@@ -26,6 +28,7 @@
 $ ->
   weeks = []
   artists = []
+  data = {}

   socket = io.connect('http://' + document.domain + ':' + location.port)

@@ -38,17 +41,22 @@
     chart = $('#chart').highcharts()
     for [artist, count] in pairs
       if artist not in artists
+        data[artist] = []
         artists.push(artist)
+        data[artist] = (0 for __ in weeks)
         chart.addSeries
           name: artist
-          data: (0 for __ in weeks)
+          data: data[artist]
         , false
       seriesIndex = artists.indexOf(artist)
-      pointsIndex = weeks.indexOf(timestamp)
-      chart.series[seriesIndex].points[pointsIndex].update(y: count, false)
+      data[artist][weeks.indexOf(timestamp)] = count
+      chart.series[seriesIndex].setData(data[artist], false)
     chart.redraw()

   $('#submit').click ->
+    weeks = []
+    artists = []
+    data = {}
     username = $('#username').val().trim()
     timeRange = $('#time-range li.active').attr('id')
     fromDate = switch timeRange


Change WA message

Change WA message

--- client/components/SubmitList.coffee
+++ client/components/SubmitList.coffee
@@ -79,6 +79,8 @@
                             cl = undefined
                             message = submit.outcome
                             switch submit.outcome
+                                when "Частичное решение"
+                                    message = "Неполное решение"
                                 when "AC"
                                     cl = "success"
                                     message = "Зачтено"


client: home: minor

client: home: minor

--- client/home/lib/stacks/index.coffee
+++ client/home/lib/stacks/index.coffee
@@ -1,10 +1,11 @@
-kd                      = require 'kd'
-sectionize              = require '../commons/sectionize'
-headerize               = require '../commons/headerize'
-HomeStacksCreate        = require './homestackscreate'
-HomeStacksTeamStacks    = require './homestacksteamstacks'
+kd = require 'kd'
+sectionize = require '../commons/sectionize'
+headerize = require '../commons/headerize'
+
+HomeStacksCreate = require './homestackscreate'
+HomeStacksTeamStacks = require './homestacksteamstacks'
 HomeStacksPrivateStacks = require './homestacksprivatestacks'
-HomeStacksDrafts        = require './homestacksdrafts'
+HomeStacksDrafts = require './homestacksdrafts'

 EnvironmentFlux         = require 'app/flux/environment'


 Merge branch 'master.editorImprovements' into 'master'

Master.Editor Improvements

We can merge it

--- client/landing/Login/AppView.coffee
+++ client/landing/Login/AppView.coffee
@@ -395,6 +395,7 @@
     (KD.getSingleton 'mainController').handleFinishRegistration formData, @bound 'afterLoginCallback'

   doLogin:(credentials)->
+    KD.singletons.localSync.removeLocalContents()
     (KD.getSingleton 'mainController').handleLogin credentials, @bound 'afterLoginCallback'

   runExternal = (token)->


Removed forgotten console.log

Removed forgotten console.log

--- src/mixins/validatable-http-message.coffee
+++ src/mixins/validatable-http-message.coffee
@@ -199,7 +199,7 @@
       # e.g. for application/hal+json or or application/vnd.apiary.something
       if !(@expected.headers == undefined) and !(@expected.headers['content-type']  == undefined)
         contentType = @expected.headers['content-type'].split(';')[0]
-        console.log "GAVEL: #{contentType}"
+
         isJsonContentType = contentType == 'application/json'

       if isJsonContentType


Fix lint warning

Fix lint warning

--- src/code/views/node-view.coffee
+++ src/code/views/node-view.coffee
@@ -243,7 +243,7 @@
     evt.dataTransfer.setData('text', attributeName)
     evt.dataTransfer.setData('application/x-codap-attr-' + attributeName, attributeName)
     # CODAP sometimes seems to expect an SC.Array object with a `contains` method, so this avoids a potential error
-    evt.dataTransfer.contains = () -> false
+    evt.dataTransfer.contains = -> false

   nodeClasses: ->
     classes = ['elm']


test/credentials: show and remove credentials

--- client/test/lib/dashboard/credentials.coffee
+++ client/test/lib/dashboard/credentials.coffee
@@ -33,3 +33,34 @@
       .waitForElementVisible sectionSelector, 20000

+  showAndRemoveCredential: (browser) ->
+
+    sectionSelector = '.kdview.kdtabpaneview.credentials'
+    credential = '.kdview.kdlistitemview.kdlistitemview-default.credential-item'
+    showButton = "#{credential} .custom-link-view.HomeAppView--link.primary"
+    removeButton = "#{credential} .custom-link-view.HomeAppView--link"
+    closeModal = '.kdmodal-inner .close-icon.closeModal'
+    removeCredentialButton = '.kdmodal-inner .kdview.kdmodal-buttons .kdbutton.solid.red.medium.w-loader'
+    credentialInfo = "#{credential} .credential-info"
+
+    browser
+      .pause 5000
+      .url credentialsUrl
+      .waitForElementVisible sectionSelector, 20000
+      .waitForElementVisible showButton, 20000
+      .click showButton
+      .waitForElementVisible closeModal, 20000
+      .click closeModal
+      .pause 2000
+      .assert.containsText credentialInfo, 'aws2'
+      .click removeButton
+      .waitForElementVisible removeCredentialButton, 20000
+      .click removeCredentialButton
+      .pause 2000
+      .waitForElementVisible credential, 20000
+      .assert.containsText credentialInfo, 'aws1'
+      .pause 2000
+      .click removeButton
+      .waitForElementVisible removeCredentialButton, 20000
+      .click removeCredentialButton
+      .pause 2000


Maintain compat for not using whileLoopMarker

--- src/interpreter.coffee
+++ src/interpreter.coffee
@@ -116,21 +116,28 @@
   #console.log "----"

   top = frame_stack[0]
-
+
   if top.type is 'loop'
     if frame_stack[1].ast.type is 'WhileStatement' and frame_stack[1].ast.test.type is 'Literal'
-      if not top.marked
-        top.marked = true
-        top.mark = aether.whileLoopMarker() if aether.whileLoopMarker
-      else if not top.ast?
-        currentMark = aether.whileLoopMarker()
-        if not aether.whileLoopMarker or currentMark is top.mark
-          #console.log "[Aether] Forcing while-true loop to yield."
-          top.mark = currentMark + 1
-          return true
-        else
-          #console.log "[Aether] Loop Avoided, mark #{top.mark} isnt #{currentMark}"
-          top.mark = currentMark
+      if aether.whileLoopMarker?
+        if not top.marked
+          top.marked = true
+          top.mark = aether.whileLoopMarker()
+        else if not top.ast?
+          currentMark = aether.whileLoopMarker()
+          if currentMark is top.mark
+            #console.log "[Aether] Forcing while-true loop to yield."
+            top.mark = currentMark + 1
+            return true
+          else
+            #console.log "[Aether] Loop Avoided, mark #{top.mark} isnt #{currentMark}"
+            top.mark = currentMark
+      else
+        if not top.marked
+          top.marked = true
+        else if not top.ast?
+          if not top.didYield
+            return true

   return false


As it turned out, ref is not needed at all

--- resources/assets/coffee/react/mp-history/content.coffee
+++ resources/assets/coffee/react/mp-history/content.coffee
@@ -11,12 +11,6 @@
 el = React.createElement

 export class Content extends React.PureComponent
-  constructor: (props) ->
-    super props
-
-    @pageRef = React.createRef()
-
-
   getSnapshotBeforeUpdate: (prevProps, prevState) =>
     snapshot =
       scrollToLastEvent: prevProps.isAutoloading && @props.isAutoloading && osu.bottomPageDistance() < 10
@@ -25,16 +19,12 @@
       if prevProps.events?.length > 0 && @props.events?.length > 0
         # This is to allow events to be added without moving currently
         # visible events on viewport.
-        #
-        # When prepending, bottom position should be the reference as top
-        # will be pushed by new events.
         if prevProps.events[0].id > @props.events[0].id
-          snapshot.referenceFunc = => @pageRef.current.getBoundingClientRect().bottom
+          snapshot.referenceFunc = -> document.body.scrollHeight
         else
-          snapshot.referenceFunc = => @pageRef.current.getBoundingClientRect().top
+          snapshot.referenceFunc = -> 0

         snapshot.referencePrev = snapshot.referenceFunc()
-
     snapshot

@@ -53,7 +43,7 @@
     eventsGroupOpen = div className: classWithModifiers('mp-history-content__item', ['event', 'event-open'])
     eventsGroupClose = div className: classWithModifiers('mp-history-content__item', ['event', 'event-close'])

-    div className: 'mp-history-content', ref: @pageRef,
+    div className: 'mp-history-content',
       h3 className: 'mp-history-content__item', @props.match.name

       if @props.hasPrevious


[skip] Improved snapping for new milestones too (6m)

--- app/assets/javascripts/houston/roadmap/views/edit_roadmap_view.coffee
+++ app/assets/javascripts/houston/roadmap/views/edit_roadmap_view.coffee
@@ -26,11 +26,12 @@

     @$el.on 'mouseup', (e)=>
       return unless @$newMilestone and @supportsCreate
-      newMilestoneWidth = e.screenX - @newMilestoneX
+      newMilestoneWidth = @$newMilestone.outerWidth()
       if newMilestoneWidth > 10
         band = +@$newMilestone.closest('.roadmap-band').attr('data-band')
-        startDate = @x.invert(@$newMilestone.position().left)
-        endDate = @x.invert(@$newMilestone.position().left + @$newMilestone.width())
+        left = @$newMilestone.position().left
+        startDate = @x.invert(left)
+        endDate = @x.invert(left + newMilestoneWidth)
         attributes =
           band: band
           lanes: 1
@@ -48,8 +49,10 @@
       newMilestoneWidth = e.screenX - @newMilestoneX
       newMilestoneWidth = 0 if newMilestoneWidth < 0

-      startDate = @x.invert(@$newMilestone.position().left)
+      left = @$newMilestone.position().left
+      startDate = @x.invert(left)
       endDate = d3.time.saturday.round(@x.invert(@$newMilestone.position().left + newMilestoneWidth))
+      newMilestoneWidth = @x(endDate) - left
       milliseconds = endDate.getTime() - startDate.getTime() + 2 * Duration.DAY
       weeks = Math.floor(milliseconds / Duration.WEEK)


Update fr.coffee

Update fr.coffee

trivial (http://www.cnrtl.fr/definition/réessayer)

--- client/app/locales/fr.coffee
+++ client/app/locales/fr.coffee
@@ -9,7 +9,7 @@
       "app alert close"         : "Fermer"
       "app unimplemented"       : "Non implémenté"
       "app error"               : "Oups, une erreur est survenue,
-                                    veuillez ré-essayer"
+                                    veuillez réessayer"

       # Compose window
       "compose"                   : "Écrire un nouveau message"