Browse Source

Merge with upstream. Fix conflicts in settings.js. Fix jshint errors.

pull/40/head
Evan Theurer 11 years ago
parent
commit
46bcf9b928
  1. 5
      .gitignore
  2. 8
      .jshint
  3. 4
      .travis.yml
  4. 1
      COPYING
  5. 1
      ChangeLog
  6. 174
      Makefile
  7. 179
      Makefile.am
  8. 1
      NEWS
  9. 1
      README
  10. 21
      README.md
  11. 22
      autogen.sh
  12. 7
      build/build.js
  13. 110
      configure.ac
  14. 61
      debian/changelog
  15. 10
      doc/CHANNELING-API.txt
  16. 32
      doc/CROSSCOMPILE.txt
  17. 6
      doc/REST-API.txt
  18. 4
      doc/plugin-example.js
  19. 18
      doc/plugin-test-authorize.js
  20. 10
      html/crawler.html
  21. 1
      html/head.html
  22. 2
      html/logo.html
  23. 10
      server.conf.in
  24. 2
      spreed-speakfreely-server
  25. 2
      spreed-webrtc-server
  26. 4
      src/app/spreed-webrtc-server/api.go
  27. 4
      src/app/spreed-webrtc-server/buffercache.go
  28. 4
      src/app/spreed-webrtc-server/channeling.go
  29. 4
      src/app/spreed-webrtc-server/config.go
  30. 4
      src/app/spreed-webrtc-server/connection.go
  31. 6
      src/app/spreed-webrtc-server/context.go
  32. 4
      src/app/spreed-webrtc-server/hub.go
  33. 5
      src/app/spreed-webrtc-server/images.go
  34. 32
      src/app/spreed-webrtc-server/main.go
  35. 4
      src/app/spreed-webrtc-server/random.go
  36. 4
      src/app/spreed-webrtc-server/rooms.go
  37. 4
      src/app/spreed-webrtc-server/roomworker.go
  38. 4
      src/app/spreed-webrtc-server/server.go
  39. 4
      src/app/spreed-webrtc-server/session.go
  40. 4
      src/app/spreed-webrtc-server/sessions.go
  41. 0
      src/app/spreed-webrtc-server/sleepy/core.go
  42. 4
      src/app/spreed-webrtc-server/stats.go
  43. 0
      src/app/spreed-webrtc-server/tls.go
  44. 4
      src/app/spreed-webrtc-server/tokenprovider.go
  45. 4
      src/app/spreed-webrtc-server/tokens.go
  46. 4
      src/app/spreed-webrtc-server/users.go
  47. 4
      src/app/spreed-webrtc-server/ws.go
  48. BIN
      src/artwork/spreedmeLogo.png
  49. 179
      src/artwork/spreedmeLogo.svg
  50. 73
      src/hooks/pre-commit.hook
  51. 2
      src/i18n/Makefile
  52. 14
      src/i18n/messages-de.po
  53. 14
      src/i18n/messages-ja.po
  54. 16
      src/i18n/messages-ko.po
  55. 14
      src/i18n/messages-zh-cn.po
  56. 14
      src/i18n/messages-zh-tw.po
  57. 10
      src/i18n/messages.pot
  58. 4
      src/styles/_shame.scss
  59. 4
      src/styles/components/_audiolevel.scss
  60. 4
      src/styles/components/_audiovideo.scss
  61. 27
      src/styles/components/_bar.scss
  62. 16
      src/styles/components/_buddylist.scss
  63. 8
      src/styles/components/_chat.scss
  64. 8
      src/styles/components/_fileinfo.scss
  65. 4
      src/styles/components/_rightslide.scss
  66. 4
      src/styles/components/_roombar.scss
  67. 4
      src/styles/components/_screenshare.scss
  68. 4
      src/styles/components/_settings.scss
  69. 4
      src/styles/components/_social.scss
  70. 4
      src/styles/components/_usability.scss
  71. 4
      src/styles/global/_angular.scss
  72. 4
      src/styles/global/_animations.scss
  73. 5
      src/styles/global/_base.scss
  74. 4
      src/styles/global/_nicescroll.scss
  75. 10
      src/styles/global/_overlaybar.scss
  76. 40
      src/styles/global/_variables.scss
  77. 4
      src/styles/libs/_dialogs.scss
  78. 4
      src/styles/main.scss
  79. BIN
      static/img/opengraph-image.png
  80. 322
      static/js/app.js
  81. 7
      static/js/base.js
  82. 927
      static/js/controllers/chatroomcontroller.js
  83. 43
      static/js/controllers/controllers.js
  84. 1491
      static/js/controllers/mediastreamcontroller.js
  85. 95
      static/js/controllers/roomchangecontroller.js
  86. 38
      static/js/controllers/statusmessagecontroller.js
  87. 46
      static/js/directives/audiolevel.js
  88. 597
      static/js/directives/audiovideo.js
  89. 222
      static/js/directives/buddylist.js
  90. 893
      static/js/directives/chat.js
  91. 83
      static/js/directives/directives.js
  92. 16
      static/js/directives/fileinfo.js
  93. 40
      static/js/directives/onenter.js
  94. 40
      static/js/directives/onescape.js
  95. 4
      static/js/directives/page.js
  96. 90
      static/js/directives/roombar.js
  97. 60
      static/js/directives/screenshare.js
  98. 452
      static/js/directives/settings.js
  99. 10
      static/js/directives/socialshare.js
  100. 4
      static/js/directives/statusmessage.js
  101. Some files were not shown because too many files have changed in this diff Show More

5
.gitignore vendored

@ -16,11 +16,6 @@
/tokens.txt /tokens.txt
/dist /dist
*~ *~
debian/*.debhelper
debian/*.substvars
debian/spreed-webcaller
debian/files
debian/tmp
vendor/* vendor/*
/dist_* /dist_*
/build/out/ /build/out/

8
.jshint

@ -0,0 +1,8 @@
{
"smarttabs": true,
"onecase": true,
"curly": true,
"forin": true,
"trailing": true,
"asi": true
}

4
.travis.yml

@ -1,5 +1,5 @@
# stats available at # stats available at
# https://travis-ci.org/strukturag/spreed-speakfreely/ # https://travis-ci.org/strukturag/spreed-webrtc/
language: go language: go
go: go:
@ -21,6 +21,8 @@ install:
- sudo npm install -g autoprefixer - sudo npm install -g autoprefixer
script: script:
- ./autogen.sh
- ./configure
- make get - make get
- make styles - make styles
- make javascript - make javascript

1
COPYING

@ -0,0 +1 @@
See LICENSE for further information.

1
ChangeLog

@ -0,0 +1 @@
See debian/changelog or https://github.com/strukturag/spreed-webrtc for further information.

174
Makefile

@ -1,174 +0,0 @@
#
# Spreed Speak Freely.
# Copyright (C) 2013-2014 struktur AG
#
# This file is part of Spreed Speak Freely.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
PKG := app/spreed-speakfreely-server
EXENAME := spreed-speakfreely-server
CONFIG_FILE ?= spreed-speakfreely-server.conf
CONFIG_PATH ?= /etc
VENDOR = "$(CURDIR)/vendor"
GOPATH = "$(VENDOR):$(CURDIR)"
SYSTEM_GOPATH := /usr/share/gocode/src/
OUTPUT := $(CURDIR)/bin
OUTPUT_JS := $(CURDIR)/build/out
VERSION := $(shell dpkg-parsechangelog | sed -n 's/^Version: //p')
DESTDIR ?= /
BIN := $(DESTDIR)/usr/sbin
CONF := $(DESTDIR)/$(CONFIG_PATH)
SHARE := $(DESTDIR)/usr/share/spreed-speakfreely-server
BUILD_ARCH := $(shell go env GOARCH)
DIST := $(CURDIR)/dist_$(BUILD_ARCH)
DIST_SRC := $(DIST)/src
DIST_BIN := $(DIST)/bin
NODEJS_BIN := $(shell which nodejs)
ifeq ("$(NODEJS_BIN)", "")
NODEJS_BIN := $(shell which node)
endif
NODEJS_BIN_EXISTS := $(shell [ -x "$(NODEJS_BIN)" ] && echo 1 || echo 0)
ifneq ($(NODEJS_BIN_EXISTS), 1)
$(error "Can't find node.js runtime, please install / check your PATH")
endif
# Tools
AUTOPREFIXER_BROWSER_SUPPORT := "> 1%, last 2 versions, Firefox ESR, Opera 12.1"
build: get binary assets
gopath:
@echo GOPATH=$(GOPATH)
get:
GOPATH=$(GOPATH) go get $(PKG)
getupdate:
rm -rf vendor/*
GOPATH=$(GOPATH) go get $(PKG)
binary:
GOPATH=$(GOPATH) go build -o $(OUTPUT)/$(EXENAME) -ldflags '$(LDFLAGS)' $(PKG)
binaryrace:
GOPATH=$(GOPATH) go build -race -o $(OUTPUT)/$(EXENAME) -ldflags '$(LDFLAGS)' $(PKG)
binaryall:
GOPATH=$(GOPATH) go build -a -o $(OUTPUT)/$(EXENAME) -ldflags '$(LDFLAGS)' $(PKG)
fmt:
GOPATH=$(GOPATH) go fmt app/...
test: TESTDEPS = $(shell GOPATH=$(GOPATH) go list -f '{{.ImportPath}}{{"\n"}}{{join .Deps "\n"}}' $(PKG) |grep $(PKG))
test: get
GOPATH=$(GOPATH) go test -i $(TESTDEPS)
GOPATH=$(GOPATH) go test -v $(TESTDEPS)
assets: styles javascript
styles: SASSFLAGS = --style=expanded
styles:
mkdir -p $(CURDIR)/static/css
mkdir -p $(CURDIR)/static/fonts
cp -r $(CURDIR)/src/styles/libs/font-awesome/fonts/font* $(CURDIR)/static/fonts
sass --compass --scss $(SASSFLAGS) \
$(CURDIR)/src/styles/main.scss:$(CURDIR)/static/css/main.min.css
autoprefixer --browsers $(AUTOPREFIXER_BROWSER_SUPPORT) $(CURDIR)/static/css/main.min.css
sass --compass --scss $(SASSFLAGS) \
$(CURDIR)/src/styles/bootstrap.scss:$(CURDIR)/static/css/bootstrap.min.css
sass --compass --scss $(SASSFLAGS) \
$(CURDIR)/src/styles/font-awesome.scss:$(CURDIR)/static/css/font-awesome.min.css
releaseassets: RJSFLAGS = generateSourceMaps=false preserveLicenseComments=true
releaseassets: SASSFLAGS = --style=compressed --no-cache
releaseassets: dist_gopath assets
javascript:
mkdir -p $(OUTPUT_JS)
$(NODEJS_BIN) $(CURDIR)/build/r.js \
-o $(CURDIR)/build/build.js \
dir=$(OUTPUT_JS) $(RJSFLAGS)
release: GOPATH = "$(DIST):$(VENDOR):$(CURDIR)"
release: LDFLAGS = -X main.version $(VERSION) -X main.defaultConfig $(CONFIG_PATH)/$(CONFIG_FILE)
release: OUTPUT = $(DIST_BIN)
release: dist_gopath $(DIST_BIN) binary releaseassets
releasetest: GOPATH = "$(DIST):$(VENDOR):$(CURDIR)"
releasetest: dist_gopath test
install:
echo $(BIN)
echo $(SHARE)
install -d $(BIN) $(CONF)
install -d $(SHARE)/www/html
install -d $(SHARE)/www/static
install -d $(SHARE)/www/static/img
install -d $(SHARE)/www/static/sounds
install -d $(SHARE)/www/static/fonts
install -d $(SHARE)/www/static/translation
install -d $(SHARE)/www/static/css
install $(DIST_BIN)/* $(BIN)
install -m 644 server.conf.in $(CONF)/$(CONFIG_FILE)
install html/* $(SHARE)/www/html
install static/img/* $(SHARE)/www/static/img
install static/sounds/* $(SHARE)/www/static/sounds
install static/fonts/* $(SHARE)/www/static/fonts
install static/translation/* $(SHARE)/www/static/translation
install static/css/* $(SHARE)/www/static/css
install -D static/js/libs/require/require.js $(SHARE)/www/static/js/libs/require/require.js
install $(OUTPUT_JS)/*.js $(SHARE)/www/static/js
clean:
GOPATH=$(GOPATH) go clean -i $(PKG)
rm -rf $(CURDIR)/pkg
rm -rf $(CURDIR)/static/css
rm -rf $(CURDIR)/static/fonts
rm -rf $(CURDIR)/build/out
distclean: clean
rm -rf $(DIST)
pristine: distclean
rm -f server.conf
rm -rf vendor/*
$(DIST_SRC):
mkdir -p $@
$(DIST_BIN):
mkdir -p $@
dist_gopath: $(DIST_SRC)
find $(SYSTEM_GOPATH) -mindepth 1 -maxdepth 1 -type d \
-exec ln -sf {} $(DIST_SRC) \;
tarball: PACKAGE_NAME = $(EXENAME)-$(VERSION)
tarball: TARPATH = $(DIST)/$(PACKAGE_NAME)
tarball: BIN = $(TARPATH)/loader
tarball: CONF = $(TARPATH)/loader
tarball: DOCS = $(CONF)/docs
tarball: SHARE = $(TARPATH)/
tarball: distclean release install
echo -n $(VERSION) > $(TARPATH)/version.txt
tar czf $(DIST)/$(PACKAGE_NAME).tar.gz -C $(DIST) $(PACKAGE_NAME)
.PHONY: clean distclean pristine get getupdate build styles javascript release releasetest dist_gopath install gopath binary binaryrace binaryall tarball assets

179
Makefile.am

@ -0,0 +1,179 @@
#
# Spreed WebRTC.
# Copyright (C) 2013-2014 struktur AG
#
# This file is part of Spreed WebRTC.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
AUTOMAKE_OPTIONS = -Wno-portability
PKG := app/spreed-webrtc-server
EXENAME := spreed-webrtc-server
CONFIG_FILE ?= spreed-webrtc-server.conf
CONFIG_PATH ?= /etc
VENDOR = "$(CURDIR)/vendor"
GOPATH = "$(VENDOR):$(CURDIR)"
SYSTEM_GOPATH := /usr/share/gocode/src/
OUTPUT := $(CURDIR)/bin
OUTPUT_JS := $(CURDIR)/build/out
DESTDIR ?= /
BIN := $(DESTDIR)/usr/sbin
CONFIG_DIR := $(DESTDIR)/$(CONFIG_PATH)
SHARE := $(DESTDIR)/usr/share/spreed-webrtc-server
BUILD_ARCH := $(shell $(GO) env GOARCH)
BUILD_OS := $(shell go env GOOS)
DIST := $(CURDIR)/dist_$(BUILD_ARCH)
DIST_SRC := $(DIST)/src
DIST_BIN := $(DIST)/bin
# Tools
AUTOPREFIXER_BROWSER_SUPPORT := "> 1%, last 2 versions, Firefox ESR, Opera 12.1"
all: build
build: get binary assets
gopath:
@echo GOPATH=$(GOPATH)
get:
GOPATH=$(GOPATH) $(GO) get $(PKG)
getupdate:
rm -rf vendor/*
GOPATH=$(GOPATH) $(GO) get $(PKG)
binary:
GOPATH=$(GOPATH) $(GO) build -o $(OUTPUT)/$(EXENAME) -ldflags '$(LDFLAGS)' $(PKG)
binaryrace:
GOPATH=$(GOPATH) $(GO) build -race -o $(OUTPUT)/$(EXENAME) -ldflags '$(LDFLAGS)' $(PKG)
binaryall:
GOPATH=$(GOPATH) $(GO) build -a -o $(OUTPUT)/$(EXENAME) -ldflags '$(LDFLAGS)' $(PKG)
fmt:
GOPATH=$(GOPATH) $(GO) fmt app/...
test: TESTDEPS = $(shell GOPATH=$(GOPATH) $(GO) list -f '{{.ImportPath}}{{"\n"}}{{join .Deps "\n"}}' $(PKG) | $(GREP) $(PKG))
test: get
GOPATH=$(GOPATH) $(GO) test -i $(TESTDEPS)
GOPATH=$(GOPATH) $(GO) test -v $(TESTDEPS)
assets: styles javascript
styles: SASSFLAGS = --style=expanded
styles:
$(MKDIR_P) $(CURDIR)/static/css
$(MKDIR_P) $(CURDIR)/static/fonts
cp -r $(CURDIR)/src/styles/libs/font-awesome/fonts/font* $(CURDIR)/static/fonts
$(SASS) --compass --scss $(SASSFLAGS) \
$(CURDIR)/src/styles/main.scss:$(CURDIR)/static/css/main.min.css
$(AUTOPREFIXER) --browsers $(AUTOPREFIXER_BROWSER_SUPPORT) $(CURDIR)/static/css/main.min.css
$(SASS) --compass --scss $(SASSFLAGS) \
$(CURDIR)/src/styles/bootstrap.scss:$(CURDIR)/static/css/bootstrap.min.css
$(SASS) --compass --scss $(SASSFLAGS) \
$(CURDIR)/src/styles/font-awesome.scss:$(CURDIR)/static/css/font-awesome.min.css
styleshint:
$(FIND) src/styles -maxdepth 1 -name "*.scss" -print0 | xargs -0 -n1 $(SASS) --compass --scss $(SASSFLAGS) -c
releaseassets: RJSFLAGS = generateSourceMaps=false preserveLicenseComments=true
releaseassets: SASSFLAGS = --style=compressed --no-cache
releaseassets: dist_gopath assets
javascript:
$(MKDIR_P) $(OUTPUT_JS)
$(NODEJS) $(CURDIR)/build/r.js \
-o $(CURDIR)/build/build.js \
dir=$(OUTPUT_JS) $(RJSFLAGS)
jshint:
@if [ "$(JSHINT)" = "" ]; then echo "Command 'jshint' not found"; exit 1; fi
$(FIND) static/ -wholename static/js/libs -prune -o -name "*.js" -print0 | xargs -0 -n1 $(JSHINT) --config .jshint
jsbeautify:
@if [ "$(JS_BEAUTIFY)" = "" ]; then echo "Command 'js-beautify' not found"; exit 1; fi
$(FIND) static/ \( -path static/js/libs -o -path static/translation \) -prune -o -name "*.js" -exec $(JS_BEAUTIFY) -t -o {}.new {} \; -exec mv -f {}.new {} \;
release: GOPATH = "$(DIST):$(VENDOR):$(CURDIR)"
release: LDFLAGS = -X main.version $(PACKAGE_VERSION) -X main.defaultConfig $(CONFIG_PATH)/$(CONFIG_FILE)
release: OUTPUT = $(DIST_BIN)
release: dist_gopath $(DIST_BIN) binary releaseassets
releasetest: GOPATH = "$(DIST):$(VENDOR):$(CURDIR)"
releasetest: dist_gopath test
install:
echo $(BIN)
echo $(SHARE)
$(INSTALL) -d $(BIN) $(CONF)
$(INSTALL) -d $(SHARE)/www/html
$(INSTALL) -d $(SHARE)/www/static
$(INSTALL) -d $(SHARE)/www/static/img
$(INSTALL) -d $(SHARE)/www/static/sounds
$(INSTALL) -d $(SHARE)/www/static/fonts
$(INSTALL) -d $(SHARE)/www/static/translation
$(INSTALL) -d $(SHARE)/www/static/css
$(INSTALL) $(DIST_BIN)/* $(BIN)
$(INSTALL) -m 644 server.conf.in $(CONF)/$(CONFIG_FILE)
$(INSTALL) html/* $(SHARE)/www/html
$(INSTALL) static/img/* $(SHARE)/www/static/img
$(INSTALL) static/sounds/* $(SHARE)/www/static/sounds
$(INSTALL) static/fonts/* $(SHARE)/www/static/fonts
$(INSTALL) static/translation/* $(SHARE)/www/static/translation
$(INSTALL) static/css/* $(SHARE)/www/static/css
$(INSTALL) -D static/js/libs/require/require.js $(SHARE)/www/static/js/libs/require/require.js
$(INSTALL) $(OUTPUT_JS)/*.js $(SHARE)/www/static/js
clean:
GOPATH=$(GOPATH) $(GO) clean -i $(PKG)
rm -rf $(CURDIR)/pkg
rm -rf $(CURDIR)/static/css
rm -rf $(CURDIR)/static/fonts
rm -rf $(CURDIR)/build/out
distclean: clean
rm -rf $(DIST)
pristine: distclean
rm -f server.conf
rm -rf vendor/*
$(DIST_SRC):
$(MKDIR_P) $@
$(DIST_BIN):
$(MKDIR_P) $@
dist_gopath: $(DIST_SRC)
$(FIND) $(SYSTEM_GOPATH) -mindepth 1 -maxdepth 1 -type d \
-exec ln -sf {} $(DIST_SRC) \;
tarball: TARPATH = $(DIST)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)
tarball: BIN = $(TARPATH)/loader
tarball: CONF = $(TARPATH)/loader
tarball: DOCS = $(CONF)/docs
tarball: SHARE = $(TARPATH)/
tarball: distclean release install
echo -n $(PACKAGE_VERSION) > $(TARPATH)/version.txt
tar czf $(DIST)/$(PACKAGE_NAME)-$(PACKAGE_VERSION)_$(BUILD_OS)_$(BUILD_ARCH).tar.gz -C $(DIST) $(PACKAGE_NAME)-$(PACKAGE_VERSION)
.PHONY: clean distclean pristine get getupdate build styles javascript release releasetest dist_gopath install gopath binary binaryrace binaryall tarball assets

1
NEWS

@ -0,0 +1 @@
See https://github.com/strukturag/spreed-webrtc for further information.

1
README

@ -0,0 +1 @@
See README.md for further information.

21
README.md

@ -1,9 +1,9 @@
Spreed Speak Freely Spreed WebRTC
=================== ===================
The latest version of Spreed Speak Freely can be found on GitHub: The latest version of Spreed WebRTC can be found on GitHub:
https://github.com/strukturag/spreed-speakfreely https://github.com/strukturag/spreed-webrtc
## Build prerequisites ## Build prerequisites
@ -20,11 +20,16 @@ The latest version of Spreed Speak Freely can be found on GitHub:
## Building ## Building
[![Build Status](https://travis-ci.org/strukturag/spreed-speakfreely.png?branch=master)](https://travis-ci.org/strukturag/spreed-speakfreely) [![Build Status](https://travis-ci.org/strukturag/spreed-webrtc.png?branch=master)](https://travis-ci.org/strukturag/spreed-webrtc)
Go, Sass and NodeJS need to be in your $PATH. Go, Sass and NodeJS need to be in your $PATH.
If you got spreed-webrtc from the git repository, you will first need
to run the included `autogen.sh` script to generate the `configure`
script.
```bash ```bash
$ ./configure
$ make $ make
``` ```
@ -43,7 +48,7 @@ The latest version of Spreed Speak Freely can be found on GitHub:
## Server startup ## Server startup
```bash ```bash
spreed-speakfreely-server [OPTIONS] spreed-webrtc-server [OPTIONS]
``` ```
Options Options
@ -69,7 +74,7 @@ The latest version of Spreed Speak Freely can be found on GitHub:
Copy the server.conf.in to server.conf. Copy the server.conf.in to server.conf.
Build styles, javascript and binary using make. Then run Build styles, javascript and binary using make. Then run
``./spreed-speakfreely-server`` ``./spreed-webrtc-server``
The server runs on http://localhost:8080/ per default. The server runs on http://localhost:8080/ per default.
@ -79,7 +84,7 @@ The latest version of Spreed Speak Freely can be found on GitHub:
## Production use ## Production use
Spreed Speak Freely should be run through a SSL frontend proxy with Spreed WebRTC should be run through a SSL frontend proxy with
support for Websockets. Example configuration for Nginx can be support for Websockets. Example configuration for Nginx can be
found in `doc/NGINX.txt`. found in `doc/NGINX.txt`.
@ -101,4 +106,4 @@ The latest version of Spreed Speak Freely can be found on GitHub:
## License ## License
`Spreed Speak Freely` uses the AGPL license, see our `LICENSE` file. `Spreed WebRTC` uses the AGPL license, see our `LICENSE` file.

22
autogen.sh

@ -0,0 +1,22 @@
#!/bin/sh
# the pre-commit hook performs various formatting checks
if test ! \( -x .git/hooks/pre-commit -a -L .git/hooks/pre-commit \); then \
rm -f .git/hooks/pre-commit; \
ln -s ../../src/hooks/pre-commit.hook .git/hooks/pre-commit; \
fi
if [ -x "`which autoreconf 2>/dev/null`" ] ; then
exec autoreconf -ivf
fi
LIBTOOLIZE=libtoolize
SYSNAME=`uname`
if [ "x$SYSNAME" = "xDarwin" ] ; then
LIBTOOLIZE=glibtoolize
fi
aclocal -I m4 && \
autoheader && \
$LIBTOOLIZE && \
autoconf && \
automake --add-missing --force-missing --copy

7
build/build.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
/*jshint -W030 */
({ ({
baseUrl: '../static/js', baseUrl: '../static/js',
mainConfigFile: '../static/js/main.js', mainConfigFile: '../static/js/main.js',
@ -59,4 +60,4 @@
inlineText: true, inlineText: true,
} }
] ]
}) });

110
configure.ac

@ -0,0 +1,110 @@
#
# Spreed WebRTC.
# Copyright (C) 2013-2014 struktur AG
#
# This file is part of Spreed WebRTC.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
dnl required version of autoconf
AC_PREREQ([2.53])
AC_INIT([spreed-webrtc],[unknown],[opensource@struktur.de],[],[https://github.com/strukturag/spreed-webrtc])
# minimum required versions (actually one version before)
GO_VERSION_MIN=1.0.9 # actually 1.1
NODEJS_VERSION_MIN=0.7.9 # actually 0.8.0
SASS_VERSION_MIN=3.1.9 # actually 3.2.0
AC_CONFIG_SRCDIR([src/app/spreed-webrtc-server/main.go])
AC_CONFIG_HEADERS([config.h])
dnl required version of automake
AM_INIT_AUTOMAKE([1.10])
dnl enable mainainer mode by default
AM_MAINTAINER_MODE([enable])
AC_PROG_MKDIR_P
AC_PROG_INSTALL
AC_PROG_GREP
AC_PROG_SED
AC_SUBST(MKDIR_P)
AC_SUBST(INSTALL)
AC_SUBST(GREP)
AC_SUBST(SED)
AC_PATH_PROGS([FIND],[find])
AC_PATH_PROGS([JSHINT],[jshint])
AC_PATH_PROGS([JS_BEAUTIFY],[js-beautify])
AC_SUBST(FIND)
AC_SUBST(JSHINT)
AC_SUBST(JS_BEAUTIFY)
AC_PATH_PROGS([GO],[go])
if test x"${GO}" == x"" ; then
AC_MSG_ERROR([Please install Go before trying to build spreed-webrtc.])
fi
GO_VERSION=`$GO version | sed 's/^go version go//' | $SED 's/ .*//'`
if test "$GO_VERSION" == "`echo -e "$GO_VERSION\n$GO_VERSION_MIN" | sort -V | head -n1`" ; then
AC_MSG_ERROR([Please install Go $GO_VERSION_MIN or newer before trying to build spreed-webrtc (found Go $GO_VERSION).])
fi
AC_SUBST(GO)
AC_PATH_PROGS([NODEJS],[nodejs node])
if test x"${NODEJS}" == x"" ; then
AC_MSG_ERROR([Please install node.js before trying to build spreed-webrtc.])
fi
NODEJS_VERSION=`$NODEJS --version | $SED 's/^v//'`
if test "$NODEJS_VERSION" == "`echo -e "$NODEJS_VERSION\n$NODEJS_VERSION_MIN" | sort -V | head -n1`" ; then
AC_MSG_ERROR([Please install node.js $NODEJS_VERSION_MIN or newer before trying to build spreed-webrtc (found node.js $NODEJS_VERSION).])
fi
AC_SUBST(NODEJS)
AC_PATH_PROGS([SASS],[sass])
if test x"${SASS}" == x"" ; then
AC_MSG_ERROR([Please install sass before trying to build spreed-webrtc.])
fi
SASS_VERSION=`$SASS --version | $SED 's/^Sass //' | $SED 's/ .*//'`
if test "$SASS_VERSION" == "`echo -e "$SASS_VERSION\n$SASS_VERSION_MIN" | sort -V | head -n1`" ; then
AC_MSG_ERROR([Please install sass $SASS_VERSION_MIN or newer before trying to build spreed-webrtc (found sass $SASS_VERSION).])
fi
AC_SUBST(SASS)
AC_PATH_PROGS([COMPASS],[compass])
if test x"${COMPASS}" == x"" ; then
AC_MSG_ERROR([Please install compass before trying to build spreed-webrtc.])
fi
AC_SUBST(COMPASS)
AC_PATH_PROGS([AUTOPREFIXER],[autoprefixer])
if test x"${AUTOPREFIXER}" == x"" ; then
AC_MSG_ERROR([Please install autoprefixer before trying to build spreed-webrtc.])
fi
AC_SUBST(AUTOPREFIXER)
VERSION=`dpkg-parsechangelog | sed -n 's/^Version: //p'`
PACKAGE_VERSION="$VERSION"
PACKAGE_STRING="$PACKAGE_NAME $PACKAGE_VERSION"
AC_DEFINE_UNQUOTED(VERSION, ["$VERSION"], [Version number of package])
AC_DEFINE_UNQUOTED(PACKAGE_VERSION, ["$PACKAGE_VERSION"], [Define to the version of this package.])
AC_DEFINE_UNQUOTED(PACKAGE_STRING, ["$PACKAGE_STRING"], [Define to the full name and version of this package.])
AC_CONFIG_FILES([
Makefile
])
AC_OUTPUT

61
debian/changelog vendored

@ -1,4 +1,35 @@
spreed-speakfreely-server (0.17.4) precise; urgency=low spreed-webrtc-server (0.18.0) precise; urgency=low
* The project is now named Spreed WebRTC. All reference to the old
name Spreed Speak Freely have been replaced.
* Cleanup of Javascript code to match coding guide lines.
* Added various new targets to make to check javascript and scss code.
-- Simon Eisenmann <simon@struktur.de> Fri, 23 May 2014 10:46:51 +0200
spreed-webrtc-server (0.17.5) precise; urgency=low
* Implemented server side support for user authentication and authorization.
* Added an REST API end point (see docs).
* Settings are now implicitly stored.
* Javascript console log is now disabled per default. Enable with ?debug
URL parameter or by typing debug(true) in console.
* The integrated TLS server can now provide TLS client authentication.
* Updated example plugins to latest APIs.
* Bootstrap and FontAwesome are now compiled on build from SCSS sources.
* All styles now use a common set of variables for colors and font sizes.
* Removed vendor prefixes from scss and generate them on build with
the autoprefixes utility.
* Fixed compatibility with mobile Safari < 6 which did not load.
* Fixed compatibility with Firefox in case the Firefox peer has no camera.
* Settings do now auto open on start when there is no display name set.
* The accept a call button does now share in sync with the ringing sound.
* Added support to specify the default language by URL parameter (?lang=en).
* Added support for .webp images as buddy images.
-- Simon Eisenmann <simon@struktur.de> Thu, 22 May 2014 17:49:16 +0200
spreed-webrtc-server (0.17.4) precise; urgency=low
* Updated Japanese translation. * Updated Japanese translation.
* Allow Makefile variables CONFIG_FILE and CONFIG_PATH. * Allow Makefile variables CONFIG_FILE and CONFIG_PATH.
@ -16,7 +47,7 @@ spreed-speakfreely-server (0.17.4) precise; urgency=low
-- Simon Eisenmann <simon@struktur.de> Thu, 24 Apr 2014 17:59:05 +0200 -- Simon Eisenmann <simon@struktur.de> Thu, 24 Apr 2014 17:59:05 +0200
spreed-speakfreely-server (0.17.3) precise; urgency=low spreed-webrtc-server (0.17.3) precise; urgency=low
* Buddy images are now loaded with seperate URL calls. * Buddy images are now loaded with seperate URL calls.
* Updated Korean (ko) language. * Updated Korean (ko) language.
@ -27,11 +58,11 @@ spreed-speakfreely-server (0.17.3) precise; urgency=low
* File permission fixes. * File permission fixes.
* Do not use sleepy as submodule but include it directly. * Do not use sleepy as submodule but include it directly.
* Refactored video layout renderer in seperate service. * Refactored video layout renderer in seperate service.
* Implemented alternaitve conference view (not enabled yet). * Implemented alternaitve conference view (not enabled yet).
-- Simon Eisenmann <simon@struktur.de> Wed, 16 Apr 2014 17:41:13 +0200 -- Simon Eisenmann <simon@struktur.de> Wed, 16 Apr 2014 17:41:13 +0200
spreed-speakfreely-server (0.17.2) precise; urgency=low spreed-webrtc-server (0.17.2) precise; urgency=low
* Fixed timeouts when there was a disconnect. * Fixed timeouts when there was a disconnect.
* Use sleepy as submodule from external source. * Use sleepy as submodule from external source.
@ -42,10 +73,10 @@ spreed-speakfreely-server (0.17.2) precise; urgency=low
* Added Japanese language. * Added Japanese language.
* Added Chinese Traditional language. * Added Chinese Traditional language.
* Updated Chinese language. * Updated Chinese language.
* Updated Korean language. * Updated Korean language.
* Fixed screen sharing scrolling. * Fixed screen sharing scrolling.
* Fixed screen sharing hangup in conferences. * Fixed screen sharing hangup in conferences.
* Avoid spurious bye ping pong. * Avoid spurious bye ping pong.
* Fixed hangup in conferences. * Fixed hangup in conferences.
* Fixed double click on Chrome OS. * Fixed double click on Chrome OS.
* Fixed buddy list visibility if it should auto hide. * Fixed buddy list visibility if it should auto hide.
@ -54,7 +85,7 @@ spreed-speakfreely-server (0.17.2) precise; urgency=low
-- Simon Eisenmann <simon@struktur.de> Fri, 11 Apr 2014 19:42:10 +0200 -- Simon Eisenmann <simon@struktur.de> Fri, 11 Apr 2014 19:42:10 +0200
spreed-speakfreely-server (0.17.1) precise; urgency=low spreed-webrtc-server (0.17.1) precise; urgency=low
* Added translations for Korean and Chinese. * Added translations for Korean and Chinese.
* Multiple updates to 3rd party js libraries. * Multiple updates to 3rd party js libraries.
@ -64,7 +95,7 @@ spreed-speakfreely-server (0.17.1) precise; urgency=low
-- Simon Eisenmann <simon@struktur.de> Fri, 04 Apr 2014 18:46:56 +0200 -- Simon Eisenmann <simon@struktur.de> Fri, 04 Apr 2014 18:46:56 +0200
spreed-speakfreely-server (0.17.0) precise; urgency=low spreed-webrtc-server (0.17.0) precise; urgency=low
* TURN user names now use expiration time stamp. This fixes compatibility * TURN user names now use expiration time stamp. This fixes compatibility
with latest TURN REST specification and requires a reasonably recent with latest TURN REST specification and requires a reasonably recent
@ -76,11 +107,11 @@ spreed-speakfreely-server (0.17.0) precise; urgency=low
* HTML fixes. * HTML fixes.
* Added method to generate URL-safe random string. * Added method to generate URL-safe random string.
* Use strong random number generator. * Use strong random number generator.
* Support configuring pprof HTTP server. * Support configuring pprof HTTP server.
-- Simon Eisenmann <simon@struktur.de> Fri, 28 Mar 2014 16:48:46 +0100 -- Simon Eisenmann <simon@struktur.de> Fri, 28 Mar 2014 16:48:46 +0100
spreed-speakfreely-server (0.16.1) precise; urgency=low spreed-webrtc-server (0.16.1) precise; urgency=low
* Implemented chat session control UI. * Implemented chat session control UI.
* Layout controller refactorization. * Layout controller refactorization.
@ -88,7 +119,7 @@ spreed-speakfreely-server (0.16.1) precise; urgency=low
-- Simon Eisenmann <simon@struktur.de> Fri, 21 Mar 2014 11:46:10 +0100 -- Simon Eisenmann <simon@struktur.de> Fri, 21 Mar 2014 11:46:10 +0100
spreed-speakfreely-server (0.16.0) precise; urgency=low spreed-webrtc-server (0.16.0) precise; urgency=low
* Chat UI improvements. * Chat UI improvements.
* Screen sharing is now a scroll pane and no longer scaled down. * Screen sharing is now a scroll pane and no longer scaled down.
@ -97,13 +128,13 @@ spreed-speakfreely-server (0.16.0) precise; urgency=low
* Server code was reviewed and fixed where required. * Server code was reviewed and fixed where required.
* Changed Makefile to allow tarball and release builds with * Changed Makefile to allow tarball and release builds with
local third party sources in ./vendor too. local third party sources in ./vendor too.
* Added configration for maxfd and automatically use the * Added configration for maxfd and automatically use the
numer of cpus for GOMAXPROCS per default. numer of cpus for GOMAXPROCS per default.
* Added server helper for stats and profiling. * Added server helper for stats and profiling.
-- Simon Eisenmann <simon@struktur.de> Mon, 17 Mar 2014 18:35:08 +0100 -- Simon Eisenmann <simon@struktur.de> Mon, 17 Mar 2014 18:35:08 +0100
spreed-speakfreely-server (0.15.0) precise; urgency=low spreed-webrtc-server (0.15.0) precise; urgency=low
* Initial public release. * Initial public release.

10
doc/CHANNELING-API.txt

@ -1,7 +1,7 @@
Spreed Speak Freely Channeling API v1.3.0 Spreed WebRTC Channeling API v1.3.0
================================================= =================================================
(c)2014 struktur AG (c)2014 struktur AG
The server provides a Websocket connection end point as channeling API to The server provides a Websocket connection end point as channeling API to
share peer information for peer to peer connectivity. share peer information for peer to peer connectivity.
@ -340,7 +340,7 @@ Additional types for session listing and notifications
"Batch": 0 "Batch": 0
} }
Note: The Userid field is only present, if that session belongs to a known user. Note: The Userid field is only present, if that session belongs to a known user.
Alive Alive
@ -745,8 +745,8 @@ File sharing data channel protocol
End of Channeling API. End of Channeling API.
For latest version of Spreed Speak Freely check For latest version of Spreed WebRTC check
https://github.com/strukturag/spreed-speakfreely https://github.com/strukturag/spreed-webrtc
For questions, contact mailto:opensource@struktur.de. For questions, contact mailto:opensource@struktur.de.

32
doc/CROSSCOMPILE.txt

@ -0,0 +1,32 @@
Linux:
Target linux/amd64
GOOS=linux GOARCH=amd64 make tarball
Target linux/386:
GOOS=linux GOARCH=386 make tarball
Target linux/armv5
GOOS=linux GOARCH=arm GOARM=5 make tarball
Target linux/armv6
GOOS=linux GOARCH=arm GOARM=6 make tarball
Target linux/armv7
GOOS=linux GOARCH=arm GOARM=7 make tarball
Mac:
Target darwin/amd64
GOOS=darwin GOARCH=amd64 make tarball
Windows:
Target windows/386
GOOS=windows GOARCH=386 make tarball
Target windows/amd64
GOOS=windows GOARCH=amd64 make tarball

6
doc/REST-API.txt

@ -1,5 +1,5 @@
Spreed Speak Freely REST API v1.0.0 Spreed WebRTC REST API v1.0.0
=============================================== ===============================================
(c)2014 struktur AG (c)2014 struktur AG
@ -150,8 +150,8 @@ Available end points with request methods and content-type:
End of REST API. End of REST API.
For latest version of Spreed Speak Freely check For latest version of Spreed WebRTC check
https://github.com/strukturag/spreed-speakfreely https://github.com/strukturag/spreed-webrtc
For questions, contact mailto:opensource@struktur.de. For questions, contact mailto:opensource@struktur.de.

4
doc/plugin-example.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

18
doc/plugin-test-authorize.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -50,14 +50,14 @@ define(['angular', 'sjcl'], function(angular, sjcl) {
$window.testCreateSuseridLocal = function(key, userid) { $window.testCreateSuseridLocal = function(key, userid) {
var k = sjcl.codec.utf8String.toBits(key); var k = sjcl.codec.utf8String.toBits(key);
var foo = new sjcl.misc.hmac(k, sjcl.hash.sha256) var foo = new sjcl.misc.hmac(k, sjcl.hash.sha256);
var expiration = parseInt(((new Date).getTime()/1000)+3600, 10); var expiration = parseInt(((new Date()).getTime()/1000)+3600, 10);
var useridCombo = ""+expiration+":"+userid; var useridCombo = ""+expiration+":"+userid;
var secret = foo.mac(useridCombo); var secret = foo.mac(useridCombo);
var data = { var data = {
useridcombo: useridCombo, useridcombo: useridCombo,
secret: sjcl.codec.base64.fromBits(secret) secret: sjcl.codec.base64.fromBits(secret)
} };
lastData = data; lastData = data;
return data; return data;
@ -86,7 +86,7 @@ define(['angular', 'sjcl'], function(angular, sjcl) {
$window.testLastAuthenticate = function() { $window.testLastAuthenticate = function() {
if (!lastNonce || !lastUserid) { if (!lastNonce || !lastUserid) {
console.log("Run testAuthorize first."); console.log("Run testAuthorize first.");
return return;
} }
mediaStream.api.requestAuthentication(lastUserid, lastNonce); mediaStream.api.requestAuthentication(lastUserid, lastNonce);
}; };
@ -94,7 +94,7 @@ define(['angular', 'sjcl'], function(angular, sjcl) {
$window.testLastAuthorize = function() { $window.testLastAuthorize = function() {
if (lastData === null) { if (lastData === null) {
console.log("Run testCreateSuseridServer fist."); console.log("Run testCreateSuseridServer fist.");
return return;
} }
$window.testAuthorize(lastData); $window.testAuthorize(lastData);
}; };
@ -103,6 +103,6 @@ define(['angular', 'sjcl'], function(angular, sjcl) {
} }
} };
}); });

10
html/crawler.html

@ -0,0 +1,10 @@
<%define "crawlerPage"%><!doctype html>
<html>
<head>
<meta property="og:title" content="/<%.Room%>" />
<meta property="og:site_name" content="<%.Cfg.Title%>"/>
<meta property="og:image" content="<%.Scheme%>://<%.Host%><%.Cfg.B%>static/img/opengraph-image.png" />
<meta property="og:type" content="article" />
</head>
<body></body>
</html><%end%>

1
html/head.html

@ -1,4 +1,5 @@
<%define "head"%><title><%.Cfg.Title%></title> <%define "head"%><title><%.Cfg.Title%></title>
<meta name="fragment" content="!">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">

2
html/logo.html

@ -1 +1 @@
<%define "logo"%><span class="logo" title="<%.Cfg.Title%>"><span><a target="_blank" href="https://github.com/strukturag/spreed-speakfreely">Speak Freely</a></span></span><%end%> <%define "logo"%><span class="logo" title="<%.Cfg.Title%>"><span><a target="_blank" href="https://github.com/strukturag/spreed-webrtc">WebRTC</a></span></span><%end%>

10
server.conf.in

@ -1,10 +1,10 @@
; Spreed Speak Freely server example configuration ; Spreed WebRTC server example configuration
[http] [http]
; HTTP listener in format ip:port. ; HTTP listener in format ip:port.
listen = 127.0.0.1:8080 listen = 127.0.0.1:8080
; Full path to directory where to find the server web assets. ; Full path to directory where to find the server web assets.
;root = /usr/share/spreed-speakfreely-server/www ;root = /usr/share/spreed-webrtc-server/www
; HTTP socket read timeout in seconds. ; HTTP socket read timeout in seconds.
;readtimeout = 10 ;readtimeout = 10
; HTTP socket write timeout in seconds. ; HTTP socket write timeout in seconds.
@ -35,7 +35,7 @@ listen = 127.0.0.1:8080
[app] [app]
; HTML page title ; HTML page title
;title = Spreed Speak Freely ;title = Spreed WebRTC
; Version string to use for static resources. This defaults to the server ; Version string to use for static resources. This defaults to the server
; version and should only be changed when you use your own way to invalidate ; version and should only be changed when you use your own way to invalidate
; long cached static resources. ; long cached static resources.
@ -84,7 +84,7 @@ sessionSecret = the-default-secret-do-not-keep-me
; extra-* template slots. If the extra folder has a sub folder "static", the ; extra-* template slots. If the extra folder has a sub folder "static", the
; resources in this static folder will be available as /extra/static/filename ; resources in this static folder will be available as /extra/static/filename
; relative to your servers base URL. ; relative to your servers base URL.
;extra = /usr/share/spreed-speakfreely-server/extra ;extra = /usr/share/spreed-webrtc-server/extra
; URL relative to the servers base path for a plugin javascript file which is ; URL relative to the servers base path for a plugin javascript file which is
; automatically loaded on web client start for all users. You can put your ; automatically loaded on web client start for all users. You can put your
; plugin in the extra/static folder (see above) or provide another folder using ; plugin in the extra/static folder (see above) or provide another folder using
@ -93,7 +93,7 @@ sessionSecret = the-default-secret-do-not-keep-me
;plugin = extra/static/myplugin.js ;plugin = extra/static/myplugin.js
[log] [log]
;logfile = /var/log/spreed-speakfreely-server.log ;logfile = /var/log/spreed-webrtc-server.log
[users] [users]
; Set to true to enable user functionality. ; Set to true to enable user functionality.

2
spreed-speakfreely-server

@ -1,2 +0,0 @@
#!/bin/bash
exec ./bin/spreed-speakfreely-server $*

2
spreed-webrtc-server

@ -0,0 +1,2 @@
#!/bin/bash
exec ./bin/spreed-webrtc-server $*

4
src/app/spreed-speakfreely-server/api.go → src/app/spreed-webrtc-server/api.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/buffercache.go → src/app/spreed-webrtc-server/buffercache.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/channeling.go → src/app/spreed-webrtc-server/channeling.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/config.go → src/app/spreed-webrtc-server/config.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/connection.go → src/app/spreed-webrtc-server/connection.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

6
src/app/spreed-speakfreely-server/context.go → src/app/spreed-webrtc-server/context.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -27,4 +27,6 @@ type Context struct {
Host string Host string
Ssl bool Ssl bool
Languages []string Languages []string
Room string `json:"-"`
Scheme string `json:"-"`
} }

4
src/app/spreed-speakfreely-server/hub.go → src/app/spreed-webrtc-server/hub.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

5
src/app/spreed-speakfreely-server/images.go → src/app/spreed-webrtc-server/images.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -66,6 +66,7 @@ func NewImageCache() ImageCache {
"image/png": "picture.png", "image/png": "picture.png",
"image/jpeg": "picture.jpg", "image/jpeg": "picture.jpg",
"image/gif": "picture.gif", "image/gif": "picture.gif",
"image/webp": "picture.webp",
} }
} }
return result return result

32
src/app/spreed-speakfreely-server/main.go → src/app/spreed-webrtc-server/main.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -22,7 +22,7 @@
package main package main
import ( import (
"app/spreed-speakfreely-server/sleepy" "app/spreed-webrtc-server/sleepy"
"bytes" "bytes"
"flag" "flag"
"fmt" "fmt"
@ -117,15 +117,20 @@ func makeImageHandler(hub *Hub, expires time.Duration) http.HandlerFunc {
func handleRoomView(room string, w http.ResponseWriter, r *http.Request) { func handleRoomView(room string, w http.ResponseWriter, r *http.Request) {
var err error
w.Header().Set("Content-Type", "text/html; charset=UTF-8") w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Header().Set("Expires", "-1") w.Header().Set("Expires", "-1")
w.Header().Set("Cache-Control", "private, max-age=0") w.Header().Set("Cache-Control", "private, max-age=0")
scheme := "http"
// Detect if the request was made with SSL. // Detect if the request was made with SSL.
ssl := r.TLS != nil ssl := r.TLS != nil
proto, ok := r.Header["X-Forwarded-Proto"] proto, ok := r.Header["X-Forwarded-Proto"]
if ok { if ok {
ssl = proto[0] == "https" ssl = proto[0] == "https"
scheme = "https"
} }
// Get languages from request. // Get languages from request.
@ -134,11 +139,22 @@ func handleRoomView(room string, w http.ResponseWriter, r *http.Request) {
langs = append(langs, "en") langs = append(langs, "en")
} }
// Prepare context to deliver to Javascript. // Prepare context to deliver to HTML..
context := &Context{Cfg: config, App: "main", Host: r.Host, Ssl: ssl, Languages: langs} context := &Context{Cfg: config, App: "main", Host: r.Host, Scheme: scheme, Ssl: ssl, Languages: langs, Room: room}
// Get URL parameters.
r.ParseForm()
// Check if incoming request is a crawler which supports AJAX crawling.
// See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started for details.
if _, ok := r.Form["_escaped_fragment_"]; ok {
// Render crawlerPage template..
err = templates.ExecuteTemplate(w, "crawlerPage", &context)
} else {
// Render mainPage template.
err = templates.ExecuteTemplate(w, "mainPage", &context)
}
// Render the template.
err := templates.ExecuteTemplate(w, "mainPage", &context)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
} }
@ -204,7 +220,7 @@ func runner(runtime phoenix.Runtime) error {
title, err := runtime.GetString("app", "title") title, err := runtime.GetString("app", "title")
if err != nil { if err != nil {
title = "Spreed Speak Freely" title = "Spreed WebRTC"
} }
ver, err := runtime.GetString("app", "ver") ver, err := runtime.GetString("app", "ver")

4
src/app/spreed-speakfreely-server/random.go → src/app/spreed-webrtc-server/random.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/rooms.go → src/app/spreed-webrtc-server/rooms.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/roomworker.go → src/app/spreed-webrtc-server/roomworker.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/server.go → src/app/spreed-webrtc-server/server.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/session.go → src/app/spreed-webrtc-server/session.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/sessions.go → src/app/spreed-webrtc-server/sessions.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

0
src/app/spreed-speakfreely-server/sleepy/core.go → src/app/spreed-webrtc-server/sleepy/core.go

4
src/app/spreed-speakfreely-server/stats.go → src/app/spreed-webrtc-server/stats.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

0
src/app/spreed-speakfreely-server/tls.go → src/app/spreed-webrtc-server/tls.go

4
src/app/spreed-speakfreely-server/tokenprovider.go → src/app/spreed-webrtc-server/tokenprovider.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/tokens.go → src/app/spreed-webrtc-server/tokens.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/users.go → src/app/spreed-webrtc-server/users.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/app/spreed-speakfreely-server/ws.go → src/app/spreed-webrtc-server/ws.go

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

BIN
src/artwork/spreedmeLogo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

179
src/artwork/spreedmeLogo.svg

@ -1,179 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.48.3.1 r9886"
preserveAspectRatio="xMinYMin meet"
viewBox="0 0 736.50372 232.21382"
width="736.50372"
height="232.21382"
xml:space="preserve"
sodipodi:docname="spreedmeLogo.svg"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs6"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18"><path
d="m 0,0 5244,0 0,1870.87 -5244,0 L 0,0 z"
id="path20"
inkscape:connector-curvature="0" /></clipPath></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1504"
inkscape:window-height="924"
id="namedview4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
borderlayer="false"
showborder="false"
inkscape:showpageshadow="false"
inkscape:zoom="0.70710678"
inkscape:cx="355.82367"
inkscape:cy="116.54258"
inkscape:window-x="395"
inkscape:window-y="172"
inkscape:window-maximized="0"
inkscape:current-layer="flowRoot3025"><sodipodi:guide
position="-2.5001639,-0.38867555"
orientation="0,855.51001"
id="guide3801" /><sodipodi:guide
position="853.00985,-0.38867555"
orientation="-233.8625,0"
id="guide3803" /><sodipodi:guide
position="853.00985,233.47382"
orientation="0,-855.51001"
id="guide3805" /><sodipodi:guide
position="-2.5001639,233.47382"
orientation="233.8625,0"
id="guide3807" /><sodipodi:guide
orientation="0,1"
position="386.49984,59.611324"
id="guide3815" /></sodipodi:namedview><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.25,0,0,-1.25,-2.5001639,232.6025)"><g
id="g12"
transform="scale(0.1,0.1)"><g
id="g14"><g
id="g16"
clip-path="url(#clipPath18)"><path
d="m 603.434,1251.23 c 5.625,40.32 50,105 131.25,105 81.25,0 263.75,0 292.496,0 28.75,0 62.5,-6.25 83.75,40 -1.25,-30 -8.75,-130 -11.25,-146.25 -2.5,-16.25 -22.5,-137.5 -136.246,-138.75 -113.75,0 -297.5,0 -297.5,0 0,0 -58.75,6.88 -88.438,-46.25 -0.191,-0.39 20.938,152.5 25.938,186.25"
style="fill:#009534;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path22"
inkscape:connector-curvature="0" /><path
d="m 71.7852,763.398 c 11.2304,81.493 99.8238,212.27 262.0348,212.27 162.215,0 526.571,0 583.969,0 57.399,0 124.781,-12.637 167.201,80.862 -2.49,-60.647 -17.47,-262.811 -22.46,-295.659 -4.99,-32.851 -44.92,-277.973 -272.014,-280.5 -227.098,0 -593.95,0 -593.95,0 0,0 -118.9879,13.098 -176.5621,-93.5 -0.3828,-0.801 41.8008,308.301 51.7813,376.527"
style="fill:#84b819;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path24"
inkscape:connector-curvature="0" /><path
d="m 1788.12,1102.35 c 0,0 8.18,103.6 2.5,144.51 -5.13,36.92 -22.15,69.16 -58.12,93.12 -35.97,23.97 -97.73,36.6 -170.36,37.52 -90.51,0.24 -149.64,-22.52 -196.52,-64.39 -52.28,-46.7 -69.37,-92.5 -78.12,-166.88 -8.05,-68.41 15,-128.75 46.7,-166.683 29.08,-34.809 172.67,-144.559 172.67,-144.559 25,-20.937 86.88,-66.879 79.38,-131.25 -4.65,-39.937 -13.75,-59.379 -33.75,-78.75 -22.56,-21.859 -43.75,-29.379 -80.63,-30.629 -20.05,-0.679 -50.13,1.641 -68.56,17.43 -17.5,15 -25.89,42.481 -24.6,101.281 l 0,34.231 -166.84,-0.442 -1.25,-31.25 c 0.62,-93.289 9.55,-155.007 42.5,-187.5 44.38,-43.75 84.33,-61.14 191.88,-61.871 89.66,-0.578 135.18,12.742 198.75,55 63.56,42.25 95.36,99.582 108.12,191.871 10.63,76.879 -8.42,115.391 -33.75,154.379 -25.33,38.985 -65,63.121 -109.85,102.461 0,0 -117.96,102.271 -133.9,120.661 -15.93,18.39 -22.89,63.37 -12.5,95 14.38,43.75 43.43,60.93 78.75,63.75 46.88,3.75 68.61,-12.13 82.19,-36.56 12.5,-22.5 5.94,-69.07 2.81,-110.45 l 162.5,0"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path26"
inkscape:connector-curvature="0" /><path
d="m 2613.45,491.48 163.68,0 65.37,520.38 c 13.27,78.68 36.73,132.16 75,161.25 40.03,30.44 63.75,44.37 152.5,41.25 l 12.5,162.5 c -5.24,1.68 -82.5,-3.13 -131.25,-38.75 -37.35,-27.29 -75,-80 -75,-80 l 12.5,105 -166.25,0 -109.05,-871.63"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path28"
inkscape:connector-curvature="0" /><path
d="m 3677.5,1288.11 c -37.56,65.73 -119.26,97.75 -237.5,98.75 -89.82,-1.58 -170.01,-16.6 -228.75,-87.5 -36.25,-43.75 -60.08,-95.45 -72.5,-170 -12.5,-75 -19.28,-141.505 -28.75,-218.751 -16.25,-132.5 -22.5,-216.25 -6.25,-281.25 13.04,-52.168 45.62,-106.25 93.12,-129.371 44.44,-21.636 101.81,-30.09 150.63,-28.129 95.24,1.032 170.43,18.86 227.5,78.129 48.75,50.621 72.5,108.75 79.37,211.25 l -153.75,0 c -2.03,-18.75 -5.26,-35.297 -14.32,-65.929 -9.02,-30.489 -16.01,-46.879 -36.3,-65.95 -20.63,-19.371 -56.57,-28.75 -85.63,-28.75 -47.5,2.5 -68.75,5.629 -91.87,31.25 -21.6,23.942 -18,60.403 -16.25,100.629 1.87,43.121 13.75,139.996 13.75,139.996 l 403.12,0 c 18.75,148.126 54.38,328.126 4.38,415.626 z m -141.25,-220.63 -7.5,-76.511 -246.25,-0.36 6.25,66.871 c 7.25,58.62 11.87,88.13 35,133.13 23.6,45.94 56.89,64.66 111.87,66.87 48.4,-1.2 75.63,-13.12 93.13,-48.75 17.23,-35.08 13.1,-75.21 7.5,-141.25"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path30"
inkscape:connector-curvature="0" /><path
d="m 5209.89,1860.82 -163.68,0 -70.59,-556.46 c -21.72,32.52 -30,41.25 -56.87,58.12 -31.23,19.61 -72.37,21.9 -119.38,21.25 -45.94,-0.62 -80.67,-7.12 -121.32,-33.4 -43.05,-27.85 -68.68,-64.1 -97.16,-128.4 -29.53,-66.7 -34.91,-159.7 -53.39,-286.321 -21.74,-149.8 -36.11,-256.25 -16.25,-334.371 21.42,-84.277 88.45,-120.179 155.62,-124.379 70,-4.371 110.87,12.84 147.5,35.629 28.13,17.5 41.88,30 63.75,55.621 l -6.87,-76.25 162.5,0.629 176.14,1368.332 z m -255.52,-675.21 c 3.13,-62.5 -8.12,-165 -21.87,-270.001 -12.28,-93.769 -21.25,-165 -45,-231.25 -20.84,-58.109 -54.38,-87.57 -127.19,-87.16 -50.94,0.289 -76.66,19.352 -88.44,60.289 -13.12,45.621 2.5,171.25 16.46,270.207 16.25,115.135 26.67,204.165 43.54,250.415 19.86,54.43 55.63,83.75 125.54,83.63 53.84,-0.51 94.7,-30.97 96.96,-76.13"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path32"
inkscape:connector-curvature="0" /><path
d="m 2511.25,1248.11 c -20.32,84.35 -70.66,131.67 -168.75,132.5 -47.57,-0.53 -85.94,-13.43 -125,-34.38 -39.27,-21.04 -82.5,-68.75 -82.5,-68.75 l 9.37,84.38 -167.77,0 L 1800.62,3.10938 1970.35,3.12109 2040,547.488 c 23.88,-28.297 49.73,-48.687 78.46,-60.148 26.69,-10.641 54.04,-16.102 105.91,-16.731 45.63,3.75 98.12,22.821 124.38,43.75 46.25,36.879 58.75,55 85.62,113.75 30.22,66.071 35.63,161.25 54.38,279.375 21.63,149.806 43.12,254.996 22.5,340.626 z m -158.75,-88.75 c 1.87,-52.5 -8.75,-138.75 -20,-237.501 -16.25,-118.07 -23.17,-191.129 -49.38,-244.371 -24.49,-49.758 -55.94,-83.75 -114.69,-83.129 -44.06,0.313 -88.43,23.75 -98.29,68.403 -12.46,56.398 -0.61,166.859 15.43,271.375 11.73,93.843 25.2,164.913 43.18,223.973 17.5,57.5 67.82,92.39 126.26,93.63 58.82,-1.07 95.42,-34.48 97.49,-92.38"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path34"
inkscape:connector-curvature="0" /><path
d="m 4377.5,1288.11 c -37.56,65.73 -119.26,97.75 -237.5,98.75 -89.82,-1.58 -170.01,-16.6 -228.75,-87.5 -36.25,-43.75 -60.08,-95.45 -72.5,-170 -12.5,-75 -19.28,-141.505 -28.75,-218.751 -16.25,-132.5 -22.5,-216.25 -6.25,-281.25 13.04,-52.168 45.62,-106.25 93.12,-129.371 44.44,-21.636 101.81,-30.09 150.63,-28.129 95.24,1.032 170.43,18.86 227.5,78.129 48.75,50.621 72.5,108.75 79.37,211.25 l -153.75,0 c -2.03,-18.75 -5.26,-35.297 -14.32,-65.929 -9.02,-30.489 -16.01,-46.879 -36.3,-65.95 -20.63,-19.371 -56.57,-28.75 -85.63,-28.75 -47.5,2.5 -68.75,5.629 -91.87,31.25 -21.6,23.942 -18,60.403 -16.25,100.629 1.87,43.121 13.75,139.996 13.75,139.996 l 403.12,0 c 18.75,148.126 54.38,328.126 4.38,415.626 z m -141.25,-220.63 -7.5,-76.511 -246.25,-0.36 6.25,66.871 c 7.25,58.62 11.87,88.13 35,133.13 23.6,45.94 56.89,64.66 111.87,66.87 48.4,-1.2 75.63,-13.12 93.13,-48.75 17.23,-35.08 13.1,-75.21 7.5,-141.25"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path36"
inkscape:connector-curvature="0" /></g></g><text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="725"
y="124.8625"
id="text3013"
sodipodi:linespacing="125%"
transform="matrix(8,0,0,-8,0,1870.9)"><tspan
sodipodi:role="line"
id="tspan3015"
x="725"
y="124.8625" /></text>
<g
transform="matrix(8,0,0,-8,-112,1277.1275)"
style="font-size:72px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
id="flowRoot3025"><path
d="m 677.69922,90.711252 7.41797,0 0,8.929688 -7.41797,0 0,-8.929688"
style="text-align:start;text-anchor:start;fill:#000000"
id="path3007" /><text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="701"
y="35.213821"
id="text3006"
sodipodi:linespacing="125%"
transform="translate(16.500164,-72.961562)"><tspan
sodipodi:role="line"
id="tspan3008"></tspan></text>
<text
xml:space="preserve"
style="font-size:63.99999973px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans Mono;-inkscape-font-specification:Droid Sans Mono"
x="784"
y="130.21382"
id="text3010"
sodipodi:linespacing="125%"
transform="translate(16.500164,-72.961562)"><tspan
sodipodi:role="line"
id="tspan3012"
x="784"
y="130.21382" /></text>
<text
xml:space="preserve"
style="font-size:40px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
x="805"
y="131.21382"
id="text3014"
sodipodi:linespacing="125%"
transform="translate(16.500164,-72.961562)"><tspan
sodipodi:role="line"
id="tspan3016"
x="805"
y="131.21382" /></text>
<text
xml:space="preserve"
style="font-size:64px;font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Arial Black;-inkscape-font-specification:Arial Black"
x="690.276"
y="99.640938"
id="text3018"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3020"
x="690.276"
y="99.640938"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans;font-size:69.9999997px">me</tspan></text>
</g></g></g></svg>

Before

Width:  |  Height:  |  Size: 12 KiB

73
src/hooks/pre-commit.hook

@ -0,0 +1,73 @@
#!/bin/sh
#
# Check that Go files have been formatted
#
for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.go$"` ; do
# nf is the temporary checkout. This makes sure we check against the
# revision in the index (and not the checked out version).
nf=`git checkout-index --temp ${file} | cut -f 1`
newfile=`mktemp /tmp/${nf}.XXXXXX` || exit 1
gofmt ${nf} > "${newfile}" 2>> /dev/null
diff -u -p "${nf}" "${newfile}"
r=$?
rm "${newfile}"
rm "${nf}"
if [ $r != 0 ] ; then
echo "================================================================================================="
echo " Code format error in: $file "
echo " "
echo " Please fix before committing. Don't forget to run git add before trying to commit again. "
echo " If the whole file is to be committed, this should work (run from the top-level directory): "
echo " "
echo " go fmt $file; git add $file; git commit"
echo " "
echo "================================================================================================="
exit 1
fi
done
for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.js$"` ; do
case "$file" in
*/libs/*)
echo "Not checking library ${file}"
;;
*)
echo "Checking ${file}"
nf=`git checkout-index --temp ${file} | cut -f 1`
jshint --config .jshint "${nf}"
r=$?
rm "${nf}"
if [ $r != 0 ] ; then
echo "================================================================================================="
echo " Code format error in: $file "
echo " "
echo " Please fix before committing. Don't forget to run git add before trying to commit again. "
echo " "
echo "================================================================================================="
exit 1
fi
;;
esac
done
check_styles=0
for file in `git diff-index --cached --name-only HEAD --diff-filter=ACMR| grep "\.scss$"` ; do
check_styles=1
done
if [ "${check_styles}" = "1" ]; then
make styleshint
r=$?
if [ $r != 0 ] ; then
echo "================================================================================================="
echo " Error in styles "
echo " "
echo " Please fix before committing. Don't forget to run git add before trying to commit again. "
echo " "
echo "================================================================================================="
exit 1
fi
fi

2
src/i18n/Makefile

@ -1,5 +1,5 @@
VERSION := "1.0" VERSION := "1.0"
PROJECT := "Spreed Speak Freely" PROJECT := "Spreed WebRTC"
COPYRIGHT := "struktur AG" COPYRIGHT := "struktur AG"
EMAIL := "simon@struktur.de" EMAIL := "simon@struktur.de"
ROOT := "$(CURDIR)/../.." ROOT := "$(CURDIR)/../.."

14
src/i18n/messages-de.po

@ -1,15 +1,15 @@
# German translations for Spreed Speak Freely. # German translations for Spreed WebRTC.
# Copyright (C) 2014 struktur AG # Copyright (C) 2014 struktur AG
# This file is distributed under the same license as Spreed Speak Freely. # This file is distributed under the same license as Spreed WebRTC
# project. # project.
# Simon Eisenmann <simon@struktur.de>, 2013. # Simon Eisenmann <simon@struktur.de>, 2013.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Spreed Speak Freely\n" "Project-Id-Version: Spreed WebRTC 1.0\n"
"Report-Msgid-Bugs-To: simon@struktur.de\n" "Report-Msgid-Bugs-To: simon@struktur.de\n"
"POT-Creation-Date: 2014-05-05 16:53+0200\n" "POT-Creation-Date: 2014-05-23 10:35+0200\n"
"PO-Revision-Date: 2014-05-05 16:54+0100\n" "PO-Revision-Date: 2014-05-23 10:39+0100\n"
"Last-Translator: Simon Eisenmann <simon@struktur.de>\n" "Last-Translator: Simon Eisenmann <simon@struktur.de>\n"
"Language-Team: struktur AG <opensource@struktur.de>\n" "Language-Team: struktur AG <opensource@struktur.de>\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n"
@ -372,8 +372,8 @@ msgstr "Sie geben eine Datei frei:"
msgid "Incoming file:" msgid "Incoming file:"
msgstr "Eingehende Datei:" msgstr "Eingehende Datei:"
msgid "Quit from Spreed Speak Freely?" msgid "Close this window and disconnect?"
msgstr "Spreed Speak Freely beenden?" msgstr "Fenster schließen und die Verbindung trennen?"
msgid "Restart required to apply updates. Click ok to restart now." msgid "Restart required to apply updates. Click ok to restart now."
msgstr "" msgstr ""

14
src/i18n/messages-ja.po

@ -1,14 +1,14 @@
# Japanese translations for Spreed Speak Freely. # Japanese translations for Spreed WebRTC.
# Copyright (C) 2014 struktur AG # Copyright (C) 2014 struktur AG
# This file is distributed under the same license as the Spreed Speak Freely # This file is distributed under the same license as the Spreed WebRTC
# project. # project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. # Curt Frisemo <curt.frisemo@spreed.com>, 2014.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Spreed Speak Freely 1.0\n" "Project-Id-Version: Spreed WebRTC 1.0\n"
"Report-Msgid-Bugs-To: simon@struktur.de\n" "Report-Msgid-Bugs-To: simon@struktur.de\n"
"POT-Creation-Date: 2014-05-05 16:53+0200\n" "POT-Creation-Date: 2014-05-23 10:35+0200\n"
"PO-Revision-Date: 2014-04-23 22:25+0100\n" "PO-Revision-Date: 2014-04-23 22:25+0100\n"
"Last-Translator: Curt Frisemo <curt.frisemo@spreed.com>\n" "Last-Translator: Curt Frisemo <curt.frisemo@spreed.com>\n"
"Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n" "Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n"
@ -362,8 +362,8 @@ msgstr "あなたの共有ファイル:"
msgid "Incoming file:" msgid "Incoming file:"
msgstr "受信中ファイル:" msgstr "受信中ファイル:"
msgid "Quit from Spreed Speak Freely?" msgid "Close this window and disconnect?"
msgstr "Spreed Speak Freelyを終了しますか?" msgstr ""
msgid "Restart required to apply updates. Click ok to restart now." msgid "Restart required to apply updates. Click ok to restart now."
msgstr "アップデート適用のため再起動してください.ここをクリックして再起動する." msgstr "アップデート適用のため再起動してください.ここをクリックして再起動する."

16
src/i18n/messages-ko.po

@ -1,16 +1,16 @@
# Korean translations for Spreed Speak Freely. # Korean translations for Spreed WebRTC.
# Copyright (C) 2014 struktur AG # Copyright (C) 2014 struktur AG
# This file is distributed under the same license as the Spreed Speak Freely # This file is distributed under the same license as the Spreed WebRTC
# project. # project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. # Curt Frisemo <curt.frisemo@spreed.com>, 2014.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Spreed Speak Freely 1.0\n" "Project-Id-Version: Spreed WebRTC 1.0\n"
"Report-Msgid-Bugs-To: simon@struktur.de\n" "Report-Msgid-Bugs-To: simon@struktur.de\n"
"POT-Creation-Date: 2014-05-05 16:53+0200\n" "POT-Creation-Date: 2014-05-23 10:35+0200\n"
"PO-Revision-Date: 2014-04-13 20:30+0900\n" "PO-Revision-Date: 2014-04-13 20:30+0900\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: Curt Frisemo <curt.frisemo@spreed.com>\n"
"Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n" "Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n"
"Plural-Forms: nplurals=1; plural=0\n" "Plural-Forms: nplurals=1; plural=0\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
@ -362,8 +362,8 @@ msgstr "공유 화일:"
msgid "Incoming file:" msgid "Incoming file:"
msgstr "도착하는 화일:" msgstr "도착하는 화일:"
msgid "Quit from Spreed Speak Freely?" msgid "Close this window and disconnect?"
msgstr "Spreed Speak Freely사용을 중지 하시겠습니까?" msgstr ""
msgid "Restart required to apply updates. Click ok to restart now." msgid "Restart required to apply updates. Click ok to restart now."
msgstr "업데이트를 적용하려면 재시작이 필요 합니다. 지금 재시작 하려면 ok를 클릭 하십시오" msgstr "업데이트를 적용하려면 재시작이 필요 합니다. 지금 재시작 하려면 ok를 클릭 하십시오"

14
src/i18n/messages-zh-cn.po

@ -1,14 +1,14 @@
# Chinese (China) translations for Spreed Speak Freely. # Chinese (China) translations for Spreed WebRTC.
# Copyright (C) 2014 struktur AG # Copyright (C) 2014 struktur AG
# This file is distributed under the same license as the Spreed Speak Freely # This file is distributed under the same license as the Spreed WebRTC
# project. # project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. # Curt Frisemo <curt.frisemo@spreed.com>, 2014.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Spreed Speak Freely 1.0\n" "Project-Id-Version: Spreed WebRTC 1.0\n"
"Report-Msgid-Bugs-To: simon@struktur.de\n" "Report-Msgid-Bugs-To: simon@struktur.de\n"
"POT-Creation-Date: 2014-05-05 16:53+0200\n" "POT-Creation-Date: 2014-05-23 10:35+0200\n"
"PO-Revision-Date: 2014-03-31 23:26+0100\n" "PO-Revision-Date: 2014-03-31 23:26+0100\n"
"Last-Translator: Michael P.\n" "Last-Translator: Michael P.\n"
"Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n" "Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n"
@ -363,8 +363,8 @@ msgstr "分享文件:"
msgid "Incoming file:" msgid "Incoming file:"
msgstr "发来文件:" msgstr "发来文件:"
msgid "Quit from Spreed Speak Freely?" msgid "Close this window and disconnect?"
msgstr "退出 Spreed Speak Freely?" msgstr ""
msgid "Restart required to apply updates. Click ok to restart now." msgid "Restart required to apply updates. Click ok to restart now."
msgstr "适用更新需重启,现在点击Ok重新启动。" msgstr "适用更新需重启,现在点击Ok重新启动。"

14
src/i18n/messages-zh-tw.po

@ -1,14 +1,14 @@
# Chinese (Taiwan) translations for Spreed Speak Freely. # Chinese (Taiwan) translations for Spreed WebRTC.
# Copyright (C) 2014 struktur AG # Copyright (C) 2014 struktur AG
# This file is distributed under the same license as the Spreed Speak Freely # This file is distributed under the same license as the Spreed WebRTC
# project. # project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. # Curt Frisemo <curt.frisemo@spreed.com>, 2014.
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Spreed Speak Freely 1.0\n" "Project-Id-Version: Spreed WebRTC 1.0\n"
"Report-Msgid-Bugs-To: simon@struktur.de\n" "Report-Msgid-Bugs-To: simon@struktur.de\n"
"POT-Creation-Date: 2014-05-05 16:53+0200\n" "POT-Creation-Date: 2014-05-23 10:35+0200\n"
"PO-Revision-Date: 2014-04-07 18:09+0800\n" "PO-Revision-Date: 2014-04-07 18:09+0800\n"
"Last-Translator: Michael P.\n" "Last-Translator: Michael P.\n"
"Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n" "Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n"
@ -363,8 +363,8 @@ msgstr "分享文件:"
msgid "Incoming file:" msgid "Incoming file:"
msgstr "發來文件:" msgstr "發來文件:"
msgid "Quit from Spreed Speak Freely?" msgid "Close this window and disconnect?"
msgstr "退出 Spreed Speak Freely?" msgstr ""
msgid "Restart required to apply updates. Click ok to restart now." msgid "Restart required to apply updates. Click ok to restart now."
msgstr "適用更新需重啟,現在點擊Ok重新啟動。" msgstr "適用更新需重啟,現在點擊Ok重新啟動。"

10
src/i18n/messages.pot

@ -1,15 +1,15 @@
# Translations template for Spreed Speak Freely. # Translations template for Spreed WebRTC.
# Copyright (C) 2014 struktur AG # Copyright (C) 2014 struktur AG
# This file is distributed under the same license as the Spreed Speak Freely # This file is distributed under the same license as the Spreed WebRTC
# project. # project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014. # FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Spreed Speak Freely 1.0\n" "Project-Id-Version: Spreed WebRTC 1.0\n"
"Report-Msgid-Bugs-To: simon@struktur.de\n" "Report-Msgid-Bugs-To: simon@struktur.de\n"
"POT-Creation-Date: 2014-05-05 16:53+0200\n" "POT-Creation-Date: 2014-05-23 10:35+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -362,7 +362,7 @@ msgstr ""
msgid "Incoming file:" msgid "Incoming file:"
msgstr "" msgstr ""
msgid "Quit from Spreed Speak Freely?" msgid "Close this window and disconnect?"
msgstr "" msgstr ""
msgid "Restart required to apply updates. Click ok to restart now." msgid "Restart required to apply updates. Click ok to restart now."

4
src/styles/_shame.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_audiolevel.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_audiovideo.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

27
src/styles/components/_bar.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -190,3 +190,26 @@
} }
} }
} }
@keyframes shakeityeah {
0% { transform: translate(2px, 1px) rotate(0deg); }
2% { transform: translate(-1px, -2px) rotate(-1deg); }
4% { transform: translate(-3px, 0px) rotate(1deg); }
8% { transform: translate(0px, 2px) rotate(0deg); }
10% { transform: translate(1px, -1px) rotate(1deg); }
12% { transform: translate(-1px, 2px) rotate(-1deg); }
14% { transform: translate(-3px, 1px) rotate(0deg); }
16% { transform: translate(2px, 1px) rotate(-1deg); }
18% { transform: translate(-1px, -1px) rotate(1deg); }
20% { transform: translate(2px, 2px) rotate(0deg); }
22% { transform: translate(1px, -2px) rotate(-1deg); }
24% { transform: translate(0px, 0px) rotate(0deg); }
}
.btn-shakeityeah {
animation-name: shakeityeah;
animation-duration: 4.0s;
transform-origin:50% 50%;
animation-iteration-count: infinite;
animation-timing-function: linear;
}

16
src/styles/components/_buddylist.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -126,13 +126,16 @@
} }
.buddy { .buddy {
&.withSubline .display-name { &.withSubline .buddy1 {
top: 15px; top: 15px;
} }
&.withSubline .buddy2 {
display: block;
}
&.hovered .buddyactions { &.hovered .buddyactions {
right: 0; right: 0;
} }
.avatar { .buddyPicture {
background: $actioncolor1; background: $actioncolor1;
border-radius: 2px; border-radius: 2px;
float: left; float: left;
@ -155,7 +158,7 @@
top: 0; top: 0;
} }
} }
.display-name { .buddy1 {
color: $componentfg1; color: $componentfg1;
font-weight: bold; font-weight: bold;
font-size: 14px; font-size: 14px;
@ -168,7 +171,7 @@
top: 24px; top: 24px;
white-space: nowrap; white-space: nowrap;
} }
.browser { .buddy2 {
color: $componentfg2; color: $componentfg2;
left: 65px; left: 65px;
overflow: hidden; overflow: hidden;
@ -176,6 +179,7 @@
right: 0px; right: 0px;
top: 33px; top: 33px;
white-space: nowrap; white-space: nowrap;
display: none;
} }
} }

8
src/styles/components/_chat.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -341,11 +341,11 @@
} }
.chat .message { .chat .message {
&.is_self .avatar { &.is_self .buddyPicture {
left: auto; left: auto;
right: 4px; right: 4px;
} }
.avatar { .buddyPicture {
background: $actioncolor1; background: $actioncolor1;
border-radius: 2px; border-radius: 2px;
height: 46px; height: 46px;

8
src/styles/components/_fileinfo.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -71,10 +71,10 @@
display: block; display: block;
left: 0; left: 0;
margin: 0 auto; margin: 0 auto;
padding: 4px; padding: 3px;
position: absolute; position: absolute;
text-shadow: 1px 1px 1px white; text-shadow: 1px 1px 1px white;
top: 1px; top: 0px;
right: 0; right: 0;
z-index: 5; z-index: 5;
} }

4
src/styles/components/_rightslide.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_roombar.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_screenshare.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_settings.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_social.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_usability.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/global/_angular.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/global/_animations.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

5
src/styles/global/_base.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -24,7 +24,6 @@ body {
background-clip: padding-box; background-clip: padding-box;
background-color: $background; background-color: $background;
height: 100%; height: 100%;
font: normal $base-font-size $font-sans-serif;
} }
body { body {

4
src/styles/global/_nicescroll.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

10
src/styles/global/_overlaybar.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -49,7 +49,7 @@
margin-top: 2px; margin-top: 2px;
} }
label { label {
padding-top: 7px !important; padding-top: 6px !important;
} }
} }
@ -71,12 +71,12 @@
color: $bordercolor; color: $bordercolor;
display: block; display: block;
font-size: 20px; font-size: 20px;
top: 0px;
left: 3px; left: 3px;
opacity: .7; opacity: .7;
padding: 6px; padding: 4px 6px;
position: absolute; position: absolute;
pointer-events: auto; pointer-events: auto;
top: 1px;
vertical-align: middle; vertical-align: middle;
z-index: 15; z-index: 15;
} }

40
src/styles/global/_variables.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -19,9 +19,6 @@
* *
*/ */
// ** Custom Variables **
// --------------------------------------------------
// general // general
$background: #e5e5e5; $background: #e5e5e5;
$componentbg: #f5f5f5; $componentbg: #f5f5f5;
@ -46,7 +43,7 @@ $loading: #ddd;
// font // font
$font-sans-serif: "Helvetica Neue",Helvetica,Arial,sans-serif; $font-sans-serif: "Helvetica Neue",Helvetica,Arial,sans-serif;
$base-font-size: 13px; // compass $base-font-size: 13px; // compass
$base-line-height: 19px; // compass $base-line-height: 1.53846156; // compass
// audio video // audio video
$audiovideolevel: $action-enable; $audiovideolevel: $action-enable;
@ -125,44 +122,27 @@ $breakpoint-useability-large: 1020px;
$breakpoint-small: 480px; $breakpoint-small: 480px;
$breakpoint-medium: 700px; $breakpoint-medium: 700px;
$breakpoint-large: 1280px; $breakpoint-large: 1280px;
$breakpoint-video-small: 590px; $breakpoint-video-small: 590px;
$breakpoint-video-medium: 630px; $breakpoint-video-medium: 630px;
$breakpoint-chat-small: 210px; $breakpoint-chat-small: 210px;
$breakpoint-settings-medium: 630px; $breakpoint-settings-medium: 630px;
// touch specific // touch specific
$tap-highlight: rgba(0, 0, 0, 0); $tap-highlight: rgba(0, 0, 0, 0);
// Fontawsome changed variables
// ** Fontawsome changed variables **
// original at libs/fontawesome/_variables.scss // original at libs/fontawesome/_variables.scss
// -------------------------- $fa-css-prefix: fa;
$fa-css-prefix: fa;
// Bootstrap changed variables
// ** Bootstrap changed variables **
// original at libs/bootstrap/_variables.scss // original at libs/bootstrap/_variables.scss
// -------------------------------------------------- $body-bg: $background;
//== Scaffolding
//
// ## Settings for some of the most global styles.
//** Background color for `<body>`.
$body-bg: $background;
//== Typography
//
//## Font, line-height, and color for body text, headings, and more.
// typography
// font, line-height, and color for body text, headings, and more
$font-family-sans-serif: $font-sans-serif; $font-family-sans-serif: $font-sans-serif;
$font-family-serif: Georgia, "Times New Roman", Times, serif; $font-family-serif: Georgia, "Times New Roman", Times, serif;
//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace; $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
$font-family-base: $font-family-sans-serif; $font-family-base: $font-family-sans-serif;
$font-size-base: $base-font-size; $font-size-base: $base-font-size;
$line-height-base: $base-line-height;

4
src/styles/libs/_dialogs.scss

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

4
src/styles/main.scss

@ -1,8 +1,8 @@
/*! /*!
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

BIN
static/img/opengraph-image.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

322
static/js/app.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -19,157 +19,177 @@
* *
*/ */
define([ define([
'require', 'require',
'jquery', 'jquery',
'underscore', 'underscore',
'angular', 'angular',
'modernizr', 'modernizr',
'moment', 'moment',
'services/services', 'services/services',
'directives/directives', 'directives/directives',
'filters/filters', 'filters/filters',
'controllers/controllers', 'controllers/controllers',
'translation/languages', 'translation/languages',
'ui-bootstrap', 'ui-bootstrap',
'angular-sanitize', 'angular-sanitize',
'angular-animate', 'angular-animate',
'angular-humanize', 'angular-humanize',
'angular-route', 'angular-route',
'mobile-events', 'mobile-events',
'dialogs' 'dialogs'
], function(require, $, _, angular, modernizr, moment, services, directives, filters, controllers, languages) { ], function(require, $, _, angular, modernizr, moment, services, directives, filters, controllers, languages) {
var initialize = function(ms) { // Simple and fast split based URL query parser based on location.search. We require this before the
// angular App is bootstrap to control initialization parameters like translation based on URL parameters.
var modules = ['ui.bootstrap', 'ngSanitize', 'ngAnimate', 'ngHumanize', 'ngRoute', 'dialogs']; var urlQuery = (function() {
if (ms && ms.length) { return (function(a) {
_.each(ms, function(module) { if (a === "") {
modules.push(module); return {};
}); }
} var b = {};
for (var i = 0; i < a.length; ++i) {
var app = angular.module('app', modules); var p = a[i].split('=');
services.initialize(app); if (p.length != 2) {
directives.initialize(app); continue;
filters.initialize(app); }
controllers.initialize(app); b[p[0]] = window.decodeURIComponent(p[1].replace(/\+/g, " "));
}
app.config(["$compileProvider", "$locationProvider", "$routeProvider", function($compileProvider, $locationProvider, $routeProvider) { return b;
// Allow angular to use filesystem: hrefs which would else be prefixed with unsafe:. })(window.location.search.substr(1).split("&"));
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|filesystem|blob):/); }());
$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|filesystem|blob):|data:image\//);
// Setup routing var initialize = function(ms) {
$routeProvider.when("/:room", {});
// Use HTML5 routing. var modules = ['ui.bootstrap', 'ngSanitize', 'ngAnimate', 'ngHumanize', 'ngRoute', 'dialogs'];
$locationProvider.html5Mode(true); if (ms && ms.length) {
}]); _.each(ms, function(module) {
modules.push(module);
app.run(["$rootScope", "mediaStream", "translation", function($rootScope, mediaStream, translation) { });
translation.inject($rootScope); }
console.log("Initializing ...");
mediaStream.initialize($rootScope, translation); var app = angular.module('app', modules);
}]); services.initialize(app);
directives.initialize(app);
app.constant("availableLanguages", languages); filters.initialize(app);
controllers.initialize(app);
angular.element(document).ready(function() {
app.config(["$compileProvider", "$locationProvider", "$routeProvider", function($compileProvider, $locationProvider, $routeProvider) {
var globalContext = JSON.parse($("#globalcontext").text()); // Allow angular to use filesystem: hrefs which would else be prefixed with unsafe:.
app.constant("globalContext", globalContext); $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|filesystem|blob):/);
$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|file|filesystem|blob):|data:image\//);
// Configure language. // Setup routing
var lang = (function() { $routeProvider.when("/:room", {});
var lang; // Use HTML5 routing.
var html = document.getElementsByTagName("html")[0]; $locationProvider.html5Mode(true);
if (modernizr.localstorage) { }]);
lang = localStorage.getItem("mediastream-language");
if (!lang || lang === "undefined") { app.run(["$rootScope", "mediaStream", "translation", function($rootScope, mediaStream, translation) {
lang = null; translation.inject($rootScope);
} console.log("Initializing ...");
} mediaStream.initialize($rootScope, translation);
if (!lang) { }]);
var browserLanguages = [];
// Expand browser languages with combined fallback. app.constant("availableLanguages", languages);
_.each(globalContext.Languages, function(l) {
browserLanguages.push(l); angular.element(document).ready(function() {
if (l.indexOf("-") != -1) {
browserLanguages.push(l.split("-")[0]) var globalContext = JSON.parse($("#globalcontext").text());
} app.constant("globalContext", globalContext);
});
// Loop through browser languages and use first one we got. // Configure language.
for (var i=0; i<browserLanguages.length; i++) { var lang = (function() {
if (languages.hasOwnProperty(browserLanguages[i])) { var lang = "en";
lang = browserLanguages[i]; var wanted = [];
break; var html = document.getElementsByTagName("html")[0];
} // Get from storage.
} if (modernizr.localstorage) {
} var lsl = localStorage.getItem("mediastream-language");
if (!lang) { if (lsl && lsl !== "undefined") {
lang = "en"; wanted.push(lsl);
} }
html.setAttribute("lang", lang); }
return lang; // Get from query.
}()); var qsl = urlQuery.lang;
if (qsl) {
// Prepare bootstrap function with injected locale data. wanted.push(qsl);
var domain = "messages"; }
var catalog = domain + "-" + lang; // Expand browser languages with combined fallback.
var bootstrap = function(translationData) { _.each(globalContext.Languages, function(l) {
if (!translationData) { wanted.push(l);
// Fallback catalog in case translation could not be loaded. if (l.indexOf("-") != -1) {
lang = "en"; wanted.push(l.split("-")[0]);
translationData = {}; }
translationData.locale_data = {}; });
translationData.domain = domain; // Loop through browser languages and use first one we got.
translationData.locale_data[domain] = { for (var i = 0; i < wanted.length; i++) {
"": { if (languages.hasOwnProperty(wanted[i])) {
"domain": domain, lang = wanted[i];
"lang": lang, break;
"plural_forms" : "nplurals=2; plural=(n != 1);" }
} }
} html.setAttribute("lang", lang);
} return lang;
// Set date language too. }());
moment.lang([lang, "en"]);
// Inject translation data globally. // Prepare bootstrap function with injected locale data.
app.constant("translationData", translationData); var domain = "messages";
// Bootstrap AngularJS app. var catalog = domain + "-" + lang;
console.log("Bootstrapping ..."); var bootstrap = function(translationData) {
angular.bootstrap(document, ['app']); if (!translationData) {
} // Fallback catalog in case translation could not be loaded.
lang = "en";
if (lang !== "en") { translationData = {};
// Load translation file. translationData.locale_data = {};
//console.log("Loading translation data: " + lang); translationData.domain = domain;
$.ajax({ translationData.locale_data[domain] = {
dataType: "json", "": {
url: require.toUrl('translation/'+catalog+'.json'), "domain": domain,
success: function(data) { "lang": lang,
//console.log("Loaded translation data."); "plural_forms": "nplurals=2; plural=(n != 1);"
bootstrap(data); }
}, };
error: function(err, textStatus, errorThrown) { }
console.warn("Failed to load translation data " + catalog + ": "+ errorThrown); // Set date language too.
bootstrap(null); moment.lang([lang, "en"]);
} // Inject translation data globally.
}); app.constant("translationData", translationData);
} else { // Bootstrap AngularJS app.
// No need to load english as this is built in. console.log("Bootstrapping ...");
bootstrap(); angular.bootstrap(document, ['app']);
} };
}); if (lang !== "en") {
// Load translation file.
return app; //console.log("Loading translation data: " + lang);
$.ajax({
}; dataType: "json",
url: require.toUrl('translation/' + catalog + '.json'),
return { success: function(data) {
initialize: initialize //console.log("Loaded translation data.");
}; bootstrap(data);
},
error: function(err, textStatus, errorThrown) {
console.warn("Failed to load translation data " + catalog + ": " + errorThrown);
bootstrap(null);
}
});
} else {
// No need to load english as this is built in.
bootstrap();
}
});
return app;
};
return {
initialize: initialize
};
}); });

7
static/js/base.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -32,5 +32,4 @@ define([
'rAF', 'rAF',
'humanize', 'humanize',
'sha', 'sha',
'sjcl' 'sjcl'], function() {});
], function(){});

927
static/js/controllers/chatroomcontroller.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,461 +20,472 @@
*/ */
define(['underscore', 'moment', 'text!partials/fileinfo.html'], function(_, moment, templateFileInfo) { define(['underscore', 'moment', 'text!partials/fileinfo.html'], function(_, moment, templateFileInfo) {
// ChatroomController // ChatroomController
return ["$scope", "$element", "$window", "safeMessage", "safeDisplayName", "$compile", "$filter", "translation", function($scope, $element, $window, safeMessage, safeDisplayName, $compile, $filter, translation) { return ["$scope", "$element", "$window", "safeMessage", "safeDisplayName", "$compile", "$filter", "translation", function($scope, $element, $window, safeMessage, safeDisplayName, $compile, $filter, translation) {
$scope.outputElement = $(".output", $element); $scope.outputElement = $(".output", $element);
$scope.inputElement = $(".input", $element); $scope.inputElement = $(".input", $element);
$scope.bodyElement = $(".chatbody", $element); $scope.bodyElement = $(".chatbody", $element);
var lastSender = null; var lastSender = null;
var lastDate = null; var lastDate = null;
var lastMessageContainer = null; var lastMessageContainer = null;
var senderExpired = null; var senderExpired = null;
var isTyping = false; var isTyping = false;
var isTypingExpired = null; var isTypingExpired = null;
var peerTypingExpired = null; var peerTypingExpired = null;
var p2p = false; var p2p = false;
var scrollAfterInput = false; var scrollAfterInput = false;
// Mark seen on several events. // Mark seen on several events.
$scope.bodyElement.on("mouseover mouseenter touchstart", _.debounce(function(event) { $scope.bodyElement.on("mouseover mouseenter touchstart", _.debounce(function(event) {
$scope.$parent.seen(); $scope.$parent.seen();
$scope.$apply(); $scope.$apply();
}, 100)); }, 100));
var displayName = safeDisplayName; var displayName = safeDisplayName;
var buddyImageSrc = $filter("buddyImageSrc"); var buddyImageSrc = $filter("buddyImageSrc");
var fileInfo = $compile(templateFileInfo); var fileInfo = $compile(templateFileInfo);
var knowMessage = { var knowMessage = {
r: {}, r: {},
pending: [], pending: [],
register: function(element, mid, status, received) { register: function(element, mid, status, received) {
if (mid) { if (mid) {
if (knowMessage.r.hasOwnProperty(mid)) { if (knowMessage.r.hasOwnProperty(mid)) {
console.warn("Duplicate chat message registration.", mid, element, status); console.warn("Duplicate chat message registration.", mid, element, status);
return; return;
} }
var e = knowMessage.r[mid] = { var e = knowMessage.r[mid] = {
element: element, element: element,
status: status status: status
} }
if (e.status) { if (e.status) {
element.addClass(e.status); element.addClass(e.status);
} }
if (received) { if (received) {
knowMessage.pending.push(mid); knowMessage.pending.push(mid);
$scope.$emit("submitreceived", mid); $scope.$emit("submitreceived", mid);
} }
} }
}, },
update: function(mid, status) { update: function(mid, status) {
var e = knowMessage.r[mid]; var e = knowMessage.r[mid];
if (e) { if (e) {
if (e.status !== status && status) { if (e.status !== status && status) {
if (e.status) { if (e.status) {
e.element.removeClass(e.status); e.element.removeClass(e.status);
} }
e.status = status; e.status = status;
e.element.addClass(e.status); e.element.addClass(e.status);
if (status === "received" || status === "read") { if (status === "received" || status === "read") {
// last one - cleanup // last one - cleanup
delete knowMessage.r[mid]; delete knowMessage.r[mid];
} }
} }
} }
}, },
seen: function() { seen: function() {
var pending = knowMessage.pending; var pending = knowMessage.pending;
if (pending.length) { if (pending.length) {
knowMessage.pending = []; knowMessage.pending = [];
$scope.$emit("submitseen", pending); $scope.$emit("submitseen", pending);
_.each(pending, function(mid) { _.each(pending, function(mid) {
knowMessage.update(mid, "read"); knowMessage.update(mid, "read");
}); });
} }
} }
}; };
// Make sure that chat links are openend in a new window. // Make sure that chat links are openend in a new window.
$element.on("click", function(event) { $element.on("click", function(event) {
var elem = $(event.target); var elem = $(event.target);
if (elem.is("a")) { if (elem.is("a")) {
var url = elem.attr("href"); var url = elem.attr("href");
if (url && !elem.attr("download")) { if (url && !elem.attr("download")) {
if (url.match(/mailto:/gi) === null) { if (url.match(/mailto:/gi) === null) {
event.preventDefault(); event.preventDefault();
$window.open(elem.attr("href"), "_blank"); $window.open(elem.attr("href"), "_blank");
} }
} }
}; }
}); });
$scope.$watch("input", function(newvalue) { $scope.$watch("input", function(newvalue) {
$scope.$parent.seen(); $scope.$parent.seen();
$window.clearTimeout(isTypingExpired); $window.clearTimeout(isTypingExpired);
if (!newvalue) { if (!newvalue) {
return; return;
} }
if (!isTyping) { if (!isTyping) {
isTyping = true; isTyping = true;
$scope.$emit("typing", {who: "local", status: "start"}); $scope.$emit("typing", {
} who: "local",
isTypingExpired = $window.setTimeout(function() { status: "start"
isTyping = false; });
$scope.$emit("typing", {who: "local", status: "stop"}); }
}, 4000); isTypingExpired = $window.setTimeout(function() {
isTyping = false;
}); $scope.$emit("typing", {
who: "local",
$scope.reset = function() { status: "stop"
$scope.input = ""; });
isTyping = false; }, 4000);
$window.clearTimeout(isTypingExpired);
}; });
$scope.focus = function() { $scope.reset = function() {
$scope.inputElement.focus(); $scope.input = "";
}; isTyping = false;
$window.clearTimeout(isTypingExpired);
$scope.submit = function() { };
var input = $scope.input;
if (input) { $scope.focus = function() {
scrollAfterInput = true; $scope.inputElement.focus();
$scope.$emit("submit", $scope.input); };
$scope.reset();
$scope.focus(); $scope.submit = function() {
} var input = $scope.input;
}; if (input) {
scrollAfterInput = true;
$scope.canScroll = function() { $scope.$emit("submit", $scope.input);
$scope.reset();
var o = $scope.outputElement.get(0); $scope.focus();
if ((o.clientHeight - 20) < o.scrollHeight) { }
if (!scrollAfterInput && (o.clientHeight + 20) < (o.scrollHeight - o.scrollTop)) { };
// Manually scrolled -> do nothing.
} else { $scope.canScroll = function() {
scrollAfterInput = false;
// Return scroll function. var o = $scope.outputElement.get(0);
return function() { if ((o.clientHeight - 20) < o.scrollHeight) {
o.scrollTop = o.scrollHeight; if (!scrollAfterInput && (o.clientHeight + 20) < (o.scrollHeight - o.scrollTop)) {
}; // Manually scrolled -> do nothing.
} } else {
} scrollAfterInput = false;
return false; // Return scroll function.
return function() {
} o.scrollTop = o.scrollHeight;
};
$scope.display = function(s, nodes, extra_css, title, picture) { }
}
var container; return false;
var element;
var scroll = this.canScroll(); }
lastMessageContainer = null;
$scope.display = function(s, nodes, extra_css, title, picture) {
if (!extra_css) {
extra_css = ""; var container;
} var element;
if (s || title || picture) { var scroll = this.canScroll();
container = $('<div class="message ' + extra_css + '"></div>'); lastMessageContainer = null;
if (title) {
container.prepend(title); if (!extra_css) {
} extra_css = "";
if (picture) { }
container.prepend(picture); if (s || title || picture) {
} container = $('<div class="message ' + extra_css + '"></div>');
lastMessageContainer = $("<ul>").appendTo(container); if (title) {
if ($.trim(s)) { container.prepend(title);
element = $("<li>").html(s).appendTo(lastMessageContainer); }
} if (picture) {
} container.prepend(picture);
if (nodes) { }
if (container) { lastMessageContainer = $("<ul>").appendTo(container);
// Insert at the end of previously created container. if ($.trim(s)) {
container.append(nodes); element = $("<li>").html(s).appendTo(lastMessageContainer);
} else { }
$scope.outputElement.append(nodes); }
} if (nodes) {
if (container && lastMessageContainer) { if (container) {
lastMessageContainer = $("<ul>").appendTo(container); // Insert at the end of previously created container.
} container.append(nodes);
} } else {
$scope.outputElement.append(nodes);
if (container) { }
$scope.outputElement.append(container); if (container && lastMessageContainer) {
} lastMessageContainer = $("<ul>").appendTo(container);
}
if (scroll) { }
scroll();
} if (container) {
$scope.outputElement.append(container);
return element; }
}; if (scroll) {
scroll();
$scope.$on("display", function(event, s, nodes) { }
$scope.display(s, nodes);
}); return element;
$scope.append = function(s, nodes) { };
if (!lastMessageContainer) { $scope.$on("display", function(event, s, nodes) {
return; $scope.display(s, nodes);
} });
var scroll = this.canScroll(); $scope.append = function(s, nodes) {
var li = $("<li>"); if (!lastMessageContainer) {
li.html(s) return;
lastMessageContainer.append(li) }
if (nodes) { var scroll = this.canScroll();
var parent = lastMessageContainer.parent();
parent.append(nodes); var li = $("<li>");
lastMessageContainer = $("<ul>"); li.html(s)
parent.append(lastMessageContainer); lastMessageContainer.append(li)
}
if (nodes) {
if (scroll) { var parent = lastMessageContainer.parent();
scroll(); parent.append(nodes);
} lastMessageContainer = $("<ul>");
parent.append(lastMessageContainer);
return li; }
}; if (scroll) {
scroll();
$scope.showtime = function(d, format, compare) { }
var m; return li;
if (d) {
m = moment(d); };
} else {
m = moment(); $scope.showtime = function(d, format, compare) {
}
if (!format) { var m;
format = "LLL"; if (d) {
} m = moment(d);
} else {
var datestring = m.format(format); m = moment();
if (compare && datestring === compare) { }
// Do nothing if compare matches. if (!format) {
return datestring; format = "LLL";
} }
$scope.display(null, $("<i>" + datestring + "</i>"));
if (!d) { var datestring = m.format(format);
lastSender = null; if (compare && datestring === compare) {
} // Do nothing if compare matches.
return datestring; return datestring;
}
}; $scope.display(null, $("<i>" + datestring + "</i>"));
if (!d) {
$scope.showdate = function(d) { lastSender = null;
}
lastDate = $scope.showtime(d, "LL", lastDate); return datestring;
}; };
$scope.showmessage = function(from, timestamp, message, nodes) { $scope.showdate = function(d) {
var userid = $scope.$parent.$parent.id; lastDate = $scope.showtime(d, "LL", lastDate);
// Prepare message to display. };
var s = [];
if (message) { $scope.showmessage = function(from, timestamp, message, nodes) {
s.push(message);
$scope.$emit("incoming", message, from, userid); var userid = $scope.$parent.$parent.id;
}
// Prepare message to display.
var is_new_message = lastSender !== from; var s = [];
var is_self = from === userid; if (message) {
s.push(message);
var extra_css = ""; $scope.$emit("incoming", message, from, userid);
var title = null; }
var picture = null;
var is_new_message = lastSender !== from;
var showTitleAndPicture = function() { var is_self = from === userid;
if ($scope.isgroupchat) {
title = $("<strong>"); var extra_css = "";
title.html(displayName(from, true)); var title = null;
extra_css += "with_name "; var picture = null;
var imgSrc = buddyImageSrc(from);
picture = $('<div class="avatar"><i class="fa fa-user fa-3x"/><img/></div>'); var showTitleAndPicture = function() {
if (imgSrc) { if ($scope.isgroupchat) {
picture.find("img").attr("src", imgSrc); title = $("<strong>");
} title.html(displayName(from, true));
} extra_css += "with_name ";
}; var imgSrc = buddyImageSrc(from);
picture = $('<div class="buddyPicture"><i class="fa fa-user fa-3x"/><img/></div>');
if (is_new_message) { if (imgSrc) {
lastSender = from; picture.find("img").attr("src", imgSrc);
$scope.showdate(timestamp); }
showTitleAndPicture() }
} };
var message = s.join(" "); if (is_new_message) {
lastSender = from;
if (!is_new_message) { $scope.showdate(timestamp);
var element = this.append(message, nodes); showTitleAndPicture()
if (element) { }
return element;
} var strMessage = s.join(" ");
showTitleAndPicture();
} if (!is_new_message) {
var element = this.append(strMessage, nodes);
if (is_self) { if (element) {
extra_css += "is_self"; return element;
} else { }
extra_css += "is_remote"; showTitleAndPicture();
} }
if (timestamp) {
var ts = $('<div class="timestamp"/>'); if (is_self) {
ts.text(moment(timestamp).format("H:mm")); extra_css += "is_self";
if (nodes) { } else {
nodes = nodes.add(ts); extra_css += "is_remote";
} else { }
nodes = ts; if (timestamp) {
} var ts = $('<div class="timestamp"/>');
} ts.text(moment(timestamp).format("H:mm"));
return $scope.display(message, nodes, extra_css, title, picture); if (nodes) {
nodes = nodes.add(ts);
}; } else {
nodes = ts;
$scope.$on("seen", function() { }
}
knowMessage.seen(); return $scope.display(strMessage, nodes, extra_css, title, picture);
}); };
$scope.$on("p2p", function(event, state) { $scope.$on("seen", function() {
//console.log("changed p2p state", state, p2p);
var msg; knowMessage.seen();
if (state) {
msg = translation._("Peer to peer chat active."); });
} else {
msg = translation._("Peer to peer chat is now off."); $scope.$on("p2p", function(event, state) {
} //console.log("changed p2p state", state, p2p);
$scope.display(null, $("<i class='p2p'><span class='icon-exchange'></span> " + msg + "</i>")); var msg;
}); if (state) {
msg = translation._("Peer to peer chat active.");
$scope.$on("focus", function() { } else {
msg = translation._("Peer to peer chat is now off.");
$scope.focus(); }
$scope.display(null, $("<i class='p2p'><span class='icon-exchange'></span> " + msg + "</i>"));
}); });
$scope.$on("received", function(event, from, data) { $scope.$on("focus", function() {
var userid = $scope.$parent.$parent.id; $scope.focus();
var mid = data.Mid || null;
});
switch (data.Type) {
case "LeftOrJoined": $scope.$on("received", function(event, from, data) {
$scope.showtime(new Date());
if (data.LeftOrJoined === "left") { var userid = $scope.$parent.$parent.id;
$scope.display(null, $("<i>"+ displayName(from) + translation._(" is now offline.") + "</i>")); var mid = data.Mid || null;
} else {
$scope.display(null, $("<i>"+ displayName(from) + translation._(" is now online.") + "</i>")); switch (data.Type) {
} case "LeftOrJoined":
break; $scope.showtime(new Date());
case "Log": if (data.LeftOrJoined === "left") {
$scope.showtime(new Date()); $scope.display(null, $("<i>" + displayName(from) + translation._(" is now offline.") + "</i>"));
$scope.display(null, data.Log); } else {
break; $scope.display(null, $("<i>" + displayName(from) + translation._(" is now online.") + "</i>"));
case "Message": }
default: break;
case "Log":
// Definitions. $scope.showtime(new Date());
var message = null; $scope.display(null, data.Log);
var nodes = null; break;
var fromself = from === userid; default:
var noop = false;
var element = null; // Definitions.
var message = null;
var timestamp = data.Time; var nodes = null;
if (!timestamp) { var fromself = from === userid;
timestamp = new Date(); var noop = false;
} var element = null;
// Process internal status messages. var timestamp = data.Time;
if (data.Status) { if (!timestamp) {
timestamp = new Date();
if (!mid && data.Status.Mid) { }
mid = data.Status.Mid; // Inner Mid means internal chat status.
} // Process internal status messages.
if (data.Status) {
// Typing notification.
if (data.Status.Typing && !fromself) { if (!mid && data.Status.Mid) {
$window.clearTimeout(peerTypingExpired); mid = data.Status.Mid; // Inner Mid means internal chat status.
$scope.$emit("typing", {who: "peer", status: data.Status.Typing}); }
if (data.Status.Typing === "stop") {
peerTypingExpired = $window.setTimeout(function() { // Typing notification.
$scope.$emit("typing", {who: "peer", status: "no"}); if (data.Status.Typing && !fromself) {
}, 20000); $window.clearTimeout(peerTypingExpired);
} $scope.$emit("typing", {
} who: "peer",
status: data.Status.Typing
// Mid updates. });
if (mid && data.Status.State) { if (data.Status.Typing === "stop") {
knowMessage.update(mid, data.Status.State); peerTypingExpired = $window.setTimeout(function() {
} $scope.$emit("typing", {
who: "peer",
// Mid batch updates. status: "no"
if (data.Status.SeenMids) { });
_.each(data.Status.SeenMids, function(mid) { }, 20000);
knowMessage.update(mid, "received"); }
}); }
}
// Mid updates.
// File offers. if (mid && data.Status.State) {
if (data.Status.FileInfo) { knowMessage.update(mid, data.Status.State);
var subscope = $scope.$new(); }
subscope.info = data.Status.FileInfo;
subscope.from = from; // Mid batch updates.
fileInfo(subscope, function(clonedElement, scope) { if (data.Status.SeenMids) {
var text = fromself ? translation._("You share file:") : translation._("Incoming file:"); _.each(data.Status.SeenMids, function(mid) {
element = $scope.showmessage(from, timestamp, text, clonedElement); knowMessage.update(mid, "received");
}); });
noop = true; }
}
// File offers.
// Ignore unknown status messages. if (data.Status.FileInfo) {
if (message === null && nodes === null) { var subscope = $scope.$new();
noop = true; subscope.info = data.Status.FileInfo;
} subscope.from = from;
fileInfo(subscope, function(clonedElement, scope) {
} var text = fromself ? translation._("You share file:") : translation._("Incoming file:");
element = $scope.showmessage(from, timestamp, text, clonedElement);
// Do nothing when where is nothing. });
if (!data.Message && message === null && nodes === null) { noop = true;
noop = true; }
}
// Ignore unknown status messages.
if (!noop) { if (message === null && nodes === null) {
// Default handling is to use full message with security in place. noop = true;
if (message === null && nodes === null && data.Message && typeof data.Message == "string") { }
message = safeMessage(data.Message);
} }
// Show the beast.
element = $scope.showmessage(from, timestamp, message, nodes); // Do nothing when where is nothing.
} if (!data.Message && message === null && nodes === null) {
noop = true;
if (element && mid && !$scope.isgroupchat) { }
knowMessage.register(element, mid, fromself ? "sending" : "unread", !fromself);
} if (!noop) {
// Default handling is to use full message with security in place.
break; if (message === null && nodes === null && data.Message && typeof data.Message == "string") {
message = safeMessage(data.Message);
} }
// Show the beast.
// Reset last sender to allow a new time stamp after a while. element = $scope.showmessage(from, timestamp, message, nodes);
$window.clearTimeout(senderExpired); }
senderExpired = $window.setTimeout(function() {
lastSender = null; if (element && mid && !$scope.isgroupchat) {
}, 61000); knowMessage.register(element, mid, fromself ? "sending" : "unread", !fromself);
}
});
break;
}];
}
// Reset last sender to allow a new time stamp after a while.
$window.clearTimeout(senderExpired);
senderExpired = $window.setTimeout(function() {
lastSender = null;
}, 61000);
});
}];
}); });

43
static/js/controllers/controllers.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -19,29 +19,28 @@
* *
*/ */
define([ define([
'underscore', 'underscore',
'controllers/mediastreamcontroller', 'controllers/mediastreamcontroller',
'controllers/statusmessagecontroller', 'controllers/statusmessagecontroller',
'controllers/chatroomcontroller', 'controllers/chatroomcontroller',
'controllers/roomchangecontroller' 'controllers/roomchangecontroller'], function(_, MediastreamController, StatusmessageController, ChatroomController, RoomchangeController) {
], function(_, MediastreamController, StatusmessageController, ChatroomController, RoomchangeController) {
var controllers = { var controllers = {
MediastreamController: MediastreamController, MediastreamController: MediastreamController,
StatusmessageController: StatusmessageController, StatusmessageController: StatusmessageController,
ChatroomController: ChatroomController, ChatroomController: ChatroomController,
RoomchangeController: RoomchangeController RoomchangeController: RoomchangeController
}; };
var initialize = function (angModule) { var initialize = function(angModule) {
_.each(controllers, function(controller, name) { _.each(controllers, function(controller, name) {
angModule.controller(name, controller); angModule.controller(name, controller);
}) })
} }
return { return {
initialize: initialize initialize: initialize
}; };
}); });

1491
static/js/controllers/mediastreamcontroller.js

File diff suppressed because it is too large Load Diff

95
static/js/controllers/roomchangecontroller.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,58 +20,59 @@
*/ */
define([], function() { define([], function() {
// RoomchangeController // RoomchangeController
return ["$scope", "$element", "$window", "$location", "mediaStream", "$http", "$timeout", function($scope, $element, $window, $location, mediaStream, $http, $timeout) { return ["$scope", "$element", "$window", "$location", "mediaStream", "$http", "$timeout", function($scope, $element, $window, $location, mediaStream, $http, $timeout) {
//console.log("Room change controller", $element, $scope.roomdata); //console.log("Room change controller", $element, $scope.roomdata);
var url = mediaStream.url.api("rooms"); var url = mediaStream.url.api("rooms");
var ctrl = this; var ctrl = this;
ctrl.enabled = true; ctrl.enabled = true;
ctrl.getRoom = function(cb) { ctrl.getRoom = function(cb) {
$http({ $http({
method: "POST", method: "POST",
url: url, url: url,
data: $.param({ data: $.param({}),
}), headers: {
headers: {'Content-Type': 'application/x-www-form-urlencoded'} 'Content-Type': 'application/x-www-form-urlencoded'
}). }
success(function(data, status) { }).
cb(data); success(function(data, status) {
}). cb(data);
error(function() { }).
console.error("Failed to retrieve room link."); error(function() {
cb({}); console.error("Failed to retrieve room link.");
}); cb({});
}; });
};
$scope.changeRoomToId = function(id) { $scope.changeRoomToId = function(id) {
var roomid = $window.encodeURIComponent(id); var roomid = $window.encodeURIComponent(id);
$location.path("/"+roomid); $location.path("/" + roomid);
return roomid; return roomid;
}; };
$scope.$on("$destroy", function() { $scope.$on("$destroy", function() {
//console.log("Room change controller destroyed"); //console.log("Room change controller destroyed");
ctrl.enabled = false; ctrl.enabled = false;
}); });
var roomDataLinkInput = $element.find(".roomdata-link-input"); var roomDataLinkInput = $element.find(".roomdata-link-input");
if (roomDataLinkInput.length) { if (roomDataLinkInput.length) {
$scope.roomdata = {}; $scope.roomdata = {};
$timeout(function() { $timeout(function() {
if (ctrl.enabled) { if (ctrl.enabled) {
ctrl.getRoom(function(roomdata) { ctrl.getRoom(function(roomdata) {
console.info("Retrieved room data", roomdata); console.info("Retrieved room data", roomdata);
$scope.roomdata = roomdata; $scope.roomdata = roomdata;
roomdata.link = $scope.roomlink = mediaStream.url.room(roomdata.name); roomdata.link = $scope.roomlink = mediaStream.url.room(roomdata.name);
}); });
} }
}, 100); }, 100);
} }
}]; }];
}); });

38
static/js/controllers/statusmessagecontroller.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,25 +20,25 @@
*/ */
define([], function() { define([], function() {
// StatusmessageController // StatusmessageController
return ["$scope", "mediaStream", function($scope, mediaStream) { return ["$scope", "mediaStream", function($scope, mediaStream) {
$scope.doHangup = function() { $scope.doHangup = function() {
mediaStream.webrtc.doHangup(); mediaStream.webrtc.doHangup();
} }
$scope.doAbort = function() { $scope.doAbort = function() {
mediaStream.webrtc.doHangup("abort", $scope.dialing); mediaStream.webrtc.doHangup("abort", $scope.dialing);
} }
$scope.doReconnect = function() { $scope.doReconnect = function() {
mediaStream.connector.reconnect(); mediaStream.connector.reconnect();
} }
$scope.doAccept = function() { $scope.doAccept = function() {
mediaStream.webrtc.doAccept(); mediaStream.webrtc.doAccept();
} }
$scope.doReject = function() { $scope.doReject = function() {
mediaStream.webrtc.doHangup('reject'); mediaStream.webrtc.doHangup('reject');
} }
}]; }];
}); });

46
static/js/directives/audiolevel.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -51,7 +51,7 @@ define(['jquery', 'underscore', 'rAF'], function($, _) {
if (webrtc.usermedia.audioLevel) { if (webrtc.usermedia.audioLevel) {
width = Math.round(100 * webrtc.usermedia.audioLevel); width = Math.round(100 * webrtc.usermedia.audioLevel);
// Hide low volumes. // Hide low volumes.
if (width<threshhold) { if (width < threshhold) {
width = 0; width = 0;
} }
} }
@ -65,13 +65,13 @@ define(['jquery', 'underscore', 'rAF'], function($, _) {
this.meter = _.bind(function() { this.meter = _.bind(function() {
var talking; var talking;
if (this.active) { if (this.active) {
var level = Math.round(100 * webrtc.usermedia.audioLevel); var level = Math.round(100 * webrtc.usermedia.audioLevel);
if (level < threshhold) { if (level < threshhold) {
level = 0; level = 0;
} else { } else {
level = level*activityMuliplier; level = level * activityMuliplier;
} }
this.audioActivityHistory.push(level); this.audioActivityHistory.push(level);
if (this.audioActivityHistory.length > activityHistorySize) { if (this.audioActivityHistory.length > activityHistorySize) {
@ -80,25 +80,25 @@ define(['jquery', 'underscore', 'rAF'], function($, _) {
this.audioActivityMeter = this.audioActivityHistory.reduce(function(a, b) { this.audioActivityMeter = this.audioActivityHistory.reduce(function(a, b) {
return a + b; return a + b;
}) / this.audioActivityHistory.length; }) / this.audioActivityHistory.length;
//console.log("audioActivityMeter", this.audioActivityMeter, $scope.talking); //console.log("audioActivityMeter", this.audioActivityMeter, $scope.talking);
if (!$scope.talking) { if (!$scope.talking) {
talking = this.audioActivityMeter > activityThreshold ? true : false; talking = this.audioActivityMeter > activityThreshold ? true : false;
} else { } else {
talking = this.audioActivityMeter > activityThresholdInactivity ? true : false; talking = this.audioActivityMeter > activityThresholdInactivity ? true : false;
} }
} else { } else {
// Clean up. // Clean up.
//console.log("cleaning up"); //console.log("cleaning up");
this.audioActivityHistory = []; this.audioActivityHistory = [];
this.audioActivityMeter = 0; this.audioActivityMeter = 0;
talking = false; talking = false;
} }
if (talking !== $scope.talking) { if (talking !== $scope.talking) {
// Apply to scope. // Apply to scope.
//console.log("talking changed", talking); //console.log("talking changed", talking);
safeApply($scope, function() { safeApply($scope, function() {
$scope.talking = talking; $scope.talking = talking;
}); });
} }
// Check peer changes and update state for peers and keep history. // Check peer changes and update state for peers and keep history.
@ -110,7 +110,7 @@ define(['jquery', 'underscore', 'rAF'], function($, _) {
if (!talkingStatus[peercall.id]) { if (!talkingStatus[peercall.id]) {
send = true; send = true;
} }
talkingStatusNew[peercall.id]=talking; talkingStatusNew[peercall.id] = talking;
} else if (!talking && talkingStatus[peercall.id]) { } else if (!talking && talkingStatus[peercall.id]) {
send = true; send = true;
} }

597
static/js/directives/audiovideo.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,300 +20,303 @@
*/ */
define(['jquery', 'underscore', 'text!partials/audiovideo.html', 'text!partials/audiovideopeer.html', 'bigscreen', 'injectCSS', 'webrtc.adapter', 'rAF'], function($, _, template, templatePeer, BigScreen) { define(['jquery', 'underscore', 'text!partials/audiovideo.html', 'text!partials/audiovideopeer.html', 'bigscreen', 'injectCSS', 'webrtc.adapter', 'rAF'], function($, _, template, templatePeer, BigScreen) {
return ["$window", "$compile", "$filter", "mediaStream", "safeApply", "desktopNotify", "buddyData", "videoWaiter", "videoLayout", function($window, $compile, $filter, mediaStream, safeApply, desktopNotify, buddyData, videoWaiter, videoLayout) { return ["$window", "$compile", "$filter", "mediaStream", "safeApply", "desktopNotify", "buddyData", "videoWaiter", "videoLayout", function($window, $compile, $filter, mediaStream, safeApply, desktopNotify, buddyData, videoWaiter, videoLayout) {
var requestAnimationFrame = $window.requestAnimationFrame; var requestAnimationFrame = $window.requestAnimationFrame;
var peerTemplate = $compile(templatePeer); var peerTemplate = $compile(templatePeer);
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
var peers = {}; var peers = {};
var events = $({}); var events = $({});
$scope.container = $element.get(0); $scope.container = $element.get(0);
$scope.layoutparent = $element.parent(); $scope.layoutparent = $element.parent();
$scope.remoteVideos = $element.find(".remoteVideos").get(0); $scope.remoteVideos = $element.find(".remoteVideos").get(0);
$scope.localVideo = $element.find(".localVideo").get(0); $scope.localVideo = $element.find(".localVideo").get(0);
$scope.miniVideo = $element.find(".miniVideo").get(0); $scope.miniVideo = $element.find(".miniVideo").get(0);
$scope.mini = $element.find(".miniContainer").get(0); $scope.mini = $element.find(".miniContainer").get(0);
$scope.hasUsermedia = false; $scope.hasUsermedia = false;
$scope.isActive = false; $scope.isActive = false;
$scope.rendererName = $scope.defaultRendererName = "onepeople"; $scope.rendererName = $scope.defaultRendererName = "onepeople";
//console.log("audiovideo", localVideo, miniVideo); //console.log("audiovideo", localVideo, miniVideo);
$scope.addRemoteStream = function(stream, currentcall) { $scope.addRemoteStream = function(stream, currentcall) {
//console.log("Add remote stream to scope", pc.id, stream); //console.log("Add remote stream to scope", pc.id, stream);
var subscope = $scope.$new(true); var subscope = $scope.$new(true);
var peerid = subscope.peerid = currentcall.id; var peerid = subscope.peerid = currentcall.id;
buddyData.push(peerid); buddyData.push(peerid);
subscope.withvideo = false; subscope.withvideo = false;
subscope.onlyaudio = false; subscope.onlyaudio = false;
subscope.talking = false; subscope.talking = false;
subscope.applyTalking = function(talking) { subscope.applyTalking = function(talking) {
subscope.talking = !!talking; subscope.talking = !! talking;
safeApply(subscope); safeApply(subscope);
}; };
subscope.$on("active", function() { subscope.$on("active", function() {
console.log("Stream scope is now active", peerid); console.log("Stream scope is now active", peerid);
events.triggerHandler("active."+peerid, [subscope, currentcall, stream]); events.triggerHandler("active." + peerid, [subscope, currentcall, stream]);
}); });
console.log("Created stream scope", peerid); console.log("Created stream scope", peerid);
peerTemplate(subscope, function(clonedElement, scope) { peerTemplate(subscope, function(clonedElement, scope) {
$($scope.remoteVideos).append(clonedElement); $($scope.remoteVideos).append(clonedElement);
clonedElement.data("peerid", scope.peerid); clonedElement.data("peerid", scope.peerid);
scope.element = clonedElement; scope.element = clonedElement;
var video = clonedElement.find("video").get(0); var video = clonedElement.find("video").get(0);
$window.attachMediaStream(video, stream); $window.attachMediaStream(video, stream);
// Waiter callbacks also count as connected, as browser support (FireFox 25) is not setting state changes properly. // Waiter callbacks also count as connected, as browser support (FireFox 25) is not setting state changes properly.
videoWaiter.wait(video, stream, function(withvideo) { videoWaiter.wait(video, stream, function(withvideo) {
peers[peerid] = scope; peers[peerid] = scope;
if (withvideo) { if (withvideo) {
scope.$apply(function($scope) { scope.$apply(function($scope) {
$scope.withvideo = true; $scope.withvideo = true;
}); });
} else { } else {
console.info("Incoming stream has no video tracks."); console.info("Incoming stream has no video tracks.");
scope.$apply(function($scope) { scope.$apply(function($scope) {
$scope.onlyaudio = true; $scope.onlyaudio = true;
}); });
} }
scope.$emit("active", currentcall); scope.$emit("active", currentcall);
$scope.redraw(); $scope.redraw();
}, function() { }, function() {
peers[peerid] = scope; peers[peerid] = scope;
console.warn("We did not receive video data for remote stream", currentcall, stream, video); console.warn("We did not receive video data for remote stream", currentcall, stream, video);
scope.$emit("active", currentcall); scope.$emit("active", currentcall);
$scope.redraw(); $scope.redraw();
}); });
scope.doChat = function() { scope.doChat = function() {
$scope.$emit("startchat", currentcall.id, {autofocus: true, restore: true}); $scope.$emit("startchat", currentcall.id, {
}; autofocus: true,
}); restore: true
});
}; };
});
$scope.removeRemoteStream = function(stream, currentcall) {
};
var subscope = peers[currentcall.id];
if (subscope) { $scope.removeRemoteStream = function(stream, currentcall) {
buddyData.pop(currentcall.id);
delete peers[currentcall.id]; var subscope = peers[currentcall.id];
//console.log("remove scope", subscope); if (subscope) {
if (subscope.element) { buddyData.pop(currentcall.id);
subscope.element.remove(); delete peers[currentcall.id];
} //console.log("remove scope", subscope);
subscope.$destroy(); if (subscope.element) {
$scope.redraw(); subscope.element.remove();
} }
subscope.$destroy();
}; $scope.redraw();
}
// Talking updates receiver.
mediaStream.api.e.on("received.talking", function(event, id, from, talking) { };
var scope = peers[from];
//console.log("received.talking", talking, scope); // Talking updates receiver.
if (scope) { mediaStream.api.e.on("received.talking", function(event, id, from, talking) {
scope.applyTalking(talking); var scope = peers[from];
} else { //console.log("received.talking", talking, scope);
console.log("Received talking state without scope -> adding event.", from, talking); if (scope) {
events.one("active."+from, function(event, scope) { scope.applyTalking(talking);
console.log("Applying previously received talking state", from, talking); } else {
scope.applyTalking(talking); console.log("Received talking state without scope -> adding event.", from, talking);
}); events.one("active." + from, function(event, scope) {
} console.log("Applying previously received talking state", from, talking);
}); scope.applyTalking(talking);
});
$scope.$on("active", function(currentcall) { }
});
//console.log("active 2");
if (!$scope.isActive) { $scope.$on("active", function(currentcall) {
$scope.isActive = true;
$scope.remoteVideos.style.opacity = 1; //console.log("active 2");
$element.addClass("active"); if (!$scope.isActive) {
//console.log("active 3"); $scope.isActive = true;
_.delay(function() { $scope.remoteVideos.style.opacity = 1;
$scope.localVideo.style.opacity = 0; $element.addClass("active");
$scope.localVideo.src = ""; //console.log("active 3");
}, 500); _.delay(function() {
_.delay(function() { $scope.localVideo.style.opacity = 0;
//console.log("active 4", $scope.mini); $scope.localVideo.src = "";
$($scope.mini).addClass("visible"); }, 500);
}, 1000); _.delay(function() {
} //console.log("active 4", $scope.mini);
$($scope.mini).addClass("visible");
}); }, 1000);
}
$scope.toggleFullscreen = function() {
//console.log("Toggle full screen", BigScreen.enabled, $scope.isActive, $scope.hasUsermedia); });
if (BigScreen.enabled && ($scope.isActive || $scope.hasUsermedia)) {
$scope.layoutparent.toggleClass("fullscreen"); $scope.toggleFullscreen = function() {
BigScreen.toggle($scope.layoutparent.get(0)); //console.log("Toggle full screen", BigScreen.enabled, $scope.isActive, $scope.hasUsermedia);
} if (BigScreen.enabled && ($scope.isActive || $scope.hasUsermedia)) {
}; $scope.layoutparent.toggleClass("fullscreen");
BigScreen.toggle($scope.layoutparent.get(0));
mediaStream.webrtc.e.on("usermedia", function(event, usermedia) { }
};
//console.log("XXXXXXXXXXXXXXXXXXXXXXXXX usermedia event", usermedia);
$scope.hasUsermedia = true; mediaStream.webrtc.e.on("usermedia", function(event, usermedia) {
usermedia.attachMediaStream($scope.localVideo);
var count = 0; //console.log("XXXXXXXXXXXXXXXXXXXXXXXXX usermedia event", usermedia);
var waitForLocalVideo = function() { $scope.hasUsermedia = true;
if (!$scope.hasUsermedia) { usermedia.attachMediaStream($scope.localVideo);
return; var count = 0;
} var waitForLocalVideo = function() {
if ($scope.localVideo.videoWidth > 0) { if (!$scope.hasUsermedia) {
$scope.localVideo.style.opacity = 1; return;
$scope.redraw(); }
} else { if ($scope.localVideo.videoWidth > 0) {
count++; $scope.localVideo.style.opacity = 1;
if (count < 100) { $scope.redraw();
setTimeout(waitForLocalVideo, 100); } else {
} else { count++;
console.warn("Timeout while waiting for local video.") if (count < 100) {
} setTimeout(waitForLocalVideo, 100);
} } else {
}; console.warn("Timeout while waiting for local video.")
waitForLocalVideo(); }
}
}); };
waitForLocalVideo();
mediaStream.webrtc.e.on("done", function() {
});
$scope.hasUsermedia = false;
$scope.isActive = false; mediaStream.webrtc.e.on("done", function() {
if (BigScreen.enabled) {
BigScreen.exit(); $scope.hasUsermedia = false;
} $scope.isActive = false;
_.delay(function() { if (BigScreen.enabled) {
if ($scope.isActive) { BigScreen.exit();
return; }
} _.delay(function() {
$scope.localVideo.src = ''; if ($scope.isActive) {
$scope.miniVideo.src = ''; return;
$($scope.remoteVideos).empty(); }
}, 1500); $scope.localVideo.src = '';
$($scope.mini).removeClass("visible"); $scope.miniVideo.src = '';
$scope.localVideo.style.opacity = 0; $($scope.remoteVideos).empty();
$scope.remoteVideos.style.opacity = 0; }, 1500);
$element.removeClass('active'); $($scope.mini).removeClass("visible");
_.each(peers, function(scope, k) { $scope.localVideo.style.opacity = 0;
scope.$destroy(); $scope.remoteVideos.style.opacity = 0;
delete peers[k]; $element.removeClass('active');
}); _.each(peers, function(scope, k) {
$scope.rendererName = $scope.defaultRendererName; scope.$destroy();
delete peers[k];
}); });
$scope.rendererName = $scope.defaultRendererName;
mediaStream.webrtc.e.on("streamadded", function(event, stream, currentcall) {
});
console.log("Remote stream added.", stream, currentcall);
if (_.isEmpty(peers)) { mediaStream.webrtc.e.on("streamadded", function(event, stream, currentcall) {
//console.log("First stream");
$window.reattachMediaStream($scope.miniVideo, $scope.localVideo); console.log("Remote stream added.", stream, currentcall);
} if (_.isEmpty(peers)) {
$scope.addRemoteStream(stream, currentcall); //console.log("First stream");
$window.reattachMediaStream($scope.miniVideo, $scope.localVideo);
}); }
$scope.addRemoteStream(stream, currentcall);
mediaStream.webrtc.e.on("streamremoved", function(event, stream, currentcall) {
});
console.log("Remote stream removed.", stream, currentcall);
$scope.removeRemoteStream(stream, currentcall); mediaStream.webrtc.e.on("streamremoved", function(event, stream, currentcall) {
}); console.log("Remote stream removed.", stream, currentcall);
$scope.removeRemoteStream(stream, currentcall);
return {
peers: peers });
};
return {
}]; peers: peers
};
var compile = function(tElement, tAttr) {
}];
return function(scope, iElement, iAttrs, controller) {
var compile = function(tElement, tAttr) {
//console.log("compile", arguments)
return function(scope, iElement, iAttrs, controller) {
iElement.on("doubletap dblclick", _.debounce(scope.toggleFullscreen, 100, true));
//console.log("compile", arguments)
var rendererName = null;
var getRendererName = function() { iElement.on("doubletap dblclick", _.debounce(scope.toggleFullscreen, 100, true));
// Return name of current renderer.
if (rendererName !== null) { var rendererName = null;
return rendererName; var getRendererName = function() {
} else { // Return name of current renderer.
return scope.rendererName; if (rendererName !== null) {
} return rendererName;
}; } else {
return scope.rendererName;
scope.setRenderer = function(name) { }
scope.rendererName = name; };
};
scope.setRenderer = function(name) {
var needsRedraw = false; scope.rendererName = name;
scope.redraw = function() { };
needsRedraw = true;
}; var needsRedraw = false;
scope.redraw = function() {
var redraw = function() { needsRedraw = true;
var size = { };
width: scope.layoutparent.width(),
height: scope.layoutparent.height() var redraw = function() {
} var size = {
var again = videoLayout.update(getRendererName(), size, scope, controller); width: scope.layoutparent.width(),
if (again) { height: scope.layoutparent.height()
// Layout needs a redraw. }
needsRedraw = true; var again = videoLayout.update(getRendererName(), size, scope, controller);
} if (again) {
}; // Layout needs a redraw.
needsRedraw = true;
// Make sure we draw on resize. }
$($window).on("resize", scope.redraw); };
scope.$on("mainresize", function(event, main) {
if (main) { // Make sure we draw on resize.
// Force smally renderer when we have a main view. $($window).on("resize", scope.redraw);
rendererName = "smally" scope.$on("mainresize", function(event, main) {
} else if (rendererName) { if (main) {
rendererName = null; // Force smally renderer when we have a main view.
} rendererName = "smally"
_.defer(scope.redraw); } else if (rendererName) {
}); rendererName = null;
scope.redraw(); }
_.defer(scope.redraw);
// Make sure we draw when the renderer was changed. });
scope.$watch("rendererName", function() { scope.redraw();
_.defer(scope.redraw);
}); // Make sure we draw when the renderer was changed.
scope.$watch("rendererName", function() {
// Update function run in rendering thread. _.defer(scope.redraw);
var update = function() { });
if (needsRedraw) {
needsRedraw =false; // Update function run in rendering thread.
redraw(); var update = function() {
} if (needsRedraw) {
requestAnimationFrame(update); needsRedraw = false;
} redraw();
_.defer(update); }
requestAnimationFrame(update);
} }
_.defer(update);
};
}
return {
restrict: 'E', };
replace: true,
scope: true, return {
template: template, restrict: 'E',
controller: controller, replace: true,
compile: compile scope: true,
} template: template,
controller: controller,
}]; compile: compile
}
}];
}); });

222
static/js/directives/buddylist.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,111 +20,117 @@
*/ */
define(['underscore', 'text!partials/buddylist.html'], function(_, template) { define(['underscore', 'text!partials/buddylist.html'], function(_, template) {
// buddyList // buddyList
return ["$compile", "buddyList", "mediaStream", function($compile, buddyList, mediaStream) { return ["$compile", "buddyList", "mediaStream", function($compile, buddyList, mediaStream) {
//console.log("buddyList directive"); //console.log("buddyList directive");
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
$scope.layout.buddylist = false; $scope.layout.buddylist = false;
$scope.enabled = false; $scope.enabled = false;
$scope.doCall = function(id) { $scope.doCall = function(id) {
mediaStream.webrtc.doCall(id); mediaStream.webrtc.doCall(id);
}; };
$scope.doChat = function(id) { $scope.doChat = function(id) {
//console.log("doChat", id); //console.log("doChat", id);
$scope.$emit("startchat", id, {autofocus: true, restore: true}); $scope.$emit("startchat", id, {
autofocus: true,
}; restore: true
});
$scope.doAudioConference = function(id) {
};
$scope.updateAutoAccept(id);
mediaStream.api.sendChat(id, null, {type: "conference", id: mediaStream.connector.roomid}) $scope.doAudioConference = function(id) {
}; $scope.updateAutoAccept(id);
mediaStream.api.sendChat(id, null, {
$scope.setRoomStatus = function(status) { type: "conference",
if (status !== $scope.enabled) { id: mediaStream.connector.roomid
$scope.enabled = status; })
$scope.$emit("roomStatus", status);
} };
if (status && !$scope.layout.buddylistAutoHide) {
$scope.layout.buddylist = true $scope.setRoomStatus = function(status) {
} if (status !== $scope.enabled) {
}; $scope.enabled = status;
$scope.$emit("roomStatus", status);
//XXX(longsleep): Debug leftover ?? Remove this. }
window.doAudioConference = $scope.doAudioConference; if (status && !$scope.layout.buddylistAutoHide) {
$scope.layout.buddylist = true
var buddylist = $scope.buddylist = buddyList.buddylist($element, $scope, {}); }
var onJoined = _.bind(buddylist.onJoined, buddylist); };
var onLeft = _.bind(buddylist.onLeft, buddylist);
var onStatus = _.bind(buddylist.onStatus, buddylist); //XXX(longsleep): Debug leftover ?? Remove this.
mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) { window.doAudioConference = $scope.doAudioConference;
if (dataType === "Left") {
onLeft(data); var buddylist = $scope.buddylist = buddyList.buddylist($element, $scope, {});
} else { var onJoined = _.bind(buddylist.onJoined, buddylist);
onJoined(data); var onLeft = _.bind(buddylist.onLeft, buddylist);
} var onStatus = _.bind(buddylist.onStatus, buddylist);
}); mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) {
mediaStream.api.e.on("received.users", function(event, data) { if (dataType === "Left") {
$scope.setRoomStatus(true); onLeft(data);
var selfId = $scope.id; } else {
_.each(data, function(p) { onJoined(data);
if (p.Id !== selfId) { }
onJoined(p); });
} mediaStream.api.e.on("received.users", function(event, data) {
}); $scope.setRoomStatus(true);
$scope.$apply(); var selfId = $scope.id;
}); _.each(data, function(p) {
mediaStream.api.e.on("received.status", function(event, data) { if (p.Id !== selfId) {
onStatus(data); onJoined(p);
}); }
mediaStream.connector.e.on("closed error", function() { });
$scope.setRoomStatus(false); $scope.$apply();
buddylist.onClosed(); });
}); mediaStream.api.e.on("received.status", function(event, data) {
onStatus(data);
// Request user list whenever the connection comes ready. });
mediaStream.connector.ready(function() { mediaStream.connector.e.on("closed error", function() {
mediaStream.api.requestUsers(); $scope.setRoomStatus(false);
}); buddylist.onClosed();
});
}];
// Request user list whenever the connection comes ready.
var link = function(scope, iElement, iAttrs, controller) { mediaStream.connector.ready(function() {
mediaStream.api.requestUsers();
// Add events to buddy list parent container to show/hide. });
var parent = iElement.parent();
parent.on("mouseenter mouseleave", function(event) { }];
if (event.type === "mouseenter") {
scope.layout.buddylist = true; var link = function(scope, iElement, iAttrs, controller) {
} else {
if (scope.layout.buddylistAutoHide) { // Add events to buddy list parent container to show/hide.
scope.layout.buddylist = false; var parent = iElement.parent();
} parent.on("mouseenter mouseleave", function(event) {
} if (event.type === "mouseenter") {
scope.$apply(); scope.layout.buddylist = true;
}); } else {
if (scope.layout.buddylistAutoHide) {
}; scope.layout.buddylist = false;
}
return { }
restrict: 'E', scope.$apply();
replace: true, });
scope: true,
template: template, };
controller: controller,
link: link return {
} restrict: 'E',
replace: true,
}]; scope: true,
template: template,
controller: controller,
link: link
}
}];
}); });

893
static/js/directives/chat.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,425 +20,474 @@
*/ */
define(['underscore', 'text!partials/chat.html', 'text!partials/chatroom.html'], function(_, templateChat, templateChatroom) { define(['underscore', 'text!partials/chat.html', 'text!partials/chatroom.html'], function(_, templateChat, templateChatroom) {
return ["$compile", "safeDisplayName", "mediaStream", "safeApply", "desktopNotify", "translation", "playSound", "fileUpload", "randomGen", "buddyData", "$timeout", function($compile, safeDisplayName, mediaStream, safeApply, desktopNotify, translation, playSound, fileUpload, randomGen, buddyData, $timeout) { return ["$compile", "safeDisplayName", "mediaStream", "safeApply", "desktopNotify", "translation", "playSound", "fileUpload", "randomGen", "buddyData", "$timeout", function($compile, safeDisplayName, mediaStream, safeApply, desktopNotify, translation, playSound, fileUpload, randomGen, buddyData, $timeout) {
var displayName = safeDisplayName; var displayName = safeDisplayName;
var group_chat_id = ""; var group_chat_id = "";
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
$scope.layout.chat = false; $scope.layout.chat = false;
$scope.layout.chatMaximized = false; $scope.layout.chatMaximized = false;
var ctrl = this; var ctrl = this;
var rooms = ctrl.rooms = {}; var rooms = ctrl.rooms = {};
ctrl.visibleRooms = []; ctrl.visibleRooms = [];
ctrl.group = group_chat_id; ctrl.group = group_chat_id;
ctrl.get = function(id) { ctrl.get = function(id) {
return ctrl.rooms[id]; return ctrl.rooms[id];
} }
$scope.currentRoom = null; $scope.currentRoom = null;
$scope.currentRoomActive = false; $scope.currentRoomActive = false;
$scope.getVisibleRooms = function() { $scope.getVisibleRooms = function() {
var res = []; var res = [];
for (var i=0; i<ctrl.visibleRooms.length; i++) { for (var i = 0; i < ctrl.visibleRooms.length; i++) {
var r = rooms[ctrl.visibleRooms[i]]; var r = rooms[ctrl.visibleRooms[i]];
if (!r || r.id === ctrl.group) { if (!r || r.id === ctrl.group) {
continue; continue;
} }
res.push(r); res.push(r);
} }
return res; return res;
}; };
$scope.getGroupRoom = function() { $scope.getGroupRoom = function() {
return rooms[ctrl.group]; return rooms[ctrl.group];
}; };
mediaStream.api.e.on("received.chat", function(event, id, from, data, p2p) { mediaStream.api.e.on("received.chat", function(event, id, from, data, p2p) {
//console.log("received", data, id, from); //console.log("received", data, id, from);
var roomid = id; var roomid = id;
if (roomid === mediaStream.api.id) { if (roomid === mediaStream.api.id) {
roomid = from; roomid = from;
} else { } else {
if (roomid !== ctrl.group && from !== mediaStream.api.id) { if (roomid !== ctrl.group && from !== mediaStream.api.id) {
console.log("Received chat message for invalid room", roomid, id, from); console.log("Received chat message for invalid room", roomid, id, from);
return; return;
} }
} }
var with_message = !!data.Message; var with_message = !! data.Message;
var room = rooms[roomid]; var room = rooms[roomid];
if (!room) { if (!room) {
if (!with_message) { if (!with_message) {
return; return;
} }
// No room with this id, get one with the from id // No room with this id, get one with the from id
$scope.$emit("startchat", from, {restore: with_message}); $scope.$emit("startchat", from, {
room = rooms[from]; restore: with_message
} });
room = rooms[from];
if (with_message && from !== mediaStream.api.id) { }
room.newmessage = true;
room.peerIsTyping = "no"; if (with_message && from !== mediaStream.api.id) {
room.p2p(!!p2p); room.newmessage = true;
} room.peerIsTyping = "no";
room.p2p( !! p2p);
room.$broadcast("received", from, data); }
safeApply(room);
room.$broadcast("received", from, data);
}); safeApply(room);
mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) { });
var room = rooms[data.Id];
if (room) { mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) {
switch (dataType) { var room = rooms[data.Id];
case "Left": if (room) {
if (data.Status !== "soft") { switch (dataType) {
room.enabled = false; case "Left":
room.$broadcast("received", data.Id, {Type: "LeftOrJoined", "LeftOrJoined": "left"}); if (data.Status !== "soft") {
safeApply(room); room.enabled = false;
} room.$broadcast("received", data.Id, {
break; Type: "LeftOrJoined",
case "Joined": "LeftOrJoined": "left"
if (!room.enabled) { });
room.enabled = true; safeApply(room);
_.delay(function() { }
room.$broadcast("received", data.Id, {Type: "LeftOrJoined", "LeftOrJoined": "joined"}); break;
safeApply(room); case "Joined":
}, 1000); if (!room.enabled) {
} room.enabled = true;
break; _.delay(function() {
default: room.$broadcast("received", data.Id, {
break; Type: "LeftOrJoined",
} "LeftOrJoined": "joined"
} });
}); safeApply(room);
}, 1000);
$scope.$parent.$on("startchat", function(event, id, options) { }
break;
//console.log("startchat requested", event, id); default:
if (id === group_chat_id) { break;
$scope.showGroupRoom(null, options); }
} else { }
$scope.showRoom(id, {title: translation._("Chat with")}, options); });
}
$scope.$parent.$on("startchat", function(event, id, options) {
});
//console.log("startchat requested", event, id);
}]; if (id === group_chat_id) {
$scope.showGroupRoom(null, options);
var compile = function(tElement, tAttrs) { } else {
$scope.showRoom(id, {
var chat = $compile(templateChatroom); title: translation._("Chat with")
return function(scope, iElement, iAttrs, controller) { }, options);
}
var pane = iElement.find(".chatpane");
});
scope.showGroupRoom = function(settings, options) {
var stngs = $.extend({title: translation._("Room chat")}, settings); }];
return scope.showRoom(controller.group, stngs, options);
}; var compile = function(tElement, tAttrs) {
scope.showRoom = function(id, settings, options) { var chat = $compile(templateChatroom);
var options = $.extend({}, options); return function(scope, iElement, iAttrs, controller) {
var subscope = controller.rooms[id];
var index = controller.visibleRooms.length; var pane = iElement.find(".chatpane");
if (!subscope) {
console.log("Create new chatroom", [id]); scope.showGroupRoom = function(settings, options) {
controller.visibleRooms.push(id); var stngs = $.extend({
subscope = controller.rooms[id] = scope.$new(); title: translation._("Room chat")
translation.inject(subscope); }, settings);
subscope.id = id; return scope.showRoom(controller.group, stngs, options);
subscope.isgroupchat = id === controller.group ? true : false; };
subscope.index = index;
subscope.settings = settings; scope.showRoom = function(id, settings, opts) {
subscope.visible = false; var options = $.extend({}, opts);
subscope.newmessage = false; var subscope = controller.rooms[id];
subscope.enabled = true; var index = controller.visibleRooms.length;
subscope.peerIsTyping = "no"; if (!subscope) {
subscope.firstmessage = true; console.log("Create new chatroom", [id]);
subscope.p2pstate = false; controller.visibleRooms.push(id);
subscope.active = false; subscope = controller.rooms[id] = scope.$new();
subscope.pending = 0; translation.inject(subscope);
if (!subscope.isgroupchat) { subscope.id = id;
buddyData.push(id); subscope.isgroupchat = id === controller.group ? true : false;
} subscope.index = index;
subscope.hide = function() { subscope.settings = settings;
scope.hideRoom(id); subscope.visible = false;
}; subscope.newmessage = false;
//TODO(longsleep): This is currently never called. Find a suitable way to clean up old chats. subscope.enabled = true;
subscope.kill = function() { subscope.peerIsTyping = "no";
if (!subscope.isgroupchat) { subscope.firstmessage = true;
buddyData.pop(id); subscope.p2pstate = false;
} subscope.active = false;
scope.killRoom(id); subscope.pending = 0;
}; if (!subscope.isgroupchat) {
subscope.seen = function() { buddyData.push(id);
subscope.pending = 0; }
scope.$emit("chatseen", subscope.id); subscope.hide = function() {
if (subscope.newmessage) { scope.hideRoom(id);
subscope.newmessage = false; };
subscope.$broadcast("seen"); //TODO(longsleep): This is currently never called. Find a suitable way to clean up old chats.
} subscope.kill = function() {
}; if (!subscope.isgroupchat) {
subscope.deactivate =function() { buddyData.pop(id);
scope.deactivateRoom(); }
}; scope.killRoom(id);
subscope.toggleMax = function() { };
scope.toggleMax(); subscope.seen = function() {
}; subscope.pending = 0;
subscope.sendChat = function(to, message, status, mid, noloop) { scope.$emit("chatseen", subscope.id);
//console.log("send chat", to, scope.peer); if (subscope.newmessage) {
var peercall = mediaStream.webrtc.findTargetCall(to); subscope.newmessage = false;
if (message && !mid) { subscope.$broadcast("seen");
mid = randomGen.random({hex: true}); }
}; };
if (peercall && peercall.peerconnection.datachannelReady) { subscope.deactivate = function() {
subscope.p2p(true); scope.deactivateRoom();
// Send out stuff through data channel. };
_.delay(function() { subscope.toggleMax = function() {
mediaStream.api.apply("sendChat", { scope.toggleMax();
send: function(type, data) { };
// We also send to self, to display our own stuff. subscope.sendChat = function(to, message, status, mid, noloop) {
if (!noloop) { //console.log("send chat", to, scope.peer);
mediaStream.api.received({Type: data.Type, Data: data, From: mediaStream.api.id, To: peercall.id}); var peercall = mediaStream.webrtc.findTargetCall(to);
} if (message && !mid) {
return peercall.peerconnection.send(data); mid = randomGen.random({
} hex: true
})(to, message, status, mid); });
}, 100); }
if (peercall && peercall.peerconnection.datachannelReady) {
} else { subscope.p2p(true);
subscope.p2p(false); // Send out stuff through data channel.
_.delay(function() { _.delay(function() {
mediaStream.api.send2("sendChat", function(type, data) { mediaStream.api.apply("sendChat", {
if (!noloop) { send: function(type, data) {
//console.log("looped to self", type, data); // We also send to self, to display our own stuff.
mediaStream.api.received({Type: data.Type, Data: data, From: mediaStream.api.id, To: to}); if (!noloop) {
} mediaStream.api.received({
})(to, message, status, mid); Type: data.Type,
}, 100); Data: data,
} From: mediaStream.api.id,
return mid; To: peercall.id
}; });
subscope.p2p = function(state) { }
if (state !== subscope.p2pstate) { return peercall.peerconnection.send(data);
subscope.p2pstate = state; }
subscope.$broadcast("p2p", state); })(to, message, status, mid);
} }, 100);
};
//console.log("Creating new chat room", controller, subscope, index); } else {
subscope.$on("submit", function(event, input) { subscope.p2p(false);
subscope.seen(); _.delay(function() {
var mid = subscope.sendChat(event.targetScope.id, input); mediaStream.api.send2("sendChat", function(type, data) {
event.targetScope.$broadcast("received", null, {Type: "Message", Status: {State: "sent", "Mid": mid}}); if (!noloop) {
}); //console.log("looped to self", type, data);
subscope.$on("submitseen", function(event, pending) { mediaStream.api.received({
//console.log("submitseen", pending); Type: data.Type,
subscope.sendChat(event.targetScope.id, null, {SeenMids: pending}, null, true); Data: data,
}); From: mediaStream.api.id,
subscope.$on("submitreceived", function(event, mid) { To: to
subscope.sendChat(event.targetScope.id, null, {State: "delivered", Mid: mid}, null, true); });
}); }
subscope.$on("typing", function(event, params) { })(to, message, status, mid);
if (params.who === "local") { }, 100);
var room = event.targetScope.id; }
subscope.seen(); return mid;
//console.log("typing event", params.status); };
if (!subscope.isgroupchat) { subscope.p2p = function(state) {
// Transmit typing events to private chats. if (state !== subscope.p2pstate) {
subscope.sendChat(event.targetScope.id, null, {Typing: params.status}); subscope.p2pstate = state;
} subscope.$broadcast("p2p", state);
} else { }
subscope.peerIsTyping = params.status; };
//console.log("peer typing event", params.status, subscope.peerIsTyping); //console.log("Creating new chat room", controller, subscope, index);
} subscope.$on("submit", function(event, input) {
safeApply(subscope); subscope.seen();
}); var mid = subscope.sendChat(event.targetScope.id, input);
subscope.$on("incoming", function(event, message, from, userid) { event.targetScope.$broadcast("received", null, {
if (from !== userid) { Type: "Message",
subscope.pending++; Status: {
scope.$emit("chatincoming", subscope.id); State: "sent",
} "Mid": mid
if (subscope.firstmessage || !desktopNotify.windowHasFocus) { }
var room = event.targetScope.id; });
// Make sure we are not in group chat or the message is from ourselves });
// before we beep and shout. subscope.$on("submitseen", function(event, pending) {
if (!subscope.isgroupchat && from !== userid) { //console.log("submitseen", pending);
playSound.play("message1"); subscope.sendChat(event.targetScope.id, null, {
desktopNotify.notify(translation._("Message from ")+displayName(from), message); SeenMids: pending
} }, null, true);
subscope.firstmessage = false; });
} subscope.$on("submitreceived", function(event, mid) {
}); subscope.sendChat(event.targetScope.id, null, {
chat(subscope, function(clonedElement, $scope) { State: "delivered",
Mid: mid
pane.append(clonedElement); }, null, true);
$scope.element=clonedElement; });
$scope.visible = true; subscope.$on("typing", function(event, params) {
if (options.autofocus) { if (params.who === "local") {
_.defer(function() { var room = event.targetScope.id;
$scope.$broadcast("focus"); subscope.seen();
}); //console.log("typing event", params.status);
} if (!subscope.isgroupchat) {
// Transmit typing events to private chats.
// Support drag and drop file uploads in Chat. subscope.sendChat(event.targetScope.id, null, {
var namespace = "file_"+scope.id; Typing: params.status
var binder = fileUpload.bindDrop(namespace, clonedElement, _.bind(function(files) { });
console.log("File dragged", files); }
_.each(files, _.bind(function(f) { } else {
var info = $.extend({id: f.id}, f.info); subscope.peerIsTyping = params.status;
console.log("Advertising file", f, info); //console.log("peer typing event", params.status, subscope.peerIsTyping);
$scope.sendChat(subscope.id, "File", {FileInfo: info}); }
}, this)); safeApply(subscope);
}, this)); });
binder.namespace = function() { subscope.$on("incoming", function(event, message, from, userid) {
// Inject own id into namespace. if (from !== userid) {
return namespace+"_"+scope.myid; subscope.pending++;
}; scope.$emit("chatincoming", subscope.id);
}
}); if (subscope.firstmessage || !desktopNotify.windowHasFocus) {
} else { var room = event.targetScope.id;
// Make sure we are not in group chat or the message is from ourselves
if (options.restore) { // before we beep and shout.
if (!subscope.visible) { if (!subscope.isgroupchat && from !== userid) {
controller.visibleRooms.push(id); playSound.play("message1");
subscope.index = index; desktopNotify.notify(translation._("Message from ") + displayName(from), message);
subscope.visible = true; }
} subscope.firstmessage = false;
} }
if (options.autofocus && subscope.visible) { });
subscope.$broadcast("focus"); chat(subscope, function(clonedElement, $scope) {
}
pane.append(clonedElement);
} $scope.element = clonedElement;
$scope.visible = true;
if (!options.noactivate) { if (options.autofocus) {
scope.activateRoom(subscope.id, true); _.defer(function() {
} $scope.$broadcast("focus");
});
if (options.restore && !options.noenable) { }
if (!scope.layout.chat) {
scope.layout.chat = true; // Support drag and drop file uploads in Chat.
} var namespace = "file_" + scope.id;
} var binder = fileUpload.bindDrop(namespace, clonedElement, _.bind(function(files) {
console.log("File dragged", files);
safeApply(subscope); _.each(files, _.bind(function(f) {
return subscope; var info = $.extend({
}; id: f.id
}, f.info);
scope.hideRoom = function(id) { console.log("Advertising file", f, info);
var subscope = controller.rooms[id]; $scope.sendChat(subscope.id, "File", {
if (!subscope) { FileInfo: info
console.log("hideRoom called for unknown room", id); });
return; }, this));
} }, this));
var element = subscope.element; binder.namespace = function() {
var index = subscope.index; // Inject own id into namespace.
controller.visibleRooms.splice(index, 1); return namespace + "_" + scope.myid;
subscope.visible=false; };
subscope.firstmessage=true;
// Refresh index of the rest of the rooms. });
_.each(controller.visibleRooms, function(id, idx) { } else {
var s = controller.rooms[id];
//console.log("updated idx", idx, s.index); if (options.restore) {
s.index = idx; if (!subscope.visible) {
}); controller.visibleRooms.push(id);
if (scope.currentRoom === subscope) { subscope.index = index;
scope.currentRoom = null; subscope.visible = true;
scope.currentRoomActive = false; }
} }
if (!controller.visibleRooms.length) { if (options.autofocus && subscope.visible) {
scope.showGroupRoom(null, {restore: true, noenable: true, noactivate: true}); subscope.$broadcast("focus");
// If last visible room was removed, hide chat. }
scope.layout.chat = false;
} }
};
if (!options.noactivate) {
scope.killRoom = function(id) { scope.activateRoom(subscope.id, true);
scope.hideRoom(id); }
var subscope = controller.rooms[id];
if (!subscope) { if (options.restore && !options.noenable) {
return; if (!scope.layout.chat) {
} scope.layout.chat = true;
delete controller.rooms[id]; }
$timeout(function() { }
subscope.$destroy();
}, 0); safeApply(subscope);
}; return subscope;
};
scope.toggleMax = function() {
scope.layout.chatMaximized = !scope.layout.chatMaximized; scope.hideRoom = function(id) {
}; var subscope = controller.rooms[id];
if (!subscope) {
scope.activateRoom = function(id, active) { console.log("hideRoom called for unknown room", id);
var subscope = controller.rooms[id]; return;
if (!subscope) { }
return; var element = subscope.element;
} var index = subscope.index;
var visible = !!scope.layout.chat; controller.visibleRooms.splice(index, 1);
var flip = false; subscope.visible = false;
//console.log("toggleActive", active, id, scope.currentRoom, scope.currentRoom == subscope, subscope.active); subscope.firstmessage = true;
if (scope.currentRoom == subscope) { // Refresh index of the rest of the rooms.
subscope.active = active; _.each(controller.visibleRooms, function(id, idx) {
scope.currentRoomActive = true; var s = controller.rooms[id];
if (visible) { //console.log("updated idx", idx, s.index);
flip = true; s.index = idx;
} });
} else { if (scope.currentRoom === subscope) {
if (scope.currentRoom) { scope.currentRoom = null;
scope.currentRoom.active = false; scope.currentRoomActive = false;
//scope.currentRoom.hide(); }
if (visible) { if (!controller.visibleRooms.length) {
flip = true; scope.showGroupRoom(null, {
} restore: true,
} noenable: true,
if (active) { noactivate: true
scope.currentRoom = subscope; });
scope.currentRoomActive = true; // If last visible room was removed, hide chat.
} scope.layout.chat = false;
subscope.active = active; }
} };
if (flip) {
pane.toggleClass("flip"); scope.killRoom = function(id) {
} scope.hideRoom(id);
}; var subscope = controller.rooms[id];
if (!subscope) {
scope.deactivateRoom = function() { return;
scope.currentRoomActive = false; }
}; delete controller.rooms[id];
$timeout(function() {
scope.$watch("layout.chat", function(chat) { subscope.$destroy();
if (!chat) { }, 0);
pane.removeClass("flip"); };
}
scope.layout.chatMaximized = false; scope.toggleMax = function() {
}); scope.layout.chatMaximized = !scope.layout.chatMaximized;
};
scope.$on("room", function(event, room) {
var subscope = scope.showGroupRoom(null, {restore: true, noenable: true, noactivate: true}); scope.activateRoom = function(id, active) {
if (room) { var subscope = controller.rooms[id];
var msg = $("<span>").text(translation._("You are now in room %s ...", room)); if (!subscope) {
subscope.$broadcast("display", null, $("<i>").append(msg)); return;
} }
}); var visible = !! scope.layout.chat;
var flip = false;
}; //console.log("toggleActive", active, id, scope.currentRoom, scope.currentRoom == subscope, subscope.active);
if (scope.currentRoom == subscope) {
}; subscope.active = active;
scope.currentRoomActive = true;
return { if (visible) {
restrict: 'E', flip = true;
replace: true, }
scope: true, } else {
template: templateChat, if (scope.currentRoom) {
controller: controller, scope.currentRoom.active = false;
compile: compile //scope.currentRoom.hide();
} if (visible) {
flip = true;
}]; }
}
if (active) {
scope.currentRoom = subscope;
scope.currentRoomActive = true;
}
subscope.active = active;
}
if (flip) {
pane.toggleClass("flip");
}
};
scope.deactivateRoom = function() {
scope.currentRoomActive = false;
};
scope.$watch("layout.chat", function(chat) {
if (!chat) {
pane.removeClass("flip");
}
scope.layout.chatMaximized = false;
});
scope.$on("room", function(event, room) {
var subscope = scope.showGroupRoom(null, {
restore: true,
noenable: true,
noactivate: true
});
if (room) {
var msg = $("<span>").text(translation._("You are now in room %s ...", room));
subscope.$broadcast("display", null, $("<i>").append(msg));
}
});
};
};
return {
restrict: 'E',
replace: true,
scope: true,
template: templateChat,
controller: controller,
compile: compile
}
}];
}); });

83
static/js/directives/directives.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -19,49 +19,48 @@
* *
*/ */
define([ define([
'underscore', 'underscore',
'directives/onenter', 'directives/onenter',
'directives/onescape', 'directives/onescape',
'directives/statusmessage', 'directives/statusmessage',
'directives/buddylist', 'directives/buddylist',
'directives/settings', 'directives/settings',
'directives/chat', 'directives/chat',
'directives/audiovideo', 'directives/audiovideo',
'directives/usability', 'directives/usability',
'directives/audiolevel', 'directives/audiolevel',
'directives/fileinfo', 'directives/fileinfo',
'directives/screenshare', 'directives/screenshare',
'directives/roombar', 'directives/roombar',
'directives/socialshare', 'directives/socialshare',
'directives/page' 'directives/page'], function(_, onEnter, onEscape, statusMessage, buddyList, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page) {
], function(_, onEnter, onEscape, statusMessage, buddyList, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page) {
var directives = { var directives = {
onEnter: onEnter, onEnter: onEnter,
onEscape: onEscape, onEscape: onEscape,
statusMessage: statusMessage, statusMessage: statusMessage,
buddyList: buddyList, buddyList: buddyList,
settings: settings, settings: settings,
chat: chat, chat: chat,
audioVideo: audioVideo, audioVideo: audioVideo,
usability: usability, usability: usability,
audioLevel: audioLevel, audioLevel: audioLevel,
fileInfo: fileInfo, fileInfo: fileInfo,
screenshare: screenshare, screenshare: screenshare,
roomBar: roomBar, roomBar: roomBar,
socialShare: socialShare, socialShare: socialShare,
page: page page: page
}; };
var initialize = function (angModule) { var initialize = function(angModule) {
_.each(directives, function(directive, name) { _.each(directives, function(directive, name) {
angModule.directive(name, directive); angModule.directive(name, directive);
}) })
}; };
return { return {
initialize: initialize initialize: initialize
}; };
}); });

16
static/js/directives/fileinfo.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -46,10 +46,10 @@ define(['jquery', 'underscore'], function($, _) {
var progressBar = progressBars[0]; var progressBar = progressBars[0];
var progressBarDownload = progressBars[1]; var progressBarDownload = progressBars[1];
$scope.$watch("progress", function() { $scope.$watch("progress", function() {
progressBar.style.width=($scope.progress)+"%"; progressBar.style.width = ($scope.progress) + "%";
}); });
$scope.$watch("progressDownload", function() { $scope.$watch("progressDownload", function() {
progressBarDownload.style.width=($scope.progressDownload)+"%"; progressBarDownload.style.width = ($scope.progressDownload) + "%";
}); });
$scope.$watch("error", function() { $scope.$watch("error", function() {
@ -85,7 +85,7 @@ define(['jquery', 'underscore'], function($, _) {
} }
// Compute left bytes for eta. // Compute left bytes for eta.
var bytesLeft = $scope.info.size - ($scope.info.size * ($scope.progress/100)); var bytesLeft = $scope.info.size - ($scope.info.size * ($scope.progress / 100));
$scope.$apply(function(scope) { $scope.$apply(function(scope) {
scope.bytesPerSecond = _.reduce(bytesPerSecond, function(memo, num) { scope.bytesPerSecond = _.reduce(bytesPerSecond, function(memo, num) {
@ -177,8 +177,8 @@ define(['jquery', 'underscore'], function($, _) {
if ($scope.cancelled) { if ($scope.cancelled) {
return; return;
} }
$scope.progress = Math.ceil((written / ($scope.info.chunks-1)) * 100); $scope.progress = Math.ceil((written / ($scope.info.chunks - 1)) * 100);
if (written >= $scope.info.chunks-1) { if (written >= $scope.info.chunks - 1) {
$scope.progress = 100; $scope.progress = 100;
} }
}); });
@ -189,7 +189,7 @@ define(['jquery', 'underscore'], function($, _) {
return; return;
} }
bytesIn.push(bytesLength); bytesIn.push(bytesLength);
$scope.progressDownload = Math.ceil((chunk / ($scope.info.chunks-1)) * 100); $scope.progressDownload = Math.ceil((chunk / ($scope.info.chunks - 1)) * 100);
chunk++; chunk++;
}); });

40
static/js/directives/onenter.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,22 +20,22 @@
*/ */
define([], function() { define([], function() {
// onEnter // onEnter
return [function() { return [function() {
return { return {
restrict: "A", restrict: "A",
link: function(scope, element, attrs) { link: function(scope, element, attrs) {
var c = attrs.onEnter; var c = attrs.onEnter;
element.bind("keydown keypress", function(event) { element.bind("keydown keypress", function(event) {
if (event.which === 13 && !event.shiftKey && !event.ctrlKey) { if (event.which === 13 && !event.shiftKey && !event.ctrlKey) {
// On enter whithout shift or ctrl. // On enter whithout shift or ctrl.
event.preventDefault(); event.preventDefault();
scope.$eval(c); scope.$eval(c);
scope.$apply(); scope.$apply();
} }
}); });
} }
} }
}]; }];
}); });

40
static/js/directives/onescape.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,22 +20,22 @@
*/ */
define([], function() { define([], function() {
// onEscape // onEscape
return [function() { return [function() {
return { return {
restrict: "A", restrict: "A",
link: function(scope, element, attrs) { link: function(scope, element, attrs) {
var c = attrs.onEscape; var c = attrs.onEscape;
element.bind("keydown keypress", function(event) { element.bind("keydown keypress", function(event) {
if (event.which === 27) { if (event.which === 27) {
// On escape. // On escape.
event.preventDefault(); event.preventDefault();
scope.$eval(c); scope.$eval(c);
scope.$apply(); scope.$apply();
} }
}); });
} }
} }
}]; }];
}); });

4
static/js/directives/page.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

90
static/js/directives/roombar.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -20,58 +20,58 @@
*/ */
define(['underscore', 'text!partials/roombar.html'], function(_, template) { define(['underscore', 'text!partials/roombar.html'], function(_, template) {
// roomBar // roomBar
return ["$window", "$rootScope", "$location", function($window, $rootScope, $location) { return ["$window", "$rootScope", "$location", function($window, $rootScope, $location) {
var link = function($scope) { var link = function($scope) {
//console.log("roomBar directive link", arguments); //console.log("roomBar directive link", arguments);
$scope.newroomid = $rootScope.roomid; $scope.newroomid = $rootScope.roomid;
$scope.hideRoomBar = true; $scope.hideRoomBar = true;
$scope.save = function() { $scope.save = function() {
var roomid = $scope.changeRoomToId($scope.newroomid); var roomid = $scope.changeRoomToId($scope.newroomid);
if (roomid !== $rootScope.roomid) { if (roomid !== $rootScope.roomid) {
$scope.roombarform.$setPristine(); $scope.roombarform.$setPristine();
} }
$scope.hideRoomBar = true; $scope.hideRoomBar = true;
}; };
$scope.hitEnter = function(evt){ $scope.hitEnter = function(evt) {
if(angular.equals(evt.keyCode, 13)) { if (angular.equals(evt.keyCode, 13)) {
$scope.save(); $scope.save();
} }
}; };
$scope.exit = function() { $scope.exit = function() {
$scope.newroomid = ""; $scope.newroomid = "";
$scope.save(); $scope.save();
}; };
$rootScope.$watch("roomid", function(newroomid, roomid) { $rootScope.$watch("roomid", function(newroomid, roomid) {
if (!newroomid) { if (!newroomid) {
newroomid = ""; newroomid = "";
} }
$scope.newroomid = newroomid; $scope.newroomid = newroomid;
}); });
$scope.$watch("newroomid", function(newroomid) { $scope.$watch("newroomid", function(newroomid) {
if (newroomid === $rootScope.roomid) { if (newroomid === $rootScope.roomid) {
$scope.roombarform.$setPristine(); $scope.roombarform.$setPristine();
} }
}); });
}; };
return { return {
restrict: 'E', restrict: 'E',
replace: true, replace: true,
scope: true, scope: true,
template: template, template: template,
controller: "RoomchangeController", controller: "RoomchangeController",
link: link link: link
} }
}]; }];
}); });

60
static/js/directives/screenshare.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -48,22 +48,24 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
return; return;
} }
// Control data request. // Control data request.
var msg;
try { try {
var msg = JSON.parse(data); msg = JSON.parse(data);
} catch(e) { } catch (e) {
// Invalid JSON. // Invalid JSON.
console.warn("Invalid JSON received from screen share channel.", data); console.warn("Invalid JSON received from screen share channel.", data);
peerscreenshare.close() peerscreenshare.close();
return;
} }
switch (msg.m) { switch (msg.m) {
case "bye": case "bye":
// Close this screen share. // Close this screen share.
peerscreenshare.close(); peerscreenshare.close();
break; break;
default: default:
console.log("Unknown screen share control request", msg.m, msg); console.log("Unknown screen share control request", msg.m, msg);
break; break;
} }
} else { } else {
@ -163,7 +165,7 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
if ($scope.layout.screenshare) { if ($scope.layout.screenshare) {
$scope.stopScreenshare(); $scope.stopScreenshare();
}; }
$scope.layout.screenshare = true; $scope.layout.screenshare = true;
@ -193,15 +195,15 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
scope.usermedia = usermedia; scope.usermedia = usermedia;
// Create token to register with us and send token out to all peers. // Create token to register with us and send token out to all peers.
// Peers when connect to us with the token and we answer. // Peers when connect to us with the token and we answer.
var token = "screenshare_"+scope.id+"_"+(screenCount++); var token = "screenshare_" + scope.id + "_" + (screenCount++);
// Updater function to bring in new calls. // Updater function to bring in new calls.
var updater = function(event, state, currentcall) { var updater = function(event, state, currentcall) {
switch (state) { switch (state) {
case "completed": case "completed":
case "connected": case "connected":
connector(token, currentcall); connector(token, currentcall);
break; break;
} }
}; };
@ -227,7 +229,9 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
updated = null; updated = null;
// Send by to all connected peers. // Send by to all connected peers.
_.each(screenshares, function(peerscreenshare) { _.each(screenshares, function(peerscreenshare) {
peerscreenshare.send({m: "bye"}); peerscreenshare.send({
m: "bye"
});
$timeout(function() { $timeout(function() {
peerscreenshare.close(); peerscreenshare.close();
}, 0); }, 0);
@ -274,17 +278,17 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
} else { } else {
BigScreen.toggle(pane.get(0)); BigScreen.toggle(pane.get(0));
} }
} }
}; };
$scope.$watch("layout.screenshare", function(newval, oldval) { $scope.$watch("layout.screenshare", function(newval, oldval) {
if (newval && !oldval) { if (newval && !oldval) {
$scope.doScreenshare(); $scope.doScreenshare();
} else if(!newval && oldval) { } else if (!newval && oldval) {
$scope.stopScreenshare(); $scope.stopScreenshare();
} }
}); });
}]; }];
@ -307,4 +311,4 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
}]; }];
}); });

452
static/js/directives/settings.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -18,244 +18,252 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
*/ */
define(['underscore', 'text!partials/settings.html'], function(_, template) { define(['jquery', 'underscore', 'text!partials/settings.html'], function($, _, template) {
return ["$compile", "mediaStream", function($compile, mediaStream) { return ["$compile", "mediaStream", function($compile, mediaStream) {
var controller = ['$scope', 'desktopNotify', 'mediaSources', 'safeApply', 'availableLanguages', 'translation', '$timeout',function($scope, desktopNotify, mediaSources, safeApply, availableLanguages, translation, $timeout) { var controller = ['$scope', 'desktopNotify', 'mediaSources', 'safeApply', 'availableLanguages', 'translation', '$timeout', function($scope, desktopNotify, mediaSources, safeApply, availableLanguages, translation, $timeout) {
$scope.layout.settings = false; $scope.layout.settings = false;
$scope.showAdvancedSettings = true; $scope.showAdvancedSettings = true;
$scope.showTakePicture = false; $scope.showTakePicture = false;
$scope.previewPicture = false; $scope.showTakePictureReady = true;
$scope.showTakePictureReady = true; $scope.previewPicture = false;
$scope.rememberSettings = true; $scope.rememberSettings = true;
$scope.desktopNotify = desktopNotify; $scope.desktopNotify = desktopNotify;
$scope.mediaSources = mediaSources; $scope.mediaSources = mediaSources;
$scope.availableLanguages = [ $scope.availableLanguages = [{
{ code: "",
code: "", name: translation._("Use browser language")
name: translation._("Use browser language") }];
} $scope.withUsers = mediaStream.config.UsersEnabled;
]; $scope.withUsersRegistration = mediaStream.config.UsersAllowRegistration;
$scope.withUsers = mediaStream.config.UsersEnabled; $scope.withUsersMode = mediaStream.config.UsersMode;
$scope.withUsersRegistration = mediaStream.config.UsersAllowRegistration;
$scope.withUsersMode = mediaStream.config.UsersMode;
_.each(availableLanguages, function(name, code) { _.each(availableLanguages, function(name, code) {
$scope.availableLanguages.push({ $scope.availableLanguages.push({
code: code, code: code,
name: name name: name
}); });
}); });
var localStream = null; var localStream = null;
$scope.saveSettings = function() { // Make sure to save settings when they are open and the page is reloaded.
var user = $scope.user; $(window).on("unload", function() {
$scope.update(user); if ($scope.layout.settings) {
$scope.layout.settings = false; $scope.saveSettings();
if ($scope.rememberSettings) { }
localStorage.setItem("mediastream-user", JSON.stringify(user)); });
localStorage.setItem("mediastream-language", user.settings.language || "");
} else {
localStorage.removeItem("mediastream-user");
localStorage.removeItem("mediastream-language");
localStorage.removeItem("mediastream-access-code");
}
};
$scope.cancelSettings = function() {
$scope.reset();
$scope.layout.settings = false;
};
$scope.requestDesktopNotifyPermission = function() {
$scope.desktopNotify.requestPermission(function() {
safeApply($scope);
});
};
$scope.takePicture = function(element, take, retake, stop) {
var delayToTakePicture = 3000;
var takePictureCountFrom = 3;
var takePictureCountDown = function() {
$scope.countdown = {};
$scope.countdown.num = 3;
$timeout(function() {
$scope.countdown.num = 2;
}, delayToTakePicture/takePictureCountFrom*1);
$timeout(function() {
$scope.countdown.num = 1;
}, delayToTakePicture/takePictureCountFrom*2);
$timeout(function() {
$scope.countdown.num = null;
}, delayToTakePicture/takePictureCountFrom*3);
};
if (stop) { $scope.saveSettings = function() {
$scope.showTakePicture = false; var user = $scope.user;
$scope.previewPicture = false; $scope.update(user);
if (localStream) { $scope.layout.settings = false;
localStream.stop(); if ($scope.rememberSettings) {
localStream = null; localStorage.setItem("mediastream-user", JSON.stringify(user));
} localStorage.setItem("mediastream-language", user.settings.language || "");
return; } else {
} localStorage.removeItem("mediastream-user");
localStorage.removeItem("mediastream-language");
localStorage.removeItem("mediastream-access-code");
}
};
$scope.cancelSettings = function() {
$scope.reset();
$scope.layout.settings = false;
};
$scope.requestDesktopNotifyPermission = function() {
$scope.desktopNotify.requestPermission(function() {
safeApply($scope);
});
};
$scope.takePicture = function(element, take, retake, stop) {
var delayToTakePicture = 3000;
var takePictureCountFrom = 3;
var takePictureCountDown = function() {
$scope.countdown = {};
$scope.countdown.num = 3;
$timeout(function() {
$scope.countdown.num = 2;
}, delayToTakePicture/takePictureCountFrom*1);
$timeout(function() {
$scope.countdown.num = 1;
}, delayToTakePicture/takePictureCountFrom*2);
$timeout(function() {
$scope.countdown.num = null;
}, delayToTakePicture/takePictureCountFrom*3);
};
var video = $(element).parent().parent().find("video").get(0); if (stop) {
var makePicture = function() { $scope.showTakePicture = false;
takePictureCountDown(); $scope.previewPicture = false;
$timeout(function() { if (localStream) {
$scope.previewPicture = true; localStream.stop();
video.pause(); localStream = null;
}, delayToTakePicture); }
}; return;
}
if (!$scope.showTakePicture) { var video = $(element).parent().parent().find("video").get(0);
$scope.showTakePictureReady = false; var makePicture = function() {
var videoConstraints = true; takePictureCountDown();
if ($scope.user.settings.cameraId) { $timeout(function() {
videoConstraints = { $scope.previewPicture = true;
optional: [{sourceId: $scope.user.settings.cameraId}] video.pause();
}; }, delayToTakePicture);
} };
getUserMedia({video: videoConstraints}, function(stream) {
if ($scope.showTakePictureReady) {
stream.stop();
return;
}
$scope.showTakePicture = true;
localStream = stream;
$scope.showTakePictureReady = true;
attachMediaStream(video, stream);
safeApply($scope);
}, function(error) {
console.error('Failed to get access to local media. Error code was ' + error.code);
$scope.showTakePictureReady = true;
safeApply($scope);
});
return;
} else if (take) {
makePicture();
} else if (retake) {
video.play();
$scope.previewPicture = false;
makePicture();
} else {
var canvas = $(element).parent().parent().find("canvas").get(0);
var videoWidth = video.videoWidth;
var videoHeight = video.videoHeight;
var aspectRatio = videoWidth/videoHeight;
if (!aspectRatio) {
// NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap!
console.warn("Unable to compute aspectRatio", aspectRatio);
aspectRatio = 1.3333333333333333;
}
var x = (46*aspectRatio-46)/-2;
canvas.getContext("2d").drawImage(video, x, 0, 46*aspectRatio, 46);
$scope.user.buddyPicture = canvas.toDataURL("image/jpeg");
console.info("Image size", $scope.user.buddyPicture.length);
localStream.stop();
localStream = null;
$scope.showTakePictureReady = true;
$scope.showTakePicture = false;
$scope.previewPicture = false;
safeApply($scope);
}
};
$scope.registerUserid = function(btn) { if (!$scope.showTakePicture) {
$scope.showTakePictureReady = false;
var videoConstraints = true;
if ($scope.user.settings.cameraId) {
videoConstraints = {
optional: [{
sourceId: $scope.user.settings.cameraId
}]
};
}
getUserMedia({
video: videoConstraints
}, function(stream) {
if ($scope.showTakePictureReady) {
stream.stop();
return;
}
$scope.showTakePicture = true;
localStream = stream;
$scope.showTakePictureReady = true;
attachMediaStream(video, stream);
safeApply($scope);
}, function(error) {
console.error('Failed to get access to local media. Error code was ' + error.code);
$scope.showTakePictureReady = true;
safeApply($scope);
});
return;
} else if (take) {
makePicture();
} else if (retake) {
video.play();
$scope.previewPicture = false;
makePicture();
} else {
var canvas = $(element).parent().parent().find("canvas").get(0);
var videoWidth = video.videoWidth;
var videoHeight = video.videoHeight;
var aspectRatio = videoWidth/videoHeight;
if (!aspectRatio) {
// NOTE(longsleep): In Firefox the video size becomes available at sound point later - crap!
console.warn("Unable to compute aspectRatio", aspectRatio);
aspectRatio = 1.3333333333333333;
}
var x = (46 * aspectRatio - 46) / -2;
canvas.getContext("2d").drawImage(video, x, 0, 46 * aspectRatio, 46);
$scope.user.buddyPicture = canvas.toDataURL("image/jpeg");
console.info("Image size", $scope.user.buddyPicture.length);
localStream.stop();
localStream = null;
$scope.showTakePictureReady = true;
$scope.showTakePicture = false;
$scope.previewPicture = false;
safeApply($scope);
}
};
var successHandler = function(data) { $scope.registerUserid = function(btn) {
console.info("Created new userid:", data.userid);
// If the server provided us a nonce, we can do everthing on our own.
mediaStream.users.store(data);
$scope.loadedUserlogin = true;
safeApply($scope);
// Directly authenticate ourselves with the provided nonce.
mediaStream.api.requestAuthentication(data.userid, data.nonce);
delete data.nonce;
};
console.log("No userid - creating one ..."); var successHandler = function(data) {
mediaStream.users.register(btn.form, function(data) { console.info("Created new userid:", data.userid);
if (data.nonce) { // If the server provided us a nonce, we can do everthing on our own.
successHandler(data); mediaStream.users.store(data);
} else { $scope.loadedUserlogin = true;
// No nonce received. So this means something we cannot do on our own. safeApply($scope);
// Make are GET request and retrieve nonce that way and let the // Directly authenticate ourselves with the provided nonce.
// browser/server do the rest. mediaStream.api.requestAuthentication(data.userid, data.nonce);
mediaStream.users.authorize(data, successHandler, function(data, status) { delete data.nonce;
console.error("Failed to get nonce after create", status, data); };
});
}
}, function(data, status) {
console.error("Failed to create userid", status, data);
});
}; console.log("No userid - creating one ...");
mediaStream.users.register(btn.form, function(data) {
if (data.nonce) {
successHandler(data);
} else {
// No nonce received. So this means something we cannot do on our own.
// Make are GET request and retrieve nonce that way and let the
// browser/server do the rest.
mediaStream.users.authorize(data, successHandler, function(data, status) {
console.error("Failed to get nonce after create", status, data);
});
}
}, function(data, status) {
console.error("Failed to create userid", status, data);
});
$scope.forgetUserid = function() { };
mediaStream.users.forget();
mediaStream.connector.forgetAndReconnect();
};
$scope.checkDefaultMediaSources = function() { $scope.forgetUserid = function() {
if ($scope.master.settings.microphoneId && !$scope.mediaSources.hasAudioId($scope.master.settings.microphoneId)) { mediaStream.users.forget();
$scope.master.settings.microphoneId=null; mediaStream.connector.forgetAndReconnect();
} };
if ($scope.master.settings.cameraId && !$scope.mediaSources.hasVideoId($scope.master.settings.cameraId)) {
$scope.master.settings.cameraId=null;
}
var audio = $scope.mediaSources.audio;
var video = $scope.mediaSources.video;
if (!$scope.master.settings.microphoneId && audio.length > 0) {
$scope.master.settings.microphoneId = audio[0].id;
}
if (!$scope.master.settings.cameraId && video.length > 0) {
$scope.master.settings.cameraId = $scope.mediaSources.video[0].id;
}
//console.log("master sources updates", $scope.master);
$scope.refreshWebrtcSettings();
};
$scope.mediaSources.refresh(function() {
safeApply($scope, $scope.checkDefaultMediaSources);
});
$scope.$watch("layout.settings", function(showSettings, oldValue) {
if (showSettings) {
$scope.desktopNotify.refresh();
$scope.mediaSources.refresh(function(audio, video) {
safeApply($scope, function(scope) {
if ($scope.user.settings.microphoneId && !$scope.mediaSources.hasAudioId($scope.user.settings.microphoneId)) {
$scope.user.settings.microphoneId=null;
}
if ($scope.user.settings.cameraId && !$scope.mediaSources.hasVideoId($scope.user.settings.cameraId)) {
$scope.user.settings.cameraId=null;
}
if (!$scope.user.settings.microphoneId && audio.length > 0) {
$scope.user.settings.microphoneId = audio[0].id;
}
if (!$scope.user.settings.cameraId && video.length > 0) {
$scope.user.settings.cameraId = video[0].id;
}
});
});
} else if (!showSettings && oldValue) {
$scope.saveSettings();
}
});
}];
var link = function($scope, $element) { $scope.checkDefaultMediaSources = function() {
}; if ($scope.master.settings.microphoneId && !$scope.mediaSources.hasAudioId($scope.master.settings.microphoneId)) {
$scope.master.settings.microphoneId = null;
}
if ($scope.master.settings.cameraId && !$scope.mediaSources.hasVideoId($scope.master.settings.cameraId)) {
$scope.master.settings.cameraId = null;
}
var audio = $scope.mediaSources.audio;
var video = $scope.mediaSources.video;
if (!$scope.master.settings.microphoneId && audio.length > 0) {
$scope.master.settings.microphoneId = audio[0].id;
}
if (!$scope.master.settings.cameraId && video.length > 0) {
$scope.master.settings.cameraId = $scope.mediaSources.video[0].id;
}
//console.log("master sources updates", $scope.master);
$scope.refreshWebrtcSettings();
};
$scope.mediaSources.refresh(function() {
safeApply($scope, $scope.checkDefaultMediaSources);
});
$scope.$watch("layout.settings", function(showSettings, oldValue) {
if (showSettings) {
$scope.desktopNotify.refresh();
$scope.mediaSources.refresh(function(audio, video) {
safeApply($scope, function(scope) {
if ($scope.user.settings.microphoneId && !$scope.mediaSources.hasAudioId($scope.user.settings.microphoneId)) {
$scope.user.settings.microphoneId = null;
}
if ($scope.user.settings.cameraId && !$scope.mediaSources.hasVideoId($scope.user.settings.cameraId)) {
$scope.user.settings.cameraId = null;
}
if (!$scope.user.settings.microphoneId && audio.length > 0) {
$scope.user.settings.microphoneId = audio[0].id;
}
if (!$scope.user.settings.cameraId && video.length > 0) {
$scope.user.settings.cameraId = video[0].id;
}
});
});
} else if (!showSettings && oldValue) {
$scope.saveSettings();
}
});
}];
return { var link = function($scope, $element) {};
scope: true,
restrict: 'E',
replace: true,
template: template,
controller: controller,
link: link
}
}]; return {
scope: true,
restrict: 'E',
replace: true,
template: template,
controller: controller,
link: link
};
}];
}); });

