Comparar commits

..

39 Commits

Autor SHA1 Mensagem Data
sualko 3e7633d2c8 build v3.2.0-nightly.1 2017-03-20 17:43:33 +01:00
sualko 92e38a8abb update change log 2017-03-20 17:40:26 +01:00
sualko 7765b6b46f Merge branch 'master' into feature-mam 2017-03-20 17:30:16 +01:00
sualko d675401bc8 move composing message to window header (fix #468) 2017-03-20 17:26:59 +01:00
sualko 16e519d5ec fix state reset after disconnect 2017-03-20 16:31:03 +01:00
sualko 62ca260ba3 force features reload on log in 2017-03-20 16:20:58 +01:00
sualko f1a83cd696 fix mam feature detection 2017-03-20 16:17:54 +01:00
sualko 3d97567429 add no permanent store processing hint
XEP-0334
2017-03-20 15:09:21 +01:00
sualko 3226a3c940 make mam slave safe 2017-03-20 14:54:18 +01:00
sualko 31eba50c99 update locales 2017-03-20 14:52:59 +01:00
sualko ec0cec8a9e fix message dispatch from slave tab 2017-03-20 12:55:27 +01:00
sualko 15c7948cb8 fix mam button in empty windows 2017-03-20 10:53:42 +01:00
sualko 52588a1437 add mam support for master tab 2017-03-17 15:59:41 +01:00
sualko 1d60187f98 prefer xmpp password from settings over login form
nextcloud/jsxc.nextcloud#6
2017-03-16 13:20:04 +01:00
Klaus 81d84a02b9 Merge pull request #447 from jsxc/fix-muc-presence
[WIP] fix muc presence

fix #447
2017-03-14 12:32:24 +01:00
sualko 2eb4dfdea2 use new avatar namespace in muc 2017-03-14 12:31:27 +01:00
sualko 0aa0d4d467 define room as online after successful join 2017-03-14 12:31:08 +01:00
sualko f544b8d753 fix status indicator regression 2017-03-14 12:30:11 +01:00
sualko 60afa8efeb Merge branch 'master' into fix-muc-presence 2017-03-14 12:11:53 +01:00
Klaus 413bfd8dc3 Merge pull request #484 from jsxc/roster-enhancements
Roster enhancements
2017-03-14 10:56:31 +01:00
sualko 964de1637c catch quota exceeded errors
e.g. Safari in private mode has a quota of 0.
2017-03-14 10:47:08 +01:00
sualko 684bd5b27a support roster versioning (fix #478) 2017-03-09 15:43:02 +01:00
sualko 2cbc5b74a3 split avatar loading into chunks (fix #480) 2017-03-09 14:18:11 +01:00
sualko 66a1ed906c fix unclickable space (#483) 2017-03-08 14:10:11 +01:00
sualko 55838a4724 remove whitespace 2017-03-08 14:06:57 +01:00
sualko c8b6a7b1ba fix receiving message from unknown sender (fix #470) 2017-03-07 16:26:33 +01:00
sualko d45a5e1fda fix change of bosh url in example 2017-03-07 15:29:25 +01:00
Klaus 95689c62b6 Merge pull request #466 from jsxc/fix-bookmarks
Fix remote bookmark storage
2017-03-02 17:38:27 +01:00
Klaus 0f2960b1fb Merge pull request #465 from jsxc/fix-upload-discovery
- fix http upload discovery
- make max file size optional
2017-03-02 17:24:43 +01:00
sualko 7552e5c73a make max file size optional 2017-03-02 17:21:55 +01:00
sualko a6de6d6843 update strophe.jinglejs 2017-03-02 16:45:01 +01:00
sualko eeab8355e5 respond to software version request
implements XEP-0092, fix #464
2017-02-22 13:47:44 +01:00
sualko e95f61af25 fix vcard retrieval for rooms 2017-02-22 13:16:13 +01:00
sualko 4ec0656de6 minor dialog style fix 2017-02-22 13:09:35 +01:00
sualko 687347ec09 update strophe.bookmarks 2017-02-22 10:51:27 +01:00
sualko ace5fc585b Merge branch 'master' into fix-upload-discovery 2017-02-22 10:14:14 +01:00
sualko d38b45c441 beautify Gruntfile 2017-02-22 10:11:37 +01:00
sualko 3d408a51b9 fix http upload discovery 2017-02-22 10:05:52 +01:00
sualko e953303002 decouple room and member presence 2017-02-02 16:54:19 +01:00
196 arquivos alterados com 19608 adições e 12861 exclusões
+2
Ver Arquivo
@@ -25,3 +25,5 @@ lib/i18next/
lib/jquery-i18next/
lib/magnific-popup/
.idea
/lib/strophejs-plugin-mam
/lib/strophejs-plugin-rsm
+1 -1
Ver Arquivo
@@ -6,4 +6,4 @@
url = https://github.com/twbs/bootstrap-sass/
[submodule "lib/strophe.jinglejs"]
path = lib/strophe.jinglejs
url = https://github.com/sualko/strophe.jinglejs
url = https://github.com/jsxc/strophe.jinglejs
+1 -1
Ver Arquivo
@@ -18,7 +18,7 @@ linters:
ImportantRule:
enabled: false
Indentation:
width: 3
width: 4
LeadingZero:
style: include_zero
NameFormat:
-4
Ver Arquivo
@@ -9,7 +9,3 @@ before_install:
script:
- ./node_modules/.bin/grunt pre-commit
branches:
except:
- refactoring
+20
Ver Arquivo
@@ -5,6 +5,26 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
### Added
- [#150](https://github.com/jsxc/jsxc/issues/150) add Message Archive Management (XEP-0313)
- [#464](https://github.com/jsxc/jsxc/issues/464) respond to software version request (XEP-0092)
### Fixed
- [#447](https://github.com/jsxc/jsxc/pull/447) fix muc member presence
- fix http upload discovery
- fix vcard retrieval for rooms
- fix bookmarks
- [#470](https://github.com/jsxc/jsxc/issues/470) fix receiving message from unknown sender
- [#483](https://github.com/jsxc/jsxc/issues/483) fix unclickable space
- catch quota exceeded errors (e.g. Safari in private mode has a quota of 0)
### Changed
- update strophe.jinglejs
- make max file size optional for http upload service
- [#480](https://github.com/jsxc/jsxc/issues/480) split avatar loading into chunks
- [#478](https://github.com/jsxc/jsxc/issues/478) support roster versioning
- prefer xmpp password from settings over login form
- [#468](https://github.com/jsxc/jsxc/issues/468) move composing message to window header
## 3.1.1 - 2017-02-14
### Fixed
+403
Ver Arquivo
@@ -0,0 +1,403 @@
/* global module:false */
module.exports = function(grunt) {
var dep = grunt.file.readJSON('dep.json');
var dep_files = dep.map(function(el) {
return el.file;
});
dep_files.push('<%= target %>/lib/translation.js');
// Project configuration.
grunt.initConfig({
app: grunt.file.readJSON('package.json'),
meta: {
banner: grunt.file.read('banner.js')
},
target: 'dev',
jshint: {
options: {
jshintrc: '.jshintrc'
},
gruntfile: {
src: 'Gruntfile.js'
},
files: ['src/jsxc.lib.*.js']
},
copy: {
main: {
files: [{
expand: true,
src: ['lib/emojione/assets/svg/*.svg',
'lib/otr/build/**', 'lib/otr/lib/*.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: ['<%= target %>/'],
usebanner: {
dist: {
options: {
position: 'top',
banner: '<%= meta.banner %>'
},
files: {
src: ['<%= target %>/*.js']
}
}
},
replace: {
version: {
src: ['<%= target %>/jsxc.js'],
overwrite: true,
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\')'
}]
},
// IE 10 does not like comments starting with @
todo: {
src: ['build/jsxc.js'],
overwrite: true,
replacements: [{
from: /\/\/@(.*)/g,
to: '//$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.match(/crypto\.js$/)) {
src += ';';
}
var data = dep[dep_files.indexOf(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',
filter: function(filepath) {
if (!grunt.file.exists(filepath)) {
grunt.fail.warn('Could not find: ' + filepath);
} else {
return true;
}
},
nonull: true,
},
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.gui.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: {
bower: {
files: {
src: ['bower.json']
},
options: {
searchString: "<%= app.version %>",
logFormat: 'console',
onComplete: function(m) {
if (m.numMatches === 0) {
grunt.fail.fatal('No entry in bower.json for current version found.');
}
}
}
},
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', 'replace:imageUrl']
},
js: {
files: ['src/jsxc.lib.*'],
tasks: ['concat:jsxc']
},
template: {
files: ['template/*.html'],
tasks: ['htmlConvert', 'replace:template', 'concat:jsxc']
}
},
jsbeautifier: {
'default': {
src: ['Gruntfile.js', 'src/jsxc.lib.*', 'template/*.html',
'example/*.html', 'example/js/dev.js', 'example/js/example.js',
'example/css/example.css'
],
options: {
config: '.jsbeautifyrc'
}
},
'pre-commit': {
src: ['Gruntfile.js', 'src/jsxc.lib.*', 'template/*.html',
'example/*.html', 'example/js/dev.js', 'example/js/example.js',
'example/css/example.css'
],
options: {
config: '.jsbeautifyrc',
mode: 'VERIFY_ONLY'
}
}
},
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'
}
},
scsslint: {
files: ['scss/*.scss'],
options: {
config: '.scss-lint.yml'
}
}
});
// These plugins provide necessary tasks.
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-scss-lint');
//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', 'search:bower', 'build', 'usebanner',
'replace:version', 'replace:libraries', 'replace:todo',
'uglify', 'compress'
]);
});
grunt.registerTask('build:release', 'Build a new release', function() {
grunt.config.set('target', 'build');
grunt.task.run(['search:changelog', 'build:prerelease', 'jsdoc']);
});
// before commit
grunt.registerTask('pre-commit', ['search:console', 'jsbeautifier:pre-commit', 'scsslint', 'jshint']);
grunt.registerTask('beautify', ['jsbeautifier', 'prettysass']);
};
+1 -6
Ver Arquivo
@@ -1,4 +1,4 @@
# JavaScript XMPP Client 4.0
# JavaScript XMPP Client
[![Build Status](https://travis-ci.org/jsxc/jsxc.svg?branch=master)](https://travis-ci.org/jsxc/jsxc)
[![Dependency Status](https://dependencyci.com/github/jsxc/jsxc/badge)](https://dependencyci.com/github/jsxc/jsxc)
@@ -8,8 +8,3 @@ Real-time chat app. This app requires an external XMPP server (openfire, ejabber
You find a full list of features, supported protocols and browsers on [our homepage](http://www.jsxc.org).
If you are looking for install instructions or developer notes, please also checkout our [wiki](https://github.com/jsxc/jsxc/wiki/).
## Rewrite / Refactoring
:warning: This branch is under heavy construction and definitely not ready for production.
This next big step for JSXC uses [Typescript](http://www.typescriptlang.org/index.html), [Webpack](https://webpack.github.io), [Handlebars](http://handlebarsjs.com), [Karma](http://karma-runner.github.io), [Mocha](https://mochajs.org), [Chai](http://chaijs.com) and [Sinon](http://sinonjs.org) to bring the best open XMPP chat experience to you. Currently we ship no packed version, so install all dependencies with `npm install` and execute `npm run dev` to test the current state. An example application is available at `example/ts.html`. To run all tests, enter `npm test`.
+41
Ver Arquivo
@@ -0,0 +1,41 @@
{
"name": "jsxc",
"version": "3.2.0-nightly.1",
"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,
"devDependencies": {
"emojione": "~2.2.7",
"favico.js": "^0.3.10",
"strophe.bookmarks": "strophe/strophejs-plugin-bookmarks#ff9e95a1a823b927f8c4c45453aaa534857a37b4",
"strophe.js": "strophejs#a11ebefa3db1b6712d51d0d309b9f68f8e391d1b",
"strophe.vcard": "strophe/strophejs-plugin-vcard#de3a0c97a2c520ed900ee15b04a0c16d5c663891",
"strophe.x": "strophe/strophejs-plugin-dataforms",
"strophe.chatstates": "strophe/strophejs-plugin-chatstates",
"jquery-i18next": "^1.2.0",
"i18next": "^5.0.0",
"magnific-popup": "^1.1.0",
"strophejs-plugin-mam": "strophe/strophejs-plugin-mam#27e8d25",
"strophejs-plugin-rsm": "strophe/strophejs-plugin-rsm#fa16b3b"
}
}
+62 -25
Ver Arquivo
@@ -2168,7 +2168,8 @@ fieldset[disabled]
width: 100%; }
#jsxc_dialog .mfp-close, #jsxc_webrtc .mfp-close {
font-size: 23px; }
font-size: 23px;
font-weight: normal; }
.mfp-bg {
z-index: 9000; }
@@ -2763,15 +2764,14 @@ fieldset[disabled]
position: fixed;
left: 0;
bottom: 0;
width: 30px;
height: 30px; }
width: 30px; }
@media (max-width: 768px) {
#jsxc_windowListSB {
display: none; } }
#jsxc_windowListSB > div {
box-sizing: border-box;
width: 14px;
height: 100%;
height: 30px;
background-color: #cccccc;
color: #807f7f;
text-align: center;
@@ -2881,7 +2881,8 @@ fieldset[disabled]
.jsxc_window .jsxc_emoticons:hover:after {
opacity: 0.5; }
.jsxc_window .jsxc_fade {
position: relative; }
position: relative;
overflow: hidden; }
.jsxc_window .jsxc_fade .jsxc_overlay {
display: none;
background-color: rgba(0, 0, 0, 0.5);
@@ -2931,6 +2932,31 @@ fieldset[disabled]
text-overflow: ellipsis; }
.jsxc_window .jsxc_fade .jsxc_overlay > div a:hover {
text-decoration: underline; }
.jsxc_window .jsxc_fade .jsxc_mam-load-more {
display: none;
text-align: center;
font-size: 0.8em;
font-style: italic;
position: absolute;
top: -42px;
left: 0;
right: 0;
height: 42px;
cursor: pointer;
z-index: 80;
line-height: 42px;
opacity: 0;
-webkit-transition: opacity 0.5s, top 0.5s;
transition: opacity 0.5s, top 0.5s; }
.jsxc_window .jsxc_fade .jsxc_mam-load-more.jsxc_show {
top: 0;
opacity: 0.7; }
.jsxc_window .jsxc_fade .jsxc_mam-load-more.jsxc_show:hover {
opacity: 1; }
.jsxc_window .jsxc_fade.jsxc_mam-enable .jsxc_textarea {
padding-top: 42px; }
.jsxc_window .jsxc_fade.jsxc_mam-enable .jsxc_mam-load-more {
display: block; }
.jsxc_window .jsxc_avatar {
margin-top: 1px; }
.jsxc_window .jsxc_textarea {
@@ -3176,26 +3202,6 @@ fieldset[disabled]
width: 1.2em;
height: 1.2em;
vertical-align: middle; }
.jsxc_sys.jsxc_composing {
text-align: center;
font-size: 0.9em;
font-style: italic;
display: block;
opacity: 0;
overflow: hidden;
-webkit-transition: opacity 0.6s;
transition: opacity 0.6s; }
.jsxc_sys.jsxc_composing:before {
content: " ";
width: 1.5em;
height: 1em;
display: inline-block;
background-size: 80%;
background-repeat: no-repeat;
margin: 0 3px 0 0;
background-image: url('../img/composing.png'); }
.jsxc_sys.jsxc_composing.jsxc_fadein {
opacity: 1; }
div.jsxc_settings {
position: relative; }
@@ -3232,6 +3238,35 @@ div.jsxc_transfer {
div.jsxc_transfer.jsxc_enc.jsxc_trust {
background-image: url('../img/padlock_close_green.svg'); }
.jsxc_status-msg {
font-size: 12px;
display: none;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
height: 50%;
line-height: 17.5px;
opacity: 0.7; }
.jsxc_status-msg.jsxc_composing:before {
content: " ";
width: 1em;
height: 1em;
display: inline-block;
background-size: cover;
vertical-align: middle;
background-repeat: no-repeat;
background-image: url('../img/composing.png'); }
.jsxc_status-msg-show .jsxc_name {
height: 50%;
line-height: 20px; }
.jsxc_status-msg-show .jsxc_status-msg {
display: block; }
.jsxc_status-msg-show .jsxc_lastmsg {
display: none !important; }
.jsxc_windowItem.jsxc_groupchat.jsxc_normal .jsxc_bar .jsxc_avatar, li[data-type='groupchat'] .jsxc_avatar {
text-indent: 999px;
background-image: url('../img/group_white.svg');
@@ -3309,6 +3344,8 @@ div.jsxc_transfer {
color: inherit; }
.jsxc_windowItem .jsxc_memberlist.jsxc_expand ul > li .jsxc_avatar {
margin-right: 4px; }
.jsxc_windowItem .jsxc_memberlist .jsxc_avatar :before {
display: none; }
li[data-type='groupchat'] .jsxc_video {
display: none; }
+857 -448
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+9 -9
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+3271 -2467
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+30 -29
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
-7
Ver Arquivo
@@ -1,7 +0,0 @@
declare module '*.hbs' {
// const content: any;
// export default content;
export default function template(options:any);
}
declare function require(file:string):(context?:any, options?:any)=>string;
+128
Ver Arquivo
@@ -0,0 +1,128 @@
[
{
"name": "strophe.js",
"file": "lib/strophe.js/strophe.js",
"license": "multiple",
"url": "http://strophe.im/strophejs/"
},
{
"name": "strophe.js/muc",
"file": "lib/strophe.muc.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugins"
},
{
"name": "strophe.js/disco",
"file": "lib/strophe.disco.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugins"
},
{
"name": "strophe.js/caps",
"file": "lib/strophe.caps.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugins"
},
{
"name": "strophe.js/vcard",
"file": "lib/strophe.vcard/strophe.vcard.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugins"
},
{
"name": "strophe.js/bookmarks",
"file": "lib/strophe.bookmarks/strophe.bookmarks.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugins/tree/master/bookmarks"
},
{
"name": "strophe.js/x",
"file": "lib/strophe.x/src/strophe.x.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugins/tree/master/dataforms"
},
{
"name": "strophe.js/chatstates",
"file": "lib/strophe.chatstates/strophe.chatstates.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugins/tree/master/chatstates"
},
{
"name": "strophe.js/mam",
"file": "lib/strophejs-plugin-mam/strophe.mam.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugin-mam"
},
{
"name": "strophe.js/rsm",
"file": "lib/strophejs-plugin-rsm/strophe.rsm.js",
"license": "MIT",
"url": "https://github.com/strophe/strophejs-plugin-rsm"
},
{
"name": "strophe.jinglejs",
"file": "lib/strophe.jinglejs/strophe.jinglejs-bundle.js",
"license": "MIT",
"url": "https://github.com/sualko/strophe.jinglejs"
},
{
"name": "Salsa20",
"file": "lib/otr/build/dep/salsa20.js",
"license": "AGPL3",
"url": "https://github.com/neoatlantis/node-salsa20"
},
{
"name": "bigint",
"file": "lib/otr/build/dep/bigint.js",
"license": "public domain",
"url": "www.leemon.com"
},
{
"name": "cryptojs",
"file": "lib/otr/build/dep/crypto.js",
"license": "code.google.com/p/crypto-js/wiki/license",
"url": "code.google.com/p/crypto-js"
},
{
"name": "eventemitter",
"file": "lib/otr/build/dep/eventemitter.js",
"license": "MIT",
"url": "http://git.io/ee"
},
{
"name": "otr.js",
"file": "lib/otr/build/otr.js",
"license": "MPL v2.0",
"url": "https://arlolra.github.io/otr/"
},
{
"name": "i18next",
"file": "lib/i18next/i18next.min.js",
"license": "MIT",
"url": "http://i18next.com/"
},
{
"name": "jquery-i18next",
"file": "lib/jquery-i18next/jquery-i18next.min.js",
"license": "MIT",
"url": "http://i18next.com/"
},
{
"name": "Magnific Popup",
"file": "lib/magnific-popup/dist/jquery.magnific-popup.min.js",
"license": "MIT",
"url": "http://dimsemenov.com/plugins/magnific-popup/"
},
{
"name": "favico.js",
"file": "lib/favico.js/favico.js",
"license": "MIT",
"url": "https://github.com/ejci/favico.js"
},
{
"name": "emoji one",
"file": "lib/emojione/lib/js/emojione.js",
"license": "CC-BY 4.0",
"url": "http://emojione.com"
}
]
+1
Ver Arquivo
@@ -117,6 +117,7 @@ $(function() {
localStorage.setItem('bosh-url', url);
localStorage.setItem('xmpp-domain', domain);
jsxc.options.xmpp.url = url;
settings.xmpp.url = url;
settings.xmpp.domain = domain;
-92
Ver Arquivo
@@ -1,92 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>JSXC example application</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<link href="css/bootstrap.min.css" media="all" rel="stylesheet" type="text/css" />
<!-- require:dependencies -->
<link href="../build/css/jquery-ui.min.css" media="all" rel="stylesheet" type="text/css" />
<link href="../css/bundle.css" media="all" rel="stylesheet" type="text/css" />
<!-- endrequire -->
<link href="../node_modules/simplebar/dist/simplebar.css" media="all" rel="stylesheet" type="text/css" />
<link href="css/example.css" media="all" rel="stylesheet" type="text/css" />
<style>
#jsxc-role {
width: 50px;
height: 50px;
background-color: #a1a1a1;
border-radius: 50%;
position: absolute;
top: 15px;
left: 15px;
}
.jsxc-master #jsxc-role {
background-color: green;
}
.jsxc-slave #jsxc-role {
background-color: orange;
}
</style>
</head>
<body>
<div id="jsxc-role"></div>
<form id="loginForm" style="margin-top: 100px; padding:15px;" class="form-inline">
<div class="form-group">
<input class="form-control" type="text" name="url" placeholder="Bosh url" value="/http-bind/" />
</div>
<div class="form-group">
<input class="form-control" type="text" name="jid" placeholder="Jabber Id" value="" />
</div>
<div class="form-group">
<input class="form-control" type="text" name="password" placeholder="Password" value="" />
</div>
<button class="btn btn-primary">Login</button>
</form>
<p style="padding:15px"><a class="btn btn-danger" href="javascript:jsxc.deleteAllData()">Delete all Data</a>
<a class="btn btn-default" href="javascript:jsxc.enableDebugMode()">Enable Debug Mode</a>
<a class="btn btn-default" href="javascript:jsxc.disableDebugMode()">Disable Debug Mode</a></p>
<!-- require:dependencies -->
<script src="js/jquery.min.js"></script>
<script src="js/jquery-ui.min.js"></script>
<script src="../build/lib/jquery.slimscroll.js"></script>
<script src="../build/lib/jquery.fullscreen.js"></script>
<!-- <script src="../build/lib/jsxc.dep.js"></script> -->
<!-- endrequire -->
<script src="../node_modules/simplebar/dist/simplebar.js"></script>
<script src="js/bootstrap.min.js"></script>
<!-- jsxc library -->
<script src="../bundle.js"></script>
<script>
$('#loginForm').submit(function(ev){
ev.preventDefault();
var url = $(this).find('[name="url"]').val();
var jid = $(this).find('[name="jid"]').val();
var password = $(this).find('[name="password"]').val();
jsxc.start(url, jid, password);
});
</script>
</body>
</html>
-51
Ver Arquivo
@@ -1,51 +0,0 @@
<?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"
id="svg8"
version="1.1"
viewBox="0 0 3.1749999 3.1750001"
height="12"
width="12"
inkscape:version="0.91 r13725"
sodipodi:docname="presence_online.svg">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1879"
inkscape:window-height="1176"
id="namedview5307"
showgrid="false"
inkscape:zoom="55.625733"
inkscape:cx="3.7142348"
inkscape:cy="6.3732363"
inkscape:window-x="1241"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<defs
id="defs2" />
<metadata
id="metadata5">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
</svg>

Antes

Largura:  |  Altura:  |  Tamanho: 1.4 KiB

-100
Ver Arquivo
@@ -1,100 +0,0 @@
// jshint node:true
// var path = require('path');
var webpackConfig = require('./webpack.config.js');
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: [ /*'karma-typescript',*/ 'mocha', 'chai'],
// list of files / patterns to load in the browser
files: [
'./node_modules/jquery/dist/jquery.min.js',
'./node_modules/strophe.js/strophe.js',
'./node_modules/es6-promise/dist/es6-promise.js',
'test/*.spec.ts',
'test/**/*.spec.ts'
],
// list of files to exclude
exclude: [],
// webpack configuration
webpack: {
devtool: 'eval-source-map',
module: webpackConfig.module,
resolve: webpackConfig.resolve,
//externals: webpackConfig.externals,
// target: 'node',
node: {
fs: 'empty'
}
},
webpackMiddleware: {
quiet: false,
stats: {
colors: true
}
},
mime: {
'text/x-typescript': ['ts', 'tsx']
},
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
'test/**/*.spec.ts': ['webpack' /*'karma-typescript'*/ ]
},
karmaTypescriptConfig: {
include: ['test/**/*.spec.ts']
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: [ /*'progress', 'karma-typescript',*/ 'mocha'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_DEBUG,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity
});
};
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+7 -6
Ver Arquivo
@@ -265,10 +265,10 @@
"Use_local_audio_device": "Nutze eigenes Audio Gerät",
"Use_local_video_device": "Benutze eigene Webcam",
"is_": "ist __status__",
"You_received_a_message_from_an_unknown_sender_": "Du hast eine Nachricht von einem unbekannten Sender erhalten (__sender__) Möchtest du sie sehen?",
"You_received_a_message_from_an_unknown_sender_": "Du hast eine Nachricht von einem unbekannten Absender erhalten (__sender__). Möchtest du sie sehen?",
"Your_roster_is_empty_add_": "Deine Kontaktliste ist leer, füge einen neuen Kontakt <a>hinzu</a>",
"onsmp_explanation_question": "Dein Kontakt versucht herauszufinden ob er wirklich mit dir redet. Um dich gegenüber deinem Kontakt zu verifizieren gib die Antwort ein und klick auf Antworten.",
"onsmp_explanation_secret": "Dein Kontakt versucht herauszufinden ob er wirklich mit dir redet. Um dich gegenüber deinem Kontakt zu verifizieren gib das Geheimnis ein.",
"onsmp_explanation_secret": "Dein Kontakt versucht herauszufinden ob er wirklich mit dir redet. Um dich gegenüber deinem Kontakt zu verifizieren gib das Geheimnis ein.",
"from_sender": "von __sender__",
"Verified_private_conversation_started": "Verifizierte private Konversation gestartet.",
"Unverified_private_conversation_started": "Unverifizierte private Konversation gestartet.",
@@ -283,9 +283,9 @@
"Change": "Ändern",
"Send_file": "Datei senden",
"setting-explanation-carbon": "Wenn Kopien aktiviert sind, werden alle eingehenden Nachrichten zu allen angemeldeten Clients gesendet.",
"setting-explanation-login": "Wenn diese Option aktiviert ist, wird der Chat beim anmelden automatisch gestartet.",
"setting-explanation-login": "Wenn diese Option aktiviert ist, wird der Chat beim Anmelden automatisch gestartet.",
"setting-explanation-priority": "Wenn du mit deinem XMPP Konto mehrfach angemeldet bist, werden Nachrichten zu dem Client mit der höchsten Priorität zugestellt.",
"setting-explanation-xmpp": "Diese Optionen werden für die Verbindung zum XMPP server genutzt.",
"setting-explanation-xmpp": "Diese Optionen werden für die Verbindung zum XMPP Server genutzt.",
"_is_composing": " tippt gerade...",
"_are_composing": " tippen gerade...",
"Chat_state_notifications": "Statusbenachrichtigungen",
@@ -300,7 +300,8 @@
"Connection_accepted": "Verbindung angenommen",
"Stream_terminated": "Stream beendet",
"Close_all": "Schließe alle",
"Notification": null,
"Unreadable_OTR_message": null
"Notification": "Benachrichtigung",
"Unreadable_OTR_message": "Unlesbare OTR Nachricht verworfen",
"Load_older_messages": "Lade ältere Nachrichten"
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+8 -7
Ver Arquivo
@@ -265,13 +265,13 @@
"Use_local_audio_device": "Use local audio device.",
"Use_local_video_device": "Use local video device.",
"is_": "is __status__",
"You_received_a_message_from_an_unknown_sender_": "You received a message from an unknown sender (__sender__) Do you want to display them?",
"You_received_a_message_from_an_unknown_sender_": "You received a message from an unknown sender (__sender__). Do you want to display them?",
"Your_roster_is_empty_add_": "Your roster is empty, add a <a>new contact</a>",
"onsmp_explanation_question": "You contact is attempting to determine if they are really talking to you. To authenticate to your contact, enter the answer and click Answer.",
"onsmp_explanation_secret": "You contact is attempting to determine if they are really talking to you. To authenticate to your contact, enter the secret.",
"onsmp_explanation_question": "Your contact is attempting to determine if they are really talking to you. To authenticate to your contact, enter the answer and click Answer.",
"onsmp_explanation_secret": "Your contact is attempting to determine if they are really talking to you. To authenticate to your contact, enter the secret.",
"from_sender": "from __sender__",
"Verified_private_conversation_started": "Verified Private conversation started.",
"Unverified_private_conversation_started": "Unverified Private conversation started.",
"Verified_private_conversation_started": "Verified private conversation started.",
"Unverified_private_conversation_started": "Unverified private conversation started.",
"Bookmark": "Bookmark",
"Auto-join": "Auto-join",
"Edit_bookmark": "Edit bookmark",
@@ -301,6 +301,7 @@
"Stream_terminated": "Stream terminated",
"Close_all": "Close all",
"Notification": "Notification",
"Unreadable_OTR_message": "Unreadable OTR message omitted"
"Unreadable_OTR_message": "Unreadable OTR message omitted",
"Load_older_messages": "Load older messages"
}
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+4 -3
Ver Arquivo
@@ -267,7 +267,7 @@
"is_": "est __status__",
"You_received_a_message_from_an_unknown_sender_": "Vous avez reçu un message d'un expéditeur inconnu (__sender__) Voulez-vous les afficher ?",
"Your_roster_is_empty_add_": "Votre liste est vide, ajouter <a>Nouveau contact</a>",
"onsmp_explanation_question": "Votre contact tente de déterminer si il ou elle parle vraiment à vous. Pour vous authentifier auprès de votre contact, saisissez une réponse et cliquez sur Répondre.",
"onsmp_explanation_question": "Votre contact tente de déterminer si il ou elle vous parle vraiment. Pour vous authentifier auprès de votre contact, saisissez une réponse et cliquez sur Répondre.",
"onsmp_explanation_secret": "Votre contact tente de déterminer si il ou elle parle vraiment à vous. Pour vous authentifier auprès de votre contact, entrez le mot secret",
"from_sender": "de __sender__",
"Verified_private_conversation_started": "La conversation privée vérifiée a démarré.",
@@ -300,7 +300,8 @@
"Connection_accepted": "Connexion acceptée",
"Stream_terminated": "Flux terminé",
"Close_all": "Tout fermer",
"Notification": null,
"Unreadable_OTR_message": null
"Notification": "Notification",
"Unreadable_OTR_message": "Message OTR illisible omis",
"Load_older_messages": "Charger des messages plus anciens"
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+307
Ver Arquivo
@@ -0,0 +1,307 @@
{
"translation": {
"Logging_in": "Inloggen…",
"your_connection_is_unencrypted": "Je verbinding is niet versleuteld.",
"your_connection_is_encrypted": "Je verbinding is versleuteld.",
"your_buddy_closed_the_private_connection": "Je contactpersoon sloot de prive-verbinding.",
"start_private": "start privé",
"close_private": "Sluit privé",
"your_buddy_is_verificated": "Je contactpersoon is geverifieerd.",
"you_have_only_a_subscription_in_one_way": "Je hebt een eenrichtingsabonnement.",
"authentication_query_sent": "Verificatie vraag gestuurd.",
"your_message_wasnt_send_please_end_your_private_conversation": "Je bericht is niet verzonden. Beëindig prive gesprek.",
"unencrypted_message_received": "Ongecodeerde bericht ontvangen",
"not_available": "Niet beschikbaar",
"no_connection": "Geen Niet verbinding!",
"relogin": "opnieuw inloggen",
"trying_to_start_private_conversation": "Proberen om privé-gesprek te beginnen!",
"Verified": "Geverifieerd",
"Unverified": "Ongeverifieerd",
"private_conversation_aborted": "Privé-gesprek afgebroken!",
"your_buddy_closed_the_private_conversation_you_should_do_the_same": "Je contact sloot het Privé-gesprek! Doe hetzelfde.",
"conversation_is_now_verified": "Gesprek is geverifieerd.",
"authentication_failed": "Verificatie mislukt.",
"Creating_your_private_key_": "Een persoonlijke sleutel maken. Dit kan een tijdje duren.",
"Authenticating_a_buddy_helps_": "Authenticatie met een contact helpt ervoor te zorgen dat de persoon met wie u praat echt de persoon is die ze beweert te zijn.",
"How_do_you_want_to_authenticate_your_buddy": "Hoe wilt u verificeren __bid_name__ (<b>__bid_jid__</b>)?",
"Select_method": "Selectie methode...",
"Manual": "Handleiding",
"Question": "Vraag",
"Secret": "Geheim",
"To_verify_the_fingerprint_": "Neem via een ander betrouwbaar kanaal, contact op met uw gesprekspartner om de vingerafdruk te controleren. Bijvoorbeeld per telefoon.",
"Your_fingerprint": "Jou vingerafdruk",
"Buddy_fingerprint": "Contact vingerafdruk",
"Close": "Sluiten",
"Compared": "Vergeleken",
"To_authenticate_using_a_question_": "Gebruik een vraag om te verificeren, neem een antwoord alleen bekend bij u en uw contact.",
"Ask": "Vraag",
"To_authenticate_pick_a_secret_": "Voor verificatie, kies een geheim alleen bekend is bij u en uw contact.",
"Compare": "Vergelijk",
"Fingerprints": "Vingerafdrukken",
"Authentication": "Verificatie",
"Message": "Bericht",
"Add_buddy": "Contact toevoegen",
"rename_buddy": "contact hernoemen",
"delete_buddy": "contact verwijderen",
"Login": "Login",
"Username": "Gebruikersnaam",
"Password": "Paswoord",
"Cancel": "Annuleer",
"Connect": "Verbind",
"Type_in_the_full_username_": "Vul de volledige gebruikersnaam en een optionele alias in.",
"Alias": "Alias",
"Add": "Voeg toe",
"Subscription_request": "Abonnementsverzoek",
"You_have_a_request_from": "Je hebt een uitnodiging van",
"Deny": "Ontken",
"Approve": "Toestaan",
"Remove_buddy": "contact verwijderen",
"You_are_about_to_remove_": null,
"Continue_without_chat": "Doorgaan zonder chat",
"Please_wait": "Even geduld",
"Login_failed": "Chat login mislukt",
"Sorry_we_cant_authentikate_": "Verificatie is mislukt met de chatserver. Is het paswoord fout?",
"Retry": "Terug",
"clear_history": "Wis geschiedenis",
"New_message_from": "Nieuw bericht van__name__",
"Should_we_notify_you_": "Zullen wij u notificeren over nieuwe berichten in de toekomst?",
"Please_accept_": null,
"Hide_offline": "Offline contacten verbergen",
"Show_offline": "Offline contacten weergeven",
"About": "Over",
"dnd": "Niet storen",
"Mute": "Dempen aan",
"Unmute": "Dempen uit",
"Subscription": "Abonnement",
"both": "Beide",
"Status": "Status",
"online": "online",
"chat": "chat",
"away": "Afwezig",
"xa": "langer afwezig",
"offline": "offline",
"none": "geen",
"Unknown_instance_tag": "Voorbeeld tag onbekend.",
"Not_one_of_our_latest_keys": "Niet één van onze laatste sleutels.",
"Received_an_unreadable_encrypted_message": "Een niet leesbare versleuteld bericht ontvangen.",
"Online": "Online",
"Chatty": "Spraakzaam",
"Away": "Afwezig",
"Extended_away": "Langer afwezig",
"Offline": "Offline",
"Friendship_request": "Contact verzoek",
"Confirm": "Bevestig",
"Dismiss": "Afwijzen",
"Remove": "Verwijder",
"Online_help": "Online hulp",
"FN": "Volledige naam",
"N": null,
"FAMILY": "Familienaam",
"GIVEN": "Voornaam",
"NICKNAME": "Bijnaam",
"URL": "URL",
"ADR": "Adres",
"STREET": "Adres",
"EXTADD": "Uitgebreid adres",
"LOCALITY": null,
"REGION": "Regio",
"PCODE": "Postcode",
"CTRY": "Land",
"TEL": "Telefoon",
"NUMBER": "Nummer",
"EMAIL": "E-mail",
"USERID": null,
"ORG": "Organisatie",
"ORGNAME": "Naam",
"ORGUNIT": "Afdeling",
"TITLE": "functietitel",
"ROLE": "Functie",
"BDAY": "Verjaardag",
"DESC": "Beschrijving",
"PHOTO": null,
"send_message": "Zend bericht",
"get_info": "Gegevens weergeven",
"Settings": "Instellingen",
"Priority": "Prioriteit",
"Save": "Opslaan",
"User_settings": "Gebruikersinstellingen",
"A_fingerprint_": "Een vingerafdruk wordt gebruikt om er zeker van te zijn dat uw gesprekspartner ook is wie hij of zij zegt te zijn.",
"is": "is",
"Login_options": "Login options",
"BOSH_url": "BOSH URL",
"Domain": "Domein",
"Resource": "Bron",
"On_login": "Tijdens login",
"Received_an_unencrypted_message": "Een niet-versleuteld bericht ontvangen",
"Sorry_your_buddy_doesnt_provide_any_information": "Sorry, je contact verschaft geen informatie.",
"Info_about": "Gegevens van",
"Authentication_aborted": "Verificatie afgebroken.",
"Authentication_request_received": "Authenticatie verzoek ontvangen.",
"Log_in_without_chat": "Zonder chat inloggen",
"has_come_online": "is online gekomen",
"Unknown_sender": "Afzender onbekend",
"Please_allow_access_to_microphone_and_camera": null,
"Incoming_call": null,
"from": "van",
"Do_you_want_to_accept_the_call_from": null,
"Reject": "Weiger",
"Accept": "Aanvaard",
"hang_up": "ophangen",
"snapshot": null,
"mute_my_audio": null,
"pause_my_video": null,
"fullscreen": "volledige scherm",
"Info": "Info",
"Local_IP": "Lokaal IP",
"Remote_IP": "Extern IP",
"Local_Fingerprint": "Lokale vingerafdruk",
"Remote_Fingerprint": "Afstand vingerafdruk",
"Video_call_not_possible": null,
"Start_video_call": null,
"Join_chat": "Neem deel aan chat",
"Join": "Meedoen",
"Room": "Kamer",
"Nickname": "Bijnaam",
"left_the_building": null,
"entered_the_room": "__nickname__kwam de kamer binnen",
"is_now_known_as": null,
"This_room_is": "Deze kamer is",
"muc_hidden": {
"keyword": null,
"description": null
},
"muc_membersonly": {
"keyword": null,
"description": null
},
"muc_moderated": {
"keyword": null,
"description": null
},
"muc_nonanonymous": {
"keyword": null,
"description": null
},
"muc_open": {
"keyword": null,
"description": null
},
"muc_passwordprotected": {
"keyword": null,
"description": null
},
"muc_persistent": {
"keyword": null,
"description": null
},
"muc_public": {
"keyword": null,
"description": null
},
"muc_semianonymous": {
"keyword": null,
"description": "Je Jabber id is alleen vrijgegeven voor kamer beheerders"
},
"muc_temporary": {
"keyword": null,
"description": null
},
"muc_unmoderated": {
"keyword": null,
"description": null
},
"muc_unsecured": {
"keyword": null,
"description": null
},
"Continue": null,
"Server": null,
"Rooms_are_loaded": "Kamers zijn geladen",
"Could_load_only": "Alleen aanvullen voor__count__kamers",
"muc_explanation": "Vul de kamernaam, optioneel een bijnaam en wachtwoord in om deel te nemen een chat",
"You_already_joined_this_room": "Je bent al verbonden met deze kamer",
"This_room_will_be_closed": "De kamer wordt gesloten",
"Room_not_found_": "Een nieuwe kamer wordt aangemaakt",
"Loading_room_information": "Kamer informatie laden",
"Destroy": null,
"Leave": null,
"changed_subject_to": "__nickname__veranderde het onderwerp van de kamer naar \"__subject__\"",
"muc_removed_kicked": "Je bent afgemeld van de kamer",
"muc_removed_info_kicked": "__nickname__is uit de kamer gegooid",
"muc_removed_banned": "Je bent uit de kamer gezet",
"muc_removed_info_banned": "__nickname__is uit de kamer gezet",
"muc_removed_affiliation": "Je bent verwijderd van de kamer door een verwantschap wijziging",
"muc_removed_info_affiliation": "__nickname__is verwijderd van de kamer door een verwantschap wijziging",
"muc_removed_membersonly": null,
"muc_removed_info_membersonly": "__nickname__is verwijderd van de kamer, door de wijziging naar alleen voor leden. Je hebt geen lidmaatschap.",
"muc_removed_shutdown": null,
"Reason": null,
"message_not_send": null,
"message_not_send_item-not-found": null,
"message_not_send_forbidden": null,
"message_not_send_not-acceptable": null,
"This_room_has_been_closed": "Deze kamer is gesloten",
"Room_logging_is_enabled": "Kamerlog is ingeschakeld",
"A_password_is_required": null,
"You_are_not_on_the_member_list": null,
"You_are_banned_from_this_room": "Je bent uit deze kamer gezet",
"Your_desired_nickname_": null,
"The_maximum_number_": null,
"This_room_is_locked_": "Deze kamer is afgesloten",
"You_are_not_allowed_to_create_": null,
"Alert": null,
"Call_started": null,
"Call_terminated": null,
"Carbon_copy": null,
"Enable": null,
"jingle_reason_busy": null,
"jingle_reason_decline": null,
"jingle_reason_success": null,
"Media_failure": null,
"No_local_audio_device": null,
"No_local_video_device": null,
"Ok": null,
"PermissionDeniedError": null,
"Use_local_audio_device": null,
"Use_local_video_device": null,
"is_": null,
"You_received_a_message_from_an_unknown_sender_": "U ontvangt een bericht van een onbekende afzender (__sender__). Wilt u om het weergeven?",
"Your_roster_is_empty_add_": null,
"onsmp_explanation_question": "Je contact probeert te bepalen of ze echt met jou praten. Voer om te verifiëren naar uw contact het antwoord in.",
"onsmp_explanation_secret": "U contact probeert te bepalen of ze echt met jou praten. Voer om te verifiëren naar uw contact het geheim in.",
"from_sender": "van__sender__",
"Verified_private_conversation_started": "Privé-gesprek geverifieerd gestart.",
"Unverified_private_conversation_started": "Privé-gesprek ongeverifieerd gestart.",
"Bookmark": null,
"Auto-join": null,
"Edit_bookmark": null,
"Room_logging_is_disabled": "Kamerlog is uitgeschakeld",
"Room_is_now_non-anoymous": null,
"Room_is_now_semi-anonymous": null,
"Do_you_want_to_change_the_default_room_configuration": null,
"Default": null,
"Change": null,
"Send_file": null,
"setting-explanation-carbon": "Met ingeschakeld carbon kopie zal de XMPP server een kopie van elk inkomend bericht doorsturen naar deze cliënt, zelfs als het niet aan haar is gericht.",
"setting-explanation-login": "Wanneer ingeschakeld zal de chat starten bij het inloggen.",
"setting-explanation-priority": "Je XMPP dienst zal een prioriteitsbericht verzenden wanneer je meerdere keren ingelogd bent met hetzelfde account.",
"setting-explanation-xmpp": null,
"_is_composing": null,
"_are_composing": null,
"Chat_state_notifications": null,
"setting-explanation-chat-state": null,
"Share_screen": "Scherm delen",
"Incoming_stream": null,
"Stream_started": null,
"HTTPS_REQUIRED": null,
"EXTENSION_UNAVAILABLE": null,
"UNKNOWN_ERROR": null,
"Install_extension": "Installeer extensie om scherm delen te gebruiken: ",
"Connection_accepted": null,
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+5 -4
Ver Arquivo
@@ -23,7 +23,7 @@
"authentication_failed": "Kimlik doğrulama başarısız.",
"Creating_your_private_key_": "Özel anahtarınız oluşturuluyor; bu işlem biraz sürebilir.",
"Authenticating_a_buddy_helps_": "Kimlik doğrulaması, konuşmakta olduğunuz kişinin gerçekten o kişi olduğundan emin olmanıza yardımcı olur.",
"How_do_you_want_to_authenticate_your_buddy": "Kimlik doğrulasını nasıl yapmak istersiniz __bid_name__ (<b>__bid_jid__</b>)?",
"How_do_you_want_to_authenticate_your_buddy": "Kimlik doğrulamasını nasıl yapmak istersiniz __bid_name__ (<b>__bid_jid__</b>)?",
"Select_method": "Yöntemi seçin...",
"Manual": "Elle",
"Question": "Soru",
@@ -261,7 +261,7 @@
"No_local_audio_device": "Yerel ses cihazı bulunamadı.",
"No_local_video_device": "Yerel video cihazı bulunamadı.",
"Ok": "Tamam",
"PermissionDeniedError": "Siz veya tarayıcınız sesli/görüntülü izni reddetti",
"PermissionDeniedError": "Siz veya tarayıcınız medya iznini reddetti",
"Use_local_audio_device": "Yerel video cihazını kullan.",
"Use_local_video_device": "Yerel video cihazını kullanın.",
"is_": "__status__",
@@ -300,7 +300,8 @@
"Connection_accepted": "Bağlantı kabul edildi",
"Stream_terminated": "Akış sonlandırıldı",
"Close_all": "Hepsini kapat",
"Notification": null,
"Unreadable_OTR_message": null
"Notification": "Bildirim",
"Unreadable_OTR_message": "Okunamayan OTR iletisi atlandı",
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+3 -2
Ver Arquivo
@@ -300,7 +300,8 @@
"Connection_accepted": "連線接受了",
"Stream_terminated": "串流結束了",
"Close_all": "全部關掉",
"Notification": null,
"Unreadable_OTR_message": null
"Notification": "通知",
"Unreadable_OTR_message": "忽略無法解讀的 OTR 訊息",
"Load_older_messages": null
}
}
+2 -1
Ver Arquivo
@@ -301,6 +301,7 @@
"Stream_terminated": null,
"Close_all": null,
"Notification": null,
"Unreadable_OTR_message": null
"Unreadable_OTR_message": null,
"Load_older_messages": null
}
}
+23 -52
Ver Arquivo
@@ -1,6 +1,6 @@
{
"name": "jsxc",
"version": "3.1.1",
"version": "3.2.0-nightly.1",
"description": "Real-time xmpp chat application with video calls, file transfer and encrypted communication",
"homepage": "http://www.jsxc.org/",
"bugs": "https://github.com/jsxc/jsxc/issues",
@@ -10,59 +10,30 @@
"type": "git",
"url": "https://github.com/jsxc/jsxc"
},
"scripts": {
"start": "webpack --config webpack.config.js",
"dev": "webpack --config webpack.config.js --watch",
"test": "karma start"
},
"devDependencies": {
"@types/chai": "^4.0.0",
"@types/jquery": "^3.2.3",
"@types/mocha": "^2.2.41",
"@types/simplebar": "^2.4.0",
"@types/sinon": "^2.3.1",
"autoprefixer-core": "^6.0.1",
"bower": "^1.8.0",
"chai": "^4.0.2",
"css-loader": "^0.28.4",
"es6-promise": "^4.1.0",
"extract-text-webpack-plugin": "^2.1.2",
"handlebars-loader": "^1.5.0",
"handlebars-runtime": "^1.0.12",
"i18next": "^8.4.2",
"karma": "^1.7.0",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^2.1.1",
"karma-firefox-launcher": "^1.0.1",
"karma-mocha": "^1.3.0",
"karma-mocha-reporter": "^2.2.3",
"karma-phantomjs-launcher": "^1.0.4",
"karma-sinon": "^1.0.5",
"karma-spec-reporter": "0.0.31",
"karma-typescript": "^3.0.4",
"karma-webpack": "^2.0.3",
"mocha": "^3.4.2",
"node-sass": "^4.5.3",
"precompile-handlebars": "^1.0.5",
"resolve-url-loader": "^2.0.3",
"sass-loader": "^6.0.6",
"sinon": "^2.3.5",
"strophe": "^1.2.4",
"ts-loader": "^2.2.0",
"ts-node": "^3.1.0",
"typescript": "^2.3.4",
"webpack": "^3.0.0"
},
"dependencies": {
"@types/emojione": "^2.2.1",
"@types/handlebars": "^4.0.33",
"@types/strophe": "^1.2.28",
"i18next": "^7.1.1",
"jquery": "^3.2.1",
"magnific-popup": "^1.1.0",
"moment": "^2.18.1",
"simplebar": "^2.4.3",
"strophe.js": "^1.2.14",
"tslib": "^1.7.1"
"grunt": "^1.0.1",
"grunt-autoprefixer": "^3.0.4",
"grunt-banner": "~0.6.0",
"grunt-contrib-clean": "~1.0.0",
"grunt-contrib-compress": "^1.4.1",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-csslint": "^2.0.0",
"grunt-contrib-jshint": "~1.1.0",
"grunt-contrib-uglify": "^2.0.0",
"grunt-contrib-watch": "^1.0.0",
"grunt-data-uri": "^0.3.0",
"grunt-html-convert": "0.0.2",
"grunt-jsbeautifier": "^0.2.13",
"grunt-jsdoc": "^2.1.0",
"grunt-merge-data": "^0.4.5",
"grunt-prettysass": "^0.2.3",
"grunt-sass": "2.0.0",
"grunt-scss-lint": "^0.5.0",
"grunt-search": "^0.1.8",
"grunt-text-replace": "~0.4.0",
"node-sass": "4.3.0"
}
}
+72
Ver Arquivo
@@ -0,0 +1,72 @@
@import "modules";
#jsxc_buddylist {
list-style: none;
padding: 0;
margin: 0;
width: 204px;
z-index: 85;
.jsxc_unreadMsg {
.jsxc_name {
padding-right: 0;
}
}
.jsxc_oneway {
.jsxc_avatar, .jsxc_caption {
opacity: 0.7;
}
}
.jsxc_right {
float: right;
margin-right: 6px;
div {
font-weight: bold;
text-align: center;
font-size: 13px;
line-height: 20px;
color: $white;
&:hover {
opacity: 1;
}
}
}
.jsxc_more {
margin-right: 6px;
z-index: 10;
position: relative;
}
.jsxc_options {
height: 20px;
float: left;
border-radius: 2px;
background-color: $roster_icon_bg;
> div {
height: 20px;
width: 20px;
float: left;
margin-right: 0 1px;
background-repeat: no-repeat;
background-position: center center;
opacity: 0.6;
cursor: pointer;
&:hover {
opacity: 1;
}
}
}
&.jsxc_hideOffline {
.jsxc_rosteritem[data-status='offline'] {
display: none;
}
}
}
@@ -25,23 +25,12 @@ $dialog_input_invalid: $red;
$dialog_input_readonly_bg: $gray90;
$spot_bg: $white;
$spot_border: $black;
$state_online: green;
$state_chat: green;
$state_away: $orange;
$state_xa: $orange;
$state_dnd: $red;
$state_offline: $gray60;
$presenceColors: (
online: green,
chat: green,
away: $orange,
xa: $orange,
dnd: $red,
offline: $gray60
);
$notice_bg: $orange;
$notice_color: $black;
$window_unread_cycle: $orange;
+58
Ver Arquivo
@@ -0,0 +1,58 @@
@import "../lib/magnific-popup/src/css/main";
@import "../lib/emojione/assets/css/emojione";
// BEGIN: bootstrap
@import "../lib/bootstrap/assets/stylesheets/bootstrap/variables";
@import "../lib/bootstrap/assets/stylesheets/bootstrap/mixins";
// Spec and IE10+
@keyframes progress-bar-stripes {
from {
background-position: 40px 0;
}
to {
background-position: 0 0;
}
}
#jsxc_dialog {
@import "../lib/bootstrap/assets/stylesheets/bootstrap/progress-bars";
}
#jsxc_dialog, #jsxc_webrtc {
@import "../lib/bootstrap/assets/stylesheets/bootstrap/utilities";
@import "../lib/bootstrap/assets/stylesheets/bootstrap/code";
@import "../lib/bootstrap/assets/stylesheets/bootstrap/grid";
@import "../lib/bootstrap/assets/stylesheets/bootstrap/alerts";
@import "../lib/bootstrap/assets/stylesheets/bootstrap/buttons";
@import "../lib/bootstrap/assets/stylesheets/bootstrap/button-groups";
@import "../lib/bootstrap/assets/stylesheets/bootstrap/forms";
.progress {
margin-bottom: 0;
.progress-bar {
width: 100%;
}
}
.mfp-close {
font-size: 23px;
font-weight: normal;
}
}
.mfp-bg {
z-index: 9000;
}
.mfp-wrap {
z-index: 9010;
}
.mfp-content {
text-align: center;
}
// END: bootstrap
+530
Ver Arquivo
@@ -0,0 +1,530 @@
.jsxc_right {
text-align: right;
}
.jsxc_center {
text-align: center;
}
.jsxc_hidden {
display: none;
}
.jsxc_clear {
clear: both;
}
.jsxc_uppercase {
text-transform: uppercase;
}
.jsxc_sep {
border-top: 1px solid $separator;
}
.jsxc_name {
overflow: hidden;
cursor: pointer;
text-overflow: ellipsis;
white-space: nowrap;
}
.jsxc_maxWidth {
max-width: 500px;
}
.jsxc_meta {
text-align: right;
font-style: italic;
}
#jsxc_dialog {
padding: 20px;
min-width: 320px;
max-width: 100%;
display: inline-block;
text-align: left;
position: relative;
background: #FFF;
width: auto;
* {
box-sizing: border-box;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
margin: 0;
padding: 0;
}
p {
margin-bottom: 1em;
input {
margin-bottom: 5px;
width: 60%;
outline: none;
}
input[type='submit'] {
width: auto;
}
}
table {
margin-bottom: 1em;
}
hr {
border: 0;
border-top: 1px solid #eee;
margin-top: 20px;
margin-bottom: 20px;
}
h3 {
font-size: 120%;
font-weight: bold;
margin-bottom: 10px;
margin-top: 20px;
}
.jsxc_right {
margin-top: 20px;
}
form {
fieldset {
margin-bottom: 30px;
padding: 0 30px;
border: 1px solid #d9d9d9;
h3 {
font-size: 15px;
color: #000;
background-color: #f2f2f2;
padding: 10px;
margin: 0 -30px 10px;
}
}
}
legend {
border: 0;
font-size: 20px;
}
input {
outline: none;
&:invalid {
border: 1px solid $dialog_input_invalid;
}
}
.btn-group button {
margin-right: 0;
}
input[readonly] {
background-color: $dialog_input_readonly_bg;
}
.jsxc_inputinfo {
padding: 0;
font-style: italic;
margin: 0;
}
.jsxc_waiting {
&:before {
content: " ";
width: 1em;
height: 1em;
display: inline-block;
background-size: 100%;
margin: 0 3px 0 0;
background-image: image-url("loading.gif");
}
}
.jsxc_libraries, .jsxc_credits {
max-width: 300px;
}
.jsxc_warning {
display: block;
background-color: #fbfe7a;
padding: 3px 10px;
border-radius: 3px;
}
}
.jsxc_avatar {
width: 36px;
height: 36px;
line-height: 36px;
margin: 0 5px;
background-color: $avatar_bg;
border-radius: 50%;
float: left;
text-align: center;
font-weight: bold;
font-size: 30px;
color: $avatar_color;
position: relative;
font-family: $font_sans;
background-size: cover;
background-position: center center;
img {
display: block;
width: 25px;
height: 25px;
position: absolute;
top: 0;
left: 0;
}
&:before {
position: absolute;
top: -2px;
left: -6px;
border: 2px solid $roster_bg;
}
}
ul.jsxc_vCard {
min-width: 400px;
ul {
margin-left: 20px;
}
li {
cursor: default !important;
}
}
// Spot which is attached to xmpp: uris
.jsxc_spot {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
text-indent: -99999em;
margin-top: 3px;
margin-right: 5px;
line-height: 100%;
cursor: pointer;
border: 1px solid $spot_border;
background-color: $white;
&:before {
position: absolute;
}
&.jsxc_online, &.jsxc_chat, &.jsxc_away, &.jsxc_xa, &.jsxc_dnd, &.jsxc_offline {
border: 0;
}
}
.jsxc_unread {
display: none;
}
.jsxc_unreadMsg {
.jsxc_name {
font-style: italic;
}
.jsxc_unread {
display: block;
background-color: $unread_bg;
border-radius: 11px;
color: $unread_color;
font-size: 80%;
padding: 2px;
line-height: 15px;
float: right;
margin-right: 3px;
margin-top: 4px;
}
}
// TODO: check if required
.jsxc_list {
.jsxc_inner {
box-sizing: border-box;
max-height: 0;
transition: max-height 0.5s;
overflow: hidden;
visibility: hidden;
position: absolute;
bottom: 100%;
left: 0;
}
&.jsxc_opened {
.jsxc_inner {
max-height: 1000px;
visibility: visible;
display: block;
}
}
}
#cboxWrapper {
outline: none;
}
.jsxc_loading {
margin: 0 auto;
width: 32px;
height: 32px;
border: 0;
background-size: 32px 32px !important;
background: image-url("loading.gif");
}
// @TODO: check
#jsxc_loginForm input[type='submit'] {
height: 34px;
display: inline-block;
padding: 6px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.428571429;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
border: 1px solid transparent;
border-radius: 4px;
user-select: none;
color: $white;
background-color: $loginForm_bg;
border-color: $loginForm_border;
}
.jsxc_oneway .jsxc_avatar {
filter: grayscale(100%);
}
img.jsxc_vCard {
float: right;
max-width: 200px;
max-height: 200px;
border: 5px solid $white;
border-radius: 2px;
}
.jsxc_alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
&.jsxc_alert-warning {
color: #8a6d3b;
background-color: #fcf8e3;
border-color: #faebcc;
}
}
.jsxc_btn {
width: auto;
min-width: 25px;
display: inline-block;
padding: 6px 12px;
margin: 0 2px;
font-size: 14px;
font-weight: 400;
line-height: 1.42857143;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
user-select: none;
background-image: none;
border: 1px solid transparent;
border-radius: 4px;
transition: background-color 0.5s;
&.jsxc_btn-default {
border-color: #ccc;
color: #555;
background-color: rgba(240, 240, 240, 0.9);
&:hover {
background-color: #d6d6d6;
}
}
&.jsxc_btn-primary {
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
&:hover {
background-color: #296496;
}
}
&[disabled], &[disabled]:hover {
opacity: 0.65;
cursor: not-allowed;
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
}
}
.jsxc_menu {
display: none;
position: absolute;
background-color: #FFF;
color: #333;
border-radius: 3px;
z-index: 110;
margin: 8px 2px 5px 10px;
right: 0;
filter: drop-shadow(0 0 5px rgba(150, 150, 150, 0.75));
padding: 4px 12px;
padding-left: 5px;
&:after {
bottom: 100%;
right: 6px;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: rgba(238, 238, 238, 0);
border-bottom-color: #fff;
border-width: 10px;
}
&.jsxc_open {
display: block;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
border: 0;
cursor: auto;
}
a {
color: #000;
opacity: 0.5;
white-space: nowrap;
&:hover {
text-decoration: none;
opacity: 1;
}
&.jsxc_disabled {
text-decoration: line-through;
opacity: 0.5;
&:hover {
text-decoration: line-through;
opacity: 0.5;
}
span {
cursor: default;
}
}
}
.jsxc_icon {
width: 16px;
height: 16px;
margin-right: 8px;
display: inline-block;
background-repeat: no-repeat;
background-size: contain;
background-position: center;
vertical-align: sub;
}
}
.jsxc_editicon {
background-image: image-url("edit_black.svg");
}
.jsxc_deleteicon {
background-image: image-url("delete_black.svg");
}
.jsxc_chaticon {
background-image: image-url("speech_balloon_black.svg");
}
.jsxc_videoicon {
background-image: image-url("camera_icon_black.svg");
}
.jsxc_infoicon {
background-image: image-url("info_black.svg");
}
.jsxc_settingsicon {
background-image: image-url("gear_black.svg");
}
.jsxc_helpicon {
background-image: image-url("help_black.svg");
}
.jsxc_contacticon {
background-image: image-url("contact_black.svg");
}
.jsxc_groupcontacticon {
background-image: image-url("groupcontact_black.svg");
}
.jsxc_bookmarkicon {
background-image: image-url("bookmark_black.svg");
}
.jsxc_announcementicon {
background-image: image-url("megaphone_icon_black.svg");
}
.jsxc_more {
float: right;
width: 44px;
height: 100%;
cursor: pointer;
background-image: image-url("more_black.svg");
background-repeat: no-repeat;
background-position: center;
opacity: 0.4;
&:hover {
opacity: 1;
}
@media (min-width: 768px) {
width: 25px;
}
}
+31 -18
Ver Arquivo
@@ -1,15 +1,22 @@
.jsxc-window-item {
&.jsxc-groupchat.jsxc-normal {
.jsxc-fade {
%muc-avatar-icon {
text-indent: 999px;
background-image: image-url("group_white.svg");
background-size: 70% 70% !important;
background-repeat: no-repeat;
}
.jsxc_windowItem {
&.jsxc_groupchat.jsxc_normal {
.jsxc_fade {
padding-top: 44px;
}
.jsxc-fingerprints, .jsxc-verification, .jsxc-transfer, .jsxc-video, .jsxc-sendFile {
.jsxc_fingerprints, .jsxc_verification, .jsxc_transfer, .jsxc_video, .jsxc_sendFile {
display: none;
}
.jsxc-members {
background-image: url("../img/group_white.svg");
.jsxc_members {
background-image: image-url("group_white.svg");
background-size: 15px 15px;
background-repeat: no-repeat;
background-position: center;
@@ -19,10 +26,10 @@
}
}
.jsxc-chatmessage.jsxc-in {
.jsxc_chatmessage.jsxc_in {
margin-left: 50px;
.jsxc-avatar {
.jsxc_avatar {
display: block;
position: absolute;
bottom: 0;
@@ -35,14 +42,14 @@
}
}
.jsxc-bar {
.jsxc-avatar {
.jsxc_bar {
.jsxc_avatar {
@extend %muc-avatar-icon;
}
}
}
.jsxc-memberlist {
.jsxc_memberlist {
height: 44px;
width: 100%;
background-color: $window_bar_bg;
@@ -72,18 +79,18 @@
margin-right: 2px;
}
.jsxc-name {
.jsxc_name {
display: none;
}
.jsxc-avatar {
.jsxc_avatar {
margin-left: 2px;
margin-right: 0;
}
}
}
&.jsxc-expand {
&.jsxc_expand {
ul {
white-space: normal;
@@ -93,7 +100,7 @@
height: 40px;
line-height: 40px;
.jsxc-name {
.jsxc_name {
display: block;
cursor: default;
@@ -102,21 +109,27 @@
}
}
.jsxc-avatar {
.jsxc_avatar {
margin-right: 4px;
}
}
}
}
.jsxc_avatar {
:before {
display: none;
}
}
}
}
li[data-type='groupchat'] {
.jsxc-avatar {
.jsxc_avatar {
@extend %muc-avatar-icon;
}
.jsxc-video {
.jsxc_video {
display: none;
}
}
+399
Ver Arquivo
@@ -0,0 +1,399 @@
#jsxc_roster {
position: fixed;
top: 0;
bottom: 0;
right: 0;
width: 200px;
overflow: visible;
border-left: 1px solid #e1e1e1;
display: none;
// border-left: 1px solid $roster_border_left;
z-index: 80;
margin-left: 10px;
background-color: $roster_bg;
a {
cursor: pointer;
}
.slimScrollDiv {
margin-bottom: 30px;
z-index: 40;
}
.jsxc_wait {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 160px;
padding: 20px;
background-color: $white;
z-index: 60;
img {
padding: 5px;
}
h3 {
margin-bottom: 5px;
font-size: 1.13em;
font-weight: bold;
}
}
input {
position: absolute;
margin: 0;
height: 35px;
padding: 7px 6px 5px;
font-size: 13px;
width: 145px;
border: 1px solid #ddd;
box-sizing: border-box;
background-image: none;
background-color: $roster_input_bg;
border-radius: 3px;
box-shadow: inner 0 0 5px $roster_input_shadow;
outline: none;
}
p {
color: $roster_color;
padding: 10px;
a {
color: $roster_a;
text-decoration: underline;
}
}
.jsxc_avatar {
position: relative;
cursor: pointer;
img {
cursor: pointer;
}
}
.jsxc_expand input {
left: 51px;
width: 137px;
}
&.jsxc_noConnection {
.slimScrollDiv {
display: none;
}
> .jsxc_bottom {
display: none;
}
}
&.jsxc_state_hidden {
display: block;
right: -200px;
transition: right 0.5s;
#jsxc_toggleRoster {
&:before {
transform: rotate(0deg);
}
}
}
&.jsxc_state_shown {
display: block;
right: 0;
transition: right 0.5s;
}
> .jsxc_bottom {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
line-height: 34px;
background-color: $roster_bottom_bg;
z-index: 50;
padding-right: 4px;
&:hover {
background-color: $roster_bottom_bg_hover;
}
.jsxc_inner {
width: 100%;
}
ul {
padding: 0;
margin: 0;
width: 100%;
border-top: 1px solid $roster_bottom_border_top;
background-color: $roster_bottom_bg;
li:last-child {
border-bottom: 1px solid $roster_bottom_border_top;
}
}
li {
height: 44px;
background-color: $roster_bottom_bg;
color: $roster_bottom_color;
cursor: pointer;
width: 100%;
padding-left: 44px;
line-height: 44px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background-repeat: no-repeat;
background-position: 15px center;
background-size: 16px 16px;
opacity: 0.8;
&.jsxc_disabled {
color: $roster_bottom_disabled;
cursor: default;
}
&:hover:not(.jsxc_disabled) {
color: $roster_bottom_color_hover;
background-color: $roster_bottom_bg_hover;
}
&.jsxc_warning {
background-color: $warning_bg;
&:hover {
background-color: $warning_bg_hover;
}
}
}
> div > span {
cursor: pointer;
}
}
}
#jsxc_toggleRoster {
width: 14px;
height: 100%;
position: absolute;
left: -14px !important;
top: 0;
z-index: 110;
background-color: transparent;
cursor: pointer;
&:hover {
background-color: $roster_toggle_hover;
}
&:before {
content: " ";
position: absolute;
display: block;
width: 0;
top: 50%;
right: 0;
border-style: solid;
border-width: 6px 4px 6px 0;
border-color: transparent $roster_bg;
transform: rotate(180deg);
}
}
.jsxc_rosteritem {
padding: 0;
margin: 0;
height: 44px;
border-bottom: 1px solid $roster_bottom_border_top;
cursor: pointer;
width: 100%;
position: relative;
color: $roster_color;
font-family: $font_sans;
line-height: 44px;
padding-left: 6px;
padding-top: 4px;
padding-bottom: 4px;
box-sizing: border-box;
&:hover {
background-color: $roster_bg_hover;
}
&.jsxc_bookmarked {
.jsxc_avatar:after {
content: " ";
width: 20%;
height: 30%;
position: absolute;
top: 0;
right: 2px;
background-size: contain;
background-repeat: no-repeat;
background-image: image-url("bookmark_red.svg");
}
}
}
.jsxc_caption {
padding-right: 30px;
height: 100%;
line-height: 100%;
// padding-top: 4px;
box-sizing: border-box;
* {
cursor: pointer;
}
.jsxc_name {
height: 100%;
line-height: 40px;
.jsxc_min & {
height: 50%;
line-height: 20px;
}
.jsxc_rosteritem & {
height: 50%;
line-height: 20px;
}
}
.jsxc_lastmsg {
font-size: 12px;
display: none;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
.jsxc_min & {
display: block;
height: 50%;
line-height: 17.5px;
}
.jsxc_rosteritem & {
display: block;
height: 50%;
line-height: 17.5px;
}
.jsxc_text {
opacity: 0.6;
}
.jsxc_unread {
line-height: 100%;
font-size: 8px;
color: #fff;
text-align: center;
display: none;
height: 1em;
width: 1em;
border-radius: 50%;
background-color: orange;
vertical-align: top;
margin: 0;
float: none;
.jsxc_unreadMsg & {
display: inline-block !important;
}
}
.jsxc_emoticon {
vertical-align: middle;
}
}
}
#jsxc_avatar {
cursor: default !important;
}
#jsxc_presence {
cursor: pointer;
padding-left: 2px;
overflow: hidden;
> span {
opacity: 0.8;
}
li {
position: relative;
&:before {
// Presence indicator
position: absolute;
top: 50%;
left: 10px;
margin-top: -8px;
border: 2px solid whitesmoke;
}
}
}
#jsxc_menu {
height: 44px;
width: 44px;
cursor: pointer;
float: right;
text-align: center;
&:hover > span {
opacity: 1;
}
> span {
opacity: 0.5;
display: block;
width: 100%;
height: 100%;
background-image: image-url("menu_black.svg");
background-repeat: no-repeat;
background-position: center 10px;
background-size: 17px;
}
@media (min-width: 768px) {
height: 30px;
width: 30px;
}
}
#jsxc_notice {
height: 30px;
width: 30px;
float: right;
text-align: center;
line-height: 30px;
span {
background-color: $notice_bg;
border-radius: 11px;
color: $notice_color;
font-size: 80%;
padding: 2px;
position: relative;
animation: bounce 2s 1s infinite;
}
> span:empty {
display: none;
}
}
+49
Ver Arquivo
@@ -0,0 +1,49 @@
.jsxc_online, .jsxc_chat, .jsxc_away, .jsxc_xa, .jsxc_dnd {
&:before {
content: " ";
display: block;
width: 12px;
height: 12px;
border-radius: 100%;
line-height: 12px;
text-align: center;
color: #fff;
z-index: 99;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
box-sizing: content-box;
}
}
.jsxc_online:before {
background-color: $state_online;
}
.jsxc_chat:before {
background-image: image-url("presence_chat.svg");
background-color: $state_chat;
}
.jsxc_away:before {
background-image: image-url("presence_away.svg");
background-color: $state_away;
}
.jsxc_xa:before {
background-image: image-url("presence_xa.svg");
background-color: $state_xa;
}
.jsxc_dnd:before {
background-image: image-url("presence_dnd.svg");
background-color: $state_dnd;
}
.jsxc_hidden {
display: none;
}
.jsxc_invalid {
border: 2px solid $invalid_border !important;
}
+60 -49
Ver Arquivo
@@ -1,5 +1,16 @@
@import "colors";
#jsxc-webrtc {
%fullscreen {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 9000;
background-color: $fullscreen_bg;
}
#jsxc_webrtc {
position: fixed;
top: 0;
bottom: 0;
@@ -8,7 +19,7 @@
z-index: 9999;
background-color: black;
.jsxc-status {
.jsxc_status {
z-index: 9999;
border-radius: 20px;
display: none;
@@ -26,7 +37,7 @@
opacity: 1 !important;
}
li .jsxc-name {
li .jsxc_name {
cursor: auto;
&:hover {
@@ -35,7 +46,7 @@
}
}
.jsxc-establishing, .jsxc-ringing {
.jsxc_establishing, .jsxc_ringing {
&:after {
content: " ";
position: absolute;
@@ -51,14 +62,14 @@
$establishingColor1: #a1a1a1;
$establishingColor2: #f1f1f1;
.jsxc-establishing:before {
.jsxc_establishing:before {
content: " ";
display: block;
width: 40px;
height: 10px;
box-sizing: border-box;
background-color: $establishingColor1;
animation-name: jsxc-establishing;
animation-name: jsxc_establishing;
animation-duration: 2s;
animation-iteration-count: infinite;
position: absolute;
@@ -69,7 +80,7 @@ $establishingColor2: #f1f1f1;
margin-top: -5px;
}
@keyframes jsxc-establishing {
@keyframes jsxc_establishing {
0% {
border-width: 0;
background-color: $establishingColor1;
@@ -94,7 +105,7 @@ $establishingColor2: #f1f1f1;
$ringingColor1: #98d48f;
$ringingColor2: #76ba6c;
.jsxc-ringing:before {
.jsxc_ringing:before {
content: " ";
display: block;
width: 20px;
@@ -102,7 +113,7 @@ $ringingColor2: #76ba6c;
box-sizing: border-box;
background-color: $ringingColor1;
border-radius: 50%;
animation-name: jsxc-ringing;
animation-name: jsxc_ringing;
animation-duration: 2s;
animation-iteration-count: infinite;
position: absolute;
@@ -113,7 +124,7 @@ $ringingColor2: #76ba6c;
margin-top: -10px;
}
@keyframes jsxc-ringing {
@keyframes jsxc_ringing {
0% {
background-color: $ringingColor1;
width: 20px;
@@ -139,17 +150,17 @@ $ringingColor2: #76ba6c;
}
}
.jsxc-bell:before {
.jsxc_bell:before {
content: " ";
display: block;
width: 80px;
height: 80px;
box-sizing: border-box;
background-image: url("../img/bell.svg");
background-image: image-url("bell.svg");
background-size: contain;
background-position: center;
background-repeat: no-repeat;
animation-name: jsxc-ringing;
animation-name: jsxc_ringing;
animation-duration: 1.5s;
animation-iteration-count: infinite;
position: absolute;
@@ -160,7 +171,7 @@ $ringingColor2: #76ba6c;
margin-top: -40px;
}
@keyframes jsxc-bell {
@keyframes jsxc_bell {
0% {
margin-left: -50px;
}
@@ -194,7 +205,7 @@ $ringingColor2: #76ba6c;
}
}
.jsxc-videoContainer {
.jsxc_videoContainer {
position: absolute;
top: 0;
left: 0;
@@ -202,7 +213,7 @@ $ringingColor2: #76ba6c;
bottom: 0;
background-color: $video_bg;
&.jsxc-minimized {
&.jsxc_minimized {
position: fixed;
top: 10px;
left: 10px;
@@ -212,7 +223,7 @@ $ringingColor2: #76ba6c;
background-color: transparent;
box-shadow: 0 0 10px #a1a1a1;
.jsxc-localvideo {
.jsxc_localvideo {
position: static;
display: block;
}
@@ -222,30 +233,30 @@ $ringingColor2: #76ba6c;
display: none;
}
.jsxc-noRemoteVideo {
.jsxc_noRemoteVideo {
display: none;
}
@media (min-width: 768px) {
right: 250px;
.jsxc-controlbar {
.jsxc_controlbar {
opacity: 0;
}
&:hover {
.jsxc-controlbar {
.jsxc_controlbar {
opacity: 1;
}
}
}
}
.jsxc-remotevideo {
.jsxc_remotevideo {
@extend %fullscreen;
}
.jsxc-noRemoteVideo {
.jsxc_noRemoteVideo {
@extend %fullscreen;
p {
@@ -292,7 +303,7 @@ $ringingColor2: #76ba6c;
}
}
.jsxc-localvideo {
.jsxc_localvideo {
width: 160px;
height: 120px;
position: absolute;
@@ -309,7 +320,7 @@ div {
height: 100%;
background-color: $black;
&.jsxc-localvideo {
&.jsxc_localvideo {
border: 1px solid $white;
}
}
@@ -319,23 +330,23 @@ div {
height: 100%;
background-color: $black;
&.jsxc-localvideo {
&.jsxc_localvideo {
border: 1px solid $white;
}
}
&.jsxc-video {
background-image: url("../img/camera_icon_white.svg");
&.jsxc_video {
background-image: image-url("camera_icon_white.svg");
background-repeat: no-repeat;
background-position: center center;
background-size: 15px 15px;
opacity: 0.4;
&.jsxc-disabled {
background-image: url("../img/camera_disabled_icon_white.svg");
&.jsxc_disabled {
background-image: image-url("camera_disabled_icon_white.svg");
}
&:not(.jsxc-disabled) {
&:not(.jsxc_disabled) {
&:hover {
opacity: 1;
}
@@ -343,7 +354,7 @@ div {
}
}
.jsxc-controlbar {
.jsxc_controlbar {
position: absolute;
top: 50px;
left: 0;
@@ -358,7 +369,7 @@ div {
top: initial;
}
&.jsxc-visible {
&.jsxc_visible {
opacity: 1;
}
@@ -370,7 +381,7 @@ div {
display: inline-block;
}
.jsxc-videoControl {
.jsxc_videoControl {
height: 44px;
width: 44px;
margin: 0 5px;
@@ -386,24 +397,24 @@ div {
}
}
.jsxc-hangUp {
background-image: url("../img/hang_up_red.svg");
.jsxc_hangUp {
background-image: image-url("hang_up_red.svg");
}
.jsxc-fullscreen {
background-image: url("../img/fullscreen_white.svg");
.jsxc_fullscreen {
background-image: image-url("fullscreen_white.svg");
}
.jsxc-showchat {
.jsxc_showchat {
float: right;
}
}
.jsxc-multi > div {
.jsxc_multi > div {
display: none;
}
.jsxc-snapshotbar {
.jsxc_snapshotbar {
width: 100%;
display: none;
@@ -412,7 +423,7 @@ div {
}
}
.jsxc-buttongroup {
.jsxc_buttongroup {
display: inline;
button {
@@ -430,7 +441,7 @@ div {
}
}
.jsxc-chatarea {
.jsxc_chatarea {
position: absolute;
top: 0;
right: 0;
@@ -443,21 +454,21 @@ div {
display: block;
}
.jsxc-settings {
.jsxc_settings {
display: none !important;
}
.jsxc-close {
.jsxc_close {
display: none !important;
}
.jsxc-video {
.jsxc_video {
display: none !important;
}
.jsxc-bar {}
.jsxc_bar {}
.jsxc-window {
.jsxc_window {
bottom: 0;
box-shadow: none;
}
@@ -470,10 +481,10 @@ div {
}
}
.jsxc-fullscreen.jsxc-localvideo {
.jsxc_fullscreen.jsxc_localvideo {
border: 1px solid $white;
}
.jsxc-videoSuitable .jsxc-name {
.jsxc_videoSuitable .jsxc_name {
font-style: italic;
}
+756
Ver Arquivo
@@ -0,0 +1,756 @@
#jsxc_windowList {
position: fixed;
bottom: 0;
right: 210px;
left: 0;
z-index: 50;
transition: right 0.5s;
&.jsxc_roster_hidden {
right: 10px;
}
@media (min-width: 768px) {
clip: rect(-10000px, 10000px, 30px, 30px);
}
> ul {
list-style: none;
padding: 0;
margin: 0;
position: absolute;
bottom: 0;
right: 0;
height: 44px;
overflow: visible;
white-space: nowrap;
transition: right 0.5s;
> li {
padding: 0;
margin: 0;
display: inline-block;
height: 44px;
width: 46px;
position: relative;
overflow: visible;
margin-right: 5px;
cursor: pointer;
white-space: normal;
&.jsxc_normal {
transition: width 0.2s;
width: 250px;
}
&.jsxc_min {
transition: width 0.2s;
width: 46px !important;
// overwrite resizeable width
@media (min-width: 768px) {
width: 200px !important;
}
.jsxc_emoticons {
display: none;
}
.jsxc_tools {
display: none;
}
}
}
}
}
#jsxc_windowListSB {
position: fixed;
left: 0;
bottom: 0;
width: 30px;
@media (max-width: 768px) {
display: none;
}
> {
div {
box-sizing: border-box;
width: 14px;
height: 30px;
background-color: $windowListSB_bg;
color: $windowListSB_color;
text-align: center;
line-height: 30px;
float: left;
cursor: pointer;
user-select: none;
&:hover {
background-color: $windowListSB_bg_hover;
}
}
.jsxc_disabled {
background-color: $windowListSB_bg_disabled !important;
color: $windowListSB_color_disabled;
cursor: default !important;
display: none;
}
}
}
.jsxc_bar {
background-color: $window_bar_bg;
cursor: pointer;
height: 44px;
line-height: 26px;
padding: 2px;
color: $window_bar_color;
width: 100%;
box-sizing: border-box;
position: relative;
&:hover {
.jsxc_normal & {
color: $window_bar_color_hover;
}
}
.jsxc_tools {
&:hover {
.jsxc_normal & {
color: #000;
}
}
}
.jsxc_min & {
background-color: $window_min_bar_bg;
color: $window_min_bar_color;
}
}
.jsxc_window {
position: absolute;
bottom: -284px;
top: auto;
left: 0;
right: 0;
height: auto;
background-color: $window_bg;
z-index: 80;
cursor: default;
border: 1px solid $window_border;
border-bottom: 0;
.jsxc_min & {
transition: bottom 0.2s;
}
.jsxc_normal & {
transition: bottom 0.2s;
}
.jsxc_showOverlay & {
.jsxc_overlay {
display: block !important;
}
}
.jsxc_emoticons {
height: 44px;
width: 44px;
position: absolute;
bottom: 0;
left: 0;
cursor: pointer;
&:after {
content: " ";
background-image: image-url("smiley.svg");
background-position: center center;
background-repeat: no-repeat;
background-size: 30px 30px;
opacity: 0.3;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.jsxc_inner {
left: 5px;
}
ul {
width: 210px;
margin-bottom: 8px;
background-color: $emoticon_selection_bg;
border-radius: 3px;
z-index: 200;
list-style-type: none;
padding: 3px;
position: relative;
&:after {
content: " ";
position: absolute;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid $emoticon_selection_bg;
display: block;
width: 0;
z-index: 1;
left: 7px;
top: 100%;
}
}
li {
div {
float: left;
cursor: pointer;
border-radius: 3px;
background-size: 30px 30px;
width: 30px;
height: 30px;
&:hover {
background-color: $emoticon_selection_hover;
}
}
}
&:hover:after {
opacity: 0.5;
}
}
.jsxc_fade {
position: relative;
overflow: hidden;
.jsxc_overlay {
display: none;
background-color: rgba(0, 0, 0, 0.5);
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
overflow-y: scroll;
> div {
background-color: #fff;
margin: 30px 10px;
padding: 5px;
border-radius: 3px;
text-align: center;
position: relative;
.jsxc_close {
position: absolute;
top: 0;
right: 0;
height: 44px;
width: 44px;
&:after {
content: "×";
position: absolute;
top: 4px;
right: 4px;
font-size: 20px;
font-family: Arial, sans-serif;
cursor: pointer;
color: #000;
opacity: 0.4;
}
&:hover {
&:after {
opacity: 1;
}
}
@media (min-width: 768px) {
width: 30px;
height: 30px;
}
}
.jsxc_body {
margin-top: 20px;
}
p {
margin-bottom: 10px;
}
li {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
a:hover {
text-decoration: underline;
}
}
}
.jsxc_mam-load-more {
display: none;
text-align: center;
font-size: 0.8em;
font-style: italic;
position: absolute;
top: -42px;
left: 0;
right: 0;
height: 42px;
cursor: pointer;
z-index: 80;
line-height: 42px;
opacity: 0;
transition: opacity 0.5s, top 0.5s;
&.jsxc_show {
top: 0;
opacity: 0.7;
&:hover {
opacity: 1;
}
}
}
&.jsxc_mam-enable {
.jsxc_textarea {
padding-top: 42px;
}
.jsxc_mam-load-more {
display: block;
}
}
}
.jsxc_avatar {
margin-top: 1px;
}
.jsxc_textarea {
width: 100%;
overflow: hidden;
padding: 3px;
}
.slimScrollDiv {
margin: 0 0 6px;
left: auto !important;
top: auto !important;
}
textarea {
&.jsxc_textinput {
width: 100%;
height: 44px;
margin: 0;
padding: 14px 40px 12px;
outline: none;
border-radius: 0;
box-sizing: border-box;
border: 0;
display: block;
resize: none;
transition: height 0.5s;
font-size: 13px;
}
&::placeholder {
color: $window_placeholder;
opacity: 0.3;
}
}
.jsxc_tools {
float: right;
> .jsxc_disabled {
opacity: 0.3;
cursor: default !important;
}
> div {
width: 25px;
height: 40px;
display: block;
float: left;
color: $tools_color;
opacity: 0.4;
font-family: $font_sans;
line-height: 40px;
cursor: pointer;
text-align: center;
&.jsxc_settings {
opacity: 1;
}
}
}
.jsxc_close {
font-size: 20px;
&:hover {
color: $window_close_hover;
opacity: 1;
}
}
.jsxc_more {
background-image: image-url("more_white.svg");
opacity: 0.4;
}
.ui-resizable-w {
left: 0;
}
.ui-resizable-nw {
top: 0;
left: 0;
width: 15px;
height: 15px;
z-index: 95 !important;
background-image: image-url("resize_gray.svg");
}
.ui-resizable-n {
position: absolute;
top: 0;
left: 0;
right: 0;
height: 15px;
z-index: 100;
}
}
.jsxc_chatmessage {
margin: 3px;
padding: 4px;
word-wrap: break-word;
background-color: $chatmessage_bg;
position: relative;
outline: none;
clear: both;
&.jsxc_error {
opacity: 0.7;
&:before {
content: " ";
position: absolute;
top: 3px;
right: 3px;
width: 8px;
height: 8px;
background-color: yellow;
}
}
a {
color: $chatmessage_a;
text-decoration: underline;
display: inline-block;
max-width: 100%;
position: relative;
&[download]:before {
content: " ";
position: absolute;
top: 0;
right: 0;
bottom: 5px;
left: 0;
border-radius: 3px;
background-color: rgba(255, 255, 255, 0.7);
background-image: url("../img/download_icon_black.svg");
background-size: contain;
background-position: center center;
background-repeat: no-repeat;
opacity: 0;
transition: opacity 0.5s;
}
&[download]:hover {
&:before {
opacity: 0.6;
}
}
}
img {
max-width: 100%;
}
.jsxc_avatar {
display: none;
}
.jsxc_attachment {
border-radius: 3px;
background-color: #fff;
padding: 3px;
padding-left: 30px;
min-height: 30px;
margin-bottom: 5px;
background-position: 3px center;
background-size: 25px 25px;
background-repeat: no-repeat;
background-image: image-url("filetypes/file.svg");
img {
border-radius: 3px;
}
&.jsxc_image {
line-height: 0;
padding: 0;
background-image: url("");
display: inline-block;
}
&.jsxc_application {
background-image: image-url("filetypes/application.svg");
}
&.jsxc_application-pdf {
background-image: image-url("filetypes/application-pdf.svg");
}
&.jsxc_audio {
background-image: image-url("filetypes/audio.svg");
}
&.jsxc_video {
background-image: image-url("filetypes/video.svg");
opacity: 1;
}
&.jsxc_text {
background-image: image-url("filetypes/text.svg");
}
}
}
.jsxc_timestamp {
font-size: 8px;
color: $chatmessage_timestamp;
line-height: 8px;
overflow: hidden;
white-space: nowrap;
max-width: 100%;
text-overflow: ellipsis;
clear: both;
}
.jsxc_encrypted {
&.jsxc_received.jsxc_out .jsxc_timestamp {
margin-right: 1px;
}
.jsxc_timestamp:after {
content: " ";
display: inline-block;
width: 10px;
height: 8px;
margin-left: 2px;
background-image: image-url("padlock_close_grey.svg");
background-size: contain;
background-repeat: no-repeat;
}
}
.jsxc_in {
float: left;
position: relative;
max-width: 76%;
margin-left: 10px;
border-radius: 3px;
background-color: $chatmessage_in_bg;
&:after {
content: " ";
position: absolute;
border-style: solid;
border-width: 5px 6px 5px 0;
border-color: transparent $chatmessage_in_bg;
display: block;
width: 0;
z-index: 1;
left: -6px;
bottom: 10px;
}
.jsxc_timestamp {
float: left;
}
}
.jsxc_out {
float: right;
position: relative;
max-width: 76%;
margin-right: 10px;
padding-right: 10px;
border-radius: 3px;
background-color: $chatmessage_out_bg;
&:after {
content: " ";
position: absolute;
border-style: solid;
border-width: 5px 0 5px 6px;
border-color: transparent $chatmessage_out_bg;
display: block;
width: 0;
z-index: 1;
right: -6px;
bottom: 10px;
}
&.jsxc_received {
&:before {
content: "";
position: absolute;
bottom: 2px;
right: 2px;
font-size: 12px;
line-height: 12px;
color: $chatmessage_received;
}
.jsxc_timestamp {
margin-right: 4px;
}
}
.jsxc_timestamp {
float: right;
}
}
.jsxc_sys {
width: auto;
max-width: none;
padding-right: 4px;
box-sizing: border-box;
margin-right: 3px;
border-radius: 3px;
background-color: transparent;
font-size: 0.8em;
font-style: italic;
.jsxc_emoticon {
width: 1.2em;
height: 1.2em;
vertical-align: middle;
}
}
div.jsxc_settings {
position: relative;
.jsxc_inner {
left: auto;
top: 100%;
right: -6px;
}
}
div.jsxc_transfer {
background-image: image-url("padlock_open_black.svg");
background-repeat: no-repeat;
background-position: center center;
background-size: 14px 14px;
opacity: 0.3;
height: 44px;
width: 44px;
position: absolute;
bottom: 0;
right: 0;
cursor: pointer;
&:hover {
opacity: 1;
}
&.jsxc_disabled {
background-image: image-url("padlock_open_disabled_black.svg");
cursor: default;
&:hover {
opacity: 0.3;
}
}
&.jsxc_fin {
opacity: 1;
background-image: image-url("padlock_close_grey.svg");
}
&.jsxc_enc {
opacity: 1;
background-image: image-url("padlock_close_orange.svg");
&.jsxc_trust {
background-image: image-url("padlock_close_green.svg");
}
}
}
.jsxc_status-msg {
font-size: 12px;
display: none;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
height: 50%;
line-height: 17.5px;
opacity: 0.7;
&.jsxc_composing {
&:before {
content: " ";
width: 1em;
height: 1em;
display: inline-block;
background-size: cover;
vertical-align: middle;
background-repeat: no-repeat;
background-image: image-url("composing.png");
}
}
}
.jsxc_status-msg-show {
.jsxc_name {
height: 50%;
line-height: 20px;
}
.jsxc_status-msg {
display: block;
}
.jsxc_lastmsg {
display: none !important;
}
}
@@ -1,4 +1,4 @@
.jsxc-emoticon {
.jsxc_emoticon {
display: inline-block;
width: 19px;
height: 19px;
@@ -6,14 +6,14 @@
border: 0;
vertical-align: bottom;
&.jsxc-large {
&.jsxc_large {
width: 40px;
height: 40px;
margin-bottom: 7px;
}
}
#jsxc-roster .jsxc-emoticon.jsxc-large {
#jsxc_roster .jsxc_emoticon.jsxc_large {
width: 19px;
height: 19px;
}
@@ -21,7 +21,7 @@
$emoticons: angel, angry, smile, grin, sad, wink, tonguesmile, surpised, kiss, sunglassess, crysad, doubt, zip, thumbsup, thumbsdown, beer, devil, kissing, rose, music, love, tired, surprised;
@each $emoticon in $emoticons {
.jsxc-#{$emoticon} {
background: url("../img/emotions/#{$emoticon}.png");
.jsxc_#{$emoticon} {
background: image-url("emotions/#{$emoticon}.png");
}
}
+17
Ver Arquivo
@@ -0,0 +1,17 @@
@import "colors";
@import "dep";
//fonts
$font_sans: Arial, sans-serif;
$font_serif: serif;
@import "modules";
@import "buddylist";
@import "state";
@import "emoticons";
@import "roster";
@import "window";
@import "muc";
@import "_jsxc";
@import "webrtc";
-20
Ver Arquivo
@@ -1,20 +0,0 @@
@import "modules/all";
@import "vendor/all";
//fonts
$font_sans: Arial, sans-serif;
$font_serif: serif;
@import "partials/button";
@import "partials/dialog";
@import "partials/emoticons";
@import "partials/icon";
@import "partials/jsxc";
@import "partials/menu";
@import "partials/roster";
@import "partials/webrtc";
@import "partials/window-list";
@import "partials/window";
@import "partials/jsxc";
@import "partials/webrtc";
-5
Ver Arquivo
@@ -1,5 +0,0 @@
@import "animation";
@import "colors";
@import "muc";
@import "webrtc";
@import "presence";
-6
Ver Arquivo
@@ -1,6 +0,0 @@
%muc-avatar-icon {
text-indent: 999px;
background-image: url("../img/group_white.svg");
background-size: 70% 70% !important;
background-repeat: no-repeat;
}
-26
Ver Arquivo
@@ -1,26 +0,0 @@
$presences: online chat away xa dnd;
@mixin presenceIndicator($target) {
@each $presence in $presences {
[data-presence="#{$presence}"] #{$target} {
&:before {
content: "";
display: block;
width: 12px;
height: 12px;
border-radius: 100%;
line-height: 12px;
text-align: center;
color: #fff;
z-index: 99;
background-repeat: no-repeat;
background-position: center;
background-size: 100%;
box-sizing: content-box;
background-image: url("../img/presence_#{$presence}.svg");
background-color: map-get($presenceColors, $presence);
}
}
}
}
-9
Ver Arquivo
@@ -1,9 +0,0 @@
%fullscreen {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 9000;
background-color: $fullscreen_bg;
}
-47
Ver Arquivo
@@ -1,47 +0,0 @@
.jsxc-btn {
width: auto;
min-width: 25px;
display: inline-block;
padding: 6px 12px;
margin: 0 2px;
font-size: 14px;
font-weight: 400;
line-height: 1.42857143;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
user-select: none;
background-image: none;
border: 1px solid transparent;
border-radius: 4px;
transition: background-color 0.5s;
&.jsxc-btn-default {
border-color: #ccc;
color: #555;
background-color: rgba(240, 240, 240, 0.9);
&:hover {
background-color: #d6d6d6;
}
}
&.jsxc-btn-primary {
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
&:hover {
background-color: #296496;
}
}
&[disabled], &[disabled]:hover {
opacity: 0.65;
cursor: not-allowed;
color: #fff;
background-color: #337ab7;
border-color: #2e6da4;
}
}
-127
Ver Arquivo
@@ -1,127 +0,0 @@
.jsxc-dialog {
padding: 20px;
min-width: 320px;
max-width: 100%;
display: inline-block;
text-align: left;
position: relative;
background: #FFF;
width: auto;
* {
box-sizing: border-box;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
margin: 0;
padding: 0;
}
p {
margin-bottom: 1em;
input {
margin-bottom: 5px;
width: 60%;
outline: none;
}
input[type='submit'] {
width: auto;
}
}
table {
margin-bottom: 1em;
}
hr {
border: 0;
border-top: 1px solid #eee;
margin-top: 20px;
margin-bottom: 20px;
}
h3 {
font-size: 120%;
font-weight: bold;
margin-bottom: 10px;
margin-top: 20px;
}
.jsxc-right {
margin-top: 20px;
}
form {
fieldset {
margin-bottom: 30px;
padding: 0 30px;
border: 1px solid #d9d9d9;
h3 {
font-size: 15px;
color: #000;
background-color: #f2f2f2;
padding: 10px;
margin: 0 -30px 10px;
}
}
}
legend {
border: 0;
font-size: 20px;
}
input {
outline: none;
&:invalid {
border: 1px solid $dialog_input_invalid;
}
}
.btn-group button {
margin-right: 0;
}
input[readonly] {
background-color: $dialog_input_readonly_bg;
}
.jsxc-inputinfo {
padding: 0;
font-style: italic;
margin: 0;
}
.jsxc-waiting {
&:before {
content: " ";
width: 1em;
height: 1em;
display: inline-block;
background-size: 100%;
margin: 0 3px 0 0;
background-image: url("../img/loading.gif");
}
}
.jsxc-libraries, .jsxc-credits {
max-width: 300px;
}
.jsxc-warning {
display: block;
background-color: #fbfe7a;
padding: 3px 10px;
border-radius: 3px;
}
}
-43
Ver Arquivo
@@ -1,43 +0,0 @@
.jsxc-icon-edit {
background-image: url("../img/edit_black.svg");
}
.jsxc-icon-delete {
background-image: url("../img/delete_black.svg");
}
.jsxc-icon-chat {
background-image: url("../img/speech_balloon_black.svg");
}
.jsxc-icon-video {
background-image: url("../img/camera_icon_black.svg");
}
.jsxc-icon-info {
background-image: url("../img/info_black.svg");
}
.jsxc-icon-setting {
background-image: url("../img/gear_black.svg");
}
.jsxc-icon-help {
background-image: url("../img/help_black.svg");
}
.jsxc-icon-contact {
background-image: url("../img/contact_black.svg");
}
.jsxc-icon-groupcontact {
background-image: url("../img/groupcontact_black.svg");
}
.jsxc-icon-bookmark {
background-image: url("../img/bookmark_black.svg");
}
.jsxc-icon-announcement {
background-image: url("../img/megaphone_icon_black.svg");
}
-209
Ver Arquivo
@@ -1,209 +0,0 @@
.jsxc-right {
text-align: right;
}
.jsxc-center {
text-align: center;
}
.jsxc-hidden {
display: none;
}
.jsxc-clear {
clear: both;
}
.jsxc-uppercase {
text-transform: uppercase;
}
.jsxc-separator {
border-top: 1px solid $separator;
}
.jsxc-name {
overflow: hidden;
cursor: pointer;
text-overflow: ellipsis;
white-space: nowrap;
}
.jsxc-max-width {
max-width: 500px;
}
.jsxc-meta {
text-align: right;
font-style: italic;
}
.jsxc-invalid {
border: 2px solid $invalid_border !important;
}
.jsxc-avatar {
width: 36px;
height: 36px;
line-height: 36px;
margin: 0 5px;
background-color: $avatar_bg;
border-radius: 50%;
float: left;
text-align: center;
font-weight: bold;
font-size: 30px;
color: $avatar_color;
position: relative;
font-family: $font_sans;
background-size: cover;
background-position: center center;
img {
display: block;
width: 25px;
height: 25px;
position: absolute;
top: 0;
left: 0;
}
&:before {
position: absolute;
top: -2px;
left: -6px;
border: 2px solid $roster_bg;
}
}
ul.jsxc-vCard {
min-width: 400px;
ul {
margin-left: 20px;
}
li {
cursor: default !important;
}
}
// Spot which is attached to xmpp: uris
.jsxc-spot {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
text-indent: -99999em;
margin-top: 3px;
margin-right: 5px;
line-height: 100%;
cursor: pointer;
border: 1px solid $spot_border;
background-color: $white;
&:before {
position: absolute;
}
&.jsxc-online, &.jsxc-chat, &.jsxc-away, &.jsxc-xa, &.jsxc-dnd, &.jsxc-offline {
border: 0;
}
}
.jsxc-unread {
display: none;
}
.jsxc-unreadMsg {
.jsxc-name {
font-style: italic;
}
.jsxc-unread {
display: block;
background-color: $unread_bg;
border-radius: 11px;
color: $unread_color;
font-size: 80%;
padding: 2px;
line-height: 15px;
float: right;
margin-right: 3px;
margin-top: 4px;
}
}
.jsxc-loading {
margin: 0 auto;
width: 32px;
height: 32px;
border: 0;
background-size: 32px 32px !important;
background: url("../img/loading.gif");
}
// @TODO: check
#jsxc-login-form input[type='submit'] {
height: 34px;
display: inline-block;
padding: 6px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.428571429;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
border: 1px solid transparent;
border-radius: 4px;
user-select: none;
color: $white;
background-color: $loginForm_bg;
border-color: $loginForm_border;
}
.jsxc-oneway .jsxc-avatar {
filter: grayscale(100%);
}
img.jsxc-vCard {
float: right;
max-width: 200px;
max-height: 200px;
border: 5px solid $white;
border-radius: 2px;
}
.jsxc-alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
&.jsxc-alert-warning {
color: #8a6d3b;
background-color: #fcf8e3;
border-color: #faebcc;
}
}
.jsxc-more {
float: right;
width: 44px;
height: 100%;
cursor: pointer;
background-image: url("../img/more_black.svg");
background-repeat: no-repeat;
background-position: center;
opacity: 0.4;
&:hover {
opacity: 1;
}
@media (min-width: 768px) {
width: 25px;
}
}
-102
Ver Arquivo
@@ -1,102 +0,0 @@
.jsxc-menu {
.jsxc-inner {
box-sizing: border-box;
max-height: 0;
transition: max-height 0.5s;
overflow: hidden;
visibility: hidden;
position: absolute;
bottom: 100%;
left: 0;
}
&.jsxc-opened {
.jsxc-inner {
max-height: 1000px;
visibility: visible;
display: block;
}
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
border: 0;
cursor: auto;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
}
.jsxc-menu-dropdown {
.jsxc-inner {
display: none;
position: absolute;
background-color: #FFF;
color: #333;
border-radius: 3px;
z-index: 110;
margin: 8px 2px 5px 10px;
right: 0;
filter: drop-shadow(0 0 5px rgba(150, 150, 150, 0.75));
padding: 4px 12px 4px 5px;
top: 100%;
bottom: auto;
overflow: visible;
&:after {
bottom: 100%;
right: 6px;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-color: rgba(238, 238, 238, 0);
border-bottom-color: #fff;
border-width: 10px;
}
}
a {
color: #000;
opacity: 0.5;
white-space: nowrap;
&:hover {
text-decoration: none;
opacity: 1;
}
&.jsxc-disabled {
text-decoration: line-through;
opacity: 0.5;
&:hover {
text-decoration: line-through;
opacity: 0.5;
}
span {
cursor: default;
}
}
}
.jsxc-icon {
width: 16px;
height: 16px;
margin-right: 8px;
display: inline-block;
background-repeat: no-repeat;
background-size: contain;
background-position: center;
vertical-align: sub;
}
}
-492
Ver Arquivo
@@ -1,492 +0,0 @@
#jsxc-roster {
position: fixed;
top: 0;
bottom: 0;
right: 0;
width: 200px;
overflow: visible;
border-left: 1px solid #e1e1e1;
z-index: 80;
margin-left: 10px;
background-color: $roster_bg;
transition: right 0.5s;
.jsxc-roster-hidden & {
right: -200px;
}
a {
cursor: pointer;
}
.jsxc-avatar {
position: relative;
cursor: pointer;
img {
cursor: pointer;
}
}
.jsxc-wait {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 160px;
padding: 20px;
background-color: $white;
z-index: 60;
img {
padding: 5px;
}
h3 {
margin-bottom: 5px;
font-size: 1.13em;
font-weight: bold;
}
}
input {
position: absolute;
margin: 0;
height: 35px;
padding: 7px 6px 5px;
font-size: 13px;
width: 145px;
border: 1px solid #ddd;
box-sizing: border-box;
background-image: none;
background-color: $roster_input_bg;
border-radius: 3px;
box-shadow: inner 0 0 5px $roster_input_shadow;
outline: none;
}
p {
color: $roster_color;
padding: 10px;
a {
color: $roster_a;
text-decoration: underline;
}
}
.jsxc-expand input {
left: 51px;
width: 137px;
}
&.jsxc-state_hidden {
display: block;
right: -200px;
transition: right 0.5s;
}
&.jsxc-state_shown {
display: block;
right: 0;
transition: right 0.5s;
}
> .jsxc-bottom {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
line-height: 34px;
background-color: $roster_bottom_bg;
z-index: 50;
padding-right: 4px;
&:hover {
background-color: $roster_bottom_bg_hover;
}
.jsxc-inner {
width: 100%;
}
ul {
padding: 0;
margin: 0;
width: 100%;
border-top: 1px solid $roster_bottom_border_top;
background-color: $roster_bottom_bg;
li:last-child {
border-bottom: 1px solid $roster_bottom_border_top;
}
}
li {
height: 44px;
background-color: $roster_bottom_bg;
color: $roster_bottom_color;
cursor: pointer;
width: 100%;
padding-left: 44px;
line-height: 44px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background-repeat: no-repeat;
background-position: 15px center;
background-size: 16px 16px;
opacity: 0.8;
&.jsxc-disabled {
color: $roster_bottom_disabled;
cursor: default;
}
&:hover:not(.jsxc-disabled) {
color: $roster_bottom_color_hover;
background-color: $roster_bottom_bg_hover;
}
&.jsxc-warning {
background-color: $warning_bg;
&:hover {
background-color: $warning_bg_hover;
}
}
}
> div > span {
cursor: pointer;
}
}
form {
padding: 15px;
button,
input {
width: 100%;
margin: 0 0 5px;
border-radius: 0;
}
.btn-primary {
background-color: #dadada;
border-color: #c1c1c1;
transition: background-color 0.5s;
&:hover {
background-color: #a2a2a2;
}
}
label {
display: block;
}
input {
position: static;
}
}
.jsxc-roster-status {
display: none;
position: absolute;
bottom: 0;
}
&.jsxc-status-show {
.jsxc-roster-status {
display: block;
}
.jsxc-bottom, .jsxc-contact-list {
display: none;
}
}
}
.jsxc-roster-toggle {
width: 14px;
height: 100%;
position: absolute;
left: -14px;
top: 0;
z-index: 110;
background-color: transparent;
cursor: pointer;
&:hover {
background-color: $roster_toggle_hover;
}
}
.jsxc-roster-item {
padding: 0;
margin: 0;
height: 44px;
border-bottom: 1px solid $roster_bottom_border_top;
cursor: pointer;
width: 100%;
position: relative;
color: $roster_color;
font-family: $font_sans;
line-height: 44px;
padding-left: 6px;
padding-top: 4px;
padding-bottom: 4px;
box-sizing: border-box;
&:hover {
background-color: $roster_bg_hover;
}
&.jsxc-bookmarked {
.jsxc-avatar:after {
content: " ";
width: 20%;
height: 30%;
position: absolute;
top: 0;
right: 2px;
background-size: contain;
background-repeat: no-repeat;
background-image: url("../img/bookmark_red.svg");
}
}
}
.jsxc-caption {
padding-right: 30px;
height: 100%;
line-height: 100%;
// padding-top: 4px;
box-sizing: border-box;
* {
cursor: pointer;
}
.jsxc-name {
height: 100%;
line-height: 40px;
.jsxc-min & {
height: 50%;
line-height: 20px;
}
.jsxc-rosteritem & {
height: 50%;
line-height: 20px;
}
}
.jsxc-lastmsg {
font-size: 12px;
display: none;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
.jsxc-min & {
display: block;
height: 50%;
line-height: 17.5px;
}
.jsxc-rosteritem & {
display: block;
height: 50%;
line-height: 17.5px;
}
.jsxc-text {
opacity: 0.6;
}
.jsxc-unread {
line-height: 100%;
font-size: 8px;
color: #fff;
text-align: center;
display: none;
height: 1em;
width: 1em;
border-radius: 50%;
background-color: orange;
vertical-align: top;
margin: 0;
float: none;
.jsxc-unreadMsg & {
display: inline-block !important;
}
}
.jsxc-emoticon {
vertical-align: middle;
}
}
}
.jsxc-menu-presence {
cursor: pointer;
padding-left: 2px;
overflow: hidden;
> span {
opacity: 0.8;
}
li {
position: relative;
&:before {
// Presence indicator
position: absolute;
top: 50%;
left: 10px;
margin-top: -8px;
border: 2px solid whitesmoke;
}
}
}
.jsxc-menu-main {
height: 44px;
width: 44px;
cursor: pointer;
float: right;
text-align: center;
&:hover > span {
opacity: 1;
}
> span {
opacity: 0.5;
display: block;
width: 100%;
height: 100%;
background-image: url("../img/menu_black.svg");
background-repeat: no-repeat;
background-position: center 10px;
background-size: 17px;
}
@media (min-width: 768px) {
height: 30px;
width: 30px;
}
}
#jsxc-notice {
height: 30px;
width: 30px;
float: right;
text-align: center;
line-height: 30px;
span {
background-color: $notice_bg;
border-radius: 11px;
color: $notice_color;
font-size: 80%;
padding: 2px;
position: relative;
animation: bounce 2s 1s infinite;
}
> span:empty {
display: none;
}
}
.jsxc-contact-list {
@include presenceIndicator(".jsxc-avatar");
list-style: none;
padding: 0;
margin: 0;
width: 204px;
z-index: 85;
&.jsxc-hide-offline {
.jsxc-roster-item[data-status='offline'] {
display: none;
}
}
.jsxc-unreadMsg {
.jsxc-name {
padding-right: 0;
}
}
.jsxc-oneway {
.jsxc-avatar,
.jsxc-caption {
opacity: 0.7;
}
}
.jsxc-right {
float: right;
margin-right: 6px;
div {
font-weight: bold;
text-align: center;
font-size: 13px;
line-height: 20px;
color: $white;
&:hover {
opacity: 1;
}
}
}
.jsxc-menu {
float: right;
height: 100%;
width: 42px;
> span {
display: block;
height: 100%;
width: 100%;
background-image: url("../img/more_black.svg");
background-repeat: no-repeat;
background-position: center center;
opacity: 0.6;
cursor: pointer;
&:hover {
opacity: 1;
}
}
.jsxc-inner {
left: auto;
right: 5px;
padding: 4px;
overflow: visible;
a {
display: block;
line-height: 42px;
width: 42px;
text-align: center;
span {
margin: 0;
}
}
}
}
}
-104
Ver Arquivo
@@ -1,104 +0,0 @@
#jsxc-window-list {
@include presenceIndicator(".jsxc-window-bar .jsxc-avatar");
position: fixed;
bottom: 0;
right: 210px;
left: 0;
z-index: 50;
transition: right 0.5s;
.jsxc-roster-hidden & {
right: 10px;
}
@media (min-width: 768px) {
clip: rect(-10000px, 10000px, 30px, 30px);
}
> ul {
list-style: none;
padding: 0;
margin: 0;
position: absolute;
bottom: 0;
right: 0;
height: 44px;
overflow: visible;
white-space: nowrap;
transition: right 0.5s;
> li {
padding: 0;
margin: 0;
display: inline-block;
height: 44px;
width: 46px;
position: relative;
overflow: visible;
margin-right: 5px;
cursor: pointer;
white-space: normal;
&.jsxc-normal {
transition: width 0.2s;
width: 250px;
}
&.jsxc-minimized {
transition: width 0.2s;
width: 46px !important;
// overwrite resizeable width
@media (min-width: 768px) {
width: 200px !important;
}
.jsxc-emoticons {
display: none;
}
.jsxc-tools {
display: none;
}
}
}
}
}
#jsxc-window-list-handler {
position: fixed;
left: 0;
bottom: 0;
width: 30px;
height: 30px;
@media (max-width: 768px) {
display: none;
}
> {
div {
box-sizing: border-box;
width: 14px;
height: 100%;
background-color: $windowListSB_bg;
color: $windowListSB_color;
text-align: center;
line-height: 30px;
float: left;
cursor: pointer;
user-select: none;
&:hover {
background-color: $windowListSB_bg_hover;
}
}
.jsxc-disabled {
background-color: $windowListSB_bg_disabled !important;
color: $windowListSB_color_disabled;
cursor: default !important;
display: none;
}
}
}
-657
Ver Arquivo
@@ -1,657 +0,0 @@
.jsxc-window {
position: absolute;
bottom: 0;
top: auto;
left: 0;
right: 0;
height: auto;
background-color: $window_bg;
z-index: 80;
cursor: default;
border: 1px solid $window_border;
border-bottom: 0;
.jsxc-showOverlay & {
.jsxc-overlay {
display: block !important;
}
}
.jsxc-avatar {
margin-top: 1px;
}
.jsxc-message-area {
position: absolute;
top: 0;
right: 2px;
bottom: 44px;
left: 0;
overflow: auto;
padding: 3px;
z-index: 10;
&::-webkit-scrollbar {
width: 2px;
height: 2px;
}
&::-webkit-scrollbar-button {
width: 0;
height: 0;
}
&::-webkit-scrollbar-thumb {
background: #d1d1d1;
border: 0;
border-right: 3px solid transparent;
border-radius: 1px;
&:hover {
background: #c1c1c1;
}
&:active {
background: #b1b1b1;
}
}
&::-webkit-scrollbar-track {
background: transparent;
border: 0 none #fff;
border-radius: 50px;
&:hover {
background: transparent;
}
&:active {
background: transparent;
}
}
&::-webkit-scrollbar-corner {
background: transparent;
}
}
// .slimScrollDiv {
// margin: 0 0 6px;
// left: auto !important;
// top: auto !important;
// }
textarea {
&.jsxc-message-input {
width: 100%;
height: 44px;
margin: 0;
padding: 14px 40px 12px;
outline: none;
border-radius: 0;
box-sizing: border-box;
border: 0;
display: block;
resize: none;
transition: height 0.2s;
font-size: 13px;
position: absolute;
bottom: 0;
}
&::placeholder {
color: $window_placeholder;
opacity: 0.3;
}
}
.jsxc-tools {
float: right;
> .jsxc-disabled {
opacity: 0.3;
cursor: default !important;
}
> div {
width: 25px;
height: 40px;
display: block;
float: left;
color: $tools_color;
opacity: 0.4;
font-family: $font_sans;
line-height: 40px;
cursor: pointer;
text-align: center;
&.jsxc-menu {
opacity: 1;
}
}
}
.jsxc-close {
font-size: 20px;
&:hover {
color: $window_close_hover;
opacity: 1;
}
}
.jsxc-more {
background-image: url("../img/more_white.svg");
opacity: 0.4;
}
// .ui-resizable-w {
// left: 0;
// }
//
// .ui-resizable-nw {
// top: 0;
// left: 0;
// width: 15px;
// height: 15px;
// z-index: 95 !important;
// background-image: url("../img/resize_gray.svg");
// }
//
// .ui-resizable-n {
// position: absolute;
// top: 0;
// left: 0;
// right: 0;
// height: 15px;
// z-index: 100;
// }
}
.jsxc-window-bar {
background-color: $window_bar_bg;
cursor: pointer;
height: 44px;
line-height: 26px;
padding: 2px;
color: $window_bar_color;
width: 100%;
box-sizing: border-box;
position: relative;
transition: background-color 0.3s;
&:hover {
.jsxc-normal & {
color: $window_bar_color_hover;
}
}
.jsxc-tools {
&:hover {
.jsxc-normal & {
color: #000;
}
}
}
.jsxc-minimized & {
background-color: $window_min_bar_bg;
color: $window_min_bar_color;
}
.jsxc-highlight & {
background-color: orange;
}
}
.jsxc-window-fade {
position: relative;
height: 320px;
transition: height 0.2s;
overflow: hidden;
.jsxc-normal & {}
.jsxc-minimized & {
height: 0;
}
.jsxc-overlay {
display: none;
background-color: rgba(0, 0, 0, 0.5);
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
overflow-y: scroll;
> div {
background-color: #fff;
margin: 30px 10px;
padding: 5px;
border-radius: 3px;
text-align: center;
position: relative;
.jsxc-close {
position: absolute;
top: 0;
right: 0;
height: 44px;
width: 44px;
&:after {
content: "×";
position: absolute;
top: 4px;
right: 4px;
font-size: 20px;
font-family: Arial, sans-serif;
cursor: pointer;
color: #000;
opacity: 0.4;
}
&:hover {
&:after {
opacity: 1;
}
}
@media (min-width: 768px) {
width: 30px;
height: 30px;
}
}
.jsxc-body {
margin-top: 20px;
}
p {
margin-bottom: 10px;
}
li {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
a:hover {
text-decoration: underline;
}
}
}
}
.jsxc-menu-emoticons {
height: 44px;
width: 44px;
position: absolute;
bottom: 0;
left: 0;
cursor: pointer;
z-index: 30;
&:after {
content: " ";
background-image: url("../img/smiley.svg");
background-position: center center;
background-repeat: no-repeat;
background-size: 30px 30px;
opacity: 0.3;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.jsxc-inner {
left: 5px;
}
ul {
width: 217px;
margin-bottom: 8px;
background-color: $emoticon_selection_bg;
border-radius: 3px;
z-index: 200;
list-style-type: none;
padding: 3px;
position: relative;
&:after {
content: " ";
position: absolute;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
border-top: 8px solid $emoticon_selection_bg;
display: block;
width: 0;
z-index: 1;
left: 7px;
top: 100%;
}
}
li {
display: inline-block;
cursor: pointer;
border-radius: 3px;
width: 30px;
height: 30px;
&:hover {
background-color: $emoticon_selection_hover;
}
.jsxc-emoticon {
width: 100%;
height: 100%;
background-size: contain;
}
}
&:hover:after {
opacity: 0.5;
}
}
.jsxc-chatmessage {
margin: 3px;
padding: 4px;
word-wrap: break-word;
background-color: $chatmessage_bg;
position: relative;
outline: none;
clear: both;
&.jsxc-error {
opacity: 0.7;
&:before {
content: " ";
position: absolute;
top: 3px;
right: 3px;
width: 8px;
height: 8px;
background-color: yellow;
}
}
a {
color: $chatmessage_a;
text-decoration: underline;
display: inline-block;
max-width: 100%;
position: relative;
&[download]:before {
content: " ";
position: absolute;
top: 0;
right: 0;
bottom: 5px;
left: 0;
border-radius: 3px;
background-color: rgba(255, 255, 255, 0.7);
background-image: url("../img/download_icon_black.svg");
background-size: contain;
background-position: center center;
background-repeat: no-repeat;
opacity: 0;
transition: opacity 0.5s;
}
&[download]:hover {
&:before {
opacity: 0.6;
}
}
}
img {
max-width: 100%;
}
.jsxc-avatar {
display: none;
}
.jsxc-attachment {
border-radius: 3px;
background-color: #fff;
padding: 3px 3px 3px 30px;
min-height: 30px;
margin-bottom: 5px;
background-position: 3px center;
background-size: 25px 25px;
background-repeat: no-repeat;
background-image: url("../img/filetypes/file.svg");
img {
border-radius: 3px;
}
&.jsxc-image {
line-height: 0;
padding: 0;
background-image: url("");
display: inline-block;
}
&.jsxc-application {
background-image: url("../img/filetypes/application.svg");
}
&.jsxc-application-pdf {
background-image: url("../img/filetypes/application-pdf.svg");
}
&.jsxc-audio {
background-image: url("../img/filetypes/audio.svg");
}
&.jsxc-video {
background-image: url("../img/filetypes/video.svg");
opacity: 1;
}
&.jsxc-text {
background-image: url("../img/filetypes/text.svg");
}
}
}
.jsxc-timestamp {
font-size: 8px;
color: $chatmessage_timestamp;
line-height: 8px;
overflow: hidden;
white-space: nowrap;
max-width: 100%;
text-overflow: ellipsis;
clear: both;
}
.jsxc-encrypted {
&.jsxc-received.jsxc-out .jsxc-timestamp {
margin-right: 1px;
}
.jsxc-timestamp:after {
content: " ";
display: inline-block;
width: 10px;
height: 8px;
margin-left: 2px;
background-image: url("../img/padlock_close_grey.svg");
background-size: contain;
background-repeat: no-repeat;
}
}
.jsxc-in {
float: left;
position: relative;
max-width: 76%;
margin-left: 10px;
border-radius: 3px;
background-color: $chatmessage_in_bg;
&:after {
content: " ";
position: absolute;
border-style: solid;
border-width: 5px 6px 5px 0;
border-color: transparent $chatmessage_in_bg;
display: block;
width: 0;
z-index: 1;
left: -6px;
bottom: 10px;
}
.jsxc-timestamp {
float: left;
}
}
.jsxc-out {
float: right;
position: relative;
max-width: 76%;
margin-right: 10px;
padding-right: 10px;
border-radius: 3px;
background-color: $chatmessage_out_bg;
&:after {
content: " ";
position: absolute;
border-style: solid;
border-width: 5px 0 5px 6px;
border-color: transparent $chatmessage_out_bg;
display: block;
width: 0;
z-index: 1;
right: -6px;
bottom: 10px;
}
&.jsxc-received {
&:before {
content: "";
position: absolute;
bottom: 2px;
right: 2px;
font-size: 12px;
line-height: 12px;
color: $chatmessage_received;
}
.jsxc-timestamp {
margin-right: 4px;
}
}
.jsxc-timestamp {
float: right;
}
}
.jsxc-sys {
width: auto;
max-width: none;
padding-right: 4px;
box-sizing: border-box;
margin-right: 3px;
border-radius: 3px;
background-color: transparent;
font-size: 0.8em;
font-style: italic;
.jsxc-emoticon {
width: 1.2em;
height: 1.2em;
vertical-align: middle;
}
&.jsxc-composing {
text-align: center;
font-size: 0.9em;
font-style: italic;
display: block;
opacity: 0;
overflow: hidden;
transition: opacity 0.6s;
&:before {
content: " ";
width: 1.5em;
height: 1em;
display: inline-block;
background-size: 80%;
background-repeat: no-repeat;
margin: 0 3px 0 0;
background-image: url("../img/composing.png");
}
&.jsxc-fadein {
opacity: 1;
}
}
}
.jsxc-menu-settings {
position: relative;
.jsxc-inner {
left: auto;
top: 100%;
right: -6px;
}
}
div.jsxc-transfer {
background-image: url("../img/padlock_open_black.svg");
background-repeat: no-repeat;
background-position: center center;
background-size: 14px 14px;
opacity: 0.3;
height: 44px;
width: 44px;
position: absolute;
bottom: 0;
right: 0;
cursor: pointer;
z-index: 20;
&:hover {
opacity: 1;
}
&.jsxc-disabled {
background-image: url("../img/padlock_open_disabled_black.svg");
cursor: default;
&:hover {
opacity: 0.3;
}
}
&.jsxc-fin {
opacity: 1;
background-image: url("../img/padlock_close_grey.svg");
}
&.jsxc-enc {
opacity: 1;
background-image: url("../img/padlock_close_orange.svg");
&.jsxc-trust {
background-image: url("../img/padlock_close_green.svg");
}
}
}
-61
Ver Arquivo
@@ -1,61 +0,0 @@
@import "../../lib/magnific-popup/src/css/main";
@import "../../lib/emojione/assets/css/emojione";
// BEGIN: bootstrap
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/variables";
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/mixins";
// Spec and IE10+
@keyframes progress-bar-stripes {
from {
background-position: 40px 0;
}
to {
background-position: 0 0;
}
}
#jsxc-dialog {
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/progress-bars";
}
#jsxc-dialog, #jsxc-webrtc {
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/utilities";
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/code";
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/grid";
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/alerts";
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/buttons";
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/button-groups";
@import "../../lib/bootstrap/assets/stylesheets/bootstrap/forms";
.progress {
margin-bottom: 0;
.progress-bar {
width: 100%;
}
}
.mfp-close {
font-size: 23px;
}
}
.mfp-bg {
z-index: 9000;
}
.mfp-wrap {
z-index: 9010;
}
.mfp-content {
text-align: center;
}
// END: bootstrap
#cboxWrapper {
outline: none;
}
-334
Ver Arquivo
@@ -1,334 +0,0 @@
import Storage from './Storage'
import {IConnection} from './connection/ConnectionInterface'
import * as Connector from './connection/xmpp/connector'
import XMPPConnection from './connection/xmpp/Connection'
import StorageConnection from './connection/storage/Connection'
import JID from './JID'
import Contact from './Contact'
import ContactData from './ContactData'
import Roster from './ui/Roster'
import ChatWindow from './ui/ChatWindow'
import ChatWindowList from './ui/ChatWindowList'
import SortedPersistentMap from './SortedPersistentMap'
import PersistentMap from './PersistentMap'
import Log from './util/Log'
import {Presence} from './connection/AbstractConnection'
import Client from './Client'
import {Notice, NoticeData, TYPE as NOTICETYPE} from './Notice'
interface IConnectionParameters {
url:string,
jid: string,
sid?:string,
rid?:string,
timestamp?:number,
inactivity?:number
};
export default class Account {
private storage:Storage;
private uid:string;
private connection:IConnection;
private connectionArguments;
private connectionParameters:IConnectionParameters;
private contacts = {};
private windows:SortedPersistentMap;
private notices:SortedPersistentMap;
private contact:Contact;
constructor(boshUrl: string, jid: string, sid: string, rid:string);
constructor(boshUrl: string, jid: string, password: string);
constructor(uid:string);
constructor() {
if (arguments.length === 1) {
this.uid = arguments[0];
} else if (arguments.length === 3 || arguments.length === 4) {
this.uid = (new JID(arguments[1])).bare;
this.connectionArguments = arguments;
}
this.connection = new StorageConnection(this);
this.contact = new Contact(this, new ContactData({
jid: new JID(this.uid),
name: this.uid
}));
Roster.get().setRosterAvatar(this.contact);
this.restoreContacts();
this.initNotices();
this.initWindows();
this.getStorage().registerHook('contact:', (contactData) => {
let contact = new Contact(this, contactData.jid);
if (typeof this.contacts[contact.getId()] === 'undefined') { console.log('add', contactData.jid)
this.contacts[contact.getId()] = contact;
Roster.get().add(contact);
}
});
}
public connect() {
let self = this;
if (!this.connectionArguments) {
this.reloadConnectionData();
}
if (self.connectionParameters && self.connectionParameters.inactivity && (new Date()).getTime() - self.connectionParameters.timestamp > self.connectionParameters.inactivity) {
Log.warn('Credentials expired')
this.closeAllChatWindows();
return Promise.reject('Credentials expired');
}
return Connector.login.apply(this, this.connectionArguments).then(this.successfulConnected);
}
public getContact(jid:JID):Contact {
return this.contacts[jid.bare];
}
public addContact(data:ContactData):Contact {
let contact = new Contact(this, data);
contact.save();
this.contacts[contact.getId()] = contact;
this.save();
return contact;
}
public removeContact(contact:Contact) {
let id = contact.getId();
if (this.contacts[id]) {
delete this.contacts[id];
Roster.get().remove(contact);
//@REVIEW contact.getChatWindow would be nice
let chatWindow = this.windows.get(id);
if (chatWindow) {
this.closeChatWindow(chatWindow);
}
}
}
public removeAllContacts() {
for(let id in this.contacts) {
let contact = this.contacts[id];
delete this.contacts[id];
Roster.get().remove(contact);
}
}
public openChatWindow(contact:Contact) {
let chatWindow = new ChatWindow(this, contact);
chatWindow = ChatWindowList.get().add(chatWindow);
this.windows.push(chatWindow);
this.save();
return chatWindow;
}
public closeChatWindow(chatWindow:ChatWindow) {
// let id = chatWindow.getContact().getId();
console.log('chatWindow', chatWindow)
ChatWindowList.get().remove(chatWindow);
this.windows.remove(chatWindow);
this.save();
}
public closeAllChatWindows() {
this.windows.empty((id, chatWindow) => {
ChatWindowList.get().remove(chatWindow);
});
}
public addNotice(noticeData:NoticeData) {
let notice = new Notice(this.getStorage(), noticeData);
if (this.notices.get(notice.getId())) {
return;
}
//Roster.get().addNotice(this, notice);
this.notices.push(notice);
}
public removeNotice(notice:Notice) { console.log('removeNotice', notice);
//Roster.get().removeNotice(this, notice);
this.notices.remove(notice);
}
public getStorage() {
if(!this.storage) {
this.storage = new Storage(this.uid);
}
return this.storage;
}
public getConnection():IConnection {
return this.connection;
}
public getUid() {
return this.uid;
}
public getJID():JID {
let storedAccountData = this.getStorage().getItem('account') || {};
let jidString = (storedAccountData.connectionParameters) ? storedAccountData.connectionParameters.jid : this.getUid();
//@REVIEW maybe promise?
return new JID(jidString);
}
public remove() {
this.removeAllContacts();
this.closeAllChatWindows();
Client.removeAccount(this);
}
private successfulConnected = (data) => {
let connection = data.connection;
let status = data.status;
this.connectionParameters = $.extend(this.connectionParameters, {
url: connection.service,
jid: connection.jid,
sid: connection._proto.sid,
rid: connection._proto.rid,
timestamp: (new Date()).getTime()
});
if (connection._proto.inactivity) {
this.connectionParameters.inactivity = connection._proto.inactivity * 1000;
}
this.save();
connection.connect_callback = (status) => {
if (status === Strophe.Status.DISCONNECTED) {
this.connectionDisconnected();
}
}
connection.nextValidRid = (rid) => {
this.connectionParameters.timestamp = (new Date()).getTime();
this.connectionParameters.rid = rid;
this.save();
};
this.connection = new XMPPConnection(this, connection);
if (status === Strophe.Status.CONNECTED) {
Roster.get().setPresence(Presence.online);
Roster.get().refreshOwnPresenceIndicator();
this.connection.getRoster().then(() => {
this.connection.sendPresence();
});
} else {
this.connection.sendPresence();
}
}
private connectionDisconnected() {
console.log('disconnected');
this.remove();
}
private save() {
this.getStorage().setItem('account', {
connectionParameters: this.connectionParameters,
contacts: Object.keys(this.contacts),
// windows: Object.keys(this.windows)
});
}
private reloadConnectionData() {
let storedAccountData = this.getStorage().getItem('account') || {};
console.log('storedAccountData', storedAccountData)
this.connectionParameters = storedAccountData.connectionParameters;
let p = this.connectionParameters;
this.connectionArguments = [p.url, (new JID(p.jid)).full, p.sid, p.rid];
}
private restoreContacts() {
let storedAccountData = this.getStorage().getItem('account');
storedAccountData.contacts.forEach((id) => {
this.contacts[id] = new Contact(this, id);
Roster.get().add(this.contacts[id]);
});
}
private initWindows() {
this.windows = new SortedPersistentMap(this.getStorage(), 'windows');
this.windows.setRemoveHook((id, chatWindow) => {
console.log('remove hook', id, chatWindow);
if (chatWindow) {
ChatWindowList.get().remove(chatWindow);
}
});
this.windows.setPushHook((id) => {
let chatWindow = new ChatWindow(this, this.contacts[id]);
this.windows[id] = chatWindow;
ChatWindowList.get().add(chatWindow);
return chatWindow;
});
this.windows.init();
}
private initNotices() {
this.notices = new SortedPersistentMap(this.getStorage(), 'notices');
this.notices.setRemoveHook((id) => {
Roster.get().removeNotice(this, id);
});
this.notices.setPushHook((id) => {
let notice = new Notice(this.getStorage(), id);
Roster.get().addNotice(this, notice);
return notice;
});
this.notices.init();
}
}
-112
Ver Arquivo
@@ -1,112 +0,0 @@
import Options from './Options';
import Log from './util/Log';
export default class Attachment {
private mimeType:string;
private data:any;
private thumbnailData:any;
private size:number;
private persistent:boolean;
private name:string;
constructor(name:string, mimeType:string, data:any);
constructor(id:string);
constructor() {
// @TODO
}
public save():boolean {
if (this.isImage() && this.data && !this.thumbnailData) {
this.generateThumbnail();
}
if (this.size > Options.get('maxStorableSize')) {
Log.debug('Attachment to large to store');
this.persistent = false;
return false;
//@TODO delete data and store thumbnailData
}
//@TODO save to storage
return true;
}
public getSize():number {
return this.size;
}
public getMimeType():string {
return this.mimeType;
}
public getThumbnailData() {
return this.thumbnailData;
}
public getName() {
return this.name;
}
public isPersistent():boolean {
return this.persistent;
}
public isImage():boolean {
return /^image\//i.test(this.mimeType);
}
public hasThumbnailData():boolean {
return !!this.thumbnailData;
}
public hasData():boolean {
return !!this.data;
}
public clearData() {
this.data = null;
}
private generateThumbnail():void {
if(typeof Image === 'undefined') {
return;
}
var sHeight, sWidth, sx, sy;
var dHeight = 100,
dWidth = 100;
var canvas = <HTMLCanvasElement> $("<canvas>").get(0);
canvas.width = dWidth;
canvas.height = dHeight;
var ctx = canvas.getContext("2d");
var img = new Image();
img.src = this.data;
if (img.height > img.width) {
sHeight = img.width;
sWidth = img.width;
sx = 0;
sy = (img.height - img.width) / 2;
} else {
sHeight = img.height;
sWidth = img.height;
sx = (img.width - img.height) / 2;
sy = 0;
}
ctx.drawImage(img, sx, sy, sWidth, sHeight, 0, 0, dWidth, dHeight);
this.thumbnailData = canvas.toDataURL();
}
}
-20
Ver Arquivo
@@ -1,20 +0,0 @@
export let NOTIFICATION_DEFAULT = 'default';
export let NOTIFICATION_GRANTED = 'granted';
export let NOTIFICATION_DENIED = 'denied';
export let STATUS = ['offline', 'dnd', 'xa', 'away', 'chat', 'online'];
export let SOUNDS = {
MSG: 'incomingMessage.wav',
CALL: 'Rotary-Phone6.mp3',
NOTICE: 'Ping1.mp3'
};
export let REGEX = {
JID: new RegExp('\\b[^"&\'\\/:<>@\\s]+@[\\w-_.]+\\b', 'ig'),
URL: new RegExp(/(https?:\/\/|www\.)[^\s<>'"]+/gi)
};
export let NS = {
CARBONS: 'urn:xmpp:carbons:2',
FORWARD: 'urn:xmpp:forward:0'
};
export let HIDDEN = 'hidden';
export let SHOWN = 'shown';
-116
Ver Arquivo
@@ -1,116 +0,0 @@
import Account from './Account'
import Message from './Message'
import {PluginInterface} from './PluginInterface'
import Storage from './Storage';
import * as UI from './ui/web'
import JID from './JID'
import Roster from './ui/Roster'
import ChatWindowList from './ui/ChatWindowList'
import RoleAllocator from './RoleAllocator'
export default class Client implements ClientInterface {
private static storage;
private static accounts = {};
public static init() {
let roleAllocator = RoleAllocator.get();
let accountIds = Client.getStorage().getItem('accounts') || [];
accountIds.forEach(function(id) {
Client.accounts[id] = new Account(id);
roleAllocator.waitUntilMaster().then(function(){
return Client.accounts[id].connect();
}).then(function(){
}).catch(function(msg){
Client.accounts[id].remove();
console.warn(msg)
});
});
}
public static addConnectionPlugin(plugin:PluginInterface) {
}
public static addPreSendMessageHook(hook:(Message, Builder)=>void, position?:number) {
}
public static hasFocus() {
}
public static isExtraSmallDevice():boolean {
return $(window).width() < 500;
}
public static isDebugMode():boolean {
return Client.getStorage().getItem('debug') === true;
}
public static getStorage() {
if (!Client.storage) {
Client.storage = new Storage();
}
return Client.storage;
}
public static getAccout(jid:JID):Account;
public static getAccout(uid?:string):Account;
public static getAccout() {
let uid;
if (arguments[0] instanceof JID) {
uid = arguments[0].bare;
} else if (arguments[0]) {
uid = arguments[0];
} else {
uid = Object.keys(Client.accounts)[0];
}
return Client.accounts[uid];
}
public static createAccount(boshUrl: string, jid: string, sid: string, rid:string);
public static createAccount(boshUrl: string, jid: string, password: string);
public static createAccount() {
let account;
if (arguments.length === 4) {
account = new Account(arguments[0], arguments[1], arguments[2], arguments[3]);
} else if (arguments.length === 3) {
account = new Account(arguments[0], arguments[1], arguments[2]);
} else {
return Promise.reject(null);
}
return account.connect().then(function(){
Client.addAccount(account);
});
}
public static removeAccount(account:Account) {
delete Client.accounts[account.getUid()];
Client.save();
if (Object.keys(Client.accounts).length === 0) {
Roster.get().setNoConnection();
}
}
private static addAccount(account:Account) {
Client.accounts[account.getUid()] = account;
Client.save()
}
private static save() {
Client.getStorage().setItem('accounts', Object.keys(this.accounts));
}
}
-26
Ver Arquivo
@@ -1,26 +0,0 @@
import {JIDInterface} from './JIDInterface'
import {PluginInterface} from './PluginInterface'
export interface ClientInterface {
init();
addConnectionPlugin(plugin:PluginInterface);
addPreSendMessageHook(hook:(Message, Builder)=>void, position?:number);
hasFocus();
isExtraSmallDevice():boolean;
isDebugMode():boolean;
getStorage();
getAccout(jid:JIDInterface):Account;
getAccout(uid?:string):Account;
createAccount(boshUrl: string, jid: string, sid: string, rid:string);
createAccount(boshUrl: string, jid: string, password: string);
removeAccount(account:Account);
}
-228
Ver Arquivo
@@ -1,228 +0,0 @@
import Storage from './Storage'
import JID from './JID'
import Message from './Message'
import Notification from './Notification'
import Translation from './util/Translation'
import Account from './Account'
import ContactData from './ContactData'
import PersistentMap from './PersistentMap'
import IdentifiableInterface from './IdentifiableInterface'
import Log from './util/Log'
import {Presence} from './connection/AbstractConnection'
export default class Contact implements IdentifiableInterface {
private storage: Storage;
private readonly account:Account;
// @REVIEW Data to own object/type?
private data:PersistentMap;
private jid:JID;
constructor(account:Account, data: ContactData);
constructor(account:Account, id:string);
constructor() {
this.account = arguments[0];
this.storage = this.account.getStorage();
if (typeof arguments[1] === 'string') {
let id = arguments[1]; console.log('id', id)
this.data = new PersistentMap(this.storage, 'contact', id);
this.jid = new JID(this.data.get('jid'));
return;
}
let data = arguments[1] || {};
if (!data.jid) {
throw 'Jid missing';
} else if (typeof data.jid === 'string') {
this.jid = new JID(data.jid);
} else {
this.jid = data.jid;
data.jid = this.jid.full;
}
this.data = new PersistentMap(this.storage, 'contact', this.jid.bare);
data.rnd = Math.random() // force storage event
this.data.set(data);
}
public save() {
// if (this.storage.getItem('contact', this.getId())) {
// this.storage.updateItem('contact', this.getId(), this.data);
//
// return 'updated';
// }
//
// this.storage.setItem('contact', this.getId(), this.data);
//
// return 'created';
}
public openWindow = () => {
return this.account.openChatWindow(this);
}
public addResource(resource:string) {
let resources = this.data.get('resources') || [];
if (resource && resources.indexOf(resource) < 0) {
resources.push(resource);
this.data.set('resources', resources);
}
}
public removeResource(resource:string) {
let resources = this.data.get('resources') || [];
resources = $.grep(resources, function(r) {
return resource !== r;
});
this.data.set('resources', resources);
}
public setResource = (resource:string) => {
//this.addResource(resource);
console.log('setResource', this.jid.bare + '/' + resource)
this.jid = new JID(this.jid.bare + '/' + resource);
this.data.set('jid', this.jid.full);
}
public setPresence(resource:string, presence:Presence) {
Log.debug('set presence for ' + this.jid.bare + ' / ' + resource, presence);
let resources = this.data.get('resources') || {};
if (presence === Presence.offline) {
delete resources[resource];
} else if (resource) {
resources[resource] = presence;
}
if (this.getType() === 'groupchat') {
// group chat doesn't have a presence
return;
}
presence = this.getHighestPresence();
console.log('highest presence', presence);
if (this.data.get('presence') === Presence.offline && presence !== Presence.offline) {
// buddy has come online
// @TODO
// Notification.notify({
// title: this.getName(),
// message: Translation.t('has_come_online'),
// source: this.getId()
// });
}
this.data.set('presence', presence);
}
public sendMessage(message:Message) {
// message.bid = this.getId();
}
public getId():string {
return this.jid.bare;
}
public getJid():JID {
return this.jid;
}
public getFingerprint() {
return this.data.get('fingerprint');
}
public getMsgState() {
return this.data.get('msgstate');
}
public getPresence() {
return this.data.get('presence');
}
public getType() {
return this.data.get('type');
}
public getNumberOfUnreadMessages():number {
}
public getName():string {
return this.data.get('name') || this.jid.bare;
}
public getAvatar():Promise<{}> {
}
public getSubscription() {
return this.data.get('subscription');
}
public getCapabilitiesByRessource():Promise<{}> {
// @TODO
return Promise.resolve({});
}
public getVcard():Promise<{}> {
return this.account.getConnection().loadVcard(this.getJid());
}
public isEncrypted() {
}
public getStatus():string {
return this.data.get('status');
}
public setStatus(status:string) { console.trace(this.getId() + ', setStatus: ' + status)
return this.data.set('status', status);
}
public setTrust(trust:boolean) {
this.data.set('trust', trust);
}
public setName(name:string) {
let oldName = this.getName();
this.data.set('name', name);
if (oldName !== name) {
this.account.getConnection().setDisplayName(this.jid, name);
}
}
public setSubscription(subscription:string) {
this.data.set('subscription', subscription);
}
public registerHook(property:string, func:(newValue:any, oldValue:any)=>void) {
this.data.registerHook(property, func);
}
private getHighestPresence() {
let maxPresence = Presence.offline;
let resources = this.data.get('resources');
for (let resource in resources) {
if(resources[resource] < maxPresence) {
maxPresence = resources[resource];
}
}
return maxPresence;
}
}
-26
Ver Arquivo
@@ -1,26 +0,0 @@
//@TODO duplicate of AbstractConnection
enum Presence {
online,
chat,
away,
xa,
dnd,
offline
}
export default class ContactData {
public jid;
public name;
public presence:Presence = Presence.offline;
public status:string = '';
public subscription = 'none';
public msgstate = 0;
public trust:boolean = false;
public fingerprint:string = null;
public resources = {};
public type = 'chat'
constructor(data:any) {
$.extend(this, data);
}
}
-55
Ver Arquivo
@@ -1,55 +0,0 @@
import {MessageInterface} from './MessageInterface'
import {JIDInterface} from './JIDInterface'
import {Presence} from './connection/AbstractConnection'
export interface ContactInterface {
openWindow();
addResource(resource:string);
removeResource(resource:string);
setResource(resource:string);
setPresence(resource:string, presence:Presence);
sendMessage(message:MessageInterface);
getId():string;
getJid():JIDInterface;
getFingerprint();
getMsgState();
getPresence();
getType();
getNumberOfUnreadMessages():number;
getName():string;
getAvatar():Promise<{}>;
getSubscription();
getCapabilitiesByRessource():Promise<{}>;
getVcard():Promise<{}>;
isEncrypted();
getStatus():string;
setStatus(status:string);
setTrust(trust:boolean);
setName(name:string);
setSubscription(subscription:string);
registerHook(property:string, func:(newValue:any, oldValue:any)=>void);
}
Ver Arquivo
-127
Ver Arquivo
@@ -1,127 +0,0 @@
import Options from './Options'
const EMOTICONS = [
['O:-) O:)', 'innocent'],
['>:-( >:( &gt;:-( &gt;:(', 'angry'],
[':-) :)', 'slight_smile'],
[':-D :D', 'grin'],
[':-( :(', 'disappointed'],
[';-) ;)', 'wink'],
[':-P :P', 'stuck_out_tongue'],
['=-O', 'astonished'],
[':kiss: :-*', 'kissing_heart'],
['8-) :cool:', 'sunglasses'],
[':-X :X', 'zipper_mouth'],
[':yes:', 'thumbsup'],
[':no:', 'thumbsdown'],
[':beer:', 'beer'],
[':coffee:', 'coffee'],
[':devil:', 'smiling_imp'],
[':kiss: :kissing:', 'kissing'],
['@->-- @-&gt;--', 'rose'],
[':music:', 'musical_note'],
[':love:', 'heart_eyes'],
[':heart:', 'heart'],
[':brokenheart:', 'broken_heart'],
[':zzz:', 'zzz'],
[':wait:', 'hand_splayed']
]
import * as emojione from '../lib/emojione/lib/js/emojione.js';
const EMOTICON_LIST = {
'core': {
':klaus:': ['klaus'],
':jabber:': ['jabber'],
':xmpp:': ['xmpp'],
':jsxc:': ['jsxc'],
':owncloud:': ['owncloud'],
':nextcloud:': ['nextcloud']
},
'emojione': emojione.emojioneList
}
export default class Emoticons {
private static initialised = false;
private static shortRegex = new RegExp(emojione.regShortNames.source + '|(' + Object.keys(EMOTICON_LIST.core).join('|') + ')', 'gi');
public static getDefaultEmoticonList() {
let list = [];
EMOTICONS.forEach(emoticon => {
list.push(emoticon[0].split(' ')[0]);
});
return list;
}
public static toImage(text:string):string {
Emoticons.init();
text = Emoticons.standardToImage(text);
text = Emoticons.shortnameToImage(text);
return text;
}
private static init() {
if (Emoticons.initialised) {
return;
}
$.each(EMOTICONS, function(i, val) {
// escape characters
var reg = val[0].replace(/(\/|\||\*|\.|\+|\?|\^|\$|\(|\)|\[|\]|\{|\})/g, '\\$1');
reg = '(' + reg.split(' ').join('|') + ')';
EMOTICONS[i][2] = new RegExp(reg, 'g');
});
Emoticons.initialised = true;
}
private static standardToImage(text:string):string {
// replace emoticons from XEP-0038 and pidgin with shortnames
$.each(EMOTICONS, function(i, val) {
text = text.replace(val[2], ':' + val[1] + ':');
});
return text;
}
private static shortnameToImage(text:string):string {
text = text.replace(this.shortRegex, Emoticons.replaceShortnameWithImage);
var wrapper = $('<div>' + text + '</div>');
if (wrapper.find('.jsxc_emoticon').length === 1 && wrapper.text().replace(/ /, '').length === 0 && wrapper.find('*').length === 1) {
wrapper.find('.jsxc_emoticon').addClass('jsxc_large');
text = wrapper.html();
}
return text;
}
private static replaceShortnameWithImage = (shortname) => {
if (typeof shortname === 'undefined' || shortname === '' || (!(shortname in EMOTICON_LIST.emojione) && !(shortname in EMOTICON_LIST.core))) {
return shortname;
}
var src, filename;
if (EMOTICON_LIST.core[shortname]) {
filename = EMOTICON_LIST.core[shortname][EMOTICON_LIST.core[shortname].length - 1].replace(/^:([^:]+):$/, '$1');
src = Options.get('root') + '/img/emotions/' + filename + '.svg';
} else if (EMOTICON_LIST.emojione[shortname]) {
filename = EMOTICON_LIST.emojione[shortname].fname;
src = Options.get('root') + '/lib/emojione/assets/svg/' + filename + '.svg';
}
var div = $('<div>');
div.addClass('jsxc-emoticon');
div.css('background-image', 'url(' + src + ')');
div.attr('title', shortname);
return div.prop('outerHTML');
}
}
-6
Ver Arquivo
@@ -1,6 +0,0 @@
interface Identifiable {
getId():string
}
export default Identifiable;
-65
Ver Arquivo
@@ -1,65 +0,0 @@
import {JIDInterface} from './JIDInterface'
export default class JID implements JIDInterface {
public readonly full:string;
public readonly bare:string;
public readonly node:string;
public readonly domain:string;
public readonly resource:string;
constructor(full:string) {
let matches = /([^@]+)@([^/]+)(?:\/(.+))?/.exec(full);
this.node = this.unescapeNode(matches[1].toLowerCase());
this.domain = matches[2].toLowerCase();
this.resource = matches[3];
this.bare = this.node + '@' + this.domain;
this.full = this.bare + ((this.resource) ? '/' + this.resource : '');
}
public toString():string {
return this.full;
}
public toEscapedString():string {
let bare = this.escapeNode(this.node) + '@' + this.domain;
return bare + ((this.resource) ? '/' + this.resource : '');
}
public isBare():boolean {
return this.full === this.bare;
}
private escapeNode(node:string) {
return node.replace(/^\s+|\s+$/g, '')
.replace(/\\/g, "\\5c")
.replace(/ /g, "\\20")
.replace(/\"/g, "\\22")
.replace(/\&/g, "\\26")
.replace(/\'/g, "\\27")
.replace(/\//g, "\\2f")
.replace(/:/g, "\\3a")
.replace(/</g, "\\3c")
.replace(/>/g, "\\3e")
.replace(/@/g, "\\40");
}
private unescapeNode(node:string) {
return node.replace(/\\20/g, " ")
.replace(/\\22/g, '"')
.replace(/\\26/g, "&")
.replace(/\\27/g, "'")
.replace(/\\2f/g, "/")
.replace(/\\3a/g, ":")
.replace(/\\3c/g, "<")
.replace(/\\3e/g, ">")
.replace(/\\40/g, "@")
.replace(/\\5c/g, "\\");
}
}
-16
Ver Arquivo
@@ -1,16 +0,0 @@
export interface JIDInterface {
readonly full:string;
readonly bare:string;
readonly node:string;
readonly domain:string;
readonly resource:string;
toString():string;
isBare():boolean;
}
-244
Ver Arquivo
@@ -1,244 +0,0 @@
import Storage from './Storage';
import Log from './util/Log';
import Options from './Options';
import Attachment from './Attachment';
import StorageSingleton from './StorageSingleton';
import JID from './JID'
import * as CONST from './CONST'
import Emoticons from './Emoticons'
import Translation from './util/Translation'
import Identifiable from './IdentifiableInterface'
import Client from './Client'
import Utils from './util/Utils'
import {MessageInterface, DIRECTION, MSGTYPE} from './MessageInterface'
const MSGPOSTFIX = ':msg';
const ATREGEX = new RegExp('(xmpp:)?(' + CONST.REGEX.JID.source + ')(\\?[^\\s]+\\b)?', 'i');
interface MessagePayload {
peer:JID,
direction:DIRECTION,
plaintextMessage?:string,
htmlMessage?:string,
errorMessage?:string,
attachment?:Attachment,
received?:boolean,
encrypted?:boolean,
forwarded?:boolean,
stamp?:number,
type?:MSGTYPE,
}
export default class Message implements Identifiable, MessageInterface {
private uid:string;
private payload:MessagePayload = {
received: false,
encrypted: null,
forwarded: false,
stamp: new Date().getTime(),
type: MSGTYPE.CHAT
} as any;
static readonly DIRECTION = DIRECTION;
static readonly MSGTYPE = MSGTYPE;
private storage:Storage;
constructor(uid:string);
constructor(data:MessagePayload);
constructor() {
this.storage = Client.getStorage();
if (typeof arguments[0] === 'string' && arguments[0].length > 0 && arguments.length === 1) {
this.uid = arguments[0];
this.load(this.uid);
} else if (typeof arguments[0] === 'object' && arguments[0] !== null) { console.log('arg', arguments[0])
$.extend(this.payload, arguments[0]);
}
if (!this.uid) {
this.uid = new Date().getTime() + MSGPOSTFIX;
}
}
public getId() {
return this.uid;
}
public save() {
let attachment = this.getAttachment();
if (attachment) {
if (this.getDirection() === DIRECTION.OUT) {
// save storage
attachment.clearData();
}
let saved = attachment.save();
if (!saved && this.getDirection() === DIRECTION.IN) {
//@TODO inform user
}
}
let payloadCopy = $.extend({}, this.payload); //Object.assign
if (payloadCopy.attachment) {
payloadCopy.attachment = payloadCopy.attachment.getId();
}
this.storage.setItem('msg', this.uid, {
payload: payloadCopy
});
return this;
}
public delete() {
var data = this.storage.getItem('msg', this.uid);
if (data) {
this.storage.removeItem('msg', this.uid);
}
}
public getCssId() {
return this.uid.replace(/:/g, '-');
}
public getDOM() {
return $('#' + this.getCssId());
}
public getStamp() {
return this.payload.stamp;
}
public getDirection():DIRECTION {
return this.payload.direction;
}
public getDirectionString():string {
return DIRECTION[this.payload.direction].toLowerCase();
}
public getAttachment():Attachment {
return this.payload.attachment;
}
public getPeer():JID {
return this.payload.peer;
}
public getType():MSGTYPE {
return this.payload.type;
}
public getTypeString():string {
return MSGTYPE[this.payload.type].toLowerCase();
}
public getHtmlMessage():string {
return this.payload.htmlMessage;
}
public getPlaintextMessage():string {
return this.payload.plaintextMessage;
}
public received() {
this.payload.received = true;
this.save();
this.getDOM().addClass('jsxc_received');
}
public isReceived():boolean {
return this.payload.received;
}
public isForwarded():boolean {
return this.payload.forwarded;
}
public isEncrypted():boolean {
return this.payload.encrypted;
}
public hasAttachment():boolean {
return !!this.payload.attachment;
}
public setUnread() {
}
public getProcessedBody():string {
let body = this.payload.plaintextMessage;
body = this.convertUrlToLink(body);
body = this.convertEmailToLink(body);
body = Emoticons.toImage(body);
body = this.replaceLineBreaks(body);
// hide unprocessed otr messages
if (body.match(/^\?OTR([:,|?]|[?v0-9x]+)/)) {
body = '<i title="' + body + '">' + Translation.t('Unreadable_OTR_message') + '</i>';
}
return body;
}
public getErrorMessage():string {
return this.payload.errorMessage;
}
private load(uid:string):void {
var data = this.storage.getItem('msg', uid);
window._storage = this.storage;
if (!data) {
Log.debug('Could not load message with uid ' + uid);
throw new Error('Could not load message with uid ' + uid)
}
$.extend(this.payload, data.payload);
if (data.attachment) {
this.payload.attachment = new Attachment(data.attachment);
}
}
private replaceLineBreaks(text) {
return text.replace(/(\r\n|\r|\n)/g, '<br />');
}
private convertUrlToLink(text) {
return text.replace(CONST.REGEX.URL, function(url) {
let href = (url.match(/^https?:\/\//i)) ? url : 'http://' + url;
return '<a href="' + href + '" target="_blank">' + url + '</a>';
});
}
private convertEmailToLink(text) {
return text.replace(ATREGEX, function(undefined, protocol, jid, action) {
if (protocol === 'xmpp:') {
if (typeof action === 'string') {
jid += action;
}
return '<a href="xmpp:' + jid + '">xmpp:' + jid + '</a>';
}
return '<a href="mailto:' + jid + '" target="_blank">mailto:' + jid + '</a>';
});
}
}
-55
Ver Arquivo
@@ -1,55 +0,0 @@
import {JIDInterface} from './JIDInterface'
export enum DIRECTION {
IN, OUT, SYS
};
export enum MSGTYPE {
CHAT, GROUPCHAT
};
export interface MessageInterface {
getId();
save();
delete();
getCssId();
getDOM();
getStamp();
getDirection():DIRECTION;
getDirectionString():string;
getAttachment():Attachment;
getPeer():JIDInterface;
getType():MSGTYPE;
getTypeString():string;
getHtmlMessage():string;
getPlaintextMessage():string;
received();
isReceived():boolean;
isForwarded():boolean;
isEncrypted():boolean;
hasAttachment():boolean;
setUnread();
getProcessedBody():string;
getErrorMessage():string;
}
-52
Ver Arquivo
@@ -1,52 +0,0 @@
import Storable from './StorableAbstract';
import Identifiable from './IdentifiableInterface'
import Storage from './Storage'
const SEP = ':';
export default class ModelManager <Element extends Storable> {
private id:string;
private elementIds;
constructor(private owner:Identifiable, private ElementClass:any, private storage:Storage) { //@REVIEW any -> Element?
this.id = owner.getId() + SEP + ElementClass.constructor.name;
this.elementIds = this.storage.getItem(this.id);
}
public get(id:string):Element {
let data = this.storage.getItem(this.id + SEP + id);
return new this.ElementClass(data);
}
public getAll():Element[] {
let elements:Element[] = [];
for(let elementId in this.elementIds) {
elements.push(this.get(elementId));
}
return elements;
}
public add(element:Element) {
this.elementIds.push(element.getId());
this.save();
}
public remove(element:Element) {
this.elementIds = $.grep(this.elementIds, function(e) {
return e !== element.getId();
})
this.save();
}
private save() {
this.storage.setItem(this.id, this.elementIds);
}
}
-68
Ver Arquivo
@@ -1,68 +0,0 @@
import IdentifiableInterface from './IdentifiableInterface'
import Storage from './Storage'
import ContactDialog from './ui/dialogs/contact'
export const enum TYPE {
normal, announcement, contact
}
export const enum FUNCTION {
contactRequest
}
let functions = {};
functions[FUNCTION.contactRequest] = ContactDialog;
export interface NoticeData {
title:string;
description:string;
fnName: FUNCTION;
fnParams?:Array<string>;
type?:TYPE;
}
export class Notice implements IdentifiableInterface {
private storage:Storage;
private data:NoticeData;
constructor(storage:Storage, data:NoticeData);
constructor(storage:Storage, id:string);
constructor() {
this.storage = arguments[0];
if (arguments.length === 2 && typeof arguments[1] === 'string') {
this.data = this.storage.getItem(arguments[1]);
} else {
this.data = arguments[1];
this.data.fnParams = this.data.fnParams || [];
this.data.type = this.data.type || TYPE.normal;
this.storage.setItem(this.getId(), this.data);
}
}
public getId():string {
return this.data.fnName + '|' + this.data.fnParams.toString();
}
public getTitle():string {
return this.data.title;
}
public getDescription():string {
return this.data.description;
}
public getFnParams():Array<string> {
return this.data.fnParams;
}
public getType():TYPE {
return this.data.type;
}
public callFunction() {
return functions[this.data.fnName].apply(this, this.data.fnParams);
}
}
-178
Ver Arquivo
@@ -1,178 +0,0 @@
import Options from './Options'
import Contact from './Contact'
import Translation from './util/Translation'
import Client from './Client'
import * as CONST from './CONST'
interface NotificationSettings {
title:string,
message:string,
duration?:number,
force?:boolean,
soundFile?:string,
loop?:boolean,
source?:string,
icon?:string
};
export default class Notification {
private static inited = false;
private static popupTimeout;
private static popupDelay = 1000;
private static audioObject;
public static init() {
if(Notification.inited) {
return;
}
$(document).on('postmessagein.jsxc', function(event, bid, msg) {
msg = (msg && msg.match(/^\?OTR/)) ? $.t('Encrypted_message') : msg;
var data = jsxc.storage.getUserItem('buddy', bid);
Notification.notify({
title: Translation.t('New_message_from'),
message: msg,
soundFile: CONST.SOUNDS.MSG,
source: bid
});
});
$(document).on('callincoming.jingle', function() {
Notification.playSound(CONST.SOUNDS.CALL, true, true);
});
$(document).on('accept.call.jsxc reject.call.jsxc', function() {
Notification.stopSound();
});
if (!Notice.has('gui.showRequestNotification')) {
Notice.add({
msg: Translation.t('Notifications') + '?',
description: Translation.t('Should_we_notify_you_')
}, 'gui.showRequestNotification');
}
}
public static muteSound(external?) {
$('#jsxc-menu .jsxc-muteNotification').text(Translation.t('Unmute'));
if (external !== true) {
Options.set('muteNotification', true);
}
}
public static unmuteSound(external?) {
$('#jsxc-menu .jsxc-muteNotification').text(Translation.t('Mute'));
if (external !== true) {
Options.set('muteNotification', false);
}
}
public static notify(settings:NotificationSettings) {
if (!Options.get('notification') || !Notification.hasPermission()) {
return; // notifications disabled
}
if (Client.hasFocus() && !settings.force) {
return; // Tab is visible
}
settings.icon = settings.icon || Options.get('root') + '/img/XMPP_logo.png';
if (typeof settings.source === 'string') {
let contact = new Contact(settings.source);
let avatar = contact.getAvatar();
if (typeof avatar === 'string' && avatar !== '0') {
settings.icon = avatar;
}
}
settings.duration = settings.duration || Options.get('notification').duration;
settings.title = Translation.t(settings.title);
settings.message = Translation.t(settings.message);
Notification.popupTimeout = setTimeout(function() {
Notification.showPopup(settings);
}, Notification.popupDelay);
}
private static showPopup(settings:NotificationSettings) {
if (typeof settings.soundFile === 'string') {
Notification.playSound(settings.soundFile, settings.loop, settings.force);
}
var popup = new window.Notification(settings.title, {
body: settings.message,
icon: settings.icon
});
if (settings.duration > 0) {
setTimeout(function() {
popup.close();
}, settings.duration);
}
}
private static hasSupport() {
return !!window.Notification;
}
private static requestPermission() {
window.Notification.requestPermission(function(status) {
if (window.Notification.permission !== status) {
window.Notification.permission = status;
}
if (Notification.hasPermission()) {
$(document).trigger('notificationready.jsxc');
} else {
$(document).trigger('notificationfailure.jsxc');
}
});
}
private static hasPermission() {
return window.Notification.permission === CONST.NOTIFICATION_GRANTED;
}
private static playSound(soundFile:string, loop?:boolean, force?:boolean) {
if (!jsxc.master) {
// only master plays sound
return;
}
if (Options.get('muteNotification') || jsxc.storage.getUserItem('presence') === 'dnd') {
// sound mute or own presence is dnd
return;
}
if (Client.hasFocus() && !force) {
// tab is visible
return;
}
// stop current audio file
Notification.stopSound();
var audio = new Audio(Options.get('root') + '/sound/' + soundFile);
audio.loop = loop || false;
audio.play();
Notification.audioObject = audio;
}
private static stopSound() {
var audio = Notification.audioObject;
if (typeof audio !== 'undefined' && audio !== null) {
audio.pause();
Notification.audioObject = null;
}
}
}
-92
Ver Arquivo
@@ -1,92 +0,0 @@
import Identifiable from './IdentifiableInterface'
import Storage from './Storage'
export default class PersistentMap {
private map = {};
private key:string;
private initialized = false;
constructor(private storage:Storage, ...identifier:string[]) {
this.key = storage.generateKey.apply(storage, identifier);
this.map = this.storage.getItem(this.key) || {};
this.storage.registerHook(this.key, (newValue) => {
this.map = newValue;
});
}
public get(id:string) {
return this.map[id];
}
public set(id:string, value:any);
public set(value:any);
public set() {
if (typeof arguments[0] === 'string'){
let id = arguments[0];
let value = arguments[1];
this.map[id] = value;
} else if(typeof arguments[0] === 'object' && arguments[0] !== null) {
$.extend(this.map, arguments[0]);
}
this.save();
}
public empty() {
this.map = {};
this.save();
}
public remove(id:Identifiable);
public remove(id:string);
public remove() {
let id;
if (typeof arguments[0] === 'string') {
id = arguments[0];
} else if(typeof arguments[0].getId === 'function') {
id = arguments[0].getId();
} else {
//@TODO error
return;
}
delete this.map[id];
this.save();
}
public registerHook(id:string, func: (newValue: any, oldValue: any, key: string) => void);
public registerHook(func: (newValue: any, oldValue: any, key: string) => void);
public registerHook() {
if (typeof arguments[0] === 'string' && typeof arguments[1] === 'function') {
let id = arguments[0];
let func = arguments[1];
this.storage.registerHook(this.key, function(newData, oldData) {
if (newData && !oldData) {
func(newData[id]);
} else if (newData[id] !== oldData[id]) {
func(newData[id], oldData[id]);
}
});
} else {
let func = arguments[0];
this.storage.registerHook(this.key, func);
}
}
private save() {
this.initialized = true;
this.storage.setItem(this.key, this.map);
}
}
-6
Ver Arquivo
@@ -1,6 +0,0 @@
import Connection from './connection/Connection'
export interface PluginInterface {
constructor:(Connection);
};
-145
Ver Arquivo
@@ -1,145 +0,0 @@
import Storage from './Storage'
import Client from './Client'
import Log from './util/Log'
export default class RoleAllocator {
private storage:Storage;
private master:boolean = null;
private keepAliveInterval;
private resolveTimeout;
private observationTimeout;
private resolves = [];
// private reject;
private slaveValue;
private masterValue;
private static instance;
private constructor() {
this.storage = Client.getStorage();
this.storage.registerHook('master', (value) => {
if (this.masterValue === value) {
return;
}
if (this.master === null) {
Log.debug('i am slave');
this.master = false;
clearTimeout(this.resolveTimeout);
$('body').addClass('jsxc-slave').removeClass('jsxc-master');
// if (typeof this.reject === 'function') {
// //this.reject();
// this.reject = null;
// }
}
if (this.master !== true) {
this.masterIsStillAlive();
} else {
Log.error('Something went wrong. We have another master.');
}
});
this.storage.registerHook('slave', (value) => {
if (this.slaveValue === value) {
return;
}
if (this.master === true) {
this.stillAlive();
}
});
}
public static get() {
if (!RoleAllocator.instance) {
RoleAllocator.instance = new RoleAllocator();
}
return RoleAllocator.instance;
}
public isMaster() {
return this.master;
}
public waitUntilMaster() {
return new Promise((resolve) => {
if (this.master === true || typeof this.storage.getItem('master') === 'undefined') {
resolve();
} else {
this.resolves.push(resolve);
if (this.master !== false){
this.queryMaster();
}
}
});
}
private queryMaster() {
Log.debug('query master');
let self = this;
this.resolveTimeout = setTimeout(() => {
this.master = true;
Log.debug('no one responded, i am master')
$('body').addClass('jsxc-master').removeClass('jsxc-slave');
this.startKeepAliveSignal();
this.resolveAll();
}, 1000);
this.storage.setItem('slave', this.slaveValue = Math.random());
}
private masterIsStillAlive() {
clearTimeout(this.observationTimeout);
let randomTime = (Math.random() * 1000) % 500;
this.observationTimeout = setTimeout(this.masterProbablyDied, 2000 + randomTime)
}
private masterProbablyDied = () => {
this.master = null;
this.queryMaster();
}
private startKeepAliveSignal() {
this.stillAlive();
this.keepAliveInterval = window.setInterval(this.stillAlive, 1000);
}
private stopKeepAliveSignal() {
window.clearInterval(this.keepAliveInterval);
}
private resolveAll() {
for(let resolveIndex in this.resolves) {
this.resolves[resolveIndex]();
delete this.resolves[resolveIndex];
}
}
private stillAlive = () => {
this.storage.setItem('master', this.masterValue = Math.random());
}
}
-153
Ver Arquivo
@@ -1,153 +0,0 @@
import Identifiable from './IdentifiableInterface'
import Storage from './Storage'
import Log from './util/Log'
export default class SortedPersistentMap {
private map = {};
private list;
private key: string;
private initialized = false;
private pushHook;
private removeHook;
constructor(private storage: Storage, ...identifier: string[]) {
this.key = storage.generateKey.apply(storage, identifier);
this.list = this.storage.getItem(this.key) || [];
this.storage.registerHook(this.key, this.onStorage);
}
public init() {
if (this.initialized) {
return;
}
if (typeof this.pushHook !== 'function') {
Log.error('push hook required');
return;
}
this.list.forEach(id => {
try {
this.map[id] = this.pushHook(id);
} catch(err) {
Log.error('Push hook threw the following error', err);
}
});
this.initialized = true;
}
public get(id: string) {
return this.map[id];
}
public push(element: Identifiable) {
let id = element.getId();
if (typeof this.map[id] !== 'undefined') {
//@TODO error reporting
return;
}
this.map[id] = element;
this.list.push(id);
this.save();
}
public empty(callback) {
this.list.forEach(id => {
callback(id, this.map[id]);
});
this.map = {};
this.list = [];
this.save();
}
public remove(id: Identifiable);
public remove(id: string);
public remove() {
let id;
if (typeof arguments[0] === 'string') {
id = arguments[0];
} else if (typeof arguments[0].getId === 'function') {
id = arguments[0].getId();
} else {
//@TODO error
return;
}
this.list = $.grep(this.list, function(i) {
return id !== i;
});
delete this.map[id];
this.save();
}
public registerHook(func: (newValue: any, oldValue: any, key: string) => void) {
this.storage.registerHook(this.key, func);
}
public setPushHook(func: (newValue: any, oldValue: any, key: string) => void) {
this.pushHook = func;
}
public setRemoveHook(func: (newValue: any, oldValue: any, key: string) => void) {
this.removeHook = func;
}
private onStorage = (newValue: any, oldValue: any, key: string) => {
oldValue = oldValue || [];
if (newValue.length === oldValue.length) {
return;
}
let pushDiff: string[] = newValue.filter(id => oldValue.indexOf(id) < 0);
for (let value of pushDiff) {
// call push hook
if (typeof this.pushHook === 'function') {
let result = this.pushHook(value);
if (typeof this.get(value) === 'undefined') {
this.map[value] = result;
}
}
}
let removeDiff: string[] = oldValue.filter(id => newValue.indexOf(id) < 0);
for (let value of removeDiff) {
// call remove hook
if (typeof this.removeHook === 'function') {
this.removeHook(value, this.map[value]);
}
delete this.map[value];
}
this.list = newValue;
}
private save() {
this.initialized = true;
this.storage.setItem(this.key, this.list);
}
}
-37
Ver Arquivo
@@ -1,37 +0,0 @@
import Log from './util/Log'
export default class StateMachine{
public static STATE = {
INITIATING: 0,
PREVCONFOUND: 1,
SUSPEND: 2,
TRYTOINTERCEPT: 3,
INTERCEPTED: 4,
ESTABLISHING: 5,
READY: 6
};
public static UISTATE = {
INITIATING: 0,
READY: 1
}
private static currentState;
private static currentUIState;
public static changeState(state:number) {
StateMachine.currentState = state;
Log.debug('State changed to ' + Object.keys(StateMachine.STATE)[state]);
$(document).trigger('stateChange.jsxc', state);
}
public static changeUIState(state:number) {
StateMachine.currentUIState = state;
Log.debug('UI State changed to ' + Object.keys(StateMachine.UISTATE)[state]);
$(document).trigger('stateUIChange.jsxc', state);
}
}
-15
Ver Arquivo
@@ -1,15 +0,0 @@
import Identifiable from './IdentifiableInterface'
abstract class Storable implements Identifiable {
constructor(data:any) {
$.extend(this, data);
}
public abstract getId():string;
public abstract save();
public abstract remove();
}
export default Storable;
-273
Ver Arquivo
@@ -1,273 +0,0 @@
import Log from './util/Log'
const PREFIX = 'jsxc2';
const SEP = ':';
const IGNORE_KEY = ['rid'];
const BACKEND = localStorage;
export default class Storage {
static storageNotConform: boolean = false;
static tested: boolean = false;
private hooks: any = {};
static toSNC: number;
constructor(private name: string = null) {
if (!Storage.tested) {
Storage.tested = true;
this.testStorage();
}
window.addEventListener('storage', this.onStorageEvent, false);
}
public generateKey(...args:string[]):string {
let key = '';
args.forEach(function(arg) {
if (key !== '') {
key += SEP;
}
key += arg;
})
return key;
}
private testStorage() {
let randomNumber = Math.round(Math.random() * 1000000000) + '';
let key = this.getPrefix() + randomNumber;
let timeout;
let listenerFunction = function(ev) {
if (ev.newValue === randomNumber) {
clearTimeout(timeout);
cleanup();
Storage.storageNotConform = true;
}
};
let cleanup = function() {
window.removeEventListener('storage', listenerFunction, false);
BACKEND.removeItem(key)
}
window.addEventListener('storage', listenerFunction, false);
timeout = setTimeout(function() {
cleanup();
}, 20);
BACKEND.setItem(key, randomNumber);
}
public getPrefix(): string {
let prefix = PREFIX + SEP;
if (this.name) {
prefix += this.name + SEP;
}
return prefix;
}
public getBackend() {
return BACKEND;
}
public setItem(type: string, key: string, value: any): void;
public setItem(key: string, value: any): void
public setItem(): void {
let key, value;
if (arguments.length === 2) {
key = arguments[0];
value = arguments[1];
} else if (arguments.length === 3) {
key = arguments[0] + SEP + arguments[1];
value = arguments[2];
}
//@REVIEW why do we just stringify objects?
if (typeof (value) === 'object') {
// exclude jquery objects, because otherwise safari will fail
try {
value = JSON.stringify(value, function(key, val) {
if (!(val instanceof jQuery)) {
return val;
}
});
} catch (err) {
console.warn('Could not stringify value', err);
}
}
let oldValue = BACKEND.getItem(this.getPrefix() + key);
BACKEND.setItem(this.getPrefix() + key, value);
if (!Storage.storageNotConform && oldValue !== value) {
this.onStorageEvent({
key: this.getPrefix() + key,
oldValue: oldValue,
newValue: value
});
}
}
public getItem(type: string, key: string): any;
public getItem(key: string): any;
public getItem(): any {
let key;
if (arguments.length === 1) {
key = arguments[0];
} else if (arguments.length === 2) {
key = arguments[0] + SEP + arguments[1];
}
key = this.getPrefix() + key;
var value = BACKEND.getItem(key);
return this.parseValue(value);
}
public removeItem(type, key): void;
public removeItem(key): void;
public removeItem(): void {
let key;
if (arguments.length === 1) {
key = arguments[0];
} else if (arguments.length === 2) {
key = arguments[0] + SEP + arguments[1];
}
BACKEND.removeItem(this.getPrefix() + key);
}
public updateItem(type, key, variable, value): void;
public updateItem(key, variable, value): void;
public updateItem(): void {
let key, variable, value;
if (arguments.length === 4 || (arguments.length === 3 && typeof variable === 'object')) {
key = arguments[0] + SEP + arguments[1];
variable = arguments[2];
value = arguments[3];
} else {
key = arguments[0];
variable = arguments[1];
value = arguments[2];
}
var data = this.getItem(key) || {};
if (typeof (variable) === 'object') {
$.each(variable, function(key, val) {
if (typeof (data[key]) === 'undefined') {
Log.debug('Variable ' + key + ' doesn\'t exist in ' + variable + '. It was created.');
}
data[key] = val;
});
} else {
if (typeof data[variable] === 'undefined') {
Log.debug('Variable ' + variable + ' doesn\'t exist. It was created.');
}
data[variable] = value;
}
this.setItem(key, data);
}
public increment(key: string): void {
let value = Number(this.getItem(key));
this.setItem(key, value + 1);
}
public removeElement(type, key, name): void;
public removeElement(key, name): void;
public removeElement(): void {
let key, name;
if (arguments.length === 2) {
key = arguments[0];
name = arguments[1];
} else if (arguments.length === 3) {
key = arguments[0] + SEP + arguments[1];
name = arguments[2];
}
var item = this.getItem(key);
if ($.isArray(item)) {
item = $.grep(item, function(e) {
return e !== name;
});
} else if (typeof (item) === 'object' && item !== null) {
delete item[name];
}
this.setItem(key, item);
}
public registerHook(eventName: string, func: (newValue: any, oldValue: any, key: string) => void) {
if (!this.hooks[eventName]) {
this.hooks[eventName] = [];
}
this.hooks[eventName].push(func);
}
public removeHook(eventName:string, func: (newValue: any, oldValue: any, key: string) => void) {
let eventNameList = this.hooks[eventName] || [];
if (eventNameList.indexOf(func) > -1) {
eventNameList = $.grep(eventNameList, function(i) {
return func !== i;
});
}
this.hooks[eventName] = eventNameList;
}
private onStorageEvent = (ev: any) => {
let hooks = this.hooks;
let key = ev.key.replace(new RegExp('^' + this.getPrefix()), '');
let oldValue = this.parseValue(ev.oldValue);
let newValue = this.parseValue(ev.newValue);
if (IGNORE_KEY.indexOf(key) > -1) {
return;
}
let eventNames = Object.keys(hooks);
eventNames.forEach(function(eventName) {
if (key.match(new RegExp('^' + eventName + '(:.+)?$'))) {
let eventNameHooks = hooks[eventName] || [];
eventNameHooks.forEach(function(hook) {
hook(newValue, oldValue, key);
});
}
});
}
private parseValue(value:string) {
try {
return JSON.parse(value);
} catch (e) {
return value;
}
}
}
-16
Ver Arquivo
@@ -1,16 +0,0 @@
import Storage from './Storage';
import User from './User';
export default class StorageSingleton {
private static globalStorage:Storage;
private static userStorage:Storage;
public static getGlobalStorage():Storage {
}
public static getUserStorage():Storage {
}
}
-241
Ver Arquivo
@@ -1,241 +0,0 @@
import Message from '../Message'
import JID from '../JID'
import * as NS from './xmpp/namespace'
import onRoster from './xmpp/handlers/roster'
import Log from '../util/Log'
enum Presence {
online,
chat,
away,
xa,
dnd,
offline
}
abstract class AbstractConnection {
protected abstract connection;
protected abstract send(stanzaElement:Element);
protected abstract send(stanzaElement:Strophe.Builder);
protected abstract sendIQ(stanzaElement:Element):Promise<{}>;
protected abstract sendIQ(stanzaElement:Strophe.Builder):Promise<{}>;
public getRoster() {
let iq = $iq({
type: 'get'
}).c('query', {
xmlns: 'jabber:iq:roster'
});
//@TODO use account.getStorage().getItem('roster', 'version'), maybe better as parameter
return this.sendIQ(iq).then(function() {
return onRoster.apply(this, arguments);
});
}
public sendMessage(message:Message) {
// @TODO pipes
if (message.getDirection() !== Message.DIRECTION.OUT) {
return;
}
let xmlMsg = $msg({
to: message.getPeer().full,
type: message.getTypeString(),
id: message.getId()
});
if (message.getHtmlMessage()) {
xmlMsg.c('html', {
xmlns: Strophe.NS.XHTML_IM
}).c('body', {
xmlns: Strophe.NS.XHTML
}).h(message.getHtmlMessage()).up();
}
if (message.getPlaintextMessage()) {
xmlMsg.c('body').t(message.getPlaintextMessage()).up();
}
// @TODO call pre send hook
this.send(xmlMsg);
}
public sendPresence(presence:Presence = Presence.online) {
if (this.connection.disco) {
this.connection.disco.addIdentity('client', 'web', 'JSXC');
this.connection.disco.addFeature(NS.get('DISCO_INFO'));
this.connection.disco.addFeature(NS.get('RECEIPTS'));
}
var presenceStanza = $pres();
if (this.connection.caps) {
presenceStanza.c('c', this.connection.caps.generateCapsAttrs()).up();
}
if (presence !== Presence.online) {
presenceStanza.c('show').t(Presence[presence]).up();
}
// var priority = Options.get('priority');
// if (priority && typeof priority[status] !== 'undefined' && parseInt(priority[status]) !== 0) {
// presenceStanza.c('priority').t(priority[status]).up();
// }
Log.debug('Send presence', presenceStanza.toString());
this.send(presenceStanza);
}
public removeContact(jid:JID) {
let self = this;
// Shortcut to remove buddy from roster and cancle all subscriptions
let iq = $iq({
type: 'set'
}).c('query', {
xmlns: NS.get('roster')
}).c('item', {
jid: jid.bare,
subscription: 'remove'
});
// @TODO
// jsxc.gui.roster.purge(bid);
return this.sendIQ(iq);
}
public addContact(jid:JID, alias:string) {
let waitForRoster = this.addContactToRoster(jid, alias);
this.sendSubscriptionRequest(jid);
return waitForRoster;
};
public loadVcard(jid:JID) {
let iq = $iq({
type: 'get',
to: jid.full
}).c('vCard', {
xmlns: NS.get('VCARD')
});
//@TODO register Namespace 'VCARD', 'vcard-temp'
return this.sendIQ(iq).then(this.parseVcard);
}
public getAvatar(jid:JID) {
return this.loadVcard(jid).then(function(vcard){
return new Promise(function(resolve, reject){
if (vcard.PHOTO && vcard.PHOTO.src) {
resolve(vcard.PHOTO);
} else {
reject();
}
});
});
}
public setDisplayName(jid:JID, displayName:string) {
var iq = $iq({
type: 'set'
}).c('query', {
xmlns: 'jabber:iq:roster'
}).c('item', {
jid: jid.bare,
name: displayName
});
this.sendIQ(iq);
}
public sendSubscriptionAnswer(to:JID, accept:boolean) {
let presenceStanza = $pres({
to: to.bare,
type: (accept) ? 'subscribed' : 'unsubscribed'
});
this.send(presenceStanza);
}
private addContactToRoster(jid:JID, alias:string) {
var iq = $iq({
type: 'set'
}).c('query', {
xmlns: 'jabber:iq:roster'
}).c('item', {
jid: jid.full,
name: alias || ''
});
return this.sendIQ(iq);
}
private sendSubscriptionRequest(jid:JID) {
// send subscription request to buddy (trigger onRosterChanged)
this.send($pres({
to: jid.full,
type: 'subscribe'
}));
}
private parseVcard = (stanza) => {
let data:any = {};
let vcard = $(stanza).find('vCard');
if (!vcard.length) {
return data;
}
return this.parseVcardChildren(vcard);
}
private parseVcardChildren(stanza) {
let data:any = {};
let children = stanza.children();
children.each(function(){
let item = $(this);
let children = item.children();
let itemName = item[0].tagName;
let value = null;
if (itemName === 'PHOTO') {
let img = item.find('BINVAL').text();
let type = item.find('TYPE').text();
let src = 'data:' + type + ';base64,' + img;
if (item.find('EXTVAL').length > 0) {
src = item.find('EXTVAL').text();
}
// concat chunks
src = src.replace(/[\t\r\n\f]/gi, '');
value = {
type: type,
src: src
};
} else if (children.length > 0) {
value = this.parseVcardChildren(children);
} else {
value = item.text();
}
data[itemName] = value;
});
return data;
}
}
export {AbstractConnection, Presence};
-27
Ver Arquivo
@@ -1,27 +0,0 @@
import JID from './../JID';
import Message from './../Message';
export interface IConnection {
loadVcard(jid:JID):any;
getCapabilitiesByJid(jid:JID):any;
addContact(jid:JID, alias:string);
removeContact(jid:JID);
sendMessage(message:Message);
sendPresence();
getAvatar(jid:JID);
setDisplayName(jid:JID, displayName:string);
hasFeatureByJid(jid:JID, feature:string);
hasFeatureByJid(jid:JID, feature:string[]);
getRoster();
logout();
}
-107
Ver Arquivo
@@ -1,107 +0,0 @@
import JID from '../../JID';
import Message from '../../Message';
import {IConnection} from '../ConnectionInterface';
import Log from '../../util/Log'
import Account from '../../Account'
import {AbstractConnection, Presence} from '../AbstractConnection'
import * as StropheLib from 'strophe.js'
let Strophe = StropheLib.Strophe;
export default class StorageConnection extends AbstractConnection implements IConnection {
protected connection:any = {};
constructor(private account: Account) {
super();
window.storageConnection = this;
this.connection = {
jid: account.getJID().full,
send: this.send,
sendIQ: (elem, success, error) => {
this.sendIQ(elem).then(success).catch(error);
},
addHandler: () => {}
}
for (var k in (<any>Strophe)._connectionPlugins) {
if ((<any>Strophe)._connectionPlugins.hasOwnProperty(k)) {
var ptype = (<any>Strophe)._connectionPlugins[k];
// jslint complaints about the below line, but this is fine
var F = function() { }; // jshint ignore:line
F.prototype = ptype;
this.connection[k] = new F();
this.connection[k].init(this.connection);
}
}
}
public getCapabilitiesByJid(jid: JID): any {
Log.info('[SC] getCapabilitiesByJid');
};
public hasFeatureByJid(jid: JID, feature: string);
public hasFeatureByJid(jid: JID, feature: string[]);
public hasFeatureByJid() {
Log.info('[SC] has feature by jid');
}
public logout() {
Log.info('[SC] logout');
}
protected send(stanzaElement: Element);
protected send(stanzaElement: Strophe.Builder);
protected send() {
let storage = this.account.getStorage();
let stanzaString = this.stanzaElementToString(arguments[0]);
let key = storage.generateKey(
'stanza',
stanzaString.length + '',
new Date().getTime() + ''
);
storage.setItem(key, stanzaString);
}
protected sendIQ(stanzaElement:Element):Promise<{}>;
protected sendIQ(stanzaElement:Strophe.Builder):Promise<{}>;
protected sendIQ():Promise<{}> {
let storage = this.account.getStorage();
let stanzaString = this.stanzaElementToString(arguments[0]);
let key = storage.generateKey(
'stanzaIQ',
stanzaString.length + '',
new Date().getTime() + ''
);
storage.setItem(key, stanzaString);
return new Promise(function(resolve, reject) {
storage.registerHook(key, function(newValue) { console.log('got an answer', newValue)
storage.removeItem(key);
if (newValue.type === 'success') {
resolve(newValue.stanza);
} else if (newValue.type === 'error') {
reject(newValue.stanza);
}
});
});
}
private stanzaElementToString(stanzaElement: Element):string;
private stanzaElementToString(stanzaElement: Strophe.Builder):string;
private stanzaElementToString() {
let stanzaString: string;
let stanzaElement = arguments[0] || {};
if (typeof stanzaElement.innerHTML === 'string') {
stanzaString = stanzaElement.innerHTML;
} else {
stanzaString = stanzaElement.toString();
}
return stanzaString;
}
}
-124
Ver Arquivo
@@ -1,124 +0,0 @@
import JID from '../../JID';
import Message from '../../Message';
import Options from '../../Options'
import * as CONST from '../../CONST';
import {IConnection} from '../ConnectionInterface';
import {Strophe} from 'strophe';
import * as NS from './namespace'
import XMPPHandler from './handler'
import Log from '../../util/Log'
import Account from '../../Account'
import {AbstractConnection, Presence} from '../AbstractConnection'
import Roster from '../../ui/Roster'
export default class XMPPConnection extends AbstractConnection implements IConnection {
private handler;
constructor(private account:Account, private connection:Strophe.Connection) {
super();
window._conn = connection;
this.handler = new XMPPHandler(connection);
this.handler.registerHandler();
this.account.getStorage().registerHook('stanza', (newValue, oldValue, key) => {
if (newValue && !oldValue) {
this.onIncomingStorageStanza(newValue);
this.account.getStorage().removeItem(key);
}
});
this.account.getStorage().registerHook('stanzaIQ', (newValue, oldValue, key) => {
if (newValue && !oldValue) {
this.onIncomingStorageStanzaIQ(key, newValue);
}
});
Roster.get().registerHook('presence', (presence) => {
if (presence === Presence.offline) {
this.connection.disconnect('');
}
});
}
public getCapabilitiesByJid(jid:JID):any {
};
public renameContact(jid:JID, name:string) {
//@TODO maybe replace jid with contact?
if (d.type === 'chat') {
var iq = $iq({
type: 'set'
}).c('query', {
xmlns: NS.get('roster')
}).c('item', {
jid: jid.bare,
name: name
});
this.connection.sendIQ(iq);
} else if (d.type === 'groupchat') {
jsxc.xmpp.bookmarks.add(bid, newname, d.nickname, d.autojoin);
}
}
public hasFeatureByJid(jid:JID, feature:string);
public hasFeatureByJid(jid:JID, feature:string[]);
public hasFeatureByJid() {
}
public logout() {
}
protected send(stanzaElement:Element);
protected send(stanzaElement:Strophe.Builder);
protected send() {
this.connection.send(arguments[0]);
}
protected sendIQ(stanzaElement:Element):Promise<{}>;
protected sendIQ(stanzaElement:Strophe.Builder):Promise<{}>;
protected sendIQ():Promise<{}> {
let stanzaElement = arguments[0];
return new Promise((resolve, reject) => {
this.connection.sendIQ(stanzaElement, resolve, reject);
});
}
private onIncomingStorageStanza(stanzaString:string) {
let stanzaElement = new DOMParser().parseFromString(stanzaString, 'text/xml').documentElement
if ($(stanzaElement).find('parsererror').length > 0) {
Log.error('Could not parse stanza string from storage.');
return;
}
this.send(stanzaElement);
}
private onIncomingStorageStanzaIQ(key:string, stanzaString:string) {
let stanzaElement = new DOMParser().parseFromString(stanzaString, 'text/xml').documentElement
if ($(stanzaElement).find('parsererror').length > 0) {
Log.error('Could not parse stanza string from storage.');
return;
}
this.sendIQ(stanzaElement).then((stanza) => {
this.account.getStorage().setItem(key, {
type: 'success',
stanza: stanza.outerHTML
});
}).catch((stanza) => {
this.account.getStorage().setItem(key, {
type: 'error',
stanza: stanza.outerHTML
});
});
}
}

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais