From bc041ec73b2683811e3a6c292e5f40ccbea9b46d Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Tue, 26 May 2015 11:28:35 -0400 Subject: [PATCH 01/29] Updated grunt-contrib-uglify version to deal with build problems --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a7a986..e454895 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "grunt-contrib-jshint": "~0.1.0", "grunt-contrib-jst": "~0.5.0", "grunt-contrib-less": "~0.5.0", - "grunt-contrib-uglify": "~0.1.0", + "grunt-contrib-uglify": "~0.9.0", "grunt-contrib-watch": "~0.1.4" }, "scripts": { From cbd8f88ed2e1749ef0bbfc8453ef23cc4aacb2df Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Tue, 26 May 2015 12:27:15 -0400 Subject: [PATCH 02/29] Fixed firechat development for images --- Gruntfile.js | 172 ++++++++++++++++++++++++--------------------- package.json | 1 + website/index.html | 4 +- 3 files changed, 95 insertions(+), 82 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 5df1853..bb291cd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,96 +1,108 @@ module.exports = function(grunt) { - "use strict"; + "use strict"; - // Initializes the Grunt tasks with the following settings - grunt.initConfig({ + // Initializes the Grunt tasks with the following settings + grunt.initConfig({ - // A list of files which will be syntax-checked by JSHint. - jshint: { - files: ['src/js/shims.js', 'src/js/firechat.js', 'src/js/firechat-ui.js'], - options: { - regexdash: false - } - }, + // A list of files which will be syntax-checked by JSHint. + jshint: { + files: ['src/js/shims.js', 'src/js/firechat.js', 'src/js/firechat-ui.js'], + options: { + regexdash: false + } + }, - // Precompile templates and strip whitespace with 'processContent'. - jst: { - compile: { - options: { - path: 'templates', - namespace: 'FirechatDefaultTemplates', - prettify: true, - processContent: function(src) { - return src.replace(/(^\s+|\s+$)/gm, ''); - } + // Precompile templates and strip whitespace with 'processContent'. + jst: { + compile: { + options: { + path: 'templates', + namespace: 'FirechatDefaultTemplates', + prettify: true, + processContent: function(src) { + return src.replace(/(^\s+|\s+$)/gm, ''); + } + }, + files: { + 'compiled/templates.js': ['templates/*.html'] + } + } }, - files: { - 'compiled/templates.js': ['templates/*.html'] - } - } - }, - // Compile and minify LESS CSS for production. - less: { - development: { - files: { - "dist/firechat.css": "src/less/styles.less" - } - }, - production: { - options: { - yuicompress: true + // Compile and minify LESS CSS for production. + less: { + development: { + files: { + "dist/firechat.css": "src/less/styles.less" + } + }, + production: { + options: { + yuicompress: true + }, + files: { + "dist/firechat.min.css": "src/less/styles.less" + } + } }, - files: { - "dist/firechat.min.css": "src/less/styles.less" - } - } - }, - // Concatenate files in a specific order. - concat: { - js: { - src: [ - 'src/js/libs/underscore-1.7.0.min.js', - 'compiled/templates.js', - 'src/js/shims.js', - 'src/js/firechat.js', - 'src/js/firechat-ui.js' - ], - dest: 'dist/firechat.js' - } - }, + // Concatenate files in a specific order. + concat: { + js: { + src: [ + 'src/js/libs/underscore-1.7.0.min.js', + 'compiled/templates.js', + 'src/js/shims.js', + 'src/js/firechat.js', + 'src/js/firechat-ui.js' + ], + dest: 'dist/firechat.js' + } + }, - // Minify concatenated files. - uglify: { - dist: { - src: ['<%= concat.js.dest %>'], - dest: 'dist/firechat.min.js' - } - }, + // Minify concatenated files. + uglify: { + dist: { + src: ['<%= concat.js.dest %>'], + dest: 'dist/firechat.min.js' + } + }, - // Clean up temporary files. - clean: ['compiled/'], + // Clean up temporary files. + clean: ['compiled/'], - // Tasks to execute upon file change when using `grunt watch`. - watch: { - src: { - files: ['src/**/*.*', 'templates/**/*.*'], - tasks: ['default'] - } - } - }); + // Tasks to execute upon file change when using `grunt watch`. + watch: { + src: { + files: ['src/**/*.*', 'templates/**/*.*'], + tasks: ['default'] + } + }, + copy: { + default: { + files: [{ + src: 'dist/firechat.js', + dest: 'website/firechat-latest.js' + }, { + src: 'dist/firechat.css', + dest: 'website/firechat-latest.css' + }] + } + } + }); - // Load specific plugins, which have been installed and specified in package.json. - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-jst'); - grunt.loadNpmTasks('grunt-contrib-less'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-watch'); + // Load specific plugins, which have been installed and specified in package.json. + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-jst'); + grunt.loadNpmTasks('grunt-contrib-less'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-copy'); - // Default task operations if simply calling `grunt` without options. - grunt.registerTask('default', ['jshint', 'jst', 'less', 'concat', 'uglify', 'clean']); + // Default task operations if simply calling `grunt` without options. + grunt.registerTask('default', ['jshint', 'jst', 'less', 'concat', 'uglify', 'clean', 'copy']); }; diff --git a/package.json b/package.json index e454895..57db16f 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "grunt-cli": "^0.1.13", "grunt-contrib-clean": "~0.4.1", "grunt-contrib-concat": "~0.1.1", + "grunt-contrib-copy": "^0.8.0", "grunt-contrib-jshint": "~0.1.0", "grunt-contrib-jst": "~0.5.0", "grunt-contrib-less": "~0.5.0", diff --git a/website/index.html b/website/index.html index 76c63c7..715302c 100644 --- a/website/index.html +++ b/website/index.html @@ -178,8 +178,8 @@

Authenticate to continue

- - + + + + + + From 894e2dd8785a522ccd059cca347c4ba42dcc0217 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 1 Jun 2015 09:42:12 -0400 Subject: [PATCH 04/29] Switched Chrome out for PhantomTest --- assets/img/file_upload.png | Bin 0 -> 1693 bytes karma.conf.js | 65 +++++++++++++++++++++++++++++++++++++ package.json | 7 +++- website/index.html | 1 + 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 assets/img/file_upload.png create mode 100644 karma.conf.js diff --git a/assets/img/file_upload.png b/assets/img/file_upload.png new file mode 100644 index 0000000000000000000000000000000000000000..8931bfdd864970f9a85c599f012ffbe57898de0f GIT binary patch literal 1693 zcmV;O24eY%P)qefHUF?{#Xx$G}vC64_D%>an8`;xQ<8 z076_u0EHt0D4e#6&;JHK4H<~wovA>3voGpR?6Yuj34z#1lXES%fWi?06pjd>a6|xw zBLXNK5kTRH018J0P&guh!Vv)!PE{^I2+v4h4saT9IIt7=23QNM!{fRQ$pyrv19%MB zM)Pw~2fhF` z2iDX2?|Q_-SGEGEVK#A+%Yd*QbyfdG^>5h# zoNwu;sQ{`9M63r+v2^H)3xQV+{%^S`!-D>T^vJ3QxDhzQVS6LV=dmz2sr3NEfuAelvaww91ir|o z2Uv)o?z#p%O&)oIprq6Ti~|0wh{=`p2KzN>kwp)%7?s!e$>aFT6LbJ8fUnSBvloq2 zdVnreeL|mCf5UtX2u}yL?Bio6aFPc8X&&s+^ZK1fmkr&jn6X|3c5hGT!5 z`jxo*7LpWzZddBdR`wI)3{S7k`lnI3cs=KE?^O`-Ls!(?GK?g$q1kZd{p7L zBsguS$(ZUxaYh9LzoA2=qUzg(CO+!8Z@5KjT^z)uyv#8k%6_r($QDPRFGHju9z zIRrHw9Xw+gLI5LxI|KO1opXV!Lpu#2fZI^3eT4(_BT=pH-+i0wYWXa5I4yFA9|$kL9gccR@%e@LR?IiN sCrBN;cP+3BGl?tAsq&z zZUx#ILtO!k0dCcGA_QS7221dD1#mrT04Su%Qq*3ImeK7p-b58PNTmR>@PB?sRb1CX zcMvG#NisEpgoF?Q6pjd>a6|xwBLXO#8frAym+ioYz_AE^nL?9oW>o?Z3PElGg(Cte n91%d_v;mue39$naqOkct869|gnCKi500000NkvXXu0mjf#uw-; literal 0 HcmV?d00001 diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..e6c0bfe --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,65 @@ +// Karma configuration +// Generated on Mon Jun 01 2015 09:06:11 GMT-0400 (EDT) + +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: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [ + 'src/js/*.js, spec/**/*spec.js' + ], + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // 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_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + + // 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 + }); +}; diff --git a/package.json b/package.json index 73687af..9d0e610 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,12 @@ "grunt-contrib-jst": "~0.5.0", "grunt-contrib-less": "~0.5.0", "grunt-contrib-uglify": "~0.9.0", - "grunt-contrib-watch": "~0.1.4" + "grunt-contrib-watch": "~0.1.4", + "jasmine-core": "^2.3.4", + "karma": "^0.12.35", + "karma-jasmine": "^0.3.5", + "karma-phantomjs-launcher": "^0.2.0", + "phantomjs": "^1.9.17" }, "scripts": { "test": "gulp test", diff --git a/website/index.html b/website/index.html index 4d6edc8..6536b56 100644 --- a/website/index.html +++ b/website/index.html @@ -14,6 +14,7 @@ + From dae31cf391ac4338d8186bb9994188d8fbb926a0 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 1 Jun 2015 09:46:32 -0400 Subject: [PATCH 05/29] Added Travis file --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2793c72 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: node_js +node_js: + - "0.12" +script: node_modules/karma/bin/karma start karma.conf.js --single-run +before_install: + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start +before_script: + - npm install \ No newline at end of file From ddfdfd8e8eb67a7e609699177a6bc42b847fb748 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 1 Jun 2015 09:50:05 -0400 Subject: [PATCH 06/29] initial test --- spec/index-spec.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 spec/index-spec.js diff --git a/spec/index-spec.js b/spec/index-spec.js new file mode 100644 index 0000000..44f59e4 --- /dev/null +++ b/spec/index-spec.js @@ -0,0 +1,7 @@ +describe('getDivAttribute', function() { + var d = document.querySelector('title'); + + it('Should show the title of the index page', function() { + expect(d.innerHTML().toBe('Firechat - open source chat built on Firebase'); + }); +}); \ No newline at end of file From d684a24a76652d3d9ce766fecdba4d4ec6c070b6 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 1 Jun 2015 09:57:08 -0400 Subject: [PATCH 07/29] Removed Chrome --- karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/karma.conf.js b/karma.conf.js index e6c0bfe..30ed37d 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -55,7 +55,7 @@ module.exports = function(config) { // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['Chrome'], + browsers: [], // Continuous Integration mode From 0a74603324205d3c2cd6a11b2ca57247f43987ee Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 1 Jun 2015 09:58:34 -0400 Subject: [PATCH 08/29] Removed Travis instructions --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2793c72..b33a486 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,5 @@ language: node_js node_js: - "0.12" script: node_modules/karma/bin/karma start karma.conf.js --single-run -before_install: - - export DISPLAY=:99.0 - - sh -e /etc/init.d/xvfb start before_script: - npm install \ No newline at end of file From 61a0f242f215f55d430ad5e3a368696093e14084 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Wed, 3 Jun 2015 02:02:42 -0400 Subject: [PATCH 09/29] upload image positioned --- src/less/styles.less | 16 +++++++++++++++- templates/tab-content.html | 5 ++++- website/firechat-latest.css | 12 ++++++++++++ website/firechat-latest.js | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/less/styles.less b/src/less/styles.less index 829a647..8afdce1 100644 --- a/src/less/styles.less +++ b/src/less/styles.less @@ -377,7 +377,7 @@ position: absolute; z-index: 1001; background-color: #ffffff; - .box-shadow(0 5px 10px rgba(0, 0, 0, 0.45)); + .box-shadow(0 5px 10px rgba(0, 0, 0, 0.45)); } .prompt-header { padding: 4px 8px; @@ -596,6 +596,20 @@ overflow: auto; vertical-align: top; } + + #textarea-container { + position: relative; + width: 100%; + float: left; + height: 35px; + } + + #upload-icon { + top: 20px; + right: 5px; + position: absolute; + float: right; + } .message { color: #333; padding: 3px 5px; diff --git a/templates/tab-content.html b/templates/tab-content.html index 71f560b..585e204 100644 --- a/templates/tab-content.html +++ b/templates/tab-content.html @@ -51,6 +51,9 @@
- +
+ +
+
\ No newline at end of file diff --git a/website/firechat-latest.css b/website/firechat-latest.css index 68b0473..0ac9c94 100644 --- a/website/firechat-latest.css +++ b/website/firechat-latest.css @@ -818,6 +818,18 @@ overflow: auto; vertical-align: top; } +#firechat #textarea-container { + position: relative; + width: 100%; + float: left; + height: 35px; +} +#firechat #upload-icon { + top: 20px; + right: 5px; + position: absolute; + float: right; +} #firechat .message { color: #333; padding: 3px 5px; diff --git a/website/firechat-latest.js b/website/firechat-latest.js index 373040f..3e5e8da 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -34,7 +34,7 @@ this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = functio this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
  • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n+\n'; } ;__p += '\n\n
  • ';}return __p}; -this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
    \n
    \n\n\nIn Room\n\n\n
    \n
      \n
      \n
      \n\n+\nInvite\n\n
      \n
      \n
      \n\n\n
      \n
      \n
        \n
        \n
        \n
        \n
        \n\n\n
        \n
        ';}return __p}; +this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
        \n
        \n\n\nIn Room\n\n\n
        \n
          \n
          \n
          \n\n+\nInvite\n\n
          \n
          \n
          \n\n\n
          \n
          \n
            \n
            \n
            \n
            \n
            \n\n
            \n\n
            \n
            \n
            \n
            ';}return __p}; this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
          • \n' +__e( name ) +'\n
          • ';}return __p}; From 7a0327eff09305f5f4c89a5b1e95bb3a21cc4576 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Wed, 3 Jun 2015 09:02:54 -0400 Subject: [PATCH 10/29] WIP --- Gruntfile.js | 3 ++- src/less/styles.less | 17 ++++++++++-- templates/tab-content.html | 6 ++++- website/firechat-latest.css | 15 +++++++++-- website/firechat-latest.js | 53 ++++++++++++++++++++++++++++++++++++- 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index bb291cd..b3b59bb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -55,7 +55,8 @@ module.exports = function(grunt) { 'compiled/templates.js', 'src/js/shims.js', 'src/js/firechat.js', - 'src/js/firechat-ui.js' + 'src/js/firechat-ui.js', + 'src/js/firepano.js' ], dest: 'dist/firechat.js' } diff --git a/src/less/styles.less b/src/less/styles.less index 8afdce1..711b1ce 100644 --- a/src/less/styles.less +++ b/src/less/styles.less @@ -605,11 +605,24 @@ } #upload-icon { - top: 20px; - right: 5px; position: absolute; float: right; + height: 16px; + width: 18px; } + + #file-upload { + display: block; + position: relative; + overflow: hidden; + z-index: 2; + opacity: 0; + } + #upload-icon img { + top: 20px; + right: 5px; + } + .message { color: #333; padding: 3px 5px; diff --git a/templates/tab-content.html b/templates/tab-content.html index 585e204..1a7d8e1 100644 --- a/templates/tab-content.html +++ b/templates/tab-content.html @@ -53,7 +53,11 @@
            -
            + + + +
            + \ No newline at end of file diff --git a/website/firechat-latest.css b/website/firechat-latest.css index 0ac9c94..00e8247 100644 --- a/website/firechat-latest.css +++ b/website/firechat-latest.css @@ -825,10 +825,21 @@ height: 35px; } #firechat #upload-icon { - top: 20px; - right: 5px; position: absolute; float: right; + height: 16px; + width: 18px; +} +#firechat #file-upload { + display: block; + position: relative; + overflow: hidden; + z-index: 2; + opacity: 0; +} +#firechat #upload-icon img { + top: 20px; + right: 5px; } #firechat .message { color: #333; diff --git a/website/firechat-latest.js b/website/firechat-latest.js index 3e5e8da..5105759 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -34,7 +34,7 @@ this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = functio this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
          • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n+\n'; } ;__p += '\n\n
          • ';}return __p}; -this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
            \n
            \n\n\nIn Room\n\n\n
            \n
              \n
              \n
              \n\n+\nInvite\n\n
              \n
              \n
              \n\n\n
              \n
              \n
                \n
                \n
                \n
                \n
                \n\n
                \n\n
                \n
                \n
                \n
                ';}return __p}; +this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                \n
                \n\n\nIn Room\n\n\n
                \n
                  \n
                  \n
                  \n\n+\nInvite\n\n
                  \n
                  \n
                  \n\n\n
                  \n
                  \n
                    \n
                    \n
                    \n
                    \n
                    \n\n
                    \n\n\n\n\n\n
                    \n
                    ';}return __p}; this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                  • \n' +__e( name ) +'\n
                  • ';}return __p}; @@ -1870,3 +1870,54 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct }; })(jQuery); + +var spinner = new Spinner({color: '#ddd'}); +var firebaseRef = 'https://brilliant-fire-2797.firebaseio.com'; + +function handleFileSelect(evt) { + var f = evt.target.files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var filePayload = e.target.result; + // Generate a location that can't be guessed using the file's contents and a random number + var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); + var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); + spinner.spin(document.getElementById('spin')); + // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview + f.set(filePayload, function() { + spinner.stop(); + document.getElementById("pano").src = e.target.result; + $('#file-upload').hide(); + // Update the location bar so the URL can be shared with others + window.location.hash = hash; + }); + }; + })(f); + reader.readAsDataURL(f); +} + +$(function() { + $('#spin').append(spinner); + + var idx = window.location.href.indexOf('#'); + var hash = (idx > 0) ? window.location.href.slice(idx + 1) : ''; + if (hash === '') { + // No hash found, so render the file upload button. + $('#file-upload').show(); + document.getElementById("file-upload").addEventListener('change', handleFileSelect, false); + } else { + // A hash was passed in, so let's retrieve and render it. + spinner.spin(document.getElementById('spin')); + var f = new Firebase(firebaseRef + '/pano/' + hash + '/filePayload'); + f.once('value', function(snap) { + var payload = snap.val(); + if (payload != null) { + document.getElementById("pano").src = payload; + } else { + $('#body').append("Not found"); + } + spinner.stop(); + }); + } +}); \ No newline at end of file From 756c96de5e2025e9f0b0cee4ce4715453d825dff Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Thu, 4 Jun 2015 09:24:44 -0400 Subject: [PATCH 11/29] Changing firepano to fix upload problem --- Gruntfile.js | 3 +- src/less/styles.less | 6 +-- templates/tab-content.html | 2 +- website/firechat-latest.css | 6 +-- website/firechat-latest.js | 88 ++++++++++++++++++------------------- website/index.html | 1 + 6 files changed, 52 insertions(+), 54 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index b3b59bb..1a3a7d7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -56,7 +56,8 @@ module.exports = function(grunt) { 'src/js/shims.js', 'src/js/firechat.js', 'src/js/firechat-ui.js', - 'src/js/firepano.js' + 'src/js/firepano.js', + 'src/js/sha256.js' ], dest: 'dist/firechat.js' } diff --git a/src/less/styles.less b/src/less/styles.less index 711b1ce..15d8f23 100644 --- a/src/less/styles.less +++ b/src/less/styles.less @@ -609,6 +609,8 @@ float: right; height: 16px; width: 18px; + bottom: 25px; + right: 5px; } #file-upload { @@ -618,10 +620,6 @@ z-index: 2; opacity: 0; } - #upload-icon img { - top: 20px; - right: 5px; - } .message { color: #333; diff --git a/templates/tab-content.html b/templates/tab-content.html index 1a7d8e1..934f76e 100644 --- a/templates/tab-content.html +++ b/templates/tab-content.html @@ -55,7 +55,7 @@ - + diff --git a/website/firechat-latest.css b/website/firechat-latest.css index 00e8247..605cbc1 100644 --- a/website/firechat-latest.css +++ b/website/firechat-latest.css @@ -829,6 +829,8 @@ float: right; height: 16px; width: 18px; + bottom: 25px; + right: 5px; } #firechat #file-upload { display: block; @@ -837,10 +839,6 @@ z-index: 2; opacity: 0; } -#firechat #upload-icon img { - top: 20px; - right: 5px; -} #firechat .message { color: #333; padding: 3px 5px; diff --git a/website/firechat-latest.js b/website/firechat-latest.js index 5105759..8b59c45 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -34,7 +34,7 @@ this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = functio this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                  • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n+\n'; } ;__p += '\n\n
                  • ';}return __p}; -this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                    \n
                    \n\n\nIn Room\n\n\n
                    \n
                      \n
                      \n
                      \n\n+\nInvite\n\n
                      \n
                      \n
                      \n\n\n
                      \n
                      \n
                        \n
                        \n
                        \n
                        \n
                        \n\n
                        \n\n\n\n\n\n
                        \n
                        ';}return __p}; +this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                        \n
                        \n\n\nIn Room\n\n\n
                        \n
                          \n
                          \n
                          \n\n+\nInvite\n\n
                          \n
                          \n
                          \n\n\n
                          \n
                          \n
                            \n
                            \n
                            \n
                            \n
                            \n\n
                            \n\n\n\n\n\n
                            \n
                            ';}return __p}; this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                          • \n' +__e( name ) +'\n
                          • ';}return __p}; @@ -1871,53 +1871,53 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct })(jQuery); -var spinner = new Spinner({color: '#ddd'}); +var spinner = new Spinner({ + color: '#ddd' +}); var firebaseRef = 'https://brilliant-fire-2797.firebaseio.com'; function handleFileSelect(evt) { - var f = evt.target.files[0]; - var reader = new FileReader(); - reader.onload = (function(theFile) { - return function(e) { - var filePayload = e.target.result; - // Generate a location that can't be guessed using the file's contents and a random number - var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); - var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); - spinner.spin(document.getElementById('spin')); - // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview - f.set(filePayload, function() { - spinner.stop(); - document.getElementById("pano").src = e.target.result; - $('#file-upload').hide(); - // Update the location bar so the URL can be shared with others - window.location.hash = hash; - }); - }; - })(f); - reader.readAsDataURL(f); + var fileUploadInput = $(evt.target).prev(); + fileUploadInput.click(function(evt) { + var f = $(evt.target).get(0).files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var filePayload = e.target.result; + // Generate a location that can't be guessed using the file's contents and a random number + var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); + var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); + spinner.spin(document.getElementById('spin')); + // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview + f.set(filePayload, function() { + spinner.stop(); + console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created') + }); + }; + })(f); + reader.readAsDataURL(f); + }); } $(function() { - $('#spin').append(spinner); - - var idx = window.location.href.indexOf('#'); - var hash = (idx > 0) ? window.location.href.slice(idx + 1) : ''; - if (hash === '') { - // No hash found, so render the file upload button. - $('#file-upload').show(); - document.getElementById("file-upload").addEventListener('change', handleFileSelect, false); - } else { - // A hash was passed in, so let's retrieve and render it. - spinner.spin(document.getElementById('spin')); - var f = new Firebase(firebaseRef + '/pano/' + hash + '/filePayload'); - f.once('value', function(snap) { - var payload = snap.val(); - if (payload != null) { - document.getElementById("pano").src = payload; - } else { - $('#body').append("Not found"); - } - spinner.stop(); + $('#spin').append(spinner); + $('#upload-image').ready(function() { + $(this).get(0).addEventListener("click", handleFileSelect, false); }); - } -}); \ No newline at end of file +}); + +/* +CryptoJS v3.0.2 +code.google.com/p/crypto-js +(c) 2009-2012 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +var CryptoJS=CryptoJS||function(i,p){var f={},q=f.lib={},j=q.Base=function(){function a(){}return{extend:function(h){a.prototype=this;var d=new a;h&&d.mixIn(h);d.$super=this;return d},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var d in a)a.hasOwnProperty(d)&&(this[d]=a[d]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.$super.extend(this)}}}(),k=q.WordArray=j.extend({init:function(a,h){a= +this.words=a||[];this.sigBytes=h!=p?h:4*a.length},toString:function(a){return(a||m).stringify(this)},concat:function(a){var h=this.words,d=a.words,c=this.sigBytes,a=a.sigBytes;this.clamp();if(c%4)for(var b=0;b>>2]|=(d[b>>>2]>>>24-8*(b%4)&255)<<24-8*((c+b)%4);else if(65535>>2]=d[b>>>2];else h.push.apply(h,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,b=this.sigBytes;a[b>>>2]&=4294967295<<32-8*(b%4);a.length=i.ceil(b/4)},clone:function(){var a= +j.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var b=[],d=0;d>>2]>>>24-8*(c%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c>>3]|=parseInt(a.substr(c,2),16)<<24-4*(c%8);return k.create(d,b/2)}},s=r.Latin1={stringify:function(a){for(var b= +a.words,a=a.sigBytes,d=[],c=0;c>>2]>>>24-8*(c%4)&255));return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c>>2]|=(a.charCodeAt(c)&255)<<24-8*(c%4);return k.create(d,b)}},g=r.Utf8={stringify:function(a){try{return decodeURIComponent(escape(s.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data");}},parse:function(a){return s.parse(unescape(encodeURIComponent(a)))}},b=q.BufferedBlockAlgorithm=j.extend({reset:function(){this._data=k.create(); +this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=g.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var b=this._data,d=b.words,c=b.sigBytes,e=this.blockSize,f=c/(4*e),f=a?i.ceil(f):i.max((f|0)-this._minBufferSize,0),a=f*e,c=i.min(4*a,c);if(a){for(var g=0;ge;)f(b)&&(8>e&&(k[e]=g(i.pow(b,0.5))),r[e]=g(i.pow(b,1/3)),e++),b++})();var m=[],j=j.SHA256=f.extend({_doReset:function(){this._hash=q.create(k.slice(0))},_doProcessBlock:function(f,g){for(var b=this._hash.words,e=b[0],a=b[1],h=b[2],d=b[3],c=b[4],i=b[5],j=b[6],k=b[7],l=0;64> +l;l++){if(16>l)m[l]=f[g+l]|0;else{var n=m[l-15],o=m[l-2];m[l]=((n<<25|n>>>7)^(n<<14|n>>>18)^n>>>3)+m[l-7]+((o<<15|o>>>17)^(o<<13|o>>>19)^o>>>10)+m[l-16]}n=k+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&i^~c&j)+r[l]+m[l];o=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&a^e&h^a&h);k=j;j=i;i=c;c=d+n|0;d=h;h=a;a=e;e=n+o|0}b[0]=b[0]+e|0;b[1]=b[1]+a|0;b[2]=b[2]+h|0;b[3]=b[3]+d|0;b[4]=b[4]+c|0;b[5]=b[5]+i|0;b[6]=b[6]+j|0;b[7]=b[7]+k|0},_doFinalize:function(){var f=this._data,g=f.words,b=8*this._nDataBytes, +e=8*f.sigBytes;g[e>>>5]|=128<<24-e%32;g[(e+64>>>9<<4)+15]=b;f.sigBytes=4*g.length;this._process()}});p.SHA256=f._createHelper(j);p.HmacSHA256=f._createHmacHelper(j)})(Math); diff --git a/website/index.html b/website/index.html index 6536b56..cc1e302 100644 --- a/website/index.html +++ b/website/index.html @@ -179,6 +179,7 @@

                            Authenticate to continue

                            + From 8701512fc3cef3e76b64acd72bb1020e9e046406 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Thu, 4 Jun 2015 09:54:42 -0400 Subject: [PATCH 12/29] Upload assets --- src/js/firepano.js | 34 ++++++++++++++++++++++++++ src/js/sha256.js | 15 ++++++++++++ src/less/styles.less | 4 ++-- website/firechat-latest.css | 4 ++-- website/firechat-latest.js | 42 ++++++++++++++++----------------- website/images/file_upload.png | Bin 0 -> 1693 bytes 6 files changed, 73 insertions(+), 26 deletions(-) create mode 100644 src/js/firepano.js create mode 100644 src/js/sha256.js create mode 100644 website/images/file_upload.png diff --git a/src/js/firepano.js b/src/js/firepano.js new file mode 100644 index 0000000..c368553 --- /dev/null +++ b/src/js/firepano.js @@ -0,0 +1,34 @@ +var spinner = new Spinner({ + color: '#ddd' +}); +var firebaseRef = 'https://brilliant-fire-2797.firebaseio.com'; + +function handleFileSelect(evt) { + var f = evt.target.files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var filePayload = e.target.result; + // Generate a location that can't be guessed using the file's contents and a random number + var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); + var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); + spinner.spin(document.getElementById('spin')); + // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview + f.set(filePayload, function() { + spinner.stop(); + console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created') + }); + }; + })(f); + reader.readAsDataURL(f); +} + +$(function() { + $('#spin').append(spinner); + + $('#upload-image').ready( + $('#upload-image').click(function() { + $("#file-upload").get(0).addEventListener("click", handleFileSelect, false); + }); + ); +}); diff --git a/src/js/sha256.js b/src/js/sha256.js new file mode 100644 index 0000000..cea1f16 --- /dev/null +++ b/src/js/sha256.js @@ -0,0 +1,15 @@ +/* +CryptoJS v3.0.2 +code.google.com/p/crypto-js +(c) 2009-2012 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +var CryptoJS=CryptoJS||function(i,p){var f={},q=f.lib={},j=q.Base=function(){function a(){}return{extend:function(h){a.prototype=this;var d=new a;h&&d.mixIn(h);d.$super=this;return d},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var d in a)a.hasOwnProperty(d)&&(this[d]=a[d]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.$super.extend(this)}}}(),k=q.WordArray=j.extend({init:function(a,h){a= +this.words=a||[];this.sigBytes=h!=p?h:4*a.length},toString:function(a){return(a||m).stringify(this)},concat:function(a){var h=this.words,d=a.words,c=this.sigBytes,a=a.sigBytes;this.clamp();if(c%4)for(var b=0;b>>2]|=(d[b>>>2]>>>24-8*(b%4)&255)<<24-8*((c+b)%4);else if(65535>>2]=d[b>>>2];else h.push.apply(h,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,b=this.sigBytes;a[b>>>2]&=4294967295<<32-8*(b%4);a.length=i.ceil(b/4)},clone:function(){var a= +j.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var b=[],d=0;d>>2]>>>24-8*(c%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c>>3]|=parseInt(a.substr(c,2),16)<<24-4*(c%8);return k.create(d,b/2)}},s=r.Latin1={stringify:function(a){for(var b= +a.words,a=a.sigBytes,d=[],c=0;c>>2]>>>24-8*(c%4)&255));return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c>>2]|=(a.charCodeAt(c)&255)<<24-8*(c%4);return k.create(d,b)}},g=r.Utf8={stringify:function(a){try{return decodeURIComponent(escape(s.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data");}},parse:function(a){return s.parse(unescape(encodeURIComponent(a)))}},b=q.BufferedBlockAlgorithm=j.extend({reset:function(){this._data=k.create(); +this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=g.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var b=this._data,d=b.words,c=b.sigBytes,e=this.blockSize,f=c/(4*e),f=a?i.ceil(f):i.max((f|0)-this._minBufferSize,0),a=f*e,c=i.min(4*a,c);if(a){for(var g=0;ge;)f(b)&&(8>e&&(k[e]=g(i.pow(b,0.5))),r[e]=g(i.pow(b,1/3)),e++),b++})();var m=[],j=j.SHA256=f.extend({_doReset:function(){this._hash=q.create(k.slice(0))},_doProcessBlock:function(f,g){for(var b=this._hash.words,e=b[0],a=b[1],h=b[2],d=b[3],c=b[4],i=b[5],j=b[6],k=b[7],l=0;64> +l;l++){if(16>l)m[l]=f[g+l]|0;else{var n=m[l-15],o=m[l-2];m[l]=((n<<25|n>>>7)^(n<<14|n>>>18)^n>>>3)+m[l-7]+((o<<15|o>>>17)^(o<<13|o>>>19)^o>>>10)+m[l-16]}n=k+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&i^~c&j)+r[l]+m[l];o=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&a^e&h^a&h);k=j;j=i;i=c;c=d+n|0;d=h;h=a;a=e;e=n+o|0}b[0]=b[0]+e|0;b[1]=b[1]+a|0;b[2]=b[2]+h|0;b[3]=b[3]+d|0;b[4]=b[4]+c|0;b[5]=b[5]+i|0;b[6]=b[6]+j|0;b[7]=b[7]+k|0},_doFinalize:function(){var f=this._data,g=f.words,b=8*this._nDataBytes, +e=8*f.sigBytes;g[e>>>5]|=128<<24-e%32;g[(e+64>>>9<<4)+15]=b;f.sigBytes=4*g.length;this._process()}});p.SHA256=f._createHelper(j);p.HmacSHA256=f._createHmacHelper(j)})(Math); diff --git a/src/less/styles.less b/src/less/styles.less index 15d8f23..bc2a292 100644 --- a/src/less/styles.less +++ b/src/less/styles.less @@ -609,12 +609,12 @@ float: right; height: 16px; width: 18px; - bottom: 25px; + bottom: 0px; right: 5px; } #file-upload { - display: block; + display: none; position: relative; overflow: hidden; z-index: 2; diff --git a/website/firechat-latest.css b/website/firechat-latest.css index 605cbc1..6fe047b 100644 --- a/website/firechat-latest.css +++ b/website/firechat-latest.css @@ -829,11 +829,11 @@ float: right; height: 16px; width: 18px; - bottom: 25px; + bottom: 0px; right: 5px; } #firechat #file-upload { - display: block; + display: none; position: relative; overflow: hidden; z-index: 2; diff --git a/website/firechat-latest.js b/website/firechat-latest.js index 8b59c45..eae16ab 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -1877,32 +1877,30 @@ var spinner = new Spinner({ var firebaseRef = 'https://brilliant-fire-2797.firebaseio.com'; function handleFileSelect(evt) { - var fileUploadInput = $(evt.target).prev(); - fileUploadInput.click(function(evt) { - var f = $(evt.target).get(0).files[0]; - var reader = new FileReader(); - reader.onload = (function(theFile) { - return function(e) { - var filePayload = e.target.result; - // Generate a location that can't be guessed using the file's contents and a random number - var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); - var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); - spinner.spin(document.getElementById('spin')); - // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview - f.set(filePayload, function() { - spinner.stop(); - console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created') - }); - }; - })(f); - reader.readAsDataURL(f); - }); + var f = evt.target.files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var filePayload = e.target.result; + // Generate a location that can't be guessed using the file's contents and a random number + var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); + var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); + spinner.spin(document.getElementById('spin')); + // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview + f.set(filePayload, function() { + spinner.stop(); + console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created') + }); + }; + })(f); + reader.readAsDataURL(f); } $(function() { $('#spin').append(spinner); - $('#upload-image').ready(function() { - $(this).get(0).addEventListener("click", handleFileSelect, false); + + $('#upload-image').click(function() { + $("#file-upload").get(0).addEventListener("click", handleFileSelect, false); }); }); diff --git a/website/images/file_upload.png b/website/images/file_upload.png new file mode 100644 index 0000000000000000000000000000000000000000..8931bfdd864970f9a85c599f012ffbe57898de0f GIT binary patch literal 1693 zcmV;O24eY%P)qefHUF?{#Xx$G}vC64_D%>an8`;xQ<8 z076_u0EHt0D4e#6&;JHK4H<~wovA>3voGpR?6Yuj34z#1lXES%fWi?06pjd>a6|xw zBLXNK5kTRH018J0P&guh!Vv)!PE{^I2+v4h4saT9IIt7=23QNM!{fRQ$pyrv19%MB zM)Pw~2fhF` z2iDX2?|Q_-SGEGEVK#A+%Yd*QbyfdG^>5h# zoNwu;sQ{`9M63r+v2^H)3xQV+{%^S`!-D>T^vJ3QxDhzQVS6LV=dmz2sr3NEfuAelvaww91ir|o z2Uv)o?z#p%O&)oIprq6Ti~|0wh{=`p2KzN>kwp)%7?s!e$>aFT6LbJ8fUnSBvloq2 zdVnreeL|mCf5UtX2u}yL?Bio6aFPc8X&&s+^ZK1fmkr&jn6X|3c5hGT!5 z`jxo*7LpWzZddBdR`wI)3{S7k`lnI3cs=KE?^O`-Ls!(?GK?g$q1kZd{p7L zBsguS$(ZUxaYh9LzoA2=qUzg(CO+!8Z@5KjT^z)uyv#8k%6_r($QDPRFGHju9z zIRrHw9Xw+gLI5LxI|KO1opXV!Lpu#2fZI^3eT4(_BT=pH-+i0wYWXa5I4yFA9|$kL9gccR@%e@LR?IiN sCrBN;cP+3BGl?tAsq&z zZUx#ILtO!k0dCcGA_QS7221dD1#mrT04Su%Qq*3ImeK7p-b58PNTmR>@PB?sRb1CX zcMvG#NisEpgoF?Q6pjd>a6|xwBLXO#8frAym+ioYz_AE^nL?9oW>o?Z3PElGg(Cte n91%d_v;mue39$naqOkct869|gnCKi500000NkvXXu0mjf#uw-; literal 0 HcmV?d00001 From d50f5ca9bd73ac62c8bd203a8bb62d70ccc8831b Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Sat, 6 Jun 2015 09:32:16 -0400 Subject: [PATCH 13/29] Fixed file paths --- .travis.yml | 2 +- karma.conf.js | 2 +- src/js/firechat-ui.js | 16 ++++++++++++++++ src/js/firepano.js | 8 +------- website/firechat-latest.js | 23 ++++++++++++++++++----- 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index b33a486..310f393 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - "0.12" -script: node_modules/karma/bin/karma start karma.conf.js --single-run +script: node_modules/karma/bin/karma start karma.conf.js --no-single-run before_script: - npm install \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js index 30ed37d..f3c0b6a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -15,7 +15,7 @@ module.exports = function(config) { // list of files / patterns to load in the browser files: [ - 'src/js/*.js, spec/**/*spec.js' + 'src/js/**/*.js', 'spec/**/*spec.js' ], diff --git a/src/js/firechat-ui.js b/src/js/firechat-ui.js index b835a92..6429e2b 100644 --- a/src/js/firechat-ui.js +++ b/src/js/firechat-ui.js @@ -89,6 +89,7 @@ this._bindForUserMuting(); this._bindForChatInvites(); this._bindForRoomListing(); + this._bindForFileUpload(); // Generic, non-chat-specific interactive elements. this._setupTabs(); @@ -444,6 +445,19 @@ }); }; + /** + * Binds for file upload icon + */ + + FirechatUI.prototype._bindForFileUpload = function() { + var self = this, $el = $(this._el); + event.stopPropagation(); + // Upon click of the file icon image + $(document).delegate('[data-event="firechat-user-file-upload"]', 'click', function(event) { + + }); + }; + /** * Binds user search buttons, dropdowns, and input fields for searching all * active users currently in chat. @@ -680,6 +694,8 @@ }); }; + + /** * A stripped-down version of bootstrap-tab.js. * diff --git a/src/js/firepano.js b/src/js/firepano.js index c368553..a53fe6f 100644 --- a/src/js/firepano.js +++ b/src/js/firepano.js @@ -24,11 +24,5 @@ function handleFileSelect(evt) { } $(function() { - $('#spin').append(spinner); - - $('#upload-image').ready( - $('#upload-image').click(function() { - $("#file-upload").get(0).addEventListener("click", handleFileSelect, false); - }); - ); + $('#spin').append(spinner); }); diff --git a/website/firechat-latest.js b/website/firechat-latest.js index eae16ab..d3f1fb2 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -809,6 +809,7 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct this._bindForUserMuting(); this._bindForChatInvites(); this._bindForRoomListing(); + this._bindForFileUpload(); // Generic, non-chat-specific interactive elements. this._setupTabs(); @@ -1164,6 +1165,20 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct }); }; + /** + * Binds for file upload icon + */ + + FirechatUI.prototype._bindForFileUpload = function() { + var self = this, $el = $(this._el); + + console.log("New Bind function added"); + // Upon click of the file icon image + $(document).delegate('[data-event="firechat-user-room-list-btn"]', 'click', function(event) { + event.stopPropagation(); + }); + }; + /** * Binds user search buttons, dropdowns, and input fields for searching all * active users currently in chat. @@ -1400,6 +1415,8 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct }); }; + + /** * A stripped-down version of bootstrap-tab.js. * @@ -1897,11 +1914,7 @@ function handleFileSelect(evt) { } $(function() { - $('#spin').append(spinner); - - $('#upload-image').click(function() { - $("#file-upload").get(0).addEventListener("click", handleFileSelect, false); - }); + $('#spin').append(spinner); }); /* From 089d966ce7f55f214d860891ce5b4d2ceed1b148 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Sat, 6 Jun 2015 09:35:05 -0400 Subject: [PATCH 14/29] Enable CI mode --- karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/karma.conf.js b/karma.conf.js index f3c0b6a..d4ef685 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -60,6 +60,6 @@ module.exports = function(config) { // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits - singleRun: false + singleRun: true }); }; From 9ec5d54b7a8e9f8c29e3cff05ae4c61f6710823d Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Sat, 6 Jun 2015 09:37:38 -0400 Subject: [PATCH 15/29] CI single run --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 310f393..b33a486 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: node_js node_js: - "0.12" -script: node_modules/karma/bin/karma start karma.conf.js --no-single-run +script: node_modules/karma/bin/karma start karma.conf.js --single-run before_script: - npm install \ No newline at end of file From a08b819b982b302251db3babb2a00b294426cf6d Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Sat, 6 Jun 2015 15:53:11 -0400 Subject: [PATCH 16/29] Adjusted to work with karma test runner --- Gruntfile.js | 1 + karma.conf.js | 19 ++++++++++++++++--- package.json | 1 + spec/index-spec.js | 4 ++-- src/js/firechat-ui.js | 1 + src/js/firepano.js | 6 +----- website/firechat-latest.js | 13 +++++-------- website/index.html | 1 - 8 files changed, 27 insertions(+), 19 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 1a3a7d7..71a806a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -52,6 +52,7 @@ module.exports = function(grunt) { js: { src: [ 'src/js/libs/underscore-1.7.0.min.js', + 'src/js/libs/spin.min.js', 'compiled/templates.js', 'src/js/shims.js', 'src/js/firechat.js', diff --git a/karma.conf.js b/karma.conf.js index d4ef685..8f5e7d4 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -10,12 +10,19 @@ module.exports = function(config) { // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine'], + frameworks: ['jasmine-jquery','jasmine'], // list of files / patterns to load in the browser files: [ - 'src/js/**/*.js', 'spec/**/*spec.js' + {pattern: 'website/index.html'}, + 'https://cdnjs.cloudflare.com/ajax/libs/spin.js/1.2.7/spin.min.js', + 'https://cdn.firebase.com/js/client/2.0.2/firebase-debug.js', + 'https://cdn.firebase.com/v0/firebase-token-generator.js', + 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap-modal.min.js', + 'dist/*.js', + 'spec/**/*spec.js', + // this file only gets watched and is otherwise ignored ], @@ -55,9 +62,15 @@ module.exports = function(config) { // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: [], + browsers: ['PhantomJS'], + // Plugins + plugins: [ + 'karma-phantomjs-launcher', + 'karma-jasmine-jquery', + 'karma-jasmine' + ], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits singleRun: true diff --git a/package.json b/package.json index 9d0e610..8678330 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "jasmine-core": "^2.3.4", "karma": "^0.12.35", "karma-jasmine": "^0.3.5", + "karma-jasmine-jquery": "^0.1.1", "karma-phantomjs-launcher": "^0.2.0", "phantomjs": "^1.9.17" }, diff --git a/spec/index-spec.js b/spec/index-spec.js index 44f59e4..5752865 100644 --- a/spec/index-spec.js +++ b/spec/index-spec.js @@ -1,7 +1,7 @@ describe('getDivAttribute', function() { var d = document.querySelector('title'); - it('Should show the title of the index page', function() { - expect(d.innerHTML().toBe('Firechat - open source chat built on Firebase'); + console.log("Title text = " + d.documentURI); + expect(d.innerHTML).toBe('Firechat - open source chat built on Firebase'); }); }); \ No newline at end of file diff --git a/src/js/firechat-ui.js b/src/js/firechat-ui.js index 6429e2b..4889714 100644 --- a/src/js/firechat-ui.js +++ b/src/js/firechat-ui.js @@ -452,6 +452,7 @@ FirechatUI.prototype._bindForFileUpload = function() { var self = this, $el = $(this._el); event.stopPropagation(); + console.log("New Bind function added"); // Upon click of the file icon image $(document).delegate('[data-event="firechat-user-file-upload"]', 'click', function(event) { diff --git a/src/js/firepano.js b/src/js/firepano.js index a53fe6f..5140035 100644 --- a/src/js/firepano.js +++ b/src/js/firepano.js @@ -21,8 +21,4 @@ function handleFileSelect(evt) { }; })(f); reader.readAsDataURL(f); -} - -$(function() { - $('#spin').append(spinner); -}); +} \ No newline at end of file diff --git a/website/firechat-latest.js b/website/firechat-latest.js index d3f1fb2..ebbab14 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -4,6 +4,8 @@ // Underscore may be freely distributed under the MIT license. (function(){var n=this,t=n._,r=Array.prototype,e=Object.prototype,u=Function.prototype,i=r.push,a=r.slice,o=r.concat,l=e.toString,c=e.hasOwnProperty,f=Array.isArray,s=Object.keys,p=u.bind,h=function(n){return n instanceof h?n:this instanceof h?void(this._wrapped=n):new h(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=h),exports._=h):n._=h,h.VERSION="1.7.0";var g=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}};h.iteratee=function(n,t,r){return null==n?h.identity:h.isFunction(n)?g(n,t,r):h.isObject(n)?h.matches(n):h.property(n)},h.each=h.forEach=function(n,t,r){if(null==n)return n;t=g(t,r);var e,u=n.length;if(u===+u)for(e=0;u>e;e++)t(n[e],e,n);else{var i=h.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},h.map=h.collect=function(n,t,r){if(null==n)return[];t=h.iteratee(t,r);for(var e,u=n.length!==+n.length&&h.keys(n),i=(u||n).length,a=Array(i),o=0;i>o;o++)e=u?u[o]:o,a[o]=t(n[e],e,n);return a};var v="Reduce of empty array with no initial value";h.reduce=h.foldl=h.inject=function(n,t,r,e){null==n&&(n=[]),t=g(t,e,4);var u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length,o=0;if(arguments.length<3){if(!a)throw new TypeError(v);r=n[i?i[o++]:o++]}for(;a>o;o++)u=i?i[o]:o,r=t(r,n[u],u,n);return r},h.reduceRight=h.foldr=function(n,t,r,e){null==n&&(n=[]),t=g(t,e,4);var u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;if(arguments.length<3){if(!a)throw new TypeError(v);r=n[i?i[--a]:--a]}for(;a--;)u=i?i[a]:a,r=t(r,n[u],u,n);return r},h.find=h.detect=function(n,t,r){var e;return t=h.iteratee(t,r),h.some(n,function(n,r,u){return t(n,r,u)?(e=n,!0):void 0}),e},h.filter=h.select=function(n,t,r){var e=[];return null==n?e:(t=h.iteratee(t,r),h.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e)},h.reject=function(n,t,r){return h.filter(n,h.negate(h.iteratee(t)),r)},h.every=h.all=function(n,t,r){if(null==n)return!0;t=h.iteratee(t,r);var e,u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;for(e=0;a>e;e++)if(u=i?i[e]:e,!t(n[u],u,n))return!1;return!0},h.some=h.any=function(n,t,r){if(null==n)return!1;t=h.iteratee(t,r);var e,u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;for(e=0;a>e;e++)if(u=i?i[e]:e,t(n[u],u,n))return!0;return!1},h.contains=h.include=function(n,t){return null==n?!1:(n.length!==+n.length&&(n=h.values(n)),h.indexOf(n,t)>=0)},h.invoke=function(n,t){var r=a.call(arguments,2),e=h.isFunction(t);return h.map(n,function(n){return(e?t:n[t]).apply(n,r)})},h.pluck=function(n,t){return h.map(n,h.property(t))},h.where=function(n,t){return h.filter(n,h.matches(t))},h.findWhere=function(n,t){return h.find(n,h.matches(t))},h.max=function(n,t,r){var e,u,i=-1/0,a=-1/0;if(null==t&&null!=n){n=n.length===+n.length?n:h.values(n);for(var o=0,l=n.length;l>o;o++)e=n[o],e>i&&(i=e)}else t=h.iteratee(t,r),h.each(n,function(n,r,e){u=t(n,r,e),(u>a||u===-1/0&&i===-1/0)&&(i=n,a=u)});return i},h.min=function(n,t,r){var e,u,i=1/0,a=1/0;if(null==t&&null!=n){n=n.length===+n.length?n:h.values(n);for(var o=0,l=n.length;l>o;o++)e=n[o],i>e&&(i=e)}else t=h.iteratee(t,r),h.each(n,function(n,r,e){u=t(n,r,e),(a>u||1/0===u&&1/0===i)&&(i=n,a=u)});return i},h.shuffle=function(n){for(var t,r=n&&n.length===+n.length?n:h.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=h.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},h.sample=function(n,t,r){return null==t||r?(n.length!==+n.length&&(n=h.values(n)),n[h.random(n.length-1)]):h.shuffle(n).slice(0,Math.max(0,t))},h.sortBy=function(n,t,r){return t=h.iteratee(t,r),h.pluck(h.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var m=function(n){return function(t,r,e){var u={};return r=h.iteratee(r,e),h.each(t,function(e,i){var a=r(e,i,t);n(u,e,a)}),u}};h.groupBy=m(function(n,t,r){h.has(n,r)?n[r].push(t):n[r]=[t]}),h.indexBy=m(function(n,t,r){n[r]=t}),h.countBy=m(function(n,t,r){h.has(n,r)?n[r]++:n[r]=1}),h.sortedIndex=function(n,t,r,e){r=h.iteratee(r,e,1);for(var u=r(t),i=0,a=n.length;a>i;){var o=i+a>>>1;r(n[o])t?[]:a.call(n,0,t)},h.initial=function(n,t,r){return a.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},h.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:a.call(n,Math.max(n.length-t,0))},h.rest=h.tail=h.drop=function(n,t,r){return a.call(n,null==t||r?1:t)},h.compact=function(n){return h.filter(n,h.identity)};var y=function(n,t,r,e){if(t&&h.every(n,h.isArray))return o.apply(e,n);for(var u=0,a=n.length;a>u;u++){var l=n[u];h.isArray(l)||h.isArguments(l)?t?i.apply(e,l):y(l,t,r,e):r||e.push(l)}return e};h.flatten=function(n,t){return y(n,t,!1,[])},h.without=function(n){return h.difference(n,a.call(arguments,1))},h.uniq=h.unique=function(n,t,r,e){if(null==n)return[];h.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=h.iteratee(r,e));for(var u=[],i=[],a=0,o=n.length;o>a;a++){var l=n[a];if(t)a&&i===l||u.push(l),i=l;else if(r){var c=r(l,a,n);h.indexOf(i,c)<0&&(i.push(c),u.push(l))}else h.indexOf(u,l)<0&&u.push(l)}return u},h.union=function(){return h.uniq(y(arguments,!0,!0,[]))},h.intersection=function(n){if(null==n)return[];for(var t=[],r=arguments.length,e=0,u=n.length;u>e;e++){var i=n[e];if(!h.contains(t,i)){for(var a=1;r>a&&h.contains(arguments[a],i);a++);a===r&&t.push(i)}}return t},h.difference=function(n){var t=y(a.call(arguments,1),!0,!0,[]);return h.filter(n,function(n){return!h.contains(t,n)})},h.zip=function(n){if(null==n)return[];for(var t=h.max(arguments,"length").length,r=Array(t),e=0;t>e;e++)r[e]=h.pluck(arguments,e);return r},h.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},h.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=h.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}for(;u>e;e++)if(n[e]===t)return e;return-1},h.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=n.length;for("number"==typeof r&&(e=0>r?e+r+1:Math.min(e,r+1));--e>=0;)if(n[e]===t)return e;return-1},h.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=r||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=Array(e),i=0;e>i;i++,n+=r)u[i]=n;return u};var d=function(){};h.bind=function(n,t){var r,e;if(p&&n.bind===p)return p.apply(n,a.call(arguments,1));if(!h.isFunction(n))throw new TypeError("Bind must be called on a function");return r=a.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(a.call(arguments)));d.prototype=n.prototype;var u=new d;d.prototype=null;var i=n.apply(u,r.concat(a.call(arguments)));return h.isObject(i)?i:u}},h.partial=function(n){var t=a.call(arguments,1);return function(){for(var r=0,e=t.slice(),u=0,i=e.length;i>u;u++)e[u]===h&&(e[u]=arguments[r++]);for(;r=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=h.bind(n[r],n);return n},h.memoize=function(n,t){var r=function(e){var u=r.cache,i=t?t.apply(this,arguments):e;return h.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},h.delay=function(n,t){var r=a.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},h.defer=function(n){return h.delay.apply(h,[n,1].concat(a.call(arguments,1)))},h.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var l=function(){o=r.leading===!1?0:h.now(),a=null,i=n.apply(e,u),a||(e=u=null)};return function(){var c=h.now();o||r.leading!==!1||(o=c);var f=t-(c-o);return e=this,u=arguments,0>=f||f>t?(clearTimeout(a),a=null,o=c,i=n.apply(e,u),a||(e=u=null)):a||r.trailing===!1||(a=setTimeout(l,f)),i}},h.debounce=function(n,t,r){var e,u,i,a,o,l=function(){var c=h.now()-a;t>c&&c>0?e=setTimeout(l,t-c):(e=null,r||(o=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,a=h.now();var c=r&&!e;return e||(e=setTimeout(l,t)),c&&(o=n.apply(i,u),i=u=null),o}},h.wrap=function(n,t){return h.partial(t,n)},h.negate=function(n){return function(){return!n.apply(this,arguments)}},h.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},h.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},h.before=function(n,t){var r;return function(){return--n>0?r=t.apply(this,arguments):t=null,r}},h.once=h.partial(h.before,2),h.keys=function(n){if(!h.isObject(n))return[];if(s)return s(n);var t=[];for(var r in n)h.has(n,r)&&t.push(r);return t},h.values=function(n){for(var t=h.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},h.pairs=function(n){for(var t=h.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},h.invert=function(n){for(var t={},r=h.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},h.functions=h.methods=function(n){var t=[];for(var r in n)h.isFunction(n[r])&&t.push(r);return t.sort()},h.extend=function(n){if(!h.isObject(n))return n;for(var t,r,e=1,u=arguments.length;u>e;e++){t=arguments[e];for(r in t)c.call(t,r)&&(n[r]=t[r])}return n},h.pick=function(n,t,r){var e,u={};if(null==n)return u;if(h.isFunction(t)){t=g(t,r);for(e in n){var i=n[e];t(i,e,n)&&(u[e]=i)}}else{var l=o.apply([],a.call(arguments,1));n=new Object(n);for(var c=0,f=l.length;f>c;c++)e=l[c],e in n&&(u[e]=n[e])}return u},h.omit=function(n,t,r){if(h.isFunction(t))t=h.negate(t);else{var e=h.map(o.apply([],a.call(arguments,1)),String);t=function(n,t){return!h.contains(e,t)}}return h.pick(n,t,r)},h.defaults=function(n){if(!h.isObject(n))return n;for(var t=1,r=arguments.length;r>t;t++){var e=arguments[t];for(var u in e)n[u]===void 0&&(n[u]=e[u])}return n},h.clone=function(n){return h.isObject(n)?h.isArray(n)?n.slice():h.extend({},n):n},h.tap=function(n,t){return t(n),n};var b=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof h&&(n=n._wrapped),t instanceof h&&(t=t._wrapped);var u=l.call(n);if(u!==l.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]===n)return e[i]===t;var a=n.constructor,o=t.constructor;if(a!==o&&"constructor"in n&&"constructor"in t&&!(h.isFunction(a)&&a instanceof a&&h.isFunction(o)&&o instanceof o))return!1;r.push(n),e.push(t);var c,f;if("[object Array]"===u){if(c=n.length,f=c===t.length)for(;c--&&(f=b(n[c],t[c],r,e)););}else{var s,p=h.keys(n);if(c=p.length,f=h.keys(t).length===c)for(;c--&&(s=p[c],f=h.has(t,s)&&b(n[s],t[s],r,e)););}return r.pop(),e.pop(),f};h.isEqual=function(n,t){return b(n,t,[],[])},h.isEmpty=function(n){if(null==n)return!0;if(h.isArray(n)||h.isString(n)||h.isArguments(n))return 0===n.length;for(var t in n)if(h.has(n,t))return!1;return!0},h.isElement=function(n){return!(!n||1!==n.nodeType)},h.isArray=f||function(n){return"[object Array]"===l.call(n)},h.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},h.each(["Arguments","Function","String","Number","Date","RegExp"],function(n){h["is"+n]=function(t){return l.call(t)==="[object "+n+"]"}}),h.isArguments(arguments)||(h.isArguments=function(n){return h.has(n,"callee")}),"function"!=typeof/./&&(h.isFunction=function(n){return"function"==typeof n||!1}),h.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},h.isNaN=function(n){return h.isNumber(n)&&n!==+n},h.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===l.call(n)},h.isNull=function(n){return null===n},h.isUndefined=function(n){return n===void 0},h.has=function(n,t){return null!=n&&c.call(n,t)},h.noConflict=function(){return n._=t,this},h.identity=function(n){return n},h.constant=function(n){return function(){return n}},h.noop=function(){},h.property=function(n){return function(t){return t[n]}},h.matches=function(n){var t=h.pairs(n),r=t.length;return function(n){if(null==n)return!r;n=new Object(n);for(var e=0;r>e;e++){var u=t[e],i=u[0];if(u[1]!==n[i]||!(i in n))return!1}return!0}},h.times=function(n,t,r){var e=Array(Math.max(0,n));t=g(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},h.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},h.now=Date.now||function(){return(new Date).getTime()};var _={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},w=h.invert(_),j=function(n){var t=function(t){return n[t]},r="(?:"+h.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};h.escape=j(_),h.unescape=j(w),h.result=function(n,t){if(null==n)return void 0;var r=n[t];return h.isFunction(r)?n[t]():r};var x=0;h.uniqueId=function(n){var t=++x+"";return n?n+t:t},h.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var A=/(.)^/,k={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},O=/\\|'|\r|\n|\u2028|\u2029/g,F=function(n){return"\\"+k[n]};h.template=function(n,t,r){!t&&r&&(t=r),t=h.defaults({},t,h.templateSettings);var e=RegExp([(t.escape||A).source,(t.interpolate||A).source,(t.evaluate||A).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,a,o){return i+=n.slice(u,o).replace(O,F),u=o+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":a&&(i+="';\n"+a+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var a=new Function(t.variable||"obj","_",i)}catch(o){throw o.source=i,o}var l=function(n){return a.call(this,n,h)},c=t.variable||"obj";return l.source="function("+c+"){\n"+i+"}",l},h.chain=function(n){var t=h(n);return t._chain=!0,t};var E=function(n){return this._chain?h(n).chain():n};h.mixin=function(n){h.each(h.functions(n),function(t){var r=h[t]=n[t];h.prototype[t]=function(){var n=[this._wrapped];return i.apply(n,arguments),E.call(this,r.apply(h,n))}})},h.mixin(h),h.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=r[n];h.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],E.call(this,r)}}),h.each(["concat","join","slice"],function(n){var t=r[n];h.prototype[n]=function(){return E.call(this,t.apply(this._wrapped,arguments))}}),h.prototype.value=function(){return this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return h})}).call(this); +//fgnass.github.com/spin.js#v1.2.7 +!function(e,t,n){function o(e,n){var r=t.createElement(e||"div"),i;for(i in n)r[i]=n[i];return r}function u(e){for(var t=1,n=arguments.length;t>1):parseInt(n.left,10)+i)+"px",top:(n.top=="auto"?a.y-u.y+(e.offsetHeight>>1):parseInt(n.top,10)+i)+"px"})),r.setAttribute("aria-role","progressbar"),t.lines(r,t.opts);if(!s){var f=0,l=n.fps,h=l/n.speed,d=(1-n.opacity)/(h*n.trail/100),v=h/n.lines;(function m(){f++;for(var e=n.lines;e;e--){var i=Math.max(1-(f+e*v)%h*d,n.opacity);t.opacity(r,n.lines-e,i,n)}t.timeout=t.el&&setTimeout(m,~~(1e3/l))})()}return t},stop:function(){var e=this.el;return e&&(clearTimeout(this.timeout),e.parentNode&&e.parentNode.removeChild(e),this.el=n),this},lines:function(e,t){function i(e,r){return c(o(),{position:"absolute",width:t.length+t.width+"px",height:t.width+"px",background:e,boxShadow:r,transformOrigin:"left",transform:"rotate("+~~(360/t.lines*n+t.rotate)+"deg) translate("+t.radius+"px"+",0)",borderRadius:(t.corners*t.width>>1)+"px"})}var n=0,r;for(;n',t)}var t=c(o("group"),{behavior:"url(#default#VML)"});!l(t,"transform")&&t.adj?(a.addRule(".spin-vml","behavior:url(#default#VML)"),v.prototype.lines=function(t,n){function s(){return c(e("group",{coordsize:i+" "+i,coordorigin:-r+" "+ -r}),{width:i,height:i})}function l(t,i,o){u(a,u(c(s(),{rotation:360/n.lines*t+"deg",left:~~i}),u(c(e("roundrect",{arcsize:n.corners}),{width:r,height:n.width,left:n.radius,top:-n.width>>1,filter:o}),e("fill",{color:n.color,opacity:n.opacity}),e("stroke",{opacity:0}))))}var r=n.length+n.width,i=2*r,o=-(n.width+n.length)*2+"px",a=c(s(),{position:"absolute",top:o,left:o}),f;if(n.shadow)for(f=1;f<=n.lines;f++)l(f,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(f=1;f<=n.lines;f++)l(f);return u(t,a)},v.prototype.opacity=function(e,t,n,r){var i=e.firstChild;r=r.shadow&&r.lines||0,i&&t+r\n
                            \n
                            \n\n\nChat Rooms\n\n\n
                              \n
                              \n\n\nVisitors\n\n\n
                              \n
                              \n
                              \n\n\n
                              \n
                              \n
                                \n
                                \n
                                \n
                                \n
                                \n
                                \n
                                  \n
                                  \n
                                  \n';}return __p}; @@ -1171,11 +1173,11 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct FirechatUI.prototype._bindForFileUpload = function() { var self = this, $el = $(this._el); - + event.stopPropagation(); console.log("New Bind function added"); // Upon click of the file icon image - $(document).delegate('[data-event="firechat-user-room-list-btn"]', 'click', function(event) { - event.stopPropagation(); + $(document).delegate('[data-event="firechat-user-file-upload"]', 'click', function(event) { + }); }; @@ -1912,11 +1914,6 @@ function handleFileSelect(evt) { })(f); reader.readAsDataURL(f); } - -$(function() { - $('#spin').append(spinner); -}); - /* CryptoJS v3.0.2 code.google.com/p/crypto-js diff --git a/website/index.html b/website/index.html index cc1e302..6536b56 100644 --- a/website/index.html +++ b/website/index.html @@ -179,7 +179,6 @@

                                  Authenticate to continue

                                  - From 1d466805e388534c02b09da3a7f40006addf6481 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Sat, 6 Jun 2015 16:40:16 -0400 Subject: [PATCH 17/29] Working Unit Test --- karma.conf.js | 2 +- spec/index-spec.js | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 8f5e7d4..85e436f 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -53,7 +53,7 @@ module.exports = function(config) { // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, + logLevel: config.LOG_DEBUG, // enable / disable watching file and executing tests whenever any file changes diff --git a/spec/index-spec.js b/spec/index-spec.js index 5752865..ace10de 100644 --- a/spec/index-spec.js +++ b/spec/index-spec.js @@ -1,7 +1,8 @@ -describe('getDivAttribute', function() { - var d = document.querySelector('title'); - it('Should show the title of the index page', function() { - console.log("Title text = " + d.documentURI); - expect(d.innerHTML).toBe('Firechat - open source chat built on Firebase'); +describe('Loaded Libraries', function() { + it('The Firebase library should be loaded', function() { + var createFirebase = function() { + return new Firebase('https://brilliant-fire-2797.firebaseio.com'); + }; + expect(createFirebase).not.toThrow(); }); }); \ No newline at end of file From 602efe70995cd1c6a2bad7cd59ab0beef4a619bc Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Sat, 6 Jun 2015 16:43:03 -0400 Subject: [PATCH 18/29] Added spinner library --- src/js/libs/spin.min.js | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/js/libs/spin.min.js diff --git a/src/js/libs/spin.min.js b/src/js/libs/spin.min.js new file mode 100644 index 0000000..942980c --- /dev/null +++ b/src/js/libs/spin.min.js @@ -0,0 +1,2 @@ +//fgnass.github.com/spin.js#v1.2.7 +!function(e,t,n){function o(e,n){var r=t.createElement(e||"div"),i;for(i in n)r[i]=n[i];return r}function u(e){for(var t=1,n=arguments.length;t>1):parseInt(n.left,10)+i)+"px",top:(n.top=="auto"?a.y-u.y+(e.offsetHeight>>1):parseInt(n.top,10)+i)+"px"})),r.setAttribute("aria-role","progressbar"),t.lines(r,t.opts);if(!s){var f=0,l=n.fps,h=l/n.speed,d=(1-n.opacity)/(h*n.trail/100),v=h/n.lines;(function m(){f++;for(var e=n.lines;e;e--){var i=Math.max(1-(f+e*v)%h*d,n.opacity);t.opacity(r,n.lines-e,i,n)}t.timeout=t.el&&setTimeout(m,~~(1e3/l))})()}return t},stop:function(){var e=this.el;return e&&(clearTimeout(this.timeout),e.parentNode&&e.parentNode.removeChild(e),this.el=n),this},lines:function(e,t){function i(e,r){return c(o(),{position:"absolute",width:t.length+t.width+"px",height:t.width+"px",background:e,boxShadow:r,transformOrigin:"left",transform:"rotate("+~~(360/t.lines*n+t.rotate)+"deg) translate("+t.radius+"px"+",0)",borderRadius:(t.corners*t.width>>1)+"px"})}var n=0,r;for(;n',t)}var t=c(o("group"),{behavior:"url(#default#VML)"});!l(t,"transform")&&t.adj?(a.addRule(".spin-vml","behavior:url(#default#VML)"),v.prototype.lines=function(t,n){function s(){return c(e("group",{coordsize:i+" "+i,coordorigin:-r+" "+ -r}),{width:i,height:i})}function l(t,i,o){u(a,u(c(s(),{rotation:360/n.lines*t+"deg",left:~~i}),u(c(e("roundrect",{arcsize:n.corners}),{width:r,height:n.width,left:n.radius,top:-n.width>>1,filter:o}),e("fill",{color:n.color,opacity:n.opacity}),e("stroke",{opacity:0}))))}var r=n.length+n.width,i=2*r,o=-(n.width+n.length)*2+"px",a=c(s(),{position:"absolute",top:o,left:o}),f;if(n.shadow)for(f=1;f<=n.lines;f++)l(f,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(f=1;f<=n.lines;f++)l(f);return u(t,a)},v.prototype.opacity=function(e,t,n,r){var i=e.firstChild;r=r.shadow&&r.lines||0,i&&t+r Date: Fri, 12 Jun 2015 05:37:11 -0400 Subject: [PATCH 19/29] Added Upload File Event --- src/js/firechat-ui.js | 7 ++++--- templates/tab-content.html | 2 +- website/firechat-latest.js | 9 +++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/js/firechat-ui.js b/src/js/firechat-ui.js index 4889714..bcb4916 100644 --- a/src/js/firechat-ui.js +++ b/src/js/firechat-ui.js @@ -451,11 +451,12 @@ FirechatUI.prototype._bindForFileUpload = function() { var self = this, $el = $(this._el); - event.stopPropagation(); console.log("New Bind function added"); // Upon click of the file icon image - $(document).delegate('[data-event="firechat-user-file-upload"]', 'click', function(event) { - + console.log("Does the link exist? "); + $(document).delegate('[data-event="firechat-upload-file"]', 'click', function(event) { + event.stopPropagation(); + console.log("Clicked on the button!"); }); }; diff --git a/templates/tab-content.html b/templates/tab-content.html index 934f76e..27377e1 100644 --- a/templates/tab-content.html +++ b/templates/tab-content.html @@ -55,7 +55,7 @@ - + diff --git a/website/firechat-latest.js b/website/firechat-latest.js index ebbab14..b8214bd 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -36,7 +36,7 @@ this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = functio this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n+\n'; } ;__p += '\n\n
                                • ';}return __p}; -this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                  \n
                                  \n\n\nIn Room\n\n\n
                                  \n
                                    \n
                                    \n
                                    \n\n+\nInvite\n\n
                                    \n
                                    \n
                                    \n\n\n
                                    \n
                                    \n
                                      \n
                                      \n
                                      \n
                                      \n
                                      \n\n
                                      \n\n\n\n\n\n
                                      \n
                                      ';}return __p}; +this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                      \n
                                      \n\n\nIn Room\n\n\n
                                      \n
                                        \n
                                        \n
                                        \n\n+\nInvite\n\n
                                        \n
                                        \n
                                        \n\n\n
                                        \n
                                        \n
                                          \n
                                          \n
                                          \n
                                          \n
                                          \n\n
                                          \n\n\n\n\n\n
                                          \n
                                          ';}return __p}; this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                        • \n' +__e( name ) +'\n
                                        • ';}return __p}; @@ -1173,11 +1173,12 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct FirechatUI.prototype._bindForFileUpload = function() { var self = this, $el = $(this._el); - event.stopPropagation(); console.log("New Bind function added"); // Upon click of the file icon image - $(document).delegate('[data-event="firechat-user-file-upload"]', 'click', function(event) { - + console.log("Does the link exist? "); + $(document).delegate('[data-event="firechat-upload-file"]', 'click', function(event) { + event.stopPropagation(); + console.log("Clicked on the button!"); }); }; From d035f4b209f3ca6691c07c211a29c338974684d9 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Fri, 12 Jun 2015 14:09:33 -0400 Subject: [PATCH 20/29] Upload working better --- src/js/firechat-ui.js | 52 ++++++++++++++++++++++++++++++++--- src/less/styles.less | 4 +++ templates/tab-content.html | 10 ++++--- website/firechat-latest.css | 3 +++ website/firechat-latest.js | 54 +++++++++++++++++++++++++++++++++---- 5 files changed, 110 insertions(+), 13 deletions(-) diff --git a/src/js/firechat-ui.js b/src/js/firechat-ui.js index bcb4916..d15f312 100644 --- a/src/js/firechat-ui.js +++ b/src/js/firechat-ui.js @@ -450,14 +450,59 @@ */ FirechatUI.prototype._bindForFileUpload = function() { - var self = this, $el = $(this._el); - console.log("New Bind function added"); + var self = this; + var handleFileSelect = function(event) { + var f = event.target.files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var filePayload = e.target.result; + // Generate a location that can't be guessed using the file's contents and a random number + var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); + var f = new Firebase(firebaseRef + '/pano/' + hash + '/filePayload'); + spinner.spin(document.getElementById('spin')); + // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview + f.set(filePayload, function() { + spinner.stop(); + var imageFileName = firebaseRef + '/pano/' + hash + '/filePayload'; + console.log("File with hash: " + imageFileName + ' created'); + $('#file-upload').hide(); + var roomId = $("textarea").attr("id").replace(/textarea/, ""); + var message = self.trimWithEllipsis("File Uploaded from " + self._chat._userName, self.maxLengthMessage); + self._chat.sendMessage(roomId, message); + f.once('value', function(snap) { + var payload = snap.val(); + if (payload !== null) { + var uploadImg = $(''); + uploadImg.attr("src", payload); + uploadImg.appendTo($(".message").last()); + uploadImg.width(313); + uploadImg.show(); + } else { + $('#body').append("Not found"); + } + spinner.stop(); + }); + }); + }; + })(f); + reader.readAsDataURL(f); + }; // Upon click of the file icon image - console.log("Does the link exist? "); $(document).delegate('[data-event="firechat-upload-file"]', 'click', function(event) { event.stopPropagation(); console.log("Clicked on the button!"); + $('#file-upload').show(); + $("#file-upload").get(0).addEventListener('change', handleFileSelect, false); + }); + + // Upon completed file upload + $(document).delegate('[data-event="firechat-file-uploaded"]', 'change', function(event) { + event.stopPropagation(); + console.log("Upload Complete"); + // }); + }; /** @@ -1008,7 +1053,6 @@ isSelfMessage : (self._user && rawMessage.userId == self._user.id), disableActions : (!self._user || rawMessage.userId == self._user.id) }; - // While other data is escaped in the Underscore.js templates, escape and // process the message content here to add additional functionality (add links). // Also trim the message length to some client-defined maximum. diff --git a/src/less/styles.less b/src/less/styles.less index bc2a292..578ee8f 100644 --- a/src/less/styles.less +++ b/src/less/styles.less @@ -604,6 +604,10 @@ height: 35px; } + #uploaded-image { + display: none; + } + #upload-icon { position: absolute; float: right; diff --git a/templates/tab-content.html b/templates/tab-content.html index 27377e1..84209bc 100644 --- a/templates/tab-content.html +++ b/templates/tab-content.html @@ -53,10 +53,12 @@
                                          - - - - +
                                          diff --git a/website/firechat-latest.css b/website/firechat-latest.css index 6fe047b..3a0ead6 100644 --- a/website/firechat-latest.css +++ b/website/firechat-latest.css @@ -824,6 +824,9 @@ float: left; height: 35px; } +#firechat #uploaded-image { + display: none; +} #firechat #upload-icon { position: absolute; float: right; diff --git a/website/firechat-latest.js b/website/firechat-latest.js index b8214bd..d25c3dc 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -36,7 +36,7 @@ this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = functio this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                        • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n+\n'; } ;__p += '\n\n
                                        • ';}return __p}; -this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                          \n
                                          \n\n\nIn Room\n\n\n
                                          \n
                                            \n
                                            \n
                                            \n\n+\nInvite\n\n
                                            \n
                                            \n
                                            \n\n\n
                                            \n
                                            \n
                                              \n
                                              \n
                                              \n
                                              \n
                                              \n\n
                                              \n\n\n\n\n\n
                                              \n
                                              ';}return __p}; +this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                              \n
                                              \n\n\nIn Room\n\n\n
                                              \n
                                                \n
                                                \n
                                                \n\n+\nInvite\n\n
                                                \n
                                                \n
                                                \n\n\n
                                                \n
                                                \n
                                                  \n
                                                  \n
                                                  \n
                                                  \n
                                                  \n\n
                                                  \n\n\n
                                                  \n
                                                  ';}return __p}; this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                • \n' +__e( name ) +'\n
                                                • ';}return __p}; @@ -1172,14 +1172,59 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct */ FirechatUI.prototype._bindForFileUpload = function() { - var self = this, $el = $(this._el); - console.log("New Bind function added"); + var self = this; + var handleFileSelect = function(event) { + var f = event.target.files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var filePayload = e.target.result; + // Generate a location that can't be guessed using the file's contents and a random number + var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); + var f = new Firebase(firebaseRef + '/pano/' + hash + '/filePayload'); + spinner.spin(document.getElementById('spin')); + // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview + f.set(filePayload, function() { + spinner.stop(); + var imageFileName = firebaseRef + '/pano/' + hash + '/filePayload'; + console.log("File with hash: " + imageFileName + ' created'); + $('#file-upload').hide(); + var roomId = $("textarea").attr("id").replace(/textarea/, ""); + var message = self.trimWithEllipsis("File Uploaded from " + self._chat._userName, self.maxLengthMessage); + self._chat.sendMessage(roomId, message); + f.once('value', function(snap) { + var payload = snap.val(); + if (payload !== null) { + var uploadImg = $(''); + uploadImg.attr("src", payload); + uploadImg.appendTo($(".message").last()); + uploadImg.width(313); + uploadImg.show(); + } else { + $('#body').append("Not found"); + } + spinner.stop(); + }); + }); + }; + })(f); + reader.readAsDataURL(f); + }; // Upon click of the file icon image - console.log("Does the link exist? "); $(document).delegate('[data-event="firechat-upload-file"]', 'click', function(event) { event.stopPropagation(); console.log("Clicked on the button!"); + $('#file-upload').show(); + $("#file-upload").get(0).addEventListener('change', handleFileSelect, false); + }); + + // Upon completed file upload + $(document).delegate('[data-event="firechat-file-uploaded"]', 'change', function(event) { + event.stopPropagation(); + console.log("Upload Complete"); + // }); + }; /** @@ -1730,7 +1775,6 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct isSelfMessage : (self._user && rawMessage.userId == self._user.id), disableActions : (!self._user || rawMessage.userId == self._user.id) }; - // While other data is escaped in the Underscore.js templates, escape and // process the message content here to add additional functionality (add links). // Also trim the message length to some client-defined maximum. From 338cdfb1ad7aa60d64fe36a4581d06477a76d11d Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 15 Jun 2015 08:11:15 -0400 Subject: [PATCH 21/29] Updated version --- package.json | 2 +- spec/index-spec.js | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 spec/index-spec.js diff --git a/package.json b/package.json index 8678330..ffcc413 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "firechat", "description": "Realtime open source chat client powered by Firebase", - "version": "0.0.0", + "version": "2.1.0", "author": "Firebase (https://www.firebase.com/)", "homepage": "https://firechat.firebaseapp.com/", "repository": { diff --git a/spec/index-spec.js b/spec/index-spec.js deleted file mode 100644 index ace10de..0000000 --- a/spec/index-spec.js +++ /dev/null @@ -1,8 +0,0 @@ -describe('Loaded Libraries', function() { - it('The Firebase library should be loaded', function() { - var createFirebase = function() { - return new Firebase('https://brilliant-fire-2797.firebaseio.com'); - }; - expect(createFirebase).not.toThrow(); - }); -}); \ No newline at end of file From 87825afcf8f85def0f6292ee653ca95ec41c06bd Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 15 Jun 2015 08:28:52 -0400 Subject: [PATCH 22/29] Added distro --- .gitignore | 3 - dist/firechat.css | 968 ++++++++++++++++++++ dist/firechat.js | 1976 +++++++++++++++++++++++++++++++++++++++++ dist/firechat.min.css | 1 + dist/firechat.min.js | 3 + package.json | 2 +- 6 files changed, 2949 insertions(+), 4 deletions(-) create mode 100644 dist/firechat.css create mode 100644 dist/firechat.js create mode 100644 dist/firechat.min.css create mode 100644 dist/firechat.min.js diff --git a/.gitignore b/.gitignore index 6792931..00c0488 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,5 @@ node_modules/ # Bower bower_components/ -# Distribution files -dist/ - # Jekyll _site/ diff --git a/dist/firechat.css b/dist/firechat.css new file mode 100644 index 0000000..3a0ead6 --- /dev/null +++ b/dist/firechat.css @@ -0,0 +1,968 @@ +@charset "UTF-8"; +/* Boilerplate: Reset +============================================================ */ +#firechat div, +#firechat span, +#firechat applet, +#firechat object, +#firechat iframe, +#firechat h1, +#firechat h2, +#firechat h3, +#firechat h4, +#firechat h5, +#firechat h6, +#firechat p, +#firechat blockquote, +#firechat pre, +#firechat a, +#firechat abbr, +#firechat acronym, +#firechat address, +#firechat big, +#firechat cite, +#firechat code, +#firechat del, +#firechat dfn, +#firechat em, +#firechat img, +#firechat ins, +#firechat kbd, +#firechat q, +#firechat s, +#firechat samp, +#firechat small, +#firechat strike, +#firechat strong, +#firechat sub, +#firechat sup, +#firechat tt, +#firechat var, +#firechat b, +#firechat u, +#firechat i, +#firechat center, +#firechat dl, +#firechat dt, +#firechat dd, +#firechat ol, +#firechat ul, +#firechat li, +#firechat fieldset, +#firechat form, +#firechat label, +#firechat legend, +#firechat table, +#firechat caption, +#firechat tbody, +#firechat tfoot, +#firechat thead, +#firechat tr, +#firechat th, +#firechat td, +#firechat article, +#firechat aside, +#firechat canvas, +#firechat details, +#firechat embed, +#firechat figure, +#firechat figcaption, +#firechat footer, +#firechat header, +#firechat hgroup, +#firechat menu, +#firechat nav, +#firechat output, +#firechat ruby, +#firechat section, +#firechat summary, +#firechat time, +#firechat mark, +#firechat audio, +#firechat video { + border: 0; + font-size: 12px; + font-family: arial, helvetica, sans-serif; + vertical-align: baseline; + margin: 0; + padding: 0; +} +#firechat article, +#firechat aside, +#firechat details, +#firechat figcaption, +#firechat figure, +#firechat footer, +#firechat header, +#firechat hgroup, +#firechat menu, +#firechat nav, +#firechat section { + display: block; +} +#firechat body { + line-height: 1; +} +#firechat ol, +#firechat ul { + list-style: none; +} +#firechat blockquote, +#firechat q { + quotes: none; +} +#firechat blockquote:before, +#firechat blockquote:after, +#firechat q:before, +#firechat q:after { + content: none; +} +#firechat table { + border-collapse: collapse; + border-spacing: 0; +} +/* Boilerplate: Mixins +============================================================ */ +.clearfix { + *zoom: 1; +} +.clearfix:before, +.clearfix:after { + display: table; + content: ""; + line-height: 0; +} +.clearfix:after { + clear: both; +} +/* Boilerplate: Responsive Layout +============================================================ */ +#firechat { + color: #333; + text-align: left; +} +#firechat .center { + float: none !important; + margin-left: auto !important; + margin-right: auto !important; +} +#firechat .left { + float: left !important; +} +#firechat .right { + float: right !important; +} +#firechat .alignleft { + text-align: left !important; +} +#firechat .alignright { + text-align: right !important; +} +#firechat .aligncenter { + text-align: center !important; +} +#firechat .hidden { + display: none !important; +} +#firechat .row { + clear: both; +} +#firechat .fifth, +#firechat .fivesixth, +#firechat .fourfifth, +#firechat .half, +#firechat .ninetenth, +#firechat .quarter, +#firechat .sevententh, +#firechat .sixth, +#firechat .tenth, +#firechat .third, +#firechat .threefifth, +#firechat .threequarter, +#firechat .threetenth, +#firechat .twofifth, +#firechat .twothird, +#firechat .full { + margin-left: 2.127659574468085%; + float: left; + min-height: 1px; +} +#firechat .fifth:first-child, +#firechat .fivesixth:first-child, +#firechat .fourfifth:first-child, +#firechat .half:first-child, +#firechat .ninetenth:first-child, +#firechat .quarter:first-child, +#firechat .sevententh:first-child, +#firechat .sixth:first-child, +#firechat .tenth:first-child, +#firechat .third:first-child, +#firechat .threefifth:first-child, +#firechat .threequarter:first-child, +#firechat .threetenth:first-child, +#firechat .twofifth:first-child, +#firechat .twothird:first-child, +#firechat .full:first-child { + margin-left: 0; +} +#firechat .tenth { + width: 8.08510638297872%; +} +#firechat .sixth { + width: 14.893617021276595%; +} +#firechat .fifth { + width: 18.297872340425535%; +} +#firechat .quarter { + width: 23.404255319148938%; +} +#firechat .threetenth { + width: 26.3829787235%; +} +#firechat .third { + width: 31.914893617021278%; +} +#firechat .twofifth { + width: 38.72340425531915%; +} +#firechat .half { + width: 48.93617021276596%; +} +#firechat .sevententh { + width: 58.7234042555%; +} +#firechat .threefifth { + width: 59.14893617021278%; +} +#firechat .twothird { + width: 65.95744680851064%; +} +#firechat .threequarter { + width: 74.46808510638297%; +} +#firechat .ninetenth { + width: 74.8936170215%; +} +#firechat .fourfifth { + width: 79.57446808510639%; +} +#firechat .fivesixth { + width: 82.9787234042553%; +} +#firechat .full { + width: 100%; +} +#firechat .clipped { + overflow: hidden; +} +#firechat strong { + font-weight: bold; +} +#firechat em { + font-style: italic; +} +#firechat label { + display: block; +} +#firechat a { + color: #005580; +} +#firechat a:visited, +#firechat a:hover, +#firechat a:active { + color: #005580; +} +#firechat p { + margin: 10px 0; +} +#firechat h1, +#firechat h2, +#firechat h3, +#firechat h4, +#firechat h5, +#firechat h6 { + margin: 10px 0; + font-family: inherit; + font-weight: bold; + line-height: 20px; + color: inherit; +} +#firechat h1, +#firechat h2, +#firechat h3 { + line-height: 40px; +} +#firechat h1 { + font-size: 38.5px; +} +#firechat h2 { + font-size: 31.5px; +} +#firechat h3 { + font-size: 24.5px; +} +#firechat h4 { + font-size: 17.5px; +} +#firechat h5 { + font-size: 14px; +} +#firechat h6 { + font-size: 11.9px; +} +#firechat small { + font-size: 90%; +} +/* Component: Tabs +============================================================ */ +#firechat .nav { + list-style: none; +} +#firechat .nav > li > a { + display: block; + background-color: #eeeeee; + text-decoration: none; + overflow: hidden; + white-space: nowrap; +} +#firechat .nav > li > a:hover, +#firechat .nav > li > a:focus { + background-color: #ffffff; +} +#firechat .nav-tabs { + border-bottom: 1px solid #ddd; + clear: both; +} +#firechat .nav-tabs > li { + float: left; + margin-bottom: -1px; + max-width: 45%; +} +#firechat .nav-tabs > li > a { + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 0; + -webkit-border-bottom-left-radius: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 0; + -moz-border-radius-bottomleft: 0; + -moz-border-radius-topleft: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-top-left-radius: 4px; + padding: 4px 8px; + margin-right: 2px; + line-height: 20px; + border: 1px solid transparent; + border-color: #cccccc; +} +#firechat .nav-tabs > .active > a, +#firechat .nav-tabs > .active > a:hover, +#firechat .nav-tabs > .active > a:focus { + border-bottom-color: transparent; + background-color: #ffffff; + cursor: default; +} +#firechat .tab-content { + overflow: auto; +} +#firechat .tab-content > .tab-pane { + display: none; +} +#firechat .tab-content > .active { + display: block; + background-color: #ffffff; +} +/* Component: dropdowns +============================================================ */ +#firechat .caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; + margin-top: 8px; + margin-left: 2px; +} +#firechat .firechat-dropdown { + position: relative; +} +#firechat .firechat-dropdown-toggle { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-decoration: none; +} +#firechat .firechat-dropdown-toggle:focus, +#firechat .firechat-dropdown-toggle:active { + outline: none; + text-decoration: none; +} +#firechat .firechat-dropdown-toggle.btn { + padding: 4px 0 0; + height: 22px; +} +#firechat .firechat-dropdown-menu { + *zoom: 1; + -webkit-border-top-right-radius: 0; + -webkit-border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 0; + -moz-border-radius-topright: 0; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + border-top-left-radius: 0; + z-index: 1000; + display: none; + float: left; + position: absolute; + top: 100%; + left: 0; + width: 100%; + background-color: #ffffff; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; + border: 1px solid #ccc; + min-width: 98%; + padding: 0; + margin: -1px 0 0; +} +#firechat .firechat-dropdown-menu:before, +#firechat .firechat-dropdown-menu:after { + display: table; + content: ""; + line-height: 0; +} +#firechat .firechat-dropdown-menu:after { + clear: both; +} +#firechat .firechat-dropdown-menu ul { + background-color: #ffffff; + list-style: none; + overflow-y: scroll; + max-height: 300px; +} +#firechat .firechat-dropdown-menu ul > li > a { + display: block; + padding: 1px 1px 1px 3px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} +#firechat .firechat-dropdown-menu ul > li > a.highlight { + background-color: #d9edf7; +} +#firechat .firechat-dropdown-menu ul > li > a:hover, +#firechat .firechat-dropdown-menu ul > li > a:focus, +#firechat .firechat-dropdown-menu ul > .active > a, +#firechat .firechat-dropdown-menu ul > .active > a:hover, +#firechat .firechat-dropdown-menu ul > .active > a:focus { + text-decoration: none; + color: #000000; + background-color: #d9edf7; + outline: 0; +} +#firechat .firechat-dropdown-menu ul > .disabled > a, +#firechat .firechat-dropdown-menu ul > .disabled > a:hover, +#firechat .firechat-dropdown-menu ul > .disabled > a:focus { + color: #999999; + text-decoration: none; + background-color: transparent; + background-image: none; + cursor: default; +} +#firechat .firechat-dropdown-header { + position: relative; + width: 100%; + padding: 10px 0; + background-color: #eeeeee; + border-bottom: 1px solid #cccccc; +} +#firechat .firechat-dropdown-footer { + position: relative; + width: 100%; + padding: 10px 0px; + background-color: #eeeeee; + border-top: 1px solid #cccccc; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +#firechat .open { + *z-index: 1000; +} +#firechat .open > .firechat-dropdown-menu { + display: block; + border: 1px solid #cccccc; + -webkit-border-top-right-radius: 0; + -webkit-border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 0; + -moz-border-radius-topright: 0; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + border-top-left-radius: 0; +} +#firechat .open > .firechat-dropdown-toggle { + outline: none; + text-decoration: none; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 0; + -webkit-border-bottom-left-radius: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 0; + -moz-border-radius-bottomleft: 0; + -moz-border-radius-topleft: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-top-left-radius: 4px; +} +/* Component: Prompts +============================================================ */ +#firechat .prompt-wrapper { + position: absolute; + z-index: 1000; +} +#firechat .prompt { + position: absolute; + z-index: 1001; + background-color: #ffffff; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45); +} +#firechat .prompt-header { + padding: 4px 8px; + font-weight: bold; + background-color: #eeeeee; + border: 1px solid #cccccc; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 0; + -webkit-border-bottom-left-radius: 0; + -webkit-border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 0; + -moz-border-radius-bottomleft: 0; + -moz-border-radius-topleft: 4px; + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-top-left-radius: 4px; +} +#firechat .prompt-header a.close { + opacity: 0.6; + font-size: 13px; + margin-top: 2px; +} +#firechat .prompt-header a.close:hover { + opacity: 0.9; +} +#firechat .prompt-body { + background-color: #ffffff; + padding: 4px 8px; + border-left: 1px solid #cccccc; + border-right: 1px solid #cccccc; +} +#firechat .prompt-footer { + padding: 4px 8px; + background-color: #eeeeee; + border: 1px solid #cccccc; + -webkit-border-top-right-radius: 0; + -webkit-border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 0; + -moz-border-radius-topright: 0; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + border-top-left-radius: 0; +} +#firechat .prompt-background { + background-color: #333333; + border: 1px solid #333333; + opacity: 0.8; + z-index: 1000; + height: 100%; + width: 100%; +} +/* Component: Buttons +============================================================ */ +#firechat .btn { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + height: 24px; + display: inline-block; + *display: inline; + *zoom: 1; + padding: 2px 5px; + margin-bottom: 0; + text-align: center; + vertical-align: middle; + cursor: pointer; + color: #333333; + font-size: 12px; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + *background-color: #e6e6e6; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + border: 1px solid #cccccc; + *border: 0; + border-bottom-color: #b3b3b3; + *margin-left: .3em; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} +#firechat .btn:hover, +#firechat .btn:focus, +#firechat .btn:active, +#firechat .btn.active, +#firechat .btn.disabled, +#firechat .btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; + outline: 0; +} +#firechat .btn:active, +#firechat .btn.active { + background-color: #cccccc; +} +#firechat .btn:first-child { + *margin-left: 0; +} +#firechat .btn:hover, +#firechat .btn:focus { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} +#firechat .btn.active, +#firechat .btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} +#firechat .btn.disabled, +#firechat .btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); +} +#firechat .btn.disabled:active, +#firechat .btn[disabled]:active { + -webkit-box-shadow: inherit; + -moz-box-shadow: inherit; + box-shadow: inherit; + background-color: #e6e6e6; +} +/* Component: Context Menu +============================================================ */ +#firechat .contextmenu { + position: fixed; + z-index: 1001; + min-width: 150px; + border: 1px solid #cccccc; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +#firechat .contextmenu ul { + background-color: #ffffff; + list-style: none; +} +#firechat .contextmenu ul > li > a { + display: block; + padding: 3px 10px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} +#firechat .contextmenu ul > li > a.highlight { + background-color: #d9edf7; +} +#firechat .contextmenu ul > li > a:hover, +#firechat .contextmenu ul > li > a:focus { + text-decoration: none; + color: #ffffff; + background-color: #0081c2; + outline: 0; +} +/* Custom Styles +============================================================ */ +#firechat { + padding: 0; + font-family: sans-serif; + font-size: 12px; + line-height: 18px; +} +#firechat input, +#firechat textarea { + width: 100%; + font-family: sans-serif; + font-size: 12px; + line-height: 18px; + padding: 2px 5px; + border: 1px solid #cccccc; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +#firechat input:-moz-placeholder, +#firechat textarea:-moz-placeholder { + color: #aaaaaa; +} +#firechat input:-ms-input-placeholder, +#firechat textarea:-ms-input-placeholder { + color: #aaaaaa; +} +#firechat input::-webkit-input-placeholder, +#firechat textarea::-webkit-input-placeholder { + color: #aaaaaa; +} +#firechat input[disabled], +#firechat textarea[disabled] { + background-color: #eeeeee; +} +#firechat input { + height: 24px; +} +#firechat textarea { + resize: none; + height: 40px; +} +#firechat .search-wrapper { + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + border: 1px solid #cccccc; + margin: 0 5px; + padding: 2px 5px; + background: #ffffff; +} +#firechat .search-wrapper > input[type=text] { + padding-left: 0px; + border: none; +} +#firechat .search-wrapper > input[type=text]:focus, +#firechat .search-wrapper > input[type=text]:active { + outline: 0; +} +#firechat .chat { + overflow: auto; + -ms-overflow-x: hidden; + overflow-x: hidden; + height: 290px; + position: relative; + margin-bottom: 5px; + border: 1px solid #cccccc; + border-top: none; + overflow-y: scroll; +} +#firechat .chat textarea { + overflow: auto; + vertical-align: top; +} +#firechat #textarea-container { + position: relative; + width: 100%; + float: left; + height: 35px; +} +#firechat #uploaded-image { + display: none; +} +#firechat #upload-icon { + position: absolute; + float: right; + height: 16px; + width: 18px; + bottom: 0px; + right: 5px; +} +#firechat #file-upload { + display: none; + position: relative; + overflow: hidden; + z-index: 2; + opacity: 0; +} +#firechat .message { + color: #333; + padding: 3px 5px; + border-bottom: 1px solid #ccc; +} +#firechat .message.highlighted { + background-color: #d9edf7; +} +#firechat .message .name { + font-weight: bold; + overflow-x: hidden; +} +#firechat .message.message-self { + color: #2675ab; +} +#firechat .message:nth-child(odd) { + background-color: #f9f9f9; +} +#firechat .message:nth-child(odd).highlighted { + background-color: #d9edf7; +} +#firechat .message:nth-child(odd).message-local { + background-color: #effafc; +} +#firechat .message-content { + word-wrap: break-word; + padding-right: 45px; +} +#firechat .message-content.red { + color: red; +} +#firechat .message.message-notification .message-content { + font-style: italic; +} +#firechat ul::-webkit-scrollbar { + -webkit-appearance: none; + width: 7px; +} +#firechat ul::-webkit-scrollbar-thumb { + border-radius: 4px; + -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, 0.5); +} +#firechat #firechat-header { + padding: 6px 0 0 0; + height: 40px; +} +#firechat #firechat-tabs { + height: 435px; +} +#firechat #firechat-tab-list { + background-color: #ffffff; +} +#firechat #firechat-tab-content { + width: 100%; + background-color: #ffffff; +} +#firechat .tab-pane-menu { + border: 1px solid #ccc; + border-top: none; + vertical-align: middle; + padding-bottom: 5px; +} +#firechat .tab-pane-menu .firechat-dropdown { + margin: 5px 0 0 5px; +} +#firechat .tab-pane-menu > .icon { + margin: 5px 2px 0; +} +#firechat .icon { + display: inline-block; + *margin-right: .3em; + line-height: 20px; + vertical-align: middle; + background-repeat: no-repeat; + padding: 0; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAL8AAAANEAYAAACoeGM7AAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAM80lEQVR42t2cZ4xWRRfHZ3dhwbK7CJZYYiOxV+wlUQzCKmBBsWPvYjQiaiyxYUwULLErltgrNpRF4q5iV0BRLFE0diUi7LIq6Pqw74f//rzO4Zm9d+5z9c37ni//3OfemXtm5sypc58q55xzrrpauHSpcOONheedJ9x9d2Hv3sLvvxfefbfw5puFf/5Zvr+8VFUl7Ozs/rkNNxTef79w222F77wjPOoo4ccfF/O+UDvGzTVEf8wH1zU1wlJJePTRwv33Fx57rPDnn/1+wbzzG+IXvrhmPUPzY/kJEc/HzqslK1fLLy8cMUK4667CFVYQ/vqr8PXXhU884f8eL6eXXKJ2wqSd3tDY2KOHc84NGqSRnnCC7tbVCdvbhRMnasWnTdt5Z+eca2pK6797Yh6ef1641lrCPfYQfv21UNwl62qv115b2Nws/PZb4d57C3/7LftalaOQ/C63nPCII4Tsg6228scHffqp8LHHhPfe6/8eu49feEH44YfCq64S/v67cMGC7tuvu65w6FDhllsKkS/0zoQJaZzMmSO+JaEzZmgkY8b88Ydzzs2b19HhnHNffSWJ6tVLM1cq/fKLrjXiUaPUrn9/XZ9yip6rqVmyxDnnnnrKvPbAA4V6TTJxP/zgT4zdyC+9JOzXz++PgceSVSS1tUJtE+c22si/f+21Pj9Wwd54o//8ZpsJd9xR2KtX9+8vmkLzcsABPt9z5wr32af88xiOf4oaGoSHH17M+/LKg203aJDwiy+EVh5DyHzuuWcxfDn31lvOOffMM7Nn6z1SsZ2dn30m/OQT4eefC7/8UvjBB0LaVzav7D873vfeE6LQISvv3Of50P6OJetgWFp5ZeFzz5V/b1bEEd1333x80g+O4mWXCXEQMDB33CG8/XYhBhuDmMZnOn30kZ5/+23nnGtpefNN55wbP96Xl/nzhYsWCdvauEbeQP1Of6US/XRZfDz8Bx8U9uwpPPFE4eOPC/EMVl9dOG6ccORI4Q03CA87LHbA5RcCwgO47TbhokXCYcOERCKQ7GJiMLiPokeQ2QCjRwtvukkY6zHg0V10kXDAAH++EIz77hM++aRwxRWFq64q3H57v9/+/YVPPy2cOFF47rnCNE8kll/Gi4eIAWU9v/vOnz8MA4qjb18hG51+2JiLF+ebX/hA4U+b5t+/7jrhAw8IkQ88WvnPiZzi4Q0eXL6/dEJhawaGDydmk4uEQmhu1kj79tVImb8RI8TZwIG0p78ddnAubOhDhIcPIXd4nnh4OHYYzPXXF7K/ed5GBLb/NLKRFOtMfyCZAiIKns8aSVp9xP4i8nv//Ti+icjgl0iDeUsjpKDSyJYeqqs1A+3taDBpkn79Qi5YW9vf5wXq0YP+1L5U6loAUjpW4WPhQhN00EFC2SXnDj1UiAF44w2hTWnEEqkcCIWJYkShQNbDIIJZZx2h9Xhs/7EpFDwCNs6UKf584tGQsiFCGTJEuMEG/jxBzBe/H3+8cJddhBiAZ58thl/eM2uW8MgjhWyAyy8XojhRUGuuKayvF7Jhf/pJ+O67wltvFU6dGscv78fTgg45RPjII+XbYZA23bT8/Vtu8ecBDy9MpHS0EROFr1B76lQp7r32su20EwYMkGSOG4dq4I0a4fDh9G9TQN0TKR0iB8aD3G+9tRDHDoPPenKf53GYiABiPWm7f046SUgKDs8aQwxlVfiQTVXh0BChxir+kDol5WPv24im+Ahcb6iu9jVnR4euGX9oXsLj7GKYHP68eUI8ANsRA7WKE8sNkUopdvgJsW0QUBbc3oewl6GQs9LUDgr85JOF5OZHjRKyESZNEp55ppBIC7IbxgoSkQzt2OgXX1wMv9RCFBAuG4HgSREKU0vB42Jjo6gxtPvtJ8TzTM91+kQOf731hHj4KHybA0bRK8B1bpNNhAqkE8OH40CKLZ3I4a+0kq6l8JuapPAbGx991Lm/r5s8+aFDlWOdOVMuS0ODNm5bm1RWSwsSrJY2FZVGRFYYYgwt+wO5EpeJ4eaa+zxPexQ+/Wcl+iFCxeBvs43QRujW048lu09Y16KI/m3Ewu8h/VS55w/5b7AGMrbW5lyXImQh8EhtqGBDGOu525QDnm5RhOcBzZ8vfO01IYIaev/Mmf5zpALsfSiv5bYLfeqpQhSUrYHY92GYbD+shx0XKSOKlrFk1xHFTQRon7M1FNtepaOErwsvFBIqkzKKlQ8MDoTnCpFKwyCi2FZbTYhDgydO6gfaaaesnFC0xQcUUQwlBi6VpPCHDJGKmDyZGWMldY2nPmmSP5NEdlkJRYSCZr7FRbiIzTX3eZ72tiiclZjf444rzyd6hkid9+fNCNhxvfJKvn5C/YVy9nZVYw89ZCdfI6TVEuCLCI4Zhp+Ojq6FIAdLFR0PjpQOFpyFsQMidw5ZxRo7ATaEI6fMgFD8FJsxXCgee00qSiWPJNfKaYLp08u/P1YQ4ZfxWgWDAcOjZmMR8G+3nZBTPbwffhYuFJ5zjhCPKi9ZBUzkh8dpBTkk2KSKLr1UiAIJEYYhK2GQIOto4OGj8NdYQ4hck8tnvkmtQSGDHKK6On8nUNtIPHwUvp05SeSwYTI1s2YpJhk5kliO/uP4Qe6IxMnhk9JhXqyCtQ4Oz9Oe/nwzl05EtJbI5fMeTs8QscIP+zwtEuA+csz+fvjhOH5tf6SSoZCjEipeKw5MVj12PemZ9tXVvunt2dOuHE+K06oqvbG2lp2ikS1ZIknv3burO45lXn+9kKItOfzQwhO6jR0r5PiXPaUQmzNHkMllIyhMMBudmgKnjqxnwnSssooQhWpTLOR6UVwc/4ul1lYhx7rwRBF4PBEEwxLFavhkeTmmN2aMEAG3ghdrqHx149z555efx9DGY37vvFNoPcxQe1v0SyObe8cRIYf/4otCPHwUPsVge4yXWgTEumWl9nZtsPp6irbk8OVyTJ5sYyRJdGOjkitJjUP3FyzwNzIOV1ZivdinFG3J4dt5twqW9eJ5nUFKDIB1xNIIh8p6oijUa64RcnyT2SLSJHWXdtqKcdD/BRcIifBiCf44TIGe2WILYaiGhWHFoaFGxnxtvnlWDvwZY/yLF6toy+8LF2rGamrESXK8WRIwe7YcjKYmzdD06Xpi7lzFWqR4/1pYeywMT5ncL4rpiiuE9tgnIRyeozP9ZyVSBNZyskHxpFFUCGroOCf36Zf28MtzRCqxOXPaM24iJxsJQQgOCgyiqM4GJvduKZRbjOWXXH+fPkKKiUQmOnyYRBrwZeeXCIxxQ/mPSfpEkZn3KZO+7PHiH38U2mKurQHY478ooHSSaZswgWOZum5uFra2iqPOTs0g93EE4NzWAKZM4RioIoDx4/PNE4YQxWNTs6HUgL1Pe3sMNCuF9qOVG2penIPHYOHokcJ8+WVhS4sQR4NaJP3F7luI9tSALBFxovhBW6uonFSORm7mzMEAzJjhnHMNDdLI9fXgq68651xdnZLYffpY+cpIhLzkUNNySd98I7QKFPs0cGC+4dv3sCAYIE4bhXJboWvwrruExxwjJPWStyjD8/b0AyEiCt4Wh6xBpCi+225CG5kUdWogxC/HMyldshGJ7IhcWIfTTxciLxhWqKgcJxuPc/h2nTAAaYrq4IP9dni01jCEiVM3nIdWdaizUxuTDdvaSgQQ6kfPNTVhKPgOgP7j5id0Dh9DbR05Unlch54PfQeQRuyrUM7ZOoxkCq6+WkikhiOBIQ/JEx7sGWfE8QlZOYKyOi7sS+uQgdn3ra/4LT/ZSS1razEEfBgoOf0rdRUaIB4rXyCedpqQFAu5KzxdPyBJPPRlj7d1Tw89JLznHiGeb+hDFVIWIQPll9SS3ynKUUwj5RWbI6Q/inWVEgJsUxRFKdKi+T3rLKEtshf9IZytPdgIgNM75PA5dWQ9fBAFE0+cu+dDGQyAHwGMHi0P/sordT12LB4+Ct//0Cbvh1zWINr9gAePIYe4thGCbU//sYRHn/fDLBwyawhDOfe8ESbvCx3/zHuKJp5Cil8cVlVlxcjXhv5yICvh4aPwreDlJY5nUay1Cj2rINn2lD4qPX6KwcPzRQHhKeP5WeQ+ng2nSyhCcv4fKip1EuIXRQlfXIMUn7nPl9SkhKhFFM2v7QcDEIoAQoiHbxV+5V/uEgGQAuJLXRQ7X/KS0sHD///8cpcIl/P69MN3GDh2RBzUvvjLFVI2NuK1einty+CsZDMY/z0qyuOvkGwIY8+zMuE2ZYGHj8JHUWQlm/sm1ENRZ81dWrShLEVAy1/20F9EEZrTQnk9HJCNYL+YLMrD+F/jF7IbnBQQNQDOi/MFJ9fk8O26xisMQmb7OykaagD+p/RLl3JNDj+U0gn13z0xLhQ0BtEqfLtP7TXP057+YvcDCpvDInwvYInUcnIqqjLKK2/IydlnF8NHfvq3FP9/ANgTCJ9z9ZF7AAAAAElFTkSuQmCC) no-repeat top left; + opacity: 0.3; + font-size: 22px; + font-family: Arial; + font-weight: bold; + overflow: hidden; +} +#firechat .icon.plus { + margin-top: 0; + vertical-align: top; + background: transparent; +} +#firechat .icon.search { + background-position: 0 0; + width: 13px; + height: 13px; +} +#firechat .icon.close { + background-position: -120px 0; + width: 13px; + height: 13px; +} +#firechat .icon.user-chat { + background-position: -138px 0; + width: 17px; + height: 13px; +} +#firechat .icon.user-group { + background-position: -18px 0; + width: 17px; + height: 13px; +} +#firechat .icon.user-mute { + background-position: -84px 0; + width: 13px; + height: 13px; +} +#firechat .icon.user-mute.red { + background-position: -102px 0; + width: 13px; + height: 13px; +} +#firechat .icon:hover, +#firechat .btn:hover > .icon { + opacity: 0.6; +} +#firechat a > .icon { + margin: 3px 1px; +} diff --git a/dist/firechat.js b/dist/firechat.js new file mode 100644 index 0000000..d25c3dc --- /dev/null +++ b/dist/firechat.js @@ -0,0 +1,1976 @@ +// Underscore.js 1.7.0 +// http://underscorejs.org +// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Underscore may be freely distributed under the MIT license. +(function(){var n=this,t=n._,r=Array.prototype,e=Object.prototype,u=Function.prototype,i=r.push,a=r.slice,o=r.concat,l=e.toString,c=e.hasOwnProperty,f=Array.isArray,s=Object.keys,p=u.bind,h=function(n){return n instanceof h?n:this instanceof h?void(this._wrapped=n):new h(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=h),exports._=h):n._=h,h.VERSION="1.7.0";var g=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}};h.iteratee=function(n,t,r){return null==n?h.identity:h.isFunction(n)?g(n,t,r):h.isObject(n)?h.matches(n):h.property(n)},h.each=h.forEach=function(n,t,r){if(null==n)return n;t=g(t,r);var e,u=n.length;if(u===+u)for(e=0;u>e;e++)t(n[e],e,n);else{var i=h.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},h.map=h.collect=function(n,t,r){if(null==n)return[];t=h.iteratee(t,r);for(var e,u=n.length!==+n.length&&h.keys(n),i=(u||n).length,a=Array(i),o=0;i>o;o++)e=u?u[o]:o,a[o]=t(n[e],e,n);return a};var v="Reduce of empty array with no initial value";h.reduce=h.foldl=h.inject=function(n,t,r,e){null==n&&(n=[]),t=g(t,e,4);var u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length,o=0;if(arguments.length<3){if(!a)throw new TypeError(v);r=n[i?i[o++]:o++]}for(;a>o;o++)u=i?i[o]:o,r=t(r,n[u],u,n);return r},h.reduceRight=h.foldr=function(n,t,r,e){null==n&&(n=[]),t=g(t,e,4);var u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;if(arguments.length<3){if(!a)throw new TypeError(v);r=n[i?i[--a]:--a]}for(;a--;)u=i?i[a]:a,r=t(r,n[u],u,n);return r},h.find=h.detect=function(n,t,r){var e;return t=h.iteratee(t,r),h.some(n,function(n,r,u){return t(n,r,u)?(e=n,!0):void 0}),e},h.filter=h.select=function(n,t,r){var e=[];return null==n?e:(t=h.iteratee(t,r),h.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e)},h.reject=function(n,t,r){return h.filter(n,h.negate(h.iteratee(t)),r)},h.every=h.all=function(n,t,r){if(null==n)return!0;t=h.iteratee(t,r);var e,u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;for(e=0;a>e;e++)if(u=i?i[e]:e,!t(n[u],u,n))return!1;return!0},h.some=h.any=function(n,t,r){if(null==n)return!1;t=h.iteratee(t,r);var e,u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;for(e=0;a>e;e++)if(u=i?i[e]:e,t(n[u],u,n))return!0;return!1},h.contains=h.include=function(n,t){return null==n?!1:(n.length!==+n.length&&(n=h.values(n)),h.indexOf(n,t)>=0)},h.invoke=function(n,t){var r=a.call(arguments,2),e=h.isFunction(t);return h.map(n,function(n){return(e?t:n[t]).apply(n,r)})},h.pluck=function(n,t){return h.map(n,h.property(t))},h.where=function(n,t){return h.filter(n,h.matches(t))},h.findWhere=function(n,t){return h.find(n,h.matches(t))},h.max=function(n,t,r){var e,u,i=-1/0,a=-1/0;if(null==t&&null!=n){n=n.length===+n.length?n:h.values(n);for(var o=0,l=n.length;l>o;o++)e=n[o],e>i&&(i=e)}else t=h.iteratee(t,r),h.each(n,function(n,r,e){u=t(n,r,e),(u>a||u===-1/0&&i===-1/0)&&(i=n,a=u)});return i},h.min=function(n,t,r){var e,u,i=1/0,a=1/0;if(null==t&&null!=n){n=n.length===+n.length?n:h.values(n);for(var o=0,l=n.length;l>o;o++)e=n[o],i>e&&(i=e)}else t=h.iteratee(t,r),h.each(n,function(n,r,e){u=t(n,r,e),(a>u||1/0===u&&1/0===i)&&(i=n,a=u)});return i},h.shuffle=function(n){for(var t,r=n&&n.length===+n.length?n:h.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=h.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},h.sample=function(n,t,r){return null==t||r?(n.length!==+n.length&&(n=h.values(n)),n[h.random(n.length-1)]):h.shuffle(n).slice(0,Math.max(0,t))},h.sortBy=function(n,t,r){return t=h.iteratee(t,r),h.pluck(h.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var m=function(n){return function(t,r,e){var u={};return r=h.iteratee(r,e),h.each(t,function(e,i){var a=r(e,i,t);n(u,e,a)}),u}};h.groupBy=m(function(n,t,r){h.has(n,r)?n[r].push(t):n[r]=[t]}),h.indexBy=m(function(n,t,r){n[r]=t}),h.countBy=m(function(n,t,r){h.has(n,r)?n[r]++:n[r]=1}),h.sortedIndex=function(n,t,r,e){r=h.iteratee(r,e,1);for(var u=r(t),i=0,a=n.length;a>i;){var o=i+a>>>1;r(n[o])t?[]:a.call(n,0,t)},h.initial=function(n,t,r){return a.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},h.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:a.call(n,Math.max(n.length-t,0))},h.rest=h.tail=h.drop=function(n,t,r){return a.call(n,null==t||r?1:t)},h.compact=function(n){return h.filter(n,h.identity)};var y=function(n,t,r,e){if(t&&h.every(n,h.isArray))return o.apply(e,n);for(var u=0,a=n.length;a>u;u++){var l=n[u];h.isArray(l)||h.isArguments(l)?t?i.apply(e,l):y(l,t,r,e):r||e.push(l)}return e};h.flatten=function(n,t){return y(n,t,!1,[])},h.without=function(n){return h.difference(n,a.call(arguments,1))},h.uniq=h.unique=function(n,t,r,e){if(null==n)return[];h.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=h.iteratee(r,e));for(var u=[],i=[],a=0,o=n.length;o>a;a++){var l=n[a];if(t)a&&i===l||u.push(l),i=l;else if(r){var c=r(l,a,n);h.indexOf(i,c)<0&&(i.push(c),u.push(l))}else h.indexOf(u,l)<0&&u.push(l)}return u},h.union=function(){return h.uniq(y(arguments,!0,!0,[]))},h.intersection=function(n){if(null==n)return[];for(var t=[],r=arguments.length,e=0,u=n.length;u>e;e++){var i=n[e];if(!h.contains(t,i)){for(var a=1;r>a&&h.contains(arguments[a],i);a++);a===r&&t.push(i)}}return t},h.difference=function(n){var t=y(a.call(arguments,1),!0,!0,[]);return h.filter(n,function(n){return!h.contains(t,n)})},h.zip=function(n){if(null==n)return[];for(var t=h.max(arguments,"length").length,r=Array(t),e=0;t>e;e++)r[e]=h.pluck(arguments,e);return r},h.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},h.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=h.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}for(;u>e;e++)if(n[e]===t)return e;return-1},h.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=n.length;for("number"==typeof r&&(e=0>r?e+r+1:Math.min(e,r+1));--e>=0;)if(n[e]===t)return e;return-1},h.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=r||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=Array(e),i=0;e>i;i++,n+=r)u[i]=n;return u};var d=function(){};h.bind=function(n,t){var r,e;if(p&&n.bind===p)return p.apply(n,a.call(arguments,1));if(!h.isFunction(n))throw new TypeError("Bind must be called on a function");return r=a.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(a.call(arguments)));d.prototype=n.prototype;var u=new d;d.prototype=null;var i=n.apply(u,r.concat(a.call(arguments)));return h.isObject(i)?i:u}},h.partial=function(n){var t=a.call(arguments,1);return function(){for(var r=0,e=t.slice(),u=0,i=e.length;i>u;u++)e[u]===h&&(e[u]=arguments[r++]);for(;r=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=h.bind(n[r],n);return n},h.memoize=function(n,t){var r=function(e){var u=r.cache,i=t?t.apply(this,arguments):e;return h.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},h.delay=function(n,t){var r=a.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},h.defer=function(n){return h.delay.apply(h,[n,1].concat(a.call(arguments,1)))},h.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var l=function(){o=r.leading===!1?0:h.now(),a=null,i=n.apply(e,u),a||(e=u=null)};return function(){var c=h.now();o||r.leading!==!1||(o=c);var f=t-(c-o);return e=this,u=arguments,0>=f||f>t?(clearTimeout(a),a=null,o=c,i=n.apply(e,u),a||(e=u=null)):a||r.trailing===!1||(a=setTimeout(l,f)),i}},h.debounce=function(n,t,r){var e,u,i,a,o,l=function(){var c=h.now()-a;t>c&&c>0?e=setTimeout(l,t-c):(e=null,r||(o=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,a=h.now();var c=r&&!e;return e||(e=setTimeout(l,t)),c&&(o=n.apply(i,u),i=u=null),o}},h.wrap=function(n,t){return h.partial(t,n)},h.negate=function(n){return function(){return!n.apply(this,arguments)}},h.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},h.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},h.before=function(n,t){var r;return function(){return--n>0?r=t.apply(this,arguments):t=null,r}},h.once=h.partial(h.before,2),h.keys=function(n){if(!h.isObject(n))return[];if(s)return s(n);var t=[];for(var r in n)h.has(n,r)&&t.push(r);return t},h.values=function(n){for(var t=h.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},h.pairs=function(n){for(var t=h.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},h.invert=function(n){for(var t={},r=h.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},h.functions=h.methods=function(n){var t=[];for(var r in n)h.isFunction(n[r])&&t.push(r);return t.sort()},h.extend=function(n){if(!h.isObject(n))return n;for(var t,r,e=1,u=arguments.length;u>e;e++){t=arguments[e];for(r in t)c.call(t,r)&&(n[r]=t[r])}return n},h.pick=function(n,t,r){var e,u={};if(null==n)return u;if(h.isFunction(t)){t=g(t,r);for(e in n){var i=n[e];t(i,e,n)&&(u[e]=i)}}else{var l=o.apply([],a.call(arguments,1));n=new Object(n);for(var c=0,f=l.length;f>c;c++)e=l[c],e in n&&(u[e]=n[e])}return u},h.omit=function(n,t,r){if(h.isFunction(t))t=h.negate(t);else{var e=h.map(o.apply([],a.call(arguments,1)),String);t=function(n,t){return!h.contains(e,t)}}return h.pick(n,t,r)},h.defaults=function(n){if(!h.isObject(n))return n;for(var t=1,r=arguments.length;r>t;t++){var e=arguments[t];for(var u in e)n[u]===void 0&&(n[u]=e[u])}return n},h.clone=function(n){return h.isObject(n)?h.isArray(n)?n.slice():h.extend({},n):n},h.tap=function(n,t){return t(n),n};var b=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof h&&(n=n._wrapped),t instanceof h&&(t=t._wrapped);var u=l.call(n);if(u!==l.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]===n)return e[i]===t;var a=n.constructor,o=t.constructor;if(a!==o&&"constructor"in n&&"constructor"in t&&!(h.isFunction(a)&&a instanceof a&&h.isFunction(o)&&o instanceof o))return!1;r.push(n),e.push(t);var c,f;if("[object Array]"===u){if(c=n.length,f=c===t.length)for(;c--&&(f=b(n[c],t[c],r,e)););}else{var s,p=h.keys(n);if(c=p.length,f=h.keys(t).length===c)for(;c--&&(s=p[c],f=h.has(t,s)&&b(n[s],t[s],r,e)););}return r.pop(),e.pop(),f};h.isEqual=function(n,t){return b(n,t,[],[])},h.isEmpty=function(n){if(null==n)return!0;if(h.isArray(n)||h.isString(n)||h.isArguments(n))return 0===n.length;for(var t in n)if(h.has(n,t))return!1;return!0},h.isElement=function(n){return!(!n||1!==n.nodeType)},h.isArray=f||function(n){return"[object Array]"===l.call(n)},h.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},h.each(["Arguments","Function","String","Number","Date","RegExp"],function(n){h["is"+n]=function(t){return l.call(t)==="[object "+n+"]"}}),h.isArguments(arguments)||(h.isArguments=function(n){return h.has(n,"callee")}),"function"!=typeof/./&&(h.isFunction=function(n){return"function"==typeof n||!1}),h.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},h.isNaN=function(n){return h.isNumber(n)&&n!==+n},h.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===l.call(n)},h.isNull=function(n){return null===n},h.isUndefined=function(n){return n===void 0},h.has=function(n,t){return null!=n&&c.call(n,t)},h.noConflict=function(){return n._=t,this},h.identity=function(n){return n},h.constant=function(n){return function(){return n}},h.noop=function(){},h.property=function(n){return function(t){return t[n]}},h.matches=function(n){var t=h.pairs(n),r=t.length;return function(n){if(null==n)return!r;n=new Object(n);for(var e=0;r>e;e++){var u=t[e],i=u[0];if(u[1]!==n[i]||!(i in n))return!1}return!0}},h.times=function(n,t,r){var e=Array(Math.max(0,n));t=g(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},h.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},h.now=Date.now||function(){return(new Date).getTime()};var _={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},w=h.invert(_),j=function(n){var t=function(t){return n[t]},r="(?:"+h.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};h.escape=j(_),h.unescape=j(w),h.result=function(n,t){if(null==n)return void 0;var r=n[t];return h.isFunction(r)?n[t]():r};var x=0;h.uniqueId=function(n){var t=++x+"";return n?n+t:t},h.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var A=/(.)^/,k={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},O=/\\|'|\r|\n|\u2028|\u2029/g,F=function(n){return"\\"+k[n]};h.template=function(n,t,r){!t&&r&&(t=r),t=h.defaults({},t,h.templateSettings);var e=RegExp([(t.escape||A).source,(t.interpolate||A).source,(t.evaluate||A).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,a,o){return i+=n.slice(u,o).replace(O,F),u=o+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":a&&(i+="';\n"+a+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var a=new Function(t.variable||"obj","_",i)}catch(o){throw o.source=i,o}var l=function(n){return a.call(this,n,h)},c=t.variable||"obj";return l.source="function("+c+"){\n"+i+"}",l},h.chain=function(n){var t=h(n);return t._chain=!0,t};var E=function(n){return this._chain?h(n).chain():n};h.mixin=function(n){h.each(h.functions(n),function(t){var r=h[t]=n[t];h.prototype[t]=function(){var n=[this._wrapped];return i.apply(n,arguments),E.call(this,r.apply(h,n))}})},h.mixin(h),h.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=r[n];h.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],E.call(this,r)}}),h.each(["concat","join","slice"],function(n){var t=r[n];h.prototype[n]=function(){return E.call(this,t.apply(this._wrapped,arguments))}}),h.prototype.value=function(){return this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return h})}).call(this); + +//fgnass.github.com/spin.js#v1.2.7 +!function(e,t,n){function o(e,n){var r=t.createElement(e||"div"),i;for(i in n)r[i]=n[i];return r}function u(e){for(var t=1,n=arguments.length;t>1):parseInt(n.left,10)+i)+"px",top:(n.top=="auto"?a.y-u.y+(e.offsetHeight>>1):parseInt(n.top,10)+i)+"px"})),r.setAttribute("aria-role","progressbar"),t.lines(r,t.opts);if(!s){var f=0,l=n.fps,h=l/n.speed,d=(1-n.opacity)/(h*n.trail/100),v=h/n.lines;(function m(){f++;for(var e=n.lines;e;e--){var i=Math.max(1-(f+e*v)%h*d,n.opacity);t.opacity(r,n.lines-e,i,n)}t.timeout=t.el&&setTimeout(m,~~(1e3/l))})()}return t},stop:function(){var e=this.el;return e&&(clearTimeout(this.timeout),e.parentNode&&e.parentNode.removeChild(e),this.el=n),this},lines:function(e,t){function i(e,r){return c(o(),{position:"absolute",width:t.length+t.width+"px",height:t.width+"px",background:e,boxShadow:r,transformOrigin:"left",transform:"rotate("+~~(360/t.lines*n+t.rotate)+"deg) translate("+t.radius+"px"+",0)",borderRadius:(t.corners*t.width>>1)+"px"})}var n=0,r;for(;n',t)}var t=c(o("group"),{behavior:"url(#default#VML)"});!l(t,"transform")&&t.adj?(a.addRule(".spin-vml","behavior:url(#default#VML)"),v.prototype.lines=function(t,n){function s(){return c(e("group",{coordsize:i+" "+i,coordorigin:-r+" "+ -r}),{width:i,height:i})}function l(t,i,o){u(a,u(c(s(),{rotation:360/n.lines*t+"deg",left:~~i}),u(c(e("roundrect",{arcsize:n.corners}),{width:r,height:n.width,left:n.radius,top:-n.width>>1,filter:o}),e("fill",{color:n.color,opacity:n.opacity}),e("stroke",{opacity:0}))))}var r=n.length+n.width,i=2*r,o=-(n.width+n.length)*2+"px",a=c(s(),{position:"absolute",top:o,left:o}),f;if(n.shadow)for(f=1;f<=n.lines;f++)l(f,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(f=1;f<=n.lines;f++)l(f);return u(t,a)},v.prototype.opacity=function(e,t,n,r){var i=e.firstChild;r=r.shadow&&r.lines||0,i&&t+r\n
                                                  \n
                                                  \n\n\nChat Rooms\n\n\n
                                                    \n
                                                    \n\n\nVisitors\n\n\n
                                                    \n
                                                    \n
                                                    \n\n\n
                                                    \n
                                                    \n
                                                      \n
                                                      \n
                                                      \n
                                                      \n
                                                      \n
                                                      \n
                                                        \n
                                                        \n
                                                        \n';}return __p}; + +this["FirechatDefaultTemplates"]["templates/layout-popout.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                        \n
                                                        \n
                                                          \n
                                                          \n
                                                          \n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/message-context-menu.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                          \n\n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/message.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                          \n
                                                          \n'; if (!disableActions) { ;__p += '\n\n'; } ;__p += '
                                                          \n
                                                          \n' +((__t = ( message )) == null ? '' : __t) +'\n
                                                          \n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/prompt-alert.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                          \n
                                                          ' +__e( message ) +'
                                                          \n

                                                          \n\n

                                                          \n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/prompt-create-room.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                          \n
                                                          Give your chat room a name:
                                                          \n\n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/prompt-invitation.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                          \n
                                                          ' +__e( fromUserName ) +'
                                                          \n

                                                          invited you to join

                                                          \n
                                                          ' +__e( toRoomName ) +'
                                                          \n

                                                          \n\n\n

                                                          \n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/prompt-invite-private.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                          \n
                                                          Invite ' +__e( userName ) +' to ' +__e( roomName ) +'?
                                                          \n

                                                          \n\n\n

                                                          \n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/prompt-invite-reply.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                          \n
                                                          ' +__e( toUserName ) +'
                                                          \n

                                                          \n'; if (status === 'accepted') { ;__p += ' accepted your invite. '; } else { ;__p += ' declined your invite. '; } ;__p += '\n

                                                          \n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/prompt-user-mute.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                          \n
                                                          ' +__e( userName ) +'
                                                          \n

                                                          \n\n\n

                                                          \n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/prompt.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                          \n
                                                          \n' +__e( title ) +'\nX\n
                                                          \n
                                                          \n' +((__t = ( content )) == null ? '' : __t) +'\n
                                                          \n
                                                          \n
                                                          ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/room-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                        • \n\n' +__e( name ) +'\n\n
                                                        • ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                        • \n\n' +__e( name ) +''; if (!disableActions) { ;__p += '\n \n \n'; } ;__p += '\n\n
                                                        • ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                        • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n+\n'; } ;__p += '\n\n
                                                        • ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                          \n
                                                          \n\n\nIn Room\n\n\n
                                                          \n
                                                            \n
                                                            \n
                                                            \n\n+\nInvite\n\n
                                                            \n
                                                            \n
                                                            \n\n\n
                                                            \n
                                                            \n
                                                              \n
                                                              \n
                                                              \n
                                                              \n
                                                              \n\n
                                                              \n\n\n
                                                              \n
                                                              ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                            • \n' +__e( name ) +'\n
                                                            • ';}return __p}; + +this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                            • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n \n'; } ;__p += '\n\n
                                                            • ';}return __p}; +(function($) { + + // Shim for Function.bind(...) - (Required by IE < 9, FF < 4, SF < 6) + if (!Function.prototype.bind) { + Function.prototype.bind = function(oThis) { + if (typeof this !== "function") { + throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); + } + + var aArgs = Array.prototype.slice.call(arguments, 1), + fToBind = this, + fNOP = function() {}, + fBound = function() { + return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, + aArgs.concat(Array.prototype.slice.call(arguments))); + }; + + fNOP.prototype = this.prototype; + fBound.prototype = new fNOP(); + return fBound; + }; + } + + // Shim for Object.keys(...) - (Required by IE < 9, FF < 4) + Object.keys = Object.keys || function(oObj) { + var result = []; + for (var name in oObj) { + if (oObj.hasOwnProperty(name)) { + result.push(name); + } + } + return result; + }; + +})(); + +// Firechat is a simple, easily-extensible data layer for multi-user, +// multi-room chat, built entirely on [Firebase](https://firebase.com). +// +// The Firechat object is the primary conduit for all underlying data events. +// It exposes a number of methods for binding event listeners, creating, +// entering, or leaving chat rooms, initiating chats, sending messages, +// and moderator actions such as warning, kicking, or suspending users. +// +// Firechat.js 0.0.0 +// https://firebase.com +// (c) 2014 Firebase +// License: MIT + +// Setup +// -------------- +(function(Firebase) { + + // Establish a reference to the `window` object, and save the previous value + // of the `Firechat` variable. + var root = this, + previousFirechat = root.Firechat; + + function Firechat(firebaseRef, options) { + + // Instantiate a new connection to Firebase. + this._firebase = firebaseRef; + + // User-specific instance variables. + this._user = null; + this._userId = null; + this._userName = null; + this._isModerator = false; + + // A unique id generated for each session. + this._sessionId = null; + + // A mapping of event IDs to an array of callbacks. + this._events = {}; + + // A mapping of room IDs to a boolean indicating presence. + this._rooms = {}; + + // A mapping of operations to re-queue on disconnect. + this._presenceBits = {}; + + // Commonly-used Firebase references. + this._userRef = null; + this._messageRef = this._firebase.child('room-messages'); + this._roomRef = this._firebase.child('room-metadata'); + this._privateRoomRef = this._firebase.child('room-private-metadata'); + this._moderatorsRef = this._firebase.child('moderators'); + this._suspensionsRef = this._firebase.child('suspensions'); + this._usersOnlineRef = this._firebase.child('user-names-online'); + + // Setup and establish default options. + this._options = options || {}; + + // The number of historical messages to load per room. + this._options.numMaxMessages = this._options.numMaxMessages || 50; + } + + // Run Firechat in *noConflict* mode, returning the `Firechat` variable to + // its previous owner, and returning a reference to the Firechat object. + Firechat.noConflict = function noConflict() { + root.Firechat = previousFirechat; + return Firechat; + }; + + // Export the Firechat object as a global. + root.Firechat = Firechat; + + // Firechat Internal Methods + // -------------- + Firechat.prototype = { + + // Load the initial metadata for the user's account and set initial state. + _loadUserMetadata: function(onComplete) { + var self = this; + + // Update the user record with a default name on user's first visit. + this._userRef.transaction(function(current) { + if (!current || !current.id || !current.name) { + return { + id: self._userId, + name: self._userName + }; + } + }, function(error, committed, snapshot) { + self._user = snapshot.val(); + self._moderatorsRef.child(self._userId).once('value', function(snapshot) { + self._isModerator = !!snapshot.val(); + root.setTimeout(onComplete, 0); + }); + }); + }, + + // Initialize Firebase listeners and callbacks for the supported bindings. + _setupDataEvents: function() { + // Monitor connection state so we can requeue disconnect operations if need be. + this._firebase.root().child('.info/connected').on('value', function(snapshot) { + if (snapshot.val() === true) { + // We're connected (or reconnected)! Set up our presence state. + for (var i = 0; i < this._presenceBits; i++) { + var op = this._presenceBits[i], + ref = this._firebase.root().child(op.ref); + + ref.onDisconnect().set(op.offlineValue); + ref.set(op.onlineValue); + } + } + }, this); + + // Generate a unique session id for the visit. + var sessionRef = this._userRef.child('sessions').push(); + this._sessionId = sessionRef.key(); + this._queuePresenceOperation(sessionRef, true, null); + + // Register our username in the public user listing. + var usernameRef = this._usersOnlineRef.child(this._userName.toLowerCase()); + var usernameSessionRef = usernameRef.child(this._sessionId); + this._queuePresenceOperation(usernameSessionRef, { + id: this._userId, + name: this._userName + }, null); + + // Listen for state changes for the given user. + this._userRef.on('value', this._onUpdateUser, this); + + // Listen for chat invitations from other users. + this._userRef.child('invites').on('child_added', this._onFirechatInvite, this); + + // Listen for messages from moderators and adminstrators. + this._userRef.child('notifications').on('child_added', this._onNotification, this); + }, + + // Append the new callback to our list of event handlers. + _addEventCallback: function(eventId, callback) { + this._events[eventId] = this._events[eventId] || []; + this._events[eventId].push(callback); + }, + + // Retrieve the list of event handlers for a given event id. + _getEventCallbacks: function(eventId) { + if (this._events.hasOwnProperty(eventId)) { + return this._events[eventId]; + } + return []; + }, + + // Invoke each of the event handlers for a given event id with specified data. + _invokeEventCallbacks: function(eventId) { + var args = [], + callbacks = this._getEventCallbacks(eventId); + + Array.prototype.push.apply(args, arguments); + args = args.slice(1); + + for (var i = 0; i < callbacks.length; i += 1) { + callbacks[i].apply(null, args); + } + }, + + // Keep track of on-disconnect events so they can be requeued if we disconnect the reconnect. + _queuePresenceOperation: function(ref, onlineValue, offlineValue) { + ref.onDisconnect().set(offlineValue); + ref.set(onlineValue); + this._presenceBits[ref.toString()] = { + ref: ref, + onlineValue: onlineValue, + offlineValue: offlineValue + }; + }, + + // Remove an on-disconnect event from firing upon future disconnect and reconnect. + _removePresenceOperation: function(path, value) { + var ref = new Firebase(path); + ref.onDisconnect().cancel(); + ref.set(value); + delete this._presenceBits[path]; + }, + + // Event to monitor current user state. + _onUpdateUser: function(snapshot) { + this._user = snapshot.val(); + this._invokeEventCallbacks('user-update', this._user); + }, + + // Event to monitor current auth + user state. + _onAuthRequired: function() { + this._invokeEventCallbacks('auth-required'); + }, + + // Events to monitor room entry / exit and messages additional / removal. + _onEnterRoom: function(room) { + this._invokeEventCallbacks('room-enter', room); + }, + _onNewMessage: function(roomId, snapshot) { + var message = snapshot.val(); + message.id = snapshot.key(); + this._invokeEventCallbacks('message-add', roomId, message); + }, + _onRemoveMessage: function(roomId, snapshot) { + var messageId = snapshot.key(); + this._invokeEventCallbacks('message-remove', roomId, messageId); + }, + _onLeaveRoom: function(roomId) { + this._invokeEventCallbacks('room-exit', roomId); + }, + + // Event to listen for notifications from administrators and moderators. + _onNotification: function(snapshot) { + var notification = snapshot.val(); + if (!notification.read) { + if (notification.notificationType !== 'suspension' || notification.data.suspendedUntil < new Date().getTime()) { + snapshot.ref().child('read').set(true); + } + this._invokeEventCallbacks('notification', notification); + } + }, + + // Events to monitor chat invitations and invitation replies. + _onFirechatInvite: function(snapshot) { + var self = this, + invite = snapshot.val(); + + // Skip invites we've already responded to. + if (invite.status) { + return; + } + + invite.id = invite.id || snapshot.key(); + self.getRoom(invite.roomId, function(room) { + invite.toRoomName = room.name; + self._invokeEventCallbacks('room-invite', invite); + }); + }, + _onFirechatInviteResponse: function(snapshot) { + var self = this, + invite = snapshot.val(); + + invite.id = invite.id || snapshot.key(); + this._invokeEventCallbacks('room-invite-response', invite); + } + }; + + // Firechat External Methods + // -------------- + + // Initialize the library and setup data listeners. + Firechat.prototype.setUser = function(userId, userName, callback) { + var self = this; + + self._firebase.onAuth(function(authData) { + if (authData) { + self._userId = userId.toString(); + self._userName = userName.toString(); + self._userRef = self._firebase.child('users').child(self._userId); + self._loadUserMetadata(function() { + root.setTimeout(function() { + callback(self._user); + self._setupDataEvents(); + }, 0); + }); + } else { + self.warn('Firechat requires an authenticated Firebase reference. Pass an authenticated reference before loading.'); + } + }); + }; + + // Resumes the previous session by automatically entering rooms. + Firechat.prototype.resumeSession = function() { + this._userRef.child('rooms').once('value', function(snapshot) { + var rooms = snapshot.val(); + for (var roomId in rooms) { + this.enterRoom(rooms[roomId].id); + } + }, /* onError */ function(){}, /* context */ this); + }; + + // Callback registration. Supports each of the following events: + Firechat.prototype.on = function(eventType, cb) { + this._addEventCallback(eventType, cb); + }; + + // Create and automatically enter a new chat room. + Firechat.prototype.createRoom = function(roomName, roomType, callback) { + var self = this, + newRoomRef = this._roomRef.push(); + + var newRoom = { + id: newRoomRef.key(), + name: roomName, + type: roomType || 'public', + createdByUserId: this._userId, + createdAt: Firebase.ServerValue.TIMESTAMP + }; + + if (roomType === 'private') { + newRoom.authorizedUsers = {}; + newRoom.authorizedUsers[this._userId] = true; + } + + newRoomRef.set(newRoom, function(error) { + if (!error) { + self.enterRoom(newRoomRef.key()); + } + if (callback) { + callback(newRoomRef.key()); + } + }); + }; + + // Enter a chat room. + Firechat.prototype.enterRoom = function(roomId) { + var self = this; + self.getRoom(roomId, function(room) { + var roomName = room.name; + + if (!roomId || !roomName) return; + + // Skip if we're already in this room. + if (self._rooms[roomId]) { + return; + } + + self._rooms[roomId] = true; + + if (self._user) { + // Save entering this room to resume the session again later. + self._userRef.child('rooms').child(roomId).set({ + id: roomId, + name: roomName, + active: true + }); + + // Set presence bit for the room and queue it for removal on disconnect. + var presenceRef = self._firebase.child('room-users').child(roomId).child(self._userId).child(self._sessionId); + self._queuePresenceOperation(presenceRef, { + id: self._userId, + name: self._userName + }, null); + } + + // Invoke our callbacks before we start listening for new messages. + self._onEnterRoom({ id: roomId, name: roomName }); + + // Setup message listeners + self._roomRef.child(roomId).once('value', function(snapshot) { + self._messageRef.child(roomId).limitToLast(self._options.numMaxMessages).on('child_added', function(snapshot) { + self._onNewMessage(roomId, snapshot); + }, /* onCancel */ function() { + // Turns out we don't have permission to access these messages. + self.leaveRoom(roomId); + }, /* context */ self); + + self._messageRef.child(roomId).limitToLast(self._options.numMaxMessages).on('child_removed', function(snapshot) { + self._onRemoveMessage(roomId, snapshot); + }, /* onCancel */ function(){}, /* context */ self); + }, /* onFailure */ function(){}, self); + }); + }; + + // Leave a chat room. + Firechat.prototype.leaveRoom = function(roomId) { + var self = this, + userRoomRef = self._firebase.child('room-users').child(roomId); + + // Remove listener for new messages to this room. + self._messageRef.child(roomId).off(); + + if (self._user) { + var presenceRef = userRoomRef.child(self._userId).child(self._sessionId); + + // Remove presence bit for the room and cancel on-disconnect removal. + self._removePresenceOperation(presenceRef.toString(), null); + + // Remove session bit for the room. + self._userRef.child('rooms').child(roomId).remove(); + } + + delete self._rooms[roomId]; + + // Invoke event callbacks for the room-exit event. + self._onLeaveRoom(roomId); + }; + + Firechat.prototype.sendMessage = function(roomId, messageContent, messageType, cb) { + var self = this, + message = { + userId: self._userId, + name: self._userName, + timestamp: Firebase.ServerValue.TIMESTAMP, + message: messageContent, + type: messageType || 'default' + }, + newMessageRef; + + if (!self._user) { + self._onAuthRequired(); + if (cb) { + cb(new Error('Not authenticated or user not set!')); + } + return; + } + + newMessageRef = self._messageRef.child(roomId).push(); + newMessageRef.setWithPriority(message, Firebase.ServerValue.TIMESTAMP, cb); + }; + + Firechat.prototype.deleteMessage = function(roomId, messageId, cb) { + var self = this; + + self._messageRef.child(roomId).child(messageId).remove(cb); + }; + + // Mute or unmute a given user by id. This list will be stored internally and + // all messages from the muted clients will be filtered client-side after + // receipt of each new message. + Firechat.prototype.toggleUserMute = function(userId, cb) { + var self = this; + + if (!self._user) { + self._onAuthRequired(); + if (cb) { + cb(new Error('Not authenticated or user not set!')); + } + return; + } + + self._userRef.child('muted').child(userId).transaction(function(isMuted) { + return (isMuted) ? null : true; + }, cb); + }; + + // Send a moderator notification to a specific user. + Firechat.prototype.sendSuperuserNotification = function(userId, notificationType, data, cb) { + var self = this, + userNotificationsRef = self._firebase.child('users').child(userId).child('notifications'); + + userNotificationsRef.push({ + fromUserId: self._userId, + timestamp: Firebase.ServerValue.TIMESTAMP, + notificationType: notificationType, + data: data || {} + }, cb); + }; + + // Warn a user for violating the terms of service or being abusive. + Firechat.prototype.warnUser = function(userId) { + var self = this; + + self.sendSuperuserNotification(userId, 'warning'); + }; + + // Suspend a user by putting the user into read-only mode for a period. + Firechat.prototype.suspendUser = function(userId, timeLengthSeconds, cb) { + var self = this, + suspendedUntil = new Date().getTime() + 1000*timeLengthSeconds; + + self._suspensionsRef.child(userId).set(suspendedUntil, function(error) { + if (error && cb) { + return cb(error); + } else { + self.sendSuperuserNotification(userId, 'suspension', { + suspendedUntil: suspendedUntil + }); + return cb(null); + } + }); + }; + + // Invite a user to a specific chat room. + Firechat.prototype.inviteUser = function(userId, roomId) { + var self = this, + sendInvite = function() { + var inviteRef = self._firebase.child('users').child(userId).child('invites').push(); + inviteRef.set({ + id: inviteRef.key(), + fromUserId: self._userId, + fromUserName: self._userName, + roomId: roomId + }); + + // Handle listen unauth / failure in case we're kicked. + inviteRef.on('value', self._onFirechatInviteResponse, function(){}, self); + }; + + if (!self._user) { + self._onAuthRequired(); + return; + } + + self.getRoom(roomId, function(room) { + if (room.type === 'private') { + var authorizedUserRef = self._roomRef.child(roomId).child('authorizedUsers'); + authorizedUserRef.child(userId).set(true, function(error) { + if (!error) { + sendInvite(); + } + }); + } else { + sendInvite(); + } + }); + }; + + Firechat.prototype.acceptInvite = function(inviteId, cb) { + var self = this; + + self._userRef.child('invites').child(inviteId).once('value', function(snapshot) { + var invite = snapshot.val(); + if (invite === null && cb) { + return cb(new Error('acceptInvite(' + inviteId + '): invalid invite id')); + } else { + self.enterRoom(invite.roomId); + self._userRef.child('invites').child(inviteId).update({ + 'status': 'accepted', + 'toUserName': self._userName + }, cb); + } + }, self); + }; + + Firechat.prototype.declineInvite = function(inviteId, cb) { + var self = this, + updates = { + 'status': 'declined', + 'toUserName': self._userName + }; + + self._userRef.child('invites').child(inviteId).update(updates, cb); + }; + + Firechat.prototype.getRoomList = function(cb) { + var self = this; + + self._roomRef.once('value', function(snapshot) { + cb(snapshot.val()); + }); + }; + + Firechat.prototype.getUsersByRoom = function() { + var self = this, + roomId = arguments[0], + query = self._firebase.child('room-users').child(roomId), + cb = arguments[arguments.length - 1], + limit = null; + + if (arguments.length > 2) { + limit = arguments[1]; + } + + query = (limit) ? query.limitToLast(limit) : query; + + query.once('value', function(snapshot) { + var usernames = snapshot.val() || {}, + usernamesUnique = {}; + + for (var username in usernames) { + for (var session in usernames[username]) { + // Skip all other sessions for this user as we only need one. + usernamesUnique[username] = usernames[username][session]; + break; + } + } + + root.setTimeout(function() { + cb(usernamesUnique); + }, 0); + }); + }; + + Firechat.prototype.getUsersByPrefix = function(prefix, startAt, endAt, limit, cb) { + var self = this, + query = this._usersOnlineRef, + prefixLower = prefix.toLowerCase(); + + if (startAt) { + query = query.startAt(null, startAt); + } else if (endAt) { + query = query.endAt(null, endAt); + } else { + query = (prefixLower) ? query.startAt(null, prefixLower) : query.startAt(); + } + + query = (limit) ? query.limitToLast(limit) : query; + + query.once('value', function(snapshot) { + var usernames = snapshot.val() || {}, + usernamesFiltered = {}; + + for (var userNameKey in usernames) { + var sessions = usernames[userNameKey], + userName, userId, usernameClean; + + // Grab the user data from the first registered active session. + for (var sessionId in sessions) { + userName = sessions[sessionId].name; + userId = sessions[sessionId].id; + + // Skip all other sessions for this user as we only need one. + break; + } + + // Filter out any usernames that don't match our prefix and break. + if ((prefix.length > 0) && (userName.toLowerCase().indexOf(prefixLower) !== 0)) + continue; + + usernamesFiltered[userName] = { + name: userName, + id: userId + }; + } + + root.setTimeout(function() { + cb(usernamesFiltered); + }, 0); + }); + }; + + // Miscellaneous helper methods. + Firechat.prototype.getRoom = function(roomId, callback) { + this._roomRef.child(roomId).once('value', function(snapshot) { + callback(snapshot.val()); + }); + }; + + Firechat.prototype.userIsModerator = function() { + return this._isModerator; + }; + + Firechat.prototype.warn = function(msg) { + if (console) { + msg = 'Firechat Warning: ' + msg; + if (typeof console.warn === 'function') { + console.warn(msg); + } else if (typeof console.log === 'function') { + console.log(msg); + } + } + }; +})(Firebase); + +(function($) { + + + if (!$ || (parseInt($().jquery.replace(/\./g, ""), 10) < 170)) { + throw new Error("jQuery 1.7 or later required!"); + } + + var root = this, + previousFirechatUI = root.FirechatUI; + + root.FirechatUI = FirechatUI; + + if (!self.FirechatDefaultTemplates) { + throw new Error("Unable to find chat templates!"); + } + + function FirechatUI(firebaseRef, el, options) { + var self = this; + + if (!firebaseRef) { + throw new Error('FirechatUI: Missing required argument `firebaseRef`'); + } + + if (!el) { + throw new Error('FirechatUI: Missing required argument `el`'); + } + + options = options || {}; + this._options = options; + + this._el = el; + this._user = null; + this._chat = new Firechat(firebaseRef, options); + + // A list of rooms to enter once we've made room for them (once we've hit the max room limit). + this._roomQueue = []; + + // Define some constants regarding maximum lengths, client-enforced. + this.maxLengthUsername = 15; + this.maxLengthUsernameDisplay = 15; + this.maxLengthRoomName = 24; + this.maxLengthMessage = 120; + this.maxUserSearchResults = 100; + + // Define some useful regexes. + this.urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim; + this.pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim; + + this._renderLayout(); + + // Grab shortcuts to commonly used jQuery elements. + this.$wrapper = $('#firechat'); + this.$roomList = $('#firechat-room-list'); + this.$tabList = $('#firechat-tab-list'); + this.$tabContent = $('#firechat-tab-content'); + this.$messages = {}; + + // Rate limit messages from a given user with some defaults. + this.$rateLimit = { + limitCount: 10, // max number of events + limitInterval: 10000, // max interval for above count in milliseconds + limitWaitTime: 30000, // wait time if a user hits the wait limit + history: {} + }; + + // Setup UI bindings for chat controls. + this._bindUIEvents(); + + // Setup bindings to internal methods + this._bindDataEvents(); + } + + // Run FirechatUI in *noConflict* mode, returning the `FirechatUI` variable to + // its previous owner, and returning a reference to the FirechatUI object. + FirechatUI.noConflict = function noConflict() { + root.FirechatUI = previousFirechatUI; + return FirechatUI; + }; + + FirechatUI.prototype = { + + _bindUIEvents: function() { + // Chat-specific custom interactions and functionality. + this._bindForHeightChange(); + this._bindForTabControls(); + this._bindForRoomList(); + this._bindForUserRoomList(); + this._bindForUserSearch(); + this._bindForUserMuting(); + this._bindForChatInvites(); + this._bindForRoomListing(); + this._bindForFileUpload(); + + // Generic, non-chat-specific interactive elements. + this._setupTabs(); + this._setupDropdowns(); + this._bindTextInputFieldLimits(); + }, + + _bindDataEvents: function() { + this._chat.on('user-update', this._onUpdateUser.bind(this)); + + // Bind events for new messages, enter / leaving rooms, and user metadata. + this._chat.on('room-enter', this._onEnterRoom.bind(this)); + this._chat.on('room-exit', this._onLeaveRoom.bind(this)); + this._chat.on('message-add', this._onNewMessage.bind(this)); + this._chat.on('message-remove', this._onRemoveMessage.bind(this)); + + // Bind events related to chat invitations. + this._chat.on('room-invite', this._onChatInvite.bind(this)); + this._chat.on('room-invite-response', this._onChatInviteResponse.bind(this)); + + // Binds events related to admin or moderator notifications. + this._chat.on('notification', this._onNotification.bind(this)); + }, + + _renderLayout: function() { + var template = FirechatDefaultTemplates["templates/layout-full.html"]; + $(this._el).html(template({ + maxLengthUsername: this.maxLengthUsername + })); + }, + + _onUpdateUser: function(user) { + // Update our current user state and render latest user name. + this._user = user; + + // Update our interface to reflect which users are muted or not. + var mutedUsers = this._user.muted || {}; + $('[data-event="firechat-user-mute-toggle"]').each(function(i, el) { + var userId = $(this).closest('[data-user-id]').data('user-id'); + $(this).toggleClass('red', !!mutedUsers[userId]); + }); + + // Ensure that all messages from muted users are removed. + for (var userId in mutedUsers) { + $('.message[data-user-id="' + userId + '"]').fadeOut(); + } + }, + + _onEnterRoom: function(room) { + this.attachTab(room.id, room.name); + }, + _onLeaveRoom: function(roomId) { + this.removeTab(roomId); + + // Auto-enter rooms in the queue + if ((this._roomQueue.length > 0)) { + this._chat.enterRoom(this._roomQueue.shift(roomId)); + } + }, + _onNewMessage: function(roomId, message) { + var userId = message.userId; + if (!this._user || !this._user.muted || !this._user.muted[userId]) { + this.showMessage(roomId, message); + } + }, + _onRemoveMessage: function(roomId, messageId) { + this.removeMessage(roomId, messageId); + }, + + // Events related to chat invitations. + _onChatInvite: function(invitation) { + var self = this; + var template = FirechatDefaultTemplates["templates/prompt-invitation.html"]; + var $prompt = this.prompt('Invite', template(invitation)); + $prompt.find('a.close').click(function() { + $prompt.remove(); + self._chat.declineInvite(invitation.id); + return false; + }); + + $prompt.find('[data-toggle=accept]').click(function() { + $prompt.remove(); + self._chat.acceptInvite(invitation.id); + return false; + }); + + $prompt.find('[data-toggle=decline]').click(function() { + $prompt.remove(); + self._chat.declineInvite(invitation.id); + return false; + }); + }, + _onChatInviteResponse: function(invitation) { + if (!invitation.status) return; + + var self = this, + template = FirechatDefaultTemplates["templates/prompt-invite-reply.html"], + $prompt; + + if (invitation.status && invitation.status === 'accepted') { + $prompt = this.prompt('Accepted', template(invitation)); + this._chat.getRoom(invitation.roomId, function(room) { + self.attachTab(invitation.roomId, room.name); + }); + } else { + $prompt = this.prompt('Declined', template(invitation)); + } + + $prompt.find('a.close').click(function() { + $prompt.remove(); + return false; + }); + }, + + // Events related to admin or moderator notifications. + _onNotification: function(notification) { + if (notification.notificationType === 'warning') { + this.renderAlertPrompt('Warning', 'You are being warned for inappropriate messaging. Further violation may result in temporary or permanent ban of service.'); + } else if (notification.notificationType === 'suspension') { + var suspendedUntil = notification.data.suspendedUntil, + secondsLeft = Math.round((suspendedUntil - new Date().getTime()) / 1000), + timeLeft = ''; + + if (secondsLeft > 0) { + if (secondsLeft > 2*3600) { + var hours = Math.floor(secondsLeft / 3600); + timeLeft = hours + ' hours, '; + secondsLeft -= 3600*hours; + } + timeLeft += Math.floor(secondsLeft / 60) + ' minutes'; + this.renderAlertPrompt('Suspended', 'A moderator has suspended you for violating site rules. You cannot send messages for another ' + timeLeft + '.'); + } + } + } + }; + + /** + * Initialize an authenticated session with a user id and name. + * This method assumes that the underlying Firebase reference has + * already been authenticated. + */ + FirechatUI.prototype.setUser = function(userId, userName) { + var self = this; + + // Initialize data events + self._chat.setUser(userId, userName, function(user) { + self._user = user; + + if (self._chat.userIsModerator()) { + self._bindSuperuserUIEvents(); + } + + self._chat.resumeSession(); + }); + }; + + /** + * Exposes internal chat bindings via this external interface. + */ + FirechatUI.prototype.on = function(eventType, cb) { + var self = this; + + this._chat.on(eventType, cb); + }; + + /** + * Binds a custom context menu to messages for superusers to warn or ban + * users for violating terms of service. + */ + FirechatUI.prototype._bindSuperuserUIEvents = function() { + var self = this, + parseMessageVars = function(event) { + var $this = $(this), + messageId = $this.closest('[data-message-id]').data('message-id'), + userId = $('[data-message-id="' + messageId + '"]').closest('[data-user-id]').data('user-id'), + roomId = $('[data-message-id="' + messageId + '"]').closest('[data-room-id]').data('room-id'); + + return { messageId: messageId, userId: userId, roomId: roomId }; + }, + clearMessageContextMenus = function() { + // Remove any context menus currently showing. + $('[data-toggle="firechat-contextmenu"]').each(function() { + $(this).remove(); + }); + + // Remove any messages currently highlighted. + $('#firechat .message.highlighted').each(function() { + $(this).removeClass('highlighted'); + }); + }, + showMessageContextMenu = function(event) { + var $this = $(this), + $message = $this.closest('[data-message-id]'), + template = FirechatDefaultTemplates["templates/message-context-menu.html"], + messageVars = parseMessageVars.call(this, event), + $template; + + event.preventDefault(); + + // Clear existing menus. + clearMessageContextMenus(); + + // Highlight the relevant message. + $this.addClass('highlighted'); + + self._chat.getRoom(messageVars.roomId, function(room) { + // Show the context menu. + $template = $(template({ + id: $message.data('message-id') + })); + $template.css({ + left: event.clientX, + top: event.clientY + }).appendTo(self.$wrapper); + }); + }; + + // Handle dismissal of message context menus (any non-right-click click event). + $(document).bind('click', { self: this }, function(event) { + if (!event.button || event.button != 2) { + clearMessageContextMenus(); + } + }); + + // Handle display of message context menus (via right-click on a message). + $(document).delegate('[data-class="firechat-message"]', 'contextmenu', showMessageContextMenu); + + // Handle click of the 'Warn User' contextmenu item. + $(document).delegate('[data-event="firechat-user-warn"]', 'click', function(event) { + var messageVars = parseMessageVars.call(this, event); + self._chat.warnUser(messageVars.userId); + }); + + // Handle click of the 'Suspend User (1 Hour)' contextmenu item. + $(document).delegate('[data-event="firechat-user-suspend-hour"]', 'click', function(event) { + var messageVars = parseMessageVars.call(this, event); + self._chat.suspendUser(messageVars.userId, /* 1 Hour = 3600s */ 60*60); + }); + + // Handle click of the 'Suspend User (1 Day)' contextmenu item. + $(document).delegate('[data-event="firechat-user-suspend-day"]', 'click', function(event) { + var messageVars = parseMessageVars.call(this, event); + self._chat.suspendUser(messageVars.userId, /* 1 Day = 86400s */ 24*60*60); + }); + + // Handle click of the 'Delete Message' contextmenu item. + $(document).delegate('[data-event="firechat-message-delete"]', 'click', function(event) { + var messageVars = parseMessageVars.call(this, event); + self._chat.deleteMessage(messageVars.roomId, messageVars.messageId); + }); + }; + + /** + * Binds to height changes in the surrounding div. + */ + FirechatUI.prototype._bindForHeightChange = function() { + var self = this, + $el = $(this._el), + lastHeight = null; + + setInterval(function() { + var height = $el.height(); + if (height != lastHeight) { + lastHeight = height; + $('.chat').each(function(i, el) { + + }); + } + }, 500); + }; + + /** + * Binds custom inner-tab events. + */ + FirechatUI.prototype._bindForTabControls = function() { + var self = this; + + // Handle click of tab close button. + $(document).delegate('[data-event="firechat-close-tab"]', 'click', function(event) { + var roomId = $(this).closest('[data-room-id]').data('room-id'); + self._chat.leaveRoom(roomId); + return false; + }); + }; + + /** + * Binds room list dropdown to populate room list on-demand. + */ + FirechatUI.prototype._bindForRoomList = function() { + var self = this; + + $('#firechat-btn-rooms').bind('click', function() { + if ($(this).parent().hasClass('open')) { + return; + } + + var $this = $(this), + template = FirechatDefaultTemplates["templates/room-list-item.html"], + selectRoomListItem = function() { + var parent = $(this).parent(), + roomId = parent.data('room-id'), + roomName = parent.data('room-name'); + + if (self.$messages[roomId]) { + self.focusTab(roomId); + } else { + self._chat.enterRoom(roomId, roomName); + } + return false; + }; + + self._chat.getRoomList(function(rooms) { + self.$roomList.empty(); + for (var roomId in rooms) { + var room = rooms[roomId]; + if (room.type != "public") continue; + room.isRoomOpen = !!self.$messages[room.id]; + var $roomItem = $(template(room)); + $roomItem.children('a').bind('click', selectRoomListItem); + self.$roomList.append($roomItem.toggle(true)); + } + }); + }); + }; + + /** + * Binds user list dropdown per room to populate user list on-demand. + */ + FirechatUI.prototype._bindForUserRoomList = function() { + var self = this; + + // Upon click of the dropdown, autofocus the input field and trigger list population. + $(document).delegate('[data-event="firechat-user-room-list-btn"]', 'click', function(event) { + event.stopPropagation(); + + var $this = $(this), + roomId = $this.closest('[data-room-id]').data('room-id'), + template = FirechatDefaultTemplates["templates/room-user-list-item.html"], + targetId = $this.data('target'), + $target = $('#' + targetId); + + $target.empty(); + self._chat.getUsersByRoom(roomId, function(users) { + for (var username in users) { + user = users[username]; + user.disableActions = (!self._user || user.id === self._user.id); + user.nameTrimmed = self.trimWithEllipsis(user.name, self.maxLengthUsernameDisplay); + user.isMuted = (self._user && self._user.muted && self._user.muted[user.id]); + $target.append($(template(user))); + } + self.sortListLexicographically('#' + targetId); + }); + }); + }; + + /** + * Binds for file upload icon + */ + + FirechatUI.prototype._bindForFileUpload = function() { + var self = this; + var handleFileSelect = function(event) { + var f = event.target.files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var filePayload = e.target.result; + // Generate a location that can't be guessed using the file's contents and a random number + var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); + var f = new Firebase(firebaseRef + '/pano/' + hash + '/filePayload'); + spinner.spin(document.getElementById('spin')); + // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview + f.set(filePayload, function() { + spinner.stop(); + var imageFileName = firebaseRef + '/pano/' + hash + '/filePayload'; + console.log("File with hash: " + imageFileName + ' created'); + $('#file-upload').hide(); + var roomId = $("textarea").attr("id").replace(/textarea/, ""); + var message = self.trimWithEllipsis("File Uploaded from " + self._chat._userName, self.maxLengthMessage); + self._chat.sendMessage(roomId, message); + f.once('value', function(snap) { + var payload = snap.val(); + if (payload !== null) { + var uploadImg = $(''); + uploadImg.attr("src", payload); + uploadImg.appendTo($(".message").last()); + uploadImg.width(313); + uploadImg.show(); + } else { + $('#body').append("Not found"); + } + spinner.stop(); + }); + }); + }; + })(f); + reader.readAsDataURL(f); + }; + // Upon click of the file icon image + $(document).delegate('[data-event="firechat-upload-file"]', 'click', function(event) { + event.stopPropagation(); + console.log("Clicked on the button!"); + $('#file-upload').show(); + $("#file-upload").get(0).addEventListener('change', handleFileSelect, false); + }); + + // Upon completed file upload + $(document).delegate('[data-event="firechat-file-uploaded"]', 'change', function(event) { + event.stopPropagation(); + console.log("Upload Complete"); + // + }); + + }; + + /** + * Binds user search buttons, dropdowns, and input fields for searching all + * active users currently in chat. + */ + FirechatUI.prototype._bindForUserSearch = function() { + var self = this, + handleUserSearchSubmit = function(event) { + var $this = $(this), + targetId = $this.data('target'), + controlsId = $this.data('controls'), + templateId = $this.data('template'), + prefix = $this.val() || $this.data('prefix') || '', + startAt = $this.data('startAt') || null, + endAt = $this.data('endAt') || null; + + event.preventDefault(); + + userSearch(targetId, templateId, controlsId, prefix, startAt, endAt); + }, + userSearch = function(targetId, templateId, controlsId, prefix, startAt, endAt) { + var $target = $('#' + targetId), + $controls = $('#' + controlsId), + template = FirechatDefaultTemplates[templateId]; + + // Query results, filtered by prefix, using the defined startAt and endAt markets. + self._chat.getUsersByPrefix(prefix, startAt, endAt, self.maxUserSearchResults, function(users) { + var numResults = 0, + $prevBtn, $nextBtn, username, firstResult, lastResult; + + $target.empty(); + + for (username in users) { + var user = users[username]; + + // Disable buttons for . + user.disableActions = (!self._user || user.id === self._user.id); + + numResults += 1; + + $target.append(template(user)); + + // If we've hit our result limit, the additional value signifies we should paginate. + if (numResults === 1) { + firstResult = user.name.toLowerCase(); + } else if (numResults >= self.maxUserSearchResults) { + lastResult = user.name.toLowerCase(); + break; + } + } + + if ($controls) { + $prevBtn = $controls.find('[data-toggle="firechat-pagination-prev"]'); + $nextBtn = $controls.find('[data-toggle="firechat-pagination-next"]'); + + // Sort out configuration for the 'next' button + if (lastResult) { + $nextBtn + .data('event', 'firechat-user-search') + .data('startAt', lastResult) + .data('prefix', prefix) + .removeClass('disabled').removeAttr('disabled'); + } else { + $nextBtn + .data('event', null) + .data('startAt', null) + .data('prefix', null) + .addClass('disabled').attr('disabled', 'disabled'); + } + } + }); + }; + + $(document).delegate('[data-event="firechat-user-search"]', 'keyup', handleUserSearchSubmit); + $(document).delegate('[data-event="firechat-user-search"]', 'click', handleUserSearchSubmit); + + // Upon click of the dropdown, autofocus the input field and trigger list population. + $(document).delegate('[data-event="firechat-user-search-btn"]', 'click', function(event) { + event.stopPropagation(); + var $input = $(this).next('div.firechat-dropdown-menu').find('input'); + $input.focus(); + $input.trigger(jQuery.Event('keyup')); + }); + + // Ensure that the dropdown stays open despite clicking on the input element. + $(document).delegate('[data-event="firechat-user-search"]', 'click', function(event) { + event.stopPropagation(); + }); + }; + + /** + * Binds user mute toggles and removes all messages for a given user upon mute. + */ + FirechatUI.prototype._bindForUserMuting = function() { + var self = this; + $(document).delegate('[data-event="firechat-user-mute-toggle"]', 'click', function(event) { + var $this = $(this), + userId = $this.closest('[data-user-id]').data('user-id'), + userName = $this.closest('[data-user-name]').data('user-name'), + isMuted = $this.hasClass('red'), + template = FirechatDefaultTemplates["templates/prompt-user-mute.html"]; + + event.preventDefault(); + + // Require user confirmation for muting. + if (!isMuted) { + var $prompt = self.prompt('Mute User?', template({ + userName: userName + })); + + $prompt.find('a.close').first().click(function() { + $prompt.remove(); + return false; + }); + + $prompt.find('[data-toggle=decline]').first().click(function() { + $prompt.remove(); + return false; + }); + + $prompt.find('[data-toggle=accept]').first().click(function() { + self._chat.toggleUserMute(userId); + $prompt.remove(); + return false; + }); + } else { + self._chat.toggleUserMute(userId); + } + }); + }; + + /** + * Binds to elements with the data-event='firechat-user-(private)-invite' and + * handles invitations as well as room creation and entering. + */ + FirechatUI.prototype._bindForChatInvites = function() { + var self = this, + renderInvitePrompt = function(event) { + var $this = $(this), + userId = $this.closest('[data-user-id]').data('user-id'), + roomId = $this.closest('[data-room-id]').data('room-id'), + userName = $this.closest('[data-user-name]').data('user-name'), + template = FirechatDefaultTemplates["templates/prompt-invite-private.html"], + $prompt; + + self._chat.getRoom(roomId, function(room) { + $prompt = self.prompt('Invite', template({ + userName: userName, + roomName: room.name + })); + + $prompt.find('a.close').click(function() { + $prompt.remove(); + return false; + }); + + $prompt.find('[data-toggle=decline]').click(function() { + $prompt.remove(); + return false; + }); + + $prompt.find('[data-toggle=accept]').first().click(function() { + $prompt.remove(); + self._chat.inviteUser(userId, roomId, room.name); + return false; + }); + return false; + }); + return false; + }, + renderPrivateInvitePrompt = function(event) { + var $this = $(this), + userId = $this.closest('[data-user-id]').data('user-id'), + userName = $this.closest('[data-user-name]').data('user-name'), + template = FirechatDefaultTemplates["templates/prompt-invite-private.html"], + $prompt; + + if (userId && userName) { + $prompt = self.prompt('Private Invite', template({ + userName: userName, + roomName: 'Private Chat' + })); + + $prompt.find('a.close').click(function() { + $prompt.remove(); + return false; + }); + + $prompt.find('[data-toggle=decline]').click(function() { + $prompt.remove(); + return false; + }); + + $prompt.find('[data-toggle=accept]').first().click(function() { + $prompt.remove(); + var roomName = 'Private Chat'; + self._chat.createRoom(roomName, 'private', function(roomId) { + self._chat.inviteUser(userId, roomId, roomName); + }); + return false; + }); + } + return false; + }; + + $(document).delegate('[data-event="firechat-user-chat"]', 'click', renderPrivateInvitePrompt); + $(document).delegate('[data-event="firechat-user-invite"]', 'click', renderInvitePrompt); + }; + + /** + * Binds to room dropdown button, menu items, and create room button. + */ + FirechatUI.prototype._bindForRoomListing = function() { + var self = this, + $createRoomPromptButton = $('#firechat-btn-create-room-prompt'), + $createRoomButton = $('#firechat-btn-create-room'), + renderRoomList = function(event) { + var type = $(this).data('room-type'); + + self.sortListLexicographically('#firechat-room-list'); + }; + + // Handle click of the create new room prompt-button. + $createRoomPromptButton.bind('click', function(event) { + self.promptCreateRoom(); + return false; + }); + + // Handle click of the create new room button. + $createRoomButton.bind('click', function(event) { + var roomName = $('#firechat-input-room-name').val(); + $('#firechat-prompt-create-room').remove(); + self._chat.createRoom(roomName); + return false; + }); + }; + + + + /** + * A stripped-down version of bootstrap-tab.js. + * + * Original bootstrap-tab.js Copyright 2012 Twitter, Inc.,licensed under the Apache v2.0 + */ + FirechatUI.prototype._setupTabs = function() { + var self = this, + show = function($el) { + var $this = $el, + $ul = $this.closest('ul:not(.firechat-dropdown-menu)'), + selector = $this.attr('data-target'), + previous = $ul.find('.active:last a')[0], + $target, + e; + + if (!selector) { + selector = $this.attr('href'); + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ''); + } + + if ($this.parent('li').hasClass('active')) return; + + e = $.Event('show', { relatedTarget: previous }); + + $this.trigger(e); + + if (e.isDefaultPrevented()) return; + + $target = $(selector); + + activate($this.parent('li'), $ul); + activate($target, $target.parent(), function () { + $this.trigger({ + type: 'shown', + relatedTarget: previous + }); + }); + }, + activate = function (element, container, callback) { + var $active = container.find('> .active'), + transition = callback && $.support.transition && $active.hasClass('fade'); + + function next() { + $active + .removeClass('active') + .find('> .firechat-dropdown-menu > .active') + .removeClass('active'); + + element.addClass('active'); + + if (transition) { + element.addClass('in'); + } else { + element.removeClass('fade'); + } + + if (element.parent('.firechat-dropdown-menu')) { + element.closest('li.firechat-dropdown').addClass('active'); + } + + if (callback) { + callback(); + } + } + + if (transition) { + $active.one($.support.transition.end, next); + } else { + next(); + } + + $active.removeClass('in'); + }; + + $(document).delegate('[data-toggle="firechat-tab"]', 'click', function(event) { + event.preventDefault(); + show($(this)); + }); + }; + + /** + * A stripped-down version of bootstrap-dropdown.js. + * + * Original bootstrap-dropdown.js Copyright 2012 Twitter, Inc., licensed under the Apache v2.0 + */ + FirechatUI.prototype._setupDropdowns = function() { + var self = this, + toggle = '[data-toggle=firechat-dropdown]', + toggleDropdown = function(event) { + var $this = $(this), + $parent = getParent($this), + isActive = $parent.hasClass('open'); + + if ($this.is('.disabled, :disabled')) return; + + clearMenus(); + + if (!isActive) { + $parent.toggleClass('open'); + } + + $this.focus(); + + return false; + }, + clearMenus = function() { + $('[data-toggle=firechat-dropdown]').each(function() { + getParent($(this)).removeClass('open'); + }); + }, + getParent = function($this) { + var selector = $this.attr('data-target'), + $parent; + + if (!selector) { + selector = $this.attr('href'); + selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, ''); + } + + $parent = selector && $(selector); + + if (!$parent || !$parent.length) $parent = $this.parent(); + + return $parent; + }; + + $(document) + .bind('click', clearMenus) + .delegate('.firechat-dropdown-menu', 'click', function(event) { event.stopPropagation(); }) + .delegate('[data-toggle=firechat-dropdown]', 'click', toggleDropdown); + }; + + /** + * Binds to any text input fields with data-provide='limit' and + * data-counter='', and upon value change updates the selector + * content to reflect the number of characters remaining, as the 'maxlength' + * attribute less the current value length. + */ + FirechatUI.prototype._bindTextInputFieldLimits = function() { + $('body').delegate('input[data-provide="limit"], textarea[data-provide="limit"]', 'keyup', function(event) { + var $this = $(this), + $target = $($this.data('counter')), + limit = $this.attr('maxlength'), + count = $this.val().length; + + $target.html(Math.max(0, limit - count)); + }); + }; + + /** + * Given a title and message content, show an alert prompt to the user. + * + * @param {string} title + * @param {string} message + */ + FirechatUI.prototype.renderAlertPrompt = function(title, message) { + var template = FirechatDefaultTemplates["templates/prompt-alert.html"], + $prompt = this.prompt(title, template({ message: message })); + + $prompt.find('.close').click(function() { + $prompt.remove(); + return false; + }); + return; + }; + + /** + * Toggle input field s if we want limit / unlimit input fields. + */ + FirechatUI.prototype.toggleInputs = function(isEnabled) { + $('#firechat-tab-content textarea').each(function() { + var $this = $(this); + if (isEnabled) { + $(this).val(''); + } else { + $(this).val('You have exceeded the message limit, please wait before sending.'); + } + $this.prop('disabled', !isEnabled); + }); + $('#firechat-input-name').prop('disabled', !isEnabled); + }; + + /** + * Given a room id and name, attach the tab to the interface and setup events. + * + * @param {string} roomId + * @param {string} roomName + */ + FirechatUI.prototype.attachTab = function(roomId, roomName) { + var self = this; + + // If this tab already exists, give it focus. + if (this.$messages[roomId]) { + this.focusTab(roomId); + return; + } + + var room = { + id: roomId, + name: roomName + }; + + // Populate and render the tab content template. + var tabTemplate = FirechatDefaultTemplates["templates/tab-content.html"]; + var $tabContent = $(tabTemplate(room)); + this.$tabContent.prepend($tabContent); + var $messages = $('#firechat-messages' + roomId); + + // Keep a reference to the message listing for later use. + this.$messages[roomId] = $messages; + + // Attach on-enter event to textarea. + var $textarea = $tabContent.find('textarea').first(); + $textarea.bind('keydown', function(e) { + var message = self.trimWithEllipsis($textarea.val(), self.maxLengthMessage); + if ((e.which === 13) && (message !== '')) { + $textarea.val(''); + self._chat.sendMessage(roomId, message); + return false; + } + }); + + // Populate and render the tab menu template. + var tabListTemplate = FirechatDefaultTemplates["templates/tab-menu-item.html"]; + var $tab = $(tabListTemplate(room)); + this.$tabList.prepend($tab); + + // Attach on-shown event to move tab to front and scroll to bottom. + $tab.bind('shown', function(event) { + $messages.scrollTop($messages[0].scrollHeight); + }); + + // Dynamically update the width of each tab based upon the number open. + var tabs = this.$tabList.children('li'); + var tabWidth = Math.floor($('#firechat-tab-list').width() / tabs.length); + this.$tabList.children('li').css('width', tabWidth); + + // Update the room listing to reflect that we're now in the room. + this.$roomList.children('[data-room-id=' + roomId + ']').children('a').addClass('highlight'); + + // Sort each item in the user list alphabetically on click of the dropdown. + $('#firechat-btn-room-user-list-' + roomId).bind('click', function() { + self.sortListLexicographically('#firechat-room-user-list-' + roomId); + return false; + }); + + // Automatically select the new tab. + this.focusTab(roomId); + }; + + /** + * Given a room id, focus the given tab. + * + * @param {string} roomId + */ + FirechatUI.prototype.focusTab = function(roomId) { + if (this.$messages[roomId]) { + var $tabLink = this.$tabList.find('[data-room-id=' + roomId + ']').find('a'); + if ($tabLink.length) { + $tabLink.first().trigger('click'); + } + } + }; + + /** + * Given a room id, remove the tab and all child elements from the interface. + * + * @param {string} roomId + */ + FirechatUI.prototype.removeTab = function(roomId) { + delete this.$messages[roomId]; + + // Remove the inner tab content. + this.$tabContent.find('[data-room-id=' + roomId + ']').remove(); + + // Remove the tab from the navigation menu. + this.$tabList.find('[data-room-id=' + roomId + ']').remove(); + + // Dynamically update the width of each tab based upon the number open. + var tabs = this.$tabList.children('li'); + var tabWidth = Math.floor($('#firechat-tab-list').width() / tabs.length); + this.$tabList.children('li').css('width', tabWidth); + + // Automatically select the next tab if there is one. + this.$tabList.find('[data-toggle="firechat-tab"]').first().trigger('click'); + + // Update the room listing to reflect that we're now in the room. + this.$roomList.children('[data-room-id=' + roomId + ']').children('a').removeClass('highlight'); + }; + + /** + * Render a new message in the specified chat room. + * + * @param {string} roomId + * @param {string} message + */ + FirechatUI.prototype.showMessage = function(roomId, rawMessage) { + var self = this; + + // Setup defaults + var message = { + id : rawMessage.id, + localtime : self.formatTime(rawMessage.timestamp), + message : rawMessage.message || '', + userId : rawMessage.userId, + name : rawMessage.name, + type : rawMessage.type || 'default', + isSelfMessage : (self._user && rawMessage.userId == self._user.id), + disableActions : (!self._user || rawMessage.userId == self._user.id) + }; + // While other data is escaped in the Underscore.js templates, escape and + // process the message content here to add additional functionality (add links). + // Also trim the message length to some client-defined maximum. + var messageConstructed = ''; + message.message = _.map(message.message.split(' '), function(token) { + if (self.urlPattern.test(token) || self.pseudoUrlPattern.test(token)) { + return self.linkify(encodeURI(token)); + } else { + return _.escape(token); + } + }).join(' '); + message.message = self.trimWithEllipsis(message.message, self.maxLengthMessage); + + // Populate and render the message template. + var template = FirechatDefaultTemplates["templates/message.html"]; + var $message = $(template(message)); + var $messages = self.$messages[roomId]; + if ($messages) { + + var scrollToBottom = false; + if ($messages.scrollTop() / ($messages[0].scrollHeight - $messages[0].offsetHeight) >= 0.95) { + // Pinned to bottom + scrollToBottom = true; + } else if ($messages[0].scrollHeight <= $messages.height()) { + // Haven't added the scrollbar yet + scrollToBottom = true; + } + + $messages.append($message); + + if (scrollToBottom) { + $messages.scrollTop($messages[0].scrollHeight); + } + } + }; + + /** + * Remove a message by id. + * + * @param {string} roomId + * @param {string} messageId + */ + FirechatUI.prototype.removeMessage = function(roomId, messageId) { + $('.message[data-message-id="' + messageId + '"]').remove(); + }; + + /** + * Given a selector for a list element, sort the items alphabetically. + * + * @param {string} selector + */ + FirechatUI.prototype.sortListLexicographically = function(selector) { + $(selector).children("li").sort(function(a, b) { + var upA = $(a).text().toUpperCase(); + var upB = $(b).text().toUpperCase(); + return (upA < upB) ? -1 : (upA > upB) ? 1 : 0; + }).appendTo(selector); + }; + + /** + * Remove leading and trailing whitespace from a string and shrink it, with + * added ellipsis, if it exceeds a specified length. + * + * @param {string} str + * @param {number} length + * @return {string} + */ + FirechatUI.prototype.trimWithEllipsis = function(str, length) { + str = str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + return (length && str.length <= length) ? str : str.substring(0, length) + '...'; + }; + + /** + * Given a timestamp, format it in the form hh:mm am/pm. Defaults to now + * if the timestamp is undefined. + * + * @param {Number} timestamp + * @param {string} date + */ + FirechatUI.prototype.formatTime = function(timestamp) { + var date = (timestamp) ? new Date(timestamp) : new Date(), + hours = date.getHours() || 12, + minutes = '' + date.getMinutes(), + ampm = (date.getHours() >= 12) ? 'pm' : 'am'; + + hours = (hours > 12) ? hours - 12 : hours; + minutes = (minutes.length < 2) ? '0' + minutes : minutes; + return '' + hours + ':' + minutes + ampm; + }; + + /** + * Launch a prompt to allow the user to create a new room. + */ + FirechatUI.prototype.promptCreateRoom = function() { + var self = this; + var template = FirechatDefaultTemplates["templates/prompt-create-room.html"]; + + var $prompt = this.prompt('Create Public Room', template({ + maxLengthRoomName: this.maxLengthRoomName, + isModerator: self._chat.userIsModerator() + })); + $prompt.find('a.close').first().click(function() { + $prompt.remove(); + return false; + }); + + + $prompt.find('[data-toggle=submit]').first().click(function() { + var name = $prompt.find('[data-input=firechat-room-name]').first().val(); + if (name !== '') { + self._chat.createRoom(name, 'public'); + $prompt.remove(); + } + return false; + }); + + $prompt.find('[data-input=firechat-room-name]').first().focus(); + $prompt.find('[data-input=firechat-room-name]').first().bind('keydown', function(e) { + if (e.which === 13) { + var name = $prompt.find('[data-input=firechat-room-name]').first().val(); + if (name !== '') { + self._chat.createRoom(name, 'public'); + $prompt.remove(); + return false; + } + } + }); + }; + + /** + * Inner method to launch a prompt given a specific title and HTML content. + * @param {string} title + * @param {string} content + */ + FirechatUI.prototype.prompt = function(title, content) { + var template = FirechatDefaultTemplates["templates/prompt.html"], + $prompt; + + $prompt = $(template({ + title: title, + content: content + })).css({ + top: this.$wrapper.position().top + (0.333 * this.$wrapper.height()), + left: this.$wrapper.position().left + (0.125 * this.$wrapper.width()), + width: 0.75 * this.$wrapper.width() + }); + this.$wrapper.append($prompt.removeClass('hidden')); + return $prompt; + }; + + // see http://stackoverflow.com/questions/37684/how-to-replace-plain-urls-with-links + FirechatUI.prototype.linkify = function(str) { + var self = this; + return str + .replace(self.urlPattern, '$&') + .replace(self.pseudoUrlPattern, '$1$2'); + }; + +})(jQuery); + +var spinner = new Spinner({ + color: '#ddd' +}); +var firebaseRef = 'https://brilliant-fire-2797.firebaseio.com'; + +function handleFileSelect(evt) { + var f = evt.target.files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var filePayload = e.target.result; + // Generate a location that can't be guessed using the file's contents and a random number + var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); + var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); + spinner.spin(document.getElementById('spin')); + // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview + f.set(filePayload, function() { + spinner.stop(); + console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created') + }); + }; + })(f); + reader.readAsDataURL(f); +} +/* +CryptoJS v3.0.2 +code.google.com/p/crypto-js +(c) 2009-2012 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +var CryptoJS=CryptoJS||function(i,p){var f={},q=f.lib={},j=q.Base=function(){function a(){}return{extend:function(h){a.prototype=this;var d=new a;h&&d.mixIn(h);d.$super=this;return d},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var d in a)a.hasOwnProperty(d)&&(this[d]=a[d]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.$super.extend(this)}}}(),k=q.WordArray=j.extend({init:function(a,h){a= +this.words=a||[];this.sigBytes=h!=p?h:4*a.length},toString:function(a){return(a||m).stringify(this)},concat:function(a){var h=this.words,d=a.words,c=this.sigBytes,a=a.sigBytes;this.clamp();if(c%4)for(var b=0;b>>2]|=(d[b>>>2]>>>24-8*(b%4)&255)<<24-8*((c+b)%4);else if(65535>>2]=d[b>>>2];else h.push.apply(h,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,b=this.sigBytes;a[b>>>2]&=4294967295<<32-8*(b%4);a.length=i.ceil(b/4)},clone:function(){var a= +j.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var b=[],d=0;d>>2]>>>24-8*(c%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c>>3]|=parseInt(a.substr(c,2),16)<<24-4*(c%8);return k.create(d,b/2)}},s=r.Latin1={stringify:function(a){for(var b= +a.words,a=a.sigBytes,d=[],c=0;c>>2]>>>24-8*(c%4)&255));return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c>>2]|=(a.charCodeAt(c)&255)<<24-8*(c%4);return k.create(d,b)}},g=r.Utf8={stringify:function(a){try{return decodeURIComponent(escape(s.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data");}},parse:function(a){return s.parse(unescape(encodeURIComponent(a)))}},b=q.BufferedBlockAlgorithm=j.extend({reset:function(){this._data=k.create(); +this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=g.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var b=this._data,d=b.words,c=b.sigBytes,e=this.blockSize,f=c/(4*e),f=a?i.ceil(f):i.max((f|0)-this._minBufferSize,0),a=f*e,c=i.min(4*a,c);if(a){for(var g=0;ge;)f(b)&&(8>e&&(k[e]=g(i.pow(b,0.5))),r[e]=g(i.pow(b,1/3)),e++),b++})();var m=[],j=j.SHA256=f.extend({_doReset:function(){this._hash=q.create(k.slice(0))},_doProcessBlock:function(f,g){for(var b=this._hash.words,e=b[0],a=b[1],h=b[2],d=b[3],c=b[4],i=b[5],j=b[6],k=b[7],l=0;64> +l;l++){if(16>l)m[l]=f[g+l]|0;else{var n=m[l-15],o=m[l-2];m[l]=((n<<25|n>>>7)^(n<<14|n>>>18)^n>>>3)+m[l-7]+((o<<15|o>>>17)^(o<<13|o>>>19)^o>>>10)+m[l-16]}n=k+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&i^~c&j)+r[l]+m[l];o=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&a^e&h^a&h);k=j;j=i;i=c;c=d+n|0;d=h;h=a;a=e;e=n+o|0}b[0]=b[0]+e|0;b[1]=b[1]+a|0;b[2]=b[2]+h|0;b[3]=b[3]+d|0;b[4]=b[4]+c|0;b[5]=b[5]+i|0;b[6]=b[6]+j|0;b[7]=b[7]+k|0},_doFinalize:function(){var f=this._data,g=f.words,b=8*this._nDataBytes, +e=8*f.sigBytes;g[e>>>5]|=128<<24-e%32;g[(e+64>>>9<<4)+15]=b;f.sigBytes=4*g.length;this._process()}});p.SHA256=f._createHelper(j);p.HmacSHA256=f._createHmacHelper(j)})(Math); diff --git a/dist/firechat.min.css b/dist/firechat.min.css new file mode 100644 index 0000000..15bd92d --- /dev/null +++ b/dist/firechat.min.css @@ -0,0 +1 @@ +@charset "UTF-8";#firechat div,#firechat span,#firechat applet,#firechat object,#firechat iframe,#firechat h1,#firechat h2,#firechat h3,#firechat h4,#firechat h5,#firechat h6,#firechat p,#firechat blockquote,#firechat pre,#firechat a,#firechat abbr,#firechat acronym,#firechat address,#firechat big,#firechat cite,#firechat code,#firechat del,#firechat dfn,#firechat em,#firechat img,#firechat ins,#firechat kbd,#firechat q,#firechat s,#firechat samp,#firechat small,#firechat strike,#firechat strong,#firechat sub,#firechat sup,#firechat tt,#firechat var,#firechat b,#firechat u,#firechat i,#firechat center,#firechat dl,#firechat dt,#firechat dd,#firechat ol,#firechat ul,#firechat li,#firechat fieldset,#firechat form,#firechat label,#firechat legend,#firechat table,#firechat caption,#firechat tbody,#firechat tfoot,#firechat thead,#firechat tr,#firechat th,#firechat td,#firechat article,#firechat aside,#firechat canvas,#firechat details,#firechat embed,#firechat figure,#firechat figcaption,#firechat footer,#firechat header,#firechat hgroup,#firechat menu,#firechat nav,#firechat output,#firechat ruby,#firechat section,#firechat summary,#firechat time,#firechat mark,#firechat audio,#firechat video{border:0;font-size:12px;font-family:arial,helvetica,sans-serif;vertical-align:baseline;margin:0;padding:0}#firechat article,#firechat aside,#firechat details,#firechat figcaption,#firechat figure,#firechat footer,#firechat header,#firechat hgroup,#firechat menu,#firechat nav,#firechat section{display:block}#firechat body{line-height:1}#firechat ol,#firechat ul{list-style:none}#firechat blockquote,#firechat q{quotes:none}#firechat blockquote:before,#firechat blockquote:after,#firechat q:before,#firechat q:after{content:none}#firechat table{border-collapse:collapse;border-spacing:0}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}#firechat{color:#333;text-align:left}#firechat .center{float:none!important;margin-left:auto!important;margin-right:auto!important}#firechat .left{float:left!important}#firechat .right{float:right!important}#firechat .alignleft{text-align:left!important}#firechat .alignright{text-align:right!important}#firechat .aligncenter{text-align:center!important}#firechat .hidden{display:none!important}#firechat .row{clear:both}#firechat .fifth,#firechat .fivesixth,#firechat .fourfifth,#firechat .half,#firechat .ninetenth,#firechat .quarter,#firechat .sevententh,#firechat .sixth,#firechat .tenth,#firechat .third,#firechat .threefifth,#firechat .threequarter,#firechat .threetenth,#firechat .twofifth,#firechat .twothird,#firechat .full{margin-left:2.127659574468085%;float:left;min-height:1px}#firechat .fifth:first-child,#firechat .fivesixth:first-child,#firechat .fourfifth:first-child,#firechat .half:first-child,#firechat .ninetenth:first-child,#firechat .quarter:first-child,#firechat .sevententh:first-child,#firechat .sixth:first-child,#firechat .tenth:first-child,#firechat .third:first-child,#firechat .threefifth:first-child,#firechat .threequarter:first-child,#firechat .threetenth:first-child,#firechat .twofifth:first-child,#firechat .twothird:first-child,#firechat .full:first-child{margin-left:0}#firechat .tenth{width:8.08510638297872%}#firechat .sixth{width:14.893617021276595%}#firechat .fifth{width:18.297872340425535%}#firechat .quarter{width:23.404255319148938%}#firechat .threetenth{width:26.3829787235%}#firechat .third{width:31.914893617021278%}#firechat .twofifth{width:38.72340425531915%}#firechat .half{width:48.93617021276596%}#firechat .sevententh{width:58.7234042555%}#firechat .threefifth{width:59.14893617021278%}#firechat .twothird{width:65.95744680851064%}#firechat .threequarter{width:74.46808510638297%}#firechat .ninetenth{width:74.8936170215%}#firechat .fourfifth{width:79.57446808510639%}#firechat .fivesixth{width:82.9787234042553%}#firechat .full{width:100%}#firechat .clipped{overflow:hidden}#firechat strong{font-weight:bold}#firechat em{font-style:italic}#firechat label{display:block}#firechat a{color:#005580}#firechat a:visited,#firechat a:hover,#firechat a:active{color:#005580}#firechat p{margin:10px 0}#firechat h1,#firechat h2,#firechat h3,#firechat h4,#firechat h5,#firechat h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit}#firechat h1,#firechat h2,#firechat h3{line-height:40px}#firechat h1{font-size:38.5px}#firechat h2{font-size:31.5px}#firechat h3{font-size:24.5px}#firechat h4{font-size:17.5px}#firechat h5{font-size:14px}#firechat h6{font-size:11.9px}#firechat small{font-size:90%}#firechat .nav{list-style:none}#firechat .nav>li>a{display:block;background-color:#eee;text-decoration:none;overflow:hidden;white-space:nowrap}#firechat .nav>li>a:hover,#firechat .nav>li>a:focus{background-color:#fff}#firechat .nav-tabs{border-bottom:1px solid #ddd;clear:both}#firechat .nav-tabs>li{float:left;margin-bottom:-1px;max-width:45%}#firechat .nav-tabs>li>a{-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px;padding:4px 8px;margin-right:2px;line-height:20px;border:1px solid transparent;border-color:#ccc}#firechat .nav-tabs>.active>a,#firechat .nav-tabs>.active>a:hover,#firechat .nav-tabs>.active>a:focus{border-bottom-color:transparent;background-color:#fff;cursor:default}#firechat .tab-content{overflow:auto}#firechat .tab-content>.tab-pane{display:none}#firechat .tab-content>.active{display:block;background-color:#fff}#firechat .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";margin-top:8px;margin-left:2px}#firechat .firechat-dropdown{position:relative}#firechat .firechat-dropdown-toggle{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none}#firechat .firechat-dropdown-toggle:focus,#firechat .firechat-dropdown-toggle:active{outline:0;text-decoration:none}#firechat .firechat-dropdown-toggle.btn{padding:4px 0 0;height:22px}#firechat .firechat-dropdown-menu{*zoom:1;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0;z-index:1000;display:none;float:left;position:absolute;top:100%;left:0;width:100%;background-color:#fff;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;min-width:98%;padding:0;margin:-1px 0 0}#firechat .firechat-dropdown-menu:before,#firechat .firechat-dropdown-menu:after{display:table;content:"";line-height:0}#firechat .firechat-dropdown-menu:after{clear:both}#firechat .firechat-dropdown-menu ul{background-color:#fff;list-style:none;overflow-y:scroll;max-height:300px}#firechat .firechat-dropdown-menu ul>li>a{display:block;padding:1px 1px 1px 3px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}#firechat .firechat-dropdown-menu ul>li>a.highlight{background-color:#d9edf7}#firechat .firechat-dropdown-menu ul>li>a:hover,#firechat .firechat-dropdown-menu ul>li>a:focus,#firechat .firechat-dropdown-menu ul>.active>a,#firechat .firechat-dropdown-menu ul>.active>a:hover,#firechat .firechat-dropdown-menu ul>.active>a:focus{text-decoration:none;color:#000;background-color:#d9edf7;outline:0}#firechat .firechat-dropdown-menu ul>.disabled>a,#firechat .firechat-dropdown-menu ul>.disabled>a:hover,#firechat .firechat-dropdown-menu ul>.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;background-image:none;cursor:default}#firechat .firechat-dropdown-header{position:relative;width:100%;padding:10px 0;background-color:#eee;border-bottom:1px solid #ccc}#firechat .firechat-dropdown-footer{position:relative;width:100%;padding:10px 0;background-color:#eee;border-top:1px solid #ccc;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#firechat .open{*z-index:1000}#firechat .open>.firechat-dropdown-menu{display:block;border:1px solid #ccc;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0}#firechat .open>.firechat-dropdown-toggle{outline:0;text-decoration:none;-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px}#firechat .prompt-wrapper{position:absolute;z-index:1000}#firechat .prompt{position:absolute;z-index:1001;background-color:#fff;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.45);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.45);box-shadow:0 5px 10px rgba(0,0,0,0.45)}#firechat .prompt-header{padding:4px 8px;font-weight:bold;background-color:#eee;border:1px solid #ccc;-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px}#firechat .prompt-header a.close{opacity:.6;font-size:13px;margin-top:2px}#firechat .prompt-header a.close:hover{opacity:.9}#firechat .prompt-body{background-color:#fff;padding:4px 8px;border-left:1px solid #ccc;border-right:1px solid #ccc}#firechat .prompt-footer{padding:4px 8px;background-color:#eee;border:1px solid #ccc;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0}#firechat .prompt-background{background-color:#333;border:1px solid #333;opacity:.8;z-index:1000;height:100%;width:100%}#firechat .btn{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;height:24px;display:inline-block;*display:inline;*zoom:1;padding:2px 5px;margin-bottom:0;text-align:center;vertical-align:middle;cursor:pointer;color:#333;font-size:12px;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}#firechat .btn:hover,#firechat .btn:focus,#firechat .btn:active,#firechat .btn.active,#firechat .btn.disabled,#firechat .btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9;outline:0}#firechat .btn:active,#firechat .btn.active{background-color:#ccc}#firechat .btn:first-child{*margin-left:0}#firechat .btn:hover,#firechat .btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}#firechat .btn.active,#firechat .btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}#firechat .btn.disabled,#firechat .btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65)}#firechat .btn.disabled:active,#firechat .btn[disabled]:active{-webkit-box-shadow:inherit;-moz-box-shadow:inherit;box-shadow:inherit;background-color:#e6e6e6}#firechat .contextmenu{position:fixed;z-index:1001;min-width:150px;border:1px solid #ccc;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}#firechat .contextmenu ul{background-color:#fff;list-style:none}#firechat .contextmenu ul>li>a{display:block;padding:3px 10px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}#firechat .contextmenu ul>li>a.highlight{background-color:#d9edf7}#firechat .contextmenu ul>li>a:hover,#firechat .contextmenu ul>li>a:focus{text-decoration:none;color:#fff;background-color:#0081c2;outline:0}#firechat{padding:0;font-family:sans-serif;font-size:12px;line-height:18px}#firechat input,#firechat textarea{width:100%;font-family:sans-serif;font-size:12px;line-height:18px;padding:2px 5px;border:1px solid #ccc;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#firechat input:-moz-placeholder,#firechat textarea:-moz-placeholder{color:#aaa}#firechat input:-ms-input-placeholder,#firechat textarea:-ms-input-placeholder{color:#aaa}#firechat input::-webkit-input-placeholder,#firechat textarea::-webkit-input-placeholder{color:#aaa}#firechat input[disabled],#firechat textarea[disabled]{background-color:#eee}#firechat input{height:24px}#firechat textarea{resize:none;height:40px}#firechat .search-wrapper{-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;border:1px solid #ccc;margin:0 5px;padding:2px 5px;background:#fff}#firechat .search-wrapper>input[type=text]{padding-left:0;border:0}#firechat .search-wrapper>input[type=text]:focus,#firechat .search-wrapper>input[type=text]:active{outline:0}#firechat .chat{overflow:auto;-ms-overflow-x:hidden;overflow-x:hidden;height:290px;position:relative;margin-bottom:5px;border:1px solid #ccc;border-top:0;overflow-y:scroll}#firechat .chat textarea{overflow:auto;vertical-align:top}#firechat #textarea-container{position:relative;width:100%;float:left;height:35px}#firechat #uploaded-image{display:none}#firechat #upload-icon{position:absolute;float:right;height:16px;width:18px;bottom:0;right:5px}#firechat #file-upload{display:none;position:relative;overflow:hidden;z-index:2;opacity:0}#firechat .message{color:#333;padding:3px 5px;border-bottom:1px solid #ccc}#firechat .message.highlighted{background-color:#d9edf7}#firechat .message .name{font-weight:bold;overflow-x:hidden}#firechat .message.message-self{color:#2675ab}#firechat .message:nth-child(odd){background-color:#f9f9f9}#firechat .message:nth-child(odd).highlighted{background-color:#d9edf7}#firechat .message:nth-child(odd).message-local{background-color:#effafc}#firechat .message-content{word-wrap:break-word;padding-right:45px}#firechat .message-content.red{color:red}#firechat .message.message-notification .message-content{font-style:italic}#firechat ul::-webkit-scrollbar{-webkit-appearance:none;width:7px}#firechat ul::-webkit-scrollbar-thumb{border-radius:4px;-webkit-box-shadow:0 0 1px rgba(255,255,255,0.5)}#firechat #firechat-header{padding:6px 0 0 0;height:40px}#firechat #firechat-tabs{height:435px}#firechat #firechat-tab-list{background-color:#fff}#firechat #firechat-tab-content{width:100%;background-color:#fff}#firechat .tab-pane-menu{border:1px solid #ccc;border-top:0;vertical-align:middle;padding-bottom:5px}#firechat .tab-pane-menu .firechat-dropdown{margin:5px 0 0 5px}#firechat .tab-pane-menu>.icon{margin:5px 2px 0}#firechat .icon{display:inline-block;*margin-right:.3em;line-height:20px;vertical-align:middle;background-repeat:no-repeat;padding:0;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAL8AAAANEAYAAACoeGM7AAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAM80lEQVR42t2cZ4xWRRfHZ3dhwbK7CJZYYiOxV+wlUQzCKmBBsWPvYjQiaiyxYUwULLErltgrNpRF4q5iV0BRLFE0diUi7LIq6Pqw74f//rzO4Zm9d+5z9c37ni//3OfemXtm5sypc58q55xzrrpauHSpcOONheedJ9x9d2Hv3sLvvxfefbfw5puFf/5Zvr+8VFUl7Ozs/rkNNxTef79w222F77wjPOoo4ccfF/O+UDvGzTVEf8wH1zU1wlJJePTRwv33Fx57rPDnn/1+wbzzG+IXvrhmPUPzY/kJEc/HzqslK1fLLy8cMUK4667CFVYQ/vqr8PXXhU884f8eL6eXXKJ2wqSd3tDY2KOHc84NGqSRnnCC7tbVCdvbhRMnasWnTdt5Z+eca2pK6797Yh6ef1641lrCPfYQfv21UNwl62qv115b2Nws/PZb4d57C3/7LftalaOQ/C63nPCII4Tsg6228scHffqp8LHHhPfe6/8eu49feEH44YfCq64S/v67cMGC7tuvu65w6FDhllsKkS/0zoQJaZzMmSO+JaEzZmgkY8b88Ydzzs2b19HhnHNffSWJ6tVLM1cq/fKLrjXiUaPUrn9/XZ9yip6rqVmyxDnnnnrKvPbAA4V6TTJxP/zgT4zdyC+9JOzXz++PgceSVSS1tUJtE+c22si/f+21Pj9Wwd54o//8ZpsJd9xR2KtX9+8vmkLzcsABPt9z5wr32af88xiOf4oaGoSHH17M+/LKg203aJDwiy+EVh5DyHzuuWcxfDn31lvOOffMM7Nn6z1SsZ2dn30m/OQT4eefC7/8UvjBB0LaVzav7D873vfeE6LQISvv3Of50P6OJetgWFp5ZeFzz5V/b1bEEd1333x80g+O4mWXCXEQMDB33CG8/XYhBhuDmMZnOn30kZ5/+23nnGtpefNN55wbP96Xl/nzhYsWCdvauEbeQP1Of6US/XRZfDz8Bx8U9uwpPPFE4eOPC/EMVl9dOG6ccORI4Q03CA87LHbA5RcCwgO47TbhokXCYcOERCKQ7GJiMLiPokeQ2QCjRwtvukkY6zHg0V10kXDAAH++EIz77hM++aRwxRWFq64q3H57v9/+/YVPPy2cOFF47rnCNE8kll/Gi4eIAWU9v/vOnz8MA4qjb18hG51+2JiLF+ebX/hA4U+b5t+/7jrhAw8IkQ88WvnPiZzi4Q0eXL6/dEJhawaGDydmk4uEQmhu1kj79tVImb8RI8TZwIG0p78ddnAubOhDhIcPIXd4nnh4OHYYzPXXF7K/ed5GBLb/NLKRFOtMfyCZAiIKns8aSVp9xP4i8nv//Ti+icjgl0iDeUsjpKDSyJYeqqs1A+3taDBpkn79Qi5YW9vf5wXq0YP+1L5U6loAUjpW4WPhQhN00EFC2SXnDj1UiAF44w2hTWnEEqkcCIWJYkShQNbDIIJZZx2h9Xhs/7EpFDwCNs6UKf584tGQsiFCGTJEuMEG/jxBzBe/H3+8cJddhBiAZ58thl/eM2uW8MgjhWyAyy8XojhRUGuuKayvF7Jhf/pJ+O67wltvFU6dGscv78fTgg45RPjII+XbYZA23bT8/Vtu8ecBDy9MpHS0EROFr1B76lQp7r32su20EwYMkGSOG4dq4I0a4fDh9G9TQN0TKR0iB8aD3G+9tRDHDoPPenKf53GYiABiPWm7f046SUgKDs8aQwxlVfiQTVXh0BChxir+kDol5WPv24im+Ahcb6iu9jVnR4euGX9oXsLj7GKYHP68eUI8ANsRA7WKE8sNkUopdvgJsW0QUBbc3oewl6GQs9LUDgr85JOF5OZHjRKyESZNEp55ppBIC7IbxgoSkQzt2OgXX1wMv9RCFBAuG4HgSREKU0vB42Jjo6gxtPvtJ8TzTM91+kQOf731hHj4KHybA0bRK8B1bpNNhAqkE8OH40CKLZ3I4a+0kq6l8JuapPAbGx991Lm/r5s8+aFDlWOdOVMuS0ODNm5bm1RWSwsSrJY2FZVGRFYYYgwt+wO5EpeJ4eaa+zxPexQ+/Wcl+iFCxeBvs43QRujW048lu09Y16KI/m3Ewu8h/VS55w/5b7AGMrbW5lyXImQh8EhtqGBDGOu525QDnm5RhOcBzZ8vfO01IYIaev/Mmf5zpALsfSiv5bYLfeqpQhSUrYHY92GYbD+shx0XKSOKlrFk1xHFTQRon7M1FNtepaOErwsvFBIqkzKKlQ8MDoTnCpFKwyCi2FZbTYhDgydO6gfaaaesnFC0xQcUUQwlBi6VpPCHDJGKmDyZGWMldY2nPmmSP5NEdlkJRYSCZr7FRbiIzTX3eZ72tiiclZjf444rzyd6hkid9+fNCNhxvfJKvn5C/YVy9nZVYw89ZCdfI6TVEuCLCI4Zhp+Ojq6FIAdLFR0PjpQOFpyFsQMidw5ZxRo7ATaEI6fMgFD8FJsxXCgee00qSiWPJNfKaYLp08u/P1YQ4ZfxWgWDAcOjZmMR8G+3nZBTPbwffhYuFJ5zjhCPKi9ZBUzkh8dpBTkk2KSKLr1UiAIJEYYhK2GQIOto4OGj8NdYQ4hck8tnvkmtQSGDHKK6On8nUNtIPHwUvp05SeSwYTI1s2YpJhk5kliO/uP4Qe6IxMnhk9JhXqyCtQ4Oz9Oe/nwzl05EtJbI5fMeTs8QscIP+zwtEuA+csz+fvjhOH5tf6SSoZCjEipeKw5MVj12PemZ9tXVvunt2dOuHE+K06oqvbG2lp2ikS1ZIknv3burO45lXn+9kKItOfzQwhO6jR0r5PiXPaUQmzNHkMllIyhMMBudmgKnjqxnwnSssooQhWpTLOR6UVwc/4ul1lYhx7rwRBF4PBEEwxLFavhkeTmmN2aMEAG3ghdrqHx149z555efx9DGY37vvFNoPcxQe1v0SyObe8cRIYf/4otCPHwUPsVge4yXWgTEumWl9nZtsPp6irbk8OVyTJ5sYyRJdGOjkitJjUP3FyzwNzIOV1ZivdinFG3J4dt5twqW9eJ5nUFKDIB1xNIIh8p6oijUa64RcnyT2SLSJHWXdtqKcdD/BRcIifBiCf44TIGe2WILYaiGhWHFoaFGxnxtvnlWDvwZY/yLF6toy+8LF2rGamrESXK8WRIwe7YcjKYmzdD06Xpi7lzFWqR4/1pYeywMT5ncL4rpiiuE9tgnIRyeozP9ZyVSBNZyskHxpFFUCGroOCf36Zf28MtzRCqxOXPaM24iJxsJQQgOCgyiqM4GJvduKZRbjOWXXH+fPkKKiUQmOnyYRBrwZeeXCIxxQ/mPSfpEkZn3KZO+7PHiH38U2mKurQHY478ooHSSaZswgWOZum5uFra2iqPOTs0g93EE4NzWAKZM4RioIoDx4/PNE4YQxWNTs6HUgL1Pe3sMNCuF9qOVG2penIPHYOHokcJ8+WVhS4sQR4NaJP3F7luI9tSALBFxovhBW6uonFSORm7mzMEAzJjhnHMNDdLI9fXgq68651xdnZLYffpY+cpIhLzkUNNySd98I7QKFPs0cGC+4dv3sCAYIE4bhXJboWvwrruExxwjJPWStyjD8/b0AyEiCt4Wh6xBpCi+225CG5kUdWogxC/HMyldshGJ7IhcWIfTTxciLxhWqKgcJxuPc/h2nTAAaYrq4IP9dni01jCEiVM3nIdWdaizUxuTDdvaSgQQ6kfPNTVhKPgOgP7j5id0Dh9DbR05Unlch54PfQeQRuyrUM7ZOoxkCq6+WkikhiOBIQ/JEx7sGWfE8QlZOYKyOi7sS+uQgdn3ra/4LT/ZSS1razEEfBgoOf0rdRUaIB4rXyCedpqQFAu5KzxdPyBJPPRlj7d1Tw89JLznHiGeb+hDFVIWIQPll9SS3ynKUUwj5RWbI6Q/inWVEgJsUxRFKdKi+T3rLKEtshf9IZytPdgIgNM75PA5dWQ9fBAFE0+cu+dDGQyAHwGMHi0P/sordT12LB4+Ct//0Cbvh1zWINr9gAePIYe4thGCbU//sYRHn/fDLBwyawhDOfe8ESbvCx3/zHuKJp5Cil8cVlVlxcjXhv5yICvh4aPwreDlJY5nUay1Cj2rINn2lD4qPX6KwcPzRQHhKeP5WeQ+ng2nSyhCcv4fKip1EuIXRQlfXIMUn7nPl9SkhKhFFM2v7QcDEIoAQoiHbxV+5V/uEgGQAuJLXRQ7X/KS0sHD///8cpcIl/P69MN3GDh2RBzUvvjLFVI2NuK1einty+CsZDMY/z0qyuOvkGwIY8+zMuE2ZYGHj8JHUWQlm/sm1ENRZ81dWrShLEVAy1/20F9EEZrTQnk9HJCNYL+YLMrD+F/jF7IbnBQQNQDOi/MFJ9fk8O26xisMQmb7OykaagD+p/RLl3JNDj+U0gn13z0xLhQ0BtEqfLtP7TXP057+YvcDCpvDInwvYInUcnIqqjLKK2/IydlnF8NHfvq3FP9/ANgTCJ9z9ZF7AAAAAElFTkSuQmCC) no-repeat top left;opacity:.3;font-size:22px;font-family:Arial;font-weight:bold;overflow:hidden}#firechat .icon.plus{margin-top:0;vertical-align:top;background:transparent}#firechat .icon.search{background-position:0 0;width:13px;height:13px}#firechat .icon.close{background-position:-120px 0;width:13px;height:13px}#firechat .icon.user-chat{background-position:-138px 0;width:17px;height:13px}#firechat .icon.user-group{background-position:-18px 0;width:17px;height:13px}#firechat .icon.user-mute{background-position:-84px 0;width:13px;height:13px}#firechat .icon.user-mute.red{background-position:-102px 0;width:13px;height:13px}#firechat .icon:hover,#firechat .btn:hover>.icon{opacity:.6}#firechat a>.icon{margin:3px 1px} \ No newline at end of file diff --git a/dist/firechat.min.js b/dist/firechat.min.js new file mode 100644 index 0000000..485a664 --- /dev/null +++ b/dist/firechat.min.js @@ -0,0 +1,3 @@ +function handleFileSelect(a){var b=a.target.files[0],c=new FileReader;c.onload=function(a){return function(a){var b=a.target.result,c=CryptoJS.SHA256(Math.random()+CryptoJS.SHA256(b)),d=new Firebase(firebaseRef+"pano/"+c+"/filePayload");spinner.spin(document.getElementById("spin")),d.set(b,function(){spinner.stop(),console.log("File with hash: "+firebaseRef+"pano/"+c+"/filePayload created")})}}(b),c.readAsDataURL(b)}(function(){var a=this,b=a._,c=Array.prototype,d=Object.prototype,e=Function.prototype,f=c.push,g=c.slice,h=c.concat,i=d.toString,j=d.hasOwnProperty,k=Array.isArray,l=Object.keys,m=e.bind,n=function(a){return a instanceof n?a:this instanceof n?void(this._wrapped=a):new n(a)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=n),exports._=n):a._=n,n.VERSION="1.7.0";var o=function(a,b,c){if(void 0===b)return a;switch(null==c?3:c){case 1:return function(c){return a.call(b,c)};case 2:return function(c,d){return a.call(b,c,d)};case 3:return function(c,d,e){return a.call(b,c,d,e)};case 4:return function(c,d,e,f){return a.call(b,c,d,e,f)}}return function(){return a.apply(b,arguments)}};n.iteratee=function(a,b,c){return null==a?n.identity:n.isFunction(a)?o(a,b,c):n.isObject(a)?n.matches(a):n.property(a)},n.each=n.forEach=function(a,b,c){if(null==a)return a;b=o(b,c);var d,e=a.length;if(e===+e)for(d=0;e>d;d++)b(a[d],d,a);else{var f=n.keys(a);for(d=0,e=f.length;e>d;d++)b(a[f[d]],f[d],a)}return a},n.map=n.collect=function(a,b,c){if(null==a)return[];b=n.iteratee(b,c);for(var d,e=a.length!==+a.length&&n.keys(a),f=(e||a).length,g=Array(f),h=0;f>h;h++)d=e?e[h]:h,g[h]=b(a[d],d,a);return g};var p="Reduce of empty array with no initial value";n.reduce=n.foldl=n.inject=function(a,b,c,d){null==a&&(a=[]),b=o(b,d,4);var e,f=a.length!==+a.length&&n.keys(a),g=(f||a).length,h=0;if(arguments.length<3){if(!g)throw new TypeError(p);c=a[f?f[h++]:h++]}for(;g>h;h++)e=f?f[h]:h,c=b(c,a[e],e,a);return c},n.reduceRight=n.foldr=function(a,b,c,d){null==a&&(a=[]),b=o(b,d,4);var e,f=a.length!==+a.length&&n.keys(a),g=(f||a).length;if(arguments.length<3){if(!g)throw new TypeError(p);c=a[f?f[--g]:--g]}for(;g--;)e=f?f[g]:g,c=b(c,a[e],e,a);return c},n.find=n.detect=function(a,b,c){var d;return b=n.iteratee(b,c),n.some(a,function(a,c,e){return b(a,c,e)?(d=a,!0):void 0}),d},n.filter=n.select=function(a,b,c){var d=[];return null==a?d:(b=n.iteratee(b,c),n.each(a,function(a,c,e){b(a,c,e)&&d.push(a)}),d)},n.reject=function(a,b,c){return n.filter(a,n.negate(n.iteratee(b)),c)},n.every=n.all=function(a,b,c){if(null==a)return!0;b=n.iteratee(b,c);var d,e,f=a.length!==+a.length&&n.keys(a),g=(f||a).length;for(d=0;g>d;d++)if(e=f?f[d]:d,!b(a[e],e,a))return!1;return!0},n.some=n.any=function(a,b,c){if(null==a)return!1;b=n.iteratee(b,c);var d,e,f=a.length!==+a.length&&n.keys(a),g=(f||a).length;for(d=0;g>d;d++)if(e=f?f[d]:d,b(a[e],e,a))return!0;return!1},n.contains=n.include=function(a,b){return null==a?!1:(a.length!==+a.length&&(a=n.values(a)),n.indexOf(a,b)>=0)},n.invoke=function(a,b){var c=g.call(arguments,2),d=n.isFunction(b);return n.map(a,function(a){return(d?b:a[b]).apply(a,c)})},n.pluck=function(a,b){return n.map(a,n.property(b))},n.where=function(a,b){return n.filter(a,n.matches(b))},n.findWhere=function(a,b){return n.find(a,n.matches(b))},n.max=function(a,b,c){var d,e,f=-1/0,g=-1/0;if(null==b&&null!=a){a=a.length===+a.length?a:n.values(a);for(var h=0,i=a.length;i>h;h++)d=a[h],d>f&&(f=d)}else b=n.iteratee(b,c),n.each(a,function(a,c,d){e=b(a,c,d),(e>g||e===-1/0&&f===-1/0)&&(f=a,g=e)});return f},n.min=function(a,b,c){var d,e,f=1/0,g=1/0;if(null==b&&null!=a){a=a.length===+a.length?a:n.values(a);for(var h=0,i=a.length;i>h;h++)d=a[h],f>d&&(f=d)}else b=n.iteratee(b,c),n.each(a,function(a,c,d){e=b(a,c,d),(g>e||1/0===e&&1/0===f)&&(f=a,g=e)});return f},n.shuffle=function(a){for(var b,c=a&&a.length===+a.length?a:n.values(a),d=c.length,e=Array(d),f=0;d>f;f++)b=n.random(0,f),b!==f&&(e[f]=e[b]),e[b]=c[f];return e},n.sample=function(a,b,c){return null==b||c?(a.length!==+a.length&&(a=n.values(a)),a[n.random(a.length-1)]):n.shuffle(a).slice(0,Math.max(0,b))},n.sortBy=function(a,b,c){return b=n.iteratee(b,c),n.pluck(n.map(a,function(a,c,d){return{value:a,index:c,criteria:b(a,c,d)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;if(c!==d){if(c>d||void 0===c)return 1;if(d>c||void 0===d)return-1}return a.index-b.index}),"value")};var q=function(a){return function(b,c,d){var e={};return c=n.iteratee(c,d),n.each(b,function(d,f){var g=c(d,f,b);a(e,d,g)}),e}};n.groupBy=q(function(a,b,c){n.has(a,c)?a[c].push(b):a[c]=[b]}),n.indexBy=q(function(a,b,c){a[c]=b}),n.countBy=q(function(a,b,c){n.has(a,c)?a[c]++:a[c]=1}),n.sortedIndex=function(a,b,c,d){c=n.iteratee(c,d,1);for(var e=c(b),f=0,g=a.length;g>f;){var h=f+g>>>1;c(a[h])b?[]:g.call(a,0,b)},n.initial=function(a,b,c){return g.call(a,0,Math.max(0,a.length-(null==b||c?1:b)))},n.last=function(a,b,c){return null==a?void 0:null==b||c?a[a.length-1]:g.call(a,Math.max(a.length-b,0))},n.rest=n.tail=n.drop=function(a,b,c){return g.call(a,null==b||c?1:b)},n.compact=function(a){return n.filter(a,n.identity)};var r=function(a,b,c,d){if(b&&n.every(a,n.isArray))return h.apply(d,a);for(var e=0,g=a.length;g>e;e++){var i=a[e];n.isArray(i)||n.isArguments(i)?b?f.apply(d,i):r(i,b,c,d):c||d.push(i)}return d};n.flatten=function(a,b){return r(a,b,!1,[])},n.without=function(a){return n.difference(a,g.call(arguments,1))},n.uniq=n.unique=function(a,b,c,d){if(null==a)return[];n.isBoolean(b)||(d=c,c=b,b=!1),null!=c&&(c=n.iteratee(c,d));for(var e=[],f=[],g=0,h=a.length;h>g;g++){var i=a[g];if(b)g&&f===i||e.push(i),f=i;else if(c){var j=c(i,g,a);n.indexOf(f,j)<0&&(f.push(j),e.push(i))}else n.indexOf(e,i)<0&&e.push(i)}return e},n.union=function(){return n.uniq(r(arguments,!0,!0,[]))},n.intersection=function(a){if(null==a)return[];for(var b=[],c=arguments.length,d=0,e=a.length;e>d;d++){var f=a[d];if(!n.contains(b,f)){for(var g=1;c>g&&n.contains(arguments[g],f);g++);g===c&&b.push(f)}}return b},n.difference=function(a){var b=r(g.call(arguments,1),!0,!0,[]);return n.filter(a,function(a){return!n.contains(b,a)})},n.zip=function(a){if(null==a)return[];for(var b=n.max(arguments,"length").length,c=Array(b),d=0;b>d;d++)c[d]=n.pluck(arguments,d);return c},n.object=function(a,b){if(null==a)return{};for(var c={},d=0,e=a.length;e>d;d++)b?c[a[d]]=b[d]:c[a[d][0]]=a[d][1];return c},n.indexOf=function(a,b,c){if(null==a)return-1;var d=0,e=a.length;if(c){if("number"!=typeof c)return d=n.sortedIndex(a,b),a[d]===b?d:-1;d=0>c?Math.max(0,e+c):c}for(;e>d;d++)if(a[d]===b)return d;return-1},n.lastIndexOf=function(a,b,c){if(null==a)return-1;var d=a.length;for("number"==typeof c&&(d=0>c?d+c+1:Math.min(d,c+1));--d>=0;)if(a[d]===b)return d;return-1},n.range=function(a,b,c){arguments.length<=1&&(b=a||0,a=0),c=c||1;for(var d=Math.max(Math.ceil((b-a)/c),0),e=Array(d),f=0;d>f;f++,a+=c)e[f]=a;return e};var s=function(){};n.bind=function(a,b){var c,d;if(m&&a.bind===m)return m.apply(a,g.call(arguments,1));if(!n.isFunction(a))throw new TypeError("Bind must be called on a function");return c=g.call(arguments,2),d=function(){if(!(this instanceof d))return a.apply(b,c.concat(g.call(arguments)));s.prototype=a.prototype;var e=new s;s.prototype=null;var f=a.apply(e,c.concat(g.call(arguments)));return n.isObject(f)?f:e}},n.partial=function(a){var b=g.call(arguments,1);return function(){for(var c=0,d=b.slice(),e=0,f=d.length;f>e;e++)d[e]===n&&(d[e]=arguments[c++]);for(;c=d)throw new Error("bindAll must be passed function names");for(b=1;d>b;b++)c=arguments[b],a[c]=n.bind(a[c],a);return a},n.memoize=function(a,b){var c=function(d){var e=c.cache,f=b?b.apply(this,arguments):d;return n.has(e,f)||(e[f]=a.apply(this,arguments)),e[f]};return c.cache={},c},n.delay=function(a,b){var c=g.call(arguments,2);return setTimeout(function(){return a.apply(null,c)},b)},n.defer=function(a){return n.delay.apply(n,[a,1].concat(g.call(arguments,1)))},n.throttle=function(a,b,c){var d,e,f,g=null,h=0;c||(c={});var i=function(){h=c.leading===!1?0:n.now(),g=null,f=a.apply(d,e),g||(d=e=null)};return function(){var j=n.now();h||c.leading!==!1||(h=j);var k=b-(j-h);return d=this,e=arguments,0>=k||k>b?(clearTimeout(g),g=null,h=j,f=a.apply(d,e),g||(d=e=null)):g||c.trailing===!1||(g=setTimeout(i,k)),f}},n.debounce=function(a,b,c){var d,e,f,g,h,i=function(){var j=n.now()-g;b>j&&j>0?d=setTimeout(i,b-j):(d=null,c||(h=a.apply(f,e),d||(f=e=null)))};return function(){f=this,e=arguments,g=n.now();var j=c&&!d;return d||(d=setTimeout(i,b)),j&&(h=a.apply(f,e),f=e=null),h}},n.wrap=function(a,b){return n.partial(b,a)},n.negate=function(a){return function(){return!a.apply(this,arguments)}},n.compose=function(){var a=arguments,b=a.length-1;return function(){for(var c=b,d=a[b].apply(this,arguments);c--;)d=a[c].call(this,d);return d}},n.after=function(a,b){return function(){return--a<1?b.apply(this,arguments):void 0}},n.before=function(a,b){var c;return function(){return--a>0?c=b.apply(this,arguments):b=null,c}},n.once=n.partial(n.before,2),n.keys=function(a){if(!n.isObject(a))return[];if(l)return l(a);var b=[];for(var c in a)n.has(a,c)&&b.push(c);return b},n.values=function(a){for(var b=n.keys(a),c=b.length,d=Array(c),e=0;c>e;e++)d[e]=a[b[e]];return d},n.pairs=function(a){for(var b=n.keys(a),c=b.length,d=Array(c),e=0;c>e;e++)d[e]=[b[e],a[b[e]]];return d},n.invert=function(a){for(var b={},c=n.keys(a),d=0,e=c.length;e>d;d++)b[a[c[d]]]=c[d];return b},n.functions=n.methods=function(a){var b=[];for(var c in a)n.isFunction(a[c])&&b.push(c);return b.sort()},n.extend=function(a){if(!n.isObject(a))return a;for(var b,c,d=1,e=arguments.length;e>d;d++){b=arguments[d];for(c in b)j.call(b,c)&&(a[c]=b[c])}return a},n.pick=function(a,b,c){var d,e={};if(null==a)return e;if(n.isFunction(b)){b=o(b,c);for(d in a){var f=a[d];b(f,d,a)&&(e[d]=f)}}else{var i=h.apply([],g.call(arguments,1));a=new Object(a);for(var j=0,k=i.length;k>j;j++)d=i[j],d in a&&(e[d]=a[d])}return e},n.omit=function(a,b,c){if(n.isFunction(b))b=n.negate(b);else{var d=n.map(h.apply([],g.call(arguments,1)),String);b=function(a,b){return!n.contains(d,b)}}return n.pick(a,b,c)},n.defaults=function(a){if(!n.isObject(a))return a;for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];for(var e in d)void 0===a[e]&&(a[e]=d[e])}return a},n.clone=function(a){return n.isObject(a)?n.isArray(a)?a.slice():n.extend({},a):a},n.tap=function(a,b){return b(a),a};var t=function(a,b,c,d){if(a===b)return 0!==a||1/a===1/b;if(null==a||null==b)return a===b;a instanceof n&&(a=a._wrapped),b instanceof n&&(b=b._wrapped);var e=i.call(a);if(e!==i.call(b))return!1;switch(e){case"[object RegExp]":case"[object String]":return""+a==""+b;case"[object Number]":return+a!==+a?+b!==+b:0===+a?1/+a===1/b:+a===+b;case"[object Date]":case"[object Boolean]":return+a===+b}if("object"!=typeof a||"object"!=typeof b)return!1;for(var f=c.length;f--;)if(c[f]===a)return d[f]===b;var g=a.constructor,h=b.constructor;if(g!==h&&"constructor"in a&&"constructor"in b&&!(n.isFunction(g)&&g instanceof g&&n.isFunction(h)&&h instanceof h))return!1;c.push(a),d.push(b);var j,k;if("[object Array]"===e){if(j=a.length,k=j===b.length)for(;j--&&(k=t(a[j],b[j],c,d)););}else{var l,m=n.keys(a);if(j=m.length,k=n.keys(b).length===j)for(;j--&&(l=m[j],k=n.has(b,l)&&t(a[l],b[l],c,d)););}return c.pop(),d.pop(),k};n.isEqual=function(a,b){return t(a,b,[],[])},n.isEmpty=function(a){if(null==a)return!0;if(n.isArray(a)||n.isString(a)||n.isArguments(a))return 0===a.length;for(var b in a)if(n.has(a,b))return!1;return!0},n.isElement=function(a){return!(!a||1!==a.nodeType)},n.isArray=k||function(a){return"[object Array]"===i.call(a)},n.isObject=function(a){var b=typeof a;return"function"===b||"object"===b&&!!a},n.each(["Arguments","Function","String","Number","Date","RegExp"],function(a){n["is"+a]=function(b){return i.call(b)==="[object "+a+"]"}}),n.isArguments(arguments)||(n.isArguments=function(a){return n.has(a,"callee")}),"function"!=typeof/./&&(n.isFunction=function(a){return"function"==typeof a||!1}),n.isFinite=function(a){return isFinite(a)&&!isNaN(parseFloat(a))},n.isNaN=function(a){return n.isNumber(a)&&a!==+a},n.isBoolean=function(a){return a===!0||a===!1||"[object Boolean]"===i.call(a)},n.isNull=function(a){return null===a},n.isUndefined=function(a){return void 0===a},n.has=function(a,b){return null!=a&&j.call(a,b)},n.noConflict=function(){return a._=b,this},n.identity=function(a){return a},n.constant=function(a){return function(){return a}},n.noop=function(){},n.property=function(a){return function(b){return b[a]}},n.matches=function(a){var b=n.pairs(a),c=b.length;return function(a){if(null==a)return!c;a=new Object(a);for(var d=0;c>d;d++){var e=b[d],f=e[0];if(e[1]!==a[f]||!(f in a))return!1}return!0}},n.times=function(a,b,c){var d=Array(Math.max(0,a));b=o(b,c,1);for(var e=0;a>e;e++)d[e]=b(e);return d},n.random=function(a,b){return null==b&&(b=a,a=0),a+Math.floor(Math.random()*(b-a+1))},n.now=Date.now||function(){return(new Date).getTime()};var u={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},v=n.invert(u),w=function(a){var b=function(b){return a[b]},c="(?:"+n.keys(a).join("|")+")",d=RegExp(c),e=RegExp(c,"g");return function(a){return a=null==a?"":""+a,d.test(a)?a.replace(e,b):a}};n.escape=w(u),n.unescape=w(v),n.result=function(a,b){if(null==a)return void 0;var c=a[b];return n.isFunction(c)?a[b]():c};var x=0;n.uniqueId=function(a){var b=++x+"";return a?a+b:b},n.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var y=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},A=/\\|'|\r|\n|\u2028|\u2029/g,B=function(a){return"\\"+z[a]};n.template=function(a,b,c){!b&&c&&(b=c),b=n.defaults({},b,n.templateSettings);var d=RegExp([(b.escape||y).source,(b.interpolate||y).source,(b.evaluate||y).source].join("|")+"|$","g"),e=0,f="__p+='";a.replace(d,function(b,c,d,g,h){return f+=a.slice(e,h).replace(A,B),e=h+b.length,c?f+="'+\n((__t=("+c+"))==null?'':_.escape(__t))+\n'":d?f+="'+\n((__t=("+d+"))==null?'':__t)+\n'":g&&(f+="';\n"+g+"\n__p+='"),b}),f+="';\n",b.variable||(f="with(obj||{}){\n"+f+"}\n"),f="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+f+"return __p;\n";try{var g=new Function(b.variable||"obj","_",f)}catch(h){throw h.source=f,h}var i=function(a){return g.call(this,a,n)},j=b.variable||"obj";return i.source="function("+j+"){\n"+f+"}",i},n.chain=function(a){var b=n(a);return b._chain=!0,b};var C=function(a){return this._chain?n(a).chain():a};n.mixin=function(a){n.each(n.functions(a),function(b){var c=n[b]=a[b];n.prototype[b]=function(){var a=[this._wrapped];return f.apply(a,arguments),C.call(this,c.apply(n,a))}})},n.mixin(n),n.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=c[a];n.prototype[a]=function(){var c=this._wrapped;return b.apply(c,arguments),"shift"!==a&&"splice"!==a||0!==c.length||delete c[0],C.call(this,c)}}),n.each(["concat","join","slice"],function(a){var b=c[a];n.prototype[a]=function(){return C.call(this,b.apply(this._wrapped,arguments))}}),n.prototype.value=function(){return this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return n})}).call(this),!function(a,b,c){function d(a,c){var d,e=b.createElement(a||"div");for(d in c)e[d]=c[d];return e}function e(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function f(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=k.substring(0,k.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return m[e]||(n.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",n.cssRules.length),m[e]=1),e}function g(a,b){var d,e,f=a.style;if(f[b]!==c)return b;for(b=b.charAt(0).toUpperCase()+b.slice(1),e=0;e>1):parseInt(f.left,10)+i)+"px",top:("auto"==f.top?c.y-b.y+(a.offsetHeight>>1):parseInt(f.top,10)+i)+"px"})),g.setAttribute("aria-role","progressbar"),e.lines(g,e.opts),!k){var l=0,m=f.fps,n=m/f.speed,o=(1-f.opacity)/(n*f.trail/100),p=n/f.lines;!function q(){l++;for(var a=f.lines;a;a--){var b=Math.max(1-(l+a*p)%n*o,f.opacity);e.opacity(g,f.lines-a,b,f)}e.timeout=e.el&&setTimeout(q,~~(1e3/m))}()}return e},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=c),this},lines:function(a,b){function c(a,c){return h(d(),{position:"absolute",width:b.length+b.width+"px",height:b.width+"px",background:a,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/b.lines*i+b.rotate)+"deg) translate("+b.radius+"px,0)",borderRadius:(b.corners*b.width>>1)+"px"})}for(var g,i=0;i',b)}var b=h(d("group"),{behavior:"url(#default#VML)"});!g(b,"transform")&&b.adj?(n.addRule(".spin-vml","behavior:url(#default#VML)"),p.prototype.lines=function(b,c){function d(){return h(a("group",{coordsize:j+" "+j,coordorigin:-i+" "+-i}),{width:j,height:j})}function f(b,f,g){e(l,e(h(d(),{rotation:360/c.lines*b+"deg",left:~~f}),e(h(a("roundrect",{arcsize:c.corners}),{width:i,height:c.width,left:c.radius,top:-c.width>>1,filter:g}),a("fill",{color:c.color,opacity:c.opacity}),a("stroke",{opacity:0}))))}var g,i=c.length+c.width,j=2*i,k=2*-(c.width+c.length)+"px",l=h(d(),{position:"absolute",top:k,left:k});if(c.shadow)for(g=1;g<=c.lines;g++)f(g,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(g=1;g<=c.lines;g++)f(g);return e(b,l)},p.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d\n\nChat Rooms\n\n\n\n
                                                              \n\n\nVisitors\n\n\n\n
                                                              \n\n\n
                                                              \n\n
                                                              \n
                                                              \n";return __p},this.FirechatDefaultTemplates["templates/layout-popout.html"]=function(obj){obj||(obj={});var __p="";_.escape;with(obj)__p+="
                                                              \n
                                                              \n\n
                                                              \n
                                                              \n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/message-context-menu.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                              \n\n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/message.html"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                              \n
                                                              \n",disableActions||(__p+="\n\n"),__p+="
                                                              \n
                                                              \n"+(null==(__t=message)?"":__t)+"\n
                                                              \n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/prompt-alert.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                              \n
                                                              "+__e(message)+"
                                                              \n

                                                              \n\n

                                                              \n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/prompt-create-room.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                              \n
                                                              Give your chat room a name:
                                                              \n\n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/prompt-invitation.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                              \n
                                                              "+__e(fromUserName)+"
                                                              \n

                                                              invited you to join

                                                              \n
                                                              "+__e(toRoomName)+"
                                                              \n

                                                              \n\n\n

                                                              \n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/prompt-invite-private.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                              \n
                                                              Invite "+__e(userName)+" to "+__e(roomName)+"?
                                                              \n

                                                              \n\n\n

                                                              \n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/prompt-invite-reply.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                              \n
                                                              "+__e(toUserName)+"
                                                              \n

                                                              \n",__p+="accepted"===status?" accepted your invite. ":" declined your invite. ",__p+="\n

                                                              \n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/prompt-user-mute.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                              \n
                                                              "+__e(userName)+"
                                                              \n

                                                              \n\n\n

                                                              \n
                                                              ";return __p},this.FirechatDefaultTemplates["templates/prompt.html"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;with(obj)__p+="";return __p},this.FirechatDefaultTemplates["templates/room-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                            • \n\n"+__e(name)+"\n\n
                                                            • ";return __p},this.FirechatDefaultTemplates["templates/room-user-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                            • \n\n"+__e(name)+"",disableActions||(__p+="\n \n \n"),__p+="\n\n
                                                            • ";return __p},this.FirechatDefaultTemplates["templates/room-user-search-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                            • \n\n",__p+=disableActions?"\n"+__e(name)+"\n":"\n"+__e(name)+"\n+\n",__p+="\n\n
                                                            • ";return __p},this.FirechatDefaultTemplates["templates/tab-content.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                              \n
                                                              \n\n\nIn Room\n\n\n\n
                                                              \n\n+\nInvite\n\n\n
                                                              \n
                                                              \n
                                                              \n\n
                                                              \n\n\n
                                                              \n
                                                              ';return __p},this.FirechatDefaultTemplates["templates/tab-menu-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                            • \n"+__e(name)+"\n
                                                            • ";return __p},this.FirechatDefaultTemplates["templates/user-search-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape; +Array.prototype.join;with(obj)__p+="
                                                            • \n\n",__p+=disableActions?"\n"+__e(name)+"\n":"\n"+__e(name)+"\n \n",__p+="\n\n
                                                            • ";return __p},function(a){Function.prototype.bind||(Function.prototype.bind=function(a){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var b=Array.prototype.slice.call(arguments,1),c=this,d=function(){},e=function(){return c.apply(this instanceof d&&a?this:a,b.concat(Array.prototype.slice.call(arguments)))};return d.prototype=this.prototype,e.prototype=new d,e}),Object.keys=Object.keys||function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b}}(),function(a){function b(a,b){this._firebase=a,this._user=null,this._userId=null,this._userName=null,this._isModerator=!1,this._sessionId=null,this._events={},this._rooms={},this._presenceBits={},this._userRef=null,this._messageRef=this._firebase.child("room-messages"),this._roomRef=this._firebase.child("room-metadata"),this._privateRoomRef=this._firebase.child("room-private-metadata"),this._moderatorsRef=this._firebase.child("moderators"),this._suspensionsRef=this._firebase.child("suspensions"),this._usersOnlineRef=this._firebase.child("user-names-online"),this._options=b||{},this._options.numMaxMessages=this._options.numMaxMessages||50}var c=this,d=c.Firechat;b.noConflict=function(){return c.Firechat=d,b},c.Firechat=b,b.prototype={_loadUserMetadata:function(a){var b=this;this._userRef.transaction(function(a){return a&&a.id&&a.name?void 0:{id:b._userId,name:b._userName}},function(d,e,f){b._user=f.val(),b._moderatorsRef.child(b._userId).once("value",function(d){b._isModerator=!!d.val(),c.setTimeout(a,0)})})},_setupDataEvents:function(){this._firebase.root().child(".info/connected").on("value",function(a){if(a.val()===!0)for(var b=0;b2&&(f=arguments[1]),d=f?d.limitToLast(f):d,d.once("value",function(a){var b=a.val()||{},d={};for(var f in b)for(var g in b[f]){d[f]=b[f][g];break}c.setTimeout(function(){e(d)},0)})},b.prototype.getUsersByPrefix=function(a,b,d,e,f){var g=this._usersOnlineRef,h=a.toLowerCase();g=b?g.startAt(null,b):d?g.endAt(null,d):h?g.startAt(null,h):g.startAt(),g=e?g.limitToLast(e):g,g.once("value",function(b){var d=b.val()||{},e={};for(var g in d){var i,j,k=d[g];for(var l in k){i=k[l].name,j=k[l].id;break}a.length>0&&0!==i.toLowerCase().indexOf(h)||(e[i]={name:i,id:j})}c.setTimeout(function(){f(e)},0)})},b.prototype.getRoom=function(a,b){this._roomRef.child(a).once("value",function(a){b(a.val())})},b.prototype.userIsModerator=function(){return this._isModerator},b.prototype.warn=function(a){console&&(a="Firechat Warning: "+a,"function"==typeof console.warn?console.warn(a):"function"==typeof console.log&&console.log(a))}}(Firebase),function(a){function b(b,c,d){if(!b)throw new Error("FirechatUI: Missing required argument `firebaseRef`");if(!c)throw new Error("FirechatUI: Missing required argument `el`");d=d||{},this._options=d,this._el=c,this._user=null,this._chat=new Firechat(b,d),this._roomQueue=[],this.maxLengthUsername=15,this.maxLengthUsernameDisplay=15,this.maxLengthRoomName=24,this.maxLengthMessage=120,this.maxUserSearchResults=100,this.urlPattern=/\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim,this.pseudoUrlPattern=/(^|[^\/])(www\.[\S]+(\b|$))/gim,this._renderLayout(),this.$wrapper=a("#firechat"),this.$roomList=a("#firechat-room-list"),this.$tabList=a("#firechat-tab-list"),this.$tabContent=a("#firechat-tab-content"),this.$messages={},this.$rateLimit={limitCount:10,limitInterval:1e4,limitWaitTime:3e4,history:{}},this._bindUIEvents(),this._bindDataEvents()}if(!a||parseInt(a().jquery.replace(/\./g,""),10)<170)throw new Error("jQuery 1.7 or later required!");var c=this,d=c.FirechatUI;if(c.FirechatUI=b,!self.FirechatDefaultTemplates)throw new Error("Unable to find chat templates!");b.noConflict=function(){return c.FirechatUI=d,b},b.prototype={_bindUIEvents:function(){this._bindForHeightChange(),this._bindForTabControls(),this._bindForRoomList(),this._bindForUserRoomList(),this._bindForUserSearch(),this._bindForUserMuting(),this._bindForChatInvites(),this._bindForRoomListing(),this._bindForFileUpload(),this._setupTabs(),this._setupDropdowns(),this._bindTextInputFieldLimits()},_bindDataEvents:function(){this._chat.on("user-update",this._onUpdateUser.bind(this)),this._chat.on("room-enter",this._onEnterRoom.bind(this)),this._chat.on("room-exit",this._onLeaveRoom.bind(this)),this._chat.on("message-add",this._onNewMessage.bind(this)),this._chat.on("message-remove",this._onRemoveMessage.bind(this)),this._chat.on("room-invite",this._onChatInvite.bind(this)),this._chat.on("room-invite-response",this._onChatInviteResponse.bind(this)),this._chat.on("notification",this._onNotification.bind(this))},_renderLayout:function(){var b=FirechatDefaultTemplates["templates/layout-full.html"];a(this._el).html(b({maxLengthUsername:this.maxLengthUsername}))},_onUpdateUser:function(b){this._user=b;var c=this._user.muted||{};a('[data-event="firechat-user-mute-toggle"]').each(function(b,d){var e=a(this).closest("[data-user-id]").data("user-id");a(this).toggleClass("red",!!c[e])});for(var d in c)a('.message[data-user-id="'+d+'"]').fadeOut()},_onEnterRoom:function(a){this.attachTab(a.id,a.name)},_onLeaveRoom:function(a){this.removeTab(a),this._roomQueue.length>0&&this._chat.enterRoom(this._roomQueue.shift(a))},_onNewMessage:function(a,b){var c=b.userId;this._user&&this._user.muted&&this._user.muted[c]||this.showMessage(a,b)},_onRemoveMessage:function(a,b){this.removeMessage(a,b)},_onChatInvite:function(a){var b=this,c=FirechatDefaultTemplates["templates/prompt-invitation.html"],d=this.prompt("Invite",c(a));d.find("a.close").click(function(){return d.remove(),b._chat.declineInvite(a.id),!1}),d.find("[data-toggle=accept]").click(function(){return d.remove(),b._chat.acceptInvite(a.id),!1}),d.find("[data-toggle=decline]").click(function(){return d.remove(),b._chat.declineInvite(a.id),!1})},_onChatInviteResponse:function(a){if(a.status){var b,c=this,d=FirechatDefaultTemplates["templates/prompt-invite-reply.html"];a.status&&"accepted"===a.status?(b=this.prompt("Accepted",d(a)),this._chat.getRoom(a.roomId,function(b){c.attachTab(a.roomId,b.name)})):b=this.prompt("Declined",d(a)),b.find("a.close").click(function(){return b.remove(),!1})}},_onNotification:function(a){if("warning"===a.notificationType)this.renderAlertPrompt("Warning","You are being warned for inappropriate messaging. Further violation may result in temporary or permanent ban of service.");else if("suspension"===a.notificationType){var b=a.data.suspendedUntil,c=Math.round((b-(new Date).getTime())/1e3),d="";if(c>0){if(c>7200){var e=Math.floor(c/3600);d=e+" hours, ",c-=3600*e}d+=Math.floor(c/60)+" minutes",this.renderAlertPrompt("Suspended","A moderator has suspended you for violating site rules. You cannot send messages for another "+d+".")}}}},b.prototype.setUser=function(a,b){var c=this;c._chat.setUser(a,b,function(a){c._user=a,c._chat.userIsModerator()&&c._bindSuperuserUIEvents(),c._chat.resumeSession()})},b.prototype.on=function(a,b){this._chat.on(a,b)},b.prototype._bindSuperuserUIEvents=function(){var b=this,c=function(b){var c=a(this),d=c.closest("[data-message-id]").data("message-id"),e=a('[data-message-id="'+d+'"]').closest("[data-user-id]").data("user-id"),f=a('[data-message-id="'+d+'"]').closest("[data-room-id]").data("room-id");return{messageId:d,userId:e,roomId:f}},d=function(){a('[data-toggle="firechat-contextmenu"]').each(function(){a(this).remove()}),a("#firechat .message.highlighted").each(function(){a(this).removeClass("highlighted")})},e=function(e){var f,g=a(this),h=g.closest("[data-message-id]"),i=FirechatDefaultTemplates["templates/message-context-menu.html"],j=c.call(this,e);e.preventDefault(),d(),g.addClass("highlighted"),b._chat.getRoom(j.roomId,function(c){f=a(i({id:h.data("message-id")})),f.css({left:e.clientX,top:e.clientY}).appendTo(b.$wrapper)})};a(document).bind("click",{self:this},function(a){a.button&&2==a.button||d()}),a(document).delegate('[data-class="firechat-message"]',"contextmenu",e),a(document).delegate('[data-event="firechat-user-warn"]',"click",function(a){var d=c.call(this,a);b._chat.warnUser(d.userId)}),a(document).delegate('[data-event="firechat-user-suspend-hour"]',"click",function(a){var d=c.call(this,a);b._chat.suspendUser(d.userId,3600)}),a(document).delegate('[data-event="firechat-user-suspend-day"]',"click",function(a){var d=c.call(this,a);b._chat.suspendUser(d.userId,86400)}),a(document).delegate('[data-event="firechat-message-delete"]',"click",function(a){var d=c.call(this,a);b._chat.deleteMessage(d.roomId,d.messageId)})},b.prototype._bindForHeightChange=function(){var b=a(this._el),c=null;setInterval(function(){var d=b.height();d!=c&&(c=d,a(".chat").each(function(a,b){}))},500)},b.prototype._bindForTabControls=function(){var b=this;a(document).delegate('[data-event="firechat-close-tab"]',"click",function(c){var d=a(this).closest("[data-room-id]").data("room-id");return b._chat.leaveRoom(d),!1})},b.prototype._bindForRoomList=function(){var b=this;a("#firechat-btn-rooms").bind("click",function(){if(!a(this).parent().hasClass("open")){var c=(a(this),FirechatDefaultTemplates["templates/room-list-item.html"]),d=function(){var c=a(this).parent(),d=c.data("room-id"),e=c.data("room-name");return b.$messages[d]?b.focusTab(d):b._chat.enterRoom(d,e),!1};b._chat.getRoomList(function(e){b.$roomList.empty();for(var f in e){var g=e[f];if("public"==g.type){g.isRoomOpen=!!b.$messages[g.id];var h=a(c(g));h.children("a").bind("click",d),b.$roomList.append(h.toggle(!0))}}})}})},b.prototype._bindForUserRoomList=function(){var b=this;a(document).delegate('[data-event="firechat-user-room-list-btn"]',"click",function(c){c.stopPropagation();var d=a(this),e=d.closest("[data-room-id]").data("room-id"),f=FirechatDefaultTemplates["templates/room-user-list-item.html"],g=d.data("target"),h=a("#"+g);h.empty(),b._chat.getUsersByRoom(e,function(c){for(var d in c)user=c[d],user.disableActions=!b._user||user.id===b._user.id,user.nameTrimmed=b.trimWithEllipsis(user.name,b.maxLengthUsernameDisplay),user.isMuted=b._user&&b._user.muted&&b._user.muted[user.id],h.append(a(f(user)));b.sortListLexicographically("#"+g)})})},b.prototype._bindForFileUpload=function(){var b=this,c=function(c){var d=c.target.files[0],e=new FileReader;e.onload=function(c){return function(c){var d=c.target.result,e=CryptoJS.SHA256(Math.random()+CryptoJS.SHA256(d)),f=new Firebase(firebaseRef+"/pano/"+e+"/filePayload");spinner.spin(document.getElementById("spin")),f.set(d,function(){spinner.stop();var c=firebaseRef+"/pano/"+e+"/filePayload";console.log("File with hash: "+c+" created"),a("#file-upload").hide();var d=a("textarea").attr("id").replace(/textarea/,""),g=b.trimWithEllipsis("File Uploaded from "+b._chat._userName,b.maxLengthMessage);b._chat.sendMessage(d,g),f.once("value",function(b){var c=b.val();if(null!==c){var e=a('');e.attr("src",c),e.appendTo(a(".message").last()),e.width(313),e.show()}else a("#body").append("Not found");spinner.stop()})})}}(d),e.readAsDataURL(d)};a(document).delegate('[data-event="firechat-upload-file"]',"click",function(b){b.stopPropagation(),console.log("Clicked on the button!"),a("#file-upload").show(),a("#file-upload").get(0).addEventListener("change",c,!1)}),a(document).delegate('[data-event="firechat-file-uploaded"]',"change",function(a){a.stopPropagation(),console.log("Upload Complete")})},b.prototype._bindForUserSearch=function(){var b=this,c=function(b){var c=a(this),e=c.data("target"),f=c.data("controls"),g=c.data("template"),h=c.val()||c.data("prefix")||"",i=c.data("startAt")||null,j=c.data("endAt")||null;b.preventDefault(),d(e,g,f,h,i,j)},d=function(c,d,e,f,g,h){var i=a("#"+c),j=a("#"+e),k=FirechatDefaultTemplates[d];b._chat.getUsersByPrefix(f,g,h,b.maxUserSearchResults,function(a){var c,d,e,g,h,l=0;i.empty();for(e in a){var m=a[e];if(m.disableActions=!b._user||m.id===b._user.id,l+=1,i.append(k(m)),1===l)g=m.name.toLowerCase();else if(l>=b.maxUserSearchResults){h=m.name.toLowerCase();break}}j&&(c=j.find('[data-toggle="firechat-pagination-prev"]'),d=j.find('[data-toggle="firechat-pagination-next"]'),h?d.data("event","firechat-user-search").data("startAt",h).data("prefix",f).removeClass("disabled").removeAttr("disabled"):d.data("event",null).data("startAt",null).data("prefix",null).addClass("disabled").attr("disabled","disabled"))})};a(document).delegate('[data-event="firechat-user-search"]',"keyup",c),a(document).delegate('[data-event="firechat-user-search"]',"click",c),a(document).delegate('[data-event="firechat-user-search-btn"]',"click",function(b){b.stopPropagation();var c=a(this).next("div.firechat-dropdown-menu").find("input");c.focus(),c.trigger(jQuery.Event("keyup"))}),a(document).delegate('[data-event="firechat-user-search"]',"click",function(a){a.stopPropagation()})},b.prototype._bindForUserMuting=function(){var b=this;a(document).delegate('[data-event="firechat-user-mute-toggle"]',"click",function(c){var d=a(this),e=d.closest("[data-user-id]").data("user-id"),f=d.closest("[data-user-name]").data("user-name"),g=d.hasClass("red"),h=FirechatDefaultTemplates["templates/prompt-user-mute.html"];if(c.preventDefault(),g)b._chat.toggleUserMute(e);else{var i=b.prompt("Mute User?",h({userName:f}));i.find("a.close").first().click(function(){return i.remove(),!1}),i.find("[data-toggle=decline]").first().click(function(){return i.remove(),!1}),i.find("[data-toggle=accept]").first().click(function(){return b._chat.toggleUserMute(e),i.remove(),!1})}})},b.prototype._bindForChatInvites=function(){var b=this,c=function(c){var d,e=a(this),f=e.closest("[data-user-id]").data("user-id"),g=e.closest("[data-room-id]").data("room-id"),h=e.closest("[data-user-name]").data("user-name"),i=FirechatDefaultTemplates["templates/prompt-invite-private.html"];return b._chat.getRoom(g,function(a){return d=b.prompt("Invite",i({userName:h,roomName:a.name})),d.find("a.close").click(function(){return d.remove(),!1}),d.find("[data-toggle=decline]").click(function(){return d.remove(),!1}),d.find("[data-toggle=accept]").first().click(function(){return d.remove(),b._chat.inviteUser(f,g,a.name),!1}),!1}),!1},d=function(c){var d,e=a(this),f=e.closest("[data-user-id]").data("user-id"),g=e.closest("[data-user-name]").data("user-name"),h=FirechatDefaultTemplates["templates/prompt-invite-private.html"];return f&&g&&(d=b.prompt("Private Invite",h({userName:g,roomName:"Private Chat"})),d.find("a.close").click(function(){return d.remove(),!1}),d.find("[data-toggle=decline]").click(function(){return d.remove(),!1}),d.find("[data-toggle=accept]").first().click(function(){d.remove();var a="Private Chat";return b._chat.createRoom(a,"private",function(c){b._chat.inviteUser(f,c,a)}),!1})),!1};a(document).delegate('[data-event="firechat-user-chat"]',"click",d),a(document).delegate('[data-event="firechat-user-invite"]',"click",c)},b.prototype._bindForRoomListing=function(){var b=this,c=a("#firechat-btn-create-room-prompt"),d=a("#firechat-btn-create-room");c.bind("click",function(a){return b.promptCreateRoom(),!1}),d.bind("click",function(c){var d=a("#firechat-input-room-name").val();return a("#firechat-prompt-create-room").remove(),b._chat.createRoom(d),!1})},b.prototype._setupTabs=function(){var b=function(b){var d,e,f=b,g=f.closest("ul:not(.firechat-dropdown-menu)"),h=f.attr("data-target"),i=g.find(".active:last a")[0];h||(h=f.attr("href"),h=h&&h.replace(/.*(?=#[^\s]*$)/,"")),f.parent("li").hasClass("active")||(e=a.Event("show",{relatedTarget:i}),f.trigger(e),e.isDefaultPrevented()||(d=a(h),c(f.parent("li"),g),c(d,d.parent(),function(){f.trigger({type:"shown",relatedTarget:i})})))},c=function(b,c,d){function e(){f.removeClass("active").find("> .firechat-dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?b.addClass("in"):b.removeClass("fade"),b.parent(".firechat-dropdown-menu")&&b.closest("li.firechat-dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e):e(),f.removeClass("in")};a(document).delegate('[data-toggle="firechat-tab"]',"click",function(c){c.preventDefault(),b(a(this))})},b.prototype._setupDropdowns=function(){var b=function(b){var e=a(this),f=d(e),g=f.hasClass("open");if(!e.is(".disabled, :disabled"))return c(),g||f.toggleClass("open"),e.focus(),!1},c=function(){a("[data-toggle=firechat-dropdown]").each(function(){d(a(this)).removeClass("open")})},d=function(b){var c,d=b.attr("data-target");return d||(d=b.attr("href"),d=d&&/#/.test(d)&&d.replace(/.*(?=#[^\s]*$)/,"")),c=d&&a(d),c&&c.length||(c=b.parent()),c};a(document).bind("click",c).delegate(".firechat-dropdown-menu","click",function(a){a.stopPropagation()}).delegate("[data-toggle=firechat-dropdown]","click",b)},b.prototype._bindTextInputFieldLimits=function(){a("body").delegate('input[data-provide="limit"], textarea[data-provide="limit"]',"keyup",function(b){var c=a(this),d=a(c.data("counter")),e=c.attr("maxlength"),f=c.val().length;d.html(Math.max(0,e-f))})},b.prototype.renderAlertPrompt=function(a,b){var c=FirechatDefaultTemplates["templates/prompt-alert.html"],d=this.prompt(a,c({message:b}));d.find(".close").click(function(){return d.remove(),!1})},b.prototype.toggleInputs=function(b){a("#firechat-tab-content textarea").each(function(){var c=a(this);b?a(this).val(""):a(this).val("You have exceeded the message limit, please wait before sending."),c.prop("disabled",!b)}),a("#firechat-input-name").prop("disabled",!b)},b.prototype.attachTab=function(b,c){var d=this;if(this.$messages[b])return void this.focusTab(b);var e={id:b,name:c},f=FirechatDefaultTemplates["templates/tab-content.html"],g=a(f(e));this.$tabContent.prepend(g);var h=a("#firechat-messages"+b);this.$messages[b]=h;var i=g.find("textarea").first();i.bind("keydown",function(a){var c=d.trimWithEllipsis(i.val(),d.maxLengthMessage);return 13===a.which&&""!==c?(i.val(""),d._chat.sendMessage(b,c),!1):void 0});var j=FirechatDefaultTemplates["templates/tab-menu-item.html"],k=a(j(e));this.$tabList.prepend(k),k.bind("shown",function(a){h.scrollTop(h[0].scrollHeight)});var l=this.$tabList.children("li"),m=Math.floor(a("#firechat-tab-list").width()/l.length);this.$tabList.children("li").css("width",m),this.$roomList.children("[data-room-id="+b+"]").children("a").addClass("highlight"),a("#firechat-btn-room-user-list-"+b).bind("click",function(){return d.sortListLexicographically("#firechat-room-user-list-"+b),!1}),this.focusTab(b)},b.prototype.focusTab=function(a){if(this.$messages[a]){var b=this.$tabList.find("[data-room-id="+a+"]").find("a");b.length&&b.first().trigger("click")}},b.prototype.removeTab=function(b){delete this.$messages[b],this.$tabContent.find("[data-room-id="+b+"]").remove(),this.$tabList.find("[data-room-id="+b+"]").remove();var c=this.$tabList.children("li"),d=Math.floor(a("#firechat-tab-list").width()/c.length);this.$tabList.children("li").css("width",d),this.$tabList.find('[data-toggle="firechat-tab"]').first().trigger("click"),this.$roomList.children("[data-room-id="+b+"]").children("a").removeClass("highlight")},b.prototype.showMessage=function(b,c){var d=this,e={id:c.id,localtime:d.formatTime(c.timestamp),message:c.message||"",userId:c.userId,name:c.name,type:c.type||"default",isSelfMessage:d._user&&c.userId==d._user.id,disableActions:!d._user||c.userId==d._user.id};e.message=_.map(e.message.split(" "),function(a){return d.urlPattern.test(a)||d.pseudoUrlPattern.test(a)?d.linkify(encodeURI(a)):_.escape(a)}).join(" "),e.message=d.trimWithEllipsis(e.message,d.maxLengthMessage);var f=FirechatDefaultTemplates["templates/message.html"],g=a(f(e)),h=d.$messages[b];if(h){var i=!1;h.scrollTop()/(h[0].scrollHeight-h[0].offsetHeight)>=.95?i=!0:h[0].scrollHeight<=h.height()&&(i=!0),h.append(g),i&&h.scrollTop(h[0].scrollHeight)}},b.prototype.removeMessage=function(b,c){a('.message[data-message-id="'+c+'"]').remove()},b.prototype.sortListLexicographically=function(b){a(b).children("li").sort(function(b,c){var d=a(b).text().toUpperCase(),e=a(c).text().toUpperCase();return e>d?-1:d>e?1:0}).appendTo(b)},b.prototype.trimWithEllipsis=function(a,b){return a=a.replace(/^\s\s*/,"").replace(/\s\s*$/,""),b&&a.length<=b?a:a.substring(0,b)+"..."},b.prototype.formatTime=function(a){var b=a?new Date(a):new Date,c=b.getHours()||12,d=""+b.getMinutes(),e=b.getHours()>=12?"pm":"am";return c=c>12?c-12:c,d=d.length<2?"0"+d:d,""+c+":"+d+e},b.prototype.promptCreateRoom=function(){var a=this,b=FirechatDefaultTemplates["templates/prompt-create-room.html"],c=this.prompt("Create Public Room",b({maxLengthRoomName:this.maxLengthRoomName,isModerator:a._chat.userIsModerator()}));c.find("a.close").first().click(function(){return c.remove(),!1}),c.find("[data-toggle=submit]").first().click(function(){var b=c.find("[data-input=firechat-room-name]").first().val();return""!==b&&(a._chat.createRoom(b,"public"),c.remove()),!1}),c.find("[data-input=firechat-room-name]").first().focus(),c.find("[data-input=firechat-room-name]").first().bind("keydown",function(b){if(13===b.which){var d=c.find("[data-input=firechat-room-name]").first().val();if(""!==d)return a._chat.createRoom(d,"public"),c.remove(),!1}})},b.prototype.prompt=function(b,c){var d,e=FirechatDefaultTemplates["templates/prompt.html"];return d=a(e({title:b,content:c})).css({top:this.$wrapper.position().top+.333*this.$wrapper.height(),left:this.$wrapper.position().left+.125*this.$wrapper.width(),width:.75*this.$wrapper.width()}),this.$wrapper.append(d.removeClass("hidden")),d},b.prototype.linkify=function(a){var b=this;return a.replace(b.urlPattern,'$&').replace(b.pseudoUrlPattern,'$1$2')}}(jQuery);var spinner=new Spinner({color:"#ddd"}),firebaseRef="https://brilliant-fire-2797.firebaseio.com",CryptoJS=CryptoJS||function(a,b){var c={},d=c.lib={},e=d.Base=function(){function a(){}return{extend:function(b){a.prototype=this;var c=new a;return b&&c.mixIn(b),c.$super=this,c},create:function(){var a=this.extend();return a.init.apply(a,arguments),a},init:function(){},mixIn:function(a){for(var b in a)a.hasOwnProperty(b)&&(this[b]=a[b]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.$super.extend(this)}}}(),f=d.WordArray=e.extend({init:function(a,c){a=this.words=a||[],this.sigBytes=c!=b?c:4*a.length},toString:function(a){return(a||h).stringify(this)},concat:function(a){var b=this.words,c=a.words,d=this.sigBytes,a=a.sigBytes;if(this.clamp(),d%4)for(var e=0;a>e;e++)b[d+e>>>2]|=(c[e>>>2]>>>24-8*(e%4)&255)<<24-8*((d+e)%4);else if(65535e;e+=4)b[d+e>>>2]=c[e>>>2];else b.push.apply(b,c);return this.sigBytes+=a,this},clamp:function(){var b=this.words,c=this.sigBytes;b[c>>>2]&=4294967295<<32-8*(c%4),b.length=a.ceil(c/4)},clone:function(){var a=e.clone.call(this);return a.words=this.words.slice(0),a},random:function(b){for(var c=[],d=0;b>d;d+=4)c.push(4294967296*a.random()|0);return f.create(c,b)}}),g=c.enc={},h=g.Hex={stringify:function(a){for(var b=a.words,a=a.sigBytes,c=[],d=0;a>d;d++){var e=b[d>>>2]>>>24-8*(d%4)&255;c.push((e>>>4).toString(16)),c.push((15&e).toString(16))}return c.join("")},parse:function(a){for(var b=a.length,c=[],d=0;b>d;d+=2)c[d>>>3]|=parseInt(a.substr(d,2),16)<<24-4*(d%8);return f.create(c,b/2)}},i=g.Latin1={stringify:function(a){for(var b=a.words,a=a.sigBytes,c=[],d=0;a>d;d++)c.push(String.fromCharCode(b[d>>>2]>>>24-8*(d%4)&255));return c.join("")},parse:function(a){for(var b=a.length,c=[],d=0;b>d;d++)c[d>>>2]|=(255&a.charCodeAt(d))<<24-8*(d%4);return f.create(c,b)}},j=g.Utf8={stringify:function(a){try{return decodeURIComponent(escape(i.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data")}},parse:function(a){return i.parse(unescape(encodeURIComponent(a)))}},k=d.BufferedBlockAlgorithm=e.extend({reset:function(){this._data=f.create(),this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a)),this._data.concat(a),this._nDataBytes+=a.sigBytes},_process:function(b){var c=this._data,d=c.words,e=c.sigBytes,g=this.blockSize,h=e/(4*g),h=b?a.ceil(h):a.max((0|h)-this._minBufferSize,0),b=h*g,e=a.min(4*b,e);if(b){for(var i=0;b>i;i+=g)this._doProcessBlock(d,i);i=d.splice(0,b),c.sigBytes-=e}return f.create(i,e)},clone:function(){var a=e.clone.call(this);return a._data=this._data.clone(),a},_minBufferSize:0});d.Hasher=k.extend({init:function(){this.reset()},reset:function(){k.reset.call(this),this._doReset()},update:function(a){return this._append(a),this._process(),this},finalize:function(a){return a&&this._append(a),this._doFinalize(),this._hash},clone:function(){var a=k.clone.call(this);return a._hash=this._hash.clone(),a},blockSize:16,_createHelper:function(a){return function(b,c){return a.create(c).finalize(b)}},_createHmacHelper:function(a){return function(b,c){return l.HMAC.create(a,c).finalize(b)}}});var l=c.algo={};return c}(Math);!function(a){var b=CryptoJS,c=b.lib,d=c.WordArray,c=c.Hasher,e=b.algo,f=[],g=[];!function(){ +function b(b){for(var c=a.sqrt(b),d=2;c>=d;d++)if(!(b%d))return!1;return!0}function c(a){return 4294967296*(a-(0|a))|0}for(var d=2,e=0;64>e;)b(d)&&(8>e&&(f[e]=c(a.pow(d,.5))),g[e]=c(a.pow(d,1/3)),e++),d++}();var h=[],e=e.SHA256=c.extend({_doReset:function(){this._hash=d.create(f.slice(0))},_doProcessBlock:function(a,b){for(var c=this._hash.words,d=c[0],e=c[1],f=c[2],i=c[3],j=c[4],k=c[5],l=c[6],m=c[7],n=0;64>n;n++){if(16>n)h[n]=0|a[b+n];else{var o=h[n-15],p=h[n-2];h[n]=((o<<25|o>>>7)^(o<<14|o>>>18)^o>>>3)+h[n-7]+((p<<15|p>>>17)^(p<<13|p>>>19)^p>>>10)+h[n-16]}o=m+((j<<26|j>>>6)^(j<<21|j>>>11)^(j<<7|j>>>25))+(j&k^~j&l)+g[n]+h[n],p=((d<<30|d>>>2)^(d<<19|d>>>13)^(d<<10|d>>>22))+(d&e^d&f^e&f),m=l,l=k,k=j,j=i+o|0,i=f,f=e,e=d,d=o+p|0}c[0]=c[0]+d|0,c[1]=c[1]+e|0,c[2]=c[2]+f|0,c[3]=c[3]+i|0,c[4]=c[4]+j|0,c[5]=c[5]+k|0,c[6]=c[6]+l|0,c[7]=c[7]+m|0},_doFinalize:function(){var a=this._data,b=a.words,c=8*this._nDataBytes,d=8*a.sigBytes;b[d>>>5]|=128<<24-d%32,b[(d+64>>>9<<4)+15]=c,a.sigBytes=4*b.length,this._process()}});b.SHA256=c._createHelper(e),b.HmacSHA256=c._createHmacHelper(e)}(Math); \ No newline at end of file diff --git a/package.json b/package.json index ffcc413..8af7179 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "homepage": "https://firechat.firebaseapp.com/", "repository": { "type": "git", - "url": "https://github.com/firebase/firechat.git" + "url": "https://github.com/trystant/firechat.git" }, "bugs": { "url": "https://github.com/firebase/firechat/issues" From 0a680753dd96f87601a5189dd03b77f2cbedc833 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 15 Jun 2015 09:08:27 -0400 Subject: [PATCH 23/29] Removed distro for better solution --- .gitignore | 3 + dist/firechat.css | 968 -------------------- dist/firechat.js | 1976 ----------------------------------------- dist/firechat.min.css | 1 - dist/firechat.min.js | 3 - 5 files changed, 3 insertions(+), 2948 deletions(-) delete mode 100644 dist/firechat.css delete mode 100644 dist/firechat.js delete mode 100644 dist/firechat.min.css delete mode 100644 dist/firechat.min.js diff --git a/.gitignore b/.gitignore index 00c0488..6792931 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,8 @@ node_modules/ # Bower bower_components/ +# Distribution files +dist/ + # Jekyll _site/ diff --git a/dist/firechat.css b/dist/firechat.css deleted file mode 100644 index 3a0ead6..0000000 --- a/dist/firechat.css +++ /dev/null @@ -1,968 +0,0 @@ -@charset "UTF-8"; -/* Boilerplate: Reset -============================================================ */ -#firechat div, -#firechat span, -#firechat applet, -#firechat object, -#firechat iframe, -#firechat h1, -#firechat h2, -#firechat h3, -#firechat h4, -#firechat h5, -#firechat h6, -#firechat p, -#firechat blockquote, -#firechat pre, -#firechat a, -#firechat abbr, -#firechat acronym, -#firechat address, -#firechat big, -#firechat cite, -#firechat code, -#firechat del, -#firechat dfn, -#firechat em, -#firechat img, -#firechat ins, -#firechat kbd, -#firechat q, -#firechat s, -#firechat samp, -#firechat small, -#firechat strike, -#firechat strong, -#firechat sub, -#firechat sup, -#firechat tt, -#firechat var, -#firechat b, -#firechat u, -#firechat i, -#firechat center, -#firechat dl, -#firechat dt, -#firechat dd, -#firechat ol, -#firechat ul, -#firechat li, -#firechat fieldset, -#firechat form, -#firechat label, -#firechat legend, -#firechat table, -#firechat caption, -#firechat tbody, -#firechat tfoot, -#firechat thead, -#firechat tr, -#firechat th, -#firechat td, -#firechat article, -#firechat aside, -#firechat canvas, -#firechat details, -#firechat embed, -#firechat figure, -#firechat figcaption, -#firechat footer, -#firechat header, -#firechat hgroup, -#firechat menu, -#firechat nav, -#firechat output, -#firechat ruby, -#firechat section, -#firechat summary, -#firechat time, -#firechat mark, -#firechat audio, -#firechat video { - border: 0; - font-size: 12px; - font-family: arial, helvetica, sans-serif; - vertical-align: baseline; - margin: 0; - padding: 0; -} -#firechat article, -#firechat aside, -#firechat details, -#firechat figcaption, -#firechat figure, -#firechat footer, -#firechat header, -#firechat hgroup, -#firechat menu, -#firechat nav, -#firechat section { - display: block; -} -#firechat body { - line-height: 1; -} -#firechat ol, -#firechat ul { - list-style: none; -} -#firechat blockquote, -#firechat q { - quotes: none; -} -#firechat blockquote:before, -#firechat blockquote:after, -#firechat q:before, -#firechat q:after { - content: none; -} -#firechat table { - border-collapse: collapse; - border-spacing: 0; -} -/* Boilerplate: Mixins -============================================================ */ -.clearfix { - *zoom: 1; -} -.clearfix:before, -.clearfix:after { - display: table; - content: ""; - line-height: 0; -} -.clearfix:after { - clear: both; -} -/* Boilerplate: Responsive Layout -============================================================ */ -#firechat { - color: #333; - text-align: left; -} -#firechat .center { - float: none !important; - margin-left: auto !important; - margin-right: auto !important; -} -#firechat .left { - float: left !important; -} -#firechat .right { - float: right !important; -} -#firechat .alignleft { - text-align: left !important; -} -#firechat .alignright { - text-align: right !important; -} -#firechat .aligncenter { - text-align: center !important; -} -#firechat .hidden { - display: none !important; -} -#firechat .row { - clear: both; -} -#firechat .fifth, -#firechat .fivesixth, -#firechat .fourfifth, -#firechat .half, -#firechat .ninetenth, -#firechat .quarter, -#firechat .sevententh, -#firechat .sixth, -#firechat .tenth, -#firechat .third, -#firechat .threefifth, -#firechat .threequarter, -#firechat .threetenth, -#firechat .twofifth, -#firechat .twothird, -#firechat .full { - margin-left: 2.127659574468085%; - float: left; - min-height: 1px; -} -#firechat .fifth:first-child, -#firechat .fivesixth:first-child, -#firechat .fourfifth:first-child, -#firechat .half:first-child, -#firechat .ninetenth:first-child, -#firechat .quarter:first-child, -#firechat .sevententh:first-child, -#firechat .sixth:first-child, -#firechat .tenth:first-child, -#firechat .third:first-child, -#firechat .threefifth:first-child, -#firechat .threequarter:first-child, -#firechat .threetenth:first-child, -#firechat .twofifth:first-child, -#firechat .twothird:first-child, -#firechat .full:first-child { - margin-left: 0; -} -#firechat .tenth { - width: 8.08510638297872%; -} -#firechat .sixth { - width: 14.893617021276595%; -} -#firechat .fifth { - width: 18.297872340425535%; -} -#firechat .quarter { - width: 23.404255319148938%; -} -#firechat .threetenth { - width: 26.3829787235%; -} -#firechat .third { - width: 31.914893617021278%; -} -#firechat .twofifth { - width: 38.72340425531915%; -} -#firechat .half { - width: 48.93617021276596%; -} -#firechat .sevententh { - width: 58.7234042555%; -} -#firechat .threefifth { - width: 59.14893617021278%; -} -#firechat .twothird { - width: 65.95744680851064%; -} -#firechat .threequarter { - width: 74.46808510638297%; -} -#firechat .ninetenth { - width: 74.8936170215%; -} -#firechat .fourfifth { - width: 79.57446808510639%; -} -#firechat .fivesixth { - width: 82.9787234042553%; -} -#firechat .full { - width: 100%; -} -#firechat .clipped { - overflow: hidden; -} -#firechat strong { - font-weight: bold; -} -#firechat em { - font-style: italic; -} -#firechat label { - display: block; -} -#firechat a { - color: #005580; -} -#firechat a:visited, -#firechat a:hover, -#firechat a:active { - color: #005580; -} -#firechat p { - margin: 10px 0; -} -#firechat h1, -#firechat h2, -#firechat h3, -#firechat h4, -#firechat h5, -#firechat h6 { - margin: 10px 0; - font-family: inherit; - font-weight: bold; - line-height: 20px; - color: inherit; -} -#firechat h1, -#firechat h2, -#firechat h3 { - line-height: 40px; -} -#firechat h1 { - font-size: 38.5px; -} -#firechat h2 { - font-size: 31.5px; -} -#firechat h3 { - font-size: 24.5px; -} -#firechat h4 { - font-size: 17.5px; -} -#firechat h5 { - font-size: 14px; -} -#firechat h6 { - font-size: 11.9px; -} -#firechat small { - font-size: 90%; -} -/* Component: Tabs -============================================================ */ -#firechat .nav { - list-style: none; -} -#firechat .nav > li > a { - display: block; - background-color: #eeeeee; - text-decoration: none; - overflow: hidden; - white-space: nowrap; -} -#firechat .nav > li > a:hover, -#firechat .nav > li > a:focus { - background-color: #ffffff; -} -#firechat .nav-tabs { - border-bottom: 1px solid #ddd; - clear: both; -} -#firechat .nav-tabs > li { - float: left; - margin-bottom: -1px; - max-width: 45%; -} -#firechat .nav-tabs > li > a { - -webkit-border-top-right-radius: 4px; - -webkit-border-bottom-right-radius: 0; - -webkit-border-bottom-left-radius: 0; - -webkit-border-top-left-radius: 4px; - -moz-border-radius-topright: 4px; - -moz-border-radius-bottomright: 0; - -moz-border-radius-bottomleft: 0; - -moz-border-radius-topleft: 4px; - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - border-top-left-radius: 4px; - padding: 4px 8px; - margin-right: 2px; - line-height: 20px; - border: 1px solid transparent; - border-color: #cccccc; -} -#firechat .nav-tabs > .active > a, -#firechat .nav-tabs > .active > a:hover, -#firechat .nav-tabs > .active > a:focus { - border-bottom-color: transparent; - background-color: #ffffff; - cursor: default; -} -#firechat .tab-content { - overflow: auto; -} -#firechat .tab-content > .tab-pane { - display: none; -} -#firechat .tab-content > .active { - display: block; - background-color: #ffffff; -} -/* Component: dropdowns -============================================================ */ -#firechat .caret { - display: inline-block; - width: 0; - height: 0; - vertical-align: top; - border-top: 4px solid #000000; - border-right: 4px solid transparent; - border-left: 4px solid transparent; - content: ""; - margin-top: 8px; - margin-left: 2px; -} -#firechat .firechat-dropdown { - position: relative; -} -#firechat .firechat-dropdown-toggle { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - text-decoration: none; -} -#firechat .firechat-dropdown-toggle:focus, -#firechat .firechat-dropdown-toggle:active { - outline: none; - text-decoration: none; -} -#firechat .firechat-dropdown-toggle.btn { - padding: 4px 0 0; - height: 22px; -} -#firechat .firechat-dropdown-menu { - *zoom: 1; - -webkit-border-top-right-radius: 0; - -webkit-border-bottom-right-radius: 4px; - -webkit-border-bottom-left-radius: 4px; - -webkit-border-top-left-radius: 0; - -moz-border-radius-topright: 0; - -moz-border-radius-bottomright: 4px; - -moz-border-radius-bottomleft: 4px; - -moz-border-radius-topleft: 0; - border-top-right-radius: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; - border-top-left-radius: 0; - z-index: 1000; - display: none; - float: left; - position: absolute; - top: 100%; - left: 0; - width: 100%; - background-color: #ffffff; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; - border: 1px solid #ccc; - min-width: 98%; - padding: 0; - margin: -1px 0 0; -} -#firechat .firechat-dropdown-menu:before, -#firechat .firechat-dropdown-menu:after { - display: table; - content: ""; - line-height: 0; -} -#firechat .firechat-dropdown-menu:after { - clear: both; -} -#firechat .firechat-dropdown-menu ul { - background-color: #ffffff; - list-style: none; - overflow-y: scroll; - max-height: 300px; -} -#firechat .firechat-dropdown-menu ul > li > a { - display: block; - padding: 1px 1px 1px 3px; - clear: both; - font-weight: normal; - line-height: 20px; - color: #333333; - white-space: nowrap; -} -#firechat .firechat-dropdown-menu ul > li > a.highlight { - background-color: #d9edf7; -} -#firechat .firechat-dropdown-menu ul > li > a:hover, -#firechat .firechat-dropdown-menu ul > li > a:focus, -#firechat .firechat-dropdown-menu ul > .active > a, -#firechat .firechat-dropdown-menu ul > .active > a:hover, -#firechat .firechat-dropdown-menu ul > .active > a:focus { - text-decoration: none; - color: #000000; - background-color: #d9edf7; - outline: 0; -} -#firechat .firechat-dropdown-menu ul > .disabled > a, -#firechat .firechat-dropdown-menu ul > .disabled > a:hover, -#firechat .firechat-dropdown-menu ul > .disabled > a:focus { - color: #999999; - text-decoration: none; - background-color: transparent; - background-image: none; - cursor: default; -} -#firechat .firechat-dropdown-header { - position: relative; - width: 100%; - padding: 10px 0; - background-color: #eeeeee; - border-bottom: 1px solid #cccccc; -} -#firechat .firechat-dropdown-footer { - position: relative; - width: 100%; - padding: 10px 0px; - background-color: #eeeeee; - border-top: 1px solid #cccccc; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -#firechat .open { - *z-index: 1000; -} -#firechat .open > .firechat-dropdown-menu { - display: block; - border: 1px solid #cccccc; - -webkit-border-top-right-radius: 0; - -webkit-border-bottom-right-radius: 4px; - -webkit-border-bottom-left-radius: 4px; - -webkit-border-top-left-radius: 0; - -moz-border-radius-topright: 0; - -moz-border-radius-bottomright: 4px; - -moz-border-radius-bottomleft: 4px; - -moz-border-radius-topleft: 0; - border-top-right-radius: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; - border-top-left-radius: 0; -} -#firechat .open > .firechat-dropdown-toggle { - outline: none; - text-decoration: none; - -webkit-border-top-right-radius: 4px; - -webkit-border-bottom-right-radius: 0; - -webkit-border-bottom-left-radius: 0; - -webkit-border-top-left-radius: 4px; - -moz-border-radius-topright: 4px; - -moz-border-radius-bottomright: 0; - -moz-border-radius-bottomleft: 0; - -moz-border-radius-topleft: 4px; - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - border-top-left-radius: 4px; -} -/* Component: Prompts -============================================================ */ -#firechat .prompt-wrapper { - position: absolute; - z-index: 1000; -} -#firechat .prompt { - position: absolute; - z-index: 1001; - background-color: #ffffff; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45); - -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45); - box-shadow: 0 5px 10px rgba(0, 0, 0, 0.45); -} -#firechat .prompt-header { - padding: 4px 8px; - font-weight: bold; - background-color: #eeeeee; - border: 1px solid #cccccc; - -webkit-border-top-right-radius: 4px; - -webkit-border-bottom-right-radius: 0; - -webkit-border-bottom-left-radius: 0; - -webkit-border-top-left-radius: 4px; - -moz-border-radius-topright: 4px; - -moz-border-radius-bottomright: 0; - -moz-border-radius-bottomleft: 0; - -moz-border-radius-topleft: 4px; - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - border-top-left-radius: 4px; -} -#firechat .prompt-header a.close { - opacity: 0.6; - font-size: 13px; - margin-top: 2px; -} -#firechat .prompt-header a.close:hover { - opacity: 0.9; -} -#firechat .prompt-body { - background-color: #ffffff; - padding: 4px 8px; - border-left: 1px solid #cccccc; - border-right: 1px solid #cccccc; -} -#firechat .prompt-footer { - padding: 4px 8px; - background-color: #eeeeee; - border: 1px solid #cccccc; - -webkit-border-top-right-radius: 0; - -webkit-border-bottom-right-radius: 4px; - -webkit-border-bottom-left-radius: 4px; - -webkit-border-top-left-radius: 0; - -moz-border-radius-topright: 0; - -moz-border-radius-bottomright: 4px; - -moz-border-radius-bottomleft: 4px; - -moz-border-radius-topleft: 0; - border-top-right-radius: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; - border-top-left-radius: 0; -} -#firechat .prompt-background { - background-color: #333333; - border: 1px solid #333333; - opacity: 0.8; - z-index: 1000; - height: 100%; - width: 100%; -} -/* Component: Buttons -============================================================ */ -#firechat .btn { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - height: 24px; - display: inline-block; - *display: inline; - *zoom: 1; - padding: 2px 5px; - margin-bottom: 0; - text-align: center; - vertical-align: middle; - cursor: pointer; - color: #333333; - font-size: 12px; - text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); - background-color: #f5f5f5; - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); - background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); - background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); - background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); - background-repeat: repeat-x; - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); - border-color: #e6e6e6 #e6e6e6 #bfbfbf; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - *background-color: #e6e6e6; - filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); - border: 1px solid #cccccc; - *border: 0; - border-bottom-color: #b3b3b3; - *margin-left: .3em; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -} -#firechat .btn:hover, -#firechat .btn:focus, -#firechat .btn:active, -#firechat .btn.active, -#firechat .btn.disabled, -#firechat .btn[disabled] { - color: #333333; - background-color: #e6e6e6; - *background-color: #d9d9d9; - outline: 0; -} -#firechat .btn:active, -#firechat .btn.active { - background-color: #cccccc; -} -#firechat .btn:first-child { - *margin-left: 0; -} -#firechat .btn:hover, -#firechat .btn:focus { - color: #333333; - text-decoration: none; - background-position: 0 -15px; - -webkit-transition: background-position 0.1s linear; - -moz-transition: background-position 0.1s linear; - -o-transition: background-position 0.1s linear; - transition: background-position 0.1s linear; -} -#firechat .btn.active, -#firechat .btn:active { - background-image: none; - outline: 0; - -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -} -#firechat .btn.disabled, -#firechat .btn[disabled] { - cursor: default; - background-image: none; - opacity: 0.65; - filter: alpha(opacity=65); -} -#firechat .btn.disabled:active, -#firechat .btn[disabled]:active { - -webkit-box-shadow: inherit; - -moz-box-shadow: inherit; - box-shadow: inherit; - background-color: #e6e6e6; -} -/* Component: Context Menu -============================================================ */ -#firechat .contextmenu { - position: fixed; - z-index: 1001; - min-width: 150px; - border: 1px solid #cccccc; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; -} -#firechat .contextmenu ul { - background-color: #ffffff; - list-style: none; -} -#firechat .contextmenu ul > li > a { - display: block; - padding: 3px 10px; - clear: both; - font-weight: normal; - line-height: 20px; - color: #333333; - white-space: nowrap; -} -#firechat .contextmenu ul > li > a.highlight { - background-color: #d9edf7; -} -#firechat .contextmenu ul > li > a:hover, -#firechat .contextmenu ul > li > a:focus { - text-decoration: none; - color: #ffffff; - background-color: #0081c2; - outline: 0; -} -/* Custom Styles -============================================================ */ -#firechat { - padding: 0; - font-family: sans-serif; - font-size: 12px; - line-height: 18px; -} -#firechat input, -#firechat textarea { - width: 100%; - font-family: sans-serif; - font-size: 12px; - line-height: 18px; - padding: 2px 5px; - border: 1px solid #cccccc; - -webkit-border-radius: 1px; - -moz-border-radius: 1px; - border-radius: 1px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -#firechat input:-moz-placeholder, -#firechat textarea:-moz-placeholder { - color: #aaaaaa; -} -#firechat input:-ms-input-placeholder, -#firechat textarea:-ms-input-placeholder { - color: #aaaaaa; -} -#firechat input::-webkit-input-placeholder, -#firechat textarea::-webkit-input-placeholder { - color: #aaaaaa; -} -#firechat input[disabled], -#firechat textarea[disabled] { - background-color: #eeeeee; -} -#firechat input { - height: 24px; -} -#firechat textarea { - resize: none; - height: 40px; -} -#firechat .search-wrapper { - -webkit-border-radius: 15px; - -moz-border-radius: 15px; - border-radius: 15px; - border: 1px solid #cccccc; - margin: 0 5px; - padding: 2px 5px; - background: #ffffff; -} -#firechat .search-wrapper > input[type=text] { - padding-left: 0px; - border: none; -} -#firechat .search-wrapper > input[type=text]:focus, -#firechat .search-wrapper > input[type=text]:active { - outline: 0; -} -#firechat .chat { - overflow: auto; - -ms-overflow-x: hidden; - overflow-x: hidden; - height: 290px; - position: relative; - margin-bottom: 5px; - border: 1px solid #cccccc; - border-top: none; - overflow-y: scroll; -} -#firechat .chat textarea { - overflow: auto; - vertical-align: top; -} -#firechat #textarea-container { - position: relative; - width: 100%; - float: left; - height: 35px; -} -#firechat #uploaded-image { - display: none; -} -#firechat #upload-icon { - position: absolute; - float: right; - height: 16px; - width: 18px; - bottom: 0px; - right: 5px; -} -#firechat #file-upload { - display: none; - position: relative; - overflow: hidden; - z-index: 2; - opacity: 0; -} -#firechat .message { - color: #333; - padding: 3px 5px; - border-bottom: 1px solid #ccc; -} -#firechat .message.highlighted { - background-color: #d9edf7; -} -#firechat .message .name { - font-weight: bold; - overflow-x: hidden; -} -#firechat .message.message-self { - color: #2675ab; -} -#firechat .message:nth-child(odd) { - background-color: #f9f9f9; -} -#firechat .message:nth-child(odd).highlighted { - background-color: #d9edf7; -} -#firechat .message:nth-child(odd).message-local { - background-color: #effafc; -} -#firechat .message-content { - word-wrap: break-word; - padding-right: 45px; -} -#firechat .message-content.red { - color: red; -} -#firechat .message.message-notification .message-content { - font-style: italic; -} -#firechat ul::-webkit-scrollbar { - -webkit-appearance: none; - width: 7px; -} -#firechat ul::-webkit-scrollbar-thumb { - border-radius: 4px; - -webkit-box-shadow: 0 0 1px rgba(255, 255, 255, 0.5); -} -#firechat #firechat-header { - padding: 6px 0 0 0; - height: 40px; -} -#firechat #firechat-tabs { - height: 435px; -} -#firechat #firechat-tab-list { - background-color: #ffffff; -} -#firechat #firechat-tab-content { - width: 100%; - background-color: #ffffff; -} -#firechat .tab-pane-menu { - border: 1px solid #ccc; - border-top: none; - vertical-align: middle; - padding-bottom: 5px; -} -#firechat .tab-pane-menu .firechat-dropdown { - margin: 5px 0 0 5px; -} -#firechat .tab-pane-menu > .icon { - margin: 5px 2px 0; -} -#firechat .icon { - display: inline-block; - *margin-right: .3em; - line-height: 20px; - vertical-align: middle; - background-repeat: no-repeat; - padding: 0; - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAL8AAAANEAYAAACoeGM7AAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAM80lEQVR42t2cZ4xWRRfHZ3dhwbK7CJZYYiOxV+wlUQzCKmBBsWPvYjQiaiyxYUwULLErltgrNpRF4q5iV0BRLFE0diUi7LIq6Pqw74f//rzO4Zm9d+5z9c37ni//3OfemXtm5sypc58q55xzrrpauHSpcOONheedJ9x9d2Hv3sLvvxfefbfw5puFf/5Zvr+8VFUl7Ozs/rkNNxTef79w222F77wjPOoo4ccfF/O+UDvGzTVEf8wH1zU1wlJJePTRwv33Fx57rPDnn/1+wbzzG+IXvrhmPUPzY/kJEc/HzqslK1fLLy8cMUK4667CFVYQ/vqr8PXXhU884f8eL6eXXKJ2wqSd3tDY2KOHc84NGqSRnnCC7tbVCdvbhRMnasWnTdt5Z+eca2pK6797Yh6ef1641lrCPfYQfv21UNwl62qv115b2Nws/PZb4d57C3/7LftalaOQ/C63nPCII4Tsg6228scHffqp8LHHhPfe6/8eu49feEH44YfCq64S/v67cMGC7tuvu65w6FDhllsKkS/0zoQJaZzMmSO+JaEzZmgkY8b88Ydzzs2b19HhnHNffSWJ6tVLM1cq/fKLrjXiUaPUrn9/XZ9yip6rqVmyxDnnnnrKvPbAA4V6TTJxP/zgT4zdyC+9JOzXz++PgceSVSS1tUJtE+c22si/f+21Pj9Wwd54o//8ZpsJd9xR2KtX9+8vmkLzcsABPt9z5wr32af88xiOf4oaGoSHH17M+/LKg203aJDwiy+EVh5DyHzuuWcxfDn31lvOOffMM7Nn6z1SsZ2dn30m/OQT4eefC7/8UvjBB0LaVzav7D873vfeE6LQISvv3Of50P6OJetgWFp5ZeFzz5V/b1bEEd1333x80g+O4mWXCXEQMDB33CG8/XYhBhuDmMZnOn30kZ5/+23nnGtpefNN55wbP96Xl/nzhYsWCdvauEbeQP1Of6US/XRZfDz8Bx8U9uwpPPFE4eOPC/EMVl9dOG6ccORI4Q03CA87LHbA5RcCwgO47TbhokXCYcOERCKQ7GJiMLiPokeQ2QCjRwtvukkY6zHg0V10kXDAAH++EIz77hM++aRwxRWFq64q3H57v9/+/YVPPy2cOFF47rnCNE8kll/Gi4eIAWU9v/vOnz8MA4qjb18hG51+2JiLF+ebX/hA4U+b5t+/7jrhAw8IkQ88WvnPiZzi4Q0eXL6/dEJhawaGDydmk4uEQmhu1kj79tVImb8RI8TZwIG0p78ddnAubOhDhIcPIXd4nnh4OHYYzPXXF7K/ed5GBLb/NLKRFOtMfyCZAiIKns8aSVp9xP4i8nv//Ti+icjgl0iDeUsjpKDSyJYeqqs1A+3taDBpkn79Qi5YW9vf5wXq0YP+1L5U6loAUjpW4WPhQhN00EFC2SXnDj1UiAF44w2hTWnEEqkcCIWJYkShQNbDIIJZZx2h9Xhs/7EpFDwCNs6UKf584tGQsiFCGTJEuMEG/jxBzBe/H3+8cJddhBiAZ58thl/eM2uW8MgjhWyAyy8XojhRUGuuKayvF7Jhf/pJ+O67wltvFU6dGscv78fTgg45RPjII+XbYZA23bT8/Vtu8ecBDy9MpHS0EROFr1B76lQp7r32su20EwYMkGSOG4dq4I0a4fDh9G9TQN0TKR0iB8aD3G+9tRDHDoPPenKf53GYiABiPWm7f046SUgKDs8aQwxlVfiQTVXh0BChxir+kDol5WPv24im+Ahcb6iu9jVnR4euGX9oXsLj7GKYHP68eUI8ANsRA7WKE8sNkUopdvgJsW0QUBbc3oewl6GQs9LUDgr85JOF5OZHjRKyESZNEp55ppBIC7IbxgoSkQzt2OgXX1wMv9RCFBAuG4HgSREKU0vB42Jjo6gxtPvtJ8TzTM91+kQOf731hHj4KHybA0bRK8B1bpNNhAqkE8OH40CKLZ3I4a+0kq6l8JuapPAbGx991Lm/r5s8+aFDlWOdOVMuS0ODNm5bm1RWSwsSrJY2FZVGRFYYYgwt+wO5EpeJ4eaa+zxPexQ+/Wcl+iFCxeBvs43QRujW048lu09Y16KI/m3Ewu8h/VS55w/5b7AGMrbW5lyXImQh8EhtqGBDGOu525QDnm5RhOcBzZ8vfO01IYIaev/Mmf5zpALsfSiv5bYLfeqpQhSUrYHY92GYbD+shx0XKSOKlrFk1xHFTQRon7M1FNtepaOErwsvFBIqkzKKlQ8MDoTnCpFKwyCi2FZbTYhDgydO6gfaaaesnFC0xQcUUQwlBi6VpPCHDJGKmDyZGWMldY2nPmmSP5NEdlkJRYSCZr7FRbiIzTX3eZ72tiiclZjf444rzyd6hkid9+fNCNhxvfJKvn5C/YVy9nZVYw89ZCdfI6TVEuCLCI4Zhp+Ojq6FIAdLFR0PjpQOFpyFsQMidw5ZxRo7ATaEI6fMgFD8FJsxXCgee00qSiWPJNfKaYLp08u/P1YQ4ZfxWgWDAcOjZmMR8G+3nZBTPbwffhYuFJ5zjhCPKi9ZBUzkh8dpBTkk2KSKLr1UiAIJEYYhK2GQIOto4OGj8NdYQ4hck8tnvkmtQSGDHKK6On8nUNtIPHwUvp05SeSwYTI1s2YpJhk5kliO/uP4Qe6IxMnhk9JhXqyCtQ4Oz9Oe/nwzl05EtJbI5fMeTs8QscIP+zwtEuA+csz+fvjhOH5tf6SSoZCjEipeKw5MVj12PemZ9tXVvunt2dOuHE+K06oqvbG2lp2ikS1ZIknv3burO45lXn+9kKItOfzQwhO6jR0r5PiXPaUQmzNHkMllIyhMMBudmgKnjqxnwnSssooQhWpTLOR6UVwc/4ul1lYhx7rwRBF4PBEEwxLFavhkeTmmN2aMEAG3ghdrqHx149z555efx9DGY37vvFNoPcxQe1v0SyObe8cRIYf/4otCPHwUPsVge4yXWgTEumWl9nZtsPp6irbk8OVyTJ5sYyRJdGOjkitJjUP3FyzwNzIOV1ZivdinFG3J4dt5twqW9eJ5nUFKDIB1xNIIh8p6oijUa64RcnyT2SLSJHWXdtqKcdD/BRcIifBiCf44TIGe2WILYaiGhWHFoaFGxnxtvnlWDvwZY/yLF6toy+8LF2rGamrESXK8WRIwe7YcjKYmzdD06Xpi7lzFWqR4/1pYeywMT5ncL4rpiiuE9tgnIRyeozP9ZyVSBNZyskHxpFFUCGroOCf36Zf28MtzRCqxOXPaM24iJxsJQQgOCgyiqM4GJvduKZRbjOWXXH+fPkKKiUQmOnyYRBrwZeeXCIxxQ/mPSfpEkZn3KZO+7PHiH38U2mKurQHY478ooHSSaZswgWOZum5uFra2iqPOTs0g93EE4NzWAKZM4RioIoDx4/PNE4YQxWNTs6HUgL1Pe3sMNCuF9qOVG2penIPHYOHokcJ8+WVhS4sQR4NaJP3F7luI9tSALBFxovhBW6uonFSORm7mzMEAzJjhnHMNDdLI9fXgq68651xdnZLYffpY+cpIhLzkUNNySd98I7QKFPs0cGC+4dv3sCAYIE4bhXJboWvwrruExxwjJPWStyjD8/b0AyEiCt4Wh6xBpCi+225CG5kUdWogxC/HMyldshGJ7IhcWIfTTxciLxhWqKgcJxuPc/h2nTAAaYrq4IP9dni01jCEiVM3nIdWdaizUxuTDdvaSgQQ6kfPNTVhKPgOgP7j5id0Dh9DbR05Unlch54PfQeQRuyrUM7ZOoxkCq6+WkikhiOBIQ/JEx7sGWfE8QlZOYKyOi7sS+uQgdn3ra/4LT/ZSS1razEEfBgoOf0rdRUaIB4rXyCedpqQFAu5KzxdPyBJPPRlj7d1Tw89JLznHiGeb+hDFVIWIQPll9SS3ynKUUwj5RWbI6Q/inWVEgJsUxRFKdKi+T3rLKEtshf9IZytPdgIgNM75PA5dWQ9fBAFE0+cu+dDGQyAHwGMHi0P/sordT12LB4+Ct//0Cbvh1zWINr9gAePIYe4thGCbU//sYRHn/fDLBwyawhDOfe8ESbvCx3/zHuKJp5Cil8cVlVlxcjXhv5yICvh4aPwreDlJY5nUay1Cj2rINn2lD4qPX6KwcPzRQHhKeP5WeQ+ng2nSyhCcv4fKip1EuIXRQlfXIMUn7nPl9SkhKhFFM2v7QcDEIoAQoiHbxV+5V/uEgGQAuJLXRQ7X/KS0sHD///8cpcIl/P69MN3GDh2RBzUvvjLFVI2NuK1einty+CsZDMY/z0qyuOvkGwIY8+zMuE2ZYGHj8JHUWQlm/sm1ENRZ81dWrShLEVAy1/20F9EEZrTQnk9HJCNYL+YLMrD+F/jF7IbnBQQNQDOi/MFJ9fk8O26xisMQmb7OykaagD+p/RLl3JNDj+U0gn13z0xLhQ0BtEqfLtP7TXP057+YvcDCpvDInwvYInUcnIqqjLKK2/IydlnF8NHfvq3FP9/ANgTCJ9z9ZF7AAAAAElFTkSuQmCC) no-repeat top left; - opacity: 0.3; - font-size: 22px; - font-family: Arial; - font-weight: bold; - overflow: hidden; -} -#firechat .icon.plus { - margin-top: 0; - vertical-align: top; - background: transparent; -} -#firechat .icon.search { - background-position: 0 0; - width: 13px; - height: 13px; -} -#firechat .icon.close { - background-position: -120px 0; - width: 13px; - height: 13px; -} -#firechat .icon.user-chat { - background-position: -138px 0; - width: 17px; - height: 13px; -} -#firechat .icon.user-group { - background-position: -18px 0; - width: 17px; - height: 13px; -} -#firechat .icon.user-mute { - background-position: -84px 0; - width: 13px; - height: 13px; -} -#firechat .icon.user-mute.red { - background-position: -102px 0; - width: 13px; - height: 13px; -} -#firechat .icon:hover, -#firechat .btn:hover > .icon { - opacity: 0.6; -} -#firechat a > .icon { - margin: 3px 1px; -} diff --git a/dist/firechat.js b/dist/firechat.js deleted file mode 100644 index d25c3dc..0000000 --- a/dist/firechat.js +++ /dev/null @@ -1,1976 +0,0 @@ -// Underscore.js 1.7.0 -// http://underscorejs.org -// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors -// Underscore may be freely distributed under the MIT license. -(function(){var n=this,t=n._,r=Array.prototype,e=Object.prototype,u=Function.prototype,i=r.push,a=r.slice,o=r.concat,l=e.toString,c=e.hasOwnProperty,f=Array.isArray,s=Object.keys,p=u.bind,h=function(n){return n instanceof h?n:this instanceof h?void(this._wrapped=n):new h(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=h),exports._=h):n._=h,h.VERSION="1.7.0";var g=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}};h.iteratee=function(n,t,r){return null==n?h.identity:h.isFunction(n)?g(n,t,r):h.isObject(n)?h.matches(n):h.property(n)},h.each=h.forEach=function(n,t,r){if(null==n)return n;t=g(t,r);var e,u=n.length;if(u===+u)for(e=0;u>e;e++)t(n[e],e,n);else{var i=h.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},h.map=h.collect=function(n,t,r){if(null==n)return[];t=h.iteratee(t,r);for(var e,u=n.length!==+n.length&&h.keys(n),i=(u||n).length,a=Array(i),o=0;i>o;o++)e=u?u[o]:o,a[o]=t(n[e],e,n);return a};var v="Reduce of empty array with no initial value";h.reduce=h.foldl=h.inject=function(n,t,r,e){null==n&&(n=[]),t=g(t,e,4);var u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length,o=0;if(arguments.length<3){if(!a)throw new TypeError(v);r=n[i?i[o++]:o++]}for(;a>o;o++)u=i?i[o]:o,r=t(r,n[u],u,n);return r},h.reduceRight=h.foldr=function(n,t,r,e){null==n&&(n=[]),t=g(t,e,4);var u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;if(arguments.length<3){if(!a)throw new TypeError(v);r=n[i?i[--a]:--a]}for(;a--;)u=i?i[a]:a,r=t(r,n[u],u,n);return r},h.find=h.detect=function(n,t,r){var e;return t=h.iteratee(t,r),h.some(n,function(n,r,u){return t(n,r,u)?(e=n,!0):void 0}),e},h.filter=h.select=function(n,t,r){var e=[];return null==n?e:(t=h.iteratee(t,r),h.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e)},h.reject=function(n,t,r){return h.filter(n,h.negate(h.iteratee(t)),r)},h.every=h.all=function(n,t,r){if(null==n)return!0;t=h.iteratee(t,r);var e,u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;for(e=0;a>e;e++)if(u=i?i[e]:e,!t(n[u],u,n))return!1;return!0},h.some=h.any=function(n,t,r){if(null==n)return!1;t=h.iteratee(t,r);var e,u,i=n.length!==+n.length&&h.keys(n),a=(i||n).length;for(e=0;a>e;e++)if(u=i?i[e]:e,t(n[u],u,n))return!0;return!1},h.contains=h.include=function(n,t){return null==n?!1:(n.length!==+n.length&&(n=h.values(n)),h.indexOf(n,t)>=0)},h.invoke=function(n,t){var r=a.call(arguments,2),e=h.isFunction(t);return h.map(n,function(n){return(e?t:n[t]).apply(n,r)})},h.pluck=function(n,t){return h.map(n,h.property(t))},h.where=function(n,t){return h.filter(n,h.matches(t))},h.findWhere=function(n,t){return h.find(n,h.matches(t))},h.max=function(n,t,r){var e,u,i=-1/0,a=-1/0;if(null==t&&null!=n){n=n.length===+n.length?n:h.values(n);for(var o=0,l=n.length;l>o;o++)e=n[o],e>i&&(i=e)}else t=h.iteratee(t,r),h.each(n,function(n,r,e){u=t(n,r,e),(u>a||u===-1/0&&i===-1/0)&&(i=n,a=u)});return i},h.min=function(n,t,r){var e,u,i=1/0,a=1/0;if(null==t&&null!=n){n=n.length===+n.length?n:h.values(n);for(var o=0,l=n.length;l>o;o++)e=n[o],i>e&&(i=e)}else t=h.iteratee(t,r),h.each(n,function(n,r,e){u=t(n,r,e),(a>u||1/0===u&&1/0===i)&&(i=n,a=u)});return i},h.shuffle=function(n){for(var t,r=n&&n.length===+n.length?n:h.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=h.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},h.sample=function(n,t,r){return null==t||r?(n.length!==+n.length&&(n=h.values(n)),n[h.random(n.length-1)]):h.shuffle(n).slice(0,Math.max(0,t))},h.sortBy=function(n,t,r){return t=h.iteratee(t,r),h.pluck(h.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var m=function(n){return function(t,r,e){var u={};return r=h.iteratee(r,e),h.each(t,function(e,i){var a=r(e,i,t);n(u,e,a)}),u}};h.groupBy=m(function(n,t,r){h.has(n,r)?n[r].push(t):n[r]=[t]}),h.indexBy=m(function(n,t,r){n[r]=t}),h.countBy=m(function(n,t,r){h.has(n,r)?n[r]++:n[r]=1}),h.sortedIndex=function(n,t,r,e){r=h.iteratee(r,e,1);for(var u=r(t),i=0,a=n.length;a>i;){var o=i+a>>>1;r(n[o])t?[]:a.call(n,0,t)},h.initial=function(n,t,r){return a.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},h.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:a.call(n,Math.max(n.length-t,0))},h.rest=h.tail=h.drop=function(n,t,r){return a.call(n,null==t||r?1:t)},h.compact=function(n){return h.filter(n,h.identity)};var y=function(n,t,r,e){if(t&&h.every(n,h.isArray))return o.apply(e,n);for(var u=0,a=n.length;a>u;u++){var l=n[u];h.isArray(l)||h.isArguments(l)?t?i.apply(e,l):y(l,t,r,e):r||e.push(l)}return e};h.flatten=function(n,t){return y(n,t,!1,[])},h.without=function(n){return h.difference(n,a.call(arguments,1))},h.uniq=h.unique=function(n,t,r,e){if(null==n)return[];h.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=h.iteratee(r,e));for(var u=[],i=[],a=0,o=n.length;o>a;a++){var l=n[a];if(t)a&&i===l||u.push(l),i=l;else if(r){var c=r(l,a,n);h.indexOf(i,c)<0&&(i.push(c),u.push(l))}else h.indexOf(u,l)<0&&u.push(l)}return u},h.union=function(){return h.uniq(y(arguments,!0,!0,[]))},h.intersection=function(n){if(null==n)return[];for(var t=[],r=arguments.length,e=0,u=n.length;u>e;e++){var i=n[e];if(!h.contains(t,i)){for(var a=1;r>a&&h.contains(arguments[a],i);a++);a===r&&t.push(i)}}return t},h.difference=function(n){var t=y(a.call(arguments,1),!0,!0,[]);return h.filter(n,function(n){return!h.contains(t,n)})},h.zip=function(n){if(null==n)return[];for(var t=h.max(arguments,"length").length,r=Array(t),e=0;t>e;e++)r[e]=h.pluck(arguments,e);return r},h.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},h.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=h.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}for(;u>e;e++)if(n[e]===t)return e;return-1},h.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=n.length;for("number"==typeof r&&(e=0>r?e+r+1:Math.min(e,r+1));--e>=0;)if(n[e]===t)return e;return-1},h.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=r||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=Array(e),i=0;e>i;i++,n+=r)u[i]=n;return u};var d=function(){};h.bind=function(n,t){var r,e;if(p&&n.bind===p)return p.apply(n,a.call(arguments,1));if(!h.isFunction(n))throw new TypeError("Bind must be called on a function");return r=a.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(a.call(arguments)));d.prototype=n.prototype;var u=new d;d.prototype=null;var i=n.apply(u,r.concat(a.call(arguments)));return h.isObject(i)?i:u}},h.partial=function(n){var t=a.call(arguments,1);return function(){for(var r=0,e=t.slice(),u=0,i=e.length;i>u;u++)e[u]===h&&(e[u]=arguments[r++]);for(;r=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=h.bind(n[r],n);return n},h.memoize=function(n,t){var r=function(e){var u=r.cache,i=t?t.apply(this,arguments):e;return h.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},h.delay=function(n,t){var r=a.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},h.defer=function(n){return h.delay.apply(h,[n,1].concat(a.call(arguments,1)))},h.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var l=function(){o=r.leading===!1?0:h.now(),a=null,i=n.apply(e,u),a||(e=u=null)};return function(){var c=h.now();o||r.leading!==!1||(o=c);var f=t-(c-o);return e=this,u=arguments,0>=f||f>t?(clearTimeout(a),a=null,o=c,i=n.apply(e,u),a||(e=u=null)):a||r.trailing===!1||(a=setTimeout(l,f)),i}},h.debounce=function(n,t,r){var e,u,i,a,o,l=function(){var c=h.now()-a;t>c&&c>0?e=setTimeout(l,t-c):(e=null,r||(o=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,a=h.now();var c=r&&!e;return e||(e=setTimeout(l,t)),c&&(o=n.apply(i,u),i=u=null),o}},h.wrap=function(n,t){return h.partial(t,n)},h.negate=function(n){return function(){return!n.apply(this,arguments)}},h.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},h.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},h.before=function(n,t){var r;return function(){return--n>0?r=t.apply(this,arguments):t=null,r}},h.once=h.partial(h.before,2),h.keys=function(n){if(!h.isObject(n))return[];if(s)return s(n);var t=[];for(var r in n)h.has(n,r)&&t.push(r);return t},h.values=function(n){for(var t=h.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},h.pairs=function(n){for(var t=h.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},h.invert=function(n){for(var t={},r=h.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},h.functions=h.methods=function(n){var t=[];for(var r in n)h.isFunction(n[r])&&t.push(r);return t.sort()},h.extend=function(n){if(!h.isObject(n))return n;for(var t,r,e=1,u=arguments.length;u>e;e++){t=arguments[e];for(r in t)c.call(t,r)&&(n[r]=t[r])}return n},h.pick=function(n,t,r){var e,u={};if(null==n)return u;if(h.isFunction(t)){t=g(t,r);for(e in n){var i=n[e];t(i,e,n)&&(u[e]=i)}}else{var l=o.apply([],a.call(arguments,1));n=new Object(n);for(var c=0,f=l.length;f>c;c++)e=l[c],e in n&&(u[e]=n[e])}return u},h.omit=function(n,t,r){if(h.isFunction(t))t=h.negate(t);else{var e=h.map(o.apply([],a.call(arguments,1)),String);t=function(n,t){return!h.contains(e,t)}}return h.pick(n,t,r)},h.defaults=function(n){if(!h.isObject(n))return n;for(var t=1,r=arguments.length;r>t;t++){var e=arguments[t];for(var u in e)n[u]===void 0&&(n[u]=e[u])}return n},h.clone=function(n){return h.isObject(n)?h.isArray(n)?n.slice():h.extend({},n):n},h.tap=function(n,t){return t(n),n};var b=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof h&&(n=n._wrapped),t instanceof h&&(t=t._wrapped);var u=l.call(n);if(u!==l.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]===n)return e[i]===t;var a=n.constructor,o=t.constructor;if(a!==o&&"constructor"in n&&"constructor"in t&&!(h.isFunction(a)&&a instanceof a&&h.isFunction(o)&&o instanceof o))return!1;r.push(n),e.push(t);var c,f;if("[object Array]"===u){if(c=n.length,f=c===t.length)for(;c--&&(f=b(n[c],t[c],r,e)););}else{var s,p=h.keys(n);if(c=p.length,f=h.keys(t).length===c)for(;c--&&(s=p[c],f=h.has(t,s)&&b(n[s],t[s],r,e)););}return r.pop(),e.pop(),f};h.isEqual=function(n,t){return b(n,t,[],[])},h.isEmpty=function(n){if(null==n)return!0;if(h.isArray(n)||h.isString(n)||h.isArguments(n))return 0===n.length;for(var t in n)if(h.has(n,t))return!1;return!0},h.isElement=function(n){return!(!n||1!==n.nodeType)},h.isArray=f||function(n){return"[object Array]"===l.call(n)},h.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},h.each(["Arguments","Function","String","Number","Date","RegExp"],function(n){h["is"+n]=function(t){return l.call(t)==="[object "+n+"]"}}),h.isArguments(arguments)||(h.isArguments=function(n){return h.has(n,"callee")}),"function"!=typeof/./&&(h.isFunction=function(n){return"function"==typeof n||!1}),h.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},h.isNaN=function(n){return h.isNumber(n)&&n!==+n},h.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===l.call(n)},h.isNull=function(n){return null===n},h.isUndefined=function(n){return n===void 0},h.has=function(n,t){return null!=n&&c.call(n,t)},h.noConflict=function(){return n._=t,this},h.identity=function(n){return n},h.constant=function(n){return function(){return n}},h.noop=function(){},h.property=function(n){return function(t){return t[n]}},h.matches=function(n){var t=h.pairs(n),r=t.length;return function(n){if(null==n)return!r;n=new Object(n);for(var e=0;r>e;e++){var u=t[e],i=u[0];if(u[1]!==n[i]||!(i in n))return!1}return!0}},h.times=function(n,t,r){var e=Array(Math.max(0,n));t=g(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},h.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},h.now=Date.now||function(){return(new Date).getTime()};var _={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},w=h.invert(_),j=function(n){var t=function(t){return n[t]},r="(?:"+h.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};h.escape=j(_),h.unescape=j(w),h.result=function(n,t){if(null==n)return void 0;var r=n[t];return h.isFunction(r)?n[t]():r};var x=0;h.uniqueId=function(n){var t=++x+"";return n?n+t:t},h.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var A=/(.)^/,k={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},O=/\\|'|\r|\n|\u2028|\u2029/g,F=function(n){return"\\"+k[n]};h.template=function(n,t,r){!t&&r&&(t=r),t=h.defaults({},t,h.templateSettings);var e=RegExp([(t.escape||A).source,(t.interpolate||A).source,(t.evaluate||A).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,a,o){return i+=n.slice(u,o).replace(O,F),u=o+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":a&&(i+="';\n"+a+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var a=new Function(t.variable||"obj","_",i)}catch(o){throw o.source=i,o}var l=function(n){return a.call(this,n,h)},c=t.variable||"obj";return l.source="function("+c+"){\n"+i+"}",l},h.chain=function(n){var t=h(n);return t._chain=!0,t};var E=function(n){return this._chain?h(n).chain():n};h.mixin=function(n){h.each(h.functions(n),function(t){var r=h[t]=n[t];h.prototype[t]=function(){var n=[this._wrapped];return i.apply(n,arguments),E.call(this,r.apply(h,n))}})},h.mixin(h),h.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=r[n];h.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],E.call(this,r)}}),h.each(["concat","join","slice"],function(n){var t=r[n];h.prototype[n]=function(){return E.call(this,t.apply(this._wrapped,arguments))}}),h.prototype.value=function(){return this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return h})}).call(this); - -//fgnass.github.com/spin.js#v1.2.7 -!function(e,t,n){function o(e,n){var r=t.createElement(e||"div"),i;for(i in n)r[i]=n[i];return r}function u(e){for(var t=1,n=arguments.length;t>1):parseInt(n.left,10)+i)+"px",top:(n.top=="auto"?a.y-u.y+(e.offsetHeight>>1):parseInt(n.top,10)+i)+"px"})),r.setAttribute("aria-role","progressbar"),t.lines(r,t.opts);if(!s){var f=0,l=n.fps,h=l/n.speed,d=(1-n.opacity)/(h*n.trail/100),v=h/n.lines;(function m(){f++;for(var e=n.lines;e;e--){var i=Math.max(1-(f+e*v)%h*d,n.opacity);t.opacity(r,n.lines-e,i,n)}t.timeout=t.el&&setTimeout(m,~~(1e3/l))})()}return t},stop:function(){var e=this.el;return e&&(clearTimeout(this.timeout),e.parentNode&&e.parentNode.removeChild(e),this.el=n),this},lines:function(e,t){function i(e,r){return c(o(),{position:"absolute",width:t.length+t.width+"px",height:t.width+"px",background:e,boxShadow:r,transformOrigin:"left",transform:"rotate("+~~(360/t.lines*n+t.rotate)+"deg) translate("+t.radius+"px"+",0)",borderRadius:(t.corners*t.width>>1)+"px"})}var n=0,r;for(;n',t)}var t=c(o("group"),{behavior:"url(#default#VML)"});!l(t,"transform")&&t.adj?(a.addRule(".spin-vml","behavior:url(#default#VML)"),v.prototype.lines=function(t,n){function s(){return c(e("group",{coordsize:i+" "+i,coordorigin:-r+" "+ -r}),{width:i,height:i})}function l(t,i,o){u(a,u(c(s(),{rotation:360/n.lines*t+"deg",left:~~i}),u(c(e("roundrect",{arcsize:n.corners}),{width:r,height:n.width,left:n.radius,top:-n.width>>1,filter:o}),e("fill",{color:n.color,opacity:n.opacity}),e("stroke",{opacity:0}))))}var r=n.length+n.width,i=2*r,o=-(n.width+n.length)*2+"px",a=c(s(),{position:"absolute",top:o,left:o}),f;if(n.shadow)for(f=1;f<=n.lines;f++)l(f,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(f=1;f<=n.lines;f++)l(f);return u(t,a)},v.prototype.opacity=function(e,t,n,r){var i=e.firstChild;r=r.shadow&&r.lines||0,i&&t+r\n
                                                              \n
                                                              \n\n\nChat Rooms\n\n\n
                                                                \n
                                                                \n\n\nVisitors\n\n\n
                                                                \n
                                                                \n
                                                                \n\n\n
                                                                \n
                                                                \n
                                                                  \n
                                                                  \n
                                                                  \n
                                                                  \n
                                                                  \n
                                                                  \n
                                                                    \n
                                                                    \n
                                                                    \n';}return __p}; - -this["FirechatDefaultTemplates"]["templates/layout-popout.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                    \n
                                                                    \n
                                                                      \n
                                                                      \n
                                                                      \n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/message-context-menu.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                      \n\n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/message.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                      \n
                                                                      \n'; if (!disableActions) { ;__p += '\n\n'; } ;__p += '
                                                                      \n
                                                                      \n' +((__t = ( message )) == null ? '' : __t) +'\n
                                                                      \n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/prompt-alert.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                      \n
                                                                      ' +__e( message ) +'
                                                                      \n

                                                                      \n\n

                                                                      \n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/prompt-create-room.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                      \n
                                                                      Give your chat room a name:
                                                                      \n\n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/prompt-invitation.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                      \n
                                                                      ' +__e( fromUserName ) +'
                                                                      \n

                                                                      invited you to join

                                                                      \n
                                                                      ' +__e( toRoomName ) +'
                                                                      \n

                                                                      \n\n\n

                                                                      \n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/prompt-invite-private.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                      \n
                                                                      Invite ' +__e( userName ) +' to ' +__e( roomName ) +'?
                                                                      \n

                                                                      \n\n\n

                                                                      \n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/prompt-invite-reply.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                      \n
                                                                      ' +__e( toUserName ) +'
                                                                      \n

                                                                      \n'; if (status === 'accepted') { ;__p += ' accepted your invite. '; } else { ;__p += ' declined your invite. '; } ;__p += '\n

                                                                      \n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/prompt-user-mute.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                      \n
                                                                      ' +__e( userName ) +'
                                                                      \n

                                                                      \n\n\n

                                                                      \n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/prompt.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                      \n
                                                                      \n' +__e( title ) +'\nX\n
                                                                      \n
                                                                      \n' +((__t = ( content )) == null ? '' : __t) +'\n
                                                                      \n
                                                                      \n
                                                                      ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/room-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                    • \n\n' +__e( name ) +'\n\n
                                                                    • ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                    • \n\n' +__e( name ) +''; if (!disableActions) { ;__p += '\n \n \n'; } ;__p += '\n\n
                                                                    • ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                    • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n+\n'; } ;__p += '\n\n
                                                                    • ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                      \n
                                                                      \n\n\nIn Room\n\n\n
                                                                      \n
                                                                        \n
                                                                        \n
                                                                        \n\n+\nInvite\n\n
                                                                        \n
                                                                        \n
                                                                        \n\n\n
                                                                        \n
                                                                        \n
                                                                          \n
                                                                          \n
                                                                          \n
                                                                          \n
                                                                          \n\n
                                                                          \n\n\n
                                                                          \n
                                                                          ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                        • \n' +__e( name ) +'\n
                                                                        • ';}return __p}; - -this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                        • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n \n'; } ;__p += '\n\n
                                                                        • ';}return __p}; -(function($) { - - // Shim for Function.bind(...) - (Required by IE < 9, FF < 4, SF < 6) - if (!Function.prototype.bind) { - Function.prototype.bind = function(oThis) { - if (typeof this !== "function") { - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function() {}, - fBound = function() { - return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - return fBound; - }; - } - - // Shim for Object.keys(...) - (Required by IE < 9, FF < 4) - Object.keys = Object.keys || function(oObj) { - var result = []; - for (var name in oObj) { - if (oObj.hasOwnProperty(name)) { - result.push(name); - } - } - return result; - }; - -})(); - -// Firechat is a simple, easily-extensible data layer for multi-user, -// multi-room chat, built entirely on [Firebase](https://firebase.com). -// -// The Firechat object is the primary conduit for all underlying data events. -// It exposes a number of methods for binding event listeners, creating, -// entering, or leaving chat rooms, initiating chats, sending messages, -// and moderator actions such as warning, kicking, or suspending users. -// -// Firechat.js 0.0.0 -// https://firebase.com -// (c) 2014 Firebase -// License: MIT - -// Setup -// -------------- -(function(Firebase) { - - // Establish a reference to the `window` object, and save the previous value - // of the `Firechat` variable. - var root = this, - previousFirechat = root.Firechat; - - function Firechat(firebaseRef, options) { - - // Instantiate a new connection to Firebase. - this._firebase = firebaseRef; - - // User-specific instance variables. - this._user = null; - this._userId = null; - this._userName = null; - this._isModerator = false; - - // A unique id generated for each session. - this._sessionId = null; - - // A mapping of event IDs to an array of callbacks. - this._events = {}; - - // A mapping of room IDs to a boolean indicating presence. - this._rooms = {}; - - // A mapping of operations to re-queue on disconnect. - this._presenceBits = {}; - - // Commonly-used Firebase references. - this._userRef = null; - this._messageRef = this._firebase.child('room-messages'); - this._roomRef = this._firebase.child('room-metadata'); - this._privateRoomRef = this._firebase.child('room-private-metadata'); - this._moderatorsRef = this._firebase.child('moderators'); - this._suspensionsRef = this._firebase.child('suspensions'); - this._usersOnlineRef = this._firebase.child('user-names-online'); - - // Setup and establish default options. - this._options = options || {}; - - // The number of historical messages to load per room. - this._options.numMaxMessages = this._options.numMaxMessages || 50; - } - - // Run Firechat in *noConflict* mode, returning the `Firechat` variable to - // its previous owner, and returning a reference to the Firechat object. - Firechat.noConflict = function noConflict() { - root.Firechat = previousFirechat; - return Firechat; - }; - - // Export the Firechat object as a global. - root.Firechat = Firechat; - - // Firechat Internal Methods - // -------------- - Firechat.prototype = { - - // Load the initial metadata for the user's account and set initial state. - _loadUserMetadata: function(onComplete) { - var self = this; - - // Update the user record with a default name on user's first visit. - this._userRef.transaction(function(current) { - if (!current || !current.id || !current.name) { - return { - id: self._userId, - name: self._userName - }; - } - }, function(error, committed, snapshot) { - self._user = snapshot.val(); - self._moderatorsRef.child(self._userId).once('value', function(snapshot) { - self._isModerator = !!snapshot.val(); - root.setTimeout(onComplete, 0); - }); - }); - }, - - // Initialize Firebase listeners and callbacks for the supported bindings. - _setupDataEvents: function() { - // Monitor connection state so we can requeue disconnect operations if need be. - this._firebase.root().child('.info/connected').on('value', function(snapshot) { - if (snapshot.val() === true) { - // We're connected (or reconnected)! Set up our presence state. - for (var i = 0; i < this._presenceBits; i++) { - var op = this._presenceBits[i], - ref = this._firebase.root().child(op.ref); - - ref.onDisconnect().set(op.offlineValue); - ref.set(op.onlineValue); - } - } - }, this); - - // Generate a unique session id for the visit. - var sessionRef = this._userRef.child('sessions').push(); - this._sessionId = sessionRef.key(); - this._queuePresenceOperation(sessionRef, true, null); - - // Register our username in the public user listing. - var usernameRef = this._usersOnlineRef.child(this._userName.toLowerCase()); - var usernameSessionRef = usernameRef.child(this._sessionId); - this._queuePresenceOperation(usernameSessionRef, { - id: this._userId, - name: this._userName - }, null); - - // Listen for state changes for the given user. - this._userRef.on('value', this._onUpdateUser, this); - - // Listen for chat invitations from other users. - this._userRef.child('invites').on('child_added', this._onFirechatInvite, this); - - // Listen for messages from moderators and adminstrators. - this._userRef.child('notifications').on('child_added', this._onNotification, this); - }, - - // Append the new callback to our list of event handlers. - _addEventCallback: function(eventId, callback) { - this._events[eventId] = this._events[eventId] || []; - this._events[eventId].push(callback); - }, - - // Retrieve the list of event handlers for a given event id. - _getEventCallbacks: function(eventId) { - if (this._events.hasOwnProperty(eventId)) { - return this._events[eventId]; - } - return []; - }, - - // Invoke each of the event handlers for a given event id with specified data. - _invokeEventCallbacks: function(eventId) { - var args = [], - callbacks = this._getEventCallbacks(eventId); - - Array.prototype.push.apply(args, arguments); - args = args.slice(1); - - for (var i = 0; i < callbacks.length; i += 1) { - callbacks[i].apply(null, args); - } - }, - - // Keep track of on-disconnect events so they can be requeued if we disconnect the reconnect. - _queuePresenceOperation: function(ref, onlineValue, offlineValue) { - ref.onDisconnect().set(offlineValue); - ref.set(onlineValue); - this._presenceBits[ref.toString()] = { - ref: ref, - onlineValue: onlineValue, - offlineValue: offlineValue - }; - }, - - // Remove an on-disconnect event from firing upon future disconnect and reconnect. - _removePresenceOperation: function(path, value) { - var ref = new Firebase(path); - ref.onDisconnect().cancel(); - ref.set(value); - delete this._presenceBits[path]; - }, - - // Event to monitor current user state. - _onUpdateUser: function(snapshot) { - this._user = snapshot.val(); - this._invokeEventCallbacks('user-update', this._user); - }, - - // Event to monitor current auth + user state. - _onAuthRequired: function() { - this._invokeEventCallbacks('auth-required'); - }, - - // Events to monitor room entry / exit and messages additional / removal. - _onEnterRoom: function(room) { - this._invokeEventCallbacks('room-enter', room); - }, - _onNewMessage: function(roomId, snapshot) { - var message = snapshot.val(); - message.id = snapshot.key(); - this._invokeEventCallbacks('message-add', roomId, message); - }, - _onRemoveMessage: function(roomId, snapshot) { - var messageId = snapshot.key(); - this._invokeEventCallbacks('message-remove', roomId, messageId); - }, - _onLeaveRoom: function(roomId) { - this._invokeEventCallbacks('room-exit', roomId); - }, - - // Event to listen for notifications from administrators and moderators. - _onNotification: function(snapshot) { - var notification = snapshot.val(); - if (!notification.read) { - if (notification.notificationType !== 'suspension' || notification.data.suspendedUntil < new Date().getTime()) { - snapshot.ref().child('read').set(true); - } - this._invokeEventCallbacks('notification', notification); - } - }, - - // Events to monitor chat invitations and invitation replies. - _onFirechatInvite: function(snapshot) { - var self = this, - invite = snapshot.val(); - - // Skip invites we've already responded to. - if (invite.status) { - return; - } - - invite.id = invite.id || snapshot.key(); - self.getRoom(invite.roomId, function(room) { - invite.toRoomName = room.name; - self._invokeEventCallbacks('room-invite', invite); - }); - }, - _onFirechatInviteResponse: function(snapshot) { - var self = this, - invite = snapshot.val(); - - invite.id = invite.id || snapshot.key(); - this._invokeEventCallbacks('room-invite-response', invite); - } - }; - - // Firechat External Methods - // -------------- - - // Initialize the library and setup data listeners. - Firechat.prototype.setUser = function(userId, userName, callback) { - var self = this; - - self._firebase.onAuth(function(authData) { - if (authData) { - self._userId = userId.toString(); - self._userName = userName.toString(); - self._userRef = self._firebase.child('users').child(self._userId); - self._loadUserMetadata(function() { - root.setTimeout(function() { - callback(self._user); - self._setupDataEvents(); - }, 0); - }); - } else { - self.warn('Firechat requires an authenticated Firebase reference. Pass an authenticated reference before loading.'); - } - }); - }; - - // Resumes the previous session by automatically entering rooms. - Firechat.prototype.resumeSession = function() { - this._userRef.child('rooms').once('value', function(snapshot) { - var rooms = snapshot.val(); - for (var roomId in rooms) { - this.enterRoom(rooms[roomId].id); - } - }, /* onError */ function(){}, /* context */ this); - }; - - // Callback registration. Supports each of the following events: - Firechat.prototype.on = function(eventType, cb) { - this._addEventCallback(eventType, cb); - }; - - // Create and automatically enter a new chat room. - Firechat.prototype.createRoom = function(roomName, roomType, callback) { - var self = this, - newRoomRef = this._roomRef.push(); - - var newRoom = { - id: newRoomRef.key(), - name: roomName, - type: roomType || 'public', - createdByUserId: this._userId, - createdAt: Firebase.ServerValue.TIMESTAMP - }; - - if (roomType === 'private') { - newRoom.authorizedUsers = {}; - newRoom.authorizedUsers[this._userId] = true; - } - - newRoomRef.set(newRoom, function(error) { - if (!error) { - self.enterRoom(newRoomRef.key()); - } - if (callback) { - callback(newRoomRef.key()); - } - }); - }; - - // Enter a chat room. - Firechat.prototype.enterRoom = function(roomId) { - var self = this; - self.getRoom(roomId, function(room) { - var roomName = room.name; - - if (!roomId || !roomName) return; - - // Skip if we're already in this room. - if (self._rooms[roomId]) { - return; - } - - self._rooms[roomId] = true; - - if (self._user) { - // Save entering this room to resume the session again later. - self._userRef.child('rooms').child(roomId).set({ - id: roomId, - name: roomName, - active: true - }); - - // Set presence bit for the room and queue it for removal on disconnect. - var presenceRef = self._firebase.child('room-users').child(roomId).child(self._userId).child(self._sessionId); - self._queuePresenceOperation(presenceRef, { - id: self._userId, - name: self._userName - }, null); - } - - // Invoke our callbacks before we start listening for new messages. - self._onEnterRoom({ id: roomId, name: roomName }); - - // Setup message listeners - self._roomRef.child(roomId).once('value', function(snapshot) { - self._messageRef.child(roomId).limitToLast(self._options.numMaxMessages).on('child_added', function(snapshot) { - self._onNewMessage(roomId, snapshot); - }, /* onCancel */ function() { - // Turns out we don't have permission to access these messages. - self.leaveRoom(roomId); - }, /* context */ self); - - self._messageRef.child(roomId).limitToLast(self._options.numMaxMessages).on('child_removed', function(snapshot) { - self._onRemoveMessage(roomId, snapshot); - }, /* onCancel */ function(){}, /* context */ self); - }, /* onFailure */ function(){}, self); - }); - }; - - // Leave a chat room. - Firechat.prototype.leaveRoom = function(roomId) { - var self = this, - userRoomRef = self._firebase.child('room-users').child(roomId); - - // Remove listener for new messages to this room. - self._messageRef.child(roomId).off(); - - if (self._user) { - var presenceRef = userRoomRef.child(self._userId).child(self._sessionId); - - // Remove presence bit for the room and cancel on-disconnect removal. - self._removePresenceOperation(presenceRef.toString(), null); - - // Remove session bit for the room. - self._userRef.child('rooms').child(roomId).remove(); - } - - delete self._rooms[roomId]; - - // Invoke event callbacks for the room-exit event. - self._onLeaveRoom(roomId); - }; - - Firechat.prototype.sendMessage = function(roomId, messageContent, messageType, cb) { - var self = this, - message = { - userId: self._userId, - name: self._userName, - timestamp: Firebase.ServerValue.TIMESTAMP, - message: messageContent, - type: messageType || 'default' - }, - newMessageRef; - - if (!self._user) { - self._onAuthRequired(); - if (cb) { - cb(new Error('Not authenticated or user not set!')); - } - return; - } - - newMessageRef = self._messageRef.child(roomId).push(); - newMessageRef.setWithPriority(message, Firebase.ServerValue.TIMESTAMP, cb); - }; - - Firechat.prototype.deleteMessage = function(roomId, messageId, cb) { - var self = this; - - self._messageRef.child(roomId).child(messageId).remove(cb); - }; - - // Mute or unmute a given user by id. This list will be stored internally and - // all messages from the muted clients will be filtered client-side after - // receipt of each new message. - Firechat.prototype.toggleUserMute = function(userId, cb) { - var self = this; - - if (!self._user) { - self._onAuthRequired(); - if (cb) { - cb(new Error('Not authenticated or user not set!')); - } - return; - } - - self._userRef.child('muted').child(userId).transaction(function(isMuted) { - return (isMuted) ? null : true; - }, cb); - }; - - // Send a moderator notification to a specific user. - Firechat.prototype.sendSuperuserNotification = function(userId, notificationType, data, cb) { - var self = this, - userNotificationsRef = self._firebase.child('users').child(userId).child('notifications'); - - userNotificationsRef.push({ - fromUserId: self._userId, - timestamp: Firebase.ServerValue.TIMESTAMP, - notificationType: notificationType, - data: data || {} - }, cb); - }; - - // Warn a user for violating the terms of service or being abusive. - Firechat.prototype.warnUser = function(userId) { - var self = this; - - self.sendSuperuserNotification(userId, 'warning'); - }; - - // Suspend a user by putting the user into read-only mode for a period. - Firechat.prototype.suspendUser = function(userId, timeLengthSeconds, cb) { - var self = this, - suspendedUntil = new Date().getTime() + 1000*timeLengthSeconds; - - self._suspensionsRef.child(userId).set(suspendedUntil, function(error) { - if (error && cb) { - return cb(error); - } else { - self.sendSuperuserNotification(userId, 'suspension', { - suspendedUntil: suspendedUntil - }); - return cb(null); - } - }); - }; - - // Invite a user to a specific chat room. - Firechat.prototype.inviteUser = function(userId, roomId) { - var self = this, - sendInvite = function() { - var inviteRef = self._firebase.child('users').child(userId).child('invites').push(); - inviteRef.set({ - id: inviteRef.key(), - fromUserId: self._userId, - fromUserName: self._userName, - roomId: roomId - }); - - // Handle listen unauth / failure in case we're kicked. - inviteRef.on('value', self._onFirechatInviteResponse, function(){}, self); - }; - - if (!self._user) { - self._onAuthRequired(); - return; - } - - self.getRoom(roomId, function(room) { - if (room.type === 'private') { - var authorizedUserRef = self._roomRef.child(roomId).child('authorizedUsers'); - authorizedUserRef.child(userId).set(true, function(error) { - if (!error) { - sendInvite(); - } - }); - } else { - sendInvite(); - } - }); - }; - - Firechat.prototype.acceptInvite = function(inviteId, cb) { - var self = this; - - self._userRef.child('invites').child(inviteId).once('value', function(snapshot) { - var invite = snapshot.val(); - if (invite === null && cb) { - return cb(new Error('acceptInvite(' + inviteId + '): invalid invite id')); - } else { - self.enterRoom(invite.roomId); - self._userRef.child('invites').child(inviteId).update({ - 'status': 'accepted', - 'toUserName': self._userName - }, cb); - } - }, self); - }; - - Firechat.prototype.declineInvite = function(inviteId, cb) { - var self = this, - updates = { - 'status': 'declined', - 'toUserName': self._userName - }; - - self._userRef.child('invites').child(inviteId).update(updates, cb); - }; - - Firechat.prototype.getRoomList = function(cb) { - var self = this; - - self._roomRef.once('value', function(snapshot) { - cb(snapshot.val()); - }); - }; - - Firechat.prototype.getUsersByRoom = function() { - var self = this, - roomId = arguments[0], - query = self._firebase.child('room-users').child(roomId), - cb = arguments[arguments.length - 1], - limit = null; - - if (arguments.length > 2) { - limit = arguments[1]; - } - - query = (limit) ? query.limitToLast(limit) : query; - - query.once('value', function(snapshot) { - var usernames = snapshot.val() || {}, - usernamesUnique = {}; - - for (var username in usernames) { - for (var session in usernames[username]) { - // Skip all other sessions for this user as we only need one. - usernamesUnique[username] = usernames[username][session]; - break; - } - } - - root.setTimeout(function() { - cb(usernamesUnique); - }, 0); - }); - }; - - Firechat.prototype.getUsersByPrefix = function(prefix, startAt, endAt, limit, cb) { - var self = this, - query = this._usersOnlineRef, - prefixLower = prefix.toLowerCase(); - - if (startAt) { - query = query.startAt(null, startAt); - } else if (endAt) { - query = query.endAt(null, endAt); - } else { - query = (prefixLower) ? query.startAt(null, prefixLower) : query.startAt(); - } - - query = (limit) ? query.limitToLast(limit) : query; - - query.once('value', function(snapshot) { - var usernames = snapshot.val() || {}, - usernamesFiltered = {}; - - for (var userNameKey in usernames) { - var sessions = usernames[userNameKey], - userName, userId, usernameClean; - - // Grab the user data from the first registered active session. - for (var sessionId in sessions) { - userName = sessions[sessionId].name; - userId = sessions[sessionId].id; - - // Skip all other sessions for this user as we only need one. - break; - } - - // Filter out any usernames that don't match our prefix and break. - if ((prefix.length > 0) && (userName.toLowerCase().indexOf(prefixLower) !== 0)) - continue; - - usernamesFiltered[userName] = { - name: userName, - id: userId - }; - } - - root.setTimeout(function() { - cb(usernamesFiltered); - }, 0); - }); - }; - - // Miscellaneous helper methods. - Firechat.prototype.getRoom = function(roomId, callback) { - this._roomRef.child(roomId).once('value', function(snapshot) { - callback(snapshot.val()); - }); - }; - - Firechat.prototype.userIsModerator = function() { - return this._isModerator; - }; - - Firechat.prototype.warn = function(msg) { - if (console) { - msg = 'Firechat Warning: ' + msg; - if (typeof console.warn === 'function') { - console.warn(msg); - } else if (typeof console.log === 'function') { - console.log(msg); - } - } - }; -})(Firebase); - -(function($) { - - - if (!$ || (parseInt($().jquery.replace(/\./g, ""), 10) < 170)) { - throw new Error("jQuery 1.7 or later required!"); - } - - var root = this, - previousFirechatUI = root.FirechatUI; - - root.FirechatUI = FirechatUI; - - if (!self.FirechatDefaultTemplates) { - throw new Error("Unable to find chat templates!"); - } - - function FirechatUI(firebaseRef, el, options) { - var self = this; - - if (!firebaseRef) { - throw new Error('FirechatUI: Missing required argument `firebaseRef`'); - } - - if (!el) { - throw new Error('FirechatUI: Missing required argument `el`'); - } - - options = options || {}; - this._options = options; - - this._el = el; - this._user = null; - this._chat = new Firechat(firebaseRef, options); - - // A list of rooms to enter once we've made room for them (once we've hit the max room limit). - this._roomQueue = []; - - // Define some constants regarding maximum lengths, client-enforced. - this.maxLengthUsername = 15; - this.maxLengthUsernameDisplay = 15; - this.maxLengthRoomName = 24; - this.maxLengthMessage = 120; - this.maxUserSearchResults = 100; - - // Define some useful regexes. - this.urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim; - this.pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim; - - this._renderLayout(); - - // Grab shortcuts to commonly used jQuery elements. - this.$wrapper = $('#firechat'); - this.$roomList = $('#firechat-room-list'); - this.$tabList = $('#firechat-tab-list'); - this.$tabContent = $('#firechat-tab-content'); - this.$messages = {}; - - // Rate limit messages from a given user with some defaults. - this.$rateLimit = { - limitCount: 10, // max number of events - limitInterval: 10000, // max interval for above count in milliseconds - limitWaitTime: 30000, // wait time if a user hits the wait limit - history: {} - }; - - // Setup UI bindings for chat controls. - this._bindUIEvents(); - - // Setup bindings to internal methods - this._bindDataEvents(); - } - - // Run FirechatUI in *noConflict* mode, returning the `FirechatUI` variable to - // its previous owner, and returning a reference to the FirechatUI object. - FirechatUI.noConflict = function noConflict() { - root.FirechatUI = previousFirechatUI; - return FirechatUI; - }; - - FirechatUI.prototype = { - - _bindUIEvents: function() { - // Chat-specific custom interactions and functionality. - this._bindForHeightChange(); - this._bindForTabControls(); - this._bindForRoomList(); - this._bindForUserRoomList(); - this._bindForUserSearch(); - this._bindForUserMuting(); - this._bindForChatInvites(); - this._bindForRoomListing(); - this._bindForFileUpload(); - - // Generic, non-chat-specific interactive elements. - this._setupTabs(); - this._setupDropdowns(); - this._bindTextInputFieldLimits(); - }, - - _bindDataEvents: function() { - this._chat.on('user-update', this._onUpdateUser.bind(this)); - - // Bind events for new messages, enter / leaving rooms, and user metadata. - this._chat.on('room-enter', this._onEnterRoom.bind(this)); - this._chat.on('room-exit', this._onLeaveRoom.bind(this)); - this._chat.on('message-add', this._onNewMessage.bind(this)); - this._chat.on('message-remove', this._onRemoveMessage.bind(this)); - - // Bind events related to chat invitations. - this._chat.on('room-invite', this._onChatInvite.bind(this)); - this._chat.on('room-invite-response', this._onChatInviteResponse.bind(this)); - - // Binds events related to admin or moderator notifications. - this._chat.on('notification', this._onNotification.bind(this)); - }, - - _renderLayout: function() { - var template = FirechatDefaultTemplates["templates/layout-full.html"]; - $(this._el).html(template({ - maxLengthUsername: this.maxLengthUsername - })); - }, - - _onUpdateUser: function(user) { - // Update our current user state and render latest user name. - this._user = user; - - // Update our interface to reflect which users are muted or not. - var mutedUsers = this._user.muted || {}; - $('[data-event="firechat-user-mute-toggle"]').each(function(i, el) { - var userId = $(this).closest('[data-user-id]').data('user-id'); - $(this).toggleClass('red', !!mutedUsers[userId]); - }); - - // Ensure that all messages from muted users are removed. - for (var userId in mutedUsers) { - $('.message[data-user-id="' + userId + '"]').fadeOut(); - } - }, - - _onEnterRoom: function(room) { - this.attachTab(room.id, room.name); - }, - _onLeaveRoom: function(roomId) { - this.removeTab(roomId); - - // Auto-enter rooms in the queue - if ((this._roomQueue.length > 0)) { - this._chat.enterRoom(this._roomQueue.shift(roomId)); - } - }, - _onNewMessage: function(roomId, message) { - var userId = message.userId; - if (!this._user || !this._user.muted || !this._user.muted[userId]) { - this.showMessage(roomId, message); - } - }, - _onRemoveMessage: function(roomId, messageId) { - this.removeMessage(roomId, messageId); - }, - - // Events related to chat invitations. - _onChatInvite: function(invitation) { - var self = this; - var template = FirechatDefaultTemplates["templates/prompt-invitation.html"]; - var $prompt = this.prompt('Invite', template(invitation)); - $prompt.find('a.close').click(function() { - $prompt.remove(); - self._chat.declineInvite(invitation.id); - return false; - }); - - $prompt.find('[data-toggle=accept]').click(function() { - $prompt.remove(); - self._chat.acceptInvite(invitation.id); - return false; - }); - - $prompt.find('[data-toggle=decline]').click(function() { - $prompt.remove(); - self._chat.declineInvite(invitation.id); - return false; - }); - }, - _onChatInviteResponse: function(invitation) { - if (!invitation.status) return; - - var self = this, - template = FirechatDefaultTemplates["templates/prompt-invite-reply.html"], - $prompt; - - if (invitation.status && invitation.status === 'accepted') { - $prompt = this.prompt('Accepted', template(invitation)); - this._chat.getRoom(invitation.roomId, function(room) { - self.attachTab(invitation.roomId, room.name); - }); - } else { - $prompt = this.prompt('Declined', template(invitation)); - } - - $prompt.find('a.close').click(function() { - $prompt.remove(); - return false; - }); - }, - - // Events related to admin or moderator notifications. - _onNotification: function(notification) { - if (notification.notificationType === 'warning') { - this.renderAlertPrompt('Warning', 'You are being warned for inappropriate messaging. Further violation may result in temporary or permanent ban of service.'); - } else if (notification.notificationType === 'suspension') { - var suspendedUntil = notification.data.suspendedUntil, - secondsLeft = Math.round((suspendedUntil - new Date().getTime()) / 1000), - timeLeft = ''; - - if (secondsLeft > 0) { - if (secondsLeft > 2*3600) { - var hours = Math.floor(secondsLeft / 3600); - timeLeft = hours + ' hours, '; - secondsLeft -= 3600*hours; - } - timeLeft += Math.floor(secondsLeft / 60) + ' minutes'; - this.renderAlertPrompt('Suspended', 'A moderator has suspended you for violating site rules. You cannot send messages for another ' + timeLeft + '.'); - } - } - } - }; - - /** - * Initialize an authenticated session with a user id and name. - * This method assumes that the underlying Firebase reference has - * already been authenticated. - */ - FirechatUI.prototype.setUser = function(userId, userName) { - var self = this; - - // Initialize data events - self._chat.setUser(userId, userName, function(user) { - self._user = user; - - if (self._chat.userIsModerator()) { - self._bindSuperuserUIEvents(); - } - - self._chat.resumeSession(); - }); - }; - - /** - * Exposes internal chat bindings via this external interface. - */ - FirechatUI.prototype.on = function(eventType, cb) { - var self = this; - - this._chat.on(eventType, cb); - }; - - /** - * Binds a custom context menu to messages for superusers to warn or ban - * users for violating terms of service. - */ - FirechatUI.prototype._bindSuperuserUIEvents = function() { - var self = this, - parseMessageVars = function(event) { - var $this = $(this), - messageId = $this.closest('[data-message-id]').data('message-id'), - userId = $('[data-message-id="' + messageId + '"]').closest('[data-user-id]').data('user-id'), - roomId = $('[data-message-id="' + messageId + '"]').closest('[data-room-id]').data('room-id'); - - return { messageId: messageId, userId: userId, roomId: roomId }; - }, - clearMessageContextMenus = function() { - // Remove any context menus currently showing. - $('[data-toggle="firechat-contextmenu"]').each(function() { - $(this).remove(); - }); - - // Remove any messages currently highlighted. - $('#firechat .message.highlighted').each(function() { - $(this).removeClass('highlighted'); - }); - }, - showMessageContextMenu = function(event) { - var $this = $(this), - $message = $this.closest('[data-message-id]'), - template = FirechatDefaultTemplates["templates/message-context-menu.html"], - messageVars = parseMessageVars.call(this, event), - $template; - - event.preventDefault(); - - // Clear existing menus. - clearMessageContextMenus(); - - // Highlight the relevant message. - $this.addClass('highlighted'); - - self._chat.getRoom(messageVars.roomId, function(room) { - // Show the context menu. - $template = $(template({ - id: $message.data('message-id') - })); - $template.css({ - left: event.clientX, - top: event.clientY - }).appendTo(self.$wrapper); - }); - }; - - // Handle dismissal of message context menus (any non-right-click click event). - $(document).bind('click', { self: this }, function(event) { - if (!event.button || event.button != 2) { - clearMessageContextMenus(); - } - }); - - // Handle display of message context menus (via right-click on a message). - $(document).delegate('[data-class="firechat-message"]', 'contextmenu', showMessageContextMenu); - - // Handle click of the 'Warn User' contextmenu item. - $(document).delegate('[data-event="firechat-user-warn"]', 'click', function(event) { - var messageVars = parseMessageVars.call(this, event); - self._chat.warnUser(messageVars.userId); - }); - - // Handle click of the 'Suspend User (1 Hour)' contextmenu item. - $(document).delegate('[data-event="firechat-user-suspend-hour"]', 'click', function(event) { - var messageVars = parseMessageVars.call(this, event); - self._chat.suspendUser(messageVars.userId, /* 1 Hour = 3600s */ 60*60); - }); - - // Handle click of the 'Suspend User (1 Day)' contextmenu item. - $(document).delegate('[data-event="firechat-user-suspend-day"]', 'click', function(event) { - var messageVars = parseMessageVars.call(this, event); - self._chat.suspendUser(messageVars.userId, /* 1 Day = 86400s */ 24*60*60); - }); - - // Handle click of the 'Delete Message' contextmenu item. - $(document).delegate('[data-event="firechat-message-delete"]', 'click', function(event) { - var messageVars = parseMessageVars.call(this, event); - self._chat.deleteMessage(messageVars.roomId, messageVars.messageId); - }); - }; - - /** - * Binds to height changes in the surrounding div. - */ - FirechatUI.prototype._bindForHeightChange = function() { - var self = this, - $el = $(this._el), - lastHeight = null; - - setInterval(function() { - var height = $el.height(); - if (height != lastHeight) { - lastHeight = height; - $('.chat').each(function(i, el) { - - }); - } - }, 500); - }; - - /** - * Binds custom inner-tab events. - */ - FirechatUI.prototype._bindForTabControls = function() { - var self = this; - - // Handle click of tab close button. - $(document).delegate('[data-event="firechat-close-tab"]', 'click', function(event) { - var roomId = $(this).closest('[data-room-id]').data('room-id'); - self._chat.leaveRoom(roomId); - return false; - }); - }; - - /** - * Binds room list dropdown to populate room list on-demand. - */ - FirechatUI.prototype._bindForRoomList = function() { - var self = this; - - $('#firechat-btn-rooms').bind('click', function() { - if ($(this).parent().hasClass('open')) { - return; - } - - var $this = $(this), - template = FirechatDefaultTemplates["templates/room-list-item.html"], - selectRoomListItem = function() { - var parent = $(this).parent(), - roomId = parent.data('room-id'), - roomName = parent.data('room-name'); - - if (self.$messages[roomId]) { - self.focusTab(roomId); - } else { - self._chat.enterRoom(roomId, roomName); - } - return false; - }; - - self._chat.getRoomList(function(rooms) { - self.$roomList.empty(); - for (var roomId in rooms) { - var room = rooms[roomId]; - if (room.type != "public") continue; - room.isRoomOpen = !!self.$messages[room.id]; - var $roomItem = $(template(room)); - $roomItem.children('a').bind('click', selectRoomListItem); - self.$roomList.append($roomItem.toggle(true)); - } - }); - }); - }; - - /** - * Binds user list dropdown per room to populate user list on-demand. - */ - FirechatUI.prototype._bindForUserRoomList = function() { - var self = this; - - // Upon click of the dropdown, autofocus the input field and trigger list population. - $(document).delegate('[data-event="firechat-user-room-list-btn"]', 'click', function(event) { - event.stopPropagation(); - - var $this = $(this), - roomId = $this.closest('[data-room-id]').data('room-id'), - template = FirechatDefaultTemplates["templates/room-user-list-item.html"], - targetId = $this.data('target'), - $target = $('#' + targetId); - - $target.empty(); - self._chat.getUsersByRoom(roomId, function(users) { - for (var username in users) { - user = users[username]; - user.disableActions = (!self._user || user.id === self._user.id); - user.nameTrimmed = self.trimWithEllipsis(user.name, self.maxLengthUsernameDisplay); - user.isMuted = (self._user && self._user.muted && self._user.muted[user.id]); - $target.append($(template(user))); - } - self.sortListLexicographically('#' + targetId); - }); - }); - }; - - /** - * Binds for file upload icon - */ - - FirechatUI.prototype._bindForFileUpload = function() { - var self = this; - var handleFileSelect = function(event) { - var f = event.target.files[0]; - var reader = new FileReader(); - reader.onload = (function(theFile) { - return function(e) { - var filePayload = e.target.result; - // Generate a location that can't be guessed using the file's contents and a random number - var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); - var f = new Firebase(firebaseRef + '/pano/' + hash + '/filePayload'); - spinner.spin(document.getElementById('spin')); - // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview - f.set(filePayload, function() { - spinner.stop(); - var imageFileName = firebaseRef + '/pano/' + hash + '/filePayload'; - console.log("File with hash: " + imageFileName + ' created'); - $('#file-upload').hide(); - var roomId = $("textarea").attr("id").replace(/textarea/, ""); - var message = self.trimWithEllipsis("File Uploaded from " + self._chat._userName, self.maxLengthMessage); - self._chat.sendMessage(roomId, message); - f.once('value', function(snap) { - var payload = snap.val(); - if (payload !== null) { - var uploadImg = $(''); - uploadImg.attr("src", payload); - uploadImg.appendTo($(".message").last()); - uploadImg.width(313); - uploadImg.show(); - } else { - $('#body').append("Not found"); - } - spinner.stop(); - }); - }); - }; - })(f); - reader.readAsDataURL(f); - }; - // Upon click of the file icon image - $(document).delegate('[data-event="firechat-upload-file"]', 'click', function(event) { - event.stopPropagation(); - console.log("Clicked on the button!"); - $('#file-upload').show(); - $("#file-upload").get(0).addEventListener('change', handleFileSelect, false); - }); - - // Upon completed file upload - $(document).delegate('[data-event="firechat-file-uploaded"]', 'change', function(event) { - event.stopPropagation(); - console.log("Upload Complete"); - // - }); - - }; - - /** - * Binds user search buttons, dropdowns, and input fields for searching all - * active users currently in chat. - */ - FirechatUI.prototype._bindForUserSearch = function() { - var self = this, - handleUserSearchSubmit = function(event) { - var $this = $(this), - targetId = $this.data('target'), - controlsId = $this.data('controls'), - templateId = $this.data('template'), - prefix = $this.val() || $this.data('prefix') || '', - startAt = $this.data('startAt') || null, - endAt = $this.data('endAt') || null; - - event.preventDefault(); - - userSearch(targetId, templateId, controlsId, prefix, startAt, endAt); - }, - userSearch = function(targetId, templateId, controlsId, prefix, startAt, endAt) { - var $target = $('#' + targetId), - $controls = $('#' + controlsId), - template = FirechatDefaultTemplates[templateId]; - - // Query results, filtered by prefix, using the defined startAt and endAt markets. - self._chat.getUsersByPrefix(prefix, startAt, endAt, self.maxUserSearchResults, function(users) { - var numResults = 0, - $prevBtn, $nextBtn, username, firstResult, lastResult; - - $target.empty(); - - for (username in users) { - var user = users[username]; - - // Disable buttons for . - user.disableActions = (!self._user || user.id === self._user.id); - - numResults += 1; - - $target.append(template(user)); - - // If we've hit our result limit, the additional value signifies we should paginate. - if (numResults === 1) { - firstResult = user.name.toLowerCase(); - } else if (numResults >= self.maxUserSearchResults) { - lastResult = user.name.toLowerCase(); - break; - } - } - - if ($controls) { - $prevBtn = $controls.find('[data-toggle="firechat-pagination-prev"]'); - $nextBtn = $controls.find('[data-toggle="firechat-pagination-next"]'); - - // Sort out configuration for the 'next' button - if (lastResult) { - $nextBtn - .data('event', 'firechat-user-search') - .data('startAt', lastResult) - .data('prefix', prefix) - .removeClass('disabled').removeAttr('disabled'); - } else { - $nextBtn - .data('event', null) - .data('startAt', null) - .data('prefix', null) - .addClass('disabled').attr('disabled', 'disabled'); - } - } - }); - }; - - $(document).delegate('[data-event="firechat-user-search"]', 'keyup', handleUserSearchSubmit); - $(document).delegate('[data-event="firechat-user-search"]', 'click', handleUserSearchSubmit); - - // Upon click of the dropdown, autofocus the input field and trigger list population. - $(document).delegate('[data-event="firechat-user-search-btn"]', 'click', function(event) { - event.stopPropagation(); - var $input = $(this).next('div.firechat-dropdown-menu').find('input'); - $input.focus(); - $input.trigger(jQuery.Event('keyup')); - }); - - // Ensure that the dropdown stays open despite clicking on the input element. - $(document).delegate('[data-event="firechat-user-search"]', 'click', function(event) { - event.stopPropagation(); - }); - }; - - /** - * Binds user mute toggles and removes all messages for a given user upon mute. - */ - FirechatUI.prototype._bindForUserMuting = function() { - var self = this; - $(document).delegate('[data-event="firechat-user-mute-toggle"]', 'click', function(event) { - var $this = $(this), - userId = $this.closest('[data-user-id]').data('user-id'), - userName = $this.closest('[data-user-name]').data('user-name'), - isMuted = $this.hasClass('red'), - template = FirechatDefaultTemplates["templates/prompt-user-mute.html"]; - - event.preventDefault(); - - // Require user confirmation for muting. - if (!isMuted) { - var $prompt = self.prompt('Mute User?', template({ - userName: userName - })); - - $prompt.find('a.close').first().click(function() { - $prompt.remove(); - return false; - }); - - $prompt.find('[data-toggle=decline]').first().click(function() { - $prompt.remove(); - return false; - }); - - $prompt.find('[data-toggle=accept]').first().click(function() { - self._chat.toggleUserMute(userId); - $prompt.remove(); - return false; - }); - } else { - self._chat.toggleUserMute(userId); - } - }); - }; - - /** - * Binds to elements with the data-event='firechat-user-(private)-invite' and - * handles invitations as well as room creation and entering. - */ - FirechatUI.prototype._bindForChatInvites = function() { - var self = this, - renderInvitePrompt = function(event) { - var $this = $(this), - userId = $this.closest('[data-user-id]').data('user-id'), - roomId = $this.closest('[data-room-id]').data('room-id'), - userName = $this.closest('[data-user-name]').data('user-name'), - template = FirechatDefaultTemplates["templates/prompt-invite-private.html"], - $prompt; - - self._chat.getRoom(roomId, function(room) { - $prompt = self.prompt('Invite', template({ - userName: userName, - roomName: room.name - })); - - $prompt.find('a.close').click(function() { - $prompt.remove(); - return false; - }); - - $prompt.find('[data-toggle=decline]').click(function() { - $prompt.remove(); - return false; - }); - - $prompt.find('[data-toggle=accept]').first().click(function() { - $prompt.remove(); - self._chat.inviteUser(userId, roomId, room.name); - return false; - }); - return false; - }); - return false; - }, - renderPrivateInvitePrompt = function(event) { - var $this = $(this), - userId = $this.closest('[data-user-id]').data('user-id'), - userName = $this.closest('[data-user-name]').data('user-name'), - template = FirechatDefaultTemplates["templates/prompt-invite-private.html"], - $prompt; - - if (userId && userName) { - $prompt = self.prompt('Private Invite', template({ - userName: userName, - roomName: 'Private Chat' - })); - - $prompt.find('a.close').click(function() { - $prompt.remove(); - return false; - }); - - $prompt.find('[data-toggle=decline]').click(function() { - $prompt.remove(); - return false; - }); - - $prompt.find('[data-toggle=accept]').first().click(function() { - $prompt.remove(); - var roomName = 'Private Chat'; - self._chat.createRoom(roomName, 'private', function(roomId) { - self._chat.inviteUser(userId, roomId, roomName); - }); - return false; - }); - } - return false; - }; - - $(document).delegate('[data-event="firechat-user-chat"]', 'click', renderPrivateInvitePrompt); - $(document).delegate('[data-event="firechat-user-invite"]', 'click', renderInvitePrompt); - }; - - /** - * Binds to room dropdown button, menu items, and create room button. - */ - FirechatUI.prototype._bindForRoomListing = function() { - var self = this, - $createRoomPromptButton = $('#firechat-btn-create-room-prompt'), - $createRoomButton = $('#firechat-btn-create-room'), - renderRoomList = function(event) { - var type = $(this).data('room-type'); - - self.sortListLexicographically('#firechat-room-list'); - }; - - // Handle click of the create new room prompt-button. - $createRoomPromptButton.bind('click', function(event) { - self.promptCreateRoom(); - return false; - }); - - // Handle click of the create new room button. - $createRoomButton.bind('click', function(event) { - var roomName = $('#firechat-input-room-name').val(); - $('#firechat-prompt-create-room').remove(); - self._chat.createRoom(roomName); - return false; - }); - }; - - - - /** - * A stripped-down version of bootstrap-tab.js. - * - * Original bootstrap-tab.js Copyright 2012 Twitter, Inc.,licensed under the Apache v2.0 - */ - FirechatUI.prototype._setupTabs = function() { - var self = this, - show = function($el) { - var $this = $el, - $ul = $this.closest('ul:not(.firechat-dropdown-menu)'), - selector = $this.attr('data-target'), - previous = $ul.find('.active:last a')[0], - $target, - e; - - if (!selector) { - selector = $this.attr('href'); - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, ''); - } - - if ($this.parent('li').hasClass('active')) return; - - e = $.Event('show', { relatedTarget: previous }); - - $this.trigger(e); - - if (e.isDefaultPrevented()) return; - - $target = $(selector); - - activate($this.parent('li'), $ul); - activate($target, $target.parent(), function () { - $this.trigger({ - type: 'shown', - relatedTarget: previous - }); - }); - }, - activate = function (element, container, callback) { - var $active = container.find('> .active'), - transition = callback && $.support.transition && $active.hasClass('fade'); - - function next() { - $active - .removeClass('active') - .find('> .firechat-dropdown-menu > .active') - .removeClass('active'); - - element.addClass('active'); - - if (transition) { - element.addClass('in'); - } else { - element.removeClass('fade'); - } - - if (element.parent('.firechat-dropdown-menu')) { - element.closest('li.firechat-dropdown').addClass('active'); - } - - if (callback) { - callback(); - } - } - - if (transition) { - $active.one($.support.transition.end, next); - } else { - next(); - } - - $active.removeClass('in'); - }; - - $(document).delegate('[data-toggle="firechat-tab"]', 'click', function(event) { - event.preventDefault(); - show($(this)); - }); - }; - - /** - * A stripped-down version of bootstrap-dropdown.js. - * - * Original bootstrap-dropdown.js Copyright 2012 Twitter, Inc., licensed under the Apache v2.0 - */ - FirechatUI.prototype._setupDropdowns = function() { - var self = this, - toggle = '[data-toggle=firechat-dropdown]', - toggleDropdown = function(event) { - var $this = $(this), - $parent = getParent($this), - isActive = $parent.hasClass('open'); - - if ($this.is('.disabled, :disabled')) return; - - clearMenus(); - - if (!isActive) { - $parent.toggleClass('open'); - } - - $this.focus(); - - return false; - }, - clearMenus = function() { - $('[data-toggle=firechat-dropdown]').each(function() { - getParent($(this)).removeClass('open'); - }); - }, - getParent = function($this) { - var selector = $this.attr('data-target'), - $parent; - - if (!selector) { - selector = $this.attr('href'); - selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, ''); - } - - $parent = selector && $(selector); - - if (!$parent || !$parent.length) $parent = $this.parent(); - - return $parent; - }; - - $(document) - .bind('click', clearMenus) - .delegate('.firechat-dropdown-menu', 'click', function(event) { event.stopPropagation(); }) - .delegate('[data-toggle=firechat-dropdown]', 'click', toggleDropdown); - }; - - /** - * Binds to any text input fields with data-provide='limit' and - * data-counter='', and upon value change updates the selector - * content to reflect the number of characters remaining, as the 'maxlength' - * attribute less the current value length. - */ - FirechatUI.prototype._bindTextInputFieldLimits = function() { - $('body').delegate('input[data-provide="limit"], textarea[data-provide="limit"]', 'keyup', function(event) { - var $this = $(this), - $target = $($this.data('counter')), - limit = $this.attr('maxlength'), - count = $this.val().length; - - $target.html(Math.max(0, limit - count)); - }); - }; - - /** - * Given a title and message content, show an alert prompt to the user. - * - * @param {string} title - * @param {string} message - */ - FirechatUI.prototype.renderAlertPrompt = function(title, message) { - var template = FirechatDefaultTemplates["templates/prompt-alert.html"], - $prompt = this.prompt(title, template({ message: message })); - - $prompt.find('.close').click(function() { - $prompt.remove(); - return false; - }); - return; - }; - - /** - * Toggle input field s if we want limit / unlimit input fields. - */ - FirechatUI.prototype.toggleInputs = function(isEnabled) { - $('#firechat-tab-content textarea').each(function() { - var $this = $(this); - if (isEnabled) { - $(this).val(''); - } else { - $(this).val('You have exceeded the message limit, please wait before sending.'); - } - $this.prop('disabled', !isEnabled); - }); - $('#firechat-input-name').prop('disabled', !isEnabled); - }; - - /** - * Given a room id and name, attach the tab to the interface and setup events. - * - * @param {string} roomId - * @param {string} roomName - */ - FirechatUI.prototype.attachTab = function(roomId, roomName) { - var self = this; - - // If this tab already exists, give it focus. - if (this.$messages[roomId]) { - this.focusTab(roomId); - return; - } - - var room = { - id: roomId, - name: roomName - }; - - // Populate and render the tab content template. - var tabTemplate = FirechatDefaultTemplates["templates/tab-content.html"]; - var $tabContent = $(tabTemplate(room)); - this.$tabContent.prepend($tabContent); - var $messages = $('#firechat-messages' + roomId); - - // Keep a reference to the message listing for later use. - this.$messages[roomId] = $messages; - - // Attach on-enter event to textarea. - var $textarea = $tabContent.find('textarea').first(); - $textarea.bind('keydown', function(e) { - var message = self.trimWithEllipsis($textarea.val(), self.maxLengthMessage); - if ((e.which === 13) && (message !== '')) { - $textarea.val(''); - self._chat.sendMessage(roomId, message); - return false; - } - }); - - // Populate and render the tab menu template. - var tabListTemplate = FirechatDefaultTemplates["templates/tab-menu-item.html"]; - var $tab = $(tabListTemplate(room)); - this.$tabList.prepend($tab); - - // Attach on-shown event to move tab to front and scroll to bottom. - $tab.bind('shown', function(event) { - $messages.scrollTop($messages[0].scrollHeight); - }); - - // Dynamically update the width of each tab based upon the number open. - var tabs = this.$tabList.children('li'); - var tabWidth = Math.floor($('#firechat-tab-list').width() / tabs.length); - this.$tabList.children('li').css('width', tabWidth); - - // Update the room listing to reflect that we're now in the room. - this.$roomList.children('[data-room-id=' + roomId + ']').children('a').addClass('highlight'); - - // Sort each item in the user list alphabetically on click of the dropdown. - $('#firechat-btn-room-user-list-' + roomId).bind('click', function() { - self.sortListLexicographically('#firechat-room-user-list-' + roomId); - return false; - }); - - // Automatically select the new tab. - this.focusTab(roomId); - }; - - /** - * Given a room id, focus the given tab. - * - * @param {string} roomId - */ - FirechatUI.prototype.focusTab = function(roomId) { - if (this.$messages[roomId]) { - var $tabLink = this.$tabList.find('[data-room-id=' + roomId + ']').find('a'); - if ($tabLink.length) { - $tabLink.first().trigger('click'); - } - } - }; - - /** - * Given a room id, remove the tab and all child elements from the interface. - * - * @param {string} roomId - */ - FirechatUI.prototype.removeTab = function(roomId) { - delete this.$messages[roomId]; - - // Remove the inner tab content. - this.$tabContent.find('[data-room-id=' + roomId + ']').remove(); - - // Remove the tab from the navigation menu. - this.$tabList.find('[data-room-id=' + roomId + ']').remove(); - - // Dynamically update the width of each tab based upon the number open. - var tabs = this.$tabList.children('li'); - var tabWidth = Math.floor($('#firechat-tab-list').width() / tabs.length); - this.$tabList.children('li').css('width', tabWidth); - - // Automatically select the next tab if there is one. - this.$tabList.find('[data-toggle="firechat-tab"]').first().trigger('click'); - - // Update the room listing to reflect that we're now in the room. - this.$roomList.children('[data-room-id=' + roomId + ']').children('a').removeClass('highlight'); - }; - - /** - * Render a new message in the specified chat room. - * - * @param {string} roomId - * @param {string} message - */ - FirechatUI.prototype.showMessage = function(roomId, rawMessage) { - var self = this; - - // Setup defaults - var message = { - id : rawMessage.id, - localtime : self.formatTime(rawMessage.timestamp), - message : rawMessage.message || '', - userId : rawMessage.userId, - name : rawMessage.name, - type : rawMessage.type || 'default', - isSelfMessage : (self._user && rawMessage.userId == self._user.id), - disableActions : (!self._user || rawMessage.userId == self._user.id) - }; - // While other data is escaped in the Underscore.js templates, escape and - // process the message content here to add additional functionality (add links). - // Also trim the message length to some client-defined maximum. - var messageConstructed = ''; - message.message = _.map(message.message.split(' '), function(token) { - if (self.urlPattern.test(token) || self.pseudoUrlPattern.test(token)) { - return self.linkify(encodeURI(token)); - } else { - return _.escape(token); - } - }).join(' '); - message.message = self.trimWithEllipsis(message.message, self.maxLengthMessage); - - // Populate and render the message template. - var template = FirechatDefaultTemplates["templates/message.html"]; - var $message = $(template(message)); - var $messages = self.$messages[roomId]; - if ($messages) { - - var scrollToBottom = false; - if ($messages.scrollTop() / ($messages[0].scrollHeight - $messages[0].offsetHeight) >= 0.95) { - // Pinned to bottom - scrollToBottom = true; - } else if ($messages[0].scrollHeight <= $messages.height()) { - // Haven't added the scrollbar yet - scrollToBottom = true; - } - - $messages.append($message); - - if (scrollToBottom) { - $messages.scrollTop($messages[0].scrollHeight); - } - } - }; - - /** - * Remove a message by id. - * - * @param {string} roomId - * @param {string} messageId - */ - FirechatUI.prototype.removeMessage = function(roomId, messageId) { - $('.message[data-message-id="' + messageId + '"]').remove(); - }; - - /** - * Given a selector for a list element, sort the items alphabetically. - * - * @param {string} selector - */ - FirechatUI.prototype.sortListLexicographically = function(selector) { - $(selector).children("li").sort(function(a, b) { - var upA = $(a).text().toUpperCase(); - var upB = $(b).text().toUpperCase(); - return (upA < upB) ? -1 : (upA > upB) ? 1 : 0; - }).appendTo(selector); - }; - - /** - * Remove leading and trailing whitespace from a string and shrink it, with - * added ellipsis, if it exceeds a specified length. - * - * @param {string} str - * @param {number} length - * @return {string} - */ - FirechatUI.prototype.trimWithEllipsis = function(str, length) { - str = str.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); - return (length && str.length <= length) ? str : str.substring(0, length) + '...'; - }; - - /** - * Given a timestamp, format it in the form hh:mm am/pm. Defaults to now - * if the timestamp is undefined. - * - * @param {Number} timestamp - * @param {string} date - */ - FirechatUI.prototype.formatTime = function(timestamp) { - var date = (timestamp) ? new Date(timestamp) : new Date(), - hours = date.getHours() || 12, - minutes = '' + date.getMinutes(), - ampm = (date.getHours() >= 12) ? 'pm' : 'am'; - - hours = (hours > 12) ? hours - 12 : hours; - minutes = (minutes.length < 2) ? '0' + minutes : minutes; - return '' + hours + ':' + minutes + ampm; - }; - - /** - * Launch a prompt to allow the user to create a new room. - */ - FirechatUI.prototype.promptCreateRoom = function() { - var self = this; - var template = FirechatDefaultTemplates["templates/prompt-create-room.html"]; - - var $prompt = this.prompt('Create Public Room', template({ - maxLengthRoomName: this.maxLengthRoomName, - isModerator: self._chat.userIsModerator() - })); - $prompt.find('a.close').first().click(function() { - $prompt.remove(); - return false; - }); - - - $prompt.find('[data-toggle=submit]').first().click(function() { - var name = $prompt.find('[data-input=firechat-room-name]').first().val(); - if (name !== '') { - self._chat.createRoom(name, 'public'); - $prompt.remove(); - } - return false; - }); - - $prompt.find('[data-input=firechat-room-name]').first().focus(); - $prompt.find('[data-input=firechat-room-name]').first().bind('keydown', function(e) { - if (e.which === 13) { - var name = $prompt.find('[data-input=firechat-room-name]').first().val(); - if (name !== '') { - self._chat.createRoom(name, 'public'); - $prompt.remove(); - return false; - } - } - }); - }; - - /** - * Inner method to launch a prompt given a specific title and HTML content. - * @param {string} title - * @param {string} content - */ - FirechatUI.prototype.prompt = function(title, content) { - var template = FirechatDefaultTemplates["templates/prompt.html"], - $prompt; - - $prompt = $(template({ - title: title, - content: content - })).css({ - top: this.$wrapper.position().top + (0.333 * this.$wrapper.height()), - left: this.$wrapper.position().left + (0.125 * this.$wrapper.width()), - width: 0.75 * this.$wrapper.width() - }); - this.$wrapper.append($prompt.removeClass('hidden')); - return $prompt; - }; - - // see http://stackoverflow.com/questions/37684/how-to-replace-plain-urls-with-links - FirechatUI.prototype.linkify = function(str) { - var self = this; - return str - .replace(self.urlPattern, '$&') - .replace(self.pseudoUrlPattern, '$1$2'); - }; - -})(jQuery); - -var spinner = new Spinner({ - color: '#ddd' -}); -var firebaseRef = 'https://brilliant-fire-2797.firebaseio.com'; - -function handleFileSelect(evt) { - var f = evt.target.files[0]; - var reader = new FileReader(); - reader.onload = (function(theFile) { - return function(e) { - var filePayload = e.target.result; - // Generate a location that can't be guessed using the file's contents and a random number - var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); - var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); - spinner.spin(document.getElementById('spin')); - // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview - f.set(filePayload, function() { - spinner.stop(); - console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created') - }); - }; - })(f); - reader.readAsDataURL(f); -} -/* -CryptoJS v3.0.2 -code.google.com/p/crypto-js -(c) 2009-2012 by Jeff Mott. All rights reserved. -code.google.com/p/crypto-js/wiki/License -*/ -var CryptoJS=CryptoJS||function(i,p){var f={},q=f.lib={},j=q.Base=function(){function a(){}return{extend:function(h){a.prototype=this;var d=new a;h&&d.mixIn(h);d.$super=this;return d},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var d in a)a.hasOwnProperty(d)&&(this[d]=a[d]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.$super.extend(this)}}}(),k=q.WordArray=j.extend({init:function(a,h){a= -this.words=a||[];this.sigBytes=h!=p?h:4*a.length},toString:function(a){return(a||m).stringify(this)},concat:function(a){var h=this.words,d=a.words,c=this.sigBytes,a=a.sigBytes;this.clamp();if(c%4)for(var b=0;b>>2]|=(d[b>>>2]>>>24-8*(b%4)&255)<<24-8*((c+b)%4);else if(65535>>2]=d[b>>>2];else h.push.apply(h,d);this.sigBytes+=a;return this},clamp:function(){var a=this.words,b=this.sigBytes;a[b>>>2]&=4294967295<<32-8*(b%4);a.length=i.ceil(b/4)},clone:function(){var a= -j.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var b=[],d=0;d>>2]>>>24-8*(c%4)&255;d.push((e>>>4).toString(16));d.push((e&15).toString(16))}return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c>>3]|=parseInt(a.substr(c,2),16)<<24-4*(c%8);return k.create(d,b/2)}},s=r.Latin1={stringify:function(a){for(var b= -a.words,a=a.sigBytes,d=[],c=0;c>>2]>>>24-8*(c%4)&255));return d.join("")},parse:function(a){for(var b=a.length,d=[],c=0;c>>2]|=(a.charCodeAt(c)&255)<<24-8*(c%4);return k.create(d,b)}},g=r.Utf8={stringify:function(a){try{return decodeURIComponent(escape(s.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data");}},parse:function(a){return s.parse(unescape(encodeURIComponent(a)))}},b=q.BufferedBlockAlgorithm=j.extend({reset:function(){this._data=k.create(); -this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=g.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var b=this._data,d=b.words,c=b.sigBytes,e=this.blockSize,f=c/(4*e),f=a?i.ceil(f):i.max((f|0)-this._minBufferSize,0),a=f*e,c=i.min(4*a,c);if(a){for(var g=0;ge;)f(b)&&(8>e&&(k[e]=g(i.pow(b,0.5))),r[e]=g(i.pow(b,1/3)),e++),b++})();var m=[],j=j.SHA256=f.extend({_doReset:function(){this._hash=q.create(k.slice(0))},_doProcessBlock:function(f,g){for(var b=this._hash.words,e=b[0],a=b[1],h=b[2],d=b[3],c=b[4],i=b[5],j=b[6],k=b[7],l=0;64> -l;l++){if(16>l)m[l]=f[g+l]|0;else{var n=m[l-15],o=m[l-2];m[l]=((n<<25|n>>>7)^(n<<14|n>>>18)^n>>>3)+m[l-7]+((o<<15|o>>>17)^(o<<13|o>>>19)^o>>>10)+m[l-16]}n=k+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&i^~c&j)+r[l]+m[l];o=((e<<30|e>>>2)^(e<<19|e>>>13)^(e<<10|e>>>22))+(e&a^e&h^a&h);k=j;j=i;i=c;c=d+n|0;d=h;h=a;a=e;e=n+o|0}b[0]=b[0]+e|0;b[1]=b[1]+a|0;b[2]=b[2]+h|0;b[3]=b[3]+d|0;b[4]=b[4]+c|0;b[5]=b[5]+i|0;b[6]=b[6]+j|0;b[7]=b[7]+k|0},_doFinalize:function(){var f=this._data,g=f.words,b=8*this._nDataBytes, -e=8*f.sigBytes;g[e>>>5]|=128<<24-e%32;g[(e+64>>>9<<4)+15]=b;f.sigBytes=4*g.length;this._process()}});p.SHA256=f._createHelper(j);p.HmacSHA256=f._createHmacHelper(j)})(Math); diff --git a/dist/firechat.min.css b/dist/firechat.min.css deleted file mode 100644 index 15bd92d..0000000 --- a/dist/firechat.min.css +++ /dev/null @@ -1 +0,0 @@ -@charset "UTF-8";#firechat div,#firechat span,#firechat applet,#firechat object,#firechat iframe,#firechat h1,#firechat h2,#firechat h3,#firechat h4,#firechat h5,#firechat h6,#firechat p,#firechat blockquote,#firechat pre,#firechat a,#firechat abbr,#firechat acronym,#firechat address,#firechat big,#firechat cite,#firechat code,#firechat del,#firechat dfn,#firechat em,#firechat img,#firechat ins,#firechat kbd,#firechat q,#firechat s,#firechat samp,#firechat small,#firechat strike,#firechat strong,#firechat sub,#firechat sup,#firechat tt,#firechat var,#firechat b,#firechat u,#firechat i,#firechat center,#firechat dl,#firechat dt,#firechat dd,#firechat ol,#firechat ul,#firechat li,#firechat fieldset,#firechat form,#firechat label,#firechat legend,#firechat table,#firechat caption,#firechat tbody,#firechat tfoot,#firechat thead,#firechat tr,#firechat th,#firechat td,#firechat article,#firechat aside,#firechat canvas,#firechat details,#firechat embed,#firechat figure,#firechat figcaption,#firechat footer,#firechat header,#firechat hgroup,#firechat menu,#firechat nav,#firechat output,#firechat ruby,#firechat section,#firechat summary,#firechat time,#firechat mark,#firechat audio,#firechat video{border:0;font-size:12px;font-family:arial,helvetica,sans-serif;vertical-align:baseline;margin:0;padding:0}#firechat article,#firechat aside,#firechat details,#firechat figcaption,#firechat figure,#firechat footer,#firechat header,#firechat hgroup,#firechat menu,#firechat nav,#firechat section{display:block}#firechat body{line-height:1}#firechat ol,#firechat ul{list-style:none}#firechat blockquote,#firechat q{quotes:none}#firechat blockquote:before,#firechat blockquote:after,#firechat q:before,#firechat q:after{content:none}#firechat table{border-collapse:collapse;border-spacing:0}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0}.clearfix:after{clear:both}#firechat{color:#333;text-align:left}#firechat .center{float:none!important;margin-left:auto!important;margin-right:auto!important}#firechat .left{float:left!important}#firechat .right{float:right!important}#firechat .alignleft{text-align:left!important}#firechat .alignright{text-align:right!important}#firechat .aligncenter{text-align:center!important}#firechat .hidden{display:none!important}#firechat .row{clear:both}#firechat .fifth,#firechat .fivesixth,#firechat .fourfifth,#firechat .half,#firechat .ninetenth,#firechat .quarter,#firechat .sevententh,#firechat .sixth,#firechat .tenth,#firechat .third,#firechat .threefifth,#firechat .threequarter,#firechat .threetenth,#firechat .twofifth,#firechat .twothird,#firechat .full{margin-left:2.127659574468085%;float:left;min-height:1px}#firechat .fifth:first-child,#firechat .fivesixth:first-child,#firechat .fourfifth:first-child,#firechat .half:first-child,#firechat .ninetenth:first-child,#firechat .quarter:first-child,#firechat .sevententh:first-child,#firechat .sixth:first-child,#firechat .tenth:first-child,#firechat .third:first-child,#firechat .threefifth:first-child,#firechat .threequarter:first-child,#firechat .threetenth:first-child,#firechat .twofifth:first-child,#firechat .twothird:first-child,#firechat .full:first-child{margin-left:0}#firechat .tenth{width:8.08510638297872%}#firechat .sixth{width:14.893617021276595%}#firechat .fifth{width:18.297872340425535%}#firechat .quarter{width:23.404255319148938%}#firechat .threetenth{width:26.3829787235%}#firechat .third{width:31.914893617021278%}#firechat .twofifth{width:38.72340425531915%}#firechat .half{width:48.93617021276596%}#firechat .sevententh{width:58.7234042555%}#firechat .threefifth{width:59.14893617021278%}#firechat .twothird{width:65.95744680851064%}#firechat .threequarter{width:74.46808510638297%}#firechat .ninetenth{width:74.8936170215%}#firechat .fourfifth{width:79.57446808510639%}#firechat .fivesixth{width:82.9787234042553%}#firechat .full{width:100%}#firechat .clipped{overflow:hidden}#firechat strong{font-weight:bold}#firechat em{font-style:italic}#firechat label{display:block}#firechat a{color:#005580}#firechat a:visited,#firechat a:hover,#firechat a:active{color:#005580}#firechat p{margin:10px 0}#firechat h1,#firechat h2,#firechat h3,#firechat h4,#firechat h5,#firechat h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit}#firechat h1,#firechat h2,#firechat h3{line-height:40px}#firechat h1{font-size:38.5px}#firechat h2{font-size:31.5px}#firechat h3{font-size:24.5px}#firechat h4{font-size:17.5px}#firechat h5{font-size:14px}#firechat h6{font-size:11.9px}#firechat small{font-size:90%}#firechat .nav{list-style:none}#firechat .nav>li>a{display:block;background-color:#eee;text-decoration:none;overflow:hidden;white-space:nowrap}#firechat .nav>li>a:hover,#firechat .nav>li>a:focus{background-color:#fff}#firechat .nav-tabs{border-bottom:1px solid #ddd;clear:both}#firechat .nav-tabs>li{float:left;margin-bottom:-1px;max-width:45%}#firechat .nav-tabs>li>a{-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px;padding:4px 8px;margin-right:2px;line-height:20px;border:1px solid transparent;border-color:#ccc}#firechat .nav-tabs>.active>a,#firechat .nav-tabs>.active>a:hover,#firechat .nav-tabs>.active>a:focus{border-bottom-color:transparent;background-color:#fff;cursor:default}#firechat .tab-content{overflow:auto}#firechat .tab-content>.tab-pane{display:none}#firechat .tab-content>.active{display:block;background-color:#fff}#firechat .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";margin-top:8px;margin-left:2px}#firechat .firechat-dropdown{position:relative}#firechat .firechat-dropdown-toggle{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none}#firechat .firechat-dropdown-toggle:focus,#firechat .firechat-dropdown-toggle:active{outline:0;text-decoration:none}#firechat .firechat-dropdown-toggle.btn{padding:4px 0 0;height:22px}#firechat .firechat-dropdown-menu{*zoom:1;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0;z-index:1000;display:none;float:left;position:absolute;top:100%;left:0;width:100%;background-color:#fff;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;min-width:98%;padding:0;margin:-1px 0 0}#firechat .firechat-dropdown-menu:before,#firechat .firechat-dropdown-menu:after{display:table;content:"";line-height:0}#firechat .firechat-dropdown-menu:after{clear:both}#firechat .firechat-dropdown-menu ul{background-color:#fff;list-style:none;overflow-y:scroll;max-height:300px}#firechat .firechat-dropdown-menu ul>li>a{display:block;padding:1px 1px 1px 3px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}#firechat .firechat-dropdown-menu ul>li>a.highlight{background-color:#d9edf7}#firechat .firechat-dropdown-menu ul>li>a:hover,#firechat .firechat-dropdown-menu ul>li>a:focus,#firechat .firechat-dropdown-menu ul>.active>a,#firechat .firechat-dropdown-menu ul>.active>a:hover,#firechat .firechat-dropdown-menu ul>.active>a:focus{text-decoration:none;color:#000;background-color:#d9edf7;outline:0}#firechat .firechat-dropdown-menu ul>.disabled>a,#firechat .firechat-dropdown-menu ul>.disabled>a:hover,#firechat .firechat-dropdown-menu ul>.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;background-image:none;cursor:default}#firechat .firechat-dropdown-header{position:relative;width:100%;padding:10px 0;background-color:#eee;border-bottom:1px solid #ccc}#firechat .firechat-dropdown-footer{position:relative;width:100%;padding:10px 0;background-color:#eee;border-top:1px solid #ccc;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#firechat .open{*z-index:1000}#firechat .open>.firechat-dropdown-menu{display:block;border:1px solid #ccc;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0}#firechat .open>.firechat-dropdown-toggle{outline:0;text-decoration:none;-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px}#firechat .prompt-wrapper{position:absolute;z-index:1000}#firechat .prompt{position:absolute;z-index:1001;background-color:#fff;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.45);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.45);box-shadow:0 5px 10px rgba(0,0,0,0.45)}#firechat .prompt-header{padding:4px 8px;font-weight:bold;background-color:#eee;border:1px solid #ccc;-webkit-border-top-right-radius:4px;-webkit-border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:0;-moz-border-radius-bottomleft:0;-moz-border-radius-topleft:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;border-top-left-radius:4px}#firechat .prompt-header a.close{opacity:.6;font-size:13px;margin-top:2px}#firechat .prompt-header a.close:hover{opacity:.9}#firechat .prompt-body{background-color:#fff;padding:4px 8px;border-left:1px solid #ccc;border-right:1px solid #ccc}#firechat .prompt-footer{padding:4px 8px;background-color:#eee;border:1px solid #ccc;-webkit-border-top-right-radius:0;-webkit-border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-webkit-border-top-left-radius:0;-moz-border-radius-topright:0;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;border-top-left-radius:0}#firechat .prompt-background{background-color:#333;border:1px solid #333;opacity:.8;z-index:1000;height:100%;width:100%}#firechat .btn{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;height:24px;display:inline-block;*display:inline;*zoom:1;padding:2px 5px;margin-bottom:0;text-align:center;vertical-align:middle;cursor:pointer;color:#333;font-size:12px;text-shadow:0 1px 1px rgba(255,255,255,0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border:1px solid #ccc;*border:0;border-bottom-color:#b3b3b3;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}#firechat .btn:hover,#firechat .btn:focus,#firechat .btn:active,#firechat .btn.active,#firechat .btn.disabled,#firechat .btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9;outline:0}#firechat .btn:active,#firechat .btn.active{background-color:#ccc}#firechat .btn:first-child{*margin-left:0}#firechat .btn:hover,#firechat .btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}#firechat .btn.active,#firechat .btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}#firechat .btn.disabled,#firechat .btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65)}#firechat .btn.disabled:active,#firechat .btn[disabled]:active{-webkit-box-shadow:inherit;-moz-box-shadow:inherit;box-shadow:inherit;background-color:#e6e6e6}#firechat .contextmenu{position:fixed;z-index:1001;min-width:150px;border:1px solid #ccc;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}#firechat .contextmenu ul{background-color:#fff;list-style:none}#firechat .contextmenu ul>li>a{display:block;padding:3px 10px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}#firechat .contextmenu ul>li>a.highlight{background-color:#d9edf7}#firechat .contextmenu ul>li>a:hover,#firechat .contextmenu ul>li>a:focus{text-decoration:none;color:#fff;background-color:#0081c2;outline:0}#firechat{padding:0;font-family:sans-serif;font-size:12px;line-height:18px}#firechat input,#firechat textarea{width:100%;font-family:sans-serif;font-size:12px;line-height:18px;padding:2px 5px;border:1px solid #ccc;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#firechat input:-moz-placeholder,#firechat textarea:-moz-placeholder{color:#aaa}#firechat input:-ms-input-placeholder,#firechat textarea:-ms-input-placeholder{color:#aaa}#firechat input::-webkit-input-placeholder,#firechat textarea::-webkit-input-placeholder{color:#aaa}#firechat input[disabled],#firechat textarea[disabled]{background-color:#eee}#firechat input{height:24px}#firechat textarea{resize:none;height:40px}#firechat .search-wrapper{-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;border:1px solid #ccc;margin:0 5px;padding:2px 5px;background:#fff}#firechat .search-wrapper>input[type=text]{padding-left:0;border:0}#firechat .search-wrapper>input[type=text]:focus,#firechat .search-wrapper>input[type=text]:active{outline:0}#firechat .chat{overflow:auto;-ms-overflow-x:hidden;overflow-x:hidden;height:290px;position:relative;margin-bottom:5px;border:1px solid #ccc;border-top:0;overflow-y:scroll}#firechat .chat textarea{overflow:auto;vertical-align:top}#firechat #textarea-container{position:relative;width:100%;float:left;height:35px}#firechat #uploaded-image{display:none}#firechat #upload-icon{position:absolute;float:right;height:16px;width:18px;bottom:0;right:5px}#firechat #file-upload{display:none;position:relative;overflow:hidden;z-index:2;opacity:0}#firechat .message{color:#333;padding:3px 5px;border-bottom:1px solid #ccc}#firechat .message.highlighted{background-color:#d9edf7}#firechat .message .name{font-weight:bold;overflow-x:hidden}#firechat .message.message-self{color:#2675ab}#firechat .message:nth-child(odd){background-color:#f9f9f9}#firechat .message:nth-child(odd).highlighted{background-color:#d9edf7}#firechat .message:nth-child(odd).message-local{background-color:#effafc}#firechat .message-content{word-wrap:break-word;padding-right:45px}#firechat .message-content.red{color:red}#firechat .message.message-notification .message-content{font-style:italic}#firechat ul::-webkit-scrollbar{-webkit-appearance:none;width:7px}#firechat ul::-webkit-scrollbar-thumb{border-radius:4px;-webkit-box-shadow:0 0 1px rgba(255,255,255,0.5)}#firechat #firechat-header{padding:6px 0 0 0;height:40px}#firechat #firechat-tabs{height:435px}#firechat #firechat-tab-list{background-color:#fff}#firechat #firechat-tab-content{width:100%;background-color:#fff}#firechat .tab-pane-menu{border:1px solid #ccc;border-top:0;vertical-align:middle;padding-bottom:5px}#firechat .tab-pane-menu .firechat-dropdown{margin:5px 0 0 5px}#firechat .tab-pane-menu>.icon{margin:5px 2px 0}#firechat .icon{display:inline-block;*margin-right:.3em;line-height:20px;vertical-align:middle;background-repeat:no-repeat;padding:0;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAL8AAAANEAYAAACoeGM7AAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAM80lEQVR42t2cZ4xWRRfHZ3dhwbK7CJZYYiOxV+wlUQzCKmBBsWPvYjQiaiyxYUwULLErltgrNpRF4q5iV0BRLFE0diUi7LIq6Pqw74f//rzO4Zm9d+5z9c37ni//3OfemXtm5sypc58q55xzrrpauHSpcOONheedJ9x9d2Hv3sLvvxfefbfw5puFf/5Zvr+8VFUl7Ozs/rkNNxTef79w222F77wjPOoo4ccfF/O+UDvGzTVEf8wH1zU1wlJJePTRwv33Fx57rPDnn/1+wbzzG+IXvrhmPUPzY/kJEc/HzqslK1fLLy8cMUK4667CFVYQ/vqr8PXXhU884f8eL6eXXKJ2wqSd3tDY2KOHc84NGqSRnnCC7tbVCdvbhRMnasWnTdt5Z+eca2pK6797Yh6ef1641lrCPfYQfv21UNwl62qv115b2Nws/PZb4d57C3/7LftalaOQ/C63nPCII4Tsg6228scHffqp8LHHhPfe6/8eu49feEH44YfCq64S/v67cMGC7tuvu65w6FDhllsKkS/0zoQJaZzMmSO+JaEzZmgkY8b88Ydzzs2b19HhnHNffSWJ6tVLM1cq/fKLrjXiUaPUrn9/XZ9yip6rqVmyxDnnnnrKvPbAA4V6TTJxP/zgT4zdyC+9JOzXz++PgceSVSS1tUJtE+c22si/f+21Pj9Wwd54o//8ZpsJd9xR2KtX9+8vmkLzcsABPt9z5wr32af88xiOf4oaGoSHH17M+/LKg203aJDwiy+EVh5DyHzuuWcxfDn31lvOOffMM7Nn6z1SsZ2dn30m/OQT4eefC7/8UvjBB0LaVzav7D873vfeE6LQISvv3Of50P6OJetgWFp5ZeFzz5V/b1bEEd1333x80g+O4mWXCXEQMDB33CG8/XYhBhuDmMZnOn30kZ5/+23nnGtpefNN55wbP96Xl/nzhYsWCdvauEbeQP1Of6US/XRZfDz8Bx8U9uwpPPFE4eOPC/EMVl9dOG6ccORI4Q03CA87LHbA5RcCwgO47TbhokXCYcOERCKQ7GJiMLiPokeQ2QCjRwtvukkY6zHg0V10kXDAAH++EIz77hM++aRwxRWFq64q3H57v9/+/YVPPy2cOFF47rnCNE8kll/Gi4eIAWU9v/vOnz8MA4qjb18hG51+2JiLF+ebX/hA4U+b5t+/7jrhAw8IkQ88WvnPiZzi4Q0eXL6/dEJhawaGDydmk4uEQmhu1kj79tVImb8RI8TZwIG0p78ddnAubOhDhIcPIXd4nnh4OHYYzPXXF7K/ed5GBLb/NLKRFOtMfyCZAiIKns8aSVp9xP4i8nv//Ti+icjgl0iDeUsjpKDSyJYeqqs1A+3taDBpkn79Qi5YW9vf5wXq0YP+1L5U6loAUjpW4WPhQhN00EFC2SXnDj1UiAF44w2hTWnEEqkcCIWJYkShQNbDIIJZZx2h9Xhs/7EpFDwCNs6UKf584tGQsiFCGTJEuMEG/jxBzBe/H3+8cJddhBiAZ58thl/eM2uW8MgjhWyAyy8XojhRUGuuKayvF7Jhf/pJ+O67wltvFU6dGscv78fTgg45RPjII+XbYZA23bT8/Vtu8ecBDy9MpHS0EROFr1B76lQp7r32su20EwYMkGSOG4dq4I0a4fDh9G9TQN0TKR0iB8aD3G+9tRDHDoPPenKf53GYiABiPWm7f046SUgKDs8aQwxlVfiQTVXh0BChxir+kDol5WPv24im+Ahcb6iu9jVnR4euGX9oXsLj7GKYHP68eUI8ANsRA7WKE8sNkUopdvgJsW0QUBbc3oewl6GQs9LUDgr85JOF5OZHjRKyESZNEp55ppBIC7IbxgoSkQzt2OgXX1wMv9RCFBAuG4HgSREKU0vB42Jjo6gxtPvtJ8TzTM91+kQOf731hHj4KHybA0bRK8B1bpNNhAqkE8OH40CKLZ3I4a+0kq6l8JuapPAbGx991Lm/r5s8+aFDlWOdOVMuS0ODNm5bm1RWSwsSrJY2FZVGRFYYYgwt+wO5EpeJ4eaa+zxPexQ+/Wcl+iFCxeBvs43QRujW048lu09Y16KI/m3Ewu8h/VS55w/5b7AGMrbW5lyXImQh8EhtqGBDGOu525QDnm5RhOcBzZ8vfO01IYIaev/Mmf5zpALsfSiv5bYLfeqpQhSUrYHY92GYbD+shx0XKSOKlrFk1xHFTQRon7M1FNtepaOErwsvFBIqkzKKlQ8MDoTnCpFKwyCi2FZbTYhDgydO6gfaaaesnFC0xQcUUQwlBi6VpPCHDJGKmDyZGWMldY2nPmmSP5NEdlkJRYSCZr7FRbiIzTX3eZ72tiiclZjf444rzyd6hkid9+fNCNhxvfJKvn5C/YVy9nZVYw89ZCdfI6TVEuCLCI4Zhp+Ojq6FIAdLFR0PjpQOFpyFsQMidw5ZxRo7ATaEI6fMgFD8FJsxXCgee00qSiWPJNfKaYLp08u/P1YQ4ZfxWgWDAcOjZmMR8G+3nZBTPbwffhYuFJ5zjhCPKi9ZBUzkh8dpBTkk2KSKLr1UiAIJEYYhK2GQIOto4OGj8NdYQ4hck8tnvkmtQSGDHKK6On8nUNtIPHwUvp05SeSwYTI1s2YpJhk5kliO/uP4Qe6IxMnhk9JhXqyCtQ4Oz9Oe/nwzl05EtJbI5fMeTs8QscIP+zwtEuA+csz+fvjhOH5tf6SSoZCjEipeKw5MVj12PemZ9tXVvunt2dOuHE+K06oqvbG2lp2ikS1ZIknv3burO45lXn+9kKItOfzQwhO6jR0r5PiXPaUQmzNHkMllIyhMMBudmgKnjqxnwnSssooQhWpTLOR6UVwc/4ul1lYhx7rwRBF4PBEEwxLFavhkeTmmN2aMEAG3ghdrqHx149z555efx9DGY37vvFNoPcxQe1v0SyObe8cRIYf/4otCPHwUPsVge4yXWgTEumWl9nZtsPp6irbk8OVyTJ5sYyRJdGOjkitJjUP3FyzwNzIOV1ZivdinFG3J4dt5twqW9eJ5nUFKDIB1xNIIh8p6oijUa64RcnyT2SLSJHWXdtqKcdD/BRcIifBiCf44TIGe2WILYaiGhWHFoaFGxnxtvnlWDvwZY/yLF6toy+8LF2rGamrESXK8WRIwe7YcjKYmzdD06Xpi7lzFWqR4/1pYeywMT5ncL4rpiiuE9tgnIRyeozP9ZyVSBNZyskHxpFFUCGroOCf36Zf28MtzRCqxOXPaM24iJxsJQQgOCgyiqM4GJvduKZRbjOWXXH+fPkKKiUQmOnyYRBrwZeeXCIxxQ/mPSfpEkZn3KZO+7PHiH38U2mKurQHY478ooHSSaZswgWOZum5uFra2iqPOTs0g93EE4NzWAKZM4RioIoDx4/PNE4YQxWNTs6HUgL1Pe3sMNCuF9qOVG2penIPHYOHokcJ8+WVhS4sQR4NaJP3F7luI9tSALBFxovhBW6uonFSORm7mzMEAzJjhnHMNDdLI9fXgq68651xdnZLYffpY+cpIhLzkUNNySd98I7QKFPs0cGC+4dv3sCAYIE4bhXJboWvwrruExxwjJPWStyjD8/b0AyEiCt4Wh6xBpCi+225CG5kUdWogxC/HMyldshGJ7IhcWIfTTxciLxhWqKgcJxuPc/h2nTAAaYrq4IP9dni01jCEiVM3nIdWdaizUxuTDdvaSgQQ6kfPNTVhKPgOgP7j5id0Dh9DbR05Unlch54PfQeQRuyrUM7ZOoxkCq6+WkikhiOBIQ/JEx7sGWfE8QlZOYKyOi7sS+uQgdn3ra/4LT/ZSS1razEEfBgoOf0rdRUaIB4rXyCedpqQFAu5KzxdPyBJPPRlj7d1Tw89JLznHiGeb+hDFVIWIQPll9SS3ynKUUwj5RWbI6Q/inWVEgJsUxRFKdKi+T3rLKEtshf9IZytPdgIgNM75PA5dWQ9fBAFE0+cu+dDGQyAHwGMHi0P/sordT12LB4+Ct//0Cbvh1zWINr9gAePIYe4thGCbU//sYRHn/fDLBwyawhDOfe8ESbvCx3/zHuKJp5Cil8cVlVlxcjXhv5yICvh4aPwreDlJY5nUay1Cj2rINn2lD4qPX6KwcPzRQHhKeP5WeQ+ng2nSyhCcv4fKip1EuIXRQlfXIMUn7nPl9SkhKhFFM2v7QcDEIoAQoiHbxV+5V/uEgGQAuJLXRQ7X/KS0sHD///8cpcIl/P69MN3GDh2RBzUvvjLFVI2NuK1einty+CsZDMY/z0qyuOvkGwIY8+zMuE2ZYGHj8JHUWQlm/sm1ENRZ81dWrShLEVAy1/20F9EEZrTQnk9HJCNYL+YLMrD+F/jF7IbnBQQNQDOi/MFJ9fk8O26xisMQmb7OykaagD+p/RLl3JNDj+U0gn13z0xLhQ0BtEqfLtP7TXP057+YvcDCpvDInwvYInUcnIqqjLKK2/IydlnF8NHfvq3FP9/ANgTCJ9z9ZF7AAAAAElFTkSuQmCC) no-repeat top left;opacity:.3;font-size:22px;font-family:Arial;font-weight:bold;overflow:hidden}#firechat .icon.plus{margin-top:0;vertical-align:top;background:transparent}#firechat .icon.search{background-position:0 0;width:13px;height:13px}#firechat .icon.close{background-position:-120px 0;width:13px;height:13px}#firechat .icon.user-chat{background-position:-138px 0;width:17px;height:13px}#firechat .icon.user-group{background-position:-18px 0;width:17px;height:13px}#firechat .icon.user-mute{background-position:-84px 0;width:13px;height:13px}#firechat .icon.user-mute.red{background-position:-102px 0;width:13px;height:13px}#firechat .icon:hover,#firechat .btn:hover>.icon{opacity:.6}#firechat a>.icon{margin:3px 1px} \ No newline at end of file diff --git a/dist/firechat.min.js b/dist/firechat.min.js deleted file mode 100644 index 485a664..0000000 --- a/dist/firechat.min.js +++ /dev/null @@ -1,3 +0,0 @@ -function handleFileSelect(a){var b=a.target.files[0],c=new FileReader;c.onload=function(a){return function(a){var b=a.target.result,c=CryptoJS.SHA256(Math.random()+CryptoJS.SHA256(b)),d=new Firebase(firebaseRef+"pano/"+c+"/filePayload");spinner.spin(document.getElementById("spin")),d.set(b,function(){spinner.stop(),console.log("File with hash: "+firebaseRef+"pano/"+c+"/filePayload created")})}}(b),c.readAsDataURL(b)}(function(){var a=this,b=a._,c=Array.prototype,d=Object.prototype,e=Function.prototype,f=c.push,g=c.slice,h=c.concat,i=d.toString,j=d.hasOwnProperty,k=Array.isArray,l=Object.keys,m=e.bind,n=function(a){return a instanceof n?a:this instanceof n?void(this._wrapped=a):new n(a)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=n),exports._=n):a._=n,n.VERSION="1.7.0";var o=function(a,b,c){if(void 0===b)return a;switch(null==c?3:c){case 1:return function(c){return a.call(b,c)};case 2:return function(c,d){return a.call(b,c,d)};case 3:return function(c,d,e){return a.call(b,c,d,e)};case 4:return function(c,d,e,f){return a.call(b,c,d,e,f)}}return function(){return a.apply(b,arguments)}};n.iteratee=function(a,b,c){return null==a?n.identity:n.isFunction(a)?o(a,b,c):n.isObject(a)?n.matches(a):n.property(a)},n.each=n.forEach=function(a,b,c){if(null==a)return a;b=o(b,c);var d,e=a.length;if(e===+e)for(d=0;e>d;d++)b(a[d],d,a);else{var f=n.keys(a);for(d=0,e=f.length;e>d;d++)b(a[f[d]],f[d],a)}return a},n.map=n.collect=function(a,b,c){if(null==a)return[];b=n.iteratee(b,c);for(var d,e=a.length!==+a.length&&n.keys(a),f=(e||a).length,g=Array(f),h=0;f>h;h++)d=e?e[h]:h,g[h]=b(a[d],d,a);return g};var p="Reduce of empty array with no initial value";n.reduce=n.foldl=n.inject=function(a,b,c,d){null==a&&(a=[]),b=o(b,d,4);var e,f=a.length!==+a.length&&n.keys(a),g=(f||a).length,h=0;if(arguments.length<3){if(!g)throw new TypeError(p);c=a[f?f[h++]:h++]}for(;g>h;h++)e=f?f[h]:h,c=b(c,a[e],e,a);return c},n.reduceRight=n.foldr=function(a,b,c,d){null==a&&(a=[]),b=o(b,d,4);var e,f=a.length!==+a.length&&n.keys(a),g=(f||a).length;if(arguments.length<3){if(!g)throw new TypeError(p);c=a[f?f[--g]:--g]}for(;g--;)e=f?f[g]:g,c=b(c,a[e],e,a);return c},n.find=n.detect=function(a,b,c){var d;return b=n.iteratee(b,c),n.some(a,function(a,c,e){return b(a,c,e)?(d=a,!0):void 0}),d},n.filter=n.select=function(a,b,c){var d=[];return null==a?d:(b=n.iteratee(b,c),n.each(a,function(a,c,e){b(a,c,e)&&d.push(a)}),d)},n.reject=function(a,b,c){return n.filter(a,n.negate(n.iteratee(b)),c)},n.every=n.all=function(a,b,c){if(null==a)return!0;b=n.iteratee(b,c);var d,e,f=a.length!==+a.length&&n.keys(a),g=(f||a).length;for(d=0;g>d;d++)if(e=f?f[d]:d,!b(a[e],e,a))return!1;return!0},n.some=n.any=function(a,b,c){if(null==a)return!1;b=n.iteratee(b,c);var d,e,f=a.length!==+a.length&&n.keys(a),g=(f||a).length;for(d=0;g>d;d++)if(e=f?f[d]:d,b(a[e],e,a))return!0;return!1},n.contains=n.include=function(a,b){return null==a?!1:(a.length!==+a.length&&(a=n.values(a)),n.indexOf(a,b)>=0)},n.invoke=function(a,b){var c=g.call(arguments,2),d=n.isFunction(b);return n.map(a,function(a){return(d?b:a[b]).apply(a,c)})},n.pluck=function(a,b){return n.map(a,n.property(b))},n.where=function(a,b){return n.filter(a,n.matches(b))},n.findWhere=function(a,b){return n.find(a,n.matches(b))},n.max=function(a,b,c){var d,e,f=-1/0,g=-1/0;if(null==b&&null!=a){a=a.length===+a.length?a:n.values(a);for(var h=0,i=a.length;i>h;h++)d=a[h],d>f&&(f=d)}else b=n.iteratee(b,c),n.each(a,function(a,c,d){e=b(a,c,d),(e>g||e===-1/0&&f===-1/0)&&(f=a,g=e)});return f},n.min=function(a,b,c){var d,e,f=1/0,g=1/0;if(null==b&&null!=a){a=a.length===+a.length?a:n.values(a);for(var h=0,i=a.length;i>h;h++)d=a[h],f>d&&(f=d)}else b=n.iteratee(b,c),n.each(a,function(a,c,d){e=b(a,c,d),(g>e||1/0===e&&1/0===f)&&(f=a,g=e)});return f},n.shuffle=function(a){for(var b,c=a&&a.length===+a.length?a:n.values(a),d=c.length,e=Array(d),f=0;d>f;f++)b=n.random(0,f),b!==f&&(e[f]=e[b]),e[b]=c[f];return e},n.sample=function(a,b,c){return null==b||c?(a.length!==+a.length&&(a=n.values(a)),a[n.random(a.length-1)]):n.shuffle(a).slice(0,Math.max(0,b))},n.sortBy=function(a,b,c){return b=n.iteratee(b,c),n.pluck(n.map(a,function(a,c,d){return{value:a,index:c,criteria:b(a,c,d)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;if(c!==d){if(c>d||void 0===c)return 1;if(d>c||void 0===d)return-1}return a.index-b.index}),"value")};var q=function(a){return function(b,c,d){var e={};return c=n.iteratee(c,d),n.each(b,function(d,f){var g=c(d,f,b);a(e,d,g)}),e}};n.groupBy=q(function(a,b,c){n.has(a,c)?a[c].push(b):a[c]=[b]}),n.indexBy=q(function(a,b,c){a[c]=b}),n.countBy=q(function(a,b,c){n.has(a,c)?a[c]++:a[c]=1}),n.sortedIndex=function(a,b,c,d){c=n.iteratee(c,d,1);for(var e=c(b),f=0,g=a.length;g>f;){var h=f+g>>>1;c(a[h])b?[]:g.call(a,0,b)},n.initial=function(a,b,c){return g.call(a,0,Math.max(0,a.length-(null==b||c?1:b)))},n.last=function(a,b,c){return null==a?void 0:null==b||c?a[a.length-1]:g.call(a,Math.max(a.length-b,0))},n.rest=n.tail=n.drop=function(a,b,c){return g.call(a,null==b||c?1:b)},n.compact=function(a){return n.filter(a,n.identity)};var r=function(a,b,c,d){if(b&&n.every(a,n.isArray))return h.apply(d,a);for(var e=0,g=a.length;g>e;e++){var i=a[e];n.isArray(i)||n.isArguments(i)?b?f.apply(d,i):r(i,b,c,d):c||d.push(i)}return d};n.flatten=function(a,b){return r(a,b,!1,[])},n.without=function(a){return n.difference(a,g.call(arguments,1))},n.uniq=n.unique=function(a,b,c,d){if(null==a)return[];n.isBoolean(b)||(d=c,c=b,b=!1),null!=c&&(c=n.iteratee(c,d));for(var e=[],f=[],g=0,h=a.length;h>g;g++){var i=a[g];if(b)g&&f===i||e.push(i),f=i;else if(c){var j=c(i,g,a);n.indexOf(f,j)<0&&(f.push(j),e.push(i))}else n.indexOf(e,i)<0&&e.push(i)}return e},n.union=function(){return n.uniq(r(arguments,!0,!0,[]))},n.intersection=function(a){if(null==a)return[];for(var b=[],c=arguments.length,d=0,e=a.length;e>d;d++){var f=a[d];if(!n.contains(b,f)){for(var g=1;c>g&&n.contains(arguments[g],f);g++);g===c&&b.push(f)}}return b},n.difference=function(a){var b=r(g.call(arguments,1),!0,!0,[]);return n.filter(a,function(a){return!n.contains(b,a)})},n.zip=function(a){if(null==a)return[];for(var b=n.max(arguments,"length").length,c=Array(b),d=0;b>d;d++)c[d]=n.pluck(arguments,d);return c},n.object=function(a,b){if(null==a)return{};for(var c={},d=0,e=a.length;e>d;d++)b?c[a[d]]=b[d]:c[a[d][0]]=a[d][1];return c},n.indexOf=function(a,b,c){if(null==a)return-1;var d=0,e=a.length;if(c){if("number"!=typeof c)return d=n.sortedIndex(a,b),a[d]===b?d:-1;d=0>c?Math.max(0,e+c):c}for(;e>d;d++)if(a[d]===b)return d;return-1},n.lastIndexOf=function(a,b,c){if(null==a)return-1;var d=a.length;for("number"==typeof c&&(d=0>c?d+c+1:Math.min(d,c+1));--d>=0;)if(a[d]===b)return d;return-1},n.range=function(a,b,c){arguments.length<=1&&(b=a||0,a=0),c=c||1;for(var d=Math.max(Math.ceil((b-a)/c),0),e=Array(d),f=0;d>f;f++,a+=c)e[f]=a;return e};var s=function(){};n.bind=function(a,b){var c,d;if(m&&a.bind===m)return m.apply(a,g.call(arguments,1));if(!n.isFunction(a))throw new TypeError("Bind must be called on a function");return c=g.call(arguments,2),d=function(){if(!(this instanceof d))return a.apply(b,c.concat(g.call(arguments)));s.prototype=a.prototype;var e=new s;s.prototype=null;var f=a.apply(e,c.concat(g.call(arguments)));return n.isObject(f)?f:e}},n.partial=function(a){var b=g.call(arguments,1);return function(){for(var c=0,d=b.slice(),e=0,f=d.length;f>e;e++)d[e]===n&&(d[e]=arguments[c++]);for(;c=d)throw new Error("bindAll must be passed function names");for(b=1;d>b;b++)c=arguments[b],a[c]=n.bind(a[c],a);return a},n.memoize=function(a,b){var c=function(d){var e=c.cache,f=b?b.apply(this,arguments):d;return n.has(e,f)||(e[f]=a.apply(this,arguments)),e[f]};return c.cache={},c},n.delay=function(a,b){var c=g.call(arguments,2);return setTimeout(function(){return a.apply(null,c)},b)},n.defer=function(a){return n.delay.apply(n,[a,1].concat(g.call(arguments,1)))},n.throttle=function(a,b,c){var d,e,f,g=null,h=0;c||(c={});var i=function(){h=c.leading===!1?0:n.now(),g=null,f=a.apply(d,e),g||(d=e=null)};return function(){var j=n.now();h||c.leading!==!1||(h=j);var k=b-(j-h);return d=this,e=arguments,0>=k||k>b?(clearTimeout(g),g=null,h=j,f=a.apply(d,e),g||(d=e=null)):g||c.trailing===!1||(g=setTimeout(i,k)),f}},n.debounce=function(a,b,c){var d,e,f,g,h,i=function(){var j=n.now()-g;b>j&&j>0?d=setTimeout(i,b-j):(d=null,c||(h=a.apply(f,e),d||(f=e=null)))};return function(){f=this,e=arguments,g=n.now();var j=c&&!d;return d||(d=setTimeout(i,b)),j&&(h=a.apply(f,e),f=e=null),h}},n.wrap=function(a,b){return n.partial(b,a)},n.negate=function(a){return function(){return!a.apply(this,arguments)}},n.compose=function(){var a=arguments,b=a.length-1;return function(){for(var c=b,d=a[b].apply(this,arguments);c--;)d=a[c].call(this,d);return d}},n.after=function(a,b){return function(){return--a<1?b.apply(this,arguments):void 0}},n.before=function(a,b){var c;return function(){return--a>0?c=b.apply(this,arguments):b=null,c}},n.once=n.partial(n.before,2),n.keys=function(a){if(!n.isObject(a))return[];if(l)return l(a);var b=[];for(var c in a)n.has(a,c)&&b.push(c);return b},n.values=function(a){for(var b=n.keys(a),c=b.length,d=Array(c),e=0;c>e;e++)d[e]=a[b[e]];return d},n.pairs=function(a){for(var b=n.keys(a),c=b.length,d=Array(c),e=0;c>e;e++)d[e]=[b[e],a[b[e]]];return d},n.invert=function(a){for(var b={},c=n.keys(a),d=0,e=c.length;e>d;d++)b[a[c[d]]]=c[d];return b},n.functions=n.methods=function(a){var b=[];for(var c in a)n.isFunction(a[c])&&b.push(c);return b.sort()},n.extend=function(a){if(!n.isObject(a))return a;for(var b,c,d=1,e=arguments.length;e>d;d++){b=arguments[d];for(c in b)j.call(b,c)&&(a[c]=b[c])}return a},n.pick=function(a,b,c){var d,e={};if(null==a)return e;if(n.isFunction(b)){b=o(b,c);for(d in a){var f=a[d];b(f,d,a)&&(e[d]=f)}}else{var i=h.apply([],g.call(arguments,1));a=new Object(a);for(var j=0,k=i.length;k>j;j++)d=i[j],d in a&&(e[d]=a[d])}return e},n.omit=function(a,b,c){if(n.isFunction(b))b=n.negate(b);else{var d=n.map(h.apply([],g.call(arguments,1)),String);b=function(a,b){return!n.contains(d,b)}}return n.pick(a,b,c)},n.defaults=function(a){if(!n.isObject(a))return a;for(var b=1,c=arguments.length;c>b;b++){var d=arguments[b];for(var e in d)void 0===a[e]&&(a[e]=d[e])}return a},n.clone=function(a){return n.isObject(a)?n.isArray(a)?a.slice():n.extend({},a):a},n.tap=function(a,b){return b(a),a};var t=function(a,b,c,d){if(a===b)return 0!==a||1/a===1/b;if(null==a||null==b)return a===b;a instanceof n&&(a=a._wrapped),b instanceof n&&(b=b._wrapped);var e=i.call(a);if(e!==i.call(b))return!1;switch(e){case"[object RegExp]":case"[object String]":return""+a==""+b;case"[object Number]":return+a!==+a?+b!==+b:0===+a?1/+a===1/b:+a===+b;case"[object Date]":case"[object Boolean]":return+a===+b}if("object"!=typeof a||"object"!=typeof b)return!1;for(var f=c.length;f--;)if(c[f]===a)return d[f]===b;var g=a.constructor,h=b.constructor;if(g!==h&&"constructor"in a&&"constructor"in b&&!(n.isFunction(g)&&g instanceof g&&n.isFunction(h)&&h instanceof h))return!1;c.push(a),d.push(b);var j,k;if("[object Array]"===e){if(j=a.length,k=j===b.length)for(;j--&&(k=t(a[j],b[j],c,d)););}else{var l,m=n.keys(a);if(j=m.length,k=n.keys(b).length===j)for(;j--&&(l=m[j],k=n.has(b,l)&&t(a[l],b[l],c,d)););}return c.pop(),d.pop(),k};n.isEqual=function(a,b){return t(a,b,[],[])},n.isEmpty=function(a){if(null==a)return!0;if(n.isArray(a)||n.isString(a)||n.isArguments(a))return 0===a.length;for(var b in a)if(n.has(a,b))return!1;return!0},n.isElement=function(a){return!(!a||1!==a.nodeType)},n.isArray=k||function(a){return"[object Array]"===i.call(a)},n.isObject=function(a){var b=typeof a;return"function"===b||"object"===b&&!!a},n.each(["Arguments","Function","String","Number","Date","RegExp"],function(a){n["is"+a]=function(b){return i.call(b)==="[object "+a+"]"}}),n.isArguments(arguments)||(n.isArguments=function(a){return n.has(a,"callee")}),"function"!=typeof/./&&(n.isFunction=function(a){return"function"==typeof a||!1}),n.isFinite=function(a){return isFinite(a)&&!isNaN(parseFloat(a))},n.isNaN=function(a){return n.isNumber(a)&&a!==+a},n.isBoolean=function(a){return a===!0||a===!1||"[object Boolean]"===i.call(a)},n.isNull=function(a){return null===a},n.isUndefined=function(a){return void 0===a},n.has=function(a,b){return null!=a&&j.call(a,b)},n.noConflict=function(){return a._=b,this},n.identity=function(a){return a},n.constant=function(a){return function(){return a}},n.noop=function(){},n.property=function(a){return function(b){return b[a]}},n.matches=function(a){var b=n.pairs(a),c=b.length;return function(a){if(null==a)return!c;a=new Object(a);for(var d=0;c>d;d++){var e=b[d],f=e[0];if(e[1]!==a[f]||!(f in a))return!1}return!0}},n.times=function(a,b,c){var d=Array(Math.max(0,a));b=o(b,c,1);for(var e=0;a>e;e++)d[e]=b(e);return d},n.random=function(a,b){return null==b&&(b=a,a=0),a+Math.floor(Math.random()*(b-a+1))},n.now=Date.now||function(){return(new Date).getTime()};var u={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},v=n.invert(u),w=function(a){var b=function(b){return a[b]},c="(?:"+n.keys(a).join("|")+")",d=RegExp(c),e=RegExp(c,"g");return function(a){return a=null==a?"":""+a,d.test(a)?a.replace(e,b):a}};n.escape=w(u),n.unescape=w(v),n.result=function(a,b){if(null==a)return void 0;var c=a[b];return n.isFunction(c)?a[b]():c};var x=0;n.uniqueId=function(a){var b=++x+"";return a?a+b:b},n.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var y=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},A=/\\|'|\r|\n|\u2028|\u2029/g,B=function(a){return"\\"+z[a]};n.template=function(a,b,c){!b&&c&&(b=c),b=n.defaults({},b,n.templateSettings);var d=RegExp([(b.escape||y).source,(b.interpolate||y).source,(b.evaluate||y).source].join("|")+"|$","g"),e=0,f="__p+='";a.replace(d,function(b,c,d,g,h){return f+=a.slice(e,h).replace(A,B),e=h+b.length,c?f+="'+\n((__t=("+c+"))==null?'':_.escape(__t))+\n'":d?f+="'+\n((__t=("+d+"))==null?'':__t)+\n'":g&&(f+="';\n"+g+"\n__p+='"),b}),f+="';\n",b.variable||(f="with(obj||{}){\n"+f+"}\n"),f="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+f+"return __p;\n";try{var g=new Function(b.variable||"obj","_",f)}catch(h){throw h.source=f,h}var i=function(a){return g.call(this,a,n)},j=b.variable||"obj";return i.source="function("+j+"){\n"+f+"}",i},n.chain=function(a){var b=n(a);return b._chain=!0,b};var C=function(a){return this._chain?n(a).chain():a};n.mixin=function(a){n.each(n.functions(a),function(b){var c=n[b]=a[b];n.prototype[b]=function(){var a=[this._wrapped];return f.apply(a,arguments),C.call(this,c.apply(n,a))}})},n.mixin(n),n.each(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=c[a];n.prototype[a]=function(){var c=this._wrapped;return b.apply(c,arguments),"shift"!==a&&"splice"!==a||0!==c.length||delete c[0],C.call(this,c)}}),n.each(["concat","join","slice"],function(a){var b=c[a];n.prototype[a]=function(){return C.call(this,b.apply(this._wrapped,arguments))}}),n.prototype.value=function(){return this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return n})}).call(this),!function(a,b,c){function d(a,c){var d,e=b.createElement(a||"div");for(d in c)e[d]=c[d];return e}function e(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function f(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=k.substring(0,k.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return m[e]||(n.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",n.cssRules.length),m[e]=1),e}function g(a,b){var d,e,f=a.style;if(f[b]!==c)return b;for(b=b.charAt(0).toUpperCase()+b.slice(1),e=0;e>1):parseInt(f.left,10)+i)+"px",top:("auto"==f.top?c.y-b.y+(a.offsetHeight>>1):parseInt(f.top,10)+i)+"px"})),g.setAttribute("aria-role","progressbar"),e.lines(g,e.opts),!k){var l=0,m=f.fps,n=m/f.speed,o=(1-f.opacity)/(n*f.trail/100),p=n/f.lines;!function q(){l++;for(var a=f.lines;a;a--){var b=Math.max(1-(l+a*p)%n*o,f.opacity);e.opacity(g,f.lines-a,b,f)}e.timeout=e.el&&setTimeout(q,~~(1e3/m))}()}return e},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=c),this},lines:function(a,b){function c(a,c){return h(d(),{position:"absolute",width:b.length+b.width+"px",height:b.width+"px",background:a,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/b.lines*i+b.rotate)+"deg) translate("+b.radius+"px,0)",borderRadius:(b.corners*b.width>>1)+"px"})}for(var g,i=0;i',b)}var b=h(d("group"),{behavior:"url(#default#VML)"});!g(b,"transform")&&b.adj?(n.addRule(".spin-vml","behavior:url(#default#VML)"),p.prototype.lines=function(b,c){function d(){return h(a("group",{coordsize:j+" "+j,coordorigin:-i+" "+-i}),{width:j,height:j})}function f(b,f,g){e(l,e(h(d(),{rotation:360/c.lines*b+"deg",left:~~f}),e(h(a("roundrect",{arcsize:c.corners}),{width:i,height:c.width,left:c.radius,top:-c.width>>1,filter:g}),a("fill",{color:c.color,opacity:c.opacity}),a("stroke",{opacity:0}))))}var g,i=c.length+c.width,j=2*i,k=2*-(c.width+c.length)+"px",l=h(d(),{position:"absolute",top:k,left:k});if(c.shadow)for(g=1;g<=c.lines;g++)f(g,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(g=1;g<=c.lines;g++)f(g);return e(b,l)},p.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d\n\nChat Rooms\n\n\n\n
                                                                          \n\n\nVisitors\n\n\n\n
                                                                          \n\n\n
                                                                          \n\n
                                                                          \n
                                                                          \n";return __p},this.FirechatDefaultTemplates["templates/layout-popout.html"]=function(obj){obj||(obj={});var __p="";_.escape;with(obj)__p+="
                                                                          \n
                                                                          \n\n
                                                                          \n
                                                                          \n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/message-context-menu.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                                          \n\n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/message.html"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                                          \n
                                                                          \n",disableActions||(__p+="\n\n"),__p+="
                                                                          \n
                                                                          \n"+(null==(__t=message)?"":__t)+"\n
                                                                          \n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/prompt-alert.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                                          \n
                                                                          "+__e(message)+"
                                                                          \n

                                                                          \n\n

                                                                          \n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/prompt-create-room.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                                          \n
                                                                          Give your chat room a name:
                                                                          \n\n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/prompt-invitation.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                                          \n
                                                                          "+__e(fromUserName)+"
                                                                          \n

                                                                          invited you to join

                                                                          \n
                                                                          "+__e(toRoomName)+"
                                                                          \n

                                                                          \n\n\n

                                                                          \n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/prompt-invite-private.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                                          \n
                                                                          Invite "+__e(userName)+" to "+__e(roomName)+"?
                                                                          \n

                                                                          \n\n\n

                                                                          \n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/prompt-invite-reply.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                                          \n
                                                                          "+__e(toUserName)+"
                                                                          \n

                                                                          \n",__p+="accepted"===status?" accepted your invite. ":" declined your invite. ",__p+="\n

                                                                          \n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/prompt-user-mute.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                                          \n
                                                                          "+__e(userName)+"
                                                                          \n

                                                                          \n\n\n

                                                                          \n
                                                                          ";return __p},this.FirechatDefaultTemplates["templates/prompt.html"]=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;with(obj)__p+="";return __p},this.FirechatDefaultTemplates["templates/room-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                                        • \n\n"+__e(name)+"\n\n
                                                                        • ";return __p},this.FirechatDefaultTemplates["templates/room-user-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                                        • \n\n"+__e(name)+"",disableActions||(__p+="\n \n \n"),__p+="\n\n
                                                                        • ";return __p},this.FirechatDefaultTemplates["templates/room-user-search-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;Array.prototype.join;with(obj)__p+="
                                                                        • \n\n",__p+=disableActions?"\n"+__e(name)+"\n":"\n"+__e(name)+"\n+\n",__p+="\n\n
                                                                        • ";return __p},this.FirechatDefaultTemplates["templates/tab-content.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                                          \n
                                                                          \n\n\nIn Room\n\n\n\n
                                                                          \n\n+\nInvite\n\n\n
                                                                          \n
                                                                          \n
                                                                          \n\n
                                                                          \n\n\n
                                                                          \n
                                                                          ';return __p},this.FirechatDefaultTemplates["templates/tab-menu-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape;with(obj)__p+="
                                                                        • \n"+__e(name)+"\n
                                                                        • ";return __p},this.FirechatDefaultTemplates["templates/user-search-list-item.html"]=function(obj){obj||(obj={});var __p="",__e=_.escape; -Array.prototype.join;with(obj)__p+="
                                                                        • \n\n",__p+=disableActions?"\n"+__e(name)+"\n":"\n"+__e(name)+"\n \n",__p+="\n\n
                                                                        • ";return __p},function(a){Function.prototype.bind||(Function.prototype.bind=function(a){if("function"!=typeof this)throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");var b=Array.prototype.slice.call(arguments,1),c=this,d=function(){},e=function(){return c.apply(this instanceof d&&a?this:a,b.concat(Array.prototype.slice.call(arguments)))};return d.prototype=this.prototype,e.prototype=new d,e}),Object.keys=Object.keys||function(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b}}(),function(a){function b(a,b){this._firebase=a,this._user=null,this._userId=null,this._userName=null,this._isModerator=!1,this._sessionId=null,this._events={},this._rooms={},this._presenceBits={},this._userRef=null,this._messageRef=this._firebase.child("room-messages"),this._roomRef=this._firebase.child("room-metadata"),this._privateRoomRef=this._firebase.child("room-private-metadata"),this._moderatorsRef=this._firebase.child("moderators"),this._suspensionsRef=this._firebase.child("suspensions"),this._usersOnlineRef=this._firebase.child("user-names-online"),this._options=b||{},this._options.numMaxMessages=this._options.numMaxMessages||50}var c=this,d=c.Firechat;b.noConflict=function(){return c.Firechat=d,b},c.Firechat=b,b.prototype={_loadUserMetadata:function(a){var b=this;this._userRef.transaction(function(a){return a&&a.id&&a.name?void 0:{id:b._userId,name:b._userName}},function(d,e,f){b._user=f.val(),b._moderatorsRef.child(b._userId).once("value",function(d){b._isModerator=!!d.val(),c.setTimeout(a,0)})})},_setupDataEvents:function(){this._firebase.root().child(".info/connected").on("value",function(a){if(a.val()===!0)for(var b=0;b2&&(f=arguments[1]),d=f?d.limitToLast(f):d,d.once("value",function(a){var b=a.val()||{},d={};for(var f in b)for(var g in b[f]){d[f]=b[f][g];break}c.setTimeout(function(){e(d)},0)})},b.prototype.getUsersByPrefix=function(a,b,d,e,f){var g=this._usersOnlineRef,h=a.toLowerCase();g=b?g.startAt(null,b):d?g.endAt(null,d):h?g.startAt(null,h):g.startAt(),g=e?g.limitToLast(e):g,g.once("value",function(b){var d=b.val()||{},e={};for(var g in d){var i,j,k=d[g];for(var l in k){i=k[l].name,j=k[l].id;break}a.length>0&&0!==i.toLowerCase().indexOf(h)||(e[i]={name:i,id:j})}c.setTimeout(function(){f(e)},0)})},b.prototype.getRoom=function(a,b){this._roomRef.child(a).once("value",function(a){b(a.val())})},b.prototype.userIsModerator=function(){return this._isModerator},b.prototype.warn=function(a){console&&(a="Firechat Warning: "+a,"function"==typeof console.warn?console.warn(a):"function"==typeof console.log&&console.log(a))}}(Firebase),function(a){function b(b,c,d){if(!b)throw new Error("FirechatUI: Missing required argument `firebaseRef`");if(!c)throw new Error("FirechatUI: Missing required argument `el`");d=d||{},this._options=d,this._el=c,this._user=null,this._chat=new Firechat(b,d),this._roomQueue=[],this.maxLengthUsername=15,this.maxLengthUsernameDisplay=15,this.maxLengthRoomName=24,this.maxLengthMessage=120,this.maxUserSearchResults=100,this.urlPattern=/\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim,this.pseudoUrlPattern=/(^|[^\/])(www\.[\S]+(\b|$))/gim,this._renderLayout(),this.$wrapper=a("#firechat"),this.$roomList=a("#firechat-room-list"),this.$tabList=a("#firechat-tab-list"),this.$tabContent=a("#firechat-tab-content"),this.$messages={},this.$rateLimit={limitCount:10,limitInterval:1e4,limitWaitTime:3e4,history:{}},this._bindUIEvents(),this._bindDataEvents()}if(!a||parseInt(a().jquery.replace(/\./g,""),10)<170)throw new Error("jQuery 1.7 or later required!");var c=this,d=c.FirechatUI;if(c.FirechatUI=b,!self.FirechatDefaultTemplates)throw new Error("Unable to find chat templates!");b.noConflict=function(){return c.FirechatUI=d,b},b.prototype={_bindUIEvents:function(){this._bindForHeightChange(),this._bindForTabControls(),this._bindForRoomList(),this._bindForUserRoomList(),this._bindForUserSearch(),this._bindForUserMuting(),this._bindForChatInvites(),this._bindForRoomListing(),this._bindForFileUpload(),this._setupTabs(),this._setupDropdowns(),this._bindTextInputFieldLimits()},_bindDataEvents:function(){this._chat.on("user-update",this._onUpdateUser.bind(this)),this._chat.on("room-enter",this._onEnterRoom.bind(this)),this._chat.on("room-exit",this._onLeaveRoom.bind(this)),this._chat.on("message-add",this._onNewMessage.bind(this)),this._chat.on("message-remove",this._onRemoveMessage.bind(this)),this._chat.on("room-invite",this._onChatInvite.bind(this)),this._chat.on("room-invite-response",this._onChatInviteResponse.bind(this)),this._chat.on("notification",this._onNotification.bind(this))},_renderLayout:function(){var b=FirechatDefaultTemplates["templates/layout-full.html"];a(this._el).html(b({maxLengthUsername:this.maxLengthUsername}))},_onUpdateUser:function(b){this._user=b;var c=this._user.muted||{};a('[data-event="firechat-user-mute-toggle"]').each(function(b,d){var e=a(this).closest("[data-user-id]").data("user-id");a(this).toggleClass("red",!!c[e])});for(var d in c)a('.message[data-user-id="'+d+'"]').fadeOut()},_onEnterRoom:function(a){this.attachTab(a.id,a.name)},_onLeaveRoom:function(a){this.removeTab(a),this._roomQueue.length>0&&this._chat.enterRoom(this._roomQueue.shift(a))},_onNewMessage:function(a,b){var c=b.userId;this._user&&this._user.muted&&this._user.muted[c]||this.showMessage(a,b)},_onRemoveMessage:function(a,b){this.removeMessage(a,b)},_onChatInvite:function(a){var b=this,c=FirechatDefaultTemplates["templates/prompt-invitation.html"],d=this.prompt("Invite",c(a));d.find("a.close").click(function(){return d.remove(),b._chat.declineInvite(a.id),!1}),d.find("[data-toggle=accept]").click(function(){return d.remove(),b._chat.acceptInvite(a.id),!1}),d.find("[data-toggle=decline]").click(function(){return d.remove(),b._chat.declineInvite(a.id),!1})},_onChatInviteResponse:function(a){if(a.status){var b,c=this,d=FirechatDefaultTemplates["templates/prompt-invite-reply.html"];a.status&&"accepted"===a.status?(b=this.prompt("Accepted",d(a)),this._chat.getRoom(a.roomId,function(b){c.attachTab(a.roomId,b.name)})):b=this.prompt("Declined",d(a)),b.find("a.close").click(function(){return b.remove(),!1})}},_onNotification:function(a){if("warning"===a.notificationType)this.renderAlertPrompt("Warning","You are being warned for inappropriate messaging. Further violation may result in temporary or permanent ban of service.");else if("suspension"===a.notificationType){var b=a.data.suspendedUntil,c=Math.round((b-(new Date).getTime())/1e3),d="";if(c>0){if(c>7200){var e=Math.floor(c/3600);d=e+" hours, ",c-=3600*e}d+=Math.floor(c/60)+" minutes",this.renderAlertPrompt("Suspended","A moderator has suspended you for violating site rules. You cannot send messages for another "+d+".")}}}},b.prototype.setUser=function(a,b){var c=this;c._chat.setUser(a,b,function(a){c._user=a,c._chat.userIsModerator()&&c._bindSuperuserUIEvents(),c._chat.resumeSession()})},b.prototype.on=function(a,b){this._chat.on(a,b)},b.prototype._bindSuperuserUIEvents=function(){var b=this,c=function(b){var c=a(this),d=c.closest("[data-message-id]").data("message-id"),e=a('[data-message-id="'+d+'"]').closest("[data-user-id]").data("user-id"),f=a('[data-message-id="'+d+'"]').closest("[data-room-id]").data("room-id");return{messageId:d,userId:e,roomId:f}},d=function(){a('[data-toggle="firechat-contextmenu"]').each(function(){a(this).remove()}),a("#firechat .message.highlighted").each(function(){a(this).removeClass("highlighted")})},e=function(e){var f,g=a(this),h=g.closest("[data-message-id]"),i=FirechatDefaultTemplates["templates/message-context-menu.html"],j=c.call(this,e);e.preventDefault(),d(),g.addClass("highlighted"),b._chat.getRoom(j.roomId,function(c){f=a(i({id:h.data("message-id")})),f.css({left:e.clientX,top:e.clientY}).appendTo(b.$wrapper)})};a(document).bind("click",{self:this},function(a){a.button&&2==a.button||d()}),a(document).delegate('[data-class="firechat-message"]',"contextmenu",e),a(document).delegate('[data-event="firechat-user-warn"]',"click",function(a){var d=c.call(this,a);b._chat.warnUser(d.userId)}),a(document).delegate('[data-event="firechat-user-suspend-hour"]',"click",function(a){var d=c.call(this,a);b._chat.suspendUser(d.userId,3600)}),a(document).delegate('[data-event="firechat-user-suspend-day"]',"click",function(a){var d=c.call(this,a);b._chat.suspendUser(d.userId,86400)}),a(document).delegate('[data-event="firechat-message-delete"]',"click",function(a){var d=c.call(this,a);b._chat.deleteMessage(d.roomId,d.messageId)})},b.prototype._bindForHeightChange=function(){var b=a(this._el),c=null;setInterval(function(){var d=b.height();d!=c&&(c=d,a(".chat").each(function(a,b){}))},500)},b.prototype._bindForTabControls=function(){var b=this;a(document).delegate('[data-event="firechat-close-tab"]',"click",function(c){var d=a(this).closest("[data-room-id]").data("room-id");return b._chat.leaveRoom(d),!1})},b.prototype._bindForRoomList=function(){var b=this;a("#firechat-btn-rooms").bind("click",function(){if(!a(this).parent().hasClass("open")){var c=(a(this),FirechatDefaultTemplates["templates/room-list-item.html"]),d=function(){var c=a(this).parent(),d=c.data("room-id"),e=c.data("room-name");return b.$messages[d]?b.focusTab(d):b._chat.enterRoom(d,e),!1};b._chat.getRoomList(function(e){b.$roomList.empty();for(var f in e){var g=e[f];if("public"==g.type){g.isRoomOpen=!!b.$messages[g.id];var h=a(c(g));h.children("a").bind("click",d),b.$roomList.append(h.toggle(!0))}}})}})},b.prototype._bindForUserRoomList=function(){var b=this;a(document).delegate('[data-event="firechat-user-room-list-btn"]',"click",function(c){c.stopPropagation();var d=a(this),e=d.closest("[data-room-id]").data("room-id"),f=FirechatDefaultTemplates["templates/room-user-list-item.html"],g=d.data("target"),h=a("#"+g);h.empty(),b._chat.getUsersByRoom(e,function(c){for(var d in c)user=c[d],user.disableActions=!b._user||user.id===b._user.id,user.nameTrimmed=b.trimWithEllipsis(user.name,b.maxLengthUsernameDisplay),user.isMuted=b._user&&b._user.muted&&b._user.muted[user.id],h.append(a(f(user)));b.sortListLexicographically("#"+g)})})},b.prototype._bindForFileUpload=function(){var b=this,c=function(c){var d=c.target.files[0],e=new FileReader;e.onload=function(c){return function(c){var d=c.target.result,e=CryptoJS.SHA256(Math.random()+CryptoJS.SHA256(d)),f=new Firebase(firebaseRef+"/pano/"+e+"/filePayload");spinner.spin(document.getElementById("spin")),f.set(d,function(){spinner.stop();var c=firebaseRef+"/pano/"+e+"/filePayload";console.log("File with hash: "+c+" created"),a("#file-upload").hide();var d=a("textarea").attr("id").replace(/textarea/,""),g=b.trimWithEllipsis("File Uploaded from "+b._chat._userName,b.maxLengthMessage);b._chat.sendMessage(d,g),f.once("value",function(b){var c=b.val();if(null!==c){var e=a('');e.attr("src",c),e.appendTo(a(".message").last()),e.width(313),e.show()}else a("#body").append("Not found");spinner.stop()})})}}(d),e.readAsDataURL(d)};a(document).delegate('[data-event="firechat-upload-file"]',"click",function(b){b.stopPropagation(),console.log("Clicked on the button!"),a("#file-upload").show(),a("#file-upload").get(0).addEventListener("change",c,!1)}),a(document).delegate('[data-event="firechat-file-uploaded"]',"change",function(a){a.stopPropagation(),console.log("Upload Complete")})},b.prototype._bindForUserSearch=function(){var b=this,c=function(b){var c=a(this),e=c.data("target"),f=c.data("controls"),g=c.data("template"),h=c.val()||c.data("prefix")||"",i=c.data("startAt")||null,j=c.data("endAt")||null;b.preventDefault(),d(e,g,f,h,i,j)},d=function(c,d,e,f,g,h){var i=a("#"+c),j=a("#"+e),k=FirechatDefaultTemplates[d];b._chat.getUsersByPrefix(f,g,h,b.maxUserSearchResults,function(a){var c,d,e,g,h,l=0;i.empty();for(e in a){var m=a[e];if(m.disableActions=!b._user||m.id===b._user.id,l+=1,i.append(k(m)),1===l)g=m.name.toLowerCase();else if(l>=b.maxUserSearchResults){h=m.name.toLowerCase();break}}j&&(c=j.find('[data-toggle="firechat-pagination-prev"]'),d=j.find('[data-toggle="firechat-pagination-next"]'),h?d.data("event","firechat-user-search").data("startAt",h).data("prefix",f).removeClass("disabled").removeAttr("disabled"):d.data("event",null).data("startAt",null).data("prefix",null).addClass("disabled").attr("disabled","disabled"))})};a(document).delegate('[data-event="firechat-user-search"]',"keyup",c),a(document).delegate('[data-event="firechat-user-search"]',"click",c),a(document).delegate('[data-event="firechat-user-search-btn"]',"click",function(b){b.stopPropagation();var c=a(this).next("div.firechat-dropdown-menu").find("input");c.focus(),c.trigger(jQuery.Event("keyup"))}),a(document).delegate('[data-event="firechat-user-search"]',"click",function(a){a.stopPropagation()})},b.prototype._bindForUserMuting=function(){var b=this;a(document).delegate('[data-event="firechat-user-mute-toggle"]',"click",function(c){var d=a(this),e=d.closest("[data-user-id]").data("user-id"),f=d.closest("[data-user-name]").data("user-name"),g=d.hasClass("red"),h=FirechatDefaultTemplates["templates/prompt-user-mute.html"];if(c.preventDefault(),g)b._chat.toggleUserMute(e);else{var i=b.prompt("Mute User?",h({userName:f}));i.find("a.close").first().click(function(){return i.remove(),!1}),i.find("[data-toggle=decline]").first().click(function(){return i.remove(),!1}),i.find("[data-toggle=accept]").first().click(function(){return b._chat.toggleUserMute(e),i.remove(),!1})}})},b.prototype._bindForChatInvites=function(){var b=this,c=function(c){var d,e=a(this),f=e.closest("[data-user-id]").data("user-id"),g=e.closest("[data-room-id]").data("room-id"),h=e.closest("[data-user-name]").data("user-name"),i=FirechatDefaultTemplates["templates/prompt-invite-private.html"];return b._chat.getRoom(g,function(a){return d=b.prompt("Invite",i({userName:h,roomName:a.name})),d.find("a.close").click(function(){return d.remove(),!1}),d.find("[data-toggle=decline]").click(function(){return d.remove(),!1}),d.find("[data-toggle=accept]").first().click(function(){return d.remove(),b._chat.inviteUser(f,g,a.name),!1}),!1}),!1},d=function(c){var d,e=a(this),f=e.closest("[data-user-id]").data("user-id"),g=e.closest("[data-user-name]").data("user-name"),h=FirechatDefaultTemplates["templates/prompt-invite-private.html"];return f&&g&&(d=b.prompt("Private Invite",h({userName:g,roomName:"Private Chat"})),d.find("a.close").click(function(){return d.remove(),!1}),d.find("[data-toggle=decline]").click(function(){return d.remove(),!1}),d.find("[data-toggle=accept]").first().click(function(){d.remove();var a="Private Chat";return b._chat.createRoom(a,"private",function(c){b._chat.inviteUser(f,c,a)}),!1})),!1};a(document).delegate('[data-event="firechat-user-chat"]',"click",d),a(document).delegate('[data-event="firechat-user-invite"]',"click",c)},b.prototype._bindForRoomListing=function(){var b=this,c=a("#firechat-btn-create-room-prompt"),d=a("#firechat-btn-create-room");c.bind("click",function(a){return b.promptCreateRoom(),!1}),d.bind("click",function(c){var d=a("#firechat-input-room-name").val();return a("#firechat-prompt-create-room").remove(),b._chat.createRoom(d),!1})},b.prototype._setupTabs=function(){var b=function(b){var d,e,f=b,g=f.closest("ul:not(.firechat-dropdown-menu)"),h=f.attr("data-target"),i=g.find(".active:last a")[0];h||(h=f.attr("href"),h=h&&h.replace(/.*(?=#[^\s]*$)/,"")),f.parent("li").hasClass("active")||(e=a.Event("show",{relatedTarget:i}),f.trigger(e),e.isDefaultPrevented()||(d=a(h),c(f.parent("li"),g),c(d,d.parent(),function(){f.trigger({type:"shown",relatedTarget:i})})))},c=function(b,c,d){function e(){f.removeClass("active").find("> .firechat-dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?b.addClass("in"):b.removeClass("fade"),b.parent(".firechat-dropdown-menu")&&b.closest("li.firechat-dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one(a.support.transition.end,e):e(),f.removeClass("in")};a(document).delegate('[data-toggle="firechat-tab"]',"click",function(c){c.preventDefault(),b(a(this))})},b.prototype._setupDropdowns=function(){var b=function(b){var e=a(this),f=d(e),g=f.hasClass("open");if(!e.is(".disabled, :disabled"))return c(),g||f.toggleClass("open"),e.focus(),!1},c=function(){a("[data-toggle=firechat-dropdown]").each(function(){d(a(this)).removeClass("open")})},d=function(b){var c,d=b.attr("data-target");return d||(d=b.attr("href"),d=d&&/#/.test(d)&&d.replace(/.*(?=#[^\s]*$)/,"")),c=d&&a(d),c&&c.length||(c=b.parent()),c};a(document).bind("click",c).delegate(".firechat-dropdown-menu","click",function(a){a.stopPropagation()}).delegate("[data-toggle=firechat-dropdown]","click",b)},b.prototype._bindTextInputFieldLimits=function(){a("body").delegate('input[data-provide="limit"], textarea[data-provide="limit"]',"keyup",function(b){var c=a(this),d=a(c.data("counter")),e=c.attr("maxlength"),f=c.val().length;d.html(Math.max(0,e-f))})},b.prototype.renderAlertPrompt=function(a,b){var c=FirechatDefaultTemplates["templates/prompt-alert.html"],d=this.prompt(a,c({message:b}));d.find(".close").click(function(){return d.remove(),!1})},b.prototype.toggleInputs=function(b){a("#firechat-tab-content textarea").each(function(){var c=a(this);b?a(this).val(""):a(this).val("You have exceeded the message limit, please wait before sending."),c.prop("disabled",!b)}),a("#firechat-input-name").prop("disabled",!b)},b.prototype.attachTab=function(b,c){var d=this;if(this.$messages[b])return void this.focusTab(b);var e={id:b,name:c},f=FirechatDefaultTemplates["templates/tab-content.html"],g=a(f(e));this.$tabContent.prepend(g);var h=a("#firechat-messages"+b);this.$messages[b]=h;var i=g.find("textarea").first();i.bind("keydown",function(a){var c=d.trimWithEllipsis(i.val(),d.maxLengthMessage);return 13===a.which&&""!==c?(i.val(""),d._chat.sendMessage(b,c),!1):void 0});var j=FirechatDefaultTemplates["templates/tab-menu-item.html"],k=a(j(e));this.$tabList.prepend(k),k.bind("shown",function(a){h.scrollTop(h[0].scrollHeight)});var l=this.$tabList.children("li"),m=Math.floor(a("#firechat-tab-list").width()/l.length);this.$tabList.children("li").css("width",m),this.$roomList.children("[data-room-id="+b+"]").children("a").addClass("highlight"),a("#firechat-btn-room-user-list-"+b).bind("click",function(){return d.sortListLexicographically("#firechat-room-user-list-"+b),!1}),this.focusTab(b)},b.prototype.focusTab=function(a){if(this.$messages[a]){var b=this.$tabList.find("[data-room-id="+a+"]").find("a");b.length&&b.first().trigger("click")}},b.prototype.removeTab=function(b){delete this.$messages[b],this.$tabContent.find("[data-room-id="+b+"]").remove(),this.$tabList.find("[data-room-id="+b+"]").remove();var c=this.$tabList.children("li"),d=Math.floor(a("#firechat-tab-list").width()/c.length);this.$tabList.children("li").css("width",d),this.$tabList.find('[data-toggle="firechat-tab"]').first().trigger("click"),this.$roomList.children("[data-room-id="+b+"]").children("a").removeClass("highlight")},b.prototype.showMessage=function(b,c){var d=this,e={id:c.id,localtime:d.formatTime(c.timestamp),message:c.message||"",userId:c.userId,name:c.name,type:c.type||"default",isSelfMessage:d._user&&c.userId==d._user.id,disableActions:!d._user||c.userId==d._user.id};e.message=_.map(e.message.split(" "),function(a){return d.urlPattern.test(a)||d.pseudoUrlPattern.test(a)?d.linkify(encodeURI(a)):_.escape(a)}).join(" "),e.message=d.trimWithEllipsis(e.message,d.maxLengthMessage);var f=FirechatDefaultTemplates["templates/message.html"],g=a(f(e)),h=d.$messages[b];if(h){var i=!1;h.scrollTop()/(h[0].scrollHeight-h[0].offsetHeight)>=.95?i=!0:h[0].scrollHeight<=h.height()&&(i=!0),h.append(g),i&&h.scrollTop(h[0].scrollHeight)}},b.prototype.removeMessage=function(b,c){a('.message[data-message-id="'+c+'"]').remove()},b.prototype.sortListLexicographically=function(b){a(b).children("li").sort(function(b,c){var d=a(b).text().toUpperCase(),e=a(c).text().toUpperCase();return e>d?-1:d>e?1:0}).appendTo(b)},b.prototype.trimWithEllipsis=function(a,b){return a=a.replace(/^\s\s*/,"").replace(/\s\s*$/,""),b&&a.length<=b?a:a.substring(0,b)+"..."},b.prototype.formatTime=function(a){var b=a?new Date(a):new Date,c=b.getHours()||12,d=""+b.getMinutes(),e=b.getHours()>=12?"pm":"am";return c=c>12?c-12:c,d=d.length<2?"0"+d:d,""+c+":"+d+e},b.prototype.promptCreateRoom=function(){var a=this,b=FirechatDefaultTemplates["templates/prompt-create-room.html"],c=this.prompt("Create Public Room",b({maxLengthRoomName:this.maxLengthRoomName,isModerator:a._chat.userIsModerator()}));c.find("a.close").first().click(function(){return c.remove(),!1}),c.find("[data-toggle=submit]").first().click(function(){var b=c.find("[data-input=firechat-room-name]").first().val();return""!==b&&(a._chat.createRoom(b,"public"),c.remove()),!1}),c.find("[data-input=firechat-room-name]").first().focus(),c.find("[data-input=firechat-room-name]").first().bind("keydown",function(b){if(13===b.which){var d=c.find("[data-input=firechat-room-name]").first().val();if(""!==d)return a._chat.createRoom(d,"public"),c.remove(),!1}})},b.prototype.prompt=function(b,c){var d,e=FirechatDefaultTemplates["templates/prompt.html"];return d=a(e({title:b,content:c})).css({top:this.$wrapper.position().top+.333*this.$wrapper.height(),left:this.$wrapper.position().left+.125*this.$wrapper.width(),width:.75*this.$wrapper.width()}),this.$wrapper.append(d.removeClass("hidden")),d},b.prototype.linkify=function(a){var b=this;return a.replace(b.urlPattern,'$&').replace(b.pseudoUrlPattern,'$1$2')}}(jQuery);var spinner=new Spinner({color:"#ddd"}),firebaseRef="https://brilliant-fire-2797.firebaseio.com",CryptoJS=CryptoJS||function(a,b){var c={},d=c.lib={},e=d.Base=function(){function a(){}return{extend:function(b){a.prototype=this;var c=new a;return b&&c.mixIn(b),c.$super=this,c},create:function(){var a=this.extend();return a.init.apply(a,arguments),a},init:function(){},mixIn:function(a){for(var b in a)a.hasOwnProperty(b)&&(this[b]=a[b]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.$super.extend(this)}}}(),f=d.WordArray=e.extend({init:function(a,c){a=this.words=a||[],this.sigBytes=c!=b?c:4*a.length},toString:function(a){return(a||h).stringify(this)},concat:function(a){var b=this.words,c=a.words,d=this.sigBytes,a=a.sigBytes;if(this.clamp(),d%4)for(var e=0;a>e;e++)b[d+e>>>2]|=(c[e>>>2]>>>24-8*(e%4)&255)<<24-8*((d+e)%4);else if(65535e;e+=4)b[d+e>>>2]=c[e>>>2];else b.push.apply(b,c);return this.sigBytes+=a,this},clamp:function(){var b=this.words,c=this.sigBytes;b[c>>>2]&=4294967295<<32-8*(c%4),b.length=a.ceil(c/4)},clone:function(){var a=e.clone.call(this);return a.words=this.words.slice(0),a},random:function(b){for(var c=[],d=0;b>d;d+=4)c.push(4294967296*a.random()|0);return f.create(c,b)}}),g=c.enc={},h=g.Hex={stringify:function(a){for(var b=a.words,a=a.sigBytes,c=[],d=0;a>d;d++){var e=b[d>>>2]>>>24-8*(d%4)&255;c.push((e>>>4).toString(16)),c.push((15&e).toString(16))}return c.join("")},parse:function(a){for(var b=a.length,c=[],d=0;b>d;d+=2)c[d>>>3]|=parseInt(a.substr(d,2),16)<<24-4*(d%8);return f.create(c,b/2)}},i=g.Latin1={stringify:function(a){for(var b=a.words,a=a.sigBytes,c=[],d=0;a>d;d++)c.push(String.fromCharCode(b[d>>>2]>>>24-8*(d%4)&255));return c.join("")},parse:function(a){for(var b=a.length,c=[],d=0;b>d;d++)c[d>>>2]|=(255&a.charCodeAt(d))<<24-8*(d%4);return f.create(c,b)}},j=g.Utf8={stringify:function(a){try{return decodeURIComponent(escape(i.stringify(a)))}catch(b){throw Error("Malformed UTF-8 data")}},parse:function(a){return i.parse(unescape(encodeURIComponent(a)))}},k=d.BufferedBlockAlgorithm=e.extend({reset:function(){this._data=f.create(),this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=j.parse(a)),this._data.concat(a),this._nDataBytes+=a.sigBytes},_process:function(b){var c=this._data,d=c.words,e=c.sigBytes,g=this.blockSize,h=e/(4*g),h=b?a.ceil(h):a.max((0|h)-this._minBufferSize,0),b=h*g,e=a.min(4*b,e);if(b){for(var i=0;b>i;i+=g)this._doProcessBlock(d,i);i=d.splice(0,b),c.sigBytes-=e}return f.create(i,e)},clone:function(){var a=e.clone.call(this);return a._data=this._data.clone(),a},_minBufferSize:0});d.Hasher=k.extend({init:function(){this.reset()},reset:function(){k.reset.call(this),this._doReset()},update:function(a){return this._append(a),this._process(),this},finalize:function(a){return a&&this._append(a),this._doFinalize(),this._hash},clone:function(){var a=k.clone.call(this);return a._hash=this._hash.clone(),a},blockSize:16,_createHelper:function(a){return function(b,c){return a.create(c).finalize(b)}},_createHmacHelper:function(a){return function(b,c){return l.HMAC.create(a,c).finalize(b)}}});var l=c.algo={};return c}(Math);!function(a){var b=CryptoJS,c=b.lib,d=c.WordArray,c=c.Hasher,e=b.algo,f=[],g=[];!function(){ -function b(b){for(var c=a.sqrt(b),d=2;c>=d;d++)if(!(b%d))return!1;return!0}function c(a){return 4294967296*(a-(0|a))|0}for(var d=2,e=0;64>e;)b(d)&&(8>e&&(f[e]=c(a.pow(d,.5))),g[e]=c(a.pow(d,1/3)),e++),d++}();var h=[],e=e.SHA256=c.extend({_doReset:function(){this._hash=d.create(f.slice(0))},_doProcessBlock:function(a,b){for(var c=this._hash.words,d=c[0],e=c[1],f=c[2],i=c[3],j=c[4],k=c[5],l=c[6],m=c[7],n=0;64>n;n++){if(16>n)h[n]=0|a[b+n];else{var o=h[n-15],p=h[n-2];h[n]=((o<<25|o>>>7)^(o<<14|o>>>18)^o>>>3)+h[n-7]+((p<<15|p>>>17)^(p<<13|p>>>19)^p>>>10)+h[n-16]}o=m+((j<<26|j>>>6)^(j<<21|j>>>11)^(j<<7|j>>>25))+(j&k^~j&l)+g[n]+h[n],p=((d<<30|d>>>2)^(d<<19|d>>>13)^(d<<10|d>>>22))+(d&e^d&f^e&f),m=l,l=k,k=j,j=i+o|0,i=f,f=e,e=d,d=o+p|0}c[0]=c[0]+d|0,c[1]=c[1]+e|0,c[2]=c[2]+f|0,c[3]=c[3]+i|0,c[4]=c[4]+j|0,c[5]=c[5]+k|0,c[6]=c[6]+l|0,c[7]=c[7]+m|0},_doFinalize:function(){var a=this._data,b=a.words,c=8*this._nDataBytes,d=8*a.sigBytes;b[d>>>5]|=128<<24-d%32,b[(d+64>>>9<<4)+15]=c,a.sigBytes=4*b.length,this._process()}});b.SHA256=c._createHelper(e),b.HmacSHA256=c._createHmacHelper(e)}(Math); \ No newline at end of file From 0a6031a710dc9250f424003c8ec6267eb3138c58 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 15 Jun 2015 09:15:28 -0400 Subject: [PATCH 24/29] Added single spec --- spec/Firebase-spec.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 spec/Firebase-spec.js diff --git a/spec/Firebase-spec.js b/spec/Firebase-spec.js new file mode 100644 index 0000000..7883218 --- /dev/null +++ b/spec/Firebase-spec.js @@ -0,0 +1,21 @@ +describe('Loaded Libraries', function() { + it('The Firebase library should be loaded', function() { + var createFirebase = function() { + return new Firebase('https://brilliant-fire-2797.firebaseio.com'); + }; + expect(createFirebase).not.toThrow(); + }); +}); + +describe("Firebase UserRef", function() { + it('should have a user Reference', function (done) { + loadFixtures('fixtures/index.html'); + var createFirebase = function() { + return new Firebase('https://brilliant-fire-2797.firebaseio.com'); + }; + var tokenGenerator = new FirebaseTokenGenerator("LENnUH4jYdZSk4864WZDk5VgojFCE1h7UTKXcBW3"); + var chatToken = tokenGenerator.createToken({uid: "custom:1", name: "Mark Nyon"}); + + var firebaseRef = createFirebase(); + }); +}); \ No newline at end of file From 8f6ce44459e6af5b4f397c71129d44ebe1f186fe Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Mon, 15 Jun 2015 09:17:01 -0400 Subject: [PATCH 25/29] Removed bad spec --- spec/Firebase-spec.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/spec/Firebase-spec.js b/spec/Firebase-spec.js index 7883218..ace10de 100644 --- a/spec/Firebase-spec.js +++ b/spec/Firebase-spec.js @@ -5,17 +5,4 @@ describe('Loaded Libraries', function() { }; expect(createFirebase).not.toThrow(); }); -}); - -describe("Firebase UserRef", function() { - it('should have a user Reference', function (done) { - loadFixtures('fixtures/index.html'); - var createFirebase = function() { - return new Firebase('https://brilliant-fire-2797.firebaseio.com'); - }; - var tokenGenerator = new FirebaseTokenGenerator("LENnUH4jYdZSk4864WZDk5VgojFCE1h7UTKXcBW3"); - var chatToken = tokenGenerator.createToken({uid: "custom:1", name: "Mark Nyon"}); - - var firebaseRef = createFirebase(); - }); }); \ No newline at end of file From c5c3cc760de8b9cb60c7ea061880cf0fc68bc697 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Wed, 17 Jun 2015 10:39:10 -0400 Subject: [PATCH 26/29] Library Initialize spec --- karma.conf.js | 2 +- package.json | 2 +- rules.json | 3 +++ spec/Firebase-spec.js | 19 ++++++++++++++++--- src/js/firechat-ui.js | 3 +-- src/js/firechat.js | 24 ++++++++++++++++++++++++ src/less/styles.less | 21 --------------------- templates/tab-content.html | 3 --- website/firechat-latest.css | 18 ------------------ website/firechat-latest.js | 30 +++++++++++++++++++++++++++--- website/index.html | 4 ++-- 11 files changed, 75 insertions(+), 54 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 85e436f..ddce953 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -20,7 +20,7 @@ module.exports = function(config) { 'https://cdn.firebase.com/js/client/2.0.2/firebase-debug.js', 'https://cdn.firebase.com/v0/firebase-token-generator.js', 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap-modal.min.js', - 'dist/*.js', + 'dist/firechat.js', 'spec/**/*spec.js', // this file only gets watched and is otherwise ignored ], diff --git a/package.json b/package.json index 8af7179..3d9a155 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ ], "main": "dist/firechat.js", "files": [ - "dist/**", + "templates" "LICENSE", "README.md", "package.json" diff --git a/rules.json b/rules.json index b0d9b05..827ef51 100644 --- a/rules.json +++ b/rules.json @@ -28,6 +28,9 @@ } } }, + "pano": { + ".read" : true + }, "room-messages": { "$roomId": { // A list of messages by room, viewable by anyone for public rooms, or authorized users for private rooms. diff --git a/spec/Firebase-spec.js b/spec/Firebase-spec.js index ace10de..a21c751 100644 --- a/spec/Firebase-spec.js +++ b/spec/Firebase-spec.js @@ -1,8 +1,21 @@ describe('Loaded Libraries', function() { - it('The Firebase library should be loaded', function() { - var createFirebase = function() { + var createFirebase = {}; + beforeEach(function () { + createFirebase = function() { return new Firebase('https://brilliant-fire-2797.firebaseio.com'); }; + }); + + it('The Firebase library should be loaded without raising an error', function() { expect(createFirebase).not.toThrow(); }); -}); \ No newline at end of file + + it('The Firechat library should be loaded without raising an error', function() { + var firechatRef = createFirebase(); + var createFirechat = function() { + return new Firechat(firechatRef); + }; + expect(createFirechat).not.toThrow(); + }); +}); + diff --git a/src/js/firechat-ui.js b/src/js/firechat-ui.js index d15f312..135b4ea 100644 --- a/src/js/firechat-ui.js +++ b/src/js/firechat-ui.js @@ -468,8 +468,6 @@ console.log("File with hash: " + imageFileName + ' created'); $('#file-upload').hide(); var roomId = $("textarea").attr("id").replace(/textarea/, ""); - var message = self.trimWithEllipsis("File Uploaded from " + self._chat._userName, self.maxLengthMessage); - self._chat.sendMessage(roomId, message); f.once('value', function(snap) { var payload = snap.val(); if (payload !== null) { @@ -478,6 +476,7 @@ uploadImg.appendTo($(".message").last()); uploadImg.width(313); uploadImg.show(); + self._chat.sendMessage(roomId, message); } else { $('#body').append("Not found"); } diff --git a/src/js/firechat.js b/src/js/firechat.js index 4f62f6e..fe94d89 100644 --- a/src/js/firechat.js +++ b/src/js/firechat.js @@ -407,6 +407,30 @@ newMessageRef.setWithPriority(message, Firebase.ServerValue.TIMESTAMP, cb); }; + Firechat.prototype.sendPhotoMessage = function(roomId, payload, messageType, cb) { + var self = this, + message = { + userId: self._userId, + name: self._userName, + timestamp: Firebase.ServerValue.TIMESTAMP, + message: payload, + type: 'image' + }, + newMessageRef; + + if (!self._user) { + self._onAuthRequired(); + if (cb) { + cb(new Error('Not authenticated or user not set!')); + } + return; + } + + newMessageRef = self._messageRef.child(roomId).push(); + newMessageRef.setWithPriority(message, Firebase.ServerValue.TIMESTAMP, cb); + }; + + Firechat.prototype.deleteMessage = function(roomId, messageId, cb) { var self = this; diff --git a/src/less/styles.less b/src/less/styles.less index 578ee8f..a609d4d 100644 --- a/src/less/styles.less +++ b/src/less/styles.less @@ -604,27 +604,6 @@ height: 35px; } - #uploaded-image { - display: none; - } - - #upload-icon { - position: absolute; - float: right; - height: 16px; - width: 18px; - bottom: 0px; - right: 5px; - } - - #file-upload { - display: none; - position: relative; - overflow: hidden; - z-index: 2; - opacity: 0; - } - .message { color: #333; padding: 3px 5px; diff --git a/templates/tab-content.html b/templates/tab-content.html index 84209bc..37f36ef 100644 --- a/templates/tab-content.html +++ b/templates/tab-content.html @@ -32,9 +32,6 @@
                                                                          -
                                                                          diff --git a/website/firechat-latest.css b/website/firechat-latest.css index 3a0ead6..7acecae 100644 --- a/website/firechat-latest.css +++ b/website/firechat-latest.css @@ -824,24 +824,6 @@ float: left; height: 35px; } -#firechat #uploaded-image { - display: none; -} -#firechat #upload-icon { - position: absolute; - float: right; - height: 16px; - width: 18px; - bottom: 0px; - right: 5px; -} -#firechat #file-upload { - display: none; - position: relative; - overflow: hidden; - z-index: 2; - opacity: 0; -} #firechat .message { color: #333; padding: 3px 5px; diff --git a/website/firechat-latest.js b/website/firechat-latest.js index d25c3dc..d8ba16b 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -36,7 +36,7 @@ this["FirechatDefaultTemplates"]["templates/room-user-list-item.html"] = functio this["FirechatDefaultTemplates"]["templates/room-user-search-list-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                        • \n\n'; if (disableActions) { ;__p += '\n' +__e( name ) +'\n'; } else { ;__p += '\n' +__e( name ) +'\n+\n'; } ;__p += '\n\n
                                                                        • ';}return __p}; -this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                          \n
                                                                          \n\n\nIn Room\n\n\n
                                                                          \n
                                                                            \n
                                                                            \n
                                                                            \n\n+\nInvite\n\n
                                                                            \n
                                                                            \n
                                                                            \n\n\n
                                                                            \n
                                                                            \n
                                                                              \n
                                                                              \n
                                                                              \n
                                                                              \n
                                                                              \n\n
                                                                              \n\n\n
                                                                              \n
                                                                              ';}return __p}; +this["FirechatDefaultTemplates"]["templates/tab-content.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                              \n
                                                                              \n\n\nIn Room\n\n\n
                                                                              \n
                                                                                \n
                                                                                \n
                                                                                \n\n+\nInvite\n\n
                                                                                \n
                                                                                \n
                                                                                \n\n\n
                                                                                \n
                                                                                \n
                                                                                  \n
                                                                                  \n
                                                                                  \n
                                                                                  \n
                                                                                  \n\n
                                                                                  \n\n\n
                                                                                  \n
                                                                                  ';}return __p}; this["FirechatDefaultTemplates"]["templates/tab-menu-item.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                                • \n' +__e( name ) +'\n
                                                                                • ';}return __p}; @@ -486,6 +486,30 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct newMessageRef.setWithPriority(message, Firebase.ServerValue.TIMESTAMP, cb); }; + Firechat.prototype.sendPhotoMessage = function(roomId, payload, messageType, cb) { + var self = this, + message = { + userId: self._userId, + name: self._userName, + timestamp: Firebase.ServerValue.TIMESTAMP, + message: payload, + type: 'image' + }, + newMessageRef; + + if (!self._user) { + self._onAuthRequired(); + if (cb) { + cb(new Error('Not authenticated or user not set!')); + } + return; + } + + newMessageRef = self._messageRef.child(roomId).push(); + newMessageRef.setWithPriority(message, Firebase.ServerValue.TIMESTAMP, cb); + }; + + Firechat.prototype.deleteMessage = function(roomId, messageId, cb) { var self = this; @@ -1190,8 +1214,6 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct console.log("File with hash: " + imageFileName + ' created'); $('#file-upload').hide(); var roomId = $("textarea").attr("id").replace(/textarea/, ""); - var message = self.trimWithEllipsis("File Uploaded from " + self._chat._userName, self.maxLengthMessage); - self._chat.sendMessage(roomId, message); f.once('value', function(snap) { var payload = snap.val(); if (payload !== null) { @@ -1200,6 +1222,7 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct uploadImg.appendTo($(".message").last()); uploadImg.width(313); uploadImg.show(); + self._chat.sendMessage(roomId, message); } else { $('#body').append("Not found"); } @@ -1780,6 +1803,7 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct // Also trim the message length to some client-defined maximum. var messageConstructed = ''; message.message = _.map(message.message.split(' '), function(token) { + console.log("ShowMessage: " + token); if (self.urlPattern.test(token) || self.pseudoUrlPattern.test(token)) { return self.linkify(encodeURI(token)); } else { diff --git a/website/index.html b/website/index.html index 6536b56..d18b4ae 100644 --- a/website/index.html +++ b/website/index.html @@ -174,9 +174,9 @@

                                                                                  Authenticate to continue

                                                                                  - + - + From 4d015a77568636a5a321724741d9d07f5fb0272e Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Wed, 17 Jun 2015 16:44:49 -0400 Subject: [PATCH 27/29] Image inline fixed --- src/js/firechat-ui.js | 42 +++++++++++++++----------------- src/js/firepano.js | 4 +-- website/firechat-latest.js | 50 +++++++++++++++++++------------------- website/index.html | 4 +-- 4 files changed, 49 insertions(+), 51 deletions(-) diff --git a/src/js/firechat-ui.js b/src/js/firechat-ui.js index 135b4ea..ff9912c 100644 --- a/src/js/firechat-ui.js +++ b/src/js/firechat-ui.js @@ -39,12 +39,13 @@ this.maxLengthUsername = 15; this.maxLengthUsernameDisplay = 15; this.maxLengthRoomName = 24; - this.maxLengthMessage = 120; + this.maxLengthMessage = 200; this.maxUserSearchResults = 100; // Define some useful regexes. this.urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim; this.pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim; + this.imgPattern = /data:image.*$/gim; this._renderLayout(); @@ -460,7 +461,6 @@ // Generate a location that can't be guessed using the file's contents and a random number var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); var f = new Firebase(firebaseRef + '/pano/' + hash + '/filePayload'); - spinner.spin(document.getElementById('spin')); // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview f.set(filePayload, function() { spinner.stop(); @@ -468,20 +468,8 @@ console.log("File with hash: " + imageFileName + ' created'); $('#file-upload').hide(); var roomId = $("textarea").attr("id").replace(/textarea/, ""); - f.once('value', function(snap) { - var payload = snap.val(); - if (payload !== null) { - var uploadImg = $(''); - uploadImg.attr("src", payload); - uploadImg.appendTo($(".message").last()); - uploadImg.width(313); - uploadImg.show(); - self._chat.sendMessage(roomId, message); - } else { - $('#body').append("Not found"); - } - spinner.stop(); - }); + var message = imageFileName; + self._chat.sendMessage(roomId, e.target.result); }); }; })(f); @@ -1055,16 +1043,20 @@ // While other data is escaped in the Underscore.js templates, escape and // process the message content here to add additional functionality (add links). // Also trim the message length to some client-defined maximum. - var messageConstructed = ''; message.message = _.map(message.message.split(' '), function(token) { - if (self.urlPattern.test(token) || self.pseudoUrlPattern.test(token)) { + if (self.imgPattern.test(token)) { + return ""; + } else if (self.urlPattern.test(token) || self.pseudoUrlPattern.test(token)) { return self.linkify(encodeURI(token)); } else { return _.escape(token); } }).join(' '); - message.message = self.trimWithEllipsis(message.message, self.maxLengthMessage); + console.log("Message message = " + message.message + "for raw message " + rawMessage.message + " with id: " + rawMessage.id); + if (!(message.message.search(self.imgPattern.test()))) { + message.message = self.trimWithEllipsis(message.message, self.maxLengthMessage); + } // Populate and render the message template. var template = FirechatDefaultTemplates["templates/message.html"]; var $message = $(template(message)); @@ -1205,9 +1197,15 @@ // see http://stackoverflow.com/questions/37684/how-to-replace-plain-urls-with-links FirechatUI.prototype.linkify = function(str) { var self = this; - return str - .replace(self.urlPattern, '$&') - .replace(self.pseudoUrlPattern, '$1$2'); + if (self.imgPattern.test(str)) { + console.log("image link with " + str); + return ''; + } else { + console.log("Not an image link with" + str); + return str + .replace(self.urlPattern, '$&') + .replace(self.pseudoUrlPattern, '$1$2'); + } }; })(jQuery); diff --git a/src/js/firepano.js b/src/js/firepano.js index 5140035..2d88c1f 100644 --- a/src/js/firepano.js +++ b/src/js/firepano.js @@ -12,11 +12,11 @@ function handleFileSelect(evt) { // Generate a location that can't be guessed using the file's contents and a random number var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); + // Retrieve new posts as they are added to our database spinner.spin(document.getElementById('spin')); // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview f.set(filePayload, function() { - spinner.stop(); - console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created') + console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created'); }); }; })(f); diff --git a/website/firechat-latest.js b/website/firechat-latest.js index d8ba16b..e377f38 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -14,6 +14,8 @@ this["FirechatDefaultTemplates"]["templates/layout-popout.html"] = function(obj) this["FirechatDefaultTemplates"]["templates/message-context-menu.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                                  \n\n
                                                                                  ';}return __p}; +this["FirechatDefaultTemplates"]["templates/message-image-upload.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += 'message-image-upload.html';}return __p}; + this["FirechatDefaultTemplates"]["templates/message.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape, __j = Array.prototype.join;function print() { __p += __j.call(arguments, '') }with (obj) {__p += '
                                                                                  \n
                                                                                  \n'; if (!disableActions) { ;__p += '\n\n'; } ;__p += '
                                                                                  \n
                                                                                  \n' +((__t = ( message )) == null ? '' : __t) +'\n
                                                                                  \n
                                                                                  ';}return __p}; this["FirechatDefaultTemplates"]["templates/prompt-alert.html"] = function(obj) {obj || (obj = {});var __t, __p = '', __e = _.escape;with (obj) {__p += '
                                                                                  \n
                                                                                  ' +__e( message ) +'
                                                                                  \n

                                                                                  \n\n

                                                                                  \n
                                                                                  ';}return __p}; @@ -785,12 +787,13 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct this.maxLengthUsername = 15; this.maxLengthUsernameDisplay = 15; this.maxLengthRoomName = 24; - this.maxLengthMessage = 120; + this.maxLengthMessage = 200; this.maxUserSearchResults = 100; // Define some useful regexes. this.urlPattern = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim; this.pseudoUrlPattern = /(^|[^\/])(www\.[\S]+(\b|$))/gim; + this.imgPattern = /data:image.*$/gim; this._renderLayout(); @@ -1206,7 +1209,6 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct // Generate a location that can't be guessed using the file's contents and a random number var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); var f = new Firebase(firebaseRef + '/pano/' + hash + '/filePayload'); - spinner.spin(document.getElementById('spin')); // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview f.set(filePayload, function() { spinner.stop(); @@ -1214,20 +1216,8 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct console.log("File with hash: " + imageFileName + ' created'); $('#file-upload').hide(); var roomId = $("textarea").attr("id").replace(/textarea/, ""); - f.once('value', function(snap) { - var payload = snap.val(); - if (payload !== null) { - var uploadImg = $(''); - uploadImg.attr("src", payload); - uploadImg.appendTo($(".message").last()); - uploadImg.width(313); - uploadImg.show(); - self._chat.sendMessage(roomId, message); - } else { - $('#body').append("Not found"); - } - spinner.stop(); - }); + var message = imageFileName; + self._chat.sendMessage(roomId, e.target.result); }); }; })(f); @@ -1801,17 +1791,21 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct // While other data is escaped in the Underscore.js templates, escape and // process the message content here to add additional functionality (add links). // Also trim the message length to some client-defined maximum. - var messageConstructed = ''; message.message = _.map(message.message.split(' '), function(token) { - console.log("ShowMessage: " + token); - if (self.urlPattern.test(token) || self.pseudoUrlPattern.test(token)) { + if (self.imgPattern.test(token)) { + return ""; + } else if (self.urlPattern.test(token) || self.pseudoUrlPattern.test(token)) { return self.linkify(encodeURI(token)); } else { return _.escape(token); } }).join(' '); - message.message = self.trimWithEllipsis(message.message, self.maxLengthMessage); + console.log("Message message = " + message.message + "for raw message " + rawMessage.message + " with id: " + rawMessage.id); + if (!(message.message.search(self.imgPattern.test()))) { + console.log("The imgPattern " + self.imgPattern + " doesn't match" + message.message); + message.message = self.trimWithEllipsis(message.message, self.maxLengthMessage); + } // Populate and render the message template. var template = FirechatDefaultTemplates["templates/message.html"]; var $message = $(template(message)); @@ -1952,9 +1946,15 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct // see http://stackoverflow.com/questions/37684/how-to-replace-plain-urls-with-links FirechatUI.prototype.linkify = function(str) { var self = this; - return str - .replace(self.urlPattern, '$&') - .replace(self.pseudoUrlPattern, '$1$2'); + if (self.imgPattern.test(str)) { + console.log("image link with " + str); + return ''; + } else { + console.log("Not an image link with" + str); + return str + .replace(self.urlPattern, '$&') + .replace(self.pseudoUrlPattern, '$1$2'); + } }; })(jQuery); @@ -1973,11 +1973,11 @@ function handleFileSelect(evt) { // Generate a location that can't be guessed using the file's contents and a random number var hash = CryptoJS.SHA256(Math.random() + CryptoJS.SHA256(filePayload)); var f = new Firebase(firebaseRef + 'pano/' + hash + '/filePayload'); + // Retrieve new posts as they are added to our database spinner.spin(document.getElementById('spin')); // Set the file payload to Firebase and register an onComplete handler to stop the spinner and show the preview f.set(filePayload, function() { - spinner.stop(); - console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created') + console.log("File with hash: " + firebaseRef + 'pano/' + hash + '/filePayload created'); }); }; })(f); diff --git a/website/index.html b/website/index.html index d18b4ae..029ac2f 100644 --- a/website/index.html +++ b/website/index.html @@ -174,9 +174,9 @@

                                                                                  Authenticate to continue

                                                                                  - + - + From d8f4f56fc558d3d21165f5f824773272a6fc1d61 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Wed, 17 Jun 2015 17:10:06 -0400 Subject: [PATCH 28/29] Fixed licensing --- package.json | 2 +- src/js/firechat-ui.js | 2 +- website/firechat-latest.js | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 3d9a155..479a8f5 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ ], "main": "dist/firechat.js", "files": [ - "templates" + "templates", "LICENSE", "README.md", "package.json" diff --git a/src/js/firechat-ui.js b/src/js/firechat-ui.js index ff9912c..9ed8713 100644 --- a/src/js/firechat-ui.js +++ b/src/js/firechat-ui.js @@ -1199,7 +1199,7 @@ var self = this; if (self.imgPattern.test(str)) { console.log("image link with " + str); - return ''; + return ''; } else { console.log("Not an image link with" + str); return str diff --git a/website/firechat-latest.js b/website/firechat-latest.js index e377f38..324dce7 100644 --- a/website/firechat-latest.js +++ b/website/firechat-latest.js @@ -1803,7 +1803,6 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct console.log("Message message = " + message.message + "for raw message " + rawMessage.message + " with id: " + rawMessage.id); if (!(message.message.search(self.imgPattern.test()))) { - console.log("The imgPattern " + self.imgPattern + " doesn't match" + message.message); message.message = self.trimWithEllipsis(message.message, self.maxLengthMessage); } // Populate and render the message template. @@ -1948,7 +1947,7 @@ this["FirechatDefaultTemplates"]["templates/user-search-list-item.html"] = funct var self = this; if (self.imgPattern.test(str)) { console.log("image link with " + str); - return ''; + return ''; } else { console.log("Not an image link with" + str); return str From 2569ca75a71ad06daa99d2da4efda87eb51a4836 Mon Sep 17 00:00:00 2001 From: Mark Nyon Date: Fri, 3 Jul 2015 22:20:37 -0400 Subject: [PATCH 29/29] Updated karma files with proper firechat.js The test was referring to the wrong Firechat.js file. This fixes that by referring to the website/firechat-latest.js output of the grunt build task --- karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/karma.conf.js b/karma.conf.js index ddce953..fcde7dd 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -20,7 +20,7 @@ module.exports = function(config) { 'https://cdn.firebase.com/js/client/2.0.2/firebase-debug.js', 'https://cdn.firebase.com/v0/firebase-token-generator.js', 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap-modal.min.js', - 'dist/firechat.js', + 'website/firechat-latest.js', 'spec/**/*spec.js', // this file only gets watched and is otherwise ignored ],