10
static/js/directives/socialshare.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@ -50,11 +50,11 @@ define(['jquery', 'text!partials/socialshare.html'], function($, template) {
var nw = $(event.currentTarget).data("nw"); var nw = $(event.currentTarget).data("nw");
var url = makeUrl(nw, $scope.roomlink); var url = makeUrl(nw, $scope.roomlink);
if (url) { if (url) {
if (nw==="email") { if (nw === "email") {
// Hack our way to disable unload popup for mail links. // Hack our way to disable unload popup for mail links.
$scope.manualReloadApp(url); $scope.manualReloadApp(url);
} else { } else {
$window.open(url, "social_"+nw, "menubar=no,toolbar=no,resizable=yes,width=600,height=600,scrollbars=yes"); $window.open(url, "social_" + nw, "menubar=no,toolbar=no,resizable=yes,width=600,height=600,scrollbars=yes");
} }
} }
}); });
@ -63,4 +63,4 @@ define(['jquery', 'text!partials/socialshare.html'], function($, template) {
}]; }];
}); });

4
static/js/directives/statusmessage.js

@ -1,8 +1,8 @@
/* /*
* Spreed Speak Freely. * Spreed WebRTC.
* Copyright (C) 2013-2014 struktur AG * Copyright (C) 2013-2014 struktur AG
* *
* This file is part of Spreed Speak Freely. * This file is part of Spreed WebRTC.
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save