Created
May 15, 2014 17:02
-
-
Save tstachl/2dbfd73db778686225e0 to your computer and use it in GitHub Desktop.
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
'use-strict' | |
Emitter = require 'emitter' | |
_ = require 'lodash' | |
binder = require 'binder' | |
module.exports = class DrawingTracker extends Emitter | |
constructor: (@_element, visible = no) -> | |
if typeof this._element == 'string' or this._element instanceof String | |
this._element = document.getElementById this._element | |
if not this._element.getContext | |
throw 'Error: no canvas.getContext' | |
this._context = this._element.getContext '2d' | |
unless this._context | |
throw 'Error: failed to getContext' | |
this._element.setAttribute 'height', innerHeight | |
this._element.setAttribute 'width', innerWidth | |
this._context.strokeStyle = '#ff0000' | |
this._context.lineWidth = 5 | |
this._context.lineCap = 'round' | |
this._started = no | |
this._visible = no | |
do this.show if visible | |
_.bindAll this, '_drawHandler' | |
_.bindAll this, '_eventHandler' | |
_.bindAll this, '_tapHandler' | |
_.bindAll this, '_clearHandler' | |
_.bindAll this, 'mousedown' | |
_.bindAll this, 'mousemove' | |
_.bindAll this, 'mouseup' | |
binder.on this._element, 'mousedown', this._eventHandler | |
binder.on this._element, 'mousemove', this._eventHandler | |
binder.on this._element, 'mouseup', this._eventHandler | |
binder.on this._element, 'touchstart', this._tapHandler | |
this.on 'draw', this._drawHandler | |
this.on 'clear', this._clearHandler | |
_clearHandler: -> | |
this._context.clearRect 0, 0, this._element.width, this._element.height | |
_tapHandler: (ev) -> | |
this.emit 'clear' | |
do this.hide | |
_drawHandler: (ev) -> | |
if this[ev.type] | |
this[ev.type] ev.position | |
_eventHandler: (ev) -> | |
this.emit 'draw', | |
type: ev.type | |
position: | |
x: ev.offsetX | |
y: ev.offsetY | |
show: -> | |
if not this._visible | |
this._element.style.display = 'block' | |
this._visible = yes | |
hide: -> | |
if this._visible | |
this._element.style.display = 'none' | |
this._visible = no | |
mousedown: (pos) -> | |
this._context.beginPath() | |
this._context.moveTo pos.x, pos.y | |
this._started = yes | |
mousemove: (pos) -> | |
if this._started | |
this._context.lineTo pos.x, pos.y | |
this._context.stroke() | |
mouseup: (pos) -> | |
if this._started | |
this.mousemove pos.x, pos.y | |
this._started = no |
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
'use-strict' | |
Emitter = require 'emitter' | |
module.exports = class History extends Emitter | |
history: [] | |
@stopEvent: (evt) -> | |
do evt.preventDefault | |
do evt.stopPropagation | |
sendAgent: (data, url) -> | |
url = url or this.history[this.history.length - 1] | |
data = data or $('html').html() | |
this.emit 'contentchange', data: data, url: url | |
perform: (data, url) -> | |
history.pushState null, null, url | |
this.history.push url | |
this.sendAgent data, url | |
$('#sos-content').html $(data).find('#sos-content').html() | |
scrollTo 0, 0 | |
do this.getSpinner().stop if this.getSpinner() | |
request: (method, args...) -> | |
do this.getSpinner().spin if this.getSpinner() | |
$[method].apply this, args | |
getSpinner: -> | |
this.sos = require './sos' unless this.sos | |
this.sos.spinner | |
constructor: -> | |
this.history.push location.href | |
self = this | |
$(document).on 'submit', 'form', (evt) -> | |
History.stopEvent evt | |
method = $(this).attr('method').toLowerCase() | |
data = $(this).serialize() | |
url = $(this).attr('action') | |
url += "?#{data}" if method == 'get' | |
if method == 'get' | |
self.request method, url, (data) -> self.perform data, this.url | |
else | |
self.request method, url, data, (data) -> self.perform data, this.url | |
$(document).on 'click', 'a', (evt) -> | |
if $(this).attr('href') != '#' | |
History.stopEvent evt | |
self.request 'get', $(this).attr('href'), (data) -> self.perform data, this.url | |
$(window).on 'popstate', (evt) -> | |
if self.history.length > 1 | |
History.stopEvent evt | |
[this_url, last_url] = [self.history.pop(), self.history.pop()] | |
self.request 'get', last_url, (data) -> self.perform data, this.url |
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
'use-strict' | |
Emitter = require 'emitter' | |
_ = require 'lodash' | |
binder = require 'binder' | |
module.exports = class ScrollTracker | |
constructor: (@_element = window) -> | |
this._emitter = new Emitter | |
_.bindAll this, '_scrollHandler' | |
_.bindAll this, 'set' | |
this._currentPosition = this._getPosition() | |
this._throttledHandler = _.throttle this._scrollHandler, 100 | |
this._isBound = no | |
getPosition: -> this._currentPosition | |
on: (evt, listener) -> | |
this._emitter.on evt, listener | |
do this._bind if evt == 'scroll' and not this._isBound | |
off: (evt, listener) -> | |
this.emitter.off evt, listener | |
do this._unbind if not this._emitter.hasListener('scroll') and this._isBound | |
set: (value) -> | |
do this._unbind | |
if this._element == window | |
this._element.scrollTo value.position.left, value.position.top | |
else | |
this._element.scrollTop = value.position.top | |
this._element.scrollLeft = value.position.left | |
do this._bind | |
_bind: -> | |
binder.on this._element, 'scroll', this._throttledHandler | |
this._isBound = yes | |
_unbind: -> | |
binder.off this._element, 'scroll', this._throttledHandler | |
this._isBound = no | |
_scrollHandler: -> | |
new_pos = this._getPosition() | |
old_pos = this.getPosition() | |
this._emitter.emit 'scroll', | |
direction: | |
up: new_pos.top < old_pos.top | |
down: new_pos.top > old_pos.top | |
left: new_pos.left < old_pos.left | |
right: new_pos.left > old_pos.left | |
position: new_pos | |
this._currentPosition = new_pos | |
_getPosition: -> | |
pos = top: 0, left: 0 | |
if this._element == window | |
pos.top = window.pageYOffset or window.documentElement?.scrollTop or 0 | |
pos.left = window.pageXOffset or window.documentElement?.scrollLeft or 0 | |
else | |
pos.top = this._element.scrollTop or 0 | |
pos.left = this._element.scrollLeft or 0 | |
pos |
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
'use-strict' | |
_ = require 'lodash' | |
ScrollTracker = require './scroll_tracker' | |
DrawingTracker = require './drawing_tracker' | |
History = require './history' | |
Spinner = require './spinner' | |
module.exports = class SOS | |
@history: new History | |
@spinner: new Spinner | |
@session: null | |
@create: (options = {}) -> | |
do SOS.spinner.spin unless options.spinner? | |
$('#sos-overlay').attr height: innerHeight, width: innerWidth | |
$('body').css 'overflow', 'hidden' if options.agent? | |
user = | |
user: displayName: options.name | |
rooms: [options.room] | |
goinstant.connect 'https://goinstant.net/5964eaab0092/DeskSOS', user, (err, connection, room) -> | |
if err | |
console.error 'Error connecting to GoInstant: ', err | |
return alert 'Error connecting to GoInstant.' | |
SOS.session = new SOS agent: options.agent?, room: room, name: options.name | |
@createRequest: (name) -> | |
do SOS.spinner.spin | |
body = | |
url: location.href | |
room: 'xxxxxxxxxxxx'.replace /[xy]/g, -> ((Date.now()+Math.random()*16)%16 | 0).toString(16) | |
$.get '/customer/portal/emails/new', (data) -> | |
form = $(data).find('#new_email') | |
form.find('#interaction_name').val "Lauren Boyle" | |
form.find('#interaction_email').val "[email protected]" | |
form.find('#email_subject').val "Session Requested" | |
form.find('#email_body').val JSON.stringify body | |
$.post form.attr('action'), form.serialize(), (data, status) -> | |
if status == 'success' | |
SOS.create | |
name: name or 'Lauren Boyle' | |
room: body.room | |
spinner: yes | |
else | |
alert "Coulnd't send SOS request!" | |
constructor: (options = {}) -> | |
self = this | |
this._isAgent = options.agent | |
this._room = options.room | |
this._name = options.name | |
this._started = no | |
this._scrollTracker = new ScrollTracker | |
this._drawingTracker = new DrawingTracker 'sos-overlay', this._isAgent | |
script = if options.agent then 'agent' else 'cordova' | |
script = "https://desk-customers.s3.amazonaws.com/zzz-sos/#{script}.js" | |
$.getScript script, -> | |
$.getJSON "https://opentokrtc.com/#{self._room.name}.json", (data) -> | |
if self._isAgent | |
self.agent data | |
else | |
self.customer data | |
destroy: -> | |
do $('#sos-video').hide | |
agent: (data) -> | |
do $('#sos-video').show | |
room = this._room | |
draw = this._drawingTracker | |
room.channel('scroll').on 'message', (value) => | |
this._scrollTracker.set value | |
room.channel('history').on 'message', (value) => | |
SOS.history.perform value.data, value.url | |
room.channel('events').on 'message', (value) -> | |
if value.value | |
$(value.selector).val value.value | |
else | |
$(value.selector).trigger value.event | |
room.channel('drawing').on 'message', (value) -> | |
draw.emit value.event, value.value | |
draw.on 'draw', (value) -> | |
room.channel('drawing').message | |
event: 'draw' | |
value: value | |
publish = TB.initPublisher data.apiKey, 'sos-video' | |
session = TB.initSession data.sid | |
session.on | |
streamCreated: (evt) -> | |
stream = evt.stream | |
stream = evt.streams[0] unless stream | |
session.subscribe stream, 'sos-fake', | |
subscribeToAudio: yes | |
subscribeToVideo: no | |
do SOS.spinner.stop | |
streamDestroyed: (evt) -> | |
do session.disconnect | |
do SOS.session.destroy | |
session.connect data.apiKey, data.token, -> | |
session.publish publish | |
customer: (data) -> | |
room = this._room | |
scroll = this._scrollTracker | |
draw = this._drawingTracker | |
scroll.on 'scroll', (pos) -> | |
room.channel('scroll').message pos | |
SOS.history.on 'contentchange', (args) -> | |
room.channel('history').message args | |
draw.on 'clear', -> | |
room.channel('drawing').message | |
event: 'clear' | |
room.channel('drawing').on 'message', (value) -> | |
do draw.show | |
draw.emit value.event, value.value | |
$(document).on 'click', '.toggle', -> | |
room.channel('events').message | |
selector: '.toggle' | |
event: 'click' | |
$(document).on 'keyup', 'input[name="q"]', -> | |
room.channel('events').message | |
selector: 'input[name="q"]' | |
value: $(this).val() | |
publish = TB.initPublisher data.apiKey, 'sos-fake', | |
publishAudio: yes | |
publishVideo: no | |
width: 1 | |
height: 1 | |
session = TB.initSession data.apiKey, data.sid | |
session.on | |
streamCreated: (evt) -> | |
do $('#sos-video').show | |
session.subscribe evt.stream, 'sos-video', | |
subscribeToAudio: yes | |
subscribeToVideo: yes | |
do SOS.spinner.stop | |
do $('#sos-fake').remove | |
do SOS.history.sendAgent | |
room.channel('scroll').message scroll.getPosition() | |
streamDestroyed: (evt) -> | |
do session.disconnect | |
do SOS.session.destroy | |
session.connect data.token, -> | |
session.publish publish |
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
S = require 'spin' | |
module.exports = class Spinner extends S | |
constructor: -> | |
this.target = $('<div class="sos-spin">').appendTo(document.body).hide() | |
super | |
lines: 13 | |
length: 20 | |
width: 10 | |
radius: 30 | |
corners: 1 | |
rotate: 0 | |
direction: 1 | |
color: '#FFF' | |
speed: 1 | |
trail: 60 | |
shadow: false | |
hwaccel: false | |
className: 'spinner' | |
zIndex: 2e9 | |
top: '50%' | |
left: '50%' | |
spin: -> | |
super this.target.get 0 | |
do this.target.show | |
stop: -> | |
super | |
do this.target.hide |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment