Skip to content

Instantly share code, notes, and snippets.

@cmpscabral
Forked from miklschmidt/notifications.coffee
Created July 2, 2013 20:13
Show Gist options
  • Save cmpscabral/5912708 to your computer and use it in GitHub Desktop.
Save cmpscabral/5912708 to your computer and use it in GitHub Desktop.
define [
'jquery'
'underscore'
'backbone'
'lib/gui'
'models/notification'
'views/notification'
'vendor/tween'
'jquery-ui'
], ($, _, Backbone, gui, NotificationModel, Notification, TWEEN) ->
class NotificationManager
_(@prototype).extend Backbone.Events
counter: 0
windowWidth: 290
windowHeight: 0
window: null
loaded: no
stack: []
animationDuration: 350
defaultNoteOptions:
persistent: no
timeout: 5000
content: ''
title: ''
icon: ''
_makeID: () ->
return 'note' + ++@counter
constructor: () ->
@window = gui.Window.open 'notifications.html'
frame: no
toolbar: no
width: @windowWidth
height: @windowHeight
'always-on-top': yes
show: no
resizable: false
@window.on 'loaded', () =>
@$body = $(@window.window.document.body)
@$el = @$body.find('#notifications')
# @window.showDevTools()
@loaded = yes
@trigger 'loaded'
# Window.moveTo will break like a bauws if called too early
# might have been fixed after 0.6.0
try
@window.moveTo(@getX()+@windowWidth, screen.height)
catch
create: (options) ->
attributes = {}
id = @_makeID()
_.extend(attributes, @defaultNoteOptions, options)
attributes.id = id
model = new NotificationModel attributes
note = new Notification model: model, manager: @
attributes.setup(note) if typeof attributes.setup is 'function'
note.on '!close', () => @_close(note)
unless attributes.persistent
setTimeout (() => @_close(note)), attributes.timeout
if @loaded
@stack.push note
note.$el.addClass('odd') unless @stack.length % 2
@_show note
else
@once 'loaded', () =>
@stack.push note
note.$el.addClass('odd') unless @stack.length % 2
@_show note
getX: () ->
return screen.availLeft + screen.availWidth - @windowWidth
getY: () ->
return screen.availTop + screen.availHeight - @windowHeight
slideIn: (callback) ->
me = @
me.window.show()
me.shown = yes
tween = new TWEEN.Tween({x: @getX(), y: @getY()+@windowHeight})
.to({x: @getX(), y: @getY()}, @animationDuration)
.easing(TWEEN.Easing.Exponential.Out)
.onUpdate(->
me.window.moveTo(Math.round(this.x), Math.round(this.y))
)
.onComplete(->
callback?()
)
.start()
@animate(tween)
slideOut: (callback) ->
me = @
tween = new TWEEN.Tween({x: @getX(), y: @getY()})
.to({x: @getX(), y: screen.height}, @animationDuration)
.easing(TWEEN.Easing.Exponential.In)
.onUpdate(->
me.window.moveTo(Math.round(this.x), Math.round(this.y))
)
.onComplete(->
me.shown = no
me.window.hide()
callback?()
)
.start()
@animate(tween)
fitWindow: (callback) ->
me = @
me.window.setResizable(true) # Can't programatically resize the window on linux without this.
tween = new TWEEN.Tween({x: @windowWidth, y: @windowHeight})
.to({x: @windowWidth, y: @$el.innerHeight()}, @animationDuration)
.easing(TWEEN.Easing.Exponential.InOut)
.onUpdate(->
me.windowHeight = Math.round(this.y)
me.window.moveTo(me.getX(), me.getY())
me.window.resizeTo(Math.round(this.x), Math.round(this.y))
)
.onComplete(->
me.window.setResizable(false)
callback?()
)
.start()
@animate(tween)
animate: (tween) =>
time = if window.performance?.now? then window.performance.now() else Date.now()
requestAnimationFrame(()=>@animate(tween)) if tween.update(time)
_close: (note) =>
close = (note) =>
@stack = _(@stack).reject (n) -> note.model.id is n.model.id
me = @
me.window.setResizable(true) # Can't programatically resize the window on linux without this.
note.$el.css('overflow', 'hidden')
currentHeight = note.$el.outerHeight()
oldHeight = @windowHeight
tween = new TWEEN.Tween({elHeight: currentHeight, windowHeight: 0, opacity: 1})
.to({elHeight: 0, windowHeight: currentHeight, opacity: 0}, @animationDuration)
.easing(TWEEN.Easing.Cubic.In)
.onUpdate(->
me.windowHeight = Math.round(oldHeight - this.windowHeight)
note.$el.css({height: Math.round(this.elHeight), opacity: this.opacity})
me.window.resizeTo(me.windowWidth, me.windowHeight)
me.window.moveTo(me.getX(), me.getY())
)
.onComplete(->
me.window.setResizable(false)
note.dispose()
)
.start()
@animate(tween)
# note.$el.hide 'blind', 500, () =>
# note.dispose()
# @fitWindow()
if @stack.length is 1
@slideOut () ->
close(note)
else
close(note)
dispose: () ->
_show: (note) =>
@$el.append note.el
note.render()
@fitWindow () =>
unless @shown
@slideIn () =>
#TODO: Find out why the stupid height is incorrect until the friggin' window is above the fucking task bar..
@fitWindow()
return new NotificationManager
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment