vines 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,48 @@
1
+ class Filter
2
+ constructor: (options) ->
3
+ @list = options.list
4
+ @icon = options.icon
5
+ @form = options.form
6
+ @attrs = options.attrs
7
+ @open = options.open
8
+ @close = options.close
9
+ this.draw()
10
+
11
+ draw: ->
12
+ $(@icon).addClass 'filter-button'
13
+ form = $('<form class="filter-form" style="display:none;"></form>').appendTo @form
14
+ text = $('<input class="filter-text" type="search" placeholder="Filter" results="5"/>').appendTo form
15
+
16
+ new Button @icon, ICONS.search,
17
+ scale: 0.5
18
+ translation: '-8 -8'
19
+
20
+ form.submit -> false
21
+ text.keyup => this.filter(text)
22
+ text.change => this.filter(text)
23
+ text.click => this.filter(text)
24
+ $(@icon).click =>
25
+ if form.is ':hidden'
26
+ this.filter(text)
27
+ form.show()
28
+ this.open() if this.open
29
+ else
30
+ form.hide()
31
+ form[0].reset()
32
+ this.filter(text)
33
+ this.close() if this.close
34
+
35
+ filter: (input) ->
36
+ text = input.val().toLowerCase()
37
+ if text == ''
38
+ $('li', @list).show()
39
+ return
40
+
41
+ test = (node, attr) ->
42
+ val = (node.attr(attr) || '').toLowerCase()
43
+ val.indexOf(text) != -1
44
+
45
+ $('li', @list).each (ix, node) =>
46
+ node = $ node
47
+ matches = (true for attr in @attrs when test node, attr)
48
+ if matches.length > 0 then node.show() else node.hide()
@@ -20,7 +20,7 @@ class Session
20
20
  callback true
21
21
  this.findRoster =>
22
22
  this.notify('roster')
23
- @xmpp.send $pres().tree()
23
+ @xmpp.send $('<presence/>').get 0
24
24
  this.findCards()
25
25
 
26
26
  disconnect: -> @xmpp.disconnect()
@@ -44,6 +44,8 @@ class Session
44
44
 
45
45
  bareJid: -> @xmpp.jid.split('/')[0]
46
46
 
47
+ uniqueId: -> @xmpp.getUniqueId()
48
+
47
49
  avatar: (jid) ->
48
50
  card = this.loadCard(jid)
49
51
  if card && card.photo
@@ -73,8 +75,12 @@ class Session
73
75
 
74
76
  findCard: (jid, callback) ->
75
77
  return unless jid
76
-
77
- handler = (result) ->
78
+ node = this.xml """
79
+ <iq id="#{this.uniqueId()}" to="#{jid}" type="get">
80
+ <vCard xmlns="vcard-temp"/>
81
+ </iq>
82
+ """
83
+ this.sendIQ node, (result) ->
78
84
  card = $('vCard', result)
79
85
  photo = $('PHOTO', card)
80
86
  type = $('TYPE', photo).text()
@@ -86,74 +92,81 @@ class Session
86
92
  vcard = jid: jid, photo: photo, retrieved: new Date()
87
93
  callback if card.size() > 0 then vcard else null
88
94
 
89
- iq = $iq(type: 'get', to: jid, id: @xmpp.getUniqueId())
90
- .c('vCard', xmlns: 'vcard-temp').up()
91
-
92
- @xmpp.sendIQ iq, handler, handler, 5000
93
-
94
95
  parseRoster: (node) ->
95
96
  $('item', node).map(-> new Contact this ).get()
96
97
 
97
98
  findRoster: (callback) ->
98
- handler = (result) =>
99
+ node = $("""
100
+ <iq id='#{this.uniqueId()}' type="get">
101
+ <query xmlns="jabber:iq:roster"/>
102
+ </iq>
103
+ """)
104
+ this.sendIQ node.get(0), (result) =>
99
105
  contacts = this.parseRoster(result)
100
106
  @roster[contact.jid] = contact for contact in contacts
101
107
  callback()
102
108
 
103
- iq = $iq(type: 'get', id: @xmpp.getUniqueId())
104
- .c('query', xmlns: 'jabber:iq:roster').up()
105
-
106
- @xmpp.sendIQ iq, handler, handler, 5000
107
-
108
109
  sendMessage: (jid, message) ->
109
- stanza = $msg(to: jid, from: @xmpp.jid, type: 'chat')
110
- .c('body').t(message).up()
111
- @xmpp.send stanza.tree()
110
+ node = this.xml """
111
+ <message id="#{this.uniqueId()}" to="#{jid}" type="chat">
112
+ <body></body>
113
+ </message>
114
+ """
115
+ $('body', node).text message
116
+ @xmpp.send node
112
117
 
113
118
  sendPresence: (away, status) ->
114
- stanza = $pres()
119
+ node = $ '<presence/>'
115
120
  if away
116
- stanza.c('show').t('xa').up()
117
- stanza.c('status').t status if status != 'Away'
121
+ node.append $('<show>xa</show>')
122
+ node.append $('<status/>').text status if status != 'Away'
118
123
  else
119
- stanza.c('status').t status if status != 'Available'
120
- @xmpp.send stanza.tree()
124
+ node.append $('<status/>').text status if status != 'Available'
125
+ @xmpp.send node.get 0
126
+
127
+ sendIQ: (node, callback) ->
128
+ @xmpp.sendIQ node, callback, callback, 5000
121
129
 
122
130
  updateContact: (contact, add) ->
123
- iq = $iq(type: 'set', id: @xmpp.getUniqueId())
124
- .c('query', xmlns: 'jabber:iq:roster')
125
- .c('item', jid: contact.jid, name: contact.name)
126
- iq.c('group', group).up() for group in contact.groups
127
- @xmpp.send iq.up().tree()
128
- @xmpp.send $pres(type: 'subscribe', to: contact.jid).tree() if add
131
+ node = $("""
132
+ <iq id="#{this.uniqueId()}" type="set">
133
+ <query xmlns="jabber:iq:roster">
134
+ <item name="" jid="#{contact.jid}"/>
135
+ </query>
136
+ </iq>
137
+ """)
138
+ $('item', node).attr 'name', contact.name
139
+ for group in contact.groups
140
+ $('item', node).append $('<group></group>').text group
141
+ @xmpp.send node.get 0
142
+ this.sendSubscribe(contact.jid) if add
129
143
 
130
144
  removeContact: (jid) ->
131
- iq = $iq(type: 'set', id: @xmpp.getUniqueId())
132
- .c('query', xmlns: 'jabber:iq:roster')
133
- .c('item', jid: jid, subscription: 'remove')
134
- .up().up()
135
- @xmpp.send iq.tree()
145
+ node = $("""
146
+ <iq id="#{this.uniqueId()}" type="set">
147
+ <query xmlns="jabber:iq:roster">
148
+ <item jid="#{jid}" subscription="remove"/>
149
+ </query>
150
+ </iq>
151
+ """)
152
+ @xmpp.send node.get 0
136
153
 
137
154
  sendSubscribe: (jid) ->
138
- @xmpp.send $pres(
139
- type: 'subscribe'
140
- to: jid
141
- id: @xmpp.getUniqueId()
142
- ).tree()
155
+ @xmpp.send this.presence jid, 'subscribe'
143
156
 
144
157
  sendSubscribed: (jid) ->
145
- @xmpp.send $pres(
146
- type: 'subscribed'
147
- to: jid
148
- id: @xmpp.getUniqueId()
149
- ).tree()
158
+ @xmpp.send this.presence jid, 'subscribed'
150
159
 
151
160
  sendUnsubscribed: (jid) ->
152
- @xmpp.send $pres(
153
- type: 'unsubscribed'
154
- to: jid
155
- id: @xmpp.getUniqueId()
156
- ).tree()
161
+ @xmpp.send this.presence jid, 'unsubscribed'
162
+
163
+ presence: (to, type) ->
164
+ $("""
165
+ <presence
166
+ id="#{this.uniqueId()}"
167
+ to="#{to}"
168
+ type="#{type}"/>
169
+ """).get 0
157
170
 
158
171
  handleIq: (node) ->
159
172
  node = $(node)
