Last active
July 13, 2017 06:11
-
-
Save miklschmidt/5896306 to your computer and use it in GitHub Desktop.
Take at notifications for node-webkit with a shitload of dependencies (Require.js, chaplin, TWEEN.js and so on).. sorry for that.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' | |
try | |
@window.moveTo(@getX()+@windowWidth, @window.window.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 @window.window.screen.availLeft + @window.window.screen.availWidth - @windowWidth | |
getY: () -> | |
return @window.window.screen.availTop + @window.window.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: @window.window.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) | |
) | |
.start() | |
@animate tween | |
tweenStack: [] | |
animating: false | |
animateNext: () => | |
if @tweenStack.length | |
tween = @tweenStack.splice(0,1)[0] | |
@animating = true | |
@_animate(tween) | |
animate: (tween) => | |
@tweenStack.push tween | |
unless @animating | |
@animateNext() | |
_animate: (tween) => | |
time = if window.performance?.now? then window.performance.now() else Date.now() | |
if tween.update(time) | |
setTimeout (()=>@_animate(tween)), 28 | |
else | |
setTimeout () => | |
@animating = false | |
@animateNext() | |
, 28 | |
_close: (note) => | |
return if note.disposed | |
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 | |
x = me.getX() | |
tween = new TWEEN.Tween({elHeight: currentHeight}) | |
.to({elHeight: 0}, @animationDuration) | |
.easing(TWEEN.Easing.Cubic.In) | |
.onStart(-> | |
oldHeight = me.windowHeight | |
) | |
.onUpdate(-> | |
roundedElHeight = Math.round(this.elHeight) | |
me.windowHeight = oldHeight - currentHeight + roundedElHeight | |
me.window.resizeTo(me.windowWidth, me.windowHeight) | |
me.window.moveTo(x, me.getY()) | |
note.$el?.css({height: roundedElHeight}) | |
) | |
.onComplete(-> | |
me.window.setResizable(false) | |
note.dispose() | |
) | |
.start() | |
@animate tween | |
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 |
Revision 6 survived my stress testing :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Found out there's a lot of rendering glitches when a lot of notifications are added/removed at the same time. I implemented a queue so open/close animations don't conflict while trying to resize the window. It solved some problems but also created new ones.
It looks like the DOM's innerHeight takes a while to update, so to animate the window size i have to wait for it to change, which is ugly, and a pain in the ass :/.. Working on a solution, will update the gist if i find one.