Comparar commits
387 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 49ecac9f7b | |||
| 736119b375 | |||
| d8733e73d3 | |||
| 7f73c45af0 | |||
| f8c4bf1d3b | |||
| 3c5ff959e5 | |||
| 49cf0eebca | |||
| 4efa02e4ae | |||
| 3b51e7d7a5 | |||
| c46e9fc534 | |||
| 03e423f439 | |||
| 2f432667e9 | |||
| 087e5c819c | |||
| fab9257282 | |||
| 3feb97b119 | |||
| 25667db4be | |||
| c8bf94971b | |||
| 4ce384d9b1 | |||
| fc586cff7e | |||
| adb4afc8f5 | |||
| 7888f5ed09 | |||
| b50933b263 | |||
| d203f633f2 | |||
| 22b7b71204 | |||
| a48f7e6992 | |||
| ec33ace031 | |||
| a428903a00 | |||
| 6bb5a152d7 | |||
| b49d898c9c | |||
| e45aa6ccec | |||
| e16ab27416 | |||
| 3ba25a08f6 | |||
| 87b3b1db32 | |||
| 3343044e95 | |||
| 835fa8227c | |||
| 82a28d6aba | |||
| 7c3e4119dd | |||
| 20e9f108e8 | |||
| dad49f59fb | |||
| 455484e524 | |||
| e70904b99d | |||
| fef58dee3b | |||
| 995505fc43 | |||
| c10c9453e9 | |||
| ae23b508da | |||
| aedb263d2b | |||
| 6a93988d15 | |||
| 6fc12af3d9 | |||
| d7daff286b | |||
| d8623963fe | |||
| e8da8085a1 | |||
| 04e85ee881 | |||
| efcff4f0be | |||
| ed19a6a323 | |||
| 54a65ca132 | |||
| 1c10198bb9 | |||
| f02eea99dd | |||
| e8a6b664c1 | |||
| 597c6e6346 | |||
| d4d8c335e7 | |||
| 6b2b5991fc | |||
| 869c3d1fc0 | |||
| fc1b2f4641 | |||
| 72a67f034a | |||
| ce344f6bba | |||
| c3f1ff141c | |||
| a3eee043b3 | |||
| 0c5f405503 | |||
| 499804d53b | |||
| 49a6782244 | |||
| 2c9efba0bd | |||
| b73aeafb5c | |||
| 616085d2a5 | |||
| 42c7939474 | |||
| 3538a0ad62 | |||
| 6925034cf3 | |||
| 50d5356ee4 | |||
| c242f05afe | |||
| 3b23f20268 | |||
| 3fba657d40 | |||
| 3c1ef25e2c | |||
| 569ab66016 | |||
| 84aab421a0 | |||
| 86ad16ef4b | |||
| 2fe742f169 | |||
| d7e32cc638 | |||
| 63e271e5e4 | |||
| ee93f36a4c | |||
| bdd4236d1a | |||
| c2c35b303a | |||
| b9ef5b1a69 | |||
| 3e0c752a13 | |||
| cafbd71c74 | |||
| 423cea6d41 | |||
| 850febf328 | |||
| 5d1719b92e | |||
| d998e4cacb | |||
| eda9ab60de | |||
| 13a02fa692 | |||
| 36c0727828 | |||
| e1ffa79236 | |||
| e33e3b4853 | |||
| 62eacdc5ff | |||
| 40b5ff344b | |||
| d8ae158d24 | |||
| 5fdb292690 | |||
| a0a116901d | |||
| 5a34a0fd2e | |||
| 5435326fb9 | |||
| ff453821bf | |||
| 03ac47a264 | |||
| a17f046a92 | |||
| 1b0db86edf | |||
| 77863d7a27 | |||
| 03435fce9c | |||
| f9598604e2 | |||
| edd715b993 | |||
| a8b777e5b7 | |||
| 3282285b3c | |||
| 564aa7cd8a | |||
| 81047222c6 | |||
| 329f55978f | |||
| 01b14279b3 | |||
| 630bb45eb1 | |||
| 779103ed32 | |||
| fbd0511a76 | |||
| da0a7d7b5d | |||
| da020726ec | |||
| 79f05a0799 | |||
| 2d832d1752 | |||
| 550485c07c | |||
| 3566972527 | |||
| ca21753d73 | |||
| 70abb7121c | |||
| 4e9c802da9 | |||
| 651c138b97 | |||
| 318bd7ee7d | |||
| 7929b20516 | |||
| 20c8d0e2f6 | |||
| 3628cd751a | |||
| 996ae30df8 | |||
| 7b32d598e4 | |||
| 5edf4c2368 | |||
| 9bec4084d8 | |||
| 700e62c9d4 | |||
| 9fa16fca40 | |||
| 5f0b2c8a35 | |||
| f41faaf9af | |||
| 3dd2b14e5a | |||
| 3d2fa05b1f | |||
| f8888fdbb2 | |||
| 8e5e90032c | |||
| 86df085723 | |||
| b57ab86b8f | |||
| 79c1a76427 | |||
| 7acca71a45 | |||
| 925ff098d0 | |||
| 4edcc578aa | |||
| 153f045b00 | |||
| ba03261f1e | |||
| 50fe563e1a | |||
| 31c9b29521 | |||
| b1ce729ec9 | |||
| ffc3678cb9 | |||
| 5772868738 | |||
| 4529f71896 | |||
| 8b53842bcd | |||
| 5c2bc52b55 | |||
| e704f4d05a | |||
| fa3febf0b6 | |||
| 2814cfb36e | |||
| 8aa2736e4a | |||
| a2b216443a | |||
| 487e32a7b9 | |||
| 2950c747c9 | |||
| f39cc79dff | |||
| b62eb995d8 | |||
| e45aa41ae8 | |||
| ee1d70a1db | |||
| 66b5ebda32 | |||
| 08beae250b | |||
| 3de204d857 | |||
| a2fe0b9383 | |||
| e655247a01 | |||
| 27eefde3b3 | |||
| 708648e414 | |||
| 6e9fcf2518 | |||
| d7316e895a | |||
| 01c34f46dd | |||
| 65305f3609 | |||
| 2cd5b5764a | |||
| a52fe9884b | |||
| c95e117857 | |||
| 5f2d4ce7a6 | |||
| d988621b4d | |||
| 9d40ed8086 | |||
| 9750a558f2 | |||
| feb0c634a4 | |||
| 89c6e28970 | |||
| 5224cdf30c | |||
| c85ef77c21 | |||
| cebcc61496 | |||
| 7cf71a7c8b | |||
| 4bffcd665c | |||
| 4fb9938049 | |||
| 419eb17f65 | |||
| 20cc517457 | |||
| a30bcffeec | |||
| e1f4d1d811 | |||
| dea3a30149 | |||
| 2c2e13d966 | |||
| 65c0b7a57a | |||
| 2b6dd690f4 | |||
| 292e7646b6 | |||
| 9c137be6ae | |||
| c711167d3f | |||
| 4c388212eb | |||
| b843aa2f03 | |||
| 8d1fba000a | |||
| e9f0634d29 | |||
| a69b70af1e | |||
| 341db9e625 | |||
| 67d2c12640 | |||
| c0fae24dcd | |||
| 05d9aaa01d | |||
| 8cd97ec3e1 | |||
| 58e2fccf95 | |||
| 4b541d462a | |||
| 310ac4e0a6 | |||
| 53b44961ea | |||
| 8271e64cf7 | |||
| 27438984e1 | |||
| 0fb7de74ce | |||
| 3db02b0560 | |||
| e2dfb6bc94 | |||
| 55dbbdb636 | |||
| 308ccc1426 | |||
| 7f1a011b1b | |||
| d102d41f6b | |||
| 91def2febc | |||
| 7ea444276b | |||
| f810a8a28f | |||
| 2acf47a872 | |||
| 906136245a | |||
| a053753e10 | |||
| e996296b7f | |||
| d4a31dc8fc | |||
| c8ca2734e0 | |||
| 03e8ae8d1d | |||
| d626eb355f | |||
| 862c124366 | |||
| 3c2cf893be | |||
| ac8f014377 | |||
| d0e16c0a2a | |||
| cb926a1dec | |||
| 7aac1d6c28 | |||
| 25a982f9c3 | |||
| 76da9c0fd1 | |||
| a9d167acda | |||
| 32960f39b0 | |||
| 3e1c1ded67 | |||
| e19da058f6 | |||
| 80b5a4a350 | |||
| 5c10a738cb | |||
| 855b776ca2 | |||
| 735016e676 | |||
| 46897f0e66 | |||
| f1918e06cb | |||
| 3405d0e3c2 | |||
| c280251e3c | |||
| 0954c245c3 | |||
| 1aa44434b3 | |||
| c1bd08b3e4 | |||
| f298364a37 | |||
| e061670880 | |||
| 6680283cea | |||
| cb6b1345e0 | |||
| 09a83236ab | |||
| a68bae3288 | |||
| a7f4073f0b | |||
| 8248854ce7 | |||
| 88f225f564 | |||
| 8c1ba13449 | |||
| eb7cef099b | |||
| 8ae8d2f7bf | |||
| 33d41e2a84 | |||
| ca816760c8 | |||
| 31d6121273 | |||
| 8bc299739d | |||
| 263cb2ecb7 | |||
| c7e37147a7 | |||
| 34c880aa5c | |||
| 165dba73a4 | |||
| f2770d7a44 | |||
| b7c4cac550 | |||
| 656a82cf17 | |||
| 3d4ece2561 | |||
| 52b16e9ef0 | |||
| a07347cc22 | |||
| aa8bcf52de | |||
| 2060b8ac69 | |||
| 8776ad565d | |||
| 2e94cf6ba0 | |||
| 89bd4cdc48 | |||
| 9d87d90141 | |||
| b6e4a6baca | |||
| 4dc319502f | |||
| 98e9f77074 | |||
| 37ac46f55b | |||
| 92309b90be | |||
| dc1a79e294 | |||
| 5813f336a2 | |||
| 46116a3e8d | |||
| cfc9d5a77d | |||
| 08c660a1ae | |||
| 2140f8ad72 | |||
| de2eb4c7ba | |||
| 075f29b040 | |||
| 2ceb2ab3a6 | |||
| 21153db52d | |||
| 45ed711ad8 | |||
| bdf8ead441 | |||
| 73116b0b33 | |||
| 995133c4d2 | |||
| 4d396d4133 | |||
| de1c264c2b | |||
| c6e050ab7c | |||
| 97555780c5 | |||
| 14338ededa | |||
| e7b087e8fe | |||
| 94f49dabef | |||
| c0cd443a3d | |||
| 2f023cda05 | |||
| 03ca06ce25 | |||
| f8e40a8d30 | |||
| 49962a5abb | |||
| e2cff91acb | |||
| a9c614b598 | |||
| 5b4d89ea71 | |||
| 8d8cf2fce3 | |||
| 8b248c4258 | |||
| 9122e85f6b | |||
| ed0824a124 | |||
| 16460a4aad | |||
| 38e0a19ab3 | |||
| 0925221119 | |||
| 0bc774d01a | |||
| 89b0239974 | |||
| 5e371cc614 | |||
| 294ece30b3 | |||
| 547fb83ca4 | |||
| 315f9ec625 | |||
| 474412c44c | |||
| f43111524f | |||
| 22fb57008b | |||
| a822554a12 | |||
| d290317239 | |||
| d6da5c217e | |||
| 26af2b97c4 | |||
| 47ec163d10 | |||
| 9871b696ee | |||
| 9eb372e155 | |||
| 01691684b1 | |||
| 2f4d3aea65 | |||
| f1d622897f | |||
| a845a1b9a0 | |||
| f6c03beb27 | |||
| ee59715b18 | |||
| fc1970d3bc | |||
| a3d831af9c | |||
| ae0c381dec | |||
| 0a117a20fb | |||
| 27a9c25584 | |||
| fd3fdcd8f2 | |||
| 8387176029 | |||
| 9bccf83565 | |||
| d3812e3a15 | |||
| 8cc2a0e6a4 | |||
| d2dea6d67c | |||
| e627a7e51b | |||
| 07f2389b4e | |||
| fdd0768f38 | |||
| e1e366ac55 | |||
| 671f874797 | |||
| 3d2753aea1 | |||
| 59ab53a553 | |||
| 1ddcef660c |
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"directory": "lib/",
|
||||
"analytics": false
|
||||
}
|
||||
@@ -1 +1,13 @@
|
||||
node_modules
|
||||
*.zip
|
||||
*.zip.sig
|
||||
bower_components
|
||||
archives/
|
||||
/css/
|
||||
dev/
|
||||
.wti
|
||||
*~
|
||||
/tmp/
|
||||
lib/favico.js/
|
||||
lib/strophe.bookmarks/
|
||||
lib/strophe.x/
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
[submodule "lib/strophe.jingle"]
|
||||
path = lib/strophe.jingle
|
||||
url = https://github.com/ESTOS/strophe.jingle.git
|
||||
[submodule "lib/otr"]
|
||||
path = lib/otr
|
||||
url = https://github.com/arlolra/otr.git
|
||||
url = https://github.com/sualko/otr.git
|
||||
[submodule "lib/i18next"]
|
||||
path = lib/i18next
|
||||
url = https://github.com/i18next/i18next.git
|
||||
[submodule "lib/bootstrap"]
|
||||
path = lib/bootstrap
|
||||
url = https://github.com/twbs/bootstrap-sass/
|
||||
[submodule "lib/magnific-popup"]
|
||||
path = lib/magnific-popup
|
||||
url = https://github.com/dimsemenov/Magnific-Popup
|
||||
[submodule "lib/strophe.jinglejs"]
|
||||
path = lib/strophe.jinglejs
|
||||
url = https://github.com/sualko/strophe.jinglejs
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"indent_size": 3,
|
||||
"indent_char": " ",
|
||||
"end_with_newline": true
|
||||
}
|
||||
@@ -14,11 +14,15 @@
|
||||
"multistr": true,
|
||||
"devel": true,
|
||||
"globals": {
|
||||
"t":true,
|
||||
"i18n":true,
|
||||
"I18next":true,
|
||||
"OTR":true,
|
||||
"DSA":true,
|
||||
"Worker":true,
|
||||
"BigInt":true,
|
||||
"Notification":true,
|
||||
"$": true,
|
||||
"jQuery":true,
|
||||
"Strophe":true,
|
||||
"localStorage":true,
|
||||
@@ -29,6 +33,7 @@
|
||||
"jsxc":true,
|
||||
"getUserMediaWithConstraints":true,
|
||||
"setupRTC":true,
|
||||
"SDPUtil":true
|
||||
"SDPUtil":true,
|
||||
"getSelection":true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,219 @@
|
||||
v0.6.0 / 2014-01-28
|
||||
v2.1.3 / 2015-09-08
|
||||
===
|
||||
- fix bookmark loading
|
||||
- show unread notifications only if the chat window has no focus
|
||||
|
||||
v2.1.2 / 2015-08-12
|
||||
===
|
||||
- update grunt-sass (fix invalid css)
|
||||
|
||||
v2.1.1 / 2015-08-10
|
||||
===
|
||||
- update strophe.jingle (fix login with safari and older versions of ie, ff, chrome)
|
||||
- update favico.js
|
||||
- fix undefined error variable in ie
|
||||
- fix handling of escaped jids (e.g. used in transports)
|
||||
- fix placeholder replacement
|
||||
- rearrange bootstrap import
|
||||
- add option for custom online user manual
|
||||
|
||||
v2.1.0 / 2015-07-31
|
||||
===
|
||||
- add bookmark feature for rooms (XEP-0048)
|
||||
- add reserved room feature for muc (XEP-0045#10.1.3)
|
||||
- add counter of unread messages to roster, window and favicon
|
||||
- add join as URI query type
|
||||
- add ru language
|
||||
- add roster resize hint
|
||||
- make dialog responsive
|
||||
- allow messages to persons without valid friendship
|
||||
- replace video library for more stable connection
|
||||
- fix dsa key generation in chrome > 42
|
||||
- fix minor roster ui issues
|
||||
|
||||
- add jsbeautifier and prettysass
|
||||
- improve example
|
||||
- extract templates to single files
|
||||
- replace colorbox with magnific popup
|
||||
- use parts of bootstrap
|
||||
- replace strophe.jingle with strophe.jinglejs (jingle.js)
|
||||
- concatenate strings for better translatability
|
||||
- add new option attach if login form was found
|
||||
- add new option loginForm.startMinimized
|
||||
- add new option loginForm.enable (deprecates xmpp.onlogin)
|
||||
- add new option RTCPeerConfig.url (deprecates turnCredentialsPath)
|
||||
- ICE servers can now be passed as init option
|
||||
- loadSettings option is no longer required and supports now async requests
|
||||
|
||||
v2.0.1 / 2015-05-23
|
||||
===
|
||||
- improve login box
|
||||
- fix browsers without CSPRNG generator
|
||||
- fix ajax login after credential failure
|
||||
- fix some webrtc issues
|
||||
- fix login with different username after dirty logout
|
||||
- remove ie (<11) gradient
|
||||
- remove broken mitm detection
|
||||
- fix temporary template 404
|
||||
- fix login option
|
||||
- add connecting event
|
||||
|
||||
v2.0.0 / 2015-05-08
|
||||
===
|
||||
- add multi-user chat (XEP-0045)
|
||||
- add window resize handle
|
||||
- add username autocomplete
|
||||
- add offline state
|
||||
- add Italian, French, Polish, Portuguese/Brazil
|
||||
- use user avatar as notification icon
|
||||
- show notifications if tabs has no focus
|
||||
- split files into namespaces
|
||||
- sass improvements
|
||||
- replace own translation engine with i18next
|
||||
- fix login from login box
|
||||
- fix selection of chat messages
|
||||
- fix video calls
|
||||
- fix emoticons
|
||||
- fix duplicated roster items
|
||||
- fix notification request
|
||||
- fix logout
|
||||
|
||||
v1.1.0a / 2015-02-25
|
||||
===
|
||||
- fix css url path
|
||||
|
||||
v1.1.0 / 2015-01-08
|
||||
===
|
||||
- move from plain css to sass
|
||||
- show avatar also by EXTVAL (url), not only by BINVAL
|
||||
- add XEP-0280 (Message Carbons)
|
||||
- add XEP-0297 (Stanza Forwarding)
|
||||
- add option to disable otr
|
||||
- add timestamp to messages
|
||||
- add ajax/prebind login
|
||||
- fix offline subscription request
|
||||
- fix hide offline contacts
|
||||
- fix error with multiple own resources
|
||||
- fix avatars with newlines
|
||||
|
||||
v1.0.0 / 2014-11-06
|
||||
===
|
||||
- add unread flag to roster and scroll to target window
|
||||
- add XEP-0147 URI Scheme Query support
|
||||
- add has-come-online notification
|
||||
- add silent notification request
|
||||
- add more information in vCard view
|
||||
- add resizable function to chat window
|
||||
- add vertical scrollbar to window list
|
||||
- add call information to chat window
|
||||
- add concatinated and uglified files
|
||||
- add translations
|
||||
- minor video call improvements
|
||||
- minor style improvements
|
||||
- generate dsa key complete in background
|
||||
- update caps node property to jsxc.org
|
||||
- update strophe.jingle
|
||||
- update otr
|
||||
- fix wrong avatars
|
||||
- fix minor message delivery errors
|
||||
- fix ff snapshot security error
|
||||
- fix case sensitive resource handling
|
||||
- fix non-square avatars
|
||||
- fix several video issues
|
||||
- fix messages from unknown (not in roster) jid
|
||||
- fix vcard retrieval from unknown (not in roster) jid
|
||||
- fix vcard in second tab
|
||||
- fix jids with non-word characters (replace user identifier)
|
||||
- improve video window design
|
||||
- improve user info
|
||||
- improve login box
|
||||
- improve smp user interaction
|
||||
- improve notifications (sync sound/message, icon)
|
||||
- minor chat window improvements
|
||||
- detect email in message
|
||||
- detect uri scheme in message
|
||||
- end all private conversations on logout
|
||||
- remove email pattern from contact dialog
|
||||
- disable video on second tab
|
||||
- add/require disco dtls feature for webrtc
|
||||
- move emoticons to css
|
||||
- handle loadSettings failure
|
||||
- change cursor for some elements
|
||||
- prevent event bubbling for dialog
|
||||
|
||||
v0.8.2 / 2014-08-20
|
||||
===
|
||||
- fix use of custom username
|
||||
- write to console only if debug flag is set
|
||||
- allow string|boolean as config param
|
||||
- add translations
|
||||
|
||||
v0.8.1 / 2014-08-12
|
||||
===
|
||||
- add user-defined xmpp options
|
||||
- fix login form without id submit
|
||||
|
||||
v0.8.0 / 2014-07-02
|
||||
===
|
||||
- add spanish translation
|
||||
- add vCard view
|
||||
- add more emoticons
|
||||
- add grayscale to buddies without subscription
|
||||
- add settings for priorities
|
||||
- add hint if roster is empty
|
||||
- add sound files
|
||||
- new chat window design
|
||||
- enhanced roster design
|
||||
- fix emoticon replacement (XEP-0038)
|
||||
- fix some ui issues (explanations,...)
|
||||
- fix issue with password only field
|
||||
|
||||
v0.7.2 / 2014-05-28
|
||||
===
|
||||
- fix login issue
|
||||
- fix different dialogs
|
||||
- fix safari mobile bug
|
||||
- fix webworker debugging
|
||||
- fix issue with prosody
|
||||
- fix submodule state
|
||||
- add debug flag
|
||||
- add icon for video calls
|
||||
- add general stylesheet + vector images
|
||||
- add multiple translations
|
||||
- add link to online help
|
||||
- handle webworker security error
|
||||
- remove outline glow
|
||||
- reduce tooltip delay
|
||||
- remove already confirmed friendship request from notice stack
|
||||
- minor style fixes
|
||||
- move complete to new notification api
|
||||
|
||||
|
||||
v0.7.1 / 2014-03-18
|
||||
===
|
||||
- fix emoticons
|
||||
- fix unique message id
|
||||
|
||||
v0.7.0 / 2014-03-07
|
||||
===
|
||||
- add sound notifications
|
||||
- add support for custom default avatars
|
||||
- add support for XEP-0184 (Message Delivery Receipts)
|
||||
- update & extend hover info
|
||||
- handle presence of type unsubscribed
|
||||
- remove roster footer if offline
|
||||
- enhance otr error handling
|
||||
- enhance translations
|
||||
- reduce initial timeout
|
||||
- fix notices
|
||||
- fix friendship response dialog
|
||||
- fix shared roster item removel
|
||||
- fix debug function
|
||||
- fix webrtc bug
|
||||
- fix storage check
|
||||
- fix firefox fullscreen
|
||||
|
||||
v0.6.0 / 2014-02-28
|
||||
===
|
||||
- add notice stack (for e.g. friendship requests)
|
||||
- add option to change presence
|
||||
@@ -24,4 +239,4 @@ v0.5.1 / 2014-01-27
|
||||
- handle already attached submit events on login form
|
||||
- style changes
|
||||
- fix webrtc startup
|
||||
- don't block application on dsa key generation
|
||||
- don't block application on dsa key generation
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
You find all information in our [contributor guide](https://github.com/jsxc/jsxc/wiki/Contributor-Guide).
|
||||
@@ -1,12 +1,20 @@
|
||||
/* global module:false */
|
||||
module.exports = function(grunt) {
|
||||
|
||||
var dep = grunt.file.readJSON('dep.json');
|
||||
var dep_files = dep.map(function(el) {
|
||||
return '<%= target %>/' + el.file;
|
||||
});
|
||||
|
||||
var git_cached = [];
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
app: grunt.file.readJSON('app.json'),
|
||||
app: grunt.file.readJSON('package.json'),
|
||||
meta: {
|
||||
banner: grunt.file.read('banner.js')
|
||||
},
|
||||
target: 'dev',
|
||||
jshint: {
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
@@ -14,18 +22,28 @@ module.exports = function(grunt) {
|
||||
gruntfile: {
|
||||
src: 'Gruntfile.js'
|
||||
},
|
||||
files: [ 'jsxc.lib.webrtc.js', 'jsxc.lib.js' ]
|
||||
files: ['src/jsxc.lib.*.js']
|
||||
},
|
||||
copy: {
|
||||
main: {
|
||||
files: [ {
|
||||
files: [{
|
||||
expand: true,
|
||||
src: [ 'lib/strophe.jingle/*.js', 'lib/otr/build/**', 'lib/otr/lib/dsa-webworker.js', 'lib/otr/lib/sm-webworker.js', 'lib/otr/lib/const.js', 'lib/otr/lib/helpers.js', 'lib/otr/lib/dsa.js', 'lib/otr/vendor/*.js', 'lib/*.js', 'jsxc.lib.js', 'jsxc.lib.webrtc.js', 'LICENSE' ],
|
||||
dest: 'build/'
|
||||
} ]
|
||||
src: ['lib/i18next/release/i18next-latest.min.js', 'lib/magnific-popup/dist/*.js', 'lib/favico.js/favico.js', 'lib/strophe.x/*.js', 'lib/strophe.bookmarks/*.js', 'lib/strophe.jinglejs/*-bundle.js', 'lib/otr/build/**', 'lib/otr/lib/dsa-webworker.js', 'lib/otr/lib/sm-webworker.js', 'lib/otr/lib/const.js', 'lib/otr/lib/helpers.js', 'lib/otr/lib/dsa.js', 'lib/otr/vendor/*.js', 'lib/*.js', 'LICENSE', 'img/**', 'sound/**'],
|
||||
dest: '<%= target %>/'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'lib/',
|
||||
src: ['*.css'],
|
||||
dest: '<%= target %>/css/'
|
||||
}, {
|
||||
expand: true,
|
||||
cwd: 'lib/magnific-popup/dist/',
|
||||
src: ['*.css'],
|
||||
dest: '<%= target %>/css/'
|
||||
}]
|
||||
}
|
||||
},
|
||||
clean: [ 'build/' ],
|
||||
clean: ['<%= target %>/'],
|
||||
usebanner: {
|
||||
dist: {
|
||||
options: {
|
||||
@@ -33,18 +51,284 @@ module.exports = function(grunt) {
|
||||
banner: '<%= meta.banner %>'
|
||||
},
|
||||
files: {
|
||||
src: [ 'build/*.js' ]
|
||||
src: ['<%= target %>/*.js']
|
||||
}
|
||||
}
|
||||
},
|
||||
replace: {
|
||||
version: {
|
||||
src: [ 'build/jsxc.lib.js' ],
|
||||
src: ['<%= target %>/jsxc.js'],
|
||||
overwrite: true,
|
||||
replacements: [ {
|
||||
replacements: [{
|
||||
from: '< $ app.version $ >',
|
||||
to: "<%= app.version %>"
|
||||
} ]
|
||||
}]
|
||||
},
|
||||
libraries: {
|
||||
src: ['<%= target %>/jsxc.js'],
|
||||
overwrite: true,
|
||||
replacements: [{
|
||||
from: '<$ dep.libraries $>',
|
||||
to: function() {
|
||||
var i, d, libraries = '';
|
||||
|
||||
for (i = 0; i < dep.length; i++) {
|
||||
d = dep[i];
|
||||
if (typeof d.name === 'string') {
|
||||
libraries += '<a href="' + d.url + '">' + d.name + '</a> (' + d.license + '), ';
|
||||
}
|
||||
}
|
||||
|
||||
return libraries.replace(/, $/, '');
|
||||
}
|
||||
}]
|
||||
},
|
||||
locales: {
|
||||
src: ['<%= target %>/lib/translation.js'],
|
||||
overwrite: true,
|
||||
replacements: [{
|
||||
from: /^{/g,
|
||||
to: 'var I18next = {'
|
||||
}, {
|
||||
from: /}$/g,
|
||||
to: '};'
|
||||
}]
|
||||
},
|
||||
template: {
|
||||
src: ['tmp/template.js'],
|
||||
overwrite: true,
|
||||
replacements: [{
|
||||
from: 'var jsxc.gui.template = {};',
|
||||
to: ''
|
||||
}]
|
||||
},
|
||||
imageUrl: {
|
||||
src: ['<%= target %>/css/*.css'],
|
||||
overwrite: true,
|
||||
replacements: [{
|
||||
from: /image-url\(["'](.+)["']\)/g,
|
||||
to: 'url(\'../img/$1\')'
|
||||
}]
|
||||
}
|
||||
},
|
||||
merge_data: {
|
||||
target: {
|
||||
src: ['locales/*.{json,y{,a}ml}'],
|
||||
dest: '<%= target %>/lib/translation.js'
|
||||
}
|
||||
},
|
||||
concat: {
|
||||
dep: {
|
||||
options: {
|
||||
banner: '/*!\n' +
|
||||
' * <%= app.name %> v<%= app.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
|
||||
' * \n' +
|
||||
' * This file concatenates all dependencies of <%= app.name %>.\n' +
|
||||
' * \n' +
|
||||
' */\n\n',
|
||||
process: function(src, filepath) {
|
||||
filepath = filepath.replace(/^[a-z]+\//i, '');
|
||||
|
||||
if (filepath === 'lib/otr/build/dep/crypto.js') {
|
||||
src += ';';
|
||||
}
|
||||
|
||||
var data = dep[dep_files.indexOf('<%= target %>/' + filepath)];
|
||||
|
||||
if (data) {
|
||||
return '\n/*!\n * Source: ' + filepath + ', license: ' + data.license + ', url: ' + data.url + '\n */\n' + src;
|
||||
} else {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
},
|
||||
src: dep_files,
|
||||
dest: '<%= target %>/lib/jsxc.dep.js'
|
||||
},
|
||||
jsxc: {
|
||||
options: {
|
||||
banner: '/*! This file is concatenated for the browser. */\n\n'
|
||||
},
|
||||
src: ['src/jsxc.intro.js', 'src/jsxc.lib.js', 'src/jsxc.lib.xmpp.js', 'src/jsxc.lib.*.js', 'tmp/template.js', 'src/jsxc.outro.js'],
|
||||
dest: '<%= target %>/jsxc.js'
|
||||
}
|
||||
},
|
||||
uglify: {
|
||||
jsxc: {
|
||||
options: {
|
||||
mangle: false,
|
||||
sourceMap: true,
|
||||
preserveComments: 'some'
|
||||
},
|
||||
files: {
|
||||
'<%= target %>/lib/jsxc.dep.min.js': ['<%= target %>/lib/jsxc.dep.js'],
|
||||
'<%= target %>/jsxc.min.js': ['<%= target %>/jsxc.js']
|
||||
}
|
||||
}
|
||||
},
|
||||
search: {
|
||||
console: {
|
||||
files: {
|
||||
src: ['src/*.js']
|
||||
},
|
||||
options: {
|
||||
searchString: /console\.log\((?!'[<>]|msg)/g,
|
||||
logFormat: 'console',
|
||||
failOnMatch: true
|
||||
}
|
||||
},
|
||||
changelog: {
|
||||
files: {
|
||||
src: ['CHANGELOG.md']
|
||||
},
|
||||
options: {
|
||||
searchString: "<%= app.version %>",
|
||||
logFormat: 'console',
|
||||
onComplete: function(m) {
|
||||
if (m.numMatches === 0) {
|
||||
grunt.fail.fatal("No entry in CHANGELOG.md for current version found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
compress: {
|
||||
main: {
|
||||
options: {
|
||||
archive: "archives/jsxc-<%= app.version %>.zip"
|
||||
},
|
||||
files: [{
|
||||
src: ['**'],
|
||||
expand: true,
|
||||
dest: 'jsxc/',
|
||||
cwd: 'build/'
|
||||
}]
|
||||
}
|
||||
},
|
||||
dataUri: {
|
||||
dist: {
|
||||
src: '<%= target %>/css/*.css',
|
||||
dest: '<%= target %>/css/',
|
||||
options: {
|
||||
target: ['<%= target %>/img/*.*', '<%= target %>/img/**/*.*'],
|
||||
fixDirLevel: false,
|
||||
maxBytes: 2048
|
||||
}
|
||||
}
|
||||
},
|
||||
jsdoc: {
|
||||
dist: {
|
||||
src: ['src/jsxc.lib.*'],
|
||||
dest: 'doc'
|
||||
}
|
||||
},
|
||||
autoprefixer: {
|
||||
no_dest: {
|
||||
src: '<%= target %>/css/*.css'
|
||||
}
|
||||
},
|
||||
csslint: {
|
||||
strict: {
|
||||
options: {
|
||||
import: 2
|
||||
},
|
||||
src: ['<%= target %>/css/*.css']
|
||||
},
|
||||
},
|
||||
sass: {
|
||||
dist: {
|
||||
files: {
|
||||
'<%= target %>/css/jsxc.css': 'scss/jsxc.scss',
|
||||
'<%= target %>/css/jsxc.webrtc.css': 'scss/jsxc.webrtc.scss'
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
locales: {
|
||||
files: ['locales/*'],
|
||||
tasks: ['merge_data', 'replace:locales', 'concat:dep']
|
||||
},
|
||||
css: {
|
||||
files: ['scss/*'],
|
||||
tasks: ['sass', 'autoprefixer']
|
||||
},
|
||||
js: {
|
||||
files: ['src/jsxc.lib.*'],
|
||||
tasks: ['concat:jsxc']
|
||||
},
|
||||
template: {
|
||||
files: ['template/*.html'],
|
||||
tasks: ['htmlConvert', 'replace:template', 'concat:jsxc']
|
||||
}
|
||||
},
|
||||
jsbeautifier: {
|
||||
files: ['Gruntfile.js', 'src/jsxc.lib.*', 'template/*.html', 'example/*.html', 'example/js/dev.js', 'example/js/example.js', 'example/css/example.css'],
|
||||
options: {
|
||||
config: '.jsbeautifyrc'
|
||||
}
|
||||
},
|
||||
prettysass: {
|
||||
options: {
|
||||
alphabetize: false,
|
||||
indent: 4
|
||||
},
|
||||
jsxc: {
|
||||
src: ['scss/*.scss']
|
||||
}
|
||||
},
|
||||
htmlConvert: {
|
||||
options: {
|
||||
target: 'js',
|
||||
rename: function(name) {
|
||||
return name.match(/([-_0-9a-z]+)\.html$/i)[1];
|
||||
},
|
||||
quoteChar: '\'',
|
||||
indentString: '',
|
||||
indentGlobal: ''
|
||||
},
|
||||
'jsxc.gui.template': {
|
||||
src: 'template/*.html',
|
||||
dest: 'tmp/template.js'
|
||||
}
|
||||
},
|
||||
shell: {
|
||||
'precommit-before': {
|
||||
command: 'git diff --cached --name-only',
|
||||
options: {
|
||||
callback: function(err, stdout, stderr, cb) {
|
||||
git_cached = stdout.trim().split(/\n/);
|
||||
|
||||
cb();
|
||||
}
|
||||
}
|
||||
},
|
||||
'precommit-after': {
|
||||
command: 'git diff --name-only',
|
||||
options: {
|
||||
callback: function(err, stdout, stderr, cb) {
|
||||
var git_diff = stdout.trim().split(/\n/);
|
||||
var intersection = [];
|
||||
var i;
|
||||
|
||||
for (i = 0; i < git_diff.length; i++) {
|
||||
if (git_cached.indexOf(git_diff[i]) >= 0) {
|
||||
intersection.push(git_diff[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (intersection.length > 0) {
|
||||
grunt.log.writeln();
|
||||
|
||||
for (i = 0; i < intersection.length; i++) {
|
||||
grunt.log.writeln('> ' + intersection[i]);
|
||||
}
|
||||
|
||||
grunt.fail.warn('Some files changed during pre-commit hook!');
|
||||
}
|
||||
|
||||
cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -53,10 +337,44 @@ module.exports = function(grunt) {
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
grunt.loadNpmTasks('grunt-contrib-concat');
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-banner');
|
||||
grunt.loadNpmTasks('grunt-text-replace');
|
||||
grunt.loadNpmTasks('grunt-search');
|
||||
grunt.loadNpmTasks('grunt-contrib-compress');
|
||||
grunt.loadNpmTasks('grunt-jsdoc');
|
||||
grunt.loadNpmTasks('grunt-data-uri');
|
||||
grunt.loadNpmTasks('grunt-merge-data');
|
||||
grunt.loadNpmTasks('grunt-contrib-csslint');
|
||||
grunt.loadNpmTasks('grunt-sass');
|
||||
grunt.loadNpmTasks('grunt-autoprefixer');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-jsbeautifier');
|
||||
grunt.loadNpmTasks('grunt-prettysass');
|
||||
grunt.loadNpmTasks('grunt-html-convert');
|
||||
grunt.loadNpmTasks('grunt-shell');
|
||||
|
||||
// Default task.
|
||||
grunt.registerTask('default', [ 'jshint', 'clean', 'copy', 'usebanner', 'replace' ]);
|
||||
//Default task
|
||||
grunt.registerTask('default', ['build', 'watch']);
|
||||
|
||||
grunt.registerTask('build', ['jshint', 'clean', 'sass', 'replace:imageUrl', 'autoprefixer', 'copy', 'merge_data', 'replace:locales', 'htmlConvert', 'replace:template', 'concat']);
|
||||
|
||||
grunt.registerTask('build:prerelease', 'Build a new pre-release', function() {
|
||||
grunt.config.set('target', 'build');
|
||||
|
||||
grunt.task.run(['search:console', 'build', 'dataUri', 'usebanner', 'replace:version', 'replace:libraries', 'uglify', 'compress']);
|
||||
});
|
||||
|
||||
grunt.registerTask('build:release', 'Build a new release', function() {
|
||||
grunt.config.set('target', 'build');
|
||||
|
||||
grunt.task.run(['search:changelog', 'build:prerelease', 'jsdoc']);
|
||||
});
|
||||
|
||||
// Create alpha/beta build @deprecated
|
||||
grunt.registerTask('pre', ['build:prerelease']);
|
||||
|
||||
// before commit
|
||||
grunt.registerTask('commit', ['shell:precommit-before', 'search:console', 'jsbeautifier', 'prettysass', 'jshint', 'shell:precommit-after']);
|
||||
};
|
||||
|
||||
@@ -1,60 +1,7 @@
|
||||
# JavaScript Xmpp Client
|
||||
# JavaScript XMPP Client
|
||||
|
||||
__Beware! This is beta software.__
|
||||
Real-time chat app. This app requires an external XMPP server (openfire, ejabberd etc.).
|
||||
|
||||
Real-time chat app. This app requires external XMPP server (openfire, ejabberd etc.).
|
||||
You find a list of features, supported protocols and browsers at the homepage of __[Javascript XMPP Client](http://www.jsxc.org)__.
|
||||
|
||||
### Features
|
||||
- integration into existing ui
|
||||
- one-to-one conversation (XMPP)
|
||||
- encrypted one-to-one conversation (OTR)
|
||||
- use of whitespace tags to start a OTR session
|
||||
- user verification (SMP)
|
||||
- encrypted one-to-one video call (WebRTC)
|
||||
- [TURN REST API](http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00)
|
||||
- fullscreen mode
|
||||
- snapshots
|
||||
- auto link-detection
|
||||
- emotions
|
||||
- roster management
|
||||
- multi-language support (de, en)
|
||||
- multi tab support
|
||||
|
||||
### Supported protocols
|
||||
- XMPP Core (RFC6120)
|
||||
- XMPP IM (RFC6121)
|
||||
- Bidirectional-streams Over Synchronous HTTP (XEP-0124)
|
||||
- XMPP Over BOSH (XEP-0206)
|
||||
- Service Discovery (XEP-0030)
|
||||
- CAP (XEP-0127)
|
||||
- Jingle (XEP-0166)
|
||||
- Jingle RTP Sessions (XEP-0167)
|
||||
|
||||
### Supported browsers
|
||||
- Full support for __Chrome__ and __Firefox__.
|
||||
- __IE__ doesn't support multi tabs, WebRTC and Notifications.
|
||||
- __Safari__ doesn't support WebRTC and Notifications.
|
||||
|
||||
### Planned features
|
||||
- multi user chat
|
||||
- video conference
|
||||
- encrypted file transfer
|
||||
|
||||
## Developer notes
|
||||
|
||||
Please execude the following commands to get a copy of the code:
|
||||
|
||||
```
|
||||
git clone https://github.com/sualko/jsxc/
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
### Libaries
|
||||
- jQuery (http://jquery.com/)
|
||||
- Strophe.js (http://strophe.im/strophejs/)
|
||||
- Strophe.js Plugins (https://github.com/strophe/strophejs-plugins)
|
||||
- OTR (https://github.com/arlolra/otr)
|
||||
- strophe.jingle (https://github.com/ESTOS/strophe.jingle)
|
||||
|
||||
### Events
|
||||
coming soon...
|
||||
If you are looking for install instructions or developer notes, please also checkout our [wiki](https://github.com/jsxc/jsxc/wiki/).
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "jsxc",
|
||||
"version": "0.6.0",
|
||||
"description": "Real-time chat app",
|
||||
"homepage": "http://jsxc.org/",
|
||||
"license": "MIT",
|
||||
"author": "Klaus Herberth <klaus@jsxc.org>"
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*!
|
||||
* <%= app.name %> v<%= app.version %> - <%= grunt.template.today("yyyy-mm-dd") %>
|
||||
*
|
||||
* Copyright (c) <%= grunt.template.today("yyyy") %> <%= app.author %> <br>
|
||||
@@ -8,4 +8,5 @@
|
||||
*
|
||||
* @author <%= app.author %>
|
||||
* @version <%= app.version %>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "jsxc",
|
||||
"version": "2.1.2",
|
||||
"homepage": "https://www.jsxc.org",
|
||||
"authors": [
|
||||
"sualko <klaus@jsxc.org>"
|
||||
],
|
||||
"description": "Real-time chat app",
|
||||
"keywords": [
|
||||
"javascript",
|
||||
"xmpp",
|
||||
"webrtc",
|
||||
"otr",
|
||||
"chat",
|
||||
"realtime"
|
||||
],
|
||||
"license": "MIT",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"lib/",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"favico.js": "~0.3.9",
|
||||
"strophe.bookmarks": "https://raw.githubusercontent.com/sualko/strophejs-plugins/bookmarks/bookmarks/strophe.bookmarks.js",
|
||||
"strophe.x": "https://raw.githubusercontent.com/strophe/strophejs-plugins/master/dataforms/src/strophe.x.js"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/* Remove close button from firstrunwizard */
|
||||
#closeWizard {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/*
|
||||
Colorbox Core Style:
|
||||
The following CSS is consistent between example themes and should not be altered.
|
||||
*/
|
||||
#colorbox,#cboxOverlay,#cboxWrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#cboxWrapper {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
#cboxOverlay {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#cboxMiddleLeft,#cboxBottomLeft {
|
||||
clear: left;
|
||||
}
|
||||
|
||||
#cboxContent {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#cboxLoadedContent {
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
#cboxTitle {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#cboxLoadingOverlay,#cboxLoadingGraphic {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#cboxPrevious,#cboxNext,#cboxClose,#cboxSlideshow {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cboxPhoto {
|
||||
float: left;
|
||||
margin: auto;
|
||||
border: 0;
|
||||
display: block;
|
||||
max-width: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
.cboxIframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
#colorbox,#cboxContent,#cboxLoadedContent {
|
||||
box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box;
|
||||
}
|
||||
|
||||
/*
|
||||
User Style:
|
||||
Change the following styles to modify the appearance of Colorbox. They are
|
||||
ordered & tabbed in a way that represents the nesting of the generated HTML.
|
||||
*/
|
||||
#cboxOverlay {
|
||||
background: #000;
|
||||
}
|
||||
|
||||
#colorbox {
|
||||
|
||||
}
|
||||
|
||||
#cboxContent {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.cboxIframe {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#cboxError {
|
||||
padding: 50px;
|
||||
border: 0px solid #ccc;
|
||||
}
|
||||
|
||||
#cboxLoadedContent {
|
||||
border: 0px solid #555;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
#cboxTitle {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 0;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
#cboxCurrent {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
right: 0px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
#cboxSlideshow {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
right: 90px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
#cboxPrevious:hover {
|
||||
background-position: bottom left;
|
||||
}
|
||||
|
||||
#cboxNext:hover {
|
||||
background-position: bottom right;
|
||||
}
|
||||
|
||||
#cboxLoadingOverlay {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#cboxClose {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
display: block;
|
||||
opacity: 0.5;
|
||||
width: 19px !important;
|
||||
height: 19px;
|
||||
border: 0px;
|
||||
text-indent: -9999px;
|
||||
background-color: #fff;
|
||||
}
|
||||
#cboxClose:before {
|
||||
content: '×';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
display: block;
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
opacity: 0.5;
|
||||
text-indent: 0;
|
||||
text-align: center;
|
||||
line-height: 19px;
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
#cboxClose:before:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#cboxClose:hover {
|
||||
background-position: right center !important;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
/*
|
||||
The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
|
||||
when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9.
|
||||
See: http://jacklmoore.com/notes/ie-transparency-problems/
|
||||
*/
|
||||
.cboxIE #cboxTopLeft,.cboxIE #cboxTopCenter,.cboxIE #cboxTopRight,.cboxIE #cboxBottomLeft,.cboxIE #cboxBottomCenter,.cboxIE #cboxBottomRight,.cboxIE #cboxMiddleLeft,.cboxIE #cboxMiddleRight
|
||||
{
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,
|
||||
endColorstr=#00FFFFFF);
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
.jsxc_remotevideo, .jsxc_noRemoteVideo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9000;
|
||||
background-color: #999999; }
|
||||
|
||||
.jsxc_webrtc {
|
||||
width: 900px; }
|
||||
.jsxc_webrtc .jsxc_status {
|
||||
z-index: 9999;
|
||||
border-radius: 20px;
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left: 50%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: #fff;
|
||||
padding: 15px;
|
||||
font-weight: bold;
|
||||
text-align: center; }
|
||||
.jsxc_webrtc .slimScrollDiv {
|
||||
opacity: 1 !important; }
|
||||
.jsxc_webrtc li .jsxc_name {
|
||||
cursor: auto; }
|
||||
.jsxc_webrtc li .jsxc_name:hover {
|
||||
color: gray; }
|
||||
|
||||
.jsxc_videoContainer {
|
||||
width: 640px;
|
||||
height: 480px;
|
||||
position: relative;
|
||||
background-color: #999999; }
|
||||
.jsxc_videoContainer video {
|
||||
display: none; }
|
||||
.jsxc_videoContainer .jsxc_noRemoteVideo {
|
||||
display: none; }
|
||||
|
||||
.jsxc_noRemoteVideo p {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
z-index: 100; }
|
||||
|
||||
.jsxc_noRemoteVideo > div {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -100px;
|
||||
left: 50%;
|
||||
margin-left: -100px; }
|
||||
.jsxc_noRemoteVideo > div > div {
|
||||
background-color: #4d4d4d; }
|
||||
.jsxc_noRemoteVideo > div > div:first-child {
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -25%;
|
||||
top: 10%; }
|
||||
.jsxc_noRemoteVideo > div > div:last-child {
|
||||
position: absolute;
|
||||
bottom: -50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%; }
|
||||
|
||||
.jsxc_localvideo {
|
||||
width: 160px;
|
||||
height: 120px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
z-index: 9990;
|
||||
background-color: #000;
|
||||
cursor: pointer; }
|
||||
|
||||
div:full-screen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000; }
|
||||
div:full-screen.jsxc_localvideo {
|
||||
border: 1px solid #fff; }
|
||||
|
||||
div:-webkit-full-screen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000; }
|
||||
|
||||
div:-moz-full-screen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000; }
|
||||
|
||||
div:-ms-fullscreen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000; }
|
||||
|
||||
div:fullscreen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000; }
|
||||
div:-webkit-full-screen.jsxc_localvideo {
|
||||
border: 1px solid #fff; }
|
||||
div:-moz-full-screen.jsxc_localvideo {
|
||||
border: 1px solid #fff; }
|
||||
div:-ms-fullscreen.jsxc_localvideo {
|
||||
border: 1px solid #fff; }
|
||||
div:fullscreen.jsxc_localvideo {
|
||||
border: 1px solid #fff; }
|
||||
|
||||
div.jsxc_video {
|
||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnMiIKICAgd2lkdGg9IjIwIgogICBoZWlnaHQ9IjIwIj4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGExMCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGRlZnMKICAgICBpZD0iZGVmczgiIC8+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuMDM3ODg1OTQsMCwwLDAuMDM3ODg1OTQsLTAuNDEzNDA3OTMsLTIuNjMxMDcxNikiPgogICAgPHBhdGgKICAgICAgIGlkPSJwYXRoMzkwNiIKICAgICAgIHN0eWxlPSJmaWxsOiM4MDgwODA7c3Ryb2tlOm5vbmUiCiAgICAgICBkPSJtIDM2MS42NTE0OCwzMTMuNTE3NjggMTc3LjE2MDc0LC0xMzEuNzg1MTYgMCwzMDIuMjI5OTkgTCAzNTguOTczMzgsMzUwLjE4NTE3IFogTSAxMC45MTE5MjIsMTgyLjQwNjM0IGwgMzc4LjM3MjY3OCwwIDAsMzAyLjY1NTgyIC0zNzguMzcyNjc4LDAgeiIgLz4KICA8L2c+Cjwvc3ZnPgo=');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 15px 15px; }
|
||||
div.jsxc_video:not(.jsxc_disabled):hover {
|
||||
background-image: url('../img/camera_icon_white.svg'); }
|
||||
|
||||
.jsxc_controlbar {
|
||||
width: 640px;
|
||||
margin-top: 10px; }
|
||||
.jsxc_controlbar .jsxc_showchat {
|
||||
float: right; }
|
||||
|
||||
.jsxc_multi > div {
|
||||
display: none; }
|
||||
|
||||
.jsxc_snapshotbar {
|
||||
width: 100%;
|
||||
display: none; }
|
||||
.jsxc_snapshotbar img {
|
||||
height: 50px; }
|
||||
|
||||
.jsxc_buttongroup {
|
||||
display: inline; }
|
||||
.jsxc_buttongroup button:first-child {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
margin-right: 0; }
|
||||
.jsxc_buttongroup button:last-child {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
margin-left: 0; }
|
||||
|
||||
.jsxc_chatarea {
|
||||
position: relative;
|
||||
float: right;
|
||||
height: 480px;
|
||||
width: 250px;
|
||||
background-color: #999999; }
|
||||
.jsxc_chatarea .jsxc_settings {
|
||||
display: none !important; }
|
||||
.jsxc_chatarea .jsxc_close {
|
||||
display: none !important; }
|
||||
.jsxc_chatarea .jsxc_video {
|
||||
display: none !important; }
|
||||
.jsxc_chatarea .jsxc_window {
|
||||
bottom: 0;
|
||||
box-shadow: none; }
|
||||
.jsxc_chatarea > ul {
|
||||
width: 250px;
|
||||
height: 480px;
|
||||
list-style: none;
|
||||
padding: 0; }
|
||||
|
||||
.bubblingG {
|
||||
text-align: center;
|
||||
width: 129px;
|
||||
height: 80px;
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
margin-left: -64px; }
|
||||
.bubblingG span {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 40px auto;
|
||||
background: #000;
|
||||
border-radius: 81px;
|
||||
-webkit-animation: bubblingG 1.3s infinite alternate;
|
||||
animation: bubblingG 1.3s infinite alternate; }
|
||||
|
||||
#bubblingG_1 {
|
||||
-webkit-animation-delay: 0s;
|
||||
animation-delay: 0s; }
|
||||
|
||||
#bubblingG_2 {
|
||||
-webkit-animation-delay: 0.39s;
|
||||
animation-delay: 0.39s; }
|
||||
|
||||
#bubblingG_3 {
|
||||
-webkit-animation-delay: 0.78s;
|
||||
animation-delay: 0.78s; }
|
||||
|
||||
@-webkit-keyframes bubblingG {
|
||||
0% {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-color: #000;
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0); }
|
||||
100% {
|
||||
width: 39px;
|
||||
height: 39px;
|
||||
background-color: #fff;
|
||||
-webkit-transform: translateY(-34px);
|
||||
transform: translateY(-34px); } }
|
||||
|
||||
@keyframes bubblingG {
|
||||
0% {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-color: #000;
|
||||
-webkit-transform: translateY(0);
|
||||
transform: translateY(0); }
|
||||
100% {
|
||||
width: 39px;
|
||||
height: 39px;
|
||||
background-color: #fff;
|
||||
-webkit-transform: translateY(-34px);
|
||||
transform: translateY(-34px); } }
|
||||
|
||||
.jsxc_fullscreen.jsxc_localvideo {
|
||||
border: 1px solid #fff; }
|
||||
|
||||
.jsxc_videoSuitable .jsxc_name {
|
||||
font-style: italic; }
|
||||
|
||||
#jsxc_buddylist .jsxc_options .jsxc_video {
|
||||
background-image: url('../img/camera_icon_white.svg'); }
|
||||
#jsxc_buddylist .jsxc_options .jsxc_video.jsxc_disabled {
|
||||
opacity: 0.2; }
|
||||
@@ -0,0 +1,374 @@
|
||||
/* Magnific Popup CSS */
|
||||
.mfp-bg {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1042;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
background: #0b0b0b;
|
||||
opacity: 0.8;
|
||||
filter: alpha(opacity=80); }
|
||||
|
||||
.mfp-wrap {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1043;
|
||||
position: fixed;
|
||||
outline: none !important;
|
||||
-webkit-backface-visibility: hidden; }
|
||||
|
||||
.mfp-container {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
padding: 0 8px;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box; }
|
||||
|
||||
.mfp-container:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle; }
|
||||
|
||||
.mfp-align-top .mfp-container:before {
|
||||
display: none; }
|
||||
|
||||
.mfp-content {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
z-index: 1045; }
|
||||
|
||||
.mfp-inline-holder .mfp-content, .mfp-ajax-holder .mfp-content {
|
||||
width: 100%;
|
||||
cursor: auto; }
|
||||
|
||||
.mfp-ajax-cur {
|
||||
cursor: progress; }
|
||||
|
||||
.mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close {
|
||||
cursor: -moz-zoom-out;
|
||||
cursor: -webkit-zoom-out;
|
||||
cursor: zoom-out; }
|
||||
|
||||
.mfp-zoom {
|
||||
cursor: pointer;
|
||||
cursor: -webkit-zoom-in;
|
||||
cursor: -moz-zoom-in;
|
||||
cursor: zoom-in; }
|
||||
|
||||
.mfp-auto-cursor .mfp-content {
|
||||
cursor: auto; }
|
||||
|
||||
.mfp-close, .mfp-arrow, .mfp-preloader, .mfp-counter {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none; }
|
||||
|
||||
.mfp-loading.mfp-figure {
|
||||
display: none; }
|
||||
|
||||
.mfp-hide {
|
||||
display: none !important; }
|
||||
|
||||
.mfp-preloader {
|
||||
color: #CCC;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
margin-top: -0.8em;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
z-index: 1044; }
|
||||
.mfp-preloader a {
|
||||
color: #CCC; }
|
||||
.mfp-preloader a:hover {
|
||||
color: #FFF; }
|
||||
|
||||
.mfp-s-ready .mfp-preloader {
|
||||
display: none; }
|
||||
|
||||
.mfp-s-error .mfp-content {
|
||||
display: none; }
|
||||
|
||||
button.mfp-close, button.mfp-arrow {
|
||||
overflow: visible;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
-webkit-appearance: none;
|
||||
display: block;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
z-index: 1046;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none; }
|
||||
button::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0; }
|
||||
|
||||
.mfp-close {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
line-height: 44px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
opacity: 0.65;
|
||||
filter: alpha(opacity=65);
|
||||
padding: 0 0 18px 10px;
|
||||
color: #FFF;
|
||||
font-style: normal;
|
||||
font-size: 28px;
|
||||
font-family: Arial, Baskerville, monospace; }
|
||||
.mfp-close:hover, .mfp-close:focus {
|
||||
opacity: 1;
|
||||
filter: alpha(opacity=100); }
|
||||
.mfp-close:active {
|
||||
top: 1px; }
|
||||
|
||||
.mfp-close-btn-in .mfp-close {
|
||||
color: #333; }
|
||||
|
||||
.mfp-image-holder .mfp-close, .mfp-iframe-holder .mfp-close {
|
||||
color: #FFF;
|
||||
right: -6px;
|
||||
text-align: right;
|
||||
padding-right: 6px;
|
||||
width: 100%; }
|
||||
|
||||
.mfp-counter {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
color: #CCC;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap; }
|
||||
|
||||
.mfp-arrow {
|
||||
position: absolute;
|
||||
opacity: 0.65;
|
||||
filter: alpha(opacity=65);
|
||||
margin: 0;
|
||||
top: 50%;
|
||||
margin-top: -55px;
|
||||
padding: 0;
|
||||
width: 90px;
|
||||
height: 110px;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); }
|
||||
.mfp-arrow:active {
|
||||
margin-top: -54px; }
|
||||
.mfp-arrow:hover, .mfp-arrow:focus {
|
||||
opacity: 1;
|
||||
filter: alpha(opacity=100); }
|
||||
.mfp-arrow:before, .mfp-arrow:after, .mfp-arrow .mfp-b, .mfp-arrow .mfp-a {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
margin-top: 35px;
|
||||
margin-left: 35px;
|
||||
border: medium inset transparent; }
|
||||
.mfp-arrow:after, .mfp-arrow .mfp-a {
|
||||
border-top-width: 13px;
|
||||
border-bottom-width: 13px;
|
||||
top: 8px; }
|
||||
.mfp-arrow:before, .mfp-arrow .mfp-b {
|
||||
border-top-width: 21px;
|
||||
border-bottom-width: 21px;
|
||||
opacity: 0.7; }
|
||||
|
||||
.mfp-arrow-left {
|
||||
left: 0; }
|
||||
.mfp-arrow-left:after, .mfp-arrow-left .mfp-a {
|
||||
border-right: 17px solid #FFF;
|
||||
margin-left: 31px; }
|
||||
.mfp-arrow-left:before, .mfp-arrow-left .mfp-b {
|
||||
margin-left: 25px;
|
||||
border-right: 27px solid #3F3F3F; }
|
||||
|
||||
.mfp-arrow-right {
|
||||
right: 0; }
|
||||
.mfp-arrow-right:after, .mfp-arrow-right .mfp-a {
|
||||
border-left: 17px solid #FFF;
|
||||
margin-left: 39px; }
|
||||
.mfp-arrow-right:before, .mfp-arrow-right .mfp-b {
|
||||
border-left: 27px solid #3F3F3F; }
|
||||
|
||||
.mfp-iframe-holder {
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px; }
|
||||
.mfp-iframe-holder .mfp-content {
|
||||
line-height: 0;
|
||||
width: 100%;
|
||||
max-width: 900px; }
|
||||
.mfp-iframe-holder .mfp-close {
|
||||
top: -40px; }
|
||||
|
||||
.mfp-iframe-scaler {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
padding-top: 56.25%; }
|
||||
.mfp-iframe-scaler iframe {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
background: #000; }
|
||||
|
||||
/* Main image in popup */
|
||||
img.mfp-img {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
line-height: 0;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 40px 0 40px;
|
||||
margin: 0 auto; }
|
||||
|
||||
/* The shadow behind the image */
|
||||
.mfp-figure {
|
||||
line-height: 0; }
|
||||
.mfp-figure:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 40px;
|
||||
bottom: 40px;
|
||||
display: block;
|
||||
right: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
z-index: -1;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
background: #444; }
|
||||
.mfp-figure small {
|
||||
color: #BDBDBD;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
line-height: 14px; }
|
||||
.mfp-figure figure {
|
||||
margin: 0; }
|
||||
|
||||
.mfp-bottom-bar {
|
||||
margin-top: -36px;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
cursor: auto; }
|
||||
|
||||
.mfp-title {
|
||||
text-align: left;
|
||||
line-height: 18px;
|
||||
color: #F3F3F3;
|
||||
word-wrap: break-word;
|
||||
padding-right: 36px; }
|
||||
|
||||
.mfp-image-holder .mfp-content {
|
||||
max-width: 100%; }
|
||||
|
||||
.mfp-gallery .mfp-image-holder .mfp-figure {
|
||||
cursor: pointer; }
|
||||
|
||||
@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) {
|
||||
/**
|
||||
* Remove all paddings around the image on small screen
|
||||
*/
|
||||
.mfp-img-mobile .mfp-image-holder {
|
||||
padding-left: 0;
|
||||
padding-right: 0; }
|
||||
.mfp-img-mobile img.mfp-img {
|
||||
padding: 0; }
|
||||
.mfp-img-mobile .mfp-figure:after {
|
||||
top: 0;
|
||||
bottom: 0; }
|
||||
.mfp-img-mobile .mfp-figure small {
|
||||
display: inline;
|
||||
margin-left: 5px; }
|
||||
.mfp-img-mobile .mfp-bottom-bar {
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
top: auto;
|
||||
padding: 3px 5px;
|
||||
position: fixed;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box; }
|
||||
.mfp-img-mobile .mfp-bottom-bar:empty {
|
||||
padding: 0; }
|
||||
.mfp-img-mobile .mfp-counter {
|
||||
right: 5px;
|
||||
top: 3px; }
|
||||
.mfp-img-mobile .mfp-close {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
line-height: 35px;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
position: fixed;
|
||||
text-align: center;
|
||||
padding: 0; }
|
||||
}
|
||||
|
||||
@media all and (max-width: 900px) {
|
||||
.mfp-arrow {
|
||||
-webkit-transform: scale(0.75);
|
||||
transform: scale(0.75); }
|
||||
|
||||
.mfp-arrow-left {
|
||||
-webkit-transform-origin: 0;
|
||||
transform-origin: 0; }
|
||||
|
||||
.mfp-arrow-right {
|
||||
-webkit-transform-origin: 100%;
|
||||
transform-origin: 100%; }
|
||||
|
||||
.mfp-container {
|
||||
padding-left: 6px;
|
||||
padding-right: 6px; }
|
||||
}
|
||||
|
||||
.mfp-ie7 .mfp-img {
|
||||
padding: 0; }
|
||||
.mfp-ie7 .mfp-bottom-bar {
|
||||
width: 600px;
|
||||
left: 50%;
|
||||
margin-left: -300px;
|
||||
margin-top: 5px;
|
||||
padding-bottom: 5px; }
|
||||
.mfp-ie7 .mfp-container {
|
||||
padding: 0; }
|
||||
.mfp-ie7 .mfp-content {
|
||||
padding-top: 44px; }
|
||||
.mfp-ie7 .mfp-close {
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding-top: 0; }
|
||||
|
Depois Largura: | Altura: | Tamanho: 9.3 KiB |
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="Layer_1"
|
||||
xml:space="preserve"
|
||||
height="147.22015"
|
||||
viewBox="0 0 192.89149 147.21771"
|
||||
width="192.89587"
|
||||
version="1.1"
|
||||
y="0px"
|
||||
x="0px"
|
||||
enable-background="new 0 0 176.486 181.437"
|
||||
inkscape:version="0.91pre2 r"
|
||||
sodipodi:docname="XMPP_logo.svg"><metadata
|
||||
id="metadata41"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs39" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="640"
|
||||
inkscape:window-height="480"
|
||||
id="namedview37"
|
||||
showgrid="false"
|
||||
fit-margin-top="10"
|
||||
fit-margin-left="10"
|
||||
fit-margin-right="10"
|
||||
fit-margin-bottom="10"
|
||||
inkscape:zoom="1.3007054"
|
||||
inkscape:cx="71.332001"
|
||||
inkscape:cy="72.501142"
|
||||
inkscape:window-x="75"
|
||||
inkscape:window-y="34"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1" /><linearGradient
|
||||
id="SVGID_1_"
|
||||
y2="0.00048828"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="-1807.2"
|
||||
gradientTransform="translate(1925.9953,9.9988343)"
|
||||
y1="125.86"
|
||||
x1="-1807.2"><stop
|
||||
stop-color="#1b3967"
|
||||
offset=".011"
|
||||
id="stop4" /><stop
|
||||
stop-color="#13b5ea"
|
||||
offset=".467"
|
||||
id="stop6" /><stop
|
||||
stop-color="#002b5c"
|
||||
offset=".9945"
|
||||
id="stop8" /></linearGradient><path
|
||||
d="m 146.28531,24.187835 c 0.077,1.313 -1.786,0.968 -1.786,2.293 0,38.551 -44.720002,96.831035 -89.847002,108.190035 l 0,1.182 C 114.60931,130.34287 181.38231,69.052835 182.89231,10.002834 l -36.6,14.189001 z"
|
||||
id="path10"
|
||||
style="fill:url(#SVGID_1_)"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 130.22531,27.958835 c 0.077,1.313 0.121,2.633 0.121,3.958 0,38.551 -30.700002,90.497035 -75.827002,101.860035 l 0,1.637 c 59.065002,-3.823 105.810002,-63.023035 105.810002,-109.200035 0,-2.375 -0.125,-4.729 -0.371,-7.056 l -29.73,8.796 z"
|
||||
id="path12"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#e96d1f" /><linearGradient
|
||||
id="SVGID_2_"
|
||||
y2="1.279e-13"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x2="-1073.2"
|
||||
gradientTransform="matrix(-1,0,0,1,-998.20465,9.9988343)"
|
||||
y1="126.85"
|
||||
x1="-1073.2"><stop
|
||||
stop-color="#1b3967"
|
||||
offset=".011"
|
||||
id="stop15" /><stop
|
||||
stop-color="#13b5ea"
|
||||
offset=".467"
|
||||
id="stop17" /><stop
|
||||
stop-color="#002b5c"
|
||||
offset=".9945"
|
||||
id="stop19" /></linearGradient><path
|
||||
d="m 46.594308,24.187835 c -0.077,1.313 1.787,0.968 1.787,2.293 0,38.551 46.558,97.366035 91.688002,108.730035 l 0,1.639 C 80.116308,131.32987 11.509308,69.049835 9.9993079,9.9998343 L 46.598308,24.188835 Z"
|
||||
id="path21"
|
||||
style="fill:url(#SVGID_2_)"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 64.726308,28.930835 c -0.076,1.313 -0.12,2.63 -0.12,3.957 0,38.551 30.699,90.497035 75.827002,101.860035 l 0,1.639 C 81.389308,133.59687 34.623308,73.362835 34.623308,27.186835 c 0,-2.375 0.128,-4.729 0.371,-7.056 l 29.73,8.798 z"
|
||||
id="path23"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#a0ce67" /><path
|
||||
d="m 34.708308,19.581835 7.617,2.722 c -0.041,0.962 -0.066,2.254 -0.066,3.225 0,41.219 37.271,98.204035 87.272002,107.120035 3.245,1.088 7.538,2.077 10.932,2.931 l 0,1.638 C 75.209308,131.65787 29.363308,65.351835 34.703308,19.577835 Z"
|
||||
id="path25"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#439639" /><path
|
||||
d="m 160.33531,18.758835 -7.833,2.625 c 0.041,0.963 0.191,2.203 0.191,3.173 0,41.219 -37.272,98.205035 -87.274002,107.120035 -3.243,1.089 -7.538,2.077 -10.93,2.932 l 0,1.639 C 122.83331,127.58787 165.66931,64.528835 160.32931,18.757835 Z"
|
||||
id="path27"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#d9541e" /></svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 4.5 KiB |
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="12.923695"
|
||||
height="19.551229"
|
||||
viewBox="0 0 3.4193941 5.1729296"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91+devel r"
|
||||
sodipodi:docname="bookmark_red.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="22.4"
|
||||
inkscape:cx="-1.621067"
|
||||
inkscape:cy="11.999492"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-0.88782864,-291.84497)">
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#800000;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1.0201203,291.84497 0,4.85355 1.5774055,-1.5774 1.5774053,1.5774 0,-4.83839"
|
||||
id="path4141"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4162"
|
||||
d="m 1.0201203,291.84497 0,4.85355 1.5774055,-1.5774 1.5774053,1.5774 0,-4.83839"
|
||||
style="fill:#ff0000;fill-rule:evenodd;stroke:none;stroke-width:0.26458332;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 2.5 KiB |
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
width="20"
|
||||
height="20">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<g
|
||||
id="layer1"
|
||||
transform="matrix(0.03788594,0,0,0.03788594,-0.41340793,-2.6310716)">
|
||||
<path
|
||||
id="path3906"
|
||||
style="fill:#808080;stroke:none"
|
||||
d="m 361.65148,313.51768 177.16074,-131.78516 0,302.22999 L 358.97338,350.18517 Z M 10.911922,182.40634 l 378.372678,0 0,302.65582 -378.372678,0 z" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 1010 B |
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="535.00458"
|
||||
height="510.4368"
|
||||
id="svg3896"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r"
|
||||
sodipodi:docname="camera_icon_white.svg">
|
||||
<defs
|
||||
id="defs3898" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.98994949"
|
||||
inkscape:cx="353.91934"
|
||||
inkscape:cy="233.8456"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3901">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-5.7142771,-72.362177)">
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:none;stroke-width:1.6172694;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect3904"
|
||||
width="378.37268"
|
||||
height="302.65582"
|
||||
x="10.911922"
|
||||
y="182.40634" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:none"
|
||||
d="m 361.65148,313.51768 177.16074,-131.78516 0,302.22999 -179.83884,-133.77734 z"
|
||||
id="path3906"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 2.1 KiB |
|
Depois Largura: | Altura: | Tamanho: 610 B |
|
Depois Largura: | Altura: | Tamanho: 2.0 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.7 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.0 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.3 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.6 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.5 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.6 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.1 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.8 KiB |
|
Depois Largura: | Altura: | Tamanho: 1.9 KiB |
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="272.70593"
|
||||
height="275.19449"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r"
|
||||
sodipodi:docname="gear.svg">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="2.8"
|
||||
inkscape:cx="146.88159"
|
||||
inkscape:cy="131.06634"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1111"
|
||||
inkscape:window-height="840"
|
||||
inkscape:window-x="191"
|
||||
inkscape:window-y="34"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath4617">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#b3b3b3;stroke:none"
|
||||
id="path4619"
|
||||
sodipodi:cx="141.42857"
|
||||
sodipodi:cy="140.90877"
|
||||
sodipodi:rx="124.28571"
|
||||
sodipodi:ry="124.28571"
|
||||
d="m 265.71429,140.90877 a 124.28571,124.28571 0 1 1 -248.57143,0 124.28571,124.28571 0 1 1 248.57143,0 z"
|
||||
transform="translate(170.48656,275.14888)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-175.56216,-278.4604)">
|
||||
<path
|
||||
style="fill:#b3b3b3;stroke:none"
|
||||
d="m 322.90077,552.37609 c -0.8025,-1.03265 -4.1298,-6.77812 -7.394,-12.76771 -5.66062,-10.38686 -5.9349,-11.45971 -5.9349,-23.21429 0,-6.77827 -0.16071,-12.33471 -0.35714,-12.34764 -0.19643,-0.0129 -7.10714,-1.25351 -15.35714,-2.75686 -8.25,-1.50332 -15.42054,-2.29632 -15.93453,-1.7622 -0.51399,0.53413 -2.65068,5.852 -4.7482,11.8175 -3.29679,9.3763 -4.91271,11.81339 -11.92261,17.98135 -13.16776,11.58617 -12.78024,11.47418 -21.89865,6.32807 l -7.91867,-4.46902 2.59473,-13.70492 c 2.49374,-13.17148 2.90233,-14.05529 10.49705,-22.70579 4.34627,-4.95047 7.90231,-9.56676 7.90231,-10.2584 0,-1.47559 -18.31337,-23.80793 -20.06165,-24.4643 -0.65433,-0.24566 -6.31795,2.51133 -12.58583,6.12664 l -11.39614,6.57329 -13.13132,-0.41234 -13.13131,-0.41236 -3.2803,-8.73539 -3.28031,-8.7354 10.00696,-8.17517 c 10.84131,-8.85678 12.71635,-9.70148 27.21704,-12.26113 l 9.64286,-1.70214 0,-16.16553 0,-16.16553 -7.5,-1.47726 c -4.125,-0.81249 -9.8425,-1.8811 -12.70556,-2.37469 -3.46464,-0.5973 -8.76203,-3.85429 -15.83987,-9.73882 l -10.63432,-8.8414 3.17885,-8.52806 3.17886,-8.52805 13.60638,-0.40736 13.60637,-0.40735 10.9584,6.47878 c 6.02712,3.56333 11.38742,6.44805 11.91178,6.41048 1.07253,-0.0768 19.25751,-22.17096 20.00721,-24.30806 0.26531,-0.75631 -2.67819,-5.06316 -6.54112,-9.5708 -9.23405,-10.77518 -8.94789,-10.17209 -11.75184,-24.76724 l -2.43237,-12.66102 8.23066,-4.90297 8.23065,-4.90298 10.59272,9.07442 c 9.9688,8.53993 10.84458,9.77375 14.869,20.94783 2.78986,7.74624 4.97907,11.78706 6.2981,11.625 1.112,-0.13663 8.28967,-1.33754 15.95038,-2.66869 l 13.92857,-2.42028 0,-12.18641 c 0,-11.78521 0.21856,-12.59093 6.63887,-24.47416 3.65139,-6.75827 6.83678,-12.52672 7.07865,-12.81878 0.24187,-0.29206 4.61063,0.25596 9.70834,1.21783 10.34441,1.95186 9.29217,0.3446 12.39626,18.9345 1.53751,9.2079 1.41438,10.15238 -2.8655,21.98039 -2.45962,6.79749 -4.29177,12.48885 -4.07147,12.64746 4.71177,3.39226 27.103,15.17953 28.15202,14.81988 0.79829,-0.27369 4.84943,-4.58023 9.00255,-9.57008 6.9761,-8.38161 8.52263,-9.438 20.30933,-13.87272 l 12.75821,-4.80025 5.08923,5.87865 c 2.79907,3.23326 5.53904,6.62899 6.08881,7.54607 0.54977,0.91709 -2.04455,6.76442 -5.76518,12.99407 -6.19419,10.37126 -7.69156,11.86889 -17.75219,17.75522 -6.04307,3.53571 -11.0023,7.00724 -11.02051,7.71451 -0.0183,0.70726 2.31563,7.61798 5.18633,15.35714 3.61895,9.75638 5.91877,14.07069 7.5,14.06952 1.2543,-9.3e-4 6.9707,-0.89614 12.70311,-1.98936 10.42006,-1.9872 10.42577,-1.98654 23.57143,2.70176 l 13.14886,4.68944 0.41954,9.31679 0.41954,9.3168 -8.15887,3.05261 c -15.89207,5.94599 -18.87437,6.32689 -32.05681,4.0942 l -12.23376,-2.072 -5.26624,14.56129 c -2.89645,8.00871 -5.25595,15.12 -5.24333,15.80287 0.0128,0.68285 4.99475,3.99618 11.07143,7.36293 10.50011,5.81754 11.37924,6.70144 17.71197,17.80828 l 6.66347,11.68693 -2.7181,3.62029 c -1.49496,1.99115 -4.17209,5.33511 -5.94919,7.43102 l -3.23108,3.81075 -12.85165,-4.85782 c -10.57761,-3.99825 -13.73735,-5.93237 -17.85714,-10.93058 -2.75303,-3.34003 -6.61264,-7.82157 -8.57693,-9.959 l -3.57143,-3.88623 -13.57142,7.92583 c -7.46429,4.3592 -13.74919,8.09684 -13.96646,8.30585 -0.21727,0.20903 1.60376,5.7737 4.04673,12.36596 4.3249,11.67062 4.39808,12.26779 2.78221,22.70022 -2.66803,17.22532 -2.40288,16.70485 -9.04751,17.76102 -3.2768,0.52086 -7.29125,1.27903 -8.92097,1.68483 -1.62973,0.4058 -3.61975,-0.10714 -4.42225,-1.13973 l 0,0 z m 5.75622,-91.21091 c 40.6356,-15.20371 40.72047,-74.63235 0.12828,-89.86647 -11.6351,-4.36662 -28.19803,-3.77677 -38.37603,1.36669 -37.2726,18.83572 -35.50133,72.09244 2.92315,87.89042 10.85167,4.4616 24.40368,4.69537 35.32454,0.60936 l 6e-5,0 z"
|
||||
id="path4584"
|
||||
inkscape:connector-curvature="0"
|
||||
clip-path="url(#clipPath4617)" />
|
||||
<path
|
||||
style="fill:#999999;stroke:none"
|
||||
d="m 137.40915,254.8325 c -1.26388,-3.15876 -2.30675,-9.74805 -2.31748,-14.64286 -0.03,-13.68249 -0.66793,-14.93253 -8.47507,-16.60686 -3.72822,-0.79957 -10.89569,-1.87094 -15.92771,-2.38086 l -9.14914,-0.92711 -4.027767,10.62916 c -3.904909,10.30494 -9.421742,18.24315 -12.678473,18.24315 -1.736606,0 -17.384447,-8.69884 -21.68079,-12.05264 -4.20131,-3.27961 -1.931667,-10.19323 6.980559,-21.26363 l 7.845084,-9.74484 -6.385824,-8.1123 c -3.512203,-4.46177 -8.245923,-10.30856 -10.519376,-12.99287 l -4.133552,-4.88057 -12.329214,6.66628 c -6.781068,3.66646 -13.656601,6.66629 -15.278964,6.66629 -3.271731,0 -8.338082,-9.55112 -11.612425,-21.89182 -1.76747,-6.66142 -1.710297,-6.98112 1.710359,-9.56355 1.946426,-1.46946 9.163956,-3.80946 16.038956,-5.19999 l 12.5,-2.52823 0,-16.70704 0,-16.70704 -10.357143,-1.78814 c -5.696429,-0.98348 -12.843581,-3.02213 -15.882561,-4.53034 -5.022513,-2.4926 -5.458415,-3.15507 -4.789259,-7.2786 0.404887,-2.49503 2.547958,-9.193329 4.76238,-14.885117 3.592557,-9.234046 4.434488,-10.348706 7.816639,-10.348706 2.084728,0 9.100345,3.00841 15.59026,6.685357 l 11.799845,6.685356 4.166639,-4.899642 c 9.088134,-10.686935 15.464628,-19.545471 15.464628,-21.484214 0,-1.121577 -2.62404,-5.214683 -5.831201,-9.09579 -6.7947,-8.222527 -9.883084,-13.759459 -9.883084,-17.718639 0,-3.210132 18.974775,-15.886714 23.77982,-15.886714 3.625548,0 7.895445,5.827393 12.682653,17.308799 2.091384,5.015875 4.349691,9.69443 5.018461,10.396788 0.71142,0.747145 7.76951,0.222625 17.01037,-1.264124 l 15.79441,-2.541139 0,-11.921252 c 0,-7.621693 0.82879,-13.992614 2.29797,-17.664448 2.15452,-5.384664 2.66001,-5.743195 8.09727,-5.743195 3.18961,0 9.86981,0.708849 14.84489,1.575221 l 9.04558,1.575222 0,6.922461 c 0,3.807354 -1.65411,12.158671 -3.67581,18.558484 -2.0217,6.399813 -3.46813,11.829199 -3.21429,12.065302 0.25385,0.236103 6.82512,3.820095 14.60283,7.96443 l 14.14129,7.535151 8.71586,-9.435108 c 8.23632,-8.916025 15.3622,-13.90402 19.86332,-13.90402 1.78522,0 18.13823,18.020332 18.13823,19.987568 0,2.654106 -10.51563,12.705932 -18.94374,18.108223 -9.10246,5.834529 -9.82127,6.652683 -8.93776,10.1729 1.57242,6.264976 9.4061,25.907756 10.63515,26.667346 0.62578,0.38675 6.55497,-0.0216 13.17597,-0.90751 9.99681,-1.33756 13.11893,-1.25044 18.41143,0.51373 l 6.37324,2.12441 0,13.38956 0,13.38956 -6.42857,1.89426 c -5.17857,1.52593 -8.87329,1.5662 -19.00145,0.20712 -7.4181,-0.99542 -13.05582,-1.16059 -13.75084,-0.40286 -1.95698,2.1336 -10.3766,28.97456 -9.52241,30.35665 0.43701,0.70711 5.19671,3.90091 10.5771,7.09734 6.2538,3.71532 11.1796,7.92283 13.65558,11.66429 l 3.87307,5.8526 -2.86288,3.63956 c -4.38864,5.57927 -12.42466,14.31215 -14.15297,15.38031 -3.29983,2.0394 -12.69305,-3.81343 -21.67235,-13.50386 l -9.28571,-10.02111 -13.57143,8.13113 c -7.46428,4.47211 -13.79851,8.31193 -14.07606,8.53291 -0.27755,0.221 1.20602,5.53844 3.29682,11.81654 2.55534,7.673 3.65733,13.67335 3.36178,18.3049 l -0.43968,6.89015 -7.85714,1.64795 c -4.32143,0.90639 -10.84092,1.70996 -14.48775,1.78572 -6.45052,0.134 -6.69301,-0.0183 -8.92857,-5.60544 z m 19.61036,-73.3652 c 34.05446,-16.66129 35.92066,-67.13028 3.17384,-85.832465 -12.58073,-7.185038 -31.24883,-8.116887 -44.61884,-2.227222 -8.23256,3.62655 -18.548016,13.504017 -23.09118,22.110727 -3.416776,6.47285 -3.800721,8.7155 -3.800721,22.20021 0,12.90344 0.457912,15.85761 3.27616,21.1358 6.984552,13.08112 18.824081,22.45795 32.789441,25.96905 9.31337,2.34151 23.67947,0.84748 32.2713,-3.3561 z"
|
||||
id="path2985"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(175.56216,278.4604)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 9.5 KiB |
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="272.70593"
|
||||
height="275.19449"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="gear.svg">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.7"
|
||||
inkscape:cx="159.11118"
|
||||
inkscape:cy="75.475936"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1111"
|
||||
inkscape:window-height="840"
|
||||
inkscape:window-x="191"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="0"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath4617">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#b3b3b3;stroke:none"
|
||||
id="path4619"
|
||||
sodipodi:cx="141.42857"
|
||||
sodipodi:cy="140.90877"
|
||||
sodipodi:rx="124.28571"
|
||||
sodipodi:ry="124.28571"
|
||||
d="m 265.71429,140.90877 a 124.28571,124.28571 0 1 1 -248.57143,0 124.28571,124.28571 0 1 1 248.57143,0 z"
|
||||
transform="translate(170.48656,275.14888)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-175.56216,-278.4604)">
|
||||
<path
|
||||
style="fill:#b3b3b3;stroke:none"
|
||||
d="m 322.90077,552.37609 c -0.8025,-1.03265 -4.1298,-6.77812 -7.394,-12.76771 -5.66062,-10.38686 -5.9349,-11.45971 -5.9349,-23.21429 0,-6.77827 -0.16071,-12.33471 -0.35714,-12.34764 -0.19643,-0.0129 -7.10714,-1.25351 -15.35714,-2.75686 -8.25,-1.50332 -15.42054,-2.29632 -15.93453,-1.7622 -0.51399,0.53413 -2.65068,5.852 -4.7482,11.8175 -3.29679,9.3763 -4.91271,11.81339 -11.92261,17.98135 -13.16776,11.58617 -12.78024,11.47418 -21.89865,6.32807 l -7.91867,-4.46902 2.59473,-13.70492 c 2.49374,-13.17148 2.90233,-14.05529 10.49705,-22.70579 4.34627,-4.95047 7.90231,-9.56676 7.90231,-10.2584 0,-1.47559 -18.31337,-23.80793 -20.06165,-24.4643 -0.65433,-0.24566 -6.31795,2.51133 -12.58583,6.12664 l -11.39614,6.57329 -13.13132,-0.41234 -13.13131,-0.41236 -3.2803,-8.73539 -3.28031,-8.7354 10.00696,-8.17517 c 10.84131,-8.85678 12.71635,-9.70148 27.21704,-12.26113 l 9.64286,-1.70214 0,-16.16553 0,-16.16553 -7.5,-1.47726 c -4.125,-0.81249 -9.8425,-1.8811 -12.70556,-2.37469 -3.46464,-0.5973 -8.76203,-3.85429 -15.83987,-9.73882 l -10.63432,-8.8414 3.17885,-8.52806 3.17886,-8.52805 13.60638,-0.40736 13.60637,-0.40735 10.9584,6.47878 c 6.02712,3.56333 11.38742,6.44805 11.91178,6.41048 1.07253,-0.0768 19.25751,-22.17096 20.00721,-24.30806 0.26531,-0.75631 -2.67819,-5.06316 -6.54112,-9.5708 -9.23405,-10.77518 -8.94789,-10.17209 -11.75184,-24.76724 l -2.43237,-12.66102 8.23066,-4.90297 8.23065,-4.90298 10.59272,9.07442 c 9.9688,8.53993 10.84458,9.77375 14.869,20.94783 2.78986,7.74624 4.97907,11.78706 6.2981,11.625 1.112,-0.13663 8.28967,-1.33754 15.95038,-2.66869 l 13.92857,-2.42028 0,-12.18641 c 0,-11.78521 0.21856,-12.59093 6.63887,-24.47416 3.65139,-6.75827 6.83678,-12.52672 7.07865,-12.81878 0.24187,-0.29206 4.61063,0.25596 9.70834,1.21783 10.34441,1.95186 9.29217,0.3446 12.39626,18.9345 1.53751,9.2079 1.41438,10.15238 -2.8655,21.98039 -2.45962,6.79749 -4.29177,12.48885 -4.07147,12.64746 4.71177,3.39226 27.103,15.17953 28.15202,14.81988 0.79829,-0.27369 4.84943,-4.58023 9.00255,-9.57008 6.9761,-8.38161 8.52263,-9.438 20.30933,-13.87272 l 12.75821,-4.80025 5.08923,5.87865 c 2.79907,3.23326 5.53904,6.62899 6.08881,7.54607 0.54977,0.91709 -2.04455,6.76442 -5.76518,12.99407 -6.19419,10.37126 -7.69156,11.86889 -17.75219,17.75522 -6.04307,3.53571 -11.0023,7.00724 -11.02051,7.71451 -0.0183,0.70726 2.31563,7.61798 5.18633,15.35714 3.61895,9.75638 5.91877,14.07069 7.5,14.06952 1.2543,-9.3e-4 6.9707,-0.89614 12.70311,-1.98936 10.42006,-1.9872 10.42577,-1.98654 23.57143,2.70176 l 13.14886,4.68944 0.41954,9.31679 0.41954,9.3168 -8.15887,3.05261 c -15.89207,5.94599 -18.87437,6.32689 -32.05681,4.0942 l -12.23376,-2.072 -5.26624,14.56129 c -2.89645,8.00871 -5.25595,15.12 -5.24333,15.80287 0.0128,0.68285 4.99475,3.99618 11.07143,7.36293 10.50011,5.81754 11.37924,6.70144 17.71197,17.80828 l 6.66347,11.68693 -2.7181,3.62029 c -1.49496,1.99115 -4.17209,5.33511 -5.94919,7.43102 l -3.23108,3.81075 -12.85165,-4.85782 c -10.57761,-3.99825 -13.73735,-5.93237 -17.85714,-10.93058 -2.75303,-3.34003 -6.61264,-7.82157 -8.57693,-9.959 l -3.57143,-3.88623 -13.57142,7.92583 c -7.46429,4.3592 -13.74919,8.09684 -13.96646,8.30585 -0.21727,0.20903 1.60376,5.7737 4.04673,12.36596 4.3249,11.67062 4.39808,12.26779 2.78221,22.70022 -2.66803,17.22532 -2.40288,16.70485 -9.04751,17.76102 -3.2768,0.52086 -7.29125,1.27903 -8.92097,1.68483 -1.62973,0.4058 -3.61975,-0.10714 -4.42225,-1.13973 l 0,0 z m 5.75622,-91.21091 c 40.6356,-15.20371 40.72047,-74.63235 0.12828,-89.86647 -11.6351,-4.36662 -28.19803,-3.77677 -38.37603,1.36669 -37.2726,18.83572 -35.50133,72.09244 2.92315,87.89042 10.85167,4.4616 24.40368,4.69537 35.32454,0.60936 l 6e-5,0 z"
|
||||
id="path4584"
|
||||
inkscape:connector-curvature="0"
|
||||
clip-path="url(#clipPath4617)" />
|
||||
<path
|
||||
style="fill:#ffffff;stroke:none"
|
||||
d="m 137.40915,254.8325 c -1.26388,-3.15876 -2.30675,-9.74805 -2.31748,-14.64286 -0.03,-13.68249 -0.66793,-14.93253 -8.47507,-16.60686 -3.72822,-0.79957 -10.89569,-1.87094 -15.92771,-2.38086 l -9.14914,-0.92711 -4.027767,10.62916 c -3.904909,10.30494 -9.421742,18.24315 -12.678473,18.24315 -1.736606,0 -17.384447,-8.69884 -21.68079,-12.05264 -4.20131,-3.27961 -1.931667,-10.19323 6.980559,-21.26363 l 7.845084,-9.74484 -6.385824,-8.1123 c -3.512203,-4.46177 -8.245923,-10.30856 -10.519376,-12.99287 l -4.133552,-4.88057 -12.329214,6.66628 c -6.781068,3.66646 -13.656601,6.66629 -15.278964,6.66629 -3.271731,0 -8.338082,-9.55112 -11.612425,-21.89182 -1.76747,-6.66142 -1.710297,-6.98112 1.710359,-9.56355 1.946426,-1.46946 9.163956,-3.80946 16.038956,-5.19999 l 12.5,-2.52823 0,-16.70704 0,-16.70704 -10.357143,-1.78814 c -5.696429,-0.98348 -12.843581,-3.02213 -15.882561,-4.53034 -5.022513,-2.4926 -5.458415,-3.15507 -4.789259,-7.2786 0.404887,-2.49503 2.547958,-9.193329 4.76238,-14.885117 3.592557,-9.234046 4.434488,-10.348706 7.816639,-10.348706 2.084728,0 9.100345,3.00841 15.59026,6.685357 l 11.799845,6.685356 4.166639,-4.899642 c 9.088134,-10.686935 15.464628,-19.545471 15.464628,-21.484214 0,-1.121577 -2.62404,-5.214683 -5.831201,-9.09579 -6.7947,-8.222527 -9.883084,-13.759459 -9.883084,-17.718639 0,-3.210132 18.974775,-15.886714 23.77982,-15.886714 3.625548,0 7.895445,5.827393 12.682653,17.308799 2.091384,5.015875 4.349691,9.69443 5.018461,10.396788 0.71142,0.747145 7.76951,0.222625 17.01037,-1.264124 l 15.79441,-2.541139 0,-11.921252 c 0,-7.621693 0.82879,-13.992614 2.29797,-17.664448 2.15452,-5.384664 2.66001,-5.743195 8.09727,-5.743195 3.18961,0 9.86981,0.708849 14.84489,1.575221 l 9.04558,1.575222 0,6.922461 c 0,3.807354 -1.65411,12.158671 -3.67581,18.558484 -2.0217,6.399813 -3.46813,11.829199 -3.21429,12.065302 0.25385,0.236103 6.82512,3.820095 14.60283,7.96443 l 14.14129,7.535151 8.71586,-9.435108 c 8.23632,-8.916025 15.3622,-13.90402 19.86332,-13.90402 1.78522,0 18.13823,18.020332 18.13823,19.987568 0,2.654106 -10.51563,12.705932 -18.94374,18.108223 -9.10246,5.834529 -9.82127,6.652683 -8.93776,10.1729 1.57242,6.264976 9.4061,25.907756 10.63515,26.667346 0.62578,0.38675 6.55497,-0.0216 13.17597,-0.90751 9.99681,-1.33756 13.11893,-1.25044 18.41143,0.51373 l 6.37324,2.12441 0,13.38956 0,13.38956 -6.42857,1.89426 c -5.17857,1.52593 -8.87329,1.5662 -19.00145,0.20712 -7.4181,-0.99542 -13.05582,-1.16059 -13.75084,-0.40286 -1.95698,2.1336 -10.3766,28.97456 -9.52241,30.35665 0.43701,0.70711 5.19671,3.90091 10.5771,7.09734 6.2538,3.71532 11.1796,7.92283 13.65558,11.66429 l 3.87307,5.8526 -2.86288,3.63956 c -4.38864,5.57927 -12.42466,14.31215 -14.15297,15.38031 -3.29983,2.0394 -12.69305,-3.81343 -21.67235,-13.50386 l -9.28571,-10.02111 -13.57143,8.13113 c -7.46428,4.47211 -13.79851,8.31193 -14.07606,8.53291 -0.27755,0.221 1.20602,5.53844 3.29682,11.81654 2.55534,7.673 3.65733,13.67335 3.36178,18.3049 l -0.43968,6.89015 -7.85714,1.64795 c -4.32143,0.90639 -10.84092,1.70996 -14.48775,1.78572 -6.45052,0.134 -6.69301,-0.0183 -8.92857,-5.60544 z m 19.61036,-73.3652 c 34.05446,-16.66129 35.92066,-67.13028 3.17384,-85.832465 -12.58073,-7.185038 -31.24883,-8.116887 -44.61884,-2.227222 -8.23256,3.62655 -18.548016,13.504017 -23.09118,22.110727 -3.416776,6.47285 -3.800721,8.7155 -3.800721,22.20021 0,12.90344 0.457912,15.85761 3.27616,21.1358 6.984552,13.08112 18.824081,22.45795 32.789441,25.96905 9.31337,2.34151 23.67947,0.84748 32.2713,-3.3561 z"
|
||||
id="path2985"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(175.56216,278.4604)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 9.4 KiB |
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 1000 1000"
|
||||
preserveAspectRatio="xMinYMin meet"
|
||||
width="100%"
|
||||
height="100%"
|
||||
style="width: 512px; height: 512px;"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91+devel r"
|
||||
sodipodi:docname="group_grey.svg">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="980"
|
||||
inkscape:window-height="888"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.6675088"
|
||||
inkscape:cx="512.17823"
|
||||
inkscape:cy="480.21903"
|
||||
inkscape:window-x="889"
|
||||
inkscape:window-y="85"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" />
|
||||
<path
|
||||
d="m 0.94630456,763.0963 c 0,22.21203 9.08673644,33.31804 27.26020844,33.31804 l 112.069747,0 0,-142.35887 c 0,-18.17347 4.54363,-34.83222 13.63088,-49.97627 9.08724,-15.14405 21.70797,-26.75512 37.86216,-34.83326 l 115.09866,-54.52042 c 10.09637,-6.05782 18.17347,-13.12528 24.23129,-21.20238 -12.11564,-18.17347 -22.21202,-39.37586 -30.28912,-63.60715 -8.0771,-24.2313 -12.11564,-49.47223 -12.11564,-75.7228 0,-16.1542 2.01927,-32.3084 6.05782,-48.46259 4.03855,-16.1542 9.08674,-31.29876 15.14456,-45.43368 -20.19275,-14.13493 -41.39513,-21.20239 -63.60715,-21.20239 -38.36622,2.01928 -68.65534,17.66839 -90.86736,46.94736 -22.21201,29.27897 -33.31803,62.09244 -33.31803,98.44042 2.01928,62.59751 24.2313,107.02155 66.63606,133.27212 L 16.092416,596.50615 C 5.9960421,602.56397 0.94785546,612.66034 0.94785546,626.79527 l 0,136.30103 z M 191.76775,796.41434 c -2.01927,42.40476 10.09637,64.61678 36.34695,66.63606 l 542.17524,0 c 12.11565,-4.03855 20.69783,-10.09637 25.74653,-18.17347 5.04869,-8.0771 7.57305,-14.63948 7.57305,-19.68716 l 0,-171.13275 c 0,-18.17347 -7.06746,-30.28912 -21.20238,-36.34694 L 637.01936,545.01619 573.41221,514.72707 c 38.36622,-22.21202 63.60715,-60.57824 75.7228,-115.09865 8.0771,-30.28912 8.0771,-61.58788 0,-93.89627 -10.09637,-36.34695 -28.7744,-67.14115 -56.0341,-92.38259 -27.25969,-25.24145 -59.06352,-38.87182 -95.4115,-40.89109 -36.34694,2.01927 -67.6457,15.64964 -93.89627,40.89109 -26.25057,25.24144 -44.42404,55.02601 -54.52042,89.35368 -12.11564,46.44331 -8.07709,93.89627 12.11565,142.35886 16.1542,30.28912 37.35658,54.52041 63.60715,72.69389 l -57.54932,27.2602 -151.4456,69.66498 c -16.1542,8.0771 -24.2313,21.20238 -24.2313,39.37585 l 0,142.35887 z m 475.53918,-302.8912 c 8.0771,8.0771 18.17347,16.1542 30.28912,24.23129 12.11565,8.0771 23.22166,14.13493 33.31803,18.17348 10.09638,4.03855 23.22166,9.59181 39.37586,16.65979 16.1542,7.06797 28.26984,12.62124 36.34694,16.65979 16.1542,8.0771 28.77493,19.68819 37.86218,34.83326 9.08724,15.14507 13.63088,31.80384 13.63088,49.97627 l 0,142.35887 115.09865,0 c 18.17347,-2.01928 27.26021,-13.12529 27.26021,-33.31803 l 0,-136.30104 c 0,-14.13493 -5.04819,-24.2313 -15.14456,-30.28912 L 815.72517,514.72707 c 42.40477,-30.28912 63.60715,-73.70352 63.60715,-130.24321 0,-38.36622 -12.11565,-72.18881 -36.34694,-101.46778 -24.2313,-29.27897 -53.51078,-43.91896 -87.83845,-43.92 -22.21202,0 -44.42404,7.06747 -66.63606,21.20239 12.11564,30.28912 18.17347,61.58787 18.17347,93.89627 0,50.48187 -13.12529,96.92518 -39.37586,139.32995 z"
|
||||
id="path4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cscsscccsssccscccscccccssscccccscscccccscccssssssccssccssccscc"
|
||||
style="fill:#999999;stroke-width:1.55090213;fill-opacity:1" />
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 4.2 KiB |
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 1000 1000"
|
||||
preserveAspectRatio="xMinYMin meet"
|
||||
width="100%"
|
||||
height="100%"
|
||||
style="width: 512px; height: 512px;"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91+devel r"
|
||||
sodipodi:docname="group_white.svg">
|
||||
<metadata
|
||||
id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
id="namedview6"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.6675088"
|
||||
inkscape:cx="538.39511"
|
||||
inkscape:cy="480.21903"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<path
|
||||
d="m 0.94630456,763.0963 c 0,22.21203 9.08673644,33.31804 27.26020844,33.31804 l 112.069747,0 0,-142.35887 c 0,-18.17347 4.54363,-34.83222 13.63088,-49.97627 9.08724,-15.14405 21.70797,-26.75512 37.86216,-34.83326 l 115.09866,-54.52042 c 10.09637,-6.05782 18.17347,-13.12528 24.23129,-21.20238 -12.11564,-18.17347 -22.21202,-39.37586 -30.28912,-63.60715 -8.0771,-24.2313 -12.11564,-49.47223 -12.11564,-75.7228 0,-16.1542 2.01927,-32.3084 6.05782,-48.46259 4.03855,-16.1542 9.08674,-31.29876 15.14456,-45.43368 -20.19275,-14.13493 -41.39513,-21.20239 -63.60715,-21.20239 -38.36622,2.01928 -68.65534,17.66839 -90.86736,46.94736 -22.21201,29.27897 -33.31803,62.09244 -33.31803,98.44042 2.01928,62.59751 24.2313,107.02155 66.63606,133.27212 L 16.092416,596.50615 C 5.9960421,602.56397 0.94785546,612.66034 0.94785546,626.79527 l 0,136.30103 z M 191.76775,796.41434 c -2.01927,42.40476 10.09637,64.61678 36.34695,66.63606 l 542.17524,0 c 12.11565,-4.03855 20.69783,-10.09637 25.74653,-18.17347 5.04869,-8.0771 7.57305,-14.63948 7.57305,-19.68716 l 0,-171.13275 c 0,-18.17347 -7.06746,-30.28912 -21.20238,-36.34694 L 637.01936,545.01619 573.41221,514.72707 c 38.36622,-22.21202 63.60715,-60.57824 75.7228,-115.09865 8.0771,-30.28912 8.0771,-61.58788 0,-93.89627 -10.09637,-36.34695 -28.7744,-67.14115 -56.0341,-92.38259 -27.25969,-25.24145 -59.06352,-38.87182 -95.4115,-40.89109 -36.34694,2.01927 -67.6457,15.64964 -93.89627,40.89109 -26.25057,25.24144 -44.42404,55.02601 -54.52042,89.35368 -12.11564,46.44331 -8.07709,93.89627 12.11565,142.35886 16.1542,30.28912 37.35658,54.52041 63.60715,72.69389 l -57.54932,27.2602 -151.4456,69.66498 c -16.1542,8.0771 -24.2313,21.20238 -24.2313,39.37585 l 0,142.35887 z m 475.53918,-302.8912 c 8.0771,8.0771 18.17347,16.1542 30.28912,24.23129 12.11565,8.0771 23.22166,14.13493 33.31803,18.17348 10.09638,4.03855 23.22166,9.59181 39.37586,16.65979 16.1542,7.06797 28.26984,12.62124 36.34694,16.65979 16.1542,8.0771 28.77493,19.68819 37.86218,34.83326 9.08724,15.14507 13.63088,31.80384 13.63088,49.97627 l 0,142.35887 115.09865,0 c 18.17347,-2.01928 27.26021,-13.12529 27.26021,-33.31803 l 0,-136.30104 c 0,-14.13493 -5.04819,-24.2313 -15.14456,-30.28912 L 815.72517,514.72707 c 42.40477,-30.28912 63.60715,-73.70352 63.60715,-130.24321 0,-38.36622 -12.11565,-72.18881 -36.34694,-101.46778 -24.2313,-29.27897 -53.51078,-43.91896 -87.83845,-43.92 -22.21202,0 -44.42404,7.06747 -66.63606,21.20239 12.11564,30.28912 18.17347,61.58787 18.17347,93.89627 0,50.48187 -13.12529,96.92518 -39.37586,139.32995 z"
|
||||
id="path4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cscsscccsssccscccscccccssscccccscscccccscccssssssccssccssccscc"
|
||||
style="fill:#ffffff;stroke-width:1.55090213" />
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 4.2 KiB |
|
Depois Largura: | Altura: | Tamanho: 2.7 KiB |
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg3041"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r"
|
||||
width="15"
|
||||
height="15"
|
||||
sodipodi:docname="padlock_close_green.svg">
|
||||
<metadata
|
||||
id="metadata3047">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3045" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
id="namedview3043"
|
||||
showgrid="false"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="12.823367"
|
||||
inkscape:cy="8.9449238"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg3041"
|
||||
borderlayer="true" />
|
||||
<rect
|
||||
style="fill:#44aa00;stroke:#44aa00;stroke-width:0.92522794"
|
||||
id="rect3051"
|
||||
width="10.232394"
|
||||
height="6.4687548"
|
||||
x="2.5534275"
|
||||
y="8.074255" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#44aa00;stroke-width:2.08827519;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4101"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="7.6713805"
|
||||
sodipodi:cy="6.7928491"
|
||||
sodipodi:rx="4.534133"
|
||||
sodipodi:ry="4.5301714"
|
||||
sodipodi:start="3.1415927"
|
||||
sodipodi:end="0"
|
||||
d="M 3.1372476,6.7928489 A 4.534133,4.5301714 0 0 1 7.6713806,2.2626777 4.534133,4.5301714 0 0 1 12.205513,6.7928491"
|
||||
sodipodi:open="true" />
|
||||
<rect
|
||||
style="fill:#44aa00;fill-opacity:1;stroke:none;stroke-width:1.39526081;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4153"
|
||||
width="2.0906768"
|
||||
height="1.0984892"
|
||||
x="2.0913804"
|
||||
y="6.7554431" />
|
||||
<rect
|
||||
y="6.7632556"
|
||||
x="11.157786"
|
||||
height="1.0984892"
|
||||
width="2.0906768"
|
||||
id="rect4155"
|
||||
style="fill:#44aa00;fill-opacity:1;stroke:none;stroke-width:1.39526081;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 2.7 KiB |
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg3041"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r"
|
||||
width="15"
|
||||
height="15"
|
||||
sodipodi:docname="padlock_close_grey.svg">
|
||||
<metadata
|
||||
id="metadata3047">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3045" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
id="namedview3043"
|
||||
showgrid="false"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="12.792117"
|
||||
inkscape:cy="8.9449238"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg3041"
|
||||
borderlayer="true" />
|
||||
<rect
|
||||
style="fill:#808080;stroke:#808080;stroke-width:0.92522794"
|
||||
id="rect3051"
|
||||
width="10.232394"
|
||||
height="6.4687548"
|
||||
x="2.5534275"
|
||||
y="8.074255" />
|
||||
<a
|
||||
id="a4157"
|
||||
style="fill:none;stroke:#808080">
|
||||
<path
|
||||
sodipodi:open="true"
|
||||
d="M 3.1372476,6.7928489 A 4.534133,4.5301714 0 0 1 7.6713806,2.2626777 4.534133,4.5301714 0 0 1 12.205513,6.7928491"
|
||||
sodipodi:end="0"
|
||||
sodipodi:start="3.1415927"
|
||||
sodipodi:ry="4.5301714"
|
||||
sodipodi:rx="4.534133"
|
||||
sodipodi:cy="6.7928491"
|
||||
sodipodi:cx="7.6713805"
|
||||
sodipodi:type="arc"
|
||||
id="path4101"
|
||||
style="fill:none;fill-opacity:1;stroke:#808080;stroke-width:2.08827519;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</a>
|
||||
<g
|
||||
id="g4170"
|
||||
style="fill:#808080">
|
||||
<rect
|
||||
y="6.7554431"
|
||||
x="2.0913804"
|
||||
height="1.0984892"
|
||||
width="2.0906768"
|
||||
id="rect4153"
|
||||
style="fill:#808080;fill-opacity:1;stroke:none;stroke-width:1.39526081;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="fill:#808080;fill-opacity:1;stroke:none;stroke-width:1.39526081;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4155"
|
||||
width="2.0906768"
|
||||
height="1.0984892"
|
||||
x="11.157786"
|
||||
y="6.7632556" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 2.8 KiB |
@@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg3041"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r"
|
||||
width="15"
|
||||
height="15"
|
||||
sodipodi:docname="padlock_close_orange.svg">
|
||||
<metadata
|
||||
id="metadata3047">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3045" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
id="namedview3043"
|
||||
showgrid="false"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="12.792117"
|
||||
inkscape:cy="8.9449238"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg3041"
|
||||
borderlayer="true" />
|
||||
<rect
|
||||
style="fill:#ff7f2a;stroke:#ff7f2a;stroke-width:0.92522794"
|
||||
id="rect3051"
|
||||
width="10.232394"
|
||||
height="6.4687548"
|
||||
x="2.5534275"
|
||||
y="8.074255" />
|
||||
<a
|
||||
id="a4157"
|
||||
style="fill:none;stroke:#ff7f2a">
|
||||
<path
|
||||
sodipodi:open="true"
|
||||
d="M 3.1372476,6.7928489 A 4.534133,4.5301714 0 0 1 7.6713806,2.2626777 4.534133,4.5301714 0 0 1 12.205513,6.7928491"
|
||||
sodipodi:end="0"
|
||||
sodipodi:start="3.1415927"
|
||||
sodipodi:ry="4.5301714"
|
||||
sodipodi:rx="4.534133"
|
||||
sodipodi:cy="6.7928491"
|
||||
sodipodi:cx="7.6713805"
|
||||
sodipodi:type="arc"
|
||||
id="path4101"
|
||||
style="fill:none;fill-opacity:1;stroke:#ff7f2a;stroke-width:2.08827519;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</a>
|
||||
<g
|
||||
id="g4170"
|
||||
style="fill:#ff7f2a">
|
||||
<rect
|
||||
y="6.7554431"
|
||||
x="2.0913804"
|
||||
height="1.0984892"
|
||||
width="2.0906768"
|
||||
id="rect4153"
|
||||
style="fill:#ff7f2a;fill-opacity:1;stroke:none;stroke-width:1.39526081;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="fill:#ff7f2a;fill-opacity:1;stroke:none;stroke-width:1.39526081;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4155"
|
||||
width="2.0906768"
|
||||
height="1.0984892"
|
||||
x="11.157786"
|
||||
y="6.7632556" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 2.8 KiB |
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width="15"
|
||||
height="15"
|
||||
id="svg3041">
|
||||
<metadata
|
||||
id="metadata3047">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3045" />
|
||||
<rect
|
||||
width="11.059322"
|
||||
height="6.9915257"
|
||||
x="2.1610172"
|
||||
y="8.0084743"
|
||||
id="rect3051"
|
||||
style="fill:#999999;stroke:none" />
|
||||
<path
|
||||
d="m 3.082628,5.0211864 c 0,0 -0.127119,-4.06779652 4.449152,-4.06779652 4.576268,0 4.703386,3.94067782 4.703386,3.94067782 l 0.06356,5.5932193 0,0"
|
||||
id="path3848"
|
||||
style="fill:none;stroke:#999999;stroke-width:1.89999998;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 1.2 KiB |
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg3041"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r"
|
||||
width="15"
|
||||
height="15"
|
||||
sodipodi:docname="padlock_open-white.svg">
|
||||
<metadata
|
||||
id="metadata3047">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3045" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
id="namedview3043"
|
||||
showgrid="false"
|
||||
inkscape:zoom="44.500587"
|
||||
inkscape:cx="6.292871"
|
||||
inkscape:cy="10.986979"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg3041"
|
||||
borderlayer="true" />
|
||||
<rect
|
||||
style="fill:#808080;stroke:#808080;stroke-width:0.92522794"
|
||||
id="rect3051"
|
||||
width="10.232394"
|
||||
height="6.4687548"
|
||||
x="2.5534275"
|
||||
y="8.074255" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-color:currentColor;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.90384686;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="M 7.5078125,0.00556144 C 5.0260054,0.00556144 3.491603,0.79834464 2.75,1.9469676 2.008397,3.0955907 2.0878906,4.3496954 2.0878906,5.0250926 l 1.9042969,0 c 0,-0.7329344 0.013699,-1.5125503 0.3574219,-2.0449218 0.3437231,-0.5323715 1.0433343,-1.0703125 3.1582031,-1.0703125 2.0264219,0 2.9669635,0.6265545 3.4326915,1.3827484 0.465728,0.7561939 0.400333,1.7142789 0.400333,1.7142789 0.04517,1.7732263 -0.06599,4.3031738 0.0049,5.5357844 l 0.05274,0.898438 0.898437,0 0.945445,-0.0031 0.01,-6.4361373 c 0,0 0.06201,-1.6621328 -0.685321,-2.8754827 C 11.819768,0.91300364 10.078064,0.00556144 7.5078125,0.00556144 Z"
|
||||
id="path3848"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ssccssscccccccs" />
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 3.3 KiB |
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg3041"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
width="15"
|
||||
height="15"
|
||||
sodipodi:docname="padlock_open-white.svg">
|
||||
<metadata
|
||||
id="metadata3047">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs3045" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1444"
|
||||
inkscape:window-height="787"
|
||||
id="namedview3043"
|
||||
showgrid="false"
|
||||
inkscape:zoom="44.500587"
|
||||
inkscape:cx="9.2134583"
|
||||
inkscape:cy="8.0232356"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg3041" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:#ffffff"
|
||||
id="rect3051"
|
||||
width="11.059322"
|
||||
height="6.9915257"
|
||||
x="2.1610172"
|
||||
y="8.0084743" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1.89999998000000003;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 3.082628,5.0211864 c 0,0 -0.127119,-4.06779652 4.449152,-4.06779652 4.576268,0 4.703386,3.94067782 4.703386,3.94067782 l 0.06356,5.5932193 0,0"
|
||||
id="path3848"
|
||||
inkscape:connector-curvature="0" />
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 2.0 KiB |
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="15"
|
||||
height="15"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="resize_gray.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath3803">
|
||||
<rect
|
||||
style="stroke:none"
|
||||
id="rect3805"
|
||||
width="16.09375"
|
||||
height="14.71875"
|
||||
x="0.84375"
|
||||
y="1038.1434" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="32"
|
||||
inkscape:cx="6.9909088"
|
||||
inkscape:cy="6.5564812"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1865"
|
||||
inkscape:window-height="1056"
|
||||
inkscape:window-x="55"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1037.3622)">
|
||||
<path
|
||||
style="fill:none;stroke:#bfbfbf;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 10.46875,1032.1747 -14.5,14.2813 z m 3.5,1.2501 -17.3125,17.3124 z"
|
||||
id="path2985"
|
||||
inkscape:connector-curvature="0"
|
||||
clip-path="url(#clipPath3803)"
|
||||
transform="translate(0.8125,0.6875)"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 2.2 KiB |
|
Depois Largura: | Altura: | Tamanho: 560 B |
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="25"
|
||||
height="25"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r"
|
||||
viewBox="0 0 25 25.000001"
|
||||
sodipodi:docname="speech_balloon_white.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="22.4"
|
||||
inkscape:cx="25.186628"
|
||||
inkscape:cy="14.479999"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="1855"
|
||||
inkscape:window-height="1056"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-228.24219,-320.66798)">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 240.77627,324.02578 a 12.489309,7.9254426 0 0 0 -12.48944,7.92538 12.489309,7.9254426 0 0 0 5.26146,6.45637 c -0.17862,1.91196 -1.06119,3.95363 -3.14604,4.64437 2.54121,-0.11444 5.60026,-1.93057 7.47209,-3.40137 a 12.489309,7.9254426 0 0 0 2.90193,0.22616 12.489309,7.9254426 0 0 0 12.48928,-7.92553 12.489309,7.9254426 0 0 0 -12.48928,-7.92538 z"
|
||||
id="path4101"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Depois Largura: | Altura: | Tamanho: 2.3 KiB |
@@ -1,794 +0,0 @@
|
||||
/**
|
||||
* jsxc v0.6.0 - 2014-02-28
|
||||
*
|
||||
* Copyright (c) 2014 Klaus Herberth <klaus@jsxc.org> <br>
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Please see http://jsxc.org/
|
||||
*
|
||||
* @author Klaus Herberth <klaus@jsxc.org>
|
||||
* @version 0.6.0
|
||||
*/
|
||||
|
||||
/* jsxc, Strophe, SDPUtil, getUserMediaWithConstraints, setupRTC, jQuery */
|
||||
|
||||
var RTC = null, RTCPeerconnection = null;
|
||||
|
||||
jsxc.gui.template.incomingCall = '<h3>%%Incoming_call%%</h3>\
|
||||
<p>%%Do_you_want_to_accept_the_call_from%% {{cid_name}}?</p>\
|
||||
<p class="jsxc_right">\
|
||||
<a href="#" class="button jsxc_reject">%%Reject%%</a> <a href="#" class="button creation jsxc_accept">%%Accept%%</a>\
|
||||
</p>';
|
||||
|
||||
jsxc.gui.template.allowMediaAccess = '<p>%%Please_allow_access_to_microphone_and_camera%%</p>';
|
||||
|
||||
jsxc.gui.template.videoWindow = '<div class="jsxc_webrtc">\
|
||||
<div class="jsxc_videoContainer">\
|
||||
<video class="jsxc_localvideo" autoplay></video>\
|
||||
<video class="jsxc_remotevideo" autoplay></video>\
|
||||
<div class="jsxc_status"></div>\
|
||||
</div>\
|
||||
<div class="jsxc_controlbar">\
|
||||
<button type="button" class="jsxc_hangUp">%%hang_up%%</button>\
|
||||
<input type="range" class="jsxc_volume" min="0.0" max="1.0" step="0.05" value="0.5" />\
|
||||
<div class="jsxc_buttongroup">\
|
||||
<button type="button" class="jsxc_snapshot">%%snapshot%%</button><button type="button" class="jsxc_snapshots">▼</button>\
|
||||
</div>\
|
||||
<!-- <button type="button" class="jsxc_mute_local">%%mute_my_audio%%</button>\
|
||||
<button type="button" class="jsxc_pause_local">%%pause_my_video%%</button> --> \
|
||||
<button type="button" class="jsxc_showchat">%%chat%%</button>\
|
||||
<button type="button" class="jsxc_fullscreen">%%fullscreen%%</button>\
|
||||
<button type="button" class="jsxc_info">%%Info%%</button>\
|
||||
</div>\
|
||||
<div class="jsxc_multi">\
|
||||
<div class="jsxc_snapshotbar">\
|
||||
<p>No pictures yet!</p>\
|
||||
</div>\n\
|
||||
<div class="jsxc_chatarea">\
|
||||
<ul></ul>\
|
||||
</div>\
|
||||
<div class="jsxc_infobar"></div>\
|
||||
</div>\
|
||||
</div>';
|
||||
|
||||
(function($) {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* WebRTC namespace for jsxc.
|
||||
*
|
||||
* @namespace jsxc.webrtc
|
||||
*/
|
||||
jsxc.webrtc = {
|
||||
/** strophe connection */
|
||||
conn: null,
|
||||
|
||||
/** local video stream */
|
||||
localStream: null,
|
||||
|
||||
/** remote video stream */
|
||||
remoteStream: null,
|
||||
|
||||
/** jid of the last caller */
|
||||
last_caller: null,
|
||||
|
||||
/** should we auto accept incoming calls? */
|
||||
AUTO_ACCEPT: false,
|
||||
|
||||
/** required disco features */
|
||||
reqVideoFeatures: [ 'urn:xmpp:jingle:apps:rtp:video', 'urn:xmpp:jingle:apps:rtp:audio', 'urn:xmpp:jingle:transports:ice-udp:1' ],
|
||||
|
||||
/** bare jid to current jid mapping */
|
||||
chatJids: {},
|
||||
|
||||
/**
|
||||
* Initialize webrtc plugin.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
*/
|
||||
init: function() {
|
||||
var self = jsxc.webrtc;
|
||||
|
||||
// shortcut
|
||||
self.conn = jsxc.xmpp.conn;
|
||||
|
||||
if (RTC.browser === 'firefox') {
|
||||
self.conn.jingle.media_constraints.mandatory.MozDontOfferDataChannel = true;
|
||||
}
|
||||
|
||||
if (!self.conn.jingle) {
|
||||
jsxc.error('No jingle plugin found!');
|
||||
return;
|
||||
}
|
||||
|
||||
// jingle configuration
|
||||
self.conn.jingle.PRANSWER = false;
|
||||
self.conn.jingle.AUTOACCEPT = false;
|
||||
self.conn.jingle.ice_config = jsxc.storage.getUserItem('iceConfig');
|
||||
self.conn.jingle.MULTIPARTY = false;
|
||||
self.conn.jingle.pc_constraints = RTC.pc_constraints;
|
||||
|
||||
$(document).on('message.jsxc', $.proxy(self.onMessage, self));
|
||||
|
||||
$(document).on('mediaready.jingle', $.proxy(self.onMediaReady, self));
|
||||
$(document).on('mediafailure.jingle', $.proxy(self.onMediaFailure, self));
|
||||
$(document).on('callincoming.jingle', $.proxy(self.onCallIncoming, self));
|
||||
$(document).on('callterminated.jingle', $.proxy(self.onCallTerminated, self));
|
||||
$(document).on('ringing.jingle', $.proxy(self.onCallRinging, self));
|
||||
|
||||
$(document).on('remotestreamadded.jingle', $.proxy(self.onRemoteStreamAdded, self));
|
||||
$(document).on('remotestreamremoved.jingle', $.proxy(self.onRemoteStreamRemoved, self));
|
||||
$(document).on('iceconnectionstatechange.jingle', $.proxy(self.onIceConnectionStateChanged, self));
|
||||
$(document).on('nostuncandidates.jingle', $.proxy(self.noStunCandidates, self));
|
||||
|
||||
if (self.conn.caps) {
|
||||
$(document).on('caps.strophe', $.proxy(self.onCaps, self));
|
||||
}
|
||||
|
||||
self.getTurnCrendentials();
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if cached configuration is valid and if necessary update it.
|
||||
*
|
||||
* @memberOf jsxc.webrtc
|
||||
*/
|
||||
getTurnCrendentials: function() {
|
||||
|
||||
if (!jsxc.options.turnCredentialsPath) {
|
||||
jsxc.debug('No path for TURN credentials defined!');
|
||||
return;
|
||||
}
|
||||
|
||||
var ttl = (jsxc.storage.getUserItem('iceValidity') || 0) - (new Date()).getTime();
|
||||
if (ttl > 0) {
|
||||
// credentials valid
|
||||
|
||||
window.setTimeout(jsxc.webrtc.getTurnCrendentials, ttl + 500);
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax(jsxc.options.turnCredentialsPath, {
|
||||
async: true,
|
||||
success: function(data) {
|
||||
var iceConfig = {
|
||||
iceServers: [ {
|
||||
url: 'turn:' + data.url,
|
||||
credential: data.credential,
|
||||
username: data.username
|
||||
} ]
|
||||
};
|
||||
|
||||
jsxc.webrtc.conn.jingle.ice_config = iceConfig;
|
||||
jsxc.storage.setUserItem('iceConfig', iceConfig);
|
||||
jsxc.storage.setUserItem('iceValidity', (new Date()).getTime() + 1000 * data.ttl);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Add "video" button to window menu.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param event
|
||||
* @param win jQuery window object
|
||||
*/
|
||||
initWindow: function(event, win) {
|
||||
var self = jsxc.webrtc;
|
||||
|
||||
if (!self.conn) {
|
||||
$(document).one('connectionReady.jsxc', function() {
|
||||
self.initWindow(null, win);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var li = $('<li>Video</li>').addClass('jsxc_video');
|
||||
win.find('.jsxc_settings ul').append(li);
|
||||
|
||||
self.updateWindow(win);
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable or disable "video" button and assign full jid.
|
||||
*
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param win jQuery window object
|
||||
*/
|
||||
updateWindow: function(win) {
|
||||
if (!win || win.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = jsxc.webrtc;
|
||||
var jid = win.data('jid');
|
||||
var li = win.find('.jsxc_video');
|
||||
|
||||
// only start video call to a full jid
|
||||
if (Strophe.getResourceFromJid(jid) === null) {
|
||||
var cid = jsxc.jidToCid(jid);
|
||||
var res = jsxc.storage.getUserItem('buddy_' + cid).res;
|
||||
|
||||
if (Array.isArray(res) && res.length === 1) {
|
||||
jid += '/' + res[0];
|
||||
}
|
||||
}
|
||||
|
||||
li.off('click');
|
||||
|
||||
if (self.conn.caps.hasFeatureByJid(jid, self.reqVideoFeatures)) {
|
||||
li.click(function() {
|
||||
self.startCall(jid);
|
||||
});
|
||||
li.removeClass('jsxc_disabled');
|
||||
} else {
|
||||
li.addClass('jsxc_disabled');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if full jid changed.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param e
|
||||
* @param from full jid
|
||||
*/
|
||||
onMessage: function(e, from) {
|
||||
var self = jsxc.webrtc;
|
||||
var bJid = Strophe.getBareJidFromJid(from);
|
||||
|
||||
if (self.chatJids[bJid] !== from) {
|
||||
self.updateWindow(jsxc.gui.getWindow(jsxc.jidToCid(bJid)));
|
||||
self.chatJids[bJid] = from;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Display status message to user.
|
||||
*
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param txt message
|
||||
* @param d duration in ms
|
||||
*/
|
||||
setStatus: function(txt, d) {
|
||||
var status = $('.jsxc_webrtc .jsxc_status');
|
||||
var duration = (typeof d === 'undefined' || d === null) ? 4000 : d;
|
||||
|
||||
if (status.html()) {
|
||||
// attach old messages
|
||||
txt = status.html() + '<br />' + txt;
|
||||
}
|
||||
|
||||
status.html(txt);
|
||||
|
||||
status.css({
|
||||
'margin-left': '-' + (status.width() / 2) + 'px',
|
||||
opacity: 0,
|
||||
display: 'block'
|
||||
});
|
||||
|
||||
status.stop().animate({
|
||||
opacity: 1
|
||||
});
|
||||
|
||||
clearTimeout(status.data('timeout'));
|
||||
|
||||
if (duration === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var to = setTimeout(function() {
|
||||
status.stop().animate({
|
||||
opacity: 0
|
||||
}, function() {
|
||||
status.html('');
|
||||
});
|
||||
}, duration);
|
||||
|
||||
status.data('timeout', to);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update "video" button if we receive cap information.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param event
|
||||
* @param jid
|
||||
*/
|
||||
onCaps: function(event, jid) {
|
||||
var self = jsxc.webrtc;
|
||||
var win = jsxc.gui.getWindow(jsxc.jidToCid(jid));
|
||||
|
||||
if (win.length > 0) {
|
||||
self.updateWindow(win);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called if video/audio is ready. Open window and display some messages.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param event
|
||||
* @param stream
|
||||
*/
|
||||
onMediaReady: function(event, stream) {
|
||||
jsxc.debug('media ready');
|
||||
|
||||
var self = jsxc.webrtc;
|
||||
|
||||
self.localStream = stream;
|
||||
self.conn.jingle.localStream = stream;
|
||||
|
||||
jsxc.gui.showVideoWindow(self.last_caller);
|
||||
|
||||
var i;
|
||||
for (i = 0; i < stream.getAudioTracks().length; i++) {
|
||||
self.setStatus((stream.getAudioTracks().length > 0) ? 'Use local audio device.' : 'No local audio device.');
|
||||
|
||||
jsxc.debug('using audio device "' + stream.getAudioTracks()[i].label + '"');
|
||||
}
|
||||
for (i = 0; i < stream.getVideoTracks().length; i++) {
|
||||
self.setStatus((stream.getVideoTracks().length > 0) ? 'Use local video device.' : 'No local video device.');
|
||||
|
||||
jsxc.debug('using video device "' + stream.getVideoTracks()[i].label + '"');
|
||||
}
|
||||
|
||||
$(document).one('cleanup.dialog.jsxc', $.proxy(self.hangUp, self));
|
||||
$(document).trigger('finish.mediaready.jsxc');
|
||||
},
|
||||
|
||||
/**
|
||||
* Called if media failes.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
*/
|
||||
onMediaFailure: function() {
|
||||
this.setStatus('media failure');
|
||||
},
|
||||
|
||||
/**
|
||||
* Called on incoming call.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param event
|
||||
* @param sid Session id
|
||||
*/
|
||||
onCallIncoming: function(event, sid) {
|
||||
jsxc.debug('incoming call' + sid);
|
||||
|
||||
var self = this;
|
||||
var sess = this.conn.jingle.sessions[sid];
|
||||
var jid = jsxc.jidToCid(sess.peerjid);
|
||||
|
||||
// display notification
|
||||
jsxc.notification.notify(jsxc.translate('%%Incoming call%%'), jsxc.translate('%%from%% ' + jid));
|
||||
|
||||
// send signal to partner
|
||||
sess.sendRinging();
|
||||
|
||||
jsxc.webrtc.last_caller = sess.peerjid;
|
||||
|
||||
jsxc.switchEvents({
|
||||
'mediaready.jingle': function(event, stream) {
|
||||
self.setStatus('Accept call');
|
||||
|
||||
sess.localStream = stream;
|
||||
sess.peerconnection.addStream(stream);
|
||||
|
||||
sess.sendAnswer();
|
||||
sess.accept();
|
||||
},
|
||||
'mediafailure.jingle': function() {
|
||||
sess.sendTerminate('decline');
|
||||
sess.terminate();
|
||||
}
|
||||
});
|
||||
|
||||
if (jsxc.webrtc.AUTO_ACCEPT) {
|
||||
self.reqUserMedia();
|
||||
return;
|
||||
}
|
||||
|
||||
var dialog = jsxc.gui.dialog.open(jsxc.gui.template.get('incomingCall', jsxc.jidToCid(jid)));
|
||||
|
||||
dialog.find('.jsxc_accept').click(function() {
|
||||
self.reqUserMedia();
|
||||
});
|
||||
|
||||
dialog.find('.jsxc_reject').click(function() {
|
||||
jsxc.gui.dialog.close();
|
||||
|
||||
sess.sendTerminate('decline');
|
||||
sess.terminate();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Called if call is terminated.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param event
|
||||
* @param sid Session id
|
||||
* @param reason Reason for termination
|
||||
* @param [text] Optional explanation
|
||||
*/
|
||||
onCallTerminated: function(event, sid, reason, text) {
|
||||
this.setStatus('call terminated ' + sid + (reason ? (': ' + reason + ' ' + text) : ''));
|
||||
|
||||
if (this.localStream) {
|
||||
this.localStream.stop();
|
||||
}
|
||||
|
||||
$('.jsxc_remotevideo')[0].src = "";
|
||||
$('.jsxc_localvideo')[0].src = "";
|
||||
|
||||
this.conn.jingle.localStream = null;
|
||||
this.localStream = null;
|
||||
this.remoteStream = null;
|
||||
|
||||
$('#jsxc_windowList > ul').prepend($('#jsxc_dialog .jsxc_chatarea > ul > li').detach());
|
||||
|
||||
$(document).off('cleanup.dialog.jsxc');
|
||||
$(document).off('error.jingle');
|
||||
jsxc.gui.dialog.close();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remote station is ringing.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
*/
|
||||
onCallRinging: function() {
|
||||
this.setStatus('ringing...', 0);
|
||||
},
|
||||
|
||||
/**
|
||||
* Called if we receive a remote stream.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param event
|
||||
* @param data
|
||||
* @param sid Session id
|
||||
*/
|
||||
onRemoteStreamAdded: function(event, data, sid) {
|
||||
this.setStatus('Remote stream for session ' + sid + ' added.');
|
||||
|
||||
var stream = data.stream;
|
||||
this.remoteStream = stream;
|
||||
|
||||
var sess = this.conn.jingle.sessions[sid];
|
||||
|
||||
var isVideoDevice = stream.getVideoTracks().length > 0;
|
||||
var isAudioDevice = stream.getAudioTracks().length > 0;
|
||||
|
||||
sess.remoteDevices = {
|
||||
video: isVideoDevice,
|
||||
audio: isAudioDevice
|
||||
};
|
||||
|
||||
this.setStatus(isVideoDevice ? 'Use remote video device.' : 'No remote video device');
|
||||
this.setStatus(isAudioDevice ? 'Use remote audio device.' : 'No remote audio device');
|
||||
|
||||
if ($('.jsxc_remotevideo').length) {
|
||||
RTC.attachMediaStream($('.jsxc_remotevideo'), stream);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called if the remote stream was removed.
|
||||
*
|
||||
* @private
|
||||
* @meberOf jsxc.webrtc
|
||||
* @param event
|
||||
* @param data
|
||||
* @param sid Session id
|
||||
*/
|
||||
onRemoteStreamRemoved: function(event, data, sid) {
|
||||
this.setStatus('Remote stream for session ' + sid + ' removed.');
|
||||
},
|
||||
|
||||
/**
|
||||
* Extracts local and remote ip and display it to the user.
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param event
|
||||
* @param sid session id
|
||||
* @param sess
|
||||
*/
|
||||
onIceConnectionStateChanged: function(event, sid, sess) {
|
||||
var sigState = sess.peerconnection.signalingState;
|
||||
var iceCon = sess.peerconnection.iceConnectionState;
|
||||
|
||||
jsxc.debug('iceGat state for ' + sid, sess.peerconnection.iceGatheringState);
|
||||
jsxc.debug('iceCon state for ' + sid, iceCon);
|
||||
jsxc.debug('sig state for ' + sid, sigState);
|
||||
|
||||
if (sigState === 'stable' && iceCon === 'connected') {
|
||||
var localSDP = sess.peerconnection.localDescription.sdp;
|
||||
var remoteSDP = sess.peerconnection.remoteDescription.sdp;
|
||||
|
||||
sess.local_fp = SDPUtil.parse_fingerprint(SDPUtil.find_line(localSDP, 'a=fingerprint:')).fingerprint;
|
||||
sess.remote_fp = SDPUtil.parse_fingerprint(SDPUtil.find_line(remoteSDP, 'a=fingerprint:')).fingerprint;
|
||||
|
||||
var ip_regex = "(\\d{1,3}\\.\\d{1,3}.\\d{1,3}\\.\\d{1,3}) \\d+ typ host";
|
||||
|
||||
sess.remote_ip = remoteSDP.match(new RegExp(ip_regex))[1];
|
||||
sess.local_ip = localSDP.match(new RegExp(ip_regex))[1];
|
||||
|
||||
var regex = new RegExp(ip_regex, 'g');
|
||||
var match;
|
||||
while ((match = regex.exec(remoteSDP)) !== null) {
|
||||
if (match[1] !== sess.remote_ip) {
|
||||
alert('!!! WARNING !!!\n\nPossible Man-in-the-middle attack detected!\n\nYou should close the connection.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var text = '<p>';
|
||||
text += '<b>' + jsxc.translate('%%Local IP%%: ') + '</b>' + sess.local_ip + '<br />';
|
||||
text += '<b>' + jsxc.translate('%%Remote IP%%: ') + '</b>' + sess.remote_ip + '<br />';
|
||||
text += '<b>' + jsxc.translate('%%Local Fingerprint%%: ') + '</b>' + sess.local_fp + '<br />';
|
||||
text += '<b>' + jsxc.translate('%%Remote Fingerprint%%: ') + '</b>' + sess.remote_fp;
|
||||
text += '</p>';
|
||||
|
||||
$('#jsxc_dialog .jsxc_infobar').html(text);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* No STUN candidates found
|
||||
*
|
||||
* @private
|
||||
* @memberOf jsxc.webrtc
|
||||
*/
|
||||
noStunCandidates: function() {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Start a call to the specified jid.
|
||||
*
|
||||
* @memberOf jsxc.webrtc
|
||||
* @param jid full jid
|
||||
*/
|
||||
startCall: function(jid) {
|
||||
var self = this;
|
||||
|
||||
if (Strophe.getResourceFromJid(jid) === null) {
|
||||
jsxc.debug('We need a full jid');
|
||||
return;
|
||||
}
|
||||
|
||||
self.last_caller = jid;
|
||||
|
||||
jsxc.switchEvents({
|
||||
'finish.mediaready.jsxc': function() {
|
||||
self.setStatus('Initiate call');
|
||||
|
||||
$(document).one('error.jingle', function(e, sid, error) {
|
||||
if (error.source !== 'offer') {
|
||||
return;
|
||||
}
|
||||
|
||||
self.conn.jingle.terminate(null, 'init fail');
|
||||
|
||||
$(document).off('cleanup.dialog.jsxc');
|
||||
setTimeout(function() {
|
||||
jsxc.gui.showAlert("Sorry, we couldn't establish a connection. Maybe your buddy is offline.");
|
||||
}, 500);
|
||||
});
|
||||
|
||||
self.conn.jingle.initiate(jid, self.conn.jid.toLowerCase());
|
||||
},
|
||||
'mediafailure.jingle': function() {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
this.reqUserMedia();
|
||||
},
|
||||
|
||||
/**
|
||||
* Hang up the current call.
|
||||
*
|
||||
* @memberOf jsxc.webrtc
|
||||
*/
|
||||
hangUp: function() {
|
||||
$(document).off('cleanup.dialog.jsxc');
|
||||
|
||||
jsxc.webrtc.conn.jingle.terminate(null);
|
||||
$(document).trigger('callterminated.jingle');
|
||||
},
|
||||
|
||||
/**
|
||||
* Request video and audio from local user.
|
||||
*
|
||||
* @memberOf jsxc.webrtc
|
||||
*/
|
||||
reqUserMedia: function() {
|
||||
if (this.localStream) {
|
||||
$(document).trigger('mediaready.jingle', [ this.localStream ]);
|
||||
return;
|
||||
}
|
||||
|
||||
jsxc.gui.dialog.open(jsxc.gui.template.get('allowMediaAccess'), {
|
||||
noClose: true
|
||||
});
|
||||
this.setStatus('please allow access to microphone and camera');
|
||||
|
||||
getUserMediaWithConstraints([ 'video', 'audio' ]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Make a snapshot from a video stream and display it.
|
||||
*
|
||||
* @memberOf
|
||||
* @param video Video stream
|
||||
*/
|
||||
snapshot: function(video) {
|
||||
if (!video) {
|
||||
jsxc.debug('Missing video element');
|
||||
}
|
||||
|
||||
$('.jsxc_snapshotbar p').remove();
|
||||
|
||||
var canvas = $('<canvas/>').css('display', 'none').appendTo('body').attr({
|
||||
width: video.width(),
|
||||
height: video.height()
|
||||
}).get(0);
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.drawImage(video[0], 0, 0);
|
||||
var img = $('<img/>');
|
||||
var url = canvas.toDataURL('image/jpeg');
|
||||
img[0].src = url;
|
||||
var link = $('<a/>').attr({
|
||||
target: '_blank',
|
||||
href: url
|
||||
});
|
||||
link.append(img);
|
||||
$('.jsxc_snapshotbar').append(link);
|
||||
|
||||
canvas.remove();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Display window for video call.
|
||||
*
|
||||
* @memberOf jsxc.gui
|
||||
*/
|
||||
jsxc.gui.showVideoWindow = function(jid) {
|
||||
var self = jsxc.webrtc;
|
||||
|
||||
$(document).one('complete.dialog.jsxc', function() {
|
||||
|
||||
// mute own video element to avoid echoes
|
||||
$('#jsxc_dialog .jsxc_localvideo')[0].muted = true;
|
||||
$('#jsxc_dialog .jsxc_localvideo')[0].volume = 0;
|
||||
|
||||
var rv = $('#jsxc_dialog .jsxc_remotevideo');
|
||||
var lv = $('#jsxc_dialog .jsxc_localvideo');
|
||||
|
||||
lv.draggable({
|
||||
containment: "parent"
|
||||
});
|
||||
|
||||
RTC.attachMediaStream(lv, self.localStream);
|
||||
|
||||
var w_dialog = $('#jsxc_dialog').width();
|
||||
var w_remote = rv.width();
|
||||
|
||||
// fit in video
|
||||
if (w_remote > w_dialog) {
|
||||
var scale = w_dialog / w_remote;
|
||||
var new_h = rv.height() * scale;
|
||||
var new_w = w_dialog;
|
||||
var vc = $('#jsxc_dialog .jsxc_videoContainer');
|
||||
|
||||
rv.height(new_h);
|
||||
rv.width(new_w);
|
||||
|
||||
vc.height(new_h);
|
||||
vc.width(new_w);
|
||||
|
||||
lv.height(lv.height() * scale);
|
||||
lv.width(lv.width() * scale);
|
||||
}
|
||||
|
||||
if (self.remoteStream) {
|
||||
RTC.attachMediaStream(rv, self.remoteStream);
|
||||
}
|
||||
|
||||
var toggleMulti = function(elem, open) {
|
||||
$('#jsxc_dialog .jsxc_multi > div').not(elem).slideUp();
|
||||
|
||||
var opt = {
|
||||
complete: jsxc.gui.dialog.resize
|
||||
};
|
||||
|
||||
if (open) {
|
||||
elem.slideDown(opt);
|
||||
} else {
|
||||
elem.slideToggle(opt);
|
||||
}
|
||||
};
|
||||
|
||||
var win = jsxc.gui.window.open(jsxc.jidToCid(jid));
|
||||
|
||||
$('#jsxc_dialog .jsxc_chatarea ul').append(win.detach());
|
||||
|
||||
$('#jsxc_dialog .jsxc_hangUp').click(function() {
|
||||
jsxc.webrtc.hangUp();
|
||||
});
|
||||
|
||||
$('#jsxc_dialog .jsxc_snapshot').click(function() {
|
||||
jsxc.webrtc.snapshot(rv);
|
||||
toggleMulti($('#jsxc_dialog .jsxc_snapshotbar'), true);
|
||||
});
|
||||
|
||||
$('#jsxc_dialog .jsxc_snapshots').click(function() {
|
||||
toggleMulti($('#jsxc_dialog .jsxc_snapshotbar'));
|
||||
});
|
||||
|
||||
$('#jsxc_dialog .jsxc_showchat').click(function() {
|
||||
toggleMulti($('#jsxc_dialog .jsxc_chatarea'));
|
||||
});
|
||||
|
||||
$('#jsxc_dialog .jsxc_info').click(function() {
|
||||
toggleMulti($('#jsxc_dialog .jsxc_infobar'));
|
||||
});
|
||||
|
||||
$('#jsxc_dialog .jsxc_fullscreen').click(function() {
|
||||
|
||||
if ($.support.fullscreen) {
|
||||
// Reset position of localvideo
|
||||
$(document).one('disabled.fullscreen', function() {
|
||||
lv.removeAttr('style');
|
||||
});
|
||||
|
||||
$('#jsxc_dialog .jsxc_videoContainer').fullscreen();
|
||||
}
|
||||
});
|
||||
|
||||
$('#jsxc_dialog .jsxc_volume').change(function() {
|
||||
rv[0].volume = $(this).val();
|
||||
});
|
||||
|
||||
$('#jsxc_dialog .jsxc_volume').dblclick(function() {
|
||||
$(this).val(0.5);
|
||||
});
|
||||
});
|
||||
|
||||
jsxc.gui.dialog.open(jsxc.gui.template.get('videoWindow'), {
|
||||
noClose: true
|
||||
});
|
||||
};
|
||||
|
||||
$.extend(jsxc.CONST, {
|
||||
KEYCODE_ENTER: 13,
|
||||
KEYCODE_ESC: 27
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
RTC = setupRTC();
|
||||
|
||||
if (RTC !== null) {
|
||||
RTCPeerconnection = RTC.peerconnection;
|
||||
|
||||
$(document).on('init.window.jsxc', jsxc.webrtc.initWindow);
|
||||
$(document).on('attached.jsxc', jsxc.webrtc.init);
|
||||
}
|
||||
});
|
||||
}(jQuery));
|
||||
@@ -0,0 +1,851 @@
|
||||
/**
|
||||
* @license MIT
|
||||
* @fileOverview Favico animations
|
||||
* @author Miroslav Magda, http://blog.ejci.net
|
||||
* @version 0.3.9
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create new favico instance
|
||||
* @param {Object} Options
|
||||
* @return {Object} Favico object
|
||||
* @example
|
||||
* var favico = new Favico({
|
||||
* bgColor : '#d00',
|
||||
* textColor : '#fff',
|
||||
* fontFamily : 'sans-serif',
|
||||
* fontStyle : 'bold',
|
||||
* position : 'down',
|
||||
* type : 'circle',
|
||||
* animation : 'slide',
|
||||
* dataUrl: function(url){},
|
||||
* win: top
|
||||
* });
|
||||
*/
|
||||
(function() {
|
||||
|
||||
var Favico = (function(opt) {
|
||||
'use strict';
|
||||
opt = (opt) ? opt : {};
|
||||
var _def = {
|
||||
bgColor : '#d00',
|
||||
textColor : '#fff',
|
||||
fontFamily : 'sans-serif', //Arial,Verdana,Times New Roman,serif,sans-serif,...
|
||||
fontStyle : 'bold', //normal,italic,oblique,bold,bolder,lighter,100,200,300,400,500,600,700,800,900
|
||||
type : 'circle',
|
||||
position : 'down', // down, up, left, leftup (upleft)
|
||||
animation : 'slide',
|
||||
elementId : false,
|
||||
dataUrl : false,
|
||||
win: window
|
||||
};
|
||||
var _opt, _orig, _h, _w, _canvas, _context, _img, _ready, _lastBadge, _running, _readyCb, _stop, _browser, _animTimeout, _drawTimeout, _doc;
|
||||
|
||||
_browser = {};
|
||||
_browser.ff = typeof InstallTrigger != 'undefined';
|
||||
_browser.chrome = !!window.chrome;
|
||||
_browser.opera = !!window.opera || navigator.userAgent.indexOf('Opera') >= 0;
|
||||
_browser.ie = /*@cc_on!@*/false;
|
||||
_browser.safari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
|
||||
_browser.supported = (_browser.chrome || _browser.ff || _browser.opera);
|
||||
|
||||
var _queue = [];
|
||||
_readyCb = function() {
|
||||
};
|
||||
_ready = _stop = false;
|
||||
/**
|
||||
* Initialize favico
|
||||
*/
|
||||
var init = function() {
|
||||
//merge initial options
|
||||
_opt = merge(_def, opt);
|
||||
_opt.bgColor = hexToRgb(_opt.bgColor);
|
||||
_opt.textColor = hexToRgb(_opt.textColor);
|
||||
_opt.position = _opt.position.toLowerCase();
|
||||
_opt.animation = (animation.types['' + _opt.animation]) ? _opt.animation : _def.animation;
|
||||
|
||||
_doc = _opt.win.document;
|
||||
|
||||
var isUp = _opt.position.indexOf('up') > -1;
|
||||
var isLeft = _opt.position.indexOf('left') > -1;
|
||||
|
||||
//transform animation
|
||||
if (isUp || isLeft) {
|
||||
for (var i = 0; i < animation.types['' + _opt.animation].length; i++) {
|
||||
var step = animation.types['' + _opt.animation][i];
|
||||
|
||||
if (isUp) {
|
||||
if (step.y < 0.6) {
|
||||
step.y = step.y - 0.4;
|
||||
} else {
|
||||
step.y = step.y - 2 * step.y + (1 - step.w);
|
||||
}
|
||||
}
|
||||
|
||||
if (isLeft) {
|
||||
if (step.x < 0.6) {
|
||||
step.x = step.x - 0.4;
|
||||
} else {
|
||||
step.x = step.x - 2 * step.x + (1 - step.h);
|
||||
}
|
||||
}
|
||||
|
||||
animation.types['' + _opt.animation][i] = step;
|
||||
}
|
||||
}
|
||||
_opt.type = (type['' + _opt.type]) ? _opt.type : _def.type;
|
||||
|
||||
_orig = link.getIcon();
|
||||
//create temp canvas
|
||||
_canvas = document.createElement('canvas');
|
||||
//create temp image
|
||||
_img = document.createElement('img');
|
||||
if (_orig.hasAttribute('href')) {
|
||||
_img.setAttribute('crossOrigin', 'anonymous');
|
||||
_img.setAttribute('src', _orig.getAttribute('href'));
|
||||
//get width/height
|
||||
_img.onload = function() {
|
||||
_h = (_img.height > 0) ? _img.height : 32;
|
||||
_w = (_img.width > 0) ? _img.width : 32;
|
||||
_canvas.height = _h;
|
||||
_canvas.width = _w;
|
||||
_context = _canvas.getContext('2d');
|
||||
icon.ready();
|
||||
};
|
||||
} else {
|
||||
_img.setAttribute('src', '');
|
||||
_h = 32;
|
||||
_w = 32;
|
||||
_img.height = _h;
|
||||
_img.width = _w;
|
||||
_canvas.height = _h;
|
||||
_canvas.width = _w;
|
||||
_context = _canvas.getContext('2d');
|
||||
icon.ready();
|
||||
}
|
||||
|
||||
};
|
||||
/**
|
||||
* Icon namespace
|
||||
*/
|
||||
var icon = {};
|
||||
/**
|
||||
* Icon is ready (reset icon) and start animation (if ther is any)
|
||||
*/
|
||||
icon.ready = function() {
|
||||
_ready = true;
|
||||
icon.reset();
|
||||
_readyCb();
|
||||
};
|
||||
/**
|
||||
* Reset icon to default state
|
||||
*/
|
||||
icon.reset = function() {
|
||||
//reset
|
||||
if (!_ready) {
|
||||
return;
|
||||
}
|
||||
_queue = [];
|
||||
_lastBadge = false;
|
||||
_running = false;
|
||||
_context.clearRect(0, 0, _w, _h);
|
||||
_context.drawImage(_img, 0, 0, _w, _h);
|
||||
//_stop=true;
|
||||
link.setIcon(_canvas);
|
||||
//webcam('stop');
|
||||
//video('stop');
|
||||
window.clearTimeout(_animTimeout);
|
||||
window.clearTimeout(_drawTimeout);
|
||||
};
|
||||
/**
|
||||
* Start animation
|
||||
*/
|
||||
icon.start = function() {
|
||||
if (!_ready || _running) {
|
||||
return;
|
||||
}
|
||||
var finished = function() {
|
||||
_lastBadge = _queue[0];
|
||||
_running = false;
|
||||
if (_queue.length > 0) {
|
||||
_queue.shift();
|
||||
icon.start();
|
||||
} else {
|
||||
|
||||
}
|
||||
};
|
||||
if (_queue.length > 0) {
|
||||
_running = true;
|
||||
var run = function() {
|
||||
// apply options for this animation
|
||||
['type', 'animation', 'bgColor', 'textColor', 'fontFamily', 'fontStyle'].forEach(function(a) {
|
||||
if ( a in _queue[0].options) {
|
||||
_opt[a] = _queue[0].options[a];
|
||||
}
|
||||
});
|
||||
animation.run(_queue[0].options, function() {
|
||||
finished();
|
||||
}, false);
|
||||
};
|
||||
if (_lastBadge) {
|
||||
animation.run(_lastBadge.options, function() {
|
||||
run();
|
||||
}, true);
|
||||
} else {
|
||||
run();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Badge types
|
||||
*/
|
||||
var type = {};
|
||||
var options = function(opt) {
|
||||
opt.n = (( typeof opt.n) === 'number') ? Math.abs(opt.n | 0) : opt.n;
|
||||
opt.x = _w * opt.x;
|
||||
opt.y = _h * opt.y;
|
||||
opt.w = _w * opt.w;
|
||||
opt.h = _h * opt.h;
|
||||
opt.len = ("" + opt.n).length;
|
||||
return opt;
|
||||
};
|
||||
/**
|
||||
* Generate circle
|
||||
* @param {Object} opt Badge options
|
||||
*/
|
||||
type.circle = function(opt) {
|
||||
opt = options(opt);
|
||||
var more = false;
|
||||
if (opt.len === 2) {
|
||||
opt.x = opt.x - opt.w * 0.4;
|
||||
opt.w = opt.w * 1.4;
|
||||
more = true;
|
||||
} else if (opt.len >= 3) {
|
||||
opt.x = opt.x - opt.w * 0.65;
|
||||
opt.w = opt.w * 1.65;
|
||||
more = true;
|
||||
}
|
||||
_context.clearRect(0, 0, _w, _h);
|
||||
_context.drawImage(_img, 0, 0, _w, _h);
|
||||
_context.beginPath();
|
||||
_context.font = _opt.fontStyle + " " + Math.floor(opt.h * (opt.n > 99 ? 0.85 : 1)) + "px " + _opt.fontFamily;
|
||||
_context.textAlign = 'center';
|
||||
if (more) {
|
||||
_context.moveTo(opt.x + opt.w / 2, opt.y);
|
||||
_context.lineTo(opt.x + opt.w - opt.h / 2, opt.y);
|
||||
_context.quadraticCurveTo(opt.x + opt.w, opt.y, opt.x + opt.w, opt.y + opt.h / 2);
|
||||
_context.lineTo(opt.x + opt.w, opt.y + opt.h - opt.h / 2);
|
||||
_context.quadraticCurveTo(opt.x + opt.w, opt.y + opt.h, opt.x + opt.w - opt.h / 2, opt.y + opt.h);
|
||||
_context.lineTo(opt.x + opt.h / 2, opt.y + opt.h);
|
||||
_context.quadraticCurveTo(opt.x, opt.y + opt.h, opt.x, opt.y + opt.h - opt.h / 2);
|
||||
_context.lineTo(opt.x, opt.y + opt.h / 2);
|
||||
_context.quadraticCurveTo(opt.x, opt.y, opt.x + opt.h / 2, opt.y);
|
||||
} else {
|
||||
_context.arc(opt.x + opt.w / 2, opt.y + opt.h / 2, opt.h / 2, 0, 2 * Math.PI);
|
||||
}
|
||||
_context.fillStyle = 'rgba(' + _opt.bgColor.r + ',' + _opt.bgColor.g + ',' + _opt.bgColor.b + ',' + opt.o + ')';
|
||||
_context.fill();
|
||||
_context.closePath();
|
||||
_context.beginPath();
|
||||
_context.stroke();
|
||||
_context.fillStyle = 'rgba(' + _opt.textColor.r + ',' + _opt.textColor.g + ',' + _opt.textColor.b + ',' + opt.o + ')';
|
||||
//_context.fillText((more) ? '9+' : opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
|
||||
if (( typeof opt.n) === 'number' && opt.n > 999) {
|
||||
_context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000) ) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2));
|
||||
} else {
|
||||
_context.fillText(opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
|
||||
}
|
||||
_context.closePath();
|
||||
};
|
||||
/**
|
||||
* Generate rectangle
|
||||
* @param {Object} opt Badge options
|
||||
*/
|
||||
type.rectangle = function(opt) {
|
||||
opt = options(opt);
|
||||
var more = false;
|
||||
if (opt.len === 2) {
|
||||
opt.x = opt.x - opt.w * 0.4;
|
||||
opt.w = opt.w * 1.4;
|
||||
more = true;
|
||||
} else if (opt.len >= 3) {
|
||||
opt.x = opt.x - opt.w * 0.65;
|
||||
opt.w = opt.w * 1.65;
|
||||
more = true;
|
||||
}
|
||||
_context.clearRect(0, 0, _w, _h);
|
||||
_context.drawImage(_img, 0, 0, _w, _h);
|
||||
_context.beginPath();
|
||||
_context.font = _opt.fontStyle + " " + Math.floor(opt.h * (opt.n > 99 ? 0.9 : 1)) + "px " + _opt.fontFamily;
|
||||
_context.textAlign = 'center';
|
||||
_context.fillStyle = 'rgba(' + _opt.bgColor.r + ',' + _opt.bgColor.g + ',' + _opt.bgColor.b + ',' + opt.o + ')';
|
||||
_context.fillRect(opt.x, opt.y, opt.w, opt.h);
|
||||
_context.fillStyle = 'rgba(' + _opt.textColor.r + ',' + _opt.textColor.g + ',' + _opt.textColor.b + ',' + opt.o + ')';
|
||||
//_context.fillText((more) ? '9+' : opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
|
||||
if (( typeof opt.n) === 'number' && opt.n > 999) {
|
||||
_context.fillText(((opt.n > 9999) ? 9 : Math.floor(opt.n / 1000) ) + 'k+', Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.2));
|
||||
} else {
|
||||
_context.fillText(opt.n, Math.floor(opt.x + opt.w / 2), Math.floor(opt.y + opt.h - opt.h * 0.15));
|
||||
}
|
||||
_context.closePath();
|
||||
};
|
||||
|
||||
/**
|
||||
* Set badge
|
||||
*/
|
||||
var badge = function(number, opts) {
|
||||
opts = (( typeof opts) === 'string' ? {
|
||||
animation : opts
|
||||
} : opts) || {};
|
||||
_readyCb = function() {
|
||||
try {
|
||||
if ( typeof (number) === 'number' ? (number > 0) : (number !== '')) {
|
||||
var q = {
|
||||
type : 'badge',
|
||||
options : {
|
||||
n : number
|
||||
}
|
||||
};
|
||||
if ('animation' in opts && animation.types['' + opts.animation]) {
|
||||
q.options.animation = '' + opts.animation;
|
||||
}
|
||||
if ('type' in opts && type['' + opts.type]) {
|
||||
q.options.type = '' + opts.type;
|
||||
}
|
||||
['bgColor', 'textColor'].forEach(function(o) {
|
||||
if ( o in opts) {
|
||||
q.options[o] = hexToRgb(opts[o]);
|
||||
}
|
||||
});
|
||||
['fontStyle', 'fontFamily'].forEach(function(o) {
|
||||
if ( o in opts) {
|
||||
q.options[o] = opts[o];
|
||||
}
|
||||
});
|
||||
_queue.push(q);
|
||||
if (_queue.length > 100) {
|
||||
throw new Error('Too many badges requests in queue.');
|
||||
}
|
||||
icon.start();
|
||||
} else {
|
||||
icon.reset();
|
||||
}
|
||||
} catch(e) {
|
||||
throw new Error('Error setting badge. Message: ' + e.message);
|
||||
}
|
||||
};
|
||||
if (_ready) {
|
||||
_readyCb();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set image as icon
|
||||
*/
|
||||
var image = function(imageElement) {
|
||||
_readyCb = function() {
|
||||
try {
|
||||
var w = imageElement.width;
|
||||
var h = imageElement.height;
|
||||
var newImg = document.createElement('img');
|
||||
var ratio = (w / _w < h / _h) ? (w / _w) : (h / _h);
|
||||
newImg.setAttribute('crossOrigin', 'anonymous');
|
||||
newImg.setAttribute('src', imageElement.getAttribute('src'));
|
||||
newImg.height = (h / ratio);
|
||||
newImg.width = (w / ratio);
|
||||
_context.clearRect(0, 0, _w, _h);
|
||||
_context.drawImage(newImg, 0, 0, _w, _h);
|
||||
link.setIcon(_canvas);
|
||||
} catch(e) {
|
||||
throw new Error('Error setting image. Message: ' + e.message);
|
||||
}
|
||||
};
|
||||
if (_ready) {
|
||||
_readyCb();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Set video as icon
|
||||
*/
|
||||
var video = function(videoElement) {
|
||||
_readyCb = function() {
|
||||
try {
|
||||
if (videoElement === 'stop') {
|
||||
_stop = true;
|
||||
icon.reset();
|
||||
_stop = false;
|
||||
return;
|
||||
}
|
||||
//var w = videoElement.width;
|
||||
//var h = videoElement.height;
|
||||
//var ratio = (w / _w < h / _h) ? (w / _w) : (h / _h);
|
||||
videoElement.addEventListener('play', function() {
|
||||
drawVideo(this);
|
||||
}, false);
|
||||
|
||||
} catch(e) {
|
||||
throw new Error('Error setting video. Message: ' + e.message);
|
||||
}
|
||||
};
|
||||
if (_ready) {
|
||||
_readyCb();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Set video as icon
|
||||
*/
|
||||
var webcam = function(action) {
|
||||
//UR
|
||||
if (!window.URL || !window.URL.createObjectURL) {
|
||||
window.URL = window.URL || {};
|
||||
window.URL.createObjectURL = function(obj) {
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
if (_browser.supported) {
|
||||
var newVideo = false;
|
||||
navigator.getUserMedia = navigator.getUserMedia || navigator.oGetUserMedia || navigator.msGetUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
|
||||
_readyCb = function() {
|
||||
try {
|
||||
if (action === 'stop') {
|
||||
_stop = true;
|
||||
icon.reset();
|
||||
_stop = false;
|
||||
return;
|
||||
}
|
||||
newVideo = document.createElement('video');
|
||||
newVideo.width = _w;
|
||||
newVideo.height = _h;
|
||||
navigator.getUserMedia({
|
||||
video : true,
|
||||
audio : false
|
||||
}, function(stream) {
|
||||
newVideo.src = URL.createObjectURL(stream);
|
||||
newVideo.play();
|
||||
drawVideo(newVideo);
|
||||
}, function() {
|
||||
});
|
||||
} catch(e) {
|
||||
throw new Error('Error setting webcam. Message: ' + e.message);
|
||||
}
|
||||
};
|
||||
if (_ready) {
|
||||
_readyCb();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Draw video to context and repeat :)
|
||||
*/
|
||||
function drawVideo(video) {
|
||||
if (video.paused || video.ended || _stop) {
|
||||
return false;
|
||||
}
|
||||
//nasty hack for FF webcam (Thanks to Julian Ćwirko, kontakt@redsunmedia.pl)
|
||||
try {
|
||||
_context.clearRect(0, 0, _w, _h);
|
||||
_context.drawImage(video, 0, 0, _w, _h);
|
||||
} catch(e) {
|
||||
|
||||
}
|
||||
_drawTimeout = setTimeout(drawVideo, animation.duration, video);
|
||||
link.setIcon(_canvas);
|
||||
}
|
||||
|
||||
var link = {};
|
||||
/**
|
||||
* Get icon from HEAD tag or create a new <link> element
|
||||
*/
|
||||
link.getIcon = function() {
|
||||
var elm = false;
|
||||
//get link element
|
||||
var getLink = function() {
|
||||
var link = _doc.getElementsByTagName('head')[0].getElementsByTagName('link');
|
||||
for (var l = link.length, i = (l - 1); i >= 0; i--) {
|
||||
if ((/(^|\s)icon(\s|$)/i).test(link[i].getAttribute('rel'))) {
|
||||
return link[i];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (_opt.element) {
|
||||
elm = _opt.element;
|
||||
} else if (_opt.elementId) {
|
||||
//if img element identified by elementId
|
||||
elm = _doc.getElementById(_opt.elementId);
|
||||
elm.setAttribute('href', elm.getAttribute('src'));
|
||||
} else {
|
||||
//if link element
|
||||
elm = getLink();
|
||||
if (elm === false) {
|
||||
elm = _doc.createElement('link');
|
||||
elm.setAttribute('rel', 'icon');
|
||||
_doc.getElementsByTagName('head')[0].appendChild(elm);
|
||||
}
|
||||
}
|
||||
elm.setAttribute('type', 'image/png');
|
||||
return elm;
|
||||
};
|
||||
link.setIcon = function(canvas) {
|
||||
var url = canvas.toDataURL('image/png');
|
||||
if (_opt.dataUrl) {
|
||||
//if using custom exporter
|
||||
_opt.dataUrl(url);
|
||||
}
|
||||
if (_opt.element) {
|
||||
_opt.element.setAttribute('href', url);
|
||||
_opt.element.setAttribute('src', url);
|
||||
} else if (_opt.elementId) {
|
||||
//if is attached to element (image)
|
||||
var elm = _doc.getElementById(_opt.elementId);
|
||||
elm.setAttribute('href', url);
|
||||
elm.setAttribute('src', url);
|
||||
} else {
|
||||
//if is attached to fav icon
|
||||
if (_browser.ff || _browser.opera) {
|
||||
//for FF we need to "recreate" element, atach to dom and remove old <link>
|
||||
//var originalType = _orig.getAttribute('rel');
|
||||
var old = _orig;
|
||||
_orig = _doc.createElement('link');
|
||||
//_orig.setAttribute('rel', originalType);
|
||||
if (_browser.opera) {
|
||||
_orig.setAttribute('rel', 'icon');
|
||||
}
|
||||
_orig.setAttribute('rel', 'icon');
|
||||
_orig.setAttribute('type', 'image/png');
|
||||
_doc.getElementsByTagName('head')[0].appendChild(_orig);
|
||||
_orig.setAttribute('href', url);
|
||||
if (old.parentNode) {
|
||||
old.parentNode.removeChild(old);
|
||||
}
|
||||
} else {
|
||||
_orig.setAttribute('href', url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb#answer-5624139
|
||||
//HEX to RGB convertor
|
||||
function hexToRgb(hex) {
|
||||
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
||||
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
|
||||
return r + r + g + g + b + b;
|
||||
});
|
||||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
return result ? {
|
||||
r : parseInt(result[1], 16),
|
||||
g : parseInt(result[2], 16),
|
||||
b : parseInt(result[3], 16)
|
||||
} : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge options
|
||||
*/
|
||||
function merge(def, opt) {
|
||||
var mergedOpt = {};
|
||||
var attrname;
|
||||
for (attrname in def) {
|
||||
mergedOpt[attrname] = def[attrname];
|
||||
}
|
||||
for (attrname in opt) {
|
||||
mergedOpt[attrname] = opt[attrname];
|
||||
}
|
||||
return mergedOpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cross-browser page visibility shim
|
||||
* http://stackoverflow.com/questions/12536562/detect-whether-a-window-is-visible
|
||||
*/
|
||||
function isPageHidden() {
|
||||
return _doc.hidden || _doc.msHidden || _doc.webkitHidden || _doc.mozHidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* @namespace animation
|
||||
*/
|
||||
var animation = {};
|
||||
/**
|
||||
* Animation "frame" duration
|
||||
*/
|
||||
animation.duration = 40;
|
||||
/**
|
||||
* Animation types (none,fade,pop,slide)
|
||||
*/
|
||||
animation.types = {};
|
||||
animation.types.fade = [{
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.0
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.2
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.3
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.4
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.5
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.6
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.7
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.8
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 0.9
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1.0
|
||||
}];
|
||||
animation.types.none = [{
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}];
|
||||
animation.types.pop = [{
|
||||
x : 1,
|
||||
y : 1,
|
||||
w : 0,
|
||||
h : 0,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.9,
|
||||
y : 0.9,
|
||||
w : 0.1,
|
||||
h : 0.1,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.8,
|
||||
y : 0.8,
|
||||
w : 0.2,
|
||||
h : 0.2,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.7,
|
||||
y : 0.7,
|
||||
w : 0.3,
|
||||
h : 0.3,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.6,
|
||||
y : 0.6,
|
||||
w : 0.4,
|
||||
h : 0.4,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.5,
|
||||
y : 0.5,
|
||||
w : 0.5,
|
||||
h : 0.5,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}];
|
||||
animation.types.popFade = [{
|
||||
x : 0.75,
|
||||
y : 0.75,
|
||||
w : 0,
|
||||
h : 0,
|
||||
o : 0
|
||||
}, {
|
||||
x : 0.65,
|
||||
y : 0.65,
|
||||
w : 0.1,
|
||||
h : 0.1,
|
||||
o : 0.2
|
||||
}, {
|
||||
x : 0.6,
|
||||
y : 0.6,
|
||||
w : 0.2,
|
||||
h : 0.2,
|
||||
o : 0.4
|
||||
}, {
|
||||
x : 0.55,
|
||||
y : 0.55,
|
||||
w : 0.3,
|
||||
h : 0.3,
|
||||
o : 0.6
|
||||
}, {
|
||||
x : 0.50,
|
||||
y : 0.50,
|
||||
w : 0.4,
|
||||
h : 0.4,
|
||||
o : 0.8
|
||||
}, {
|
||||
x : 0.45,
|
||||
y : 0.45,
|
||||
w : 0.5,
|
||||
h : 0.5,
|
||||
o : 0.9
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}];
|
||||
animation.types.slide = [{
|
||||
x : 0.4,
|
||||
y : 1,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.9,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.9,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.8,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.7,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.6,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.5,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}, {
|
||||
x : 0.4,
|
||||
y : 0.4,
|
||||
w : 0.6,
|
||||
h : 0.6,
|
||||
o : 1
|
||||
}];
|
||||
/**
|
||||
* Run animation
|
||||
* @param {Object} opt Animation options
|
||||
* @param {Object} cb Callabak after all steps are done
|
||||
* @param {Object} revert Reverse order? true|false
|
||||
* @param {Object} step Optional step number (frame bumber)
|
||||
*/
|
||||
animation.run = function(opt, cb, revert, step) {
|
||||
var animationType = animation.types[isPageHidden() ? 'none' : _opt.animation];
|
||||
if (revert === true) {
|
||||
step = ( typeof step !== 'undefined') ? step : animationType.length - 1;
|
||||
} else {
|
||||
step = ( typeof step !== 'undefined') ? step : 0;
|
||||
}
|
||||
cb = (cb) ? cb : function() {
|
||||
};
|
||||
if ((step < animationType.length) && (step >= 0)) {
|
||||
type[_opt.type](merge(opt, animationType[step]));
|
||||
_animTimeout = setTimeout(function() {
|
||||
if (revert) {
|
||||
step = step - 1;
|
||||
} else {
|
||||
step = step + 1;
|
||||
}
|
||||
animation.run(opt, cb, revert, step);
|
||||
}, animation.duration);
|
||||
|
||||
link.setIcon(_canvas);
|
||||
} else {
|
||||
cb();
|
||||
return;
|
||||
}
|
||||
};
|
||||
//auto init
|
||||
init();
|
||||
return {
|
||||
badge : badge,
|
||||
video : video,
|
||||
image : image,
|
||||
webcam : webcam,
|
||||
reset : icon.reset,
|
||||
browser : {
|
||||
supported : _browser.supported
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// AMD / RequireJS
|
||||
if ( typeof define !== 'undefined' && define.amd) {
|
||||
define([], function() {
|
||||
return Favico;
|
||||
});
|
||||
}
|
||||
// CommonJS
|
||||
else if ( typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = Favico;
|
||||
}
|
||||
// included directly via <script> tag
|
||||
else {
|
||||
this.Favico = Favico;
|
||||
}
|
||||
|
||||
})();
|
||||
@@ -14,15 +14,15 @@
|
||||
var doc = document.documentElement;
|
||||
|
||||
return ('requestFullscreen' in doc) ||
|
||||
('mozRequestFullscreen' in doc && document.mozFullscreenEnabled) ||
|
||||
('mozRequestFullScreen' in doc && document.mozFullScreenEnabled) ||
|
||||
('webkitRequestFullscreen' in doc);
|
||||
}
|
||||
|
||||
function requestFullscreen(elem) {
|
||||
if (elem.requestFullscreen) {
|
||||
elem.requestFullscreen();
|
||||
} else if (elem.mozRequestFullscreen) {
|
||||
elem.mozRequestFullscreen();
|
||||
} else if (elem.mozRequestFullScreen) {
|
||||
elem.mozRequestFullScreen();
|
||||
} else if (elem.webkitRequestFullscreen) {
|
||||
elem.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
}
|
||||
@@ -38,7 +38,7 @@
|
||||
function cancelFullscreen() {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.mozCancelFullscreen) {
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.webkitCancelFullScreen) {
|
||||
document.webkitCancelFullScreen();
|
||||
@@ -61,16 +61,17 @@
|
||||
|
||||
var self = this;
|
||||
|
||||
$(self).on('fullscreenerror mozfullscreenerror webkitfullscreenerror msfullscreenerror', function() {
|
||||
// Chrome trigger event on self, Firefox on document
|
||||
$(self).add(document).on('fullscreenerror mozfullscreenerror webkitfullscreenerror msfullscreenerror', function() {
|
||||
$(document).trigger('error.fullscreen');
|
||||
});
|
||||
|
||||
$(self).on('fullscreenchange mozfullscreenchange webkitfullscreenchange msfullscreenchange', function() {
|
||||
if (fullscreenStatus()){
|
||||
$(self).add(document).on('fullscreenchange mozfullscreenchange webkitfullscreenchange msfullscreenchange', function() {
|
||||
if (fullscreenStatus()){
|
||||
$(document).trigger('enabled.fullscreen');
|
||||
}else{
|
||||
$(document).trigger('disabled.fullscreen');
|
||||
$(self).off('fullscreenchange mozfullscreenchange webkitfullscreenchange msfullscreenchange');
|
||||
$(self).add(document).off('fullscreenchange mozfullscreenchange webkitfullscreenchange msfullscreenchange');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -2,35 +2,81 @@
|
||||
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
|
||||
*
|
||||
* Version: 1.0.0
|
||||
*
|
||||
* Version: 1.3.3 + pr#94
|
||||
*
|
||||
*/
|
||||
(function($) {
|
||||
|
||||
jQuery.fn.extend({
|
||||
$.fn.extend({
|
||||
slimScroll: function(options) {
|
||||
|
||||
var defaults = {
|
||||
wheelStep : 20,
|
||||
|
||||
// width in pixels of the visible scroll area
|
||||
width : 'auto',
|
||||
|
||||
// height in pixels of the visible scroll area
|
||||
height : '250px',
|
||||
|
||||
// width in pixels of the scrollbar and rail
|
||||
size : '7px',
|
||||
|
||||
// scrollbar color, accepts any hex/color value
|
||||
color: '#000',
|
||||
|
||||
// scrollbar position - left/right
|
||||
position : 'right',
|
||||
|
||||
// distance in pixels between the side edge and the scrollbar
|
||||
distance : '1px',
|
||||
|
||||
// default scroll position on load - top / bottom / $('selector')
|
||||
start : 'top',
|
||||
|
||||
// sets scrollbar opacity
|
||||
opacity : .4,
|
||||
|
||||
// enables always-on mode for the scrollbar
|
||||
alwaysVisible : false,
|
||||
disableFadeOut: false,
|
||||
|
||||
// check if we should hide the scrollbar when user is hovering over
|
||||
disableFadeOut : false,
|
||||
|
||||
// sets visibility of the rail
|
||||
railVisible : false,
|
||||
|
||||
// sets rail color
|
||||
railColor : '#333',
|
||||
railOpacity : '0.2',
|
||||
|
||||
// sets rail opacity
|
||||
railOpacity : .2,
|
||||
|
||||
// whether we should use jQuery UI Draggable to enable bar dragging
|
||||
railDraggable : true,
|
||||
|
||||
// defautlt CSS class of the slimscroll rail
|
||||
railClass : 'slimScrollRail',
|
||||
|
||||
// defautlt CSS class of the slimscroll bar
|
||||
barClass : 'slimScrollBar',
|
||||
|
||||
// defautlt CSS class of the slimscroll wrapper
|
||||
wrapperClass : 'slimScrollDiv',
|
||||
|
||||
// check if mousewheel should scroll the window if we reach top/bottom
|
||||
allowPageScroll : false,
|
||||
scroll : 0,
|
||||
touchScrollStep : 200
|
||||
|
||||
// scroll amount applied to each mouse wheel step
|
||||
wheelStep : 20,
|
||||
|
||||
// scroll amount applied when user is using gestures
|
||||
touchScrollStep : 200,
|
||||
|
||||
// sets border radius
|
||||
borderRadius: '7px',
|
||||
|
||||
// sets border radius of the rail
|
||||
railBorderRadius : '7px'
|
||||
};
|
||||
|
||||
var o = $.extend(defaults, options);
|
||||
@@ -38,7 +84,7 @@
|
||||
// do it for every element that matches selector
|
||||
this.each(function(){
|
||||
|
||||
var isOverPanel, isOverBar, isDragg, queueHide, touchDif,
|
||||
var isOverPanel, isOverBar, isDragg, queueHide, touchDif,
|
||||
barHeight, percentScroll, lastScroll,
|
||||
divS = '<div></div>',
|
||||
minBarHeight = 30,
|
||||
@@ -48,20 +94,33 @@
|
||||
var me = $(this);
|
||||
|
||||
// ensure we are not binding it again
|
||||
if (me.parent().hasClass('slimScrollDiv'))
|
||||
{
|
||||
if (me.parent().hasClass(o.wrapperClass))
|
||||
{
|
||||
// start from last bar position
|
||||
var offset = me.scrollTop();
|
||||
|
||||
// find bar and rail
|
||||
bar = me.parent().find('.slimScrollBar');
|
||||
rail = me.parent().find('.slimScrollRail');
|
||||
|
||||
bar = me.parent().find('.' + o.barClass);
|
||||
rail = me.parent().find('.' + o.railClass);
|
||||
|
||||
getBarHeight();
|
||||
|
||||
// check if we should scroll existing instance
|
||||
if (options)
|
||||
if ($.isPlainObject(options))
|
||||
{
|
||||
// Pass height: auto to an existing slimscroll object to force a resize after contents have changed
|
||||
if ( 'height' in options && options.height == 'auto' ) {
|
||||
me.parent().css('height', 'auto');
|
||||
me.css('height', 'auto');
|
||||
var height = me.parent().parent().height();
|
||||
me.parent().css('height', height);
|
||||
me.css('height', height);
|
||||
} else if ('height' in options) {
|
||||
var h = options.height;
|
||||
me.parent().css('height', h);
|
||||
me.css('height', h);
|
||||
}
|
||||
|
||||
if ('scrollTo' in options)
|
||||
{
|
||||
// jump to a static point
|
||||
@@ -72,6 +131,14 @@
|
||||
// jump by value pixels
|
||||
offset += parseInt(o.scrollBy);
|
||||
}
|
||||
else if ('destroy' in options)
|
||||
{
|
||||
// remove slimscroll elements
|
||||
bar.remove();
|
||||
rail.remove();
|
||||
me.unwrap();
|
||||
return;
|
||||
}
|
||||
|
||||
// scroll content by the given offset
|
||||
scrollContent(offset, false, true);
|
||||
@@ -79,9 +146,16 @@
|
||||
|
||||
return;
|
||||
}
|
||||
else if ($.isPlainObject(options))
|
||||
{
|
||||
if ('destroy' in options)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// optionally set height to the parent's height
|
||||
o.height = (o.height == 'auto') ? me.parent().innerHeight() : o.height;
|
||||
o.height = (o.height == 'auto') ? me.parent().height() : o.height;
|
||||
|
||||
// wrap content
|
||||
var wrapper = $(divS)
|
||||
@@ -101,7 +175,7 @@
|
||||
});
|
||||
|
||||
// create scrollbar rail
|
||||
var rail = $(divS)
|
||||
var rail = $(divS)
|
||||
.addClass(o.railClass)
|
||||
.css({
|
||||
width: o.size,
|
||||
@@ -109,7 +183,7 @@
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
|
||||
'border-radius': o.size,
|
||||
'border-radius': o.railBorderRadius,
|
||||
background: o.railColor,
|
||||
opacity: o.railOpacity,
|
||||
zIndex: 90
|
||||
@@ -125,10 +199,10 @@
|
||||
top: 0,
|
||||
opacity: o.opacity,
|
||||
display: o.alwaysVisible ? 'block' : 'none',
|
||||
'border-radius' : o.size,
|
||||
BorderRadius: o.size,
|
||||
MozBorderRadius: o.size,
|
||||
WebkitBorderRadius: o.size,
|
||||
'border-radius' : o.borderRadius,
|
||||
BorderRadius: o.borderRadius,
|
||||
MozBorderRadius: o.borderRadius,
|
||||
WebkitBorderRadius: o.borderRadius,
|
||||
zIndex: 99
|
||||
});
|
||||
|
||||
@@ -144,18 +218,31 @@
|
||||
me.parent().append(bar);
|
||||
me.parent().append(rail);
|
||||
|
||||
// make it draggable
|
||||
bar.draggable({
|
||||
axis: 'y',
|
||||
containment: 'parent',
|
||||
start: function() { isDragg = true; },
|
||||
stop: function() { isDragg = false; hideBar(); },
|
||||
drag: function(e)
|
||||
{
|
||||
// scroll content
|
||||
scrollContent(0, $(this).position().top, false);
|
||||
}
|
||||
});
|
||||
// make it draggable and no longer dependent on the jqueryUI
|
||||
if (o.railDraggable){
|
||||
bar.bind("mousedown", function(e) {
|
||||
var $doc = $(document);
|
||||
isDragg = true;
|
||||
t = parseFloat(bar.css('top'));
|
||||
pageY = e.pageY;
|
||||
|
||||
$doc.bind("mousemove.slimscroll", function(e){
|
||||
currTop = t + e.pageY - pageY;
|
||||
bar.css('top', currTop);
|
||||
scrollContent(0, bar.position().top, false);// scroll content
|
||||
});
|
||||
|
||||
$doc.bind("mouseup.slimscroll", function(e) {
|
||||
isDragg = false;hideBar();
|
||||
$doc.unbind('.slimscroll');
|
||||
});
|
||||
return false;
|
||||
}).bind("selectstart.slimscroll", function(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// on rail over
|
||||
rail.hover(function(){
|
||||
@@ -191,18 +278,44 @@
|
||||
});
|
||||
|
||||
me.bind('touchmove', function(e){
|
||||
// prevent scrolling the page
|
||||
e.originalEvent.preventDefault();
|
||||
// prevent scrolling the page if necessary
|
||||
if(!releaseScroll)
|
||||
{
|
||||
e.originalEvent.preventDefault();
|
||||
}
|
||||
if (e.originalEvent.touches.length)
|
||||
{
|
||||
// see how far user swiped
|
||||
var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep;
|
||||
// scroll content
|
||||
scrollContent(diff, true);
|
||||
touchDif = e.originalEvent.touches[0].pageY;
|
||||
}
|
||||
});
|
||||
|
||||
var _onWheel = function(e)
|
||||
// set up initial height
|
||||
getBarHeight();
|
||||
|
||||
// check start position
|
||||
if (o.start === 'bottom')
|
||||
{
|
||||
// scroll content to bottom
|
||||
bar.css({ top: me.outerHeight() - bar.outerHeight() });
|
||||
scrollContent(0, true);
|
||||
}
|
||||
else if (o.start !== 'top')
|
||||
{
|
||||
// assume jQuery selector
|
||||
scrollContent($(o.start).position().top, null, true);
|
||||
|
||||
// make sure bar stays hidden
|
||||
if (!o.alwaysVisible) { bar.hide(); }
|
||||
}
|
||||
|
||||
// attach scroll events
|
||||
attachWheel();
|
||||
|
||||
function _onWheel(e)
|
||||
{
|
||||
// use mouse wheel only when mouse is over
|
||||
if (!isOverPanel) { return; }
|
||||
@@ -213,8 +326,11 @@
|
||||
if (e.wheelDelta) { delta = -e.wheelDelta/120; }
|
||||
if (e.detail) { delta = e.detail / 3; }
|
||||
|
||||
// scroll content
|
||||
scrollContent(delta, true);
|
||||
var target = e.target || e.srcTarget || e.srcElement;
|
||||
if ($(target).closest('.' + o.wrapperClass).is(me.parent())) {
|
||||
// scroll content
|
||||
scrollContent(delta, true);
|
||||
}
|
||||
|
||||
// stop window scroll
|
||||
if (e.preventDefault && !releaseScroll) { e.preventDefault(); }
|
||||
@@ -223,16 +339,24 @@
|
||||
|
||||
function scrollContent(y, isWheel, isJump)
|
||||
{
|
||||
releaseScroll = false;
|
||||
var delta = y;
|
||||
var maxTop = me.outerHeight() - bar.outerHeight();
|
||||
|
||||
|
||||
if (isWheel)
|
||||
{
|
||||
// move bar with mouse wheel
|
||||
delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight();
|
||||
|
||||
// move bar, make sure it doesn't go out
|
||||
// move bar, make sure it doesn't go out
|
||||
delta = Math.min(Math.max(delta, 0), maxTop);
|
||||
|
||||
// if scrolling down, make sure a fractional change to the
|
||||
// scroll position isn't rounded away when the scrollbar's CSS is set
|
||||
// this flooring of delta would happened automatically when
|
||||
// bar.css is set below, but we floor here for clarity
|
||||
delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta);
|
||||
|
||||
// scroll the scrollbar
|
||||
bar.css({ top: delta + 'px' });
|
||||
}
|
||||
@@ -245,7 +369,6 @@
|
||||
{
|
||||
delta = y;
|
||||
var offsetTop = delta / me[0].scrollHeight * me.outerHeight();
|
||||
|
||||
offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);
|
||||
bar.css({ top: offsetTop + 'px' });
|
||||
}
|
||||
@@ -253,6 +376,9 @@
|
||||
// scroll content
|
||||
me.scrollTop(delta);
|
||||
|
||||
// fire scrolling event
|
||||
me.trigger('slimscrolling', ~~delta);
|
||||
|
||||
// ensure bar is visible
|
||||
showBar();
|
||||
|
||||
@@ -260,31 +386,29 @@
|
||||
hideBar();
|
||||
}
|
||||
|
||||
var attachWheel = function()
|
||||
function attachWheel()
|
||||
{
|
||||
if (window.addEventListener)
|
||||
{
|
||||
this.addEventListener('DOMMouseScroll', _onWheel, false );
|
||||
this.addEventListener('mousewheel', _onWheel, false );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
document.attachEvent("onmousewheel", _onWheel)
|
||||
}
|
||||
}
|
||||
|
||||
// attach scroll events
|
||||
attachWheel();
|
||||
|
||||
function getBarHeight()
|
||||
{
|
||||
// calculate scrollbar height and make sure it is not too small
|
||||
barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight);
|
||||
bar.css({ height: barHeight + 'px' });
|
||||
}
|
||||
|
||||
// set up initial height
|
||||
getBarHeight();
|
||||
// hide scrollbar if content is not long enough
|
||||
var display = barHeight == me.outerHeight() ? 'none' : 'block';
|
||||
bar.css({ display: display });
|
||||
}
|
||||
|
||||
function showBar()
|
||||
{
|
||||
@@ -293,18 +417,22 @@
|
||||
clearTimeout(queueHide);
|
||||
|
||||
// when bar reached top or bottom
|
||||
if (percentScroll == ~~ percentScroll)
|
||||
if (percentScroll == ~~percentScroll)
|
||||
{
|
||||
//release wheel
|
||||
//release wheel
|
||||
releaseScroll = o.allowPageScroll;
|
||||
|
||||
|
||||
// publish approporiate event
|
||||
if (lastScroll != percentScroll)
|
||||
{
|
||||
var msg = (~~percentScroll == 0) ? 'top' : 'bottom';
|
||||
var msg = (~~percentScroll == 0) ? 'top' : 'bottom';
|
||||
me.trigger('slimscroll', msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
releaseScroll = false;
|
||||
}
|
||||
lastScroll = percentScroll;
|
||||
|
||||
// show only when required
|
||||
@@ -324,7 +452,7 @@
|
||||
{
|
||||
queueHide = setTimeout(function(){
|
||||
if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg)
|
||||
{
|
||||
{
|
||||
bar.fadeOut('slow');
|
||||
rail.fadeOut('slow');
|
||||
}
|
||||
@@ -332,30 +460,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
// check start position
|
||||
if (o.start == 'bottom')
|
||||
{
|
||||
// scroll content to bottom
|
||||
bar.css({ top: me.outerHeight() - bar.outerHeight() });
|
||||
scrollContent(0, true);
|
||||
}
|
||||
else if (typeof o.start == 'object')
|
||||
{
|
||||
// scroll content
|
||||
scrollContent($(o.start).position().top, null, true);
|
||||
|
||||
// make sure bar stays hidden
|
||||
if (!o.alwaysVisible) { bar.hide(); }
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// maintain chainability
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
jQuery.fn.extend({
|
||||
slimscroll: jQuery.fn.slimScroll
|
||||
$.fn.extend({
|
||||
slimscroll: $.fn.slimScroll
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -5,7 +5,11 @@
|
||||
} else if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = factory(require('crypto'))
|
||||
} else {
|
||||
root.BigInt = factory(root.crypto || root.msCrypto)
|
||||
try {
|
||||
root.BigInt = factory(root.crypto || root.msCrypto)
|
||||
} catch(e) {
|
||||
console.warn(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
}(this, function (crypto) {
|
||||
@@ -1680,25 +1684,18 @@
|
||||
, equalsInt : equalsInt
|
||||
, sub : sub
|
||||
, mod : mod
|
||||
, mod_ : mod_
|
||||
, modInt : modInt
|
||||
, mult : mult
|
||||
, divInt_ : divInt_
|
||||
, rightShift_ : rightShift_
|
||||
, leftShift_ : leftShift_
|
||||
, dup : dup
|
||||
, greater : greater
|
||||
, add : add
|
||||
, addInt : addInt
|
||||
, addInt_ : addInt_
|
||||
, isZero : isZero
|
||||
, bitSize : bitSize
|
||||
, randTruePrime : randTruePrime
|
||||
, millerRabin : millerRabin
|
||||
, divide_ : divide_
|
||||
, trim : trim
|
||||
, expand : expand
|
||||
, bpe : bpe
|
||||
, primes : primes
|
||||
, findPrimes : findPrimes
|
||||
, getSeed : getSeed
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
|
||||
otr.js v0.2.8 - 2013-11-11
|
||||
(c) 2013 - Arlo Breault <arlolra@gmail.com>
|
||||
otr.js v0.2.15 - 2015-05-04
|
||||
(c) 2015 - Arlo Breault <arlolra@gmail.com>
|
||||
Freely distributed under the MPL v2.0 license.
|
||||
|
||||
This file is concatenated for the browser.
|
||||
@@ -29,7 +29,9 @@
|
||||
} else {
|
||||
root.OTR = {}
|
||||
root.DSA = {}
|
||||
factory.call(root)
|
||||
if (typeof root.BigInt !== 'undefined') {
|
||||
factory.call(root)
|
||||
}
|
||||
}
|
||||
|
||||
}(this, function () {
|
||||
@@ -141,6 +143,17 @@
|
||||
child.__super__ = parent.prototype
|
||||
}
|
||||
|
||||
// assumes 32-bit
|
||||
function intCompare(x, y) {
|
||||
var z = ~(x ^ y)
|
||||
z &= z >> 16
|
||||
z &= z >> 8
|
||||
z &= z >> 4
|
||||
z &= z >> 2
|
||||
z &= z >> 1
|
||||
return z & 1
|
||||
}
|
||||
|
||||
// constant-time string comparison
|
||||
HLP.compare = function (str1, str2) {
|
||||
if (str1.length !== str2.length)
|
||||
@@ -148,7 +161,7 @@
|
||||
var i = 0, result = 0
|
||||
for (; i < str1.length; i++)
|
||||
result |= str1[i].charCodeAt(0) ^ str2[i].charCodeAt(0)
|
||||
return result === 0
|
||||
return intCompare(result, 0)
|
||||
}
|
||||
|
||||
HLP.randomExponent = function () {
|
||||
@@ -1095,7 +1108,6 @@
|
||||
this.ssid = null
|
||||
this.transmittedRS = false
|
||||
this.r = null
|
||||
this.priv = otr.priv
|
||||
|
||||
// bind methods
|
||||
var self = this
|
||||
@@ -1144,10 +1156,10 @@
|
||||
},
|
||||
|
||||
makeM: function (their_y, m1, c, m2) {
|
||||
var pk = this.priv.packPublic()
|
||||
var pk = this.otr.priv.packPublic()
|
||||
var kid = HLP.packINT(this.our_keyid)
|
||||
var m = hMac(this.our_dh.publicKey, their_y, pk, kid, m1)
|
||||
m = this.priv.sign(m)
|
||||
m = this.otr.priv.sign(m)
|
||||
var msg = pk + kid
|
||||
msg += BigInt.bigInt2bits(m[0], 20) // pad to 20 bytes
|
||||
msg += BigInt.bigInt2bits(m[1], 20)
|
||||
@@ -1161,19 +1173,21 @@
|
||||
HLP.debug.call(this.otr, 'success')
|
||||
|
||||
if (BigInt.equals(this.their_y, this.our_dh.publicKey))
|
||||
return this.otr.error('equal keys - we have a problem.', true)
|
||||
return this.otr.error('equal keys - we have a problem.')
|
||||
|
||||
if ( this.their_keyid !== this.otr.their_keyid &&
|
||||
this.their_keyid !== (this.otr.their_keyid - 1) ) {
|
||||
this.otr.our_old_dh = this.our_dh
|
||||
this.otr.their_priv_pk = this.their_priv_pk
|
||||
|
||||
// our keys
|
||||
this.otr.our_old_dh = this.our_dh
|
||||
if (!(
|
||||
(this.their_keyid === this.otr.their_keyid &&
|
||||
BigInt.equals(this.their_y, this.otr.their_y)) ||
|
||||
(this.their_keyid === (this.otr.their_keyid - 1) &&
|
||||
BigInt.equals(this.their_y, this.otr.their_old_y))
|
||||
)) {
|
||||
|
||||
// their keys
|
||||
this.otr.their_y = this.their_y
|
||||
this.otr.their_old_y = null
|
||||
this.otr.their_keyid = this.their_keyid
|
||||
this.otr.their_priv_pk = this.their_priv_pk
|
||||
|
||||
// rotate keys
|
||||
this.otr.sessKeys[0] = [ new this.otr.DHSession(
|
||||
@@ -1266,7 +1280,7 @@
|
||||
|
||||
// verify gy is legal 2 <= gy <= N-2
|
||||
if (!HLP.checkGroup(this.their_y, N_MINUS_2))
|
||||
return this.otr.error('Illegal g^y.', true)
|
||||
return this.otr.error('Illegal g^y.')
|
||||
|
||||
this.createKeys(this.their_y)
|
||||
|
||||
@@ -1302,11 +1316,11 @@
|
||||
var hash = CryptoJS.SHA256(CryptoJS.enc.Latin1.parse(gxmpi))
|
||||
|
||||
if (!HLP.compare(this.hashed, hash.toString(CryptoJS.enc.Latin1)))
|
||||
return this.otr.error('Hashed g^x does not match.', true)
|
||||
return this.otr.error('Hashed g^x does not match.')
|
||||
|
||||
// verify gx is legal 2 <= g^x <= N-2
|
||||
if (!HLP.checkGroup(this.their_y, N_MINUS_2))
|
||||
return this.otr.error('Illegal g^x.', true)
|
||||
return this.otr.error('Illegal g^x.')
|
||||
|
||||
this.createKeys(this.their_y)
|
||||
|
||||
@@ -1320,7 +1334,7 @@
|
||||
, this.m1
|
||||
, HLP.packCtr(0)
|
||||
)
|
||||
if (vsm[0]) return this.otr.error(vsm[0], true)
|
||||
if (vsm[0]) return this.otr.error(vsm[0])
|
||||
|
||||
// store their key
|
||||
this.their_keyid = vsm[1]
|
||||
@@ -1362,7 +1376,7 @@
|
||||
, this.m1_prime
|
||||
, HLP.packCtr(0)
|
||||
)
|
||||
if (vsm[0]) return this.otr.error(vsm[0], true)
|
||||
if (vsm[0]) return this.otr.error(vsm[0])
|
||||
|
||||
// store their key
|
||||
this.their_keyid = vsm[1]
|
||||
@@ -1407,7 +1421,7 @@
|
||||
)
|
||||
if (send[0]) return this.otr.error(send[0])
|
||||
|
||||
this.otr._sendMsg(send[1], true)
|
||||
this.otr.io(send[1])
|
||||
},
|
||||
|
||||
initiateAKE: function (version) {
|
||||
@@ -1499,7 +1513,7 @@
|
||||
sha256.update(CryptoJS.enc.Hex.parse(our ? this.our_fp : this.their_fp))
|
||||
sha256.update(CryptoJS.enc.Hex.parse(our ? this.their_fp : this.our_fp))
|
||||
sha256.update(CryptoJS.enc.Latin1.parse(this.ssid))
|
||||
sha256.update(CryptoJS.enc.Latin1.parse(secret)) // utf8?
|
||||
sha256.update(CryptoJS.enc.Latin1.parse(secret))
|
||||
var hash = sha256.finalize()
|
||||
this.secret = HLP.bits2bigInt(hash.toString(CryptoJS.enc.Latin1))
|
||||
}
|
||||
@@ -1554,7 +1568,7 @@
|
||||
|
||||
if (msg.type === 6) {
|
||||
this.init()
|
||||
this.trigger('trust', [false])
|
||||
this.trigger('abort')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1608,6 +1622,13 @@
|
||||
|
||||
this.smpstate = CONST.SMPSTATE_EXPECT0
|
||||
|
||||
if (question) {
|
||||
// assume utf8 question
|
||||
question = CryptoJS.enc.Latin1
|
||||
.parse(question)
|
||||
.toString(CryptoJS.enc.Utf8)
|
||||
}
|
||||
|
||||
// invoke question
|
||||
this.trigger('question', [question])
|
||||
return
|
||||
@@ -1914,6 +1935,11 @@
|
||||
var MAX_INT = Math.pow(2, 53) - 1 // doubles
|
||||
var MAX_UINT = Math.pow(2, 31) - 1 // bitwise operators
|
||||
|
||||
// an internal callback
|
||||
function OTRCB(cb) {
|
||||
this.cb = cb
|
||||
}
|
||||
|
||||
// OTR contructor
|
||||
function OTR(options) {
|
||||
if (!(this instanceof OTR)) return new OTR(options)
|
||||
@@ -2084,22 +2110,36 @@
|
||||
})
|
||||
})
|
||||
this.sm.on('send', function (ssid, send) {
|
||||
if (self.ssid === ssid)
|
||||
self._sendMsg(send)
|
||||
if (self.ssid === ssid) {
|
||||
send = self.prepareMsg(send)
|
||||
self.io(send)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
OTR.prototype.io = function (msg) {
|
||||
OTR.prototype.io = function (msg, meta) {
|
||||
|
||||
// buffer
|
||||
msg = ([].concat(msg)).map(function(m, i, arr) {
|
||||
var obj = { msg: m }
|
||||
if (!(meta instanceof OTRCB) ||
|
||||
i === (arr.length - 1) // only cb after last fragment is sent
|
||||
) obj.meta = meta
|
||||
return obj
|
||||
})
|
||||
this.outgoing = this.outgoing.concat(msg)
|
||||
|
||||
var self = this
|
||||
;(function send(first) {
|
||||
if (!first) {
|
||||
if (!self.outgoing.length) return
|
||||
var msg = self.outgoing.shift()
|
||||
self.trigger('io', [msg])
|
||||
var elem = self.outgoing.shift(), cb = null
|
||||
if (elem.meta instanceof OTRCB) {
|
||||
cb = elem.meta.cb
|
||||
elem.meta = null
|
||||
}
|
||||
self.trigger('io', [elem.msg, elem.meta])
|
||||
if (cb) cb()
|
||||
}
|
||||
setTimeout(send, first ? 0 : self.send_interval)
|
||||
}(true))
|
||||
@@ -2132,7 +2172,7 @@
|
||||
this.sendenc = HLP.mask(HLP.h1(sendbyte, secbytes), 0, 128) // f16 bytes
|
||||
this.sendmac = CryptoJS.SHA1(CryptoJS.enc.Latin1.parse(this.sendenc))
|
||||
this.sendmac = this.sendmac.toString(CryptoJS.enc.Latin1)
|
||||
this.sendmacused = false
|
||||
|
||||
this.rcvenc = HLP.mask(HLP.h1(rcvbyte, secbytes), 0, 128)
|
||||
this.rcvmac = CryptoJS.SHA1(CryptoJS.enc.Latin1.parse(this.rcvenc))
|
||||
this.rcvmac = this.rcvmac.toString(CryptoJS.enc.Latin1)
|
||||
@@ -2151,7 +2191,6 @@
|
||||
// reveal old mac keys
|
||||
var self = this
|
||||
this.sessKeys[1].forEach(function (sk) {
|
||||
if (sk && sk.sendmacused) self.oldMacKeys.push(sk.sendmac)
|
||||
if (sk && sk.rcvmacused) self.oldMacKeys.push(sk.rcvmac)
|
||||
})
|
||||
|
||||
@@ -2179,7 +2218,6 @@
|
||||
// reveal old mac keys
|
||||
var self = this
|
||||
this.sessKeys.forEach(function (sk) {
|
||||
if (sk[1] && sk[1].sendmacused) self.oldMacKeys.push(sk[1].sendmac)
|
||||
if (sk[1] && sk[1].rcvmacused) self.oldMacKeys.push(sk[1].rcvmac)
|
||||
})
|
||||
|
||||
@@ -2197,12 +2235,12 @@
|
||||
|
||||
OTR.prototype.prepareMsg = function (msg, esk) {
|
||||
if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED || this.their_keyid === 0)
|
||||
return this.error('Not ready to encrypt.')
|
||||
return this.notify('Not ready to encrypt.')
|
||||
|
||||
var sessKeys = this.sessKeys[1][0]
|
||||
|
||||
if (sessKeys.send_counter >= MAX_INT)
|
||||
return this.error('Should have rekeyed by now.')
|
||||
return this.notify('Should have rekeyed by now.')
|
||||
|
||||
sessKeys.send_counter += 1
|
||||
|
||||
@@ -2223,7 +2261,7 @@
|
||||
send += ctr.substring(0, 8)
|
||||
|
||||
if (Math.ceil(msg.length / 8) >= MAX_UINT) // * 16 / 128
|
||||
return this.error('Message is too long.')
|
||||
return this.notify('Message is too long.')
|
||||
|
||||
var aes = HLP.encryptAes(
|
||||
CryptoJS.enc.Latin1.parse(msg)
|
||||
@@ -2235,8 +2273,6 @@
|
||||
send += HLP.make1Mac(send, sessKeys.sendmac)
|
||||
send += HLP.packData(this.oldMacKeys.splice(0).join(''))
|
||||
|
||||
sessKeys.sendmacused = true
|
||||
|
||||
send = HLP.wrapMsg(
|
||||
send
|
||||
, this.fragment_size
|
||||
@@ -2244,7 +2280,7 @@
|
||||
, this.our_instance_tag
|
||||
, this.their_instance_tag
|
||||
)
|
||||
if (send[0]) return this.error(send[0])
|
||||
if (send[0]) return this.notify(send[0])
|
||||
|
||||
// emit extra symmetric key
|
||||
if (esk) this.trigger('file', ['send', sessKeys.extra_symkey, esk])
|
||||
@@ -2265,7 +2301,7 @@
|
||||
var ign = (msg[0] === '\x01')
|
||||
|
||||
if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED || msg.length !== 8) {
|
||||
if (!ign) this.error('Received an unreadable encrypted message.', true)
|
||||
if (!ign) this.error('Received an unreadable encrypted message.')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2273,12 +2309,12 @@
|
||||
var their_keyid = this.their_keyid - HLP.readLen(msg[1])
|
||||
|
||||
if (our_keyid < 0 || our_keyid > 1) {
|
||||
if (!ign) this.error('Not of our latest keys.', true)
|
||||
if (!ign) this.error('Not of our latest keys.')
|
||||
return
|
||||
}
|
||||
|
||||
if (their_keyid < 0 || their_keyid > 1) {
|
||||
if (!ign) this.error('Not of your latest keys.', true)
|
||||
if (!ign) this.error('Not of your latest keys.')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2373,12 +2409,18 @@
|
||||
|
||||
OTR.prototype.smpSecret = function (secret, question) {
|
||||
if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED)
|
||||
return this.error('Must be encrypted for SMP.')
|
||||
return this.notify('Must be encrypted for SMP.')
|
||||
|
||||
if (typeof secret !== 'string' || secret.length < 1)
|
||||
return this.error('Secret is required.')
|
||||
return this.notify('Secret is required.')
|
||||
|
||||
if (!this.sm) this._smInit()
|
||||
|
||||
// utf8 inputs
|
||||
secret = CryptoJS.enc.Utf8.parse(secret).toString(CryptoJS.enc.Latin1)
|
||||
if (question)
|
||||
question = CryptoJS.enc.Utf8.parse(question).toString(CryptoJS.enc.Latin1)
|
||||
|
||||
this.sm.rcvSecret(secret, question)
|
||||
}
|
||||
|
||||
@@ -2401,49 +2443,46 @@
|
||||
msg += '?'
|
||||
}
|
||||
|
||||
this._sendMsg(msg, true)
|
||||
this.io(msg)
|
||||
this.trigger('status', [CONST.STATUS_SEND_QUERY])
|
||||
}
|
||||
|
||||
OTR.prototype.sendMsg = function (msg) {
|
||||
OTR.prototype.sendMsg = function (msg, meta) {
|
||||
if ( this.REQUIRE_ENCRYPTION ||
|
||||
this.msgstate !== CONST.MSGSTATE_PLAINTEXT
|
||||
) {
|
||||
msg = CryptoJS.enc.Utf8.parse(msg)
|
||||
msg = msg.toString(CryptoJS.enc.Latin1)
|
||||
}
|
||||
this._sendMsg(msg)
|
||||
}
|
||||
|
||||
OTR.prototype._sendMsg = function (msg, internal) {
|
||||
if (!internal) { // a user or sm msg
|
||||
|
||||
switch (this.msgstate) {
|
||||
case CONST.MSGSTATE_PLAINTEXT:
|
||||
if (this.REQUIRE_ENCRYPTION) {
|
||||
this.storedMgs.push(msg)
|
||||
this.sendQueryMsg()
|
||||
return
|
||||
}
|
||||
if (this.SEND_WHITESPACE_TAG && !this.receivedPlaintext) {
|
||||
msg += CONST.WHITESPACE_TAG // 16 byte tag
|
||||
if (this.ALLOW_V3) msg += CONST.WHITESPACE_TAG_V3
|
||||
if (this.ALLOW_V2) msg += CONST.WHITESPACE_TAG_V2
|
||||
}
|
||||
break
|
||||
case CONST.MSGSTATE_FINISHED:
|
||||
this.storedMgs.push(msg)
|
||||
this.error('Message cannot be sent at this time.')
|
||||
switch (this.msgstate) {
|
||||
case CONST.MSGSTATE_PLAINTEXT:
|
||||
if (this.REQUIRE_ENCRYPTION) {
|
||||
this.storedMgs.push({msg: msg, meta: meta})
|
||||
this.sendQueryMsg()
|
||||
return
|
||||
default:
|
||||
msg = this.prepareMsg(msg)
|
||||
}
|
||||
|
||||
}
|
||||
if (this.SEND_WHITESPACE_TAG && !this.receivedPlaintext) {
|
||||
msg += CONST.WHITESPACE_TAG // 16 byte tag
|
||||
if (this.ALLOW_V3) msg += CONST.WHITESPACE_TAG_V3
|
||||
if (this.ALLOW_V2) msg += CONST.WHITESPACE_TAG_V2
|
||||
}
|
||||
break
|
||||
case CONST.MSGSTATE_FINISHED:
|
||||
this.storedMgs.push({msg: msg, meta: meta})
|
||||
this.notify('Message cannot be sent at this time.', 'warn')
|
||||
return
|
||||
case CONST.MSGSTATE_ENCRYPTED:
|
||||
msg = this.prepareMsg(msg)
|
||||
break
|
||||
default:
|
||||
throw new Error('Unknown message state.')
|
||||
}
|
||||
if (msg) this.io(msg)
|
||||
|
||||
if (msg) this.io(msg, meta)
|
||||
}
|
||||
|
||||
OTR.prototype.receiveMsg = function (msg) {
|
||||
OTR.prototype.receiveMsg = function (msg, meta) {
|
||||
|
||||
// parse type
|
||||
msg = Parse.parseMsg(this, msg)
|
||||
@@ -2452,18 +2491,26 @@
|
||||
|
||||
switch (msg.cls) {
|
||||
case 'error':
|
||||
this.error(msg.msg)
|
||||
this.notify(msg.msg)
|
||||
return
|
||||
case 'ake':
|
||||
if ( msg.version === CONST.OTR_VERSION_3 &&
|
||||
this.checkInstanceTags(msg.instance_tags)
|
||||
) return // ignore
|
||||
) {
|
||||
this.notify(
|
||||
'Received a message intended for a different session.', 'warn')
|
||||
return // ignore
|
||||
}
|
||||
this.ake.handleAKE(msg)
|
||||
return
|
||||
case 'data':
|
||||
if ( msg.version === CONST.OTR_VERSION_3 &&
|
||||
this.checkInstanceTags(msg.instance_tags)
|
||||
) return // ignore
|
||||
) {
|
||||
this.notify(
|
||||
'Received a message intended for a different session.', 'warn')
|
||||
return // ignore
|
||||
}
|
||||
msg.msg = this.handleDataMsg(msg)
|
||||
msg.encrypted = true
|
||||
break
|
||||
@@ -2475,7 +2522,7 @@
|
||||
// check for encrypted
|
||||
if ( this.REQUIRE_ENCRYPTION ||
|
||||
this.msgstate !== CONST.MSGSTATE_PLAINTEXT
|
||||
) this.error('Received an unencrypted message.')
|
||||
) this.notify('Received an unencrypted message.', 'warn')
|
||||
|
||||
// received a plaintext message
|
||||
// stop sending the whitespace tag
|
||||
@@ -2486,7 +2533,7 @@
|
||||
this.doAKE(msg)
|
||||
}
|
||||
|
||||
if (msg.msg) this.trigger('ui', [msg.msg, msg.encrypted])
|
||||
if (msg.msg) this.trigger('ui', [msg.msg, !!msg.encrypted, meta])
|
||||
}
|
||||
|
||||
OTR.prototype.checkInstanceTags = function (it) {
|
||||
@@ -2510,43 +2557,43 @@
|
||||
} else if (this.ALLOW_V2 && ~msg.ver.indexOf(CONST.OTR_VERSION_2)) {
|
||||
this.ake.initiateAKE(CONST.OTR_VERSION_2)
|
||||
} else {
|
||||
// is this an error?
|
||||
this.error('OTR conversation requested, ' +
|
||||
'but no compatible protocol version found.')
|
||||
this.notify('OTR conversation requested, ' +
|
||||
'but no compatible protocol version found.', 'warn')
|
||||
}
|
||||
}
|
||||
|
||||
OTR.prototype.error = function (err, send) {
|
||||
if (send) {
|
||||
if (!this.debug) err = "An OTR error has occurred."
|
||||
err = '?OTR Error:' + err
|
||||
this._sendMsg(err, true)
|
||||
return
|
||||
}
|
||||
this.trigger('error', [err])
|
||||
OTR.prototype.error = function (err) {
|
||||
if (!this.debug) err = 'An OTR error has occurred.'
|
||||
this.io('?OTR Error:' + err)
|
||||
this.notify(err)
|
||||
}
|
||||
|
||||
OTR.prototype.notify = function (err, severity) {
|
||||
this.trigger('error', [err, severity || 'error'])
|
||||
}
|
||||
|
||||
OTR.prototype.sendStored = function () {
|
||||
var self = this
|
||||
;(this.storedMgs.splice(0)).forEach(function (msg) {
|
||||
self._sendMsg(msg)
|
||||
;(this.storedMgs.splice(0)).forEach(function (elem) {
|
||||
var msg = self.prepareMsg(elem.msg)
|
||||
self.io(msg, elem.meta)
|
||||
})
|
||||
}
|
||||
|
||||
OTR.prototype.sendFile = function (filename) {
|
||||
if (this.msgstate !== CONST.MSGSTATE_ENCRYPTED)
|
||||
return this.error('Not ready to encrypt.')
|
||||
return this.notify('Not ready to encrypt.')
|
||||
|
||||
if (this.ake.otr_version !== CONST.OTR_VERSION_3)
|
||||
return this.error('Protocol v3 required.')
|
||||
return this.notify('Protocol v3 required.')
|
||||
|
||||
if (!filename) return this.error('Please specify a filename.')
|
||||
if (!filename) return this.notify('Please specify a filename.')
|
||||
|
||||
// utf8 filenames
|
||||
var l1name = CryptoJS.enc.Utf8.parse(filename)
|
||||
l1name = l1name.toString(CryptoJS.enc.Latin1)
|
||||
|
||||
if (l1name.length >= 65532) return this.error('filename is too long.')
|
||||
if (l1name.length >= 65532) return this.notify('Filename is too long.')
|
||||
|
||||
var msg = '\x00' // null byte
|
||||
msg += '\x00\x08' // type 8 tlv
|
||||
@@ -2555,17 +2602,21 @@
|
||||
msg += l1name
|
||||
|
||||
msg = this.prepareMsg(msg, filename)
|
||||
if (msg) this._sendMsg(msg, true)
|
||||
this.io(msg)
|
||||
}
|
||||
|
||||
OTR.prototype.endOtr = function () {
|
||||
OTR.prototype.endOtr = function (cb) {
|
||||
if (this.msgstate === CONST.MSGSTATE_ENCRYPTED) {
|
||||
this.sendMsg('\x00\x00\x01\x00\x00')
|
||||
if (typeof cb === 'function')
|
||||
cb = new OTRCB(cb)
|
||||
this.sendMsg('\x00\x00\x01\x00\x00', cb)
|
||||
if (this.sm) {
|
||||
if (this.smw) this.sm.worker.terminate() // destroy webworker
|
||||
this.sm = null
|
||||
}
|
||||
}
|
||||
} else if (typeof cb === 'function')
|
||||
setTimeout(cb, 0)
|
||||
|
||||
this.msgstate = CONST.MSGSTATE_PLAINTEXT
|
||||
this.receivedPlaintext = false
|
||||
this.trigger('status', [CONST.STATUS_END_OTR])
|
||||
@@ -2582,6 +2633,7 @@
|
||||
|
||||
}).call(this)
|
||||
|
||||
|
||||
return {
|
||||
OTR: this.OTR
|
||||
, DSA: this.DSA
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
|
||||
root.OTR = {}
|
||||
root.DSA = {}
|
||||
root.crypto = {
|
||||
randomBytes: function () {
|
||||
throw new Error("Haven't seeded yet.")
|
||||
|
||||
var hasCrypto = false
|
||||
if (root.crypto)
|
||||
hasCrypto = true
|
||||
else
|
||||
root.crypto = {
|
||||
randomBytes: function () {
|
||||
throw new Error("Haven't seeded yet.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default imports
|
||||
var imports = [
|
||||
@@ -30,10 +35,12 @@
|
||||
if (data.imports) imports = data.imports
|
||||
importScripts.apply(root, imports);
|
||||
|
||||
// use salsa20 since there's no prng in webworkers
|
||||
var state = new root.Salsa20(data.seed.slice(0, 32), data.seed.slice(32))
|
||||
root.crypto.randomBytes = function (n) {
|
||||
return state.getBytes(n)
|
||||
if (!hasCrypto) {
|
||||
// use salsa20 when there's no prng in webworkers
|
||||
var state = new root.Salsa20(data.seed.slice(0, 32), data.seed.slice(32))
|
||||
root.crypto.randomBytes = function (n) {
|
||||
return state.getBytes(n)
|
||||
}
|
||||
}
|
||||
|
||||
if (data.debug) sendMsg('debug', 'DSA key creation started')
|
||||
|
||||
@@ -50,6 +50,17 @@
|
||||
child.__super__ = parent.prototype
|
||||
}
|
||||
|
||||
// assumes 32-bit
|
||||
function intCompare(x, y) {
|
||||
var z = ~(x ^ y)
|
||||
z &= z >> 16
|
||||
z &= z >> 8
|
||||
z &= z >> 4
|
||||
z &= z >> 2
|
||||
z &= z >> 1
|
||||
return z & 1
|
||||
}
|
||||
|
||||
// constant-time string comparison
|
||||
HLP.compare = function (str1, str2) {
|
||||
if (str1.length !== str2.length)
|
||||
@@ -57,7 +68,7 @@
|
||||
var i = 0, result = 0
|
||||
for (; i < str1.length; i++)
|
||||
result |= str1[i].charCodeAt(0) ^ str2[i].charCodeAt(0)
|
||||
return result === 0
|
||||
return intCompare(result, 0)
|
||||
}
|
||||
|
||||
HLP.randomExponent = function () {
|
||||
|
||||
@@ -2,11 +2,16 @@
|
||||
"use strict";
|
||||
|
||||
root.OTR = {}
|
||||
root.crypto = {
|
||||
randomBytes: function () {
|
||||
throw new Error("Haven't seeded yet.")
|
||||
|
||||
var hasCrypto = false
|
||||
if (root.crypto)
|
||||
hasCrypto = true
|
||||
else
|
||||
root.crypto = {
|
||||
randomBytes: function () {
|
||||
throw new Error("Haven't seeded yet.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// default imports
|
||||
var imports = [
|
||||
@@ -36,7 +41,10 @@
|
||||
if (data.imports) imports = data.imports
|
||||
importScripts.apply(root, imports)
|
||||
|
||||
// use salsa20 since there's no prng in webworkers
|
||||
if (hasCrypto)
|
||||
break
|
||||
|
||||
// use salsa20 when there's no prng in webworkers
|
||||
var state = new root.Salsa20(
|
||||
data.seed.slice(0, 32),
|
||||
data.seed.slice(32)
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
Strophe.addConnectionPlugin('bookmarks', {
|
||||
init : function(connection) {
|
||||
this.connection = connection;
|
||||
Strophe.addNamespace('PRIVATE', 'jabber:iq:private');
|
||||
Strophe.addNamespace('BOOKMARKS', 'storage:bookmarks');
|
||||
Strophe.addNamespace('PRIVACY', 'jabber:iq:privacy');
|
||||
Strophe.addNamespace('DELAY', 'jabber:x:delay');
|
||||
Strophe.addNamespace('PUBSUB', 'http://jabber.org/protocol/pubsub');
|
||||
|
||||
},
|
||||
/**
|
||||
* Create private bookmark node.
|
||||
*
|
||||
* @param {function} [success] - Callback after success
|
||||
* @param {function} [error] - Callback after error
|
||||
*/
|
||||
createBookmarksNode : function(success, error) {
|
||||
// We do this instead of using publish-options because this is not
|
||||
// mandatory to implement according to XEP-0060
|
||||
this.connection.sendIQ($iq({
|
||||
type : 'set'
|
||||
}).c('pubsub', {
|
||||
xmlns : Strophe.NS.PUBSUB
|
||||
}).c('create', {
|
||||
node : 'storage:bookmarks'
|
||||
}).up().c('configure').c('x', {
|
||||
xmlns : 'jabber:x:data',
|
||||
type : 'submit'
|
||||
}).c('field', {
|
||||
'var' : 'FORM_TYPE',
|
||||
type : 'hidden'
|
||||
}).c('value').t('http://jabber.org/protocol/pubsub#node_config').up()
|
||||
.up().c('field', {
|
||||
'var' : 'pubsub#persist_items'
|
||||
}).c('value').t('1').up().up().c('field', {
|
||||
'var' : 'pubsub#access_model'
|
||||
}).c('value').t('whitelist'), success, error);
|
||||
|
||||
return true;
|
||||
},
|
||||
/**
|
||||
* Add bookmark to storage.
|
||||
*
|
||||
* @param {string} roomJid - The JabberID of the chat roomJid
|
||||
* @param {string} [alias] - A friendly name for the bookmark
|
||||
* @param {string} [nick] - The users's preferred roomnick for the chatroom
|
||||
* @param {boolean} [autojoin=false] - Whether the client should automatically join
|
||||
* the conference room on login.
|
||||
* @param {function} [success] - Callback after success
|
||||
* @param {function} [error] - Callback after error
|
||||
*/
|
||||
add : function(roomJid, alias, nick, autojoin, success, error) {
|
||||
var conferenceAttr = {
|
||||
jid: roomJid,
|
||||
autojoin: autojoin || false
|
||||
};
|
||||
|
||||
if (alias) {
|
||||
conferenceAttr.name = alias;
|
||||
}
|
||||
|
||||
var stanza = $iq({
|
||||
type : 'set'
|
||||
}).c('pubsub', {
|
||||
xmlns : Strophe.NS.PUBSUB
|
||||
}).c('publish', {
|
||||
node : Strophe.NS.BOOKMARKS
|
||||
}).c('item', {
|
||||
id : roomJid
|
||||
}).c('storage', {
|
||||
xmlns : Strophe.NS.BOOKMARKS
|
||||
}).c('conference', conferenceAttr);
|
||||
|
||||
if (nick) {
|
||||
stanza.c('nick').t(nick);
|
||||
}
|
||||
|
||||
this.connection.sendIQ(stanza, success, error);
|
||||
},
|
||||
/**
|
||||
* Retrieve all stored bookmarks.
|
||||
*
|
||||
* @param {function} [success] - Callback after success
|
||||
* @param {function} [error] - Callback after error
|
||||
*/
|
||||
get: function(success, error) {
|
||||
this.connection.sendIQ($iq({
|
||||
type : 'get'
|
||||
}).c('pubsub', {
|
||||
xmlns : Strophe.NS.PUBSUB
|
||||
}).c('items', {
|
||||
node : Strophe.NS.BOOKMARKS
|
||||
}), success, error);
|
||||
},
|
||||
/**
|
||||
* Delete the given entry for roomJid.
|
||||
*
|
||||
* @param {string} roomJid - The JabberID of the chat roomJid you want to remove
|
||||
* @param {function} [success] - Callback after success
|
||||
* @param {function} [error] - Callback after error
|
||||
* @param {boolean} [notify=false] - True: notify all subscribers
|
||||
*/
|
||||
delete: function(roomJid, success, error, notify) {
|
||||
this.connection.sendIQ($iq({
|
||||
type : 'set'
|
||||
}).c('pubsub', {
|
||||
xmlns : Strophe.NS.PUBSUB
|
||||
}).c('retract', {
|
||||
node : Strophe.NS.BOOKMARKS,
|
||||
notify: notify || false
|
||||
}).c('item', {
|
||||
id: roomJid
|
||||
}), success, error);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -7,6 +7,8 @@
|
||||
*
|
||||
* Authors: - Michael Weibel <michael.weibel@gmail.com> - Klaus Herberth <klaus@jsxc.org>
|
||||
* Copyright: - Michael Weibel <michael.weibel@gmail.com>
|
||||
*
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
@@ -119,11 +121,20 @@
|
||||
return null;
|
||||
},
|
||||
hasFeatureByJid: function(jid, feature) {
|
||||
if (this._jidVerIndex[jid]) {
|
||||
var length = ($.isArray(feature)) ? feature.length : 1;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (this._knownCapabilities[this._jidVerIndex[jid]]['features'].indexOf(feature[i]) < 0)
|
||||
if (this._jidVerIndex[jid] && feature !== null && typeof feature !== 'undefined') {
|
||||
if(!$.isArray(feature)){
|
||||
feature = $.makeArray(feature);
|
||||
}
|
||||
|
||||
var i, knownCapabilities;
|
||||
knownCapabilities = this._knownCapabilities[this._jidVerIndex[jid]];
|
||||
if (!knownCapabilities) {
|
||||
return null;
|
||||
}
|
||||
for (i = 0; i < feature.length; i++) {
|
||||
if (knownCapabilities['features'].indexOf(feature[i]) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -150,7 +161,7 @@
|
||||
}
|
||||
|
||||
localStorage.setItem('strophe.caps._jidVerIndex', JSON.stringify(this._jidVerIndex));
|
||||
$(document).trigger('caps.strophe', [ from ]);
|
||||
$(document).trigger('caps.strophe', [ from, this._knownCapabilities[ver], ver]);
|
||||
|
||||
return true;
|
||||
},
|
||||
@@ -185,13 +196,18 @@
|
||||
* Returns: (Boolean) - false, to automatically remove the handler.
|
||||
*/
|
||||
_handleDiscoInfoReply: function(stanza) {
|
||||
var query = stanza.querySelector('query'), node = query.getAttribute('node').split('#'), ver = node[1], from = stanza.getAttribute('from');
|
||||
var query = stanza.querySelector('query');
|
||||
var from = stanza.getAttribute('from');
|
||||
var node = query.getAttribute('node');
|
||||
var ver = (node)? node.split('#')[1] : this._jidVerIndex[from]; //fix open prosody issue
|
||||
|
||||
if (!this._knownCapabilities[ver]) {
|
||||
var childNodes = query.childNodes, childNodesLen = childNodes.length;
|
||||
this._knownCapabilities[ver] = {
|
||||
features: [],
|
||||
identities: []
|
||||
};
|
||||
|
||||
for (var i = 0; i < childNodesLen; i++) {
|
||||
var node = childNodes[i];
|
||||
if (node.nodeName == 'feature') {
|
||||
@@ -199,10 +215,11 @@
|
||||
} else if (node.nodeName == 'identity') {
|
||||
this._knownCapabilities[ver]['identities'].push(this._attributesToJsObject(node.attributes));
|
||||
} else {
|
||||
if (_knownCapabilities[ver][node.nodeName])
|
||||
_knownCapabilities[ver][node.nodeName] = [];
|
||||
if (typeof this._knownCapabilities[ver][node.nodeName] === 'undefined')
|
||||
this._knownCapabilities[ver][node.nodeName] = [];
|
||||
this._knownCapabilities[ver][node.nodeName].push(this._attributesToJsObject(node.attributes));
|
||||
}
|
||||
|
||||
}
|
||||
this._jidVerIndex[from] = ver;
|
||||
} else if (!this._jidVerIndex[from] || !this._jidVerIndex[from] !== ver) {
|
||||
@@ -211,7 +228,7 @@
|
||||
|
||||
localStorage.setItem('strophe.caps._jidVerIndex', JSON.stringify(this._jidVerIndex));
|
||||
localStorage.setItem('strophe.caps._knownCapabilities', JSON.stringify(this._knownCapabilities));
|
||||
$(document).trigger('caps.strophe', [ from ]);
|
||||
$(document).trigger('caps.strophe', [ from, this._knownCapabilities[ver], ver ]);
|
||||
|
||||
return false;
|
||||
},
|
||||
@@ -255,4 +272,4 @@
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}(jQuery));
|
||||
}(jQuery));
|
||||
|
||||
@@ -1,330 +0,0 @@
|
||||
/* jshint -W117 */
|
||||
var setupRTC, getUserMediaWithConstraints, TraceablePeerConnection;
|
||||
|
||||
(function($){
|
||||
TraceablePeerConnection = function(ice_config, constraints) {
|
||||
var self = this;
|
||||
var RTCPeerconnection = navigator.mozGetUserMedia ? mozRTCPeerConnection : webkitRTCPeerConnection;
|
||||
this.peerconnection = new RTCPeerconnection(ice_config, constraints);
|
||||
this.updateLog = [];
|
||||
|
||||
// override as desired
|
||||
this.trace = function(what, info) {
|
||||
//console.warn('WTRACE', what, info);
|
||||
self.updateLog.push({
|
||||
time: new Date(),
|
||||
type: what,
|
||||
value: info
|
||||
});
|
||||
};
|
||||
this.onicecandidate = null;
|
||||
this.peerconnection.onicecandidate = function (event) {
|
||||
self.trace('onicecandidate', event.candidate);
|
||||
if (self.onicecandidate !== null) {
|
||||
self.onicecandidate(event);
|
||||
}
|
||||
};
|
||||
this.onaddstream = null;
|
||||
this.peerconnection.onaddstream = function (event) {
|
||||
self.trace('onaddstream', event.stream);
|
||||
if (self.onaddstream !== null) {
|
||||
self.onaddstream(event);
|
||||
}
|
||||
};
|
||||
this.onremovestream = null;
|
||||
this.peerconnection.onremovestream = function (event) {
|
||||
self.trace('onremovestream', event.stream);
|
||||
if (self.onremovestream !== null) {
|
||||
self.onremovestream(event);
|
||||
}
|
||||
};
|
||||
this.onsignalingstatechange = null;
|
||||
this.peerconnection.onsignalingstatechange = function (event) {
|
||||
self.trace('onsignalingstatechange', event);
|
||||
if (self.onsignalingstatechange !== null) {
|
||||
self.onsignalingstatechange(event);
|
||||
}
|
||||
};
|
||||
this.oniceconnectionstatechange = null;
|
||||
this.peerconnection.oniceconnectionstatechange = function (event) {
|
||||
self.trace('oniceconnectionstatechange', event);
|
||||
if (self.oniceconnectionstatechange !== null) {
|
||||
self.oniceconnectionstatechange(event);
|
||||
}
|
||||
};
|
||||
this.onnegotiationneeded = null;
|
||||
this.peerconnection.onnegotiationneeded = function (event) {
|
||||
self.trace('onnegotiationneeded', event);
|
||||
if (self.onnegotiationneeded !== null) {
|
||||
self.onnegotiationneeded(event);
|
||||
}
|
||||
};
|
||||
self.ondatachannel = null;
|
||||
this.peerconnection.ondatachannel = function (event) {
|
||||
self.trace('ondatachannel', event);
|
||||
if (self.ondatachannel !== null) {
|
||||
self.ondatachannel(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.__defineGetter__('signalingState', function() { return this.peerconnection.signalingState; });
|
||||
TraceablePeerConnection.prototype.__defineGetter__('iceConnectionState', function() { return this.peerconnection.iceConnectionState; });
|
||||
TraceablePeerConnection.prototype.__defineGetter__('localDescription', function() { return this.peerconnection.localDescription; });
|
||||
TraceablePeerConnection.prototype.__defineGetter__('remoteDescription', function() { return this.peerconnection.remoteDescription; });
|
||||
|
||||
TraceablePeerConnection.prototype.addStream = function (stream) {
|
||||
this.trace('addStream', stream);
|
||||
this.peerconnection.addStream(stream);
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.removeStream = function (stream) {
|
||||
this.trace('removeStream', stream);
|
||||
this.peerconnection.removeStream(stream);
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.createDataChannel = function (label, opts) {
|
||||
this.trace('createDataChannel', label, opts);
|
||||
this.peerconnection.createDataChannel(label, opts);
|
||||
}
|
||||
|
||||
TraceablePeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) {
|
||||
var self = this;
|
||||
this.trace('setLocalDescription', description);
|
||||
this.peerconnection.setLocalDescription(description,
|
||||
function () {
|
||||
self.trace('setLocalDescriptionOnSuccess');
|
||||
successCallback();
|
||||
},
|
||||
function (err) {
|
||||
self.trace('setLocalDescriptionOnFailure', err);
|
||||
failureCallback(err);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
|
||||
var self = this;
|
||||
this.trace('setRemoteDescription', description);
|
||||
this.peerconnection.setRemoteDescription(description,
|
||||
function () {
|
||||
self.trace('setRemoteDescriptionOnSuccess');
|
||||
successCallback();
|
||||
},
|
||||
function (err) {
|
||||
self.trace('setRemoteDescriptionOnFailure', err);
|
||||
failureCallback(err);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.close = function () {
|
||||
this.trace('stop');
|
||||
this.peerconnection.close();
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.createOffer = function (successCallback, failureCallback, constraints) {
|
||||
var self = this;
|
||||
this.trace('createOffer', constraints);
|
||||
this.peerconnection.createOffer(
|
||||
function (sdp) {
|
||||
self.trace('createOfferOnSuccess', sdp);
|
||||
successCallback(sdp);
|
||||
},
|
||||
function(err) {
|
||||
self.trace('createOfferOnFailure', err);
|
||||
failureCallback(err);
|
||||
},
|
||||
constraints
|
||||
);
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.createAnswer = function (successCallback, failureCallback, constraints) {
|
||||
var self = this;
|
||||
this.trace('createAnswer', constraints);
|
||||
this.peerconnection.createAnswer(
|
||||
function (sdp) {
|
||||
self.trace('createAnswerOnSuccess', sdp);
|
||||
successCallback(sdp);
|
||||
},
|
||||
function(err) {
|
||||
self.trace('createAnswerOnFailure', err);
|
||||
failureCallback(err);
|
||||
},
|
||||
constraints
|
||||
);
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) {
|
||||
var self = this;
|
||||
this.trace('addIceCandidate', candidate);
|
||||
this.peerconnection.addIceCandidate(candidate);
|
||||
/* maybe later
|
||||
this.peerconnection.addIceCandidate(candidate,
|
||||
function () {
|
||||
self.trace('addIceCandidateOnSuccess');
|
||||
successCallback();
|
||||
},
|
||||
function (err) {
|
||||
self.trace('addIceCandidateOnFailure', err);
|
||||
failureCallback(err);
|
||||
}
|
||||
);
|
||||
*/
|
||||
};
|
||||
|
||||
TraceablePeerConnection.prototype.getStats = function(callback) {
|
||||
this.peerconnection.getStats(callback);
|
||||
};
|
||||
|
||||
|
||||
// mozilla chrome compat layer -- very similar to adapter.js
|
||||
setupRTC = function (){
|
||||
var RTC = null;
|
||||
if (navigator.mozGetUserMedia) {
|
||||
console.log('This appears to be Firefox');
|
||||
var version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
|
||||
if (version >= 22) {
|
||||
RTC = {
|
||||
peerconnection: mozRTCPeerConnection,
|
||||
browser: 'firefox',
|
||||
getUserMedia: navigator.mozGetUserMedia.bind(navigator),
|
||||
attachMediaStream: function (element, stream) {
|
||||
element[0].mozSrcObject = stream;
|
||||
element[0].play();
|
||||
},
|
||||
pc_constraints: {}
|
||||
};
|
||||
if (!MediaStream.prototype.getVideoTracks)
|
||||
MediaStream.prototype.getVideoTracks = function () { return []; };
|
||||
if (!MediaStream.prototype.getAudioTracks)
|
||||
MediaStream.prototype.getAudioTracks = function () { return []; };
|
||||
RTCSessionDescription = mozRTCSessionDescription;
|
||||
RTCIceCandidate = mozRTCIceCandidate;
|
||||
}
|
||||
} else if (navigator.webkitGetUserMedia) {
|
||||
console.log('This appears to be Chrome');
|
||||
RTC = {
|
||||
peerconnection: webkitRTCPeerConnection,
|
||||
browser: 'chrome',
|
||||
getUserMedia: navigator.webkitGetUserMedia.bind(navigator),
|
||||
attachMediaStream: function (element, stream) {
|
||||
element.attr('src', webkitURL.createObjectURL(stream));
|
||||
},
|
||||
// DTLS should now be enabled by default but..
|
||||
pc_constraints: {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]}
|
||||
};
|
||||
if (navigator.userAgent.indexOf('Android') != -1) {
|
||||
RTC.pc_constraints = {}; // disable DTLS on Android
|
||||
}
|
||||
if (!webkitMediaStream.prototype.getVideoTracks) {
|
||||
webkitMediaStream.prototype.getVideoTracks = function () {
|
||||
return this.videoTracks;
|
||||
};
|
||||
}
|
||||
if (!webkitMediaStream.prototype.getAudioTracks) {
|
||||
webkitMediaStream.prototype.getAudioTracks = function () {
|
||||
return this.audioTracks;
|
||||
};
|
||||
}
|
||||
}
|
||||
if (RTC === null) {
|
||||
try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }
|
||||
}
|
||||
return RTC;
|
||||
};
|
||||
|
||||
getUserMediaWithConstraints = function(um, resolution, bandwidth, fps) {
|
||||
var constraints = {audio: false, video: false};
|
||||
|
||||
if (um.indexOf('video') >= 0) {
|
||||
constraints.video = {mandatory: {}};// same behaviour as true
|
||||
}
|
||||
if (um.indexOf('audio') >= 0) {
|
||||
constraints.audio = {};// same behaviour as true
|
||||
}
|
||||
if (um.indexOf('screen') >= 0) {
|
||||
constraints.video = {
|
||||
"mandatory": {
|
||||
"chromeMediaSource": "screen"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (resolution && !constraints.video) {
|
||||
constraints.video = {mandatory: {}};// same behaviour as true
|
||||
}
|
||||
// see https://code.google.com/p/chromium/issues/detail?id=143631#c9 for list of supported resolutions
|
||||
switch (resolution) {
|
||||
// 16:9 first
|
||||
case '1080':
|
||||
case 'fullhd':
|
||||
constraints.video.mandatory.minWidth = 1920;
|
||||
constraints.video.mandatory.minHeight = 1080;
|
||||
constraints.video.mandatory.minAspectRatio = 1.77;
|
||||
break;
|
||||
case '720':
|
||||
case 'hd':
|
||||
constraints.video.mandatory.minWidth = 1280;
|
||||
constraints.video.mandatory.minHeight = 720;
|
||||
constraints.video.mandatory.minAspectRatio = 1.77;
|
||||
break;
|
||||
case '360':
|
||||
constraints.video.mandatory.minWidth = 640;
|
||||
constraints.video.mandatory.minHeight = 360;
|
||||
constraints.video.mandatory.minAspectRatio = 1.77;
|
||||
break;
|
||||
case '180':
|
||||
constraints.video.mandatory.minWidth = 320;
|
||||
constraints.video.mandatory.minHeight = 180;
|
||||
constraints.video.mandatory.minAspectRatio = 1.77;
|
||||
break;
|
||||
// 4:3
|
||||
case '960':
|
||||
constraints.video.mandatory.minWidth = 960;
|
||||
constraints.video.mandatory.minHeight = 720;
|
||||
break;
|
||||
case '640':
|
||||
case 'vga':
|
||||
constraints.video.mandatory.minWidth = 640;
|
||||
constraints.video.mandatory.minHeight = 480;
|
||||
break;
|
||||
case '320':
|
||||
constraints.video.mandatory.minWidth = 320;
|
||||
constraints.video.mandatory.minHeight = 240;
|
||||
break;
|
||||
default:
|
||||
if (navigator.userAgent.indexOf('Android') != -1) {
|
||||
constraints.video.mandatory.minWidth = 320;
|
||||
constraints.video.mandatory.minHeight = 240;
|
||||
constraints.video.mandatory.maxFrameRate = 15;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (bandwidth) { // doesn't work currently, see webrtc issue 1846
|
||||
if (!constraints.video) constraints.video = {mandatory: {}};//same behaviour as true
|
||||
constraints.video.optional = [{bandwidth: bandwidth}];
|
||||
}
|
||||
if (fps) { // for some cameras it might be necessary to request 30fps
|
||||
// so they choose 30fps mjpg over 10fps yuy2
|
||||
if (!constraints.video) constraints.video = {mandatory: {}};// same behaviour as tru;
|
||||
constraints.video.mandatory.minFrameRate = fps;
|
||||
}
|
||||
|
||||
try {
|
||||
RTC.getUserMedia(constraints,
|
||||
function (stream) {
|
||||
console.log('onUserMediaSuccess');
|
||||
$(document).trigger('mediaready.jingle', [stream]);
|
||||
},
|
||||
function (error) {
|
||||
console.warn('Failed to get access to local media. Error ', error);
|
||||
$(document).trigger('mediafailure.jingle');
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('GUM failed: ', e);
|
||||
$(document).trigger('mediafailure.jingle');
|
||||
}
|
||||
}
|
||||
}(jQuery));
|
||||
@@ -1,261 +0,0 @@
|
||||
/* jshint -W117 */
|
||||
(function($){
|
||||
Strophe.addConnectionPlugin('jingle', {
|
||||
connection: null,
|
||||
sessions: {},
|
||||
jid2session: {},
|
||||
ice_config: {iceServers: []},
|
||||
pc_constraints: {},
|
||||
media_constraints: {
|
||||
mandatory: {
|
||||
'OfferToReceiveAudio': true,
|
||||
'OfferToReceiveVideo': true
|
||||
}
|
||||
// MozDontOfferDataChannel: true when this is firefox
|
||||
},
|
||||
localStream: null,
|
||||
|
||||
init: function (conn) {
|
||||
this.connection = conn;
|
||||
if (this.connection.disco) {
|
||||
// http://xmpp.org/extensions/xep-0167.html#support
|
||||
// http://xmpp.org/extensions/xep-0176.html#support
|
||||
this.connection.disco.addFeature('urn:xmpp:jingle:1');
|
||||
this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:1');
|
||||
this.connection.disco.addFeature('urn:xmpp:jingle:transports:ice-udp:1');
|
||||
this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:audio');
|
||||
this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:video');
|
||||
|
||||
|
||||
// this is dealt with by SDP O/A so we don't need to annouce this
|
||||
//this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:rtcp-fb:0'); // XEP-0293
|
||||
//this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'); // XEP-0294
|
||||
this.connection.disco.addFeature('urn:ietf:rfc:5761'); // rtcp-mux
|
||||
//this.connection.disco.addFeature('urn:ietf:rfc:5888'); // a=group, e.g. bundle
|
||||
//this.connection.disco.addFeature('urn:ietf:rfc:5576'); // a=ssrc
|
||||
}
|
||||
this.connection.addHandler(this.onJingle.bind(this), 'urn:xmpp:jingle:1', 'iq', 'set', null, null);
|
||||
},
|
||||
onJingle: function (iq) {
|
||||
var sid = $(iq).find('jingle').attr('sid');
|
||||
var action = $(iq).find('jingle').attr('action');
|
||||
// send ack first
|
||||
var ack = $iq({type: 'result',
|
||||
to: iq.getAttribute('from'),
|
||||
id: iq.getAttribute('id')
|
||||
});
|
||||
console.log('on jingle ' + action);
|
||||
var sess = this.sessions[sid];
|
||||
if ('session-initiate' != action) {
|
||||
if (sess === null) {
|
||||
ack.type = 'error';
|
||||
ack.c('error', {type: 'cancel'})
|
||||
.c('item-not-found', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up()
|
||||
.c('unknown-session', {xmlns: 'urn:xmpp:jingle:errors:1'});
|
||||
this.connection.send(ack);
|
||||
return true;
|
||||
}
|
||||
// compare from to sess.peerjid (bare jid comparison for later compat with message-mode)
|
||||
// local jid is not checked
|
||||
if (Strophe.getBareJidFromJid(iq.getAttribute('from')) != Strophe.getBareJidFromJid(sess.peerjid)) {
|
||||
console.warn('jid mismatch for session id', sid, iq.getAttribute('from'), sess.peerjid);
|
||||
ack.type = 'error';
|
||||
ack.c('error', {type: 'cancel'})
|
||||
.c('item-not-found', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up()
|
||||
.c('unknown-session', {xmlns: 'urn:xmpp:jingle:errors:1'});
|
||||
this.connection.send(ack);
|
||||
return true;
|
||||
}
|
||||
} else if (sess !== undefined) {
|
||||
// existing session with same session id
|
||||
// this might be out-of-order if the sess.peerjid is the same as from
|
||||
ack.type = 'error';
|
||||
ack.c('error', {type: 'cancel'})
|
||||
.c('service-unavailable', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up();
|
||||
console.warn('duplicate session id', sid);
|
||||
this.connection.send(ack);
|
||||
return true;
|
||||
}
|
||||
// FIXME: check for a defined action
|
||||
this.connection.send(ack);
|
||||
// see http://xmpp.org/extensions/xep-0166.html#concepts-session
|
||||
switch (action) {
|
||||
case 'session-initiate':
|
||||
sess = new JingleSession($(iq).attr('to'), $(iq).find('jingle').attr('sid'), this.connection);
|
||||
// configure session
|
||||
if (this.localStream) {
|
||||
sess.localStreams.push(this.localStream);
|
||||
}
|
||||
sess.media_constraints = this.media_constraints;
|
||||
sess.pc_constraints = this.pc_constraints;
|
||||
sess.ice_config = this.ice_config;
|
||||
|
||||
sess.initiate($(iq).attr('from'), false);
|
||||
// FIXME: setRemoteDescription should only be done when this call is to be accepted
|
||||
sess.setRemoteDescription($(iq).find('>jingle'), 'offer');
|
||||
|
||||
this.sessions[sess.sid] = sess;
|
||||
this.jid2session[sess.peerjid] = sess;
|
||||
|
||||
// the callback should either
|
||||
// .sendAnswer and .accept
|
||||
// or .sendTerminate -- not necessarily synchronus
|
||||
$(document).trigger('callincoming.jingle', [sess.sid]);
|
||||
break;
|
||||
case 'session-accept':
|
||||
sess.setRemoteDescription($(iq).find('>jingle'), 'answer');
|
||||
sess.accept();
|
||||
$(document).trigger('callaccepted.jingle', [sess.sid]);
|
||||
break;
|
||||
case 'session-terminate':
|
||||
console.log('terminating...');
|
||||
sess.terminate();
|
||||
this.terminate(sess.sid);
|
||||
if ($(iq).find('>jingle>reason').length) {
|
||||
$(document).trigger('callterminated.jingle', [
|
||||
sess.sid,
|
||||
$(iq).find('>jingle>reason>:first')[0].tagName,
|
||||
$(iq).find('>jingle>reason>text').text()
|
||||
]);
|
||||
} else {
|
||||
$(document).trigger('callterminated.jingle', [sess.sid]);
|
||||
}
|
||||
break;
|
||||
case 'transport-info':
|
||||
sess.addIceCandidate($(iq).find('>jingle>content'));
|
||||
break;
|
||||
case 'session-info':
|
||||
var affected;
|
||||
if ($(iq).find('>jingle>ringing[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
|
||||
$(document).trigger('ringing.jingle', [sess.sid]);
|
||||
} else if ($(iq).find('>jingle>mute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
|
||||
affected = $(iq).find('>jingle>mute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').attr('name');
|
||||
$(document).trigger('mute.jingle', [sess.sid, affected]);
|
||||
} else if ($(iq).find('>jingle>unmute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
|
||||
affected = $(iq).find('>jingle>unmute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').attr('name');
|
||||
$(document).trigger('unmute.jingle', [sess.sid, affected]);
|
||||
}
|
||||
break;
|
||||
case 'addsource': // FIXME: proprietary
|
||||
sess.addSource($(iq).find('>jingle>content'));
|
||||
break;
|
||||
case 'removesource': // FIXME: proprietary
|
||||
sess.removeSource($(iq).find('>jingle>content'));
|
||||
break;
|
||||
default:
|
||||
console.warn('jingle action not implemented', action);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
initiate: function (peerjid, myjid) { // initiate a new jinglesession to peerjid
|
||||
var sess = new JingleSession(myjid || this.connection.jid,
|
||||
Math.random().toString(36).substr(2, 12), // random string
|
||||
this.connection);
|
||||
// configure session
|
||||
if (this.localStream) {
|
||||
sess.localStreams.push(this.localStream);
|
||||
}
|
||||
sess.media_constraints = this.media_constraints;
|
||||
sess.pc_constraints = this.pc_constraints;
|
||||
sess.ice_config = this.ice_config;
|
||||
|
||||
sess.initiate(peerjid, true);
|
||||
this.sessions[sess.sid] = sess;
|
||||
this.jid2session[sess.peerjid] = sess;
|
||||
sess.sendOffer();
|
||||
return sess;
|
||||
},
|
||||
terminate: function (sid, reason, text) { // terminate by sessionid (or all sessions)
|
||||
if (sid === null || sid === undefined) {
|
||||
for (sid in this.sessions) {
|
||||
if (this.sessions[sid].state != 'ended') {
|
||||
this.sessions[sid].sendTerminate(reason || (!this.sessions[sid].active()) ? 'cancel' : null, text);
|
||||
this.sessions[sid].terminate();
|
||||
}
|
||||
delete this.jid2session[this.sessions[sid].peerjid];
|
||||
delete this.sessions[sid];
|
||||
}
|
||||
} else if (this.sessions.hasOwnProperty(sid)) {
|
||||
if (this.sessions[sid].state != 'ended') {
|
||||
this.sessions[sid].sendTerminate(reason || (!this.sessions[sid].active()) ? 'cancel' : null, text);
|
||||
this.sessions[sid].terminate();
|
||||
}
|
||||
delete this.jid2session[this.sessions[sid].peerjid];
|
||||
delete this.sessions[sid];
|
||||
}
|
||||
},
|
||||
terminateByJid: function (jid) {
|
||||
if (this.jid2session.hasOwnProperty(jid)) {
|
||||
var sess = this.jid2session[jid];
|
||||
if (sess) {
|
||||
sess.terminate();
|
||||
console.log('peer went away silently', jid);
|
||||
delete this.sessions[sess.sid];
|
||||
delete this.jid2session[jid];
|
||||
$(document).trigger('callterminated.jingle', [sess.sid, 'gone']);
|
||||
}
|
||||
}
|
||||
},
|
||||
getStunAndTurnCredentials: function () {
|
||||
// get stun and turn configuration from server via xep-0215
|
||||
// uses time-limited credentials as described in
|
||||
// http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
|
||||
//
|
||||
// see https://code.google.com/p/prosody-modules/source/browse/mod_turncredentials/mod_turncredentials.lua
|
||||
// for a prosody module which implements this
|
||||
//
|
||||
// currently, this doesn't work with updateIce and therefore credentials with a long
|
||||
// validity have to be fetched before creating the peerconnection
|
||||
// TODO: implement refresh via updateIce as described in
|
||||
// https://code.google.com/p/webrtc/issues/detail?id=1650
|
||||
this.connection.sendIQ(
|
||||
$iq({type: 'get', to: this.connection.domain})
|
||||
.c('services', {xmlns: 'urn:xmpp:extdisco:1'}).c('service', {host: 'turn.' + this.connection.domain}),
|
||||
function (res) {
|
||||
var iceservers = [];
|
||||
$(res).find('>services>service').each(function (idx, el) {
|
||||
el = $(el);
|
||||
var dict = {};
|
||||
switch (el.attr('type')) {
|
||||
case 'stun':
|
||||
dict.url = 'stun:' + el.attr('host');
|
||||
if (el.attr('port')) {
|
||||
dict.url += ':' + el.attr('port');
|
||||
}
|
||||
iceservers.push(dict);
|
||||
break;
|
||||
case 'turn':
|
||||
dict.url = 'turn:';
|
||||
if (el.attr('username')) { // https://code.google.com/p/webrtc/issues/detail?id=1508
|
||||
if (navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./) && parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10) < 28) {
|
||||
dict.url += el.attr('username') + '@';
|
||||
} else {
|
||||
dict.username = el.attr('username'); // only works in M28
|
||||
}
|
||||
}
|
||||
dict.url += el.attr('host');
|
||||
if (el.attr('port') && el.attr('port') != '3478') {
|
||||
dict.url += ':' + el.attr('port');
|
||||
}
|
||||
if (el.attr('transport') && el.attr('transport') != 'udp') {
|
||||
dict.url += '?transport=' + el.attr('transport');
|
||||
}
|
||||
if (el.attr('password')) {
|
||||
dict.credential = el.attr('password');
|
||||
}
|
||||
iceservers.push(dict);
|
||||
break;
|
||||
}
|
||||
});
|
||||
this.ice_config.iceServers = iceservers;
|
||||
},
|
||||
function (err) {
|
||||
console.warn('getting turn credentials failed', err);
|
||||
console.warn('is mod_turncredentials or similar installed?');
|
||||
}
|
||||
);
|
||||
// implement push?
|
||||
}
|
||||
});
|
||||
}(jQuery));
|
||||
@@ -1,813 +0,0 @@
|
||||
/* jshint -W117 */
|
||||
var SDP;
|
||||
|
||||
(function($){
|
||||
// SDP STUFF
|
||||
SDP = function(sdp) {
|
||||
this.media = sdp.split('\r\nm=');
|
||||
for (var i = 1; i < this.media.length; i++) {
|
||||
this.media[i] = 'm=' + this.media[i];
|
||||
if (i != this.media.length - 1) {
|
||||
this.media[i] += '\r\n';
|
||||
}
|
||||
}
|
||||
this.session = this.media.shift() + '\r\n';
|
||||
this.raw = this.session + this.media.join('');
|
||||
}
|
||||
|
||||
// remove iSAC and CN from SDP
|
||||
SDP.prototype.mangle = function () {
|
||||
var i, j, mline, lines, rtpmap, newdesc;
|
||||
for (i = 0; i < this.media.length; i++) {
|
||||
lines = this.media[i].split('\r\n');
|
||||
lines.pop(); // remove empty last element
|
||||
mline = SDPUtil.parse_mline(lines.shift());
|
||||
if (mline.media != 'audio')
|
||||
continue;
|
||||
newdesc = '';
|
||||
mline.fmt.length = 0;
|
||||
for (j = 0; j < lines.length; j++) {
|
||||
if (lines[j].substr(0, 9) == 'a=rtpmap:') {
|
||||
rtpmap = SDPUtil.parse_rtpmap(lines[j]);
|
||||
if (rtpmap.name == 'CN' || rtpmap.name == 'ISAC')
|
||||
continue;
|
||||
mline.fmt.push(rtpmap.id);
|
||||
newdesc += lines[j] + '\r\n';
|
||||
} else {
|
||||
newdesc += lines[j] + '\r\n';
|
||||
}
|
||||
}
|
||||
this.media[i] = SDPUtil.build_mline(mline) + '\r\n';
|
||||
this.media[i] += newdesc;
|
||||
}
|
||||
this.raw = this.session + this.media.join('');
|
||||
};
|
||||
|
||||
// remove lines matching prefix from session section
|
||||
SDP.prototype.removeSessionLines = function(prefix) {
|
||||
var self = this;
|
||||
var lines = SDPUtil.find_lines(this.session, prefix);
|
||||
lines.forEach(function(line) {
|
||||
self.session = self.session.replace(line + '\r\n', '');
|
||||
});
|
||||
this.raw = this.session + this.media.join('');
|
||||
return lines;
|
||||
}
|
||||
// remove lines matching prefix from a media section specified by mediaindex
|
||||
// TODO: non-numeric mediaindex could match mid
|
||||
SDP.prototype.removeMediaLines = function(mediaindex, prefix) {
|
||||
var self = this;
|
||||
var lines = SDPUtil.find_lines(this.media[mediaindex], prefix);
|
||||
lines.forEach(function(line) {
|
||||
self.media[mediaindex] = self.media[mediaindex].replace(line + '\r\n', '');
|
||||
});
|
||||
this.raw = this.session + this.media.join('');
|
||||
return lines;
|
||||
}
|
||||
|
||||
// add content's to a jingle element
|
||||
SDP.prototype.toJingle = function (elem, thecreator) {
|
||||
var i, j, k, mline, ssrc, rtpmap, tmp, line, lines;
|
||||
var self = this;
|
||||
// new bundle plan
|
||||
if (SDPUtil.find_line(this.session, 'a=group:')) {
|
||||
lines = SDPUtil.find_lines(this.session, 'a=group:');
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
tmp = lines[i].split(' ');
|
||||
var semantics = tmp.shift().substr(8);
|
||||
// new plan
|
||||
elem.c('group', {xmlns: 'urn:xmpp:jingle:apps:grouping:0', type: semantics, semantics:semantics});
|
||||
for (j = 0; j < tmp.length; j++) {
|
||||
elem.c('content', {name: tmp[j]}).up();
|
||||
}
|
||||
elem.up();
|
||||
|
||||
// temporary plan, to be removed
|
||||
elem.c('group', {xmlns: 'urn:ietf:rfc:5888', type: semantics});
|
||||
for (j = 0; j < tmp.length; j++) {
|
||||
elem.c('content', {name: tmp[j]}).up();
|
||||
}
|
||||
elem.up();
|
||||
}
|
||||
}
|
||||
// old bundle plan, to be removed
|
||||
var bundle = [];
|
||||
if (SDPUtil.find_line(this.session, 'a=group:BUNDLE')) {
|
||||
bundle = SDPUtil.find_line(this.session, 'a=group:BUNDLE ').split(' ');
|
||||
bundle.shift();
|
||||
}
|
||||
for (i = 0; i < this.media.length; i++) {
|
||||
mline = SDPUtil.parse_mline(this.media[i].split('\r\n')[0]);
|
||||
if (!(mline.media == 'audio' || mline.media == 'video')) {
|
||||
continue;
|
||||
}
|
||||
if (SDPUtil.find_line(this.media[i], 'a=ssrc:')) {
|
||||
ssrc = SDPUtil.find_line(this.media[i], 'a=ssrc:').substring(7).split(' ')[0]; // take the first
|
||||
} else {
|
||||
ssrc = false;
|
||||
}
|
||||
|
||||
elem.c('content', {creator: thecreator, name: mline.media});
|
||||
if (SDPUtil.find_line(this.media[i], 'a=mid:')) {
|
||||
// prefer identifier from a=mid if present
|
||||
var mid = SDPUtil.parse_mid(SDPUtil.find_line(this.media[i], 'a=mid:'));
|
||||
elem.attrs({ name: mid });
|
||||
|
||||
// old BUNDLE plan, to be removed
|
||||
if (bundle.indexOf(mid) != -1) {
|
||||
elem.c('bundle', {xmlns: 'http://estos.de/ns/bundle'}).up();
|
||||
bundle.splice(bundle.indexOf(mid), 1);
|
||||
}
|
||||
}
|
||||
if (SDPUtil.find_line(this.media[i], 'a=rtpmap:').length) {
|
||||
elem.c('description',
|
||||
{xmlns: 'urn:xmpp:jingle:apps:rtp:1',
|
||||
media: mline.media });
|
||||
if (ssrc) {
|
||||
elem.attrs({ssrc: ssrc});
|
||||
}
|
||||
for (j = 0; j < mline.fmt.length; j++) {
|
||||
rtpmap = SDPUtil.find_line(this.media[i], 'a=rtpmap:' + mline.fmt[j]);
|
||||
elem.c('payload-type', SDPUtil.parse_rtpmap(rtpmap));
|
||||
// put any 'a=fmtp:' + mline.fmt[j] lines into <param name=foo value=bar/>
|
||||
if (SDPUtil.find_line(this.media[i], 'a=fmtp:' + mline.fmt[j])) {
|
||||
tmp = SDPUtil.parse_fmtp(SDPUtil.find_line(this.media[i], 'a=fmtp:' + mline.fmt[j]));
|
||||
for (k = 0; k < tmp.length; k++) {
|
||||
elem.c('parameter', tmp[k]).up();
|
||||
}
|
||||
}
|
||||
this.RtcpFbToJingle(i, elem, mline.fmt[j]); // XEP-0293 -- map a=rtcp-fb
|
||||
|
||||
elem.up();
|
||||
}
|
||||
if (SDPUtil.find_line(this.media[i], 'a=crypto:', this.session)) {
|
||||
elem.c('encryption', {required: 1});
|
||||
var crypto = SDPUtil.find_lines(this.media[i], 'a=crypto:', this.session);
|
||||
crypto.forEach(function(line) {
|
||||
elem.c('crypto', SDPUtil.parse_crypto(line)).up();
|
||||
});
|
||||
elem.up(); // end of encryption
|
||||
}
|
||||
|
||||
if (ssrc) {
|
||||
// new style mapping
|
||||
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
|
||||
// FIXME: group by ssrc and support multiple different ssrcs
|
||||
var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:');
|
||||
ssrclines.forEach(function(line) {
|
||||
idx = line.indexOf(' ');
|
||||
var linessrc = line.substr(0, idx).substr(7);
|
||||
if (linessrc != ssrc) {
|
||||
elem.up();
|
||||
ssrc = linessrc;
|
||||
elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
|
||||
}
|
||||
var kv = line.substr(idx + 1);
|
||||
elem.c('parameter');
|
||||
if (kv.indexOf(':') == -1) {
|
||||
elem.attrs({ name: kv });
|
||||
} else {
|
||||
elem.attrs({ name: kv.split(':', 2)[0] });
|
||||
elem.attrs({ value: kv.split(':', 2)[1] });
|
||||
}
|
||||
elem.up();
|
||||
});
|
||||
elem.up();
|
||||
|
||||
// old proprietary mapping, to be removed at some point
|
||||
tmp = SDPUtil.parse_ssrc(this.media[i]);
|
||||
tmp.xmlns = 'http://estos.de/ns/ssrc';
|
||||
tmp.ssrc = ssrc;
|
||||
elem.c('ssrc', tmp).up(); // ssrc is part of description
|
||||
}
|
||||
|
||||
if (SDPUtil.find_line(this.media[i], 'a=rtcp-mux')) {
|
||||
elem.c('rtcp-mux').up();
|
||||
}
|
||||
|
||||
// XEP-0293 -- map a=rtcp-fb:*
|
||||
this.RtcpFbToJingle(i, elem, '*');
|
||||
|
||||
// XEP-0294
|
||||
if (SDPUtil.find_line(this.media[i], 'a=extmap:')) {
|
||||
lines = SDPUtil.find_lines(this.media[i], 'a=extmap:');
|
||||
for (j = 0; j < lines.length; j++) {
|
||||
tmp = SDPUtil.parse_extmap(lines[j]);
|
||||
elem.c('rtp-hdrext', { xmlns: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',
|
||||
uri: tmp.uri,
|
||||
id: tmp.value });
|
||||
if (tmp.hasOwnProperty('direction')) {
|
||||
switch (tmp.direction) {
|
||||
case 'sendonly':
|
||||
elem.attrs({senders: 'responder'});
|
||||
break;
|
||||
case 'recvonly':
|
||||
elem.attrs({senders: 'initiator'});
|
||||
break;
|
||||
case 'sendrecv':
|
||||
elem.attrs({senders: 'both'});
|
||||
break;
|
||||
case 'inactive':
|
||||
elem.attrs({senders: 'none'});
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: handle params
|
||||
elem.up();
|
||||
}
|
||||
}
|
||||
elem.up(); // end of description
|
||||
}
|
||||
|
||||
// map ice-ufrag/pwd, dtls fingerprint, candidates
|
||||
this.TransportToJingle(i, elem);
|
||||
|
||||
if (SDPUtil.find_line(this.media[i], 'a=sendrecv', this.session)) {
|
||||
elem.attrs({senders: 'both'});
|
||||
} else if (SDPUtil.find_line(this.media[i], 'a=sendonly', this.session)) {
|
||||
elem.attrs({senders: 'initiator'});
|
||||
} else if (SDPUtil.find_line(this.media[i], 'a=recvonly', this.session)) {
|
||||
elem.attrs({senders: 'responder'});
|
||||
} else if (SDPUtil.find_line(this.media[i], 'a=inactive', this.session)) {
|
||||
elem.attrs({senders: 'none'});
|
||||
}
|
||||
if (mline.port == '0') {
|
||||
// estos hack to reject an m-line
|
||||
elem.attrs({senders: 'rejected'});
|
||||
}
|
||||
elem.up(); // end of content
|
||||
}
|
||||
elem.up();
|
||||
return elem;
|
||||
};
|
||||
|
||||
SDP.prototype.TransportToJingle = function (mediaindex, elem) {
|
||||
var i = mediaindex;
|
||||
var tmp;
|
||||
var self = this;
|
||||
elem.c('transport');
|
||||
|
||||
// XEP-0320
|
||||
var fingerprints = SDPUtil.find_lines(this.media[mediaindex], 'a=fingerprint:', this.session);
|
||||
fingerprints.forEach(function(line) {
|
||||
tmp = SDPUtil.parse_fingerprint(line);
|
||||
tmp.xmlns = 'urn:xmpp:tmp:jingle:apps:dtls:0';
|
||||
// tmp.xmlns = 'urn:xmpp:jingle:apps:dtls:0'; -- FIXME: update receivers first
|
||||
elem.c('fingerprint').t(tmp.fingerprint);
|
||||
delete tmp.fingerprint;
|
||||
line = SDPUtil.find_line(self.media[mediaindex], 'a=setup:', self.session);
|
||||
if (line) {
|
||||
tmp.setup = line.substr(8);
|
||||
}
|
||||
elem.attrs(tmp);
|
||||
elem.up(); // end of fingerprint
|
||||
});
|
||||
tmp = SDPUtil.iceparams(this.media[mediaindex], this.session);
|
||||
if (tmp) {
|
||||
tmp.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
|
||||
elem.attrs(tmp);
|
||||
// XEP-0176
|
||||
if (SDPUtil.find_line(this.media[mediaindex], 'a=candidate:', this.session)) { // add any a=candidate lines
|
||||
var lines = SDPUtil.find_lines(this.media[mediaindex], 'a=candidate:', this.session);
|
||||
lines.forEach(function (line) {
|
||||
elem.c('candidate', SDPUtil.candidateToJingle(line)).up();
|
||||
});
|
||||
}
|
||||
}
|
||||
elem.up(); // end of transport
|
||||
}
|
||||
|
||||
SDP.prototype.RtcpFbToJingle = function (mediaindex, elem, payloadtype) { // XEP-0293
|
||||
var lines = SDPUtil.find_lines(this.media[mediaindex], 'a=rtcp-fb:' + payloadtype);
|
||||
lines.forEach(function (line) {
|
||||
var tmp = SDPUtil.parse_rtcpfb(line);
|
||||
if (tmp.type == 'trr-int') {
|
||||
elem.c('rtcp-fb-trr-int', {xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0', value: tmp.params[0]});
|
||||
elem.up();
|
||||
} else {
|
||||
elem.c('rtcp-fb', {xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0', type: tmp.type});
|
||||
if (tmp.params.length > 0) {
|
||||
elem.attrs({'subtype': tmp.params[0]});
|
||||
}
|
||||
elem.up();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
SDP.prototype.RtcpFbFromJingle = function (elem, payloadtype) { // XEP-0293
|
||||
var media = '';
|
||||
var tmp = elem.find('>rtcp-fb-trr-int[xmlns="urn:xmpp:jingle:apps:rtp:rtcp-fb:0"]');
|
||||
if (tmp.length) {
|
||||
media += 'a=rtcp-fb:' + '*' + ' ' + 'trr-int' + ' ';
|
||||
if (tmp.attr('value')) {
|
||||
media += tmp.attr('value');
|
||||
} else {
|
||||
media += '0';
|
||||
}
|
||||
media += '\r\n';
|
||||
}
|
||||
tmp = elem.find('>rtcp-fb[xmlns="urn:xmpp:jingle:apps:rtp:rtcp-fb:0"]');
|
||||
tmp.each(function () {
|
||||
media += 'a=rtcp-fb:' + payloadtype + ' ' + $(this).attr('type');
|
||||
if ($(this).attr('subtype')) {
|
||||
media += ' ' + $(this).attr('subtype');
|
||||
}
|
||||
media += '\r\n';
|
||||
});
|
||||
return media;
|
||||
};
|
||||
|
||||
// construct an SDP from a jingle stanza
|
||||
SDP.prototype.fromJingle = function (jingle) {
|
||||
var self = this;
|
||||
this.raw = 'v=0\r\n' +
|
||||
'o=- ' + '1923518516' + ' 2 IN IP4 0.0.0.0\r\n' +// FIXME
|
||||
's=-\r\n' +
|
||||
't=0 0\r\n';
|
||||
// http://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-04#section-8
|
||||
if ($(jingle).find('>group[xmlns="urn:xmpp:jingle:apps:grouping:0"]').length) {
|
||||
$(jingle).find('>group[xmlns="urn:xmpp:jingle:apps:grouping:0"]').each(function (idx, group) {
|
||||
var contents = $(group).find('>content').map(function (idx, content) {
|
||||
return content.getAttribute('name');
|
||||
}).get();
|
||||
if (contents.length > 0) {
|
||||
self.raw += 'a=group:' + (group.getAttribute('semantics') || group.getAttribute('type')) + ' ' + contents.join(' ') + '\r\n';
|
||||
}
|
||||
});
|
||||
} else if ($(jingle).find('>group[xmlns="urn:ietf:rfc:5888"]').length) {
|
||||
// temporary namespace, not to be used. to be removed soon.
|
||||
$(jingle).find('>group[xmlns="urn:ietf:rfc:5888"]').each(function (idx, group) {
|
||||
var contents = $(group).find('>content').map(function (idx, content) {
|
||||
return content.getAttribute('name');
|
||||
}).get();
|
||||
if (group.getAttribute('type') !== null && contents.length > 0) {
|
||||
self.raw += 'a=group:' + group.getAttribute('type') + ' ' + contents.join(' ') + '\r\n';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// for backward compability, to be removed soon
|
||||
// assume all contents are in the same bundle group, can be improved upon later
|
||||
var bundle = $(jingle).find('>content').filter(function (idx, content) {
|
||||
//elem.c('bundle', {xmlns:'http://estos.de/ns/bundle'});
|
||||
return $(content).find('>bundle').length > 0;
|
||||
}).map(function (idx, content) {
|
||||
return content.getAttribute('name');
|
||||
}).get();
|
||||
if (bundle.length) {
|
||||
this.raw += 'a=group:BUNDLE ' + bundle.join(' ') + '\r\n';
|
||||
}
|
||||
}
|
||||
|
||||
this.session = this.raw;
|
||||
jingle.find('>content').each(function () {
|
||||
var m = self.jingle2media($(this));
|
||||
self.media.push(m);
|
||||
});
|
||||
|
||||
// reconstruct msid-semantic -- apparently not necessary
|
||||
/*
|
||||
var msid = SDPUtil.parse_ssrc(this.raw);
|
||||
if (msid.hasOwnProperty('mslabel')) {
|
||||
this.session += "a=msid-semantic: WMS " + msid.mslabel + "\r\n";
|
||||
}
|
||||
*/
|
||||
|
||||
this.raw = this.session + this.media.join('');
|
||||
};
|
||||
|
||||
// translate a jingle content element into an an SDP media part
|
||||
SDP.prototype.jingle2media = function (content) {
|
||||
var media = '',
|
||||
desc = content.find('description'),
|
||||
ssrc = desc.attr('ssrc'),
|
||||
self = this,
|
||||
tmp;
|
||||
|
||||
tmp = { media: desc.attr('media') };
|
||||
tmp.port = '1';
|
||||
if (content.attr('senders') == 'rejected') {
|
||||
// estos hack to reject an m-line.
|
||||
tmp.port = '0';
|
||||
}
|
||||
if (content.find('>transport>fingerprint').length || desc.find('encryption').length) {
|
||||
tmp.proto = 'RTP/SAVPF';
|
||||
} else {
|
||||
tmp.proto = 'RTP/AVPF';
|
||||
}
|
||||
tmp.fmt = desc.find('payload-type').map(function () { return this.getAttribute('id'); }).get();
|
||||
media += SDPUtil.build_mline(tmp) + '\r\n';
|
||||
media += 'c=IN IP4 0.0.0.0\r\n';
|
||||
media += 'a=rtcp:1 IN IP4 0.0.0.0\r\n';
|
||||
tmp = content.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
|
||||
if (tmp.length) {
|
||||
if (tmp.attr('ufrag')) {
|
||||
media += SDPUtil.build_iceufrag(tmp.attr('ufrag')) + '\r\n';
|
||||
}
|
||||
if (tmp.attr('pwd')) {
|
||||
media += SDPUtil.build_icepwd(tmp.attr('pwd')) + '\r\n';
|
||||
}
|
||||
tmp.find('>fingerprint').each(function () {
|
||||
// FIXME: check namespace at some point
|
||||
media += 'a=fingerprint:' + this.getAttribute('hash');
|
||||
media += ' ' + $(this).text();
|
||||
media += '\r\n';
|
||||
if (this.getAttribute('setup')) {
|
||||
media += 'a=setup:' + this.getAttribute('setup') + '\r\n';
|
||||
}
|
||||
});
|
||||
}
|
||||
switch (content.attr('senders')) {
|
||||
case 'initiator':
|
||||
media += 'a=sendonly\r\n';
|
||||
break;
|
||||
case 'responder':
|
||||
media += 'a=recvonly\r\n';
|
||||
break;
|
||||
case 'none':
|
||||
media += 'a=inactive\r\n';
|
||||
break;
|
||||
case 'both':
|
||||
media += 'a=sendrecv\r\n';
|
||||
break;
|
||||
}
|
||||
media += 'a=mid:' + content.attr('name') + '\r\n';
|
||||
|
||||
// <description><rtcp-mux/></description>
|
||||
// see http://code.google.com/p/libjingle/issues/detail?id=309 -- no spec though
|
||||
// and http://mail.jabber.org/pipermail/jingle/2011-December/001761.html
|
||||
if (desc.find('rtcp-mux').length) {
|
||||
media += 'a=rtcp-mux\r\n';
|
||||
}
|
||||
|
||||
if (desc.find('encryption').length) {
|
||||
desc.find('encryption>crypto').each(function () {
|
||||
media += 'a=crypto:' + this.getAttribute('tag');
|
||||
media += ' ' + this.getAttribute('crypto-suite');
|
||||
media += ' ' + this.getAttribute('key-params');
|
||||
if (this.getAttribute('session-params')) {
|
||||
media += ' ' + this.getAttribute('session-params');
|
||||
}
|
||||
media += '\r\n';
|
||||
});
|
||||
}
|
||||
desc.find('payload-type').each(function () {
|
||||
media += SDPUtil.build_rtpmap(this) + '\r\n';
|
||||
if ($(this).find('>parameter').length) {
|
||||
media += 'a=fmtp:' + this.getAttribute('id') + ' ';
|
||||
media += $(this).find('parameter').map(function () { return (this.getAttribute('name') ? (this.getAttribute('name') + '=') : '') + this.getAttribute('value'); }).get().join(';');
|
||||
media += '\r\n';
|
||||
}
|
||||
// xep-0293
|
||||
media += self.RtcpFbFromJingle($(this), this.getAttribute('id'));
|
||||
});
|
||||
|
||||
// xep-0293
|
||||
media += self.RtcpFbFromJingle(desc, '*');
|
||||
|
||||
// xep-0294
|
||||
tmp = desc.find('>rtp-hdrext[xmlns="urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"]');
|
||||
tmp.each(function () {
|
||||
media += 'a=extmap:' + this.getAttribute('id') + ' ' + this.getAttribute('uri') + '\r\n';
|
||||
});
|
||||
|
||||
content.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]>candidate').each(function () {
|
||||
media += SDPUtil.candidateFromJingle(this);
|
||||
});
|
||||
|
||||
tmp = content.find('description>source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]');
|
||||
tmp.each(function () {
|
||||
var ssrc = this.getAttribute('ssrc');
|
||||
$(this).find('>parameter').each(function () {
|
||||
media += 'a=ssrc:' + ssrc + ' ' + this.getAttribute('name');
|
||||
if (this.getAttribute('value') && this.getAttribute('value').length)
|
||||
media += ':' + this.getAttribute('value');
|
||||
media += '\r\n';
|
||||
});
|
||||
});
|
||||
|
||||
if (tmp.length === 0) {
|
||||
// fallback to proprietary mapping of a=ssrc lines
|
||||
tmp = content.find('description>ssrc[xmlns="http://estos.de/ns/ssrc"]');
|
||||
if (tmp.length) {
|
||||
media += 'a=ssrc:' + ssrc + ' cname:' + tmp.attr('cname') + '\r\n';
|
||||
media += 'a=ssrc:' + ssrc + ' msid:' + tmp.attr('msid') + '\r\n';
|
||||
media += 'a=ssrc:' + ssrc + ' mslabel:' + tmp.attr('mslabel') + '\r\n';
|
||||
media += 'a=ssrc:' + ssrc + ' label:' + tmp.attr('label') + '\r\n';
|
||||
}
|
||||
}
|
||||
return media;
|
||||
};
|
||||
|
||||
SDPUtil = {
|
||||
iceparams: function (mediadesc, sessiondesc) {
|
||||
var data = null;
|
||||
if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
|
||||
SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc)) {
|
||||
data = {
|
||||
ufrag: SDPUtil.parse_iceufrag(SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc)),
|
||||
pwd: SDPUtil.parse_icepwd(SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc))
|
||||
};
|
||||
}
|
||||
return data;
|
||||
},
|
||||
parse_iceufrag: function (line) {
|
||||
return line.substring(12);
|
||||
},
|
||||
build_iceufrag: function (frag) {
|
||||
return 'a=ice-ufrag:' + frag;
|
||||
},
|
||||
parse_icepwd: function (line) {
|
||||
return line.substring(10);
|
||||
},
|
||||
build_icepwd: function (pwd) {
|
||||
return 'a=ice-pwd:' + pwd;
|
||||
},
|
||||
parse_mid: function (line) {
|
||||
return line.substring(6);
|
||||
},
|
||||
parse_mline: function (line) {
|
||||
var parts = line.substring(2).split(' '),
|
||||
data = {};
|
||||
data.media = parts.shift();
|
||||
data.port = parts.shift();
|
||||
data.proto = parts.shift();
|
||||
if (parts[parts.length - 1] === '') { // trailing whitespace
|
||||
parts.pop();
|
||||
}
|
||||
data.fmt = parts;
|
||||
return data;
|
||||
},
|
||||
build_mline: function (mline) {
|
||||
return 'm=' + mline.media + ' ' + mline.port + ' ' + mline.proto + ' ' + mline.fmt.join(' ');
|
||||
},
|
||||
parse_rtpmap: function (line) {
|
||||
var parts = line.substring(9).split(' '),
|
||||
data = {};
|
||||
data.id = parts.shift();
|
||||
parts = parts[0].split('/');
|
||||
data.name = parts.shift();
|
||||
data.clockrate = parts.shift();
|
||||
data.channels = parts.length ? parts.shift() : '1';
|
||||
return data;
|
||||
},
|
||||
build_rtpmap: function (el) {
|
||||
var line = 'a=rtpmap:' + el.getAttribute('id') + ' ' + el.getAttribute('name') + '/' + el.getAttribute('clockrate');
|
||||
if (el.getAttribute('channels') && el.getAttribute('channels') != '1') {
|
||||
line += '/' + el.getAttribute('channels');
|
||||
}
|
||||
return line;
|
||||
},
|
||||
parse_crypto: function (line) {
|
||||
var parts = line.substring(9).split(' '),
|
||||
data = {};
|
||||
data.tag = parts.shift();
|
||||
data['crypto-suite'] = parts.shift();
|
||||
data['key-params'] = parts.shift();
|
||||
if (parts.length) {
|
||||
data['session-params'] = parts.join(' ');
|
||||
}
|
||||
return data;
|
||||
},
|
||||
parse_fingerprint: function (line) { // RFC 4572
|
||||
var parts = line.substring(14).split(' '),
|
||||
data = {};
|
||||
data.hash = parts.shift();
|
||||
data.fingerprint = parts.shift();
|
||||
// TODO assert that fingerprint satisfies 2UHEX *(":" 2UHEX) ?
|
||||
return data;
|
||||
},
|
||||
parse_fmtp: function (line) {
|
||||
var parts = line.split(' '),
|
||||
i, key, value,
|
||||
data = [];
|
||||
parts.shift();
|
||||
parts = parts.join(' ').split(';');
|
||||
for (i = 0; i < parts.length; i++) {
|
||||
key = parts[i].split('=')[0];
|
||||
while (key.length && key[0] == ' ') {
|
||||
key = key.substring(1);
|
||||
}
|
||||
value = parts[i].split('=')[1];
|
||||
if (key && value) {
|
||||
data.push({name: key, value: value});
|
||||
} else if (key) {
|
||||
// rfc 4733 (DTMF) style stuff
|
||||
data.push({name: '', value: key});
|
||||
}
|
||||
}
|
||||
return data;
|
||||
},
|
||||
parse_icecandidate: function (line) {
|
||||
var candidate = {},
|
||||
elems = line.split(' ');
|
||||
candidate.foundation = elems[0].substring(12);
|
||||
candidate.component = elems[1];
|
||||
candidate.protocol = elems[2].toLowerCase();
|
||||
candidate.priority = elems[3];
|
||||
candidate.ip = elems[4];
|
||||
candidate.port = elems[5];
|
||||
// elems[6] => "typ"
|
||||
candidate.type = elems[7];
|
||||
candidate.generation = 0; // default value, may be overwritten below
|
||||
for (var i = 8; i < elems.length; i += 2) {
|
||||
switch (elems[i]) {
|
||||
case 'raddr':
|
||||
candidate['rel-addr'] = elems[i + 1];
|
||||
break;
|
||||
case 'rport':
|
||||
candidate['rel-port'] = elems[i + 1];
|
||||
break;
|
||||
case 'generation':
|
||||
candidate.generation = elems[i + 1];
|
||||
break;
|
||||
default: // TODO
|
||||
console.log('parse_icecandidate not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
|
||||
}
|
||||
}
|
||||
candidate.network = '1';
|
||||
candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
|
||||
return candidate;
|
||||
},
|
||||
build_icecandidate: function (cand) {
|
||||
var line = ['a=candidate:' + cand.foundation, cand.component, cand.protocol, cand.priority, cand.ip, cand.port, 'typ', cand.type].join(' ');
|
||||
line += ' ';
|
||||
switch (cand.type) {
|
||||
case 'srflx':
|
||||
case 'prflx':
|
||||
case 'relay':
|
||||
if (cand.hasOwnAttribute('rel-addr') && cand.hasOwnAttribute('rel-port')) {
|
||||
line += 'raddr';
|
||||
line += ' ';
|
||||
line += cand['rel-addr'];
|
||||
line += ' ';
|
||||
line += 'rport';
|
||||
line += ' ';
|
||||
line += cand['rel-port'];
|
||||
line += ' ';
|
||||
}
|
||||
break;
|
||||
}
|
||||
line += 'generation';
|
||||
line += ' ';
|
||||
line += cand.hasOwnAttribute('generation') ? cand.generation : '0';
|
||||
return line;
|
||||
},
|
||||
parse_ssrc: function (desc) {
|
||||
// proprietary mapping of a=ssrc lines
|
||||
// TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher on google docs
|
||||
// and parse according to that
|
||||
var lines = desc.split('\r\n'),
|
||||
data = {};
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
if (lines[i].substring(0, 7) == 'a=ssrc:') {
|
||||
var idx = lines[i].indexOf(' ');
|
||||
data[lines[i].substr(idx + 1).split(':', 2)[0]] = lines[i].substr(idx + 1).split(':', 2)[1];
|
||||
}
|
||||
}
|
||||
return data;
|
||||
},
|
||||
parse_rtcpfb: function (line) {
|
||||
var parts = line.substr(10).split(' ');
|
||||
var data = {};
|
||||
data.pt = parts.shift();
|
||||
data.type = parts.shift();
|
||||
data.params = parts;
|
||||
return data;
|
||||
},
|
||||
parse_extmap: function (line) {
|
||||
var parts = line.substr(9).split(' ');
|
||||
var data = {};
|
||||
data.value = parts.shift();
|
||||
if (data.value.indexOf('/') != -1) {
|
||||
data.direction = data.value.substr(data.value.indexOf('/') + 1);
|
||||
data.value = data.value.substr(0, data.value.indexOf('/'));
|
||||
} else {
|
||||
data.direction = 'both';
|
||||
}
|
||||
data.uri = parts.shift();
|
||||
data.params = parts;
|
||||
return data;
|
||||
},
|
||||
find_line: function (haystack, needle, sessionpart) {
|
||||
var lines = haystack.split('\r\n');
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
if (lines[i].substring(0, needle.length) == needle) {
|
||||
return lines[i];
|
||||
}
|
||||
}
|
||||
if (!sessionpart) {
|
||||
return false;
|
||||
}
|
||||
// search session part
|
||||
lines = sessionpart.split('\r\n');
|
||||
for (var j = 0; j < lines.length; j++) {
|
||||
if (lines[j].substring(0, needle.length) == needle) {
|
||||
return lines[j];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
find_lines: function (haystack, needle, sessionpart) {
|
||||
var lines = haystack.split('\r\n'),
|
||||
needles = [];
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
if (lines[i].substring(0, needle.length) == needle)
|
||||
needles.push(lines[i]);
|
||||
}
|
||||
if (needles.length || !sessionpart) {
|
||||
return needles;
|
||||
}
|
||||
// search session part
|
||||
lines = sessionpart.split('\r\n');
|
||||
for (var j = 0; j < lines.length; j++) {
|
||||
if (lines[j].substring(0, needle.length) == needle) {
|
||||
needles.push(lines[j]);
|
||||
}
|
||||
}
|
||||
return needles;
|
||||
},
|
||||
candidateToJingle: function (line) {
|
||||
// a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host generation 0
|
||||
// <candidate component=... foundation=... generation=... id=... ip=... network=... port=... priority=... protocol=... type=.../>
|
||||
if (line.substring(0, 12) != 'a=candidate:') {
|
||||
console.log('parseCandidate called with a line that is not a candidate line');
|
||||
console.log(line);
|
||||
return null;
|
||||
}
|
||||
if (line.substring(line.length - 2) == '\r\n') // chomp it
|
||||
line = line.substring(0, line.length - 2);
|
||||
var candidate = {},
|
||||
elems = line.split(' '),
|
||||
i;
|
||||
if (elems[6] != 'typ') {
|
||||
console.log('did not find typ in the right place');
|
||||
console.log(line);
|
||||
return null;
|
||||
}
|
||||
candidate.foundation = elems[0].substring(12);
|
||||
candidate.component = elems[1];
|
||||
candidate.protocol = elems[2].toLowerCase();
|
||||
candidate.priority = elems[3];
|
||||
candidate.ip = elems[4];
|
||||
candidate.port = elems[5];
|
||||
// elems[6] => "typ"
|
||||
candidate.type = elems[7];
|
||||
for (i = 8; i < elems.length; i += 2) {
|
||||
switch (elems[i]) {
|
||||
case 'raddr':
|
||||
candidate['rel-addr'] = elems[i + 1];
|
||||
break;
|
||||
case 'rport':
|
||||
candidate['rel-port'] = elems[i + 1];
|
||||
break;
|
||||
case 'generation':
|
||||
candidate.generation = elems[i + 1];
|
||||
break;
|
||||
default: // TODO
|
||||
console.log('not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
|
||||
}
|
||||
}
|
||||
candidate.network = '1';
|
||||
candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
|
||||
return candidate;
|
||||
},
|
||||
candidateFromJingle: function (cand) {
|
||||
var line = 'a=candidate:';
|
||||
line += cand.getAttribute('foundation');
|
||||
line += ' ';
|
||||
line += cand.getAttribute('component');
|
||||
line += ' ';
|
||||
line += cand.getAttribute('protocol'); //.toUpperCase(); // chrome M23 doesn't like this
|
||||
line += ' ';
|
||||
line += cand.getAttribute('priority');
|
||||
line += ' ';
|
||||
line += cand.getAttribute('ip');
|
||||
line += ' ';
|
||||
line += cand.getAttribute('port');
|
||||
line += ' ';
|
||||
line += 'typ';
|
||||
line += ' ' + cand.getAttribute('type');
|
||||
line += ' ';
|
||||
switch (cand.getAttribute('type')) {
|
||||
case 'srflx':
|
||||
case 'prflx':
|
||||
case 'relay':
|
||||
if (cand.getAttribute('rel-addr') && cand.getAttribute('rel-port')) {
|
||||
line += 'raddr';
|
||||
line += ' ';
|
||||
line += cand.getAttribute('rel-addr');
|
||||
line += ' ';
|
||||
line += 'rport';
|
||||
line += ' ';
|
||||
line += cand.getAttribute('rel-port');
|
||||
line += ' ';
|
||||
}
|
||||
break;
|
||||
}
|
||||
line += 'generation';
|
||||
line += ' ';
|
||||
line += cand.getAttribute('generation') || '0';
|
||||
return line + '\r\n';
|
||||
}
|
||||
};
|
||||
}(jQuery));
|
||||
@@ -1,859 +0,0 @@
|
||||
/* jshint -W117 */
|
||||
// Jingle stuff
|
||||
var JingleSession;
|
||||
|
||||
(function($){
|
||||
JingleSession = function(me, sid, connection) {
|
||||
this.me = me;
|
||||
this.sid = sid;
|
||||
this.connection = connection;
|
||||
this.initiator = null;
|
||||
this.responder = null;
|
||||
this.isInitiator = null;
|
||||
this.peerjid = null;
|
||||
this.state = null;
|
||||
this.peerconnection = null;
|
||||
this.remoteStream = null;
|
||||
this.localSDP = null;
|
||||
this.remoteSDP = null;
|
||||
this.localStreams = [];
|
||||
this.relayedStreams = [];
|
||||
this.remoteStreams = [];
|
||||
this.startTime = null;
|
||||
this.stopTime = null;
|
||||
this.media_constraints = null;
|
||||
this.pc_constraints = null;
|
||||
this.ice_config = {},
|
||||
this.drip_container = [];
|
||||
|
||||
this.usetrickle = true;
|
||||
this.usepranswer = false; // early transport warmup -- mind you, this might fail. depends on webrtc issue 1718
|
||||
this.usedrip = false; // dripping is sending trickle candidates not one-by-one
|
||||
|
||||
this.hadstuncandidate = false;
|
||||
this.hadturncandidate = false;
|
||||
this.lasticecandidate = false;
|
||||
|
||||
this.statsinterval = null;
|
||||
|
||||
this.reason = null;
|
||||
|
||||
this.addssrc = [];
|
||||
this.removessrc = [];
|
||||
|
||||
this.wait = true;
|
||||
}
|
||||
|
||||
JingleSession.prototype.initiate = function (peerjid, isInitiator) {
|
||||
var self = this;
|
||||
if (this.state !== null) {
|
||||
console.error('attempt to initiate on session ' + this.sid +
|
||||
'in state ' + this.state);
|
||||
return;
|
||||
}
|
||||
this.isInitiator = isInitiator;
|
||||
this.state = 'pending';
|
||||
this.initiator = isInitiator ? this.me : peerjid;
|
||||
this.responder = !isInitiator ? this.me : peerjid;
|
||||
this.peerjid = peerjid;
|
||||
//console.log('create PeerConnection ' + JSON.stringify(this.ice_config));
|
||||
try {
|
||||
this.peerconnection = new RTCPeerconnection(this.ice_config,
|
||||
this.pc_constraints);
|
||||
} catch (e) {
|
||||
console.error('Failed to create PeerConnection, exception: ',
|
||||
e.message);
|
||||
console.error(e);
|
||||
return;
|
||||
}
|
||||
this.hadstuncandidate = false;
|
||||
this.hadturncandidate = false;
|
||||
this.lasticecandidate = false;
|
||||
this.peerconnection.onicecandidate = function (event) {
|
||||
self.sendIceCandidate(event.candidate);
|
||||
};
|
||||
this.peerconnection.onaddstream = function (event) {
|
||||
self.remoteStream = event.stream;
|
||||
self.remoteStreams.push(event.stream);
|
||||
$(document).trigger('remotestreamadded.jingle', [event, self.sid]);
|
||||
};
|
||||
this.peerconnection.onremovestream = function (event) {
|
||||
self.remoteStream = null;
|
||||
// FIXME: remove from this.remoteStreams
|
||||
$(document).trigger('remotestreamremoved.jingle', [event, self.sid]);
|
||||
};
|
||||
this.peerconnection.onsignalingstatechange = function (event) {
|
||||
if (!(self && self.peerconnection)) return;
|
||||
};
|
||||
this.peerconnection.oniceconnectionstatechange = function (event) {
|
||||
if (!(self && self.peerconnection)) return;
|
||||
switch (self.peerconnection.iceConnectionState) {
|
||||
case 'connected':
|
||||
this.startTime = new Date();
|
||||
break;
|
||||
case 'disconnected':
|
||||
this.stopTime = new Date();
|
||||
break;
|
||||
}
|
||||
$(document).trigger('iceconnectionstatechange.jingle', [self.sid, self]);
|
||||
};
|
||||
// add any local and relayed stream
|
||||
this.localStreams.forEach(function(stream) {
|
||||
self.peerconnection.addStream(stream);
|
||||
});
|
||||
this.relayedStreams.forEach(function(stream) {
|
||||
self.peerconnection.addStream(stream);
|
||||
});
|
||||
};
|
||||
|
||||
JingleSession.prototype.accept = function () {
|
||||
var self = this;
|
||||
this.state = 'active';
|
||||
|
||||
var pranswer = this.peerconnection.localDescription;
|
||||
if (!pranswer || pranswer.type != 'pranswer') {
|
||||
return;
|
||||
}
|
||||
console.log('going from pranswer to answer');
|
||||
if (this.usetrickle) {
|
||||
// remove candidates already sent from session-accept
|
||||
var lines = SDPUtil.find_lines(pranswer.sdp, 'a=candidate:');
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
pranswer.sdp = pranswer.sdp.replace(lines[i] + '\r\n', '');
|
||||
}
|
||||
}
|
||||
while (SDPUtil.find_line(pranswer.sdp, 'a=inactive')) {
|
||||
// FIXME: change any inactive to sendrecv or whatever they were originally
|
||||
pranswer.sdp = pranswer.sdp.replace('a=inactive', 'a=sendrecv');
|
||||
}
|
||||
var prsdp = new SDP(pranswer.sdp);
|
||||
var accept = $iq({to: this.peerjid,
|
||||
type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: 'session-accept',
|
||||
initiator: this.initiator,
|
||||
responder: this.responder,
|
||||
sid: this.sid });
|
||||
prsdp.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder');
|
||||
this.connection.sendIQ(accept,
|
||||
function () {
|
||||
var ack = {};
|
||||
ack.source = 'answer';
|
||||
$(document).trigger('ack.jingle', [self.sid, ack]);
|
||||
},
|
||||
function (stanza) {
|
||||
var error = ($(stanza).find('error').length) ? {
|
||||
code: $(stanza).find('error').attr('code'),
|
||||
reason: $(stanza).find('error :first')[0].tagName,
|
||||
}:{};
|
||||
error.source = 'answer';
|
||||
$(document).trigger('error.jingle', [self.sid, error]);
|
||||
},
|
||||
10000);
|
||||
|
||||
var sdp = this.peerconnection.localDescription.sdp;
|
||||
while (SDPUtil.find_line(sdp, 'a=inactive')) {
|
||||
// FIXME: change any inactive to sendrecv or whatever they were originally
|
||||
sdp = sdp.replace('a=inactive', 'a=sendrecv');
|
||||
}
|
||||
this.peerconnection.setLocalDescription(new RTCSessionDescription({type: 'answer', sdp: sdp}),
|
||||
function () {
|
||||
//console.log('setLocalDescription success');
|
||||
},
|
||||
function (e) {
|
||||
console.error('setLocalDescription failed', e);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
JingleSession.prototype.terminate = function (reason) {
|
||||
this.state = 'ended';
|
||||
this.reason = reason;
|
||||
this.peerconnection.close();
|
||||
if (this.statsinterval !== null) {
|
||||
window.clearInterval(this.statsinterval);
|
||||
this.statsinterval = null;
|
||||
}
|
||||
};
|
||||
|
||||
JingleSession.prototype.active = function () {
|
||||
return this.state == 'active';
|
||||
};
|
||||
|
||||
JingleSession.prototype.sendIceCandidate = function (candidate) {
|
||||
var self = this;
|
||||
if (candidate && !this.lasticecandidate) {
|
||||
var ice = SDPUtil.iceparams(this.localSDP.media[candidate.sdpMLineIndex], this.localSDP.session);
|
||||
var jcand = SDPUtil.candidateToJingle(candidate.candidate);
|
||||
if (!(ice && jcand)) {
|
||||
console.error('failed to get ice && jcand');
|
||||
return;
|
||||
}
|
||||
ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
|
||||
|
||||
if (jcand.type === 'srflx') {
|
||||
this.hadstuncandidate = true;
|
||||
} else if (jcand.type === 'relay') {
|
||||
this.hadturncandidate = true;
|
||||
}
|
||||
|
||||
if (this.usetrickle) {
|
||||
if (this.usedrip) {
|
||||
if (this.drip_container.length === 0) {
|
||||
// start 10ms callout
|
||||
window.setTimeout(function () {
|
||||
if (self.drip_container.length === 0) return;
|
||||
var allcands = self.drip_container;
|
||||
self.drip_container = [];
|
||||
var cand = $iq({to: self.peerjid, type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: 'transport-info',
|
||||
initiator: self.initiator,
|
||||
sid: self.sid});
|
||||
for (var mid = 0; mid < self.localSDP.media.length; mid++) {
|
||||
var cands = allcands.filter(function (el) { return el.sdpMLineIndex == mid; });
|
||||
if (cands.length > 0) {
|
||||
var ice = SDPUtil.iceparams(self.localSDP.media[mid], self.localSDP.session);
|
||||
ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
|
||||
cand.c('content', {creator: self.initiator == self.me ? 'initiator' : 'responder',
|
||||
name: cands[0].sdpMid
|
||||
}).c('transport', ice);
|
||||
for (var i = 0; i < cands.length; i++) {
|
||||
cand.c('candidate', SDPUtil.candidateToJingle(cands[i].candidate)).up();
|
||||
}
|
||||
// add fingerprint
|
||||
if (SDPUtil.find_line(self.localSDP.media[mid], 'a=fingerprint:', self.localSDP.session)) {
|
||||
var tmp = SDPUtil.parse_fingerprint(SDPUtil.find_line(self.localSDP.media[mid], 'a=fingerprint:', self.localSDP.session));
|
||||
tmp.required = true;
|
||||
cand.c('fingerprint').t(tmp.fingerprint);
|
||||
delete tmp.fingerprint;
|
||||
cand.attrs(tmp);
|
||||
cand.up();
|
||||
}
|
||||
cand.up(); // transport
|
||||
cand.up(); // content
|
||||
}
|
||||
}
|
||||
// might merge last-candidate notification into this, but it is called alot later. See webrtc issue #2340
|
||||
//console.log('was this the last candidate', self.lasticecandidate);
|
||||
self.connection.sendIQ(cand,
|
||||
function () {
|
||||
var ack = {};
|
||||
ack.source = 'transportinfo';
|
||||
$(document).trigger('ack.jingle', [self.sid, ack]);
|
||||
},
|
||||
function (stanza) {
|
||||
var error = ($(stanza).find('error').length) ? {
|
||||
code: $(stanza).find('error').attr('code'),
|
||||
reason: $(stanza).find('error :first')[0].tagName,
|
||||
}:{};
|
||||
error.source = 'transportinfo';
|
||||
$(document).trigger('error.jingle', [self.sid, error]);
|
||||
},
|
||||
10000);
|
||||
}, 10);
|
||||
}
|
||||
this.drip_container.push(event.candidate);
|
||||
return;
|
||||
}
|
||||
// map to transport-info
|
||||
var cand = $iq({to: this.peerjid, type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: 'transport-info',
|
||||
initiator: this.initiator,
|
||||
sid: this.sid})
|
||||
.c('content', {creator: this.initiator == this.me ? 'initiator' : 'responder',
|
||||
name: candidate.sdpMid
|
||||
})
|
||||
.c('transport', ice)
|
||||
.c('candidate', jcand);
|
||||
cand.up();
|
||||
// add fingerprint
|
||||
if (SDPUtil.find_line(this.localSDP.media[candidate.sdpMLineIndex], 'a=fingerprint:', this.localSDP.session)) {
|
||||
var tmp = SDPUtil.parse_fingerprint(SDPUtil.find_line(this.localSDP.media[candidate.sdpMLineIndex], 'a=fingerprint:', this.localSDP.session));
|
||||
tmp.required = true;
|
||||
cand.c('fingerprint').t(tmp.fingerprint);
|
||||
delete tmp.fingerprint;
|
||||
cand.attrs(tmp);
|
||||
cand.up();
|
||||
}
|
||||
this.connection.sendIQ(cand,
|
||||
function () {
|
||||
var ack = {};
|
||||
ack.source = 'transportinfo';
|
||||
$(document).trigger('ack.jingle', [self.sid, ack]);
|
||||
},
|
||||
function (stanza) {
|
||||
console.error('transport info error');
|
||||
var error = ($(stanza).find('error').length) ? {
|
||||
code: $(stanza).find('error').attr('code'),
|
||||
reason: $(stanza).find('error :first')[0].tagName,
|
||||
}:{};
|
||||
error.source = 'transportinfo';
|
||||
$(document).trigger('error.jingle', [self.sid, error]);
|
||||
},
|
||||
10000);
|
||||
}
|
||||
} else {
|
||||
//console.log('sendIceCandidate: last candidate.');
|
||||
if (!this.usetrickle) {
|
||||
//console.log('should send full offer now...');
|
||||
var init = $iq({to: this.peerjid,
|
||||
type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: this.peerconnection.localDescription.type == 'offer' ? 'session-initiate' : 'session-accept',
|
||||
initiator: this.initiator,
|
||||
sid: this.sid});
|
||||
this.localSDP = new SDP(this.peerconnection.localDescription.sdp);
|
||||
this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder');
|
||||
this.connection.sendIQ(init,
|
||||
function () {
|
||||
//console.log('session initiate ack');
|
||||
var ack = {};
|
||||
ack.source = 'offer';
|
||||
$(document).trigger('ack.jingle', [self.sid, ack]);
|
||||
},
|
||||
function (stanza) {
|
||||
self.state = 'error';
|
||||
self.peerconnection.close();
|
||||
var error = ($(stanza).find('error').length) ? {
|
||||
code: $(stanza).find('error').attr('code'),
|
||||
reason: $(stanza).find('error :first')[0].tagName,
|
||||
}:{};
|
||||
error.source = 'offer';
|
||||
$(document).trigger('error.jingle', [self.sid, error]);
|
||||
},
|
||||
10000);
|
||||
}
|
||||
this.lasticecandidate = true;
|
||||
console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate);
|
||||
console.log('Have we encountered any relay candidates? ' + this.hadturncandidate);
|
||||
|
||||
if (!(this.hadstuncandidate || this.hadturncandidate) && this.peerconnection.signalingState != 'closed') {
|
||||
$(document).trigger('nostuncandidates.jingle', [this.sid]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JingleSession.prototype.sendOffer = function () {
|
||||
//console.log('sendOffer...');
|
||||
var self = this;
|
||||
this.peerconnection.createOffer(function (sdp) {
|
||||
self.createdOffer(sdp);
|
||||
},
|
||||
function (e) {
|
||||
console.error('createOffer failed', e);
|
||||
},
|
||||
this.media_constraints
|
||||
);
|
||||
};
|
||||
|
||||
JingleSession.prototype.createdOffer = function (sdp) {
|
||||
//console.log('createdOffer', sdp);
|
||||
var self = this;
|
||||
this.localSDP = new SDP(sdp.sdp);
|
||||
//this.localSDP.mangle();
|
||||
if (this.usetrickle) {
|
||||
var init = $iq({to: this.peerjid,
|
||||
type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: 'session-initiate',
|
||||
initiator: this.initiator,
|
||||
sid: this.sid});
|
||||
this.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder');
|
||||
this.connection.sendIQ(init,
|
||||
function () {
|
||||
var ack = {};
|
||||
ack.source = 'offer';
|
||||
$(document).trigger('ack.jingle', [self.sid, ack]);
|
||||
},
|
||||
function (stanza) {
|
||||
self.state = 'error';
|
||||
self.peerconnection.close();
|
||||
var error = ($(stanza).find('error').length) ? {
|
||||
code: $(stanza).find('error').attr('code'),
|
||||
reason: $(stanza).find('error :first')[0].tagName,
|
||||
}:{};
|
||||
error.source = 'offer';
|
||||
$(document).trigger('error.jingle', [self.sid, error]);
|
||||
},
|
||||
10000);
|
||||
}
|
||||
sdp.sdp = this.localSDP.raw;
|
||||
this.peerconnection.setLocalDescription(sdp,
|
||||
function () {
|
||||
//console.log('setLocalDescription success');
|
||||
},
|
||||
function (e) {
|
||||
console.error('setLocalDescription failed', e);
|
||||
}
|
||||
);
|
||||
var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
|
||||
for (var i = 0; i < cands.length; i++) {
|
||||
var cand = SDPUtil.parse_icecandidate(cands[i]);
|
||||
if (cand.type == 'srflx') {
|
||||
this.hadstuncandidate = true;
|
||||
} else if (cand.type == 'relay') {
|
||||
this.hadturncandidate = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JingleSession.prototype.setRemoteDescription = function (elem, desctype) {
|
||||
//console.log('setting remote description... ', desctype);
|
||||
this.remoteSDP = new SDP('');
|
||||
this.remoteSDP.fromJingle(elem);
|
||||
if (this.peerconnection.remoteDescription !== null) {
|
||||
console.log('setRemoteDescription when remote description is not null, should be pranswer', this.peerconnection.remoteDescription);
|
||||
if (this.peerconnection.remoteDescription.type == 'pranswer') {
|
||||
var pranswer = new SDP(this.peerconnection.remoteDescription.sdp);
|
||||
for (var i = 0; i < pranswer.media.length; i++) {
|
||||
// make sure we have ice ufrag and pwd
|
||||
if (!SDPUtil.find_line(this.remoteSDP.media[i], 'a=ice-ufrag:', this.remoteSDP.session)) {
|
||||
if (SDPUtil.find_line(pranswer.media[i], 'a=ice-ufrag:', pranswer.session)) {
|
||||
this.remoteSDP.media[i] += SDPUtil.find_line(pranswer.media[i], 'a=ice-ufrag:', pranswer.session) + '\r\n';
|
||||
} else {
|
||||
console.warn('no ice ufrag?');
|
||||
}
|
||||
if (SDPUtil.find_line(pranswer.media[i], 'a=ice-pwd:', pranswer.session)) {
|
||||
this.remoteSDP.media[i] += SDPUtil.find_line(pranswer.media[i], 'a=ice-pwd:', pranswer.session) + '\r\n';
|
||||
} else {
|
||||
console.warn('no ice pwd?');
|
||||
}
|
||||
}
|
||||
// copy over candidates
|
||||
var lines = SDPUtil.find_lines(pranswer.media[i], 'a=candidate:');
|
||||
for (var j = 0; j < lines.length; j++) {
|
||||
this.remoteSDP.media[i] += lines[j] + '\r\n';
|
||||
}
|
||||
}
|
||||
this.remoteSDP.raw = this.remoteSDP.session + this.remoteSDP.media.join('');
|
||||
}
|
||||
}
|
||||
var remotedesc = new RTCSessionDescription({type: desctype, sdp: this.remoteSDP.raw});
|
||||
|
||||
this.peerconnection.setRemoteDescription(remotedesc,
|
||||
function () {
|
||||
//console.log('setRemoteDescription success');
|
||||
},
|
||||
function (e) {
|
||||
console.error('setRemoteDescription error', e);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
JingleSession.prototype.addIceCandidate = function (elem) {
|
||||
var self = this;
|
||||
if (this.peerconnection.signalingState == 'closed') {
|
||||
return;
|
||||
}
|
||||
if (!this.peerconnection.remoteDescription && this.peerconnection.signalingState == 'have-local-offer') {
|
||||
console.log('trickle ice candidate arriving before session accept...');
|
||||
// create a PRANSWER for setRemoteDescription
|
||||
if (!this.remoteSDP) {
|
||||
var cobbled = 'v=0\r\n' +
|
||||
'o=- ' + '1923518516' + ' 2 IN IP4 0.0.0.0\r\n' +// FIXME
|
||||
's=-\r\n' +
|
||||
't=0 0\r\n';
|
||||
// first, take some things from the local description
|
||||
for (var i = 0; i < this.localSDP.media.length; i++) {
|
||||
cobbled += SDPUtil.find_line(this.localSDP.media[i], 'm=') + '\r\n';
|
||||
cobbled += SDPUtil.find_lines(this.localSDP.media[i], 'a=rtpmap:').join('\r\n') + '\r\n';
|
||||
if (SDPUtil.find_line(this.localSDP.media[i], 'a=mid:')) {
|
||||
cobbled += SDPUtil.find_line(this.localSDP.media[i], 'a=mid:') + '\r\n';
|
||||
}
|
||||
cobbled += 'a=inactive\r\n';
|
||||
}
|
||||
this.remoteSDP = new SDP(cobbled);
|
||||
}
|
||||
// then add things like ice and dtls from remote candidate
|
||||
elem.each(function () {
|
||||
for (var i = 0; i < self.remoteSDP.media.length; i++) {
|
||||
if (SDPUtil.find_line(self.remoteSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
|
||||
self.remoteSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
|
||||
if (!SDPUtil.find_line(self.remoteSDP.media[i], 'a=ice-ufrag:')) {
|
||||
var tmp = $(this).find('transport');
|
||||
self.remoteSDP.media[i] += 'a=ice-ufrag:' + tmp.attr('ufrag') + '\r\n';
|
||||
self.remoteSDP.media[i] += 'a=ice-pwd:' + tmp.attr('pwd') + '\r\n';
|
||||
tmp = $(this).find('transport>fingerprint');
|
||||
if (tmp.length) {
|
||||
self.remoteSDP.media[i] += 'a=fingerprint:' + tmp.attr('hash') + ' ' + tmp.text() + '\r\n';
|
||||
} else {
|
||||
console.log('no dtls fingerprint (webrtc issue #1718?)');
|
||||
self.remoteSDP.media[i] += 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:BAADBAADBAADBAADBAADBAADBAADBAADBAADBAAD\r\n';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this.remoteSDP.raw = this.remoteSDP.session + this.remoteSDP.media.join('');
|
||||
|
||||
// we need a complete SDP with ice-ufrag/ice-pwd in all parts
|
||||
// this makes the assumption that the PRANSWER is constructed such that the ice-ufrag is in all mediaparts
|
||||
// but it could be in the session part as well. since the code above constructs this sdp this can't happen however
|
||||
var iscomplete = this.remoteSDP.media.filter(function (mediapart) {
|
||||
return SDPUtil.find_line(mediapart, 'a=ice-ufrag:');
|
||||
}).length == this.remoteSDP.media.length;
|
||||
|
||||
if (iscomplete) {
|
||||
console.log('setting pranswer');
|
||||
try {
|
||||
this.peerconnection.setRemoteDescription(new RTCSessionDescription({type: 'pranswer', sdp: this.remoteSDP.raw }),
|
||||
function() {
|
||||
},
|
||||
function(e) {
|
||||
console.log('setRemoteDescription pranswer failed', e.toString());
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('setting pranswer failed', e);
|
||||
}
|
||||
} else {
|
||||
//console.log('not yet setting pranswer');
|
||||
}
|
||||
}
|
||||
// operate on each content element
|
||||
elem.each(function () {
|
||||
// would love to deactivate this, but firefox still requires it
|
||||
var idx = -1;
|
||||
var i;
|
||||
for (i = 0; i < self.remoteSDP.media.length; i++) {
|
||||
if (SDPUtil.find_line(self.remoteSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
|
||||
self.remoteSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx == -1) { // fall back to localdescription
|
||||
for (i = 0; i < self.localSDP.media.length; i++) {
|
||||
if (SDPUtil.find_line(self.localSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
|
||||
self.localSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
var name = $(this).attr('name');
|
||||
// TODO: check ice-pwd and ice-ufrag?
|
||||
$(this).find('transport>candidate').each(function () {
|
||||
var line, candidate;
|
||||
line = SDPUtil.candidateFromJingle(this);
|
||||
candidate = new RTCIceCandidate({sdpMLineIndex: idx,
|
||||
sdpMid: name,
|
||||
candidate: line});
|
||||
try {
|
||||
self.peerconnection.addIceCandidate(candidate);
|
||||
} catch (e) {
|
||||
console.error('addIceCandidate failed', e.toString(), line);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
JingleSession.prototype.sendAnswer = function (provisional) {
|
||||
//console.log('createAnswer', provisional);
|
||||
var self = this;
|
||||
this.peerconnection.createAnswer(
|
||||
function (sdp) {
|
||||
self.createdAnswer(sdp, provisional);
|
||||
},
|
||||
function (e) {
|
||||
console.error('createAnswer failed', e);
|
||||
},
|
||||
this.media_constraints
|
||||
);
|
||||
};
|
||||
|
||||
JingleSession.prototype.createdAnswer = function (sdp, provisional) {
|
||||
//console.log('createAnswer callback');
|
||||
console.log(sdp);
|
||||
var self = this;
|
||||
this.localSDP = new SDP(sdp.sdp);
|
||||
//this.localSDP.mangle();
|
||||
this.usepranswer = provisional === true;
|
||||
if (this.usetrickle) {
|
||||
if (!this.usepranswer) {
|
||||
var accept = $iq({to: this.peerjid,
|
||||
type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: 'session-accept',
|
||||
initiator: this.initiator,
|
||||
responder: this.responder,
|
||||
sid: this.sid });
|
||||
this.localSDP.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder');
|
||||
this.connection.sendIQ(accept,
|
||||
function () {
|
||||
var ack = {};
|
||||
ack.source = 'answer';
|
||||
$(document).trigger('ack.jingle', [self.sid, ack]);
|
||||
},
|
||||
function (stanza) {
|
||||
var error = ($(stanza).find('error').length) ? {
|
||||
code: $(stanza).find('error').attr('code'),
|
||||
reason: $(stanza).find('error :first')[0].tagName,
|
||||
}:{};
|
||||
error.source = 'answer';
|
||||
$(document).trigger('error.jingle', [self.sid, error]);
|
||||
},
|
||||
10000);
|
||||
} else {
|
||||
sdp.type = 'pranswer';
|
||||
for (var i = 0; i < this.localSDP.media.length; i++) {
|
||||
this.localSDP.media[i] = this.localSDP.media[i].replace('a=sendrecv\r\n', 'a=inactive\r\n');
|
||||
}
|
||||
this.localSDP.raw = this.localSDP.session + '\r\n' + this.localSDP.media.join('');
|
||||
}
|
||||
}
|
||||
sdp.sdp = this.localSDP.raw;
|
||||
this.peerconnection.setLocalDescription(sdp,
|
||||
function () {
|
||||
//console.log('setLocalDescription success');
|
||||
},
|
||||
function (e) {
|
||||
console.error('setLocalDescription failed', e);
|
||||
}
|
||||
);
|
||||
var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
|
||||
for (var j = 0; j < cands.length; j++) {
|
||||
var cand = SDPUtil.parse_icecandidate(cands[j]);
|
||||
if (cand.type == 'srflx') {
|
||||
this.hadstuncandidate = true;
|
||||
} else if (cand.type == 'relay') {
|
||||
this.hadturncandidate = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JingleSession.prototype.sendTerminate = function (reason, text) {
|
||||
var self = this,
|
||||
term = $iq({to: this.peerjid,
|
||||
type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: 'session-terminate',
|
||||
initiator: this.initiator,
|
||||
sid: this.sid})
|
||||
.c('reason')
|
||||
.c(reason || 'success');
|
||||
|
||||
if (text) {
|
||||
term.up().c('text').t(text);
|
||||
}
|
||||
|
||||
this.connection.sendIQ(term,
|
||||
function () {
|
||||
self.peerconnection.close();
|
||||
self.peerconnection = null;
|
||||
self.terminate();
|
||||
var ack = {};
|
||||
ack.source = 'terminate';
|
||||
$(document).trigger('ack.jingle', [self.sid, ack]);
|
||||
},
|
||||
function (stanza) {
|
||||
var error = ($(stanza).find('error').length) ? {
|
||||
code: $(stanza).find('error').attr('code'),
|
||||
reason: $(stanza).find('error :first')[0].tagName,
|
||||
}:{};
|
||||
$(document).trigger('ack.jingle', [self.sid, error]);
|
||||
},
|
||||
10000);
|
||||
if (this.statsinterval !== null) {
|
||||
window.clearInterval(this.statsinterval);
|
||||
this.statsinterval = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
JingleSession.prototype.addSource = function (elem) {
|
||||
console.log('addssrc', new Date().getTime());
|
||||
console.log('ice', this.peerconnection.iceConnectionState);
|
||||
var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
|
||||
|
||||
var self = this;
|
||||
$(elem).each(function (idx, content) {
|
||||
var name = $(content).attr('name');
|
||||
var lines = '';
|
||||
tmp = $(content).find('>source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]');
|
||||
tmp.each(function () {
|
||||
var ssrc = $(this).attr('ssrc');
|
||||
$(this).find('>parameter').each(function () {
|
||||
lines += 'a=ssrc:' + ssrc + ' ' + $(this).attr('name');
|
||||
if ($(this).attr('value') && $(this).attr('value').length)
|
||||
lines += ':' + $(this).attr('value');
|
||||
lines += '\r\n';
|
||||
});
|
||||
});
|
||||
sdp.media.forEach(function(media, idx) {
|
||||
if (!SDPUtil.find_line(media, 'a=mid:' + name))
|
||||
return;
|
||||
sdp.media[idx] += lines;
|
||||
if (!self.addssrc[idx]) self.addssrc[idx] = '';
|
||||
self.addssrc[idx] += lines;
|
||||
});
|
||||
sdp.raw = sdp.session + sdp.media.join('');
|
||||
});
|
||||
this.modifySources();
|
||||
};
|
||||
|
||||
JingleSession.prototype.removeSource = function (elem) {
|
||||
console.log('removessrc', new Date().getTime());
|
||||
console.log('ice', this.peerconnection.iceConnectionState);
|
||||
var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
|
||||
|
||||
var self = this;
|
||||
$(elem).each(function (idx, content) {
|
||||
var name = $(content).attr('name');
|
||||
var lines = '';
|
||||
tmp = $(content).find('>source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]');
|
||||
tmp.each(function () {
|
||||
var ssrc = $(this).attr('ssrc');
|
||||
$(this).find('>parameter').each(function () {
|
||||
lines += 'a=ssrc:' + ssrc + ' ' + $(this).attr('name');
|
||||
if ($(this).attr('value') && $(this).attr('value').length)
|
||||
lines += ':' + $(this).attr('value');
|
||||
lines += '\r\n';
|
||||
});
|
||||
});
|
||||
sdp.media.forEach(function(media, idx) {
|
||||
if (!SDPUtil.find_line(media, 'a=mid:' + name))
|
||||
return;
|
||||
sdp.media[idx] += lines;
|
||||
if (!self.addssrc[idx]) self.removessrc[idx] = '';
|
||||
self.removessrc[idx] += lines;
|
||||
});
|
||||
sdp.raw = sdp.session + sdp.media.join('');
|
||||
});
|
||||
this.modifySources();
|
||||
};
|
||||
|
||||
JingleSession.prototype.modifySources = function() {
|
||||
var self = this;
|
||||
if (!(this.addssrc.length || this.removessrc.length)) return;
|
||||
if (this.peerconnection.signalingState == 'closed') return;
|
||||
if (!(this.peerconnection.signalingState == 'stable' && this.peerconnection.iceConnectionState == 'connected')) {
|
||||
console.warn('modifySources not yet', this.peerconnection.signalingState, this.peerconnection.iceConnectionState);
|
||||
this.wait = true;
|
||||
window.setTimeout(function() { self.modifySources(); }, 250);
|
||||
return;
|
||||
}
|
||||
if (this.wait) {
|
||||
window.setTimeout(function() { self.modifySources(); }, 2500);
|
||||
this.wait = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
|
||||
|
||||
// add sources
|
||||
this.addssrc.forEach(function(lines, idx) {
|
||||
sdp.media[idx] += lines;
|
||||
});
|
||||
this.addssrc = [];
|
||||
|
||||
// remove sources
|
||||
this.removessrc.forEach(function(lines, idx) {
|
||||
lines = lines.split('\r\n');
|
||||
lines.pop(); // remove empty last element;
|
||||
lines.forEach(function(line) {
|
||||
sdp.media[idx] = sdp.media[idx].replace(line + '\r\n', '');
|
||||
});
|
||||
});
|
||||
this.removessrc = [];
|
||||
|
||||
sdp.raw = sdp.session + sdp.media.join('');
|
||||
this.peerconnection.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp.raw}),
|
||||
function() {
|
||||
self.peerconnection.createAnswer(
|
||||
function(modifiedAnswer) {
|
||||
self.peerconnection.setLocalDescription(modifiedAnswer,
|
||||
function() {
|
||||
//console.log('modified setLocalDescription ok');
|
||||
},
|
||||
function(error) {
|
||||
console.log('modified setLocalDescription failed');
|
||||
}
|
||||
);
|
||||
},
|
||||
function(error) {
|
||||
console.log('modified answer failed');
|
||||
}
|
||||
);
|
||||
},
|
||||
function(error) {
|
||||
console.log('modify failed');
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
JingleSession.prototype.sendMute = function (muted, content) {
|
||||
var info = $iq({to: this.peerjid,
|
||||
type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: 'session-info',
|
||||
initiator: this.initiator,
|
||||
sid: this.sid });
|
||||
info.c(muted ? 'mute' : 'unmute', {xmlns: 'urn:xmpp:jingle:apps:rtp:info:1'});
|
||||
info.attrs({'creator': this.me == this.initiator ? 'creator' : 'responder'});
|
||||
if (content) {
|
||||
info.attrs({'name': content});
|
||||
}
|
||||
this.connection.send(info);
|
||||
};
|
||||
|
||||
JingleSession.prototype.sendRinging = function () {
|
||||
var info = $iq({to: this.peerjid,
|
||||
type: 'set'})
|
||||
.c('jingle', {xmlns: 'urn:xmpp:jingle:1',
|
||||
action: 'session-info',
|
||||
initiator: this.initiator,
|
||||
sid: this.sid });
|
||||
info.c('ringing', {xmlns: 'urn:xmpp:jingle:apps:rtp:info:1'});
|
||||
this.connection.send(info);
|
||||
};
|
||||
|
||||
JingleSession.prototype.getStats = function (interval) {
|
||||
var self = this;
|
||||
var recv = {audio: 0, video: 0};
|
||||
var lost = {audio: 0, video: 0};
|
||||
var lastrecv = {audio: 0, video: 0};
|
||||
var lastlost = {audio: 0, video: 0};
|
||||
var loss = {audio: 0, video: 0};
|
||||
var delta = {audio: 0, video: 0};
|
||||
this.statsinterval = window.setInterval(function () {
|
||||
if (self && self.peerconnection && self.peerconnection.getStats) {
|
||||
self.peerconnection.getStats(function (stats) {
|
||||
var results = stats.result();
|
||||
// TODO: there are so much statistics you can get from this..
|
||||
for (var i = 0; i < results.length; ++i) {
|
||||
if (results[i].type == 'ssrc') {
|
||||
var packetsrecv = results[i].stat('packetsReceived');
|
||||
var packetslost = results[i].stat('packetsLost');
|
||||
if (packetsrecv && packetslost) {
|
||||
packetsrecv = parseInt(packetsrecv, 10);
|
||||
packetslost = parseInt(packetslost, 10);
|
||||
|
||||
if (results[i].stat('googFrameRateReceived')) {
|
||||
lastlost.video = lost.video;
|
||||
lastrecv.video = recv.video;
|
||||
recv.video = packetsrecv;
|
||||
lost.video = packetslost;
|
||||
} else {
|
||||
lastlost.audio = lost.audio;
|
||||
lastrecv.audio = recv.audio;
|
||||
recv.audio = packetsrecv;
|
||||
lost.audio = packetslost;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delta.audio = recv.audio - lastrecv.audio;
|
||||
delta.video = recv.video - lastrecv.video;
|
||||
loss.audio = (delta.audio > 0) ? Math.ceil(100 * (lost.audio - lastlost.audio) / delta.audio) : 0;
|
||||
loss.video = (delta.video > 0) ? Math.ceil(100 * (lost.video - lastlost.video) / delta.video) : 0;
|
||||
$(document).trigger('packetloss.jingle', [self.sid, loss]);
|
||||
});
|
||||
}
|
||||
}, interval || 3000);
|
||||
return this.statsinterval;
|
||||
};
|
||||
|
||||
}(jQuery));
|
||||
@@ -3,9 +3,10 @@
|
||||
* Klaus Herberth, 2014
|
||||
*/
|
||||
|
||||
// This code was written by Tyler Akins and has been placed in the
|
||||
// public domain. It would be nice if you left this header intact.
|
||||
// Base64 code from Tyler Akins -- http://rumkin.com
|
||||
/*! This code was written by Tyler Akins and has been placed in the
|
||||
public domain. It would be nice if you left this header intact.
|
||||
Base64 code from Tyler Akins -- http://rumkin.com
|
||||
*/
|
||||
|
||||
var Base64 = (function () {
|
||||
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
@@ -84,7 +85,7 @@ var Base64 = (function () {
|
||||
return obj;
|
||||
})();
|
||||
|
||||
/*
|
||||
/*!
|
||||
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
||||
* in FIPS PUB 180-1
|
||||
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
||||
@@ -261,7 +262,7 @@ function binb2b64(binarray)
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
/*!
|
||||
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
||||
* Digest Algorithm, as defined in RFC 1321.
|
||||
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
|
||||
@@ -469,7 +470,7 @@ var MD5 = (function () {
|
||||
return obj;
|
||||
})();
|
||||
|
||||
/*
|
||||
/*!
|
||||
This program is distributed under the terms of the MIT license.
|
||||
Please see the LICENSE file for details.
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ Strophe.addConnectionPlugin('muc', {
|
||||
}).c("query", {
|
||||
xmlns: Strophe.NS.MUC_OWNER
|
||||
});
|
||||
if (config instanceof Form) {
|
||||
if (Strophe.x && config instanceof Strophe.x.Form) {
|
||||
config.type = "submit";
|
||||
iq.cnode(config.toXML());
|
||||
} else {
|
||||
@@ -1017,4 +1017,4 @@ Occupant = (function() {
|
||||
|
||||
return Occupant;
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||