@@ -209,3 +222,5 @@ class Session
209
222
 
210
223
  notify: (type, obj) ->
211
224
  callback(obj) for callback in (@listeners[type] || [])
225
+
226
+ xml: (xml) -> $.parseXML(xml).documentElement
@@ -0,0 +1,103 @@
1
+ class Transfer
2
+ constructor: (options) ->
3
+ @session = options.session
4
+ @file = options.file
5
+ @to = options.to
6
+ @progress = options.progress
7
+ @complete = options.complete
8
+ @chunks = new Chunks(@file)
9
+ @opened = false
10
+ @closed = false
11
+ @sid = @session.uniqueId()
12
+ @seq = 0
13
+ @sent = 0
14
+
15
+ start: ->
16
+ node = $("""
17
+ <iq id="#{@session.uniqueId()}" to="#{@to}" type="set">
18
+ <si xmlns="http://jabber.org/protocol/si" id="#{@session.uniqueId()}" profile="http://jabber.org/protocol/si/profile/file-transfer">
19
+ <file xmlns="http://jabber.org/protocol/si/profile/file-transfer" name="" size="#{@file.size}"/>
20
+ <feature xmlns="http://jabber.org/protocol/feature-neg">
21
+ <x xmlns="jabber:x:data" type="form">
22
+ <field var="stream-method" type="list-single">
23
+ <option><value>http://jabber.org/protocol/ibb</value></option>
24
+ </field>
25
+ </x>
26
+ </feature>
27
+ </si>
28
+ </iq>
29
+ """)
30
+ $('file', node).attr 'name', @file.name
31
+
32
+ callback = (result) =>
33
+ methods = $('si feature x field[var="stream-method"] value', result)
34
+ ok = (true for m in methods when $(m).text() == 'http://jabber.org/protocol/ibb').length > 0
35
+ this.open() if ok
36
+
37
+ @session.sendIQ node.get(0), callback
38
+
39
+ open: ->
40
+ node = $("""
41
+ <iq id="#{@session.uniqueId()}" to="#{@to}" type="set">
42
+ <open xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}" block-size="4096"/>
43
+ </iq>
44
+ """)
45
+ callback = (result) =>
46
+ if this.ok result
47
+ @opened = true
48
+ @chunks.start => this.sendChunk()
49
+ @session.sendIQ node.get(0), callback
50
+
51
+ sendChunk: ->
52
+ return if @closed
53
+ unless chunk = @chunks.chunk()
54
+ this.close()
55
+ return
56
+
57
+ node = $("""
58
+ <iq id="#{@session.uniqueId()}" to="#{@to}" type="set">
59
+ <data xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}" seq="#{@seq++}">#{chunk}</data>
60
+ </iq>
61
+ """)
62
+ @seq = 0 if @seq > 65535
63
+ callback = (result) =>
64
+ return unless this.ok result
65
+ pct = Math.ceil ++@sent / @chunks.total * 100
66
+ this.progress pct
67
+ this.sendChunk()
68
+ @session.sendIQ node.get(0), callback
69
+
70
+ close: ->
71
+ return if @closed
72
+ @closed = true
73
+ node = $("""
74
+ <iq id="#{@session.uniqueId()}" to="#{@to}" type="set">
75
+ <close xmlns="http://jabber.org/protocol/ibb" sid="#{@sid}"/>
76
+ </iq>
77
+ """)
78
+ @session.sendIQ node.get(0), ->
79
+ this.complete()
80
+
81
+ stop: ->
82
+ if @opened
83
+ this.close()
84
+ else
85
+ this.complete()
86
+
87
+ ok: (result) -> $(result).attr('type') == 'result'
88
+
89
+ class Chunks
90
+ constructor: (@file) ->
91
+ @chunks = []
92
+ @total = 0
93
+
94
+ chunk: -> @chunks.shift()
95
+
96
+ start: (callback) ->
97
+ reader = new FileReader()
98
+ reader.onload = (event) =>
99
+ data = btoa event.target.result
100
+ @chunks = (chunk for chunk in data.split /(.{1,4096})/ when chunk)
101
+ @total = @chunks.length
102
+ callback()
103
+ reader.readAsBinaryString @file