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 @@ @@ -16,11 +16,6 @@
/tokens.txt
/dist
*~
debian/*.debhelper
debian/*.substvars
debian/spreed-webcaller
debian/files
debian/tmp
vendor/*
/dist_*
/build/out/

8
.jshint

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

4
.travis.yml

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

1
COPYING

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

1
ChangeLog

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

174
Makefile

@ -1,174 +0,0 @@ @@ -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 @@ @@ -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 @@ @@ -0,0 +1 @@
See https://github.com/strukturag/spreed-webrtc for further information.

1
README

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

21
README.md

@ -1,9 +1,9 @@ @@ -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
@ -20,11 +20,16 @@ The latest version of Spreed Speak Freely can be found on GitHub: @@ -20,11 +20,16 @@ The latest version of Spreed Speak Freely can be found on GitHub:
## 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.
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
$ ./configure
$ make
```
@ -43,7 +48,7 @@ The latest version of Spreed Speak Freely can be found on GitHub: @@ -43,7 +48,7 @@ The latest version of Spreed Speak Freely can be found on GitHub:
## Server startup
```bash
spreed-speakfreely-server [OPTIONS]
spreed-webrtc-server [OPTIONS]
```
Options
@ -69,7 +74,7 @@ The latest version of Spreed Speak Freely can be found on GitHub: @@ -69,7 +74,7 @@ The latest version of Spreed Speak Freely can be found on GitHub:
Copy the server.conf.in to server.conf.
Build styles, javascript and binary using make. Then run
``./spreed-speakfreely-server``
``./spreed-webrtc-server``
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: @@ -79,7 +84,7 @@ The latest version of Spreed Speak Freely can be found on GitHub:
## 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
found in `doc/NGINX.txt`.
@ -101,4 +106,4 @@ The latest version of Spreed Speak Freely can be found on GitHub: @@ -101,4 +106,4 @@ The latest version of Spreed Speak Freely can be found on GitHub:
## 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 @@ @@ -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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*jshint -W030 */
({
baseUrl: '../static/js',
mainConfigFile: '../static/js/main.js',
@ -59,4 +60,4 @@ @@ -59,4 +60,4 @@
inlineText: true,
}
]
})
});

110
configure.ac

@ -0,0 +1,110 @@ @@ -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 @@ @@ -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.
* Allow Makefile variables CONFIG_FILE and CONFIG_PATH.
@ -16,7 +47,7 @@ spreed-speakfreely-server (0.17.4) precise; urgency=low @@ -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
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.
* Updated Korean (ko) language.
@ -27,11 +58,11 @@ spreed-speakfreely-server (0.17.3) precise; urgency=low @@ -27,11 +58,11 @@ spreed-speakfreely-server (0.17.3) precise; urgency=low
* File permission fixes.
* Do not use sleepy as submodule but include it directly.
* 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
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.
* Use sleepy as submodule from external source.
@ -42,10 +73,10 @@ spreed-speakfreely-server (0.17.2) precise; urgency=low @@ -42,10 +73,10 @@ spreed-speakfreely-server (0.17.2) precise; urgency=low
* Added Japanese language.
* Added Chinese Traditional language.
* Updated Chinese language.
* Updated Korean language.
* Fixed screen sharing scrolling.
* Updated Korean language.
* Fixed screen sharing scrolling.
* Fixed screen sharing hangup in conferences.
* Avoid spurious bye ping pong.
* Avoid spurious bye ping pong.
* Fixed hangup in conferences.
* Fixed double click on Chrome OS.
* Fixed buddy list visibility if it should auto hide.
@ -54,7 +85,7 @@ spreed-speakfreely-server (0.17.2) precise; urgency=low @@ -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
spreed-speakfreely-server (0.17.1) precise; urgency=low
spreed-webrtc-server (0.17.1) precise; urgency=low
* Added translations for Korean and Chinese.
* Multiple updates to 3rd party js libraries.
@ -64,7 +95,7 @@ spreed-speakfreely-server (0.17.1) precise; urgency=low @@ -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
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
with latest TURN REST specification and requires a reasonably recent
@ -76,11 +107,11 @@ spreed-speakfreely-server (0.17.0) precise; urgency=low @@ -76,11 +107,11 @@ spreed-speakfreely-server (0.17.0) precise; urgency=low
* HTML fixes.
* Added method to generate URL-safe random string.
* 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
spreed-speakfreely-server (0.16.1) precise; urgency=low
spreed-webrtc-server (0.16.1) precise; urgency=low
* Implemented chat session control UI.
* Layout controller refactorization.
@ -88,7 +119,7 @@ spreed-speakfreely-server (0.16.1) precise; urgency=low @@ -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
spreed-speakfreely-server (0.16.0) precise; urgency=low
spreed-webrtc-server (0.16.0) precise; urgency=low
* Chat UI improvements.
* 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 @@ -97,13 +128,13 @@ spreed-speakfreely-server (0.16.0) precise; urgency=low
* Server code was reviewed and fixed where required.
* Changed Makefile to allow tarball and release builds with
local third party sources in ./vendor too.
* Added configration for maxfd and automatically use the
numer of cpus for GOMAXPROCS per default.
* Added configration for maxfd and automatically use the
numer of cpus for GOMAXPROCS per default.
* Added server helper for stats and profiling.
-- 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.

10
doc/CHANNELING-API.txt

@ -1,7 +1,7 @@ @@ -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
share peer information for peer to peer connectivity.
@ -340,7 +340,7 @@ Additional types for session listing and notifications @@ -340,7 +340,7 @@ Additional types for session listing and notifications
"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
@ -745,8 +745,8 @@ File sharing data channel protocol @@ -745,8 +745,8 @@ File sharing data channel protocol
End of Channeling API.
For latest version of Spreed Speak Freely check
https://github.com/strukturag/spreed-speakfreely
For latest version of Spreed WebRTC check
https://github.com/strukturag/spreed-webrtc
For questions, contact mailto:opensource@struktur.de.

32
doc/CROSSCOMPILE.txt

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

4
doc/plugin-example.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

18
doc/plugin-test-authorize.js

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

10
html/crawler.html

@ -0,0 +1,10 @@ @@ -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 @@ @@ -1,4 +1,5 @@
<%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="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">

2
html/logo.html

@ -1 +1 @@ @@ -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 @@ @@ -1,10 +1,10 @@
; Spreed Speak Freely server example configuration
; Spreed WebRTC server example configuration
[http]
; HTTP listener in format ip:port.
listen = 127.0.0.1:8080
; 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.
;readtimeout = 10
; HTTP socket write timeout in seconds.
@ -35,7 +35,7 @@ listen = 127.0.0.1:8080 @@ -35,7 +35,7 @@ listen = 127.0.0.1:8080
[app]
; HTML page title
;title = Spreed Speak Freely
;title = Spreed WebRTC
; 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
; long cached static resources.
@ -84,7 +84,7 @@ sessionSecret = the-default-secret-do-not-keep-me @@ -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
; resources in this static folder will be available as /extra/static/filename
; 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
; 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
@ -93,7 +93,7 @@ sessionSecret = the-default-secret-do-not-keep-me @@ -93,7 +93,7 @@ sessionSecret = the-default-secret-do-not-keep-me
;plugin = extra/static/myplugin.js
[log]
;logfile = /var/log/spreed-speakfreely-server.log
;logfile = /var/log/spreed-webrtc-server.log
[users]
; Set to true to enable user functionality.

2
spreed-speakfreely-server

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

2
spreed-webrtc-server

@ -0,0 +1,2 @@ @@ -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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -27,4 +27,6 @@ type Context struct { @@ -27,4 +27,6 @@ type Context struct {
Host string
Ssl bool
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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -66,6 +66,7 @@ func NewImageCache() ImageCache { @@ -66,6 +66,7 @@ func NewImageCache() ImageCache {
"image/png": "picture.png",
"image/jpeg": "picture.jpg",
"image/gif": "picture.gif",
"image/webp": "picture.webp",
}
}
return result

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

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
package main
import (
"app/spreed-speakfreely-server/sleepy"
"app/spreed-webrtc-server/sleepy"
"bytes"
"flag"
"fmt"
@ -117,15 +117,20 @@ func makeImageHandler(hub *Hub, expires time.Duration) http.HandlerFunc { @@ -117,15 +117,20 @@ func makeImageHandler(hub *Hub, expires time.Duration) http.HandlerFunc {
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("Expires", "-1")
w.Header().Set("Cache-Control", "private, max-age=0")
scheme := "http"
// Detect if the request was made with SSL.
ssl := r.TLS != nil
proto, ok := r.Header["X-Forwarded-Proto"]
if ok {
ssl = proto[0] == "https"
scheme = "https"
}
// Get languages from request.
@ -134,11 +139,22 @@ func handleRoomView(room string, w http.ResponseWriter, r *http.Request) { @@ -134,11 +139,22 @@ func handleRoomView(room string, w http.ResponseWriter, r *http.Request) {
langs = append(langs, "en")
}
// Prepare context to deliver to Javascript.
context := &Context{Cfg: config, App: "main", Host: r.Host, Ssl: ssl, Languages: langs}
// Prepare context to deliver to HTML..
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 {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
@ -204,7 +220,7 @@ func runner(runtime phoenix.Runtime) error { @@ -204,7 +220,7 @@ func runner(runtime phoenix.Runtime) error {
title, err := runtime.GetString("app", "title")
if err != nil {
title = "Spreed Speak Freely"
title = "Spreed WebRTC"
}
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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ @@ -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 @@ @@ -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 @@ @@ -1,5 +1,5 @@
VERSION := "1.0"
PROJECT := "Spreed Speak Freely"
PROJECT := "Spreed WebRTC"
COPYRIGHT := "struktur AG"
EMAIL := "simon@struktur.de"
ROOT := "$(CURDIR)/../.."

14
src/i18n/messages-de.po

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

14
src/i18n/messages-ja.po

@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
# Japanese translations for Spreed Speak Freely.
# Japanese translations for Spreed WebRTC.
# 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.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
# Curt Frisemo <curt.frisemo@spreed.com>, 2014.
#
msgid ""
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"
"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"
"Last-Translator: Curt Frisemo <curt.frisemo@spreed.com>\n"
"Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n"
@ -362,8 +362,8 @@ msgstr "あなたの共有ファイル:" @@ -362,8 +362,8 @@ msgstr "あなたの共有ファイル:"
msgid "Incoming file:"
msgstr "受信中ファイル:"
msgid "Quit from Spreed Speak Freely?"
msgstr "Spreed Speak Freelyを終了しますか?"
msgid "Close this window and disconnect?"
msgstr ""
msgid "Restart required to apply updates. Click ok to restart now."
msgstr "アップデート適用のため再起動してください.ここをクリックして再起動する."

16
src/i18n/messages-ko.po

@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
# Korean translations for Spreed Speak Freely.
# Korean translations for Spreed WebRTC.
# 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.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
# Curt Frisemo <curt.frisemo@spreed.com>, 2014.
#
msgid ""
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"
"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"
"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"
"Plural-Forms: nplurals=1; plural=0\n"
"MIME-Version: 1.0\n"
@ -362,8 +362,8 @@ msgstr "공유 화일:" @@ -362,8 +362,8 @@ msgstr "공유 화일:"
msgid "Incoming file:"
msgstr "도착하는 화일:"
msgid "Quit from Spreed Speak Freely?"
msgstr "Spreed Speak Freely사용을 중지 하시겠습니까?"
msgid "Close this window and disconnect?"
msgstr ""
msgid "Restart required to apply updates. Click ok to restart now."
msgstr "업데이트를 적용하려면 재시작이 필요 합니다. 지금 재시작 하려면 ok를 클릭 하십시오"

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

@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
# Chinese (China) translations for Spreed Speak Freely.
# Chinese (China) translations for Spreed WebRTC.
# 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.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
# Curt Frisemo <curt.frisemo@spreed.com>, 2014.
#
msgid ""
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"
"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"
"Last-Translator: Michael P.\n"
"Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n"
@ -363,8 +363,8 @@ msgstr "分享文件:" @@ -363,8 +363,8 @@ msgstr "分享文件:"
msgid "Incoming file:"
msgstr "发来文件:"
msgid "Quit from Spreed Speak Freely?"
msgstr "退出 Spreed Speak Freely?"
msgid "Close this window and disconnect?"
msgstr ""
msgid "Restart required to apply updates. Click ok to restart now."
msgstr "适用更新需重启,现在点击Ok重新启动。"

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

@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
# Chinese (Taiwan) translations for Spreed Speak Freely.
# Chinese (Taiwan) translations for Spreed WebRTC.
# 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.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
# Curt Frisemo <curt.frisemo@spreed.com>, 2014.
#
msgid ""
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"
"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"
"Last-Translator: Michael P.\n"
"Language-Team: Curt Frisemo <curt.frisemo@spreed.com>\n"
@ -363,8 +363,8 @@ msgstr "分享文件:" @@ -363,8 +363,8 @@ msgstr "分享文件:"
msgid "Incoming file:"
msgstr "發來文件:"
msgid "Quit from Spreed Speak Freely?"
msgstr "退出 Spreed Speak Freely?"
msgid "Close this window and disconnect?"
msgstr ""
msgid "Restart required to apply updates. Click ok to restart now."
msgstr "適用更新需重啟,現在點擊Ok重新啟動。"

10
src/i18n/messages.pot

@ -1,15 +1,15 @@ @@ -1,15 +1,15 @@
# Translations template for Spreed Speak Freely.
# Translations template for Spreed WebRTC.
# 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.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
#
#, fuzzy
msgid ""
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"
"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"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -362,7 +362,7 @@ msgstr "" @@ -362,7 +362,7 @@ msgstr ""
msgid "Incoming file:"
msgstr ""
msgid "Quit from Spreed Speak Freely?"
msgid "Close this window and disconnect?"
msgstr ""
msgid "Restart required to apply updates. Click ok to restart now."

4
src/styles/_shame.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_audiolevel.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_audiovideo.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

27
src/styles/components/_bar.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -190,3 +190,26 @@ @@ -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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -126,13 +126,16 @@ @@ -126,13 +126,16 @@
}
.buddy {
&.withSubline .display-name {
&.withSubline .buddy1 {
top: 15px;
}
&.withSubline .buddy2 {
display: block;
}
&.hovered .buddyactions {
right: 0;
}
.avatar {
.buddyPicture {
background: $actioncolor1;
border-radius: 2px;
float: left;
@ -155,7 +158,7 @@ @@ -155,7 +158,7 @@
top: 0;
}
}
.display-name {
.buddy1 {
color: $componentfg1;
font-weight: bold;
font-size: 14px;
@ -168,7 +171,7 @@ @@ -168,7 +171,7 @@
top: 24px;
white-space: nowrap;
}
.browser {
.buddy2 {
color: $componentfg2;
left: 65px;
overflow: hidden;
@ -176,6 +179,7 @@ @@ -176,6 +179,7 @@
right: 0px;
top: 33px;
white-space: nowrap;
display: none;
}
}

8
src/styles/components/_chat.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -341,11 +341,11 @@ @@ -341,11 +341,11 @@
}
.chat .message {
&.is_self .avatar {
&.is_self .buddyPicture {
left: auto;
right: 4px;
}
.avatar {
.buddyPicture {
background: $actioncolor1;
border-radius: 2px;
height: 46px;

8
src/styles/components/_fileinfo.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -71,10 +71,10 @@ @@ -71,10 +71,10 @@
display: block;
left: 0;
margin: 0 auto;
padding: 4px;
padding: 3px;
position: absolute;
text-shadow: 1px 1px 1px white;
top: 1px;
top: 0px;
right: 0;
z-index: 5;
}

4
src/styles/components/_rightslide.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_roombar.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_screenshare.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_settings.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_social.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/components/_usability.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/global/_angular.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/global/_animations.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

5
src/styles/global/_base.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -24,7 +24,6 @@ body { @@ -24,7 +24,6 @@ body {
background-clip: padding-box;
background-color: $background;
height: 100%;
font: normal $base-font-size $font-sans-serif;
}
body {

4
src/styles/global/_nicescroll.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

10
src/styles/global/_overlaybar.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -49,7 +49,7 @@ @@ -49,7 +49,7 @@
margin-top: 2px;
}
label {
padding-top: 7px !important;
padding-top: 6px !important;
}
}
@ -71,12 +71,12 @@ @@ -71,12 +71,12 @@
color: $bordercolor;
display: block;
font-size: 20px;
top: 0px;
left: 3px;
opacity: .7;
padding: 6px;
padding: 4px 6px;
position: absolute;
pointer-events: auto;
top: 1px;
vertical-align: middle;
z-index: 15;
}

40
src/styles/global/_variables.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -19,9 +19,6 @@ @@ -19,9 +19,6 @@
*
*/
// ** Custom Variables **
// --------------------------------------------------
// general
$background: #e5e5e5;
$componentbg: #f5f5f5;
@ -46,7 +43,7 @@ $loading: #ddd; @@ -46,7 +43,7 @@ $loading: #ddd;
// font
$font-sans-serif: "Helvetica Neue",Helvetica,Arial,sans-serif;
$base-font-size: 13px; // compass
$base-line-height: 19px; // compass
$base-line-height: 1.53846156; // compass
// audio video
$audiovideolevel: $action-enable;
@ -125,44 +122,27 @@ $breakpoint-useability-large: 1020px; @@ -125,44 +122,27 @@ $breakpoint-useability-large: 1020px;
$breakpoint-small: 480px;
$breakpoint-medium: 700px;
$breakpoint-large: 1280px;
$breakpoint-video-small: 590px;
$breakpoint-video-medium: 630px;
$breakpoint-chat-small: 210px;
$breakpoint-settings-medium: 630px;
// touch specific
$tap-highlight: rgba(0, 0, 0, 0);
// ** Fontawsome changed variables **
// Fontawsome changed variables
// 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
// --------------------------------------------------
//== 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.
$body-bg: $background;
// typography
// font, line-height, and color for body text, headings, and more
$font-family-sans-serif: $font-sans-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-base: $font-family-sans-serif;
$font-size-base: $base-font-size;
$line-height-base: $base-line-height;

4
src/styles/libs/_dialogs.scss

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

4
src/styles/main.scss

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

927
static/js/controllers/chatroomcontroller.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,461 +20,472 @@ @@ -20,461 +20,472 @@
*/
define(['underscore', 'moment', 'text!partials/fileinfo.html'], function(_, moment, templateFileInfo) {
// ChatroomController
return ["$scope", "$element", "$window", "safeMessage", "safeDisplayName", "$compile", "$filter", "translation", function($scope, $element, $window, safeMessage, safeDisplayName, $compile, $filter, translation) {
$scope.outputElement = $(".output", $element);
$scope.inputElement = $(".input", $element);
$scope.bodyElement = $(".chatbody", $element);
var lastSender = null;
var lastDate = null;
var lastMessageContainer = null;
var senderExpired = null;
var isTyping = false;
var isTypingExpired = null;
var peerTypingExpired = null;
var p2p = false;
var scrollAfterInput = false;
// Mark seen on several events.
$scope.bodyElement.on("mouseover mouseenter touchstart", _.debounce(function(event) {
$scope.$parent.seen();
$scope.$apply();
}, 100));
var displayName = safeDisplayName;
var buddyImageSrc = $filter("buddyImageSrc");
var fileInfo = $compile(templateFileInfo);
var knowMessage = {
r: {},
pending: [],
register: function(element, mid, status, received) {
if (mid) {
if (knowMessage.r.hasOwnProperty(mid)) {
console.warn("Duplicate chat message registration.", mid, element, status);
return;
}
var e = knowMessage.r[mid] = {
element: element,
status: status
}
if (e.status) {
element.addClass(e.status);
}
if (received) {
knowMessage.pending.push(mid);
$scope.$emit("submitreceived", mid);
}
}
},
update: function(mid, status) {
var e = knowMessage.r[mid];
if (e) {
if (e.status !== status && status) {
if (e.status) {
e.element.removeClass(e.status);
}
e.status = status;
e.element.addClass(e.status);
if (status === "received" || status === "read") {
// last one - cleanup
delete knowMessage.r[mid];
}
}
}
},
seen: function() {
var pending = knowMessage.pending;
if (pending.length) {
knowMessage.pending = [];
$scope.$emit("submitseen", pending);
_.each(pending, function(mid) {
knowMessage.update(mid, "read");
});
}
}
};
// Make sure that chat links are openend in a new window.
$element.on("click", function(event) {
var elem = $(event.target);
if (elem.is("a")) {
var url = elem.attr("href");
if (url && !elem.attr("download")) {
if (url.match(/mailto:/gi) === null) {
event.preventDefault();
$window.open(elem.attr("href"), "_blank");
}
}
};
});
$scope.$watch("input", function(newvalue) {
$scope.$parent.seen();
$window.clearTimeout(isTypingExpired);
if (!newvalue) {
return;
}
if (!isTyping) {
isTyping = true;
$scope.$emit("typing", {who: "local", status: "start"});
}
isTypingExpired = $window.setTimeout(function() {
isTyping = false;
$scope.$emit("typing", {who: "local", status: "stop"});
}, 4000);
});
$scope.reset = function() {
$scope.input = "";
isTyping = false;
$window.clearTimeout(isTypingExpired);
};
$scope.focus = function() {
$scope.inputElement.focus();
};
$scope.submit = function() {
var input = $scope.input;
if (input) {
scrollAfterInput = true;
$scope.$emit("submit", $scope.input);
$scope.reset();
$scope.focus();
}
};
$scope.canScroll = function() {
var o = $scope.outputElement.get(0);
if ((o.clientHeight - 20) < o.scrollHeight) {
if (!scrollAfterInput && (o.clientHeight + 20) < (o.scrollHeight - o.scrollTop)) {
// Manually scrolled -> do nothing.
} else {
scrollAfterInput = false;
// Return scroll function.
return function() {
o.scrollTop = o.scrollHeight;
};
}
}
return false;
}
$scope.display = function(s, nodes, extra_css, title, picture) {
var container;
var element;
var scroll = this.canScroll();
lastMessageContainer = null;
if (!extra_css) {
extra_css = "";
}
if (s || title || picture) {
container = $('<div class="message ' + extra_css + '"></div>');
if (title) {
container.prepend(title);
}
if (picture) {
container.prepend(picture);
}
lastMessageContainer = $("<ul>").appendTo(container);
if ($.trim(s)) {
element = $("<li>").html(s).appendTo(lastMessageContainer);
}
}
if (nodes) {
if (container) {
// Insert at the end of previously created container.
container.append(nodes);
} else {
$scope.outputElement.append(nodes);
}
if (container && lastMessageContainer) {
lastMessageContainer = $("<ul>").appendTo(container);
}
}
if (container) {
$scope.outputElement.append(container);
}
if (scroll) {
scroll();
}
return element;
};
$scope.$on("display", function(event, s, nodes) {
$scope.display(s, nodes);
});
$scope.append = function(s, nodes) {
if (!lastMessageContainer) {
return;
}
var scroll = this.canScroll();
var li = $("<li>");
li.html(s)
lastMessageContainer.append(li)
if (nodes) {
var parent = lastMessageContainer.parent();
parent.append(nodes);
lastMessageContainer = $("<ul>");
parent.append(lastMessageContainer);
}
if (scroll) {
scroll();
}
return li;
};
$scope.showtime = function(d, format, compare) {
var m;
if (d) {
m = moment(d);
} else {
m = moment();
}
if (!format) {
format = "LLL";
}
var datestring = m.format(format);
if (compare && datestring === compare) {
// Do nothing if compare matches.
return datestring;
}
$scope.display(null, $("<i>" + datestring + "</i>"));
if (!d) {
lastSender = null;
}
return datestring;
};
$scope.showdate = function(d) {
lastDate = $scope.showtime(d, "LL", lastDate);
};
$scope.showmessage = function(from, timestamp, message, nodes) {
var userid = $scope.$parent.$parent.id;
// Prepare message to display.
var s = [];
if (message) {
s.push(message);
$scope.$emit("incoming", message, from, userid);
}
var is_new_message = lastSender !== from;
var is_self = from === userid;
var extra_css = "";
var title = null;
var picture = null;
var showTitleAndPicture = function() {
if ($scope.isgroupchat) {
title = $("<strong>");
title.html(displayName(from, true));
extra_css += "with_name ";
var imgSrc = buddyImageSrc(from);
picture = $('<div class="avatar"><i class="fa fa-user fa-3x"/><img/></div>');
if (imgSrc) {
picture.find("img").attr("src", imgSrc);
}
}
};
if (is_new_message) {
lastSender = from;
$scope.showdate(timestamp);
showTitleAndPicture()
}
var message = s.join(" ");
if (!is_new_message) {
var element = this.append(message, nodes);
if (element) {
return element;
}
showTitleAndPicture();
}
if (is_self) {
extra_css += "is_self";
} else {
extra_css += "is_remote";
}
if (timestamp) {
var ts = $('<div class="timestamp"/>');
ts.text(moment(timestamp).format("H:mm"));
if (nodes) {
nodes = nodes.add(ts);
} else {
nodes = ts;
}
}
return $scope.display(message, nodes, extra_css, title, picture);
};
$scope.$on("seen", function() {
knowMessage.seen();
});
$scope.$on("p2p", function(event, state) {
//console.log("changed p2p state", state, p2p);
var msg;
if (state) {
msg = translation._("Peer to peer chat active.");
} else {
msg = translation._("Peer to peer chat is now off.");
}
$scope.display(null, $("<i class='p2p'><span class='icon-exchange'></span> " + msg + "</i>"));
});
$scope.$on("focus", function() {
$scope.focus();
});
$scope.$on("received", function(event, from, data) {
var userid = $scope.$parent.$parent.id;
var mid = data.Mid || null;
switch (data.Type) {
case "LeftOrJoined":
$scope.showtime(new Date());
if (data.LeftOrJoined === "left") {
$scope.display(null, $("<i>"+ displayName(from) + translation._(" is now offline.") + "</i>"));
} else {
$scope.display(null, $("<i>"+ displayName(from) + translation._(" is now online.") + "</i>"));
}
break;
case "Log":
$scope.showtime(new Date());
$scope.display(null, data.Log);
break;
case "Message":
default:
// Definitions.
var message = null;
var nodes = null;
var fromself = from === userid;
var noop = false;
var element = null;
var timestamp = data.Time;
if (!timestamp) {
timestamp = new Date();
}
// Process internal status messages.
if (data.Status) {
if (!mid && data.Status.Mid) {
mid = data.Status.Mid; // Inner Mid means internal chat status.
}
// Typing notification.
if (data.Status.Typing && !fromself) {
$window.clearTimeout(peerTypingExpired);
$scope.$emit("typing", {who: "peer", status: data.Status.Typing});
if (data.Status.Typing === "stop") {
peerTypingExpired = $window.setTimeout(function() {
$scope.$emit("typing", {who: "peer", status: "no"});
}, 20000);
}
}
// Mid updates.
if (mid && data.Status.State) {
knowMessage.update(mid, data.Status.State);
}
// Mid batch updates.
if (data.Status.SeenMids) {
_.each(data.Status.SeenMids, function(mid) {
knowMessage.update(mid, "received");
});
}
// File offers.
if (data.Status.FileInfo) {
var subscope = $scope.$new();
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);
});
noop = true;
}
// Ignore unknown status messages.
if (message === null && nodes === null) {
noop = true;
}
}
// Do nothing when where is nothing.
if (!data.Message && message === null && nodes === null) {
noop = true;
}
if (!noop) {
// Default handling is to use full message with security in place.
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);
}
if (element && mid && !$scope.isgroupchat) {
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);
});
}];
// ChatroomController
return ["$scope", "$element", "$window", "safeMessage", "safeDisplayName", "$compile", "$filter", "translation", function($scope, $element, $window, safeMessage, safeDisplayName, $compile, $filter, translation) {
$scope.outputElement = $(".output", $element);
$scope.inputElement = $(".input", $element);
$scope.bodyElement = $(".chatbody", $element);
var lastSender = null;
var lastDate = null;
var lastMessageContainer = null;
var senderExpired = null;
var isTyping = false;
var isTypingExpired = null;
var peerTypingExpired = null;
var p2p = false;
var scrollAfterInput = false;
// Mark seen on several events.
$scope.bodyElement.on("mouseover mouseenter touchstart", _.debounce(function(event) {
$scope.$parent.seen();
$scope.$apply();
}, 100));
var displayName = safeDisplayName;
var buddyImageSrc = $filter("buddyImageSrc");
var fileInfo = $compile(templateFileInfo);
var knowMessage = {
r: {},
pending: [],
register: function(element, mid, status, received) {
if (mid) {
if (knowMessage.r.hasOwnProperty(mid)) {
console.warn("Duplicate chat message registration.", mid, element, status);
return;
}
var e = knowMessage.r[mid] = {
element: element,
status: status
}
if (e.status) {
element.addClass(e.status);
}
if (received) {
knowMessage.pending.push(mid);
$scope.$emit("submitreceived", mid);
}
}
},
update: function(mid, status) {
var e = knowMessage.r[mid];
if (e) {
if (e.status !== status && status) {
if (e.status) {
e.element.removeClass(e.status);
}
e.status = status;
e.element.addClass(e.status);
if (status === "received" || status === "read") {
// last one - cleanup
delete knowMessage.r[mid];
}
}
}
},
seen: function() {
var pending = knowMessage.pending;
if (pending.length) {
knowMessage.pending = [];
$scope.$emit("submitseen", pending);
_.each(pending, function(mid) {
knowMessage.update(mid, "read");
});
}
}
};
// Make sure that chat links are openend in a new window.
$element.on("click", function(event) {
var elem = $(event.target);
if (elem.is("a")) {
var url = elem.attr("href");
if (url && !elem.attr("download")) {
if (url.match(/mailto:/gi) === null) {
event.preventDefault();
$window.open(elem.attr("href"), "_blank");
}
}
}
});
$scope.$watch("input", function(newvalue) {
$scope.$parent.seen();
$window.clearTimeout(isTypingExpired);
if (!newvalue) {
return;
}
if (!isTyping) {
isTyping = true;
$scope.$emit("typing", {
who: "local",
status: "start"
});
}
isTypingExpired = $window.setTimeout(function() {
isTyping = false;
$scope.$emit("typing", {
who: "local",
status: "stop"
});
}, 4000);
});
$scope.reset = function() {
$scope.input = "";
isTyping = false;
$window.clearTimeout(isTypingExpired);
};
$scope.focus = function() {
$scope.inputElement.focus();
};
$scope.submit = function() {
var input = $scope.input;
if (input) {
scrollAfterInput = true;
$scope.$emit("submit", $scope.input);
$scope.reset();
$scope.focus();
}
};
$scope.canScroll = function() {
var o = $scope.outputElement.get(0);
if ((o.clientHeight - 20) < o.scrollHeight) {
if (!scrollAfterInput && (o.clientHeight + 20) < (o.scrollHeight - o.scrollTop)) {
// Manually scrolled -> do nothing.
} else {
scrollAfterInput = false;
// Return scroll function.
return function() {
o.scrollTop = o.scrollHeight;
};
}
}
return false;
}
$scope.display = function(s, nodes, extra_css, title, picture) {
var container;
var element;
var scroll = this.canScroll();
lastMessageContainer = null;
if (!extra_css) {
extra_css = "";
}
if (s || title || picture) {
container = $('<div class="message ' + extra_css + '"></div>');
if (title) {
container.prepend(title);
}
if (picture) {
container.prepend(picture);
}
lastMessageContainer = $("<ul>").appendTo(container);
if ($.trim(s)) {
element = $("<li>").html(s).appendTo(lastMessageContainer);
}
}
if (nodes) {
if (container) {
// Insert at the end of previously created container.
container.append(nodes);
} else {
$scope.outputElement.append(nodes);
}
if (container && lastMessageContainer) {
lastMessageContainer = $("<ul>").appendTo(container);
}
}
if (container) {
$scope.outputElement.append(container);
}
if (scroll) {
scroll();
}
return element;
};
$scope.$on("display", function(event, s, nodes) {
$scope.display(s, nodes);
});
$scope.append = function(s, nodes) {
if (!lastMessageContainer) {
return;
}
var scroll = this.canScroll();
var li = $("<li>");
li.html(s)
lastMessageContainer.append(li)
if (nodes) {
var parent = lastMessageContainer.parent();
parent.append(nodes);
lastMessageContainer = $("<ul>");
parent.append(lastMessageContainer);
}
if (scroll) {
scroll();
}
return li;
};
$scope.showtime = function(d, format, compare) {
var m;
if (d) {
m = moment(d);
} else {
m = moment();
}
if (!format) {
format = "LLL";
}
var datestring = m.format(format);
if (compare && datestring === compare) {
// Do nothing if compare matches.
return datestring;
}
$scope.display(null, $("<i>" + datestring + "</i>"));
if (!d) {
lastSender = null;
}
return datestring;
};
$scope.showdate = function(d) {
lastDate = $scope.showtime(d, "LL", lastDate);
};
$scope.showmessage = function(from, timestamp, message, nodes) {
var userid = $scope.$parent.$parent.id;
// Prepare message to display.
var s = [];
if (message) {
s.push(message);
$scope.$emit("incoming", message, from, userid);
}
var is_new_message = lastSender !== from;
var is_self = from === userid;
var extra_css = "";
var title = null;
var picture = null;
var showTitleAndPicture = function() {
if ($scope.isgroupchat) {
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 (imgSrc) {
picture.find("img").attr("src", imgSrc);
}
}
};
if (is_new_message) {
lastSender = from;
$scope.showdate(timestamp);
showTitleAndPicture()
}
var strMessage = s.join(" ");
if (!is_new_message) {
var element = this.append(strMessage, nodes);
if (element) {
return element;
}
showTitleAndPicture();
}
if (is_self) {
extra_css += "is_self";
} else {
extra_css += "is_remote";
}
if (timestamp) {
var ts = $('<div class="timestamp"/>');
ts.text(moment(timestamp).format("H:mm"));
if (nodes) {
nodes = nodes.add(ts);
} else {
nodes = ts;
}
}
return $scope.display(strMessage, nodes, extra_css, title, picture);
};
$scope.$on("seen", function() {
knowMessage.seen();
});
$scope.$on("p2p", function(event, state) {
//console.log("changed p2p state", state, p2p);
var msg;
if (state) {
msg = translation._("Peer to peer chat active.");
} else {
msg = translation._("Peer to peer chat is now off.");
}
$scope.display(null, $("<i class='p2p'><span class='icon-exchange'></span> " + msg + "</i>"));
});
$scope.$on("focus", function() {
$scope.focus();
});
$scope.$on("received", function(event, from, data) {
var userid = $scope.$parent.$parent.id;
var mid = data.Mid || null;
switch (data.Type) {
case "LeftOrJoined":
$scope.showtime(new Date());
if (data.LeftOrJoined === "left") {
$scope.display(null, $("<i>" + displayName(from) + translation._(" is now offline.") + "</i>"));
} else {
$scope.display(null, $("<i>" + displayName(from) + translation._(" is now online.") + "</i>"));
}
break;
case "Log":
$scope.showtime(new Date());
$scope.display(null, data.Log);
break;
default:
// Definitions.
var message = null;
var nodes = null;
var fromself = from === userid;
var noop = false;
var element = null;
var timestamp = data.Time;
if (!timestamp) {
timestamp = new Date();
}
// Process internal status messages.
if (data.Status) {
if (!mid && data.Status.Mid) {
mid = data.Status.Mid; // Inner Mid means internal chat status.
}
// Typing notification.
if (data.Status.Typing && !fromself) {
$window.clearTimeout(peerTypingExpired);
$scope.$emit("typing", {
who: "peer",
status: data.Status.Typing
});
if (data.Status.Typing === "stop") {
peerTypingExpired = $window.setTimeout(function() {
$scope.$emit("typing", {
who: "peer",
status: "no"
});
}, 20000);
}
}
// Mid updates.
if (mid && data.Status.State) {
knowMessage.update(mid, data.Status.State);
}
// Mid batch updates.
if (data.Status.SeenMids) {
_.each(data.Status.SeenMids, function(mid) {
knowMessage.update(mid, "received");
});
}
// File offers.
if (data.Status.FileInfo) {
var subscope = $scope.$new();
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);
});
noop = true;
}
// Ignore unknown status messages.
if (message === null && nodes === null) {
noop = true;
}
}
// Do nothing when where is nothing.
if (!data.Message && message === null && nodes === null) {
noop = true;
}
if (!noop) {
// Default handling is to use full message with security in place.
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);
}
if (element && mid && !$scope.isgroupchat) {
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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -19,29 +19,28 @@ @@ -19,29 +19,28 @@
*
*/
define([
'underscore',
'underscore',
'controllers/mediastreamcontroller',
'controllers/statusmessagecontroller',
'controllers/chatroomcontroller',
'controllers/roomchangecontroller'
], function(_, MediastreamController, StatusmessageController, ChatroomController, RoomchangeController) {
'controllers/mediastreamcontroller',
'controllers/statusmessagecontroller',
'controllers/chatroomcontroller',
'controllers/roomchangecontroller'], function(_, MediastreamController, StatusmessageController, ChatroomController, RoomchangeController) {
var controllers = {
MediastreamController: MediastreamController,
StatusmessageController: StatusmessageController,
ChatroomController: ChatroomController,
RoomchangeController: RoomchangeController
};
var controllers = {
MediastreamController: MediastreamController,
StatusmessageController: StatusmessageController,
ChatroomController: ChatroomController,
RoomchangeController: RoomchangeController
};
var initialize = function (angModule) {
_.each(controllers, function(controller, name) {
angModule.controller(name, controller);
})
}
var initialize = function(angModule) {
_.each(controllers, function(controller, name) {
angModule.controller(name, controller);
})
}
return {
initialize: initialize
};
return {
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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,58 +20,59 @@ @@ -20,58 +20,59 @@
*/
define([], function() {
// RoomchangeController
return ["$scope", "$element", "$window", "$location", "mediaStream", "$http", "$timeout", function($scope, $element, $window, $location, mediaStream, $http, $timeout) {
// RoomchangeController
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;
ctrl.enabled = true;
var ctrl = this;
ctrl.enabled = true;
ctrl.getRoom = function(cb) {
$http({
method: "POST",
url: url,
data: $.param({
}),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).
success(function(data, status) {
cb(data);
}).
error(function() {
console.error("Failed to retrieve room link.");
cb({});
});
};
ctrl.getRoom = function(cb) {
$http({
method: "POST",
url: url,
data: $.param({}),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).
success(function(data, status) {
cb(data);
}).
error(function() {
console.error("Failed to retrieve room link.");
cb({});
});
};
$scope.changeRoomToId = function(id) {
var roomid = $window.encodeURIComponent(id);
$location.path("/"+roomid);
return roomid;
};
$scope.changeRoomToId = function(id) {
var roomid = $window.encodeURIComponent(id);
$location.path("/" + roomid);
return roomid;
};
$scope.$on("$destroy", function() {
//console.log("Room change controller destroyed");
ctrl.enabled = false;
});
$scope.$on("$destroy", function() {
//console.log("Room change controller destroyed");
ctrl.enabled = false;
});
var roomDataLinkInput = $element.find(".roomdata-link-input");
if (roomDataLinkInput.length) {
$scope.roomdata = {};
$timeout(function() {
if (ctrl.enabled) {
ctrl.getRoom(function(roomdata) {
console.info("Retrieved room data", roomdata);
$scope.roomdata = roomdata;
roomdata.link = $scope.roomlink = mediaStream.url.room(roomdata.name);
});
}
}, 100);
}
var roomDataLinkInput = $element.find(".roomdata-link-input");
if (roomDataLinkInput.length) {
$scope.roomdata = {};
$timeout(function() {
if (ctrl.enabled) {
ctrl.getRoom(function(roomdata) {
console.info("Retrieved room data", roomdata);
$scope.roomdata = roomdata;
roomdata.link = $scope.roomlink = mediaStream.url.room(roomdata.name);
});
}
}, 100);
}
}];
}];
});

38
static/js/controllers/statusmessagecontroller.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,25 +20,25 @@ @@ -20,25 +20,25 @@
*/
define([], function() {
// StatusmessageController
// StatusmessageController
return ["$scope", "mediaStream", function($scope, mediaStream) {
$scope.doHangup = function() {
mediaStream.webrtc.doHangup();
}
$scope.doAbort = function() {
mediaStream.webrtc.doHangup("abort", $scope.dialing);
}
$scope.doReconnect = function() {
mediaStream.connector.reconnect();
}
$scope.doAccept = function() {
mediaStream.webrtc.doAccept();
}
$scope.doReject = function() {
mediaStream.webrtc.doHangup('reject');
}
$scope.doHangup = function() {
mediaStream.webrtc.doHangup();
}
$scope.doAbort = function() {
mediaStream.webrtc.doHangup("abort", $scope.dialing);
}
$scope.doReconnect = function() {
mediaStream.connector.reconnect();
}
$scope.doAccept = function() {
mediaStream.webrtc.doAccept();
}
$scope.doReject = function() {
mediaStream.webrtc.doHangup('reject');
}
}];
}];
});

46
static/js/directives/audiolevel.js

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

597
static/js/directives/audiovideo.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,300 +20,303 @@ @@ -20,300 +20,303 @@
*/
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) {
var requestAnimationFrame = $window.requestAnimationFrame;
var peerTemplate = $compile(templatePeer);
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
var peers = {};
var events = $({});
$scope.container = $element.get(0);
$scope.layoutparent = $element.parent();
$scope.remoteVideos = $element.find(".remoteVideos").get(0);
$scope.localVideo = $element.find(".localVideo").get(0);
$scope.miniVideo = $element.find(".miniVideo").get(0);
$scope.mini = $element.find(".miniContainer").get(0);
$scope.hasUsermedia = false;
$scope.isActive = false;
$scope.rendererName = $scope.defaultRendererName = "onepeople";
//console.log("audiovideo", localVideo, miniVideo);
$scope.addRemoteStream = function(stream, currentcall) {
//console.log("Add remote stream to scope", pc.id, stream);
var subscope = $scope.$new(true);
var peerid = subscope.peerid = currentcall.id;
buddyData.push(peerid);
subscope.withvideo = false;
subscope.onlyaudio = false;
subscope.talking = false;
subscope.applyTalking = function(talking) {
subscope.talking = !!talking;
safeApply(subscope);
};
subscope.$on("active", function() {
console.log("Stream scope is now active", peerid);
events.triggerHandler("active."+peerid, [subscope, currentcall, stream]);
});
console.log("Created stream scope", peerid);
peerTemplate(subscope, function(clonedElement, scope) {
$($scope.remoteVideos).append(clonedElement);
clonedElement.data("peerid", scope.peerid);
scope.element = clonedElement;
var video = clonedElement.find("video").get(0);
$window.attachMediaStream(video, stream);
// Waiter callbacks also count as connected, as browser support (FireFox 25) is not setting state changes properly.
videoWaiter.wait(video, stream, function(withvideo) {
peers[peerid] = scope;
if (withvideo) {
scope.$apply(function($scope) {
$scope.withvideo = true;
});
} else {
console.info("Incoming stream has no video tracks.");
scope.$apply(function($scope) {
$scope.onlyaudio = true;
});
}
scope.$emit("active", currentcall);
$scope.redraw();
}, function() {
peers[peerid] = scope;
console.warn("We did not receive video data for remote stream", currentcall, stream, video);
scope.$emit("active", currentcall);
$scope.redraw();
});
scope.doChat = function() {
$scope.$emit("startchat", currentcall.id, {autofocus: true, restore: true});
};
});
};
$scope.removeRemoteStream = function(stream, currentcall) {
var subscope = peers[currentcall.id];
if (subscope) {
buddyData.pop(currentcall.id);
delete peers[currentcall.id];
//console.log("remove scope", subscope);
if (subscope.element) {
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);
if (scope) {
scope.applyTalking(talking);
} else {
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.isActive = true;
$scope.remoteVideos.style.opacity = 1;
$element.addClass("active");
//console.log("active 3");
_.delay(function() {
$scope.localVideo.style.opacity = 0;
$scope.localVideo.src = "";
}, 500);
_.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");
BigScreen.toggle($scope.layoutparent.get(0));
}
};
mediaStream.webrtc.e.on("usermedia", function(event, usermedia) {
//console.log("XXXXXXXXXXXXXXXXXXXXXXXXX usermedia event", usermedia);
$scope.hasUsermedia = true;
usermedia.attachMediaStream($scope.localVideo);
var count = 0;
var waitForLocalVideo = function() {
if (!$scope.hasUsermedia) {
return;
}
if ($scope.localVideo.videoWidth > 0) {
$scope.localVideo.style.opacity = 1;
$scope.redraw();
} else {
count++;
if (count < 100) {
setTimeout(waitForLocalVideo, 100);
} else {
console.warn("Timeout while waiting for local video.")
}
}
};
waitForLocalVideo();
});
mediaStream.webrtc.e.on("done", function() {
$scope.hasUsermedia = false;
$scope.isActive = false;
if (BigScreen.enabled) {
BigScreen.exit();
}
_.delay(function() {
if ($scope.isActive) {
return;
}
$scope.localVideo.src = '';
$scope.miniVideo.src = '';
$($scope.remoteVideos).empty();
}, 1500);
$($scope.mini).removeClass("visible");
$scope.localVideo.style.opacity = 0;
$scope.remoteVideos.style.opacity = 0;
$element.removeClass('active');
_.each(peers, function(scope, k) {
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)) {
//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);
});
return {
peers: peers
};
}];
var compile = function(tElement, tAttr) {
return function(scope, iElement, iAttrs, controller) {
//console.log("compile", arguments)
iElement.on("doubletap dblclick", _.debounce(scope.toggleFullscreen, 100, true));
var rendererName = null;
var getRendererName = function() {
// Return name of current renderer.
if (rendererName !== null) {
return rendererName;
} else {
return scope.rendererName;
}
};
scope.setRenderer = function(name) {
scope.rendererName = name;
};
var needsRedraw = false;
scope.redraw = function() {
needsRedraw = true;
};
var redraw = function() {
var size = {
width: scope.layoutparent.width(),
height: scope.layoutparent.height()
}
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) {
// Force smally renderer when we have a main view.
rendererName = "smally"
} else if (rendererName) {
rendererName = null;
}
_.defer(scope.redraw);
});
scope.redraw();
// Make sure we draw when the renderer was changed.
scope.$watch("rendererName", function() {
_.defer(scope.redraw);
});
// Update function run in rendering thread.
var update = function() {
if (needsRedraw) {
needsRedraw =false;
redraw();
}
requestAnimationFrame(update);
}
_.defer(update);
}
};
return {
restrict: 'E',
replace: true,
scope: true,
template: template,
controller: controller,
compile: compile
}
}];
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 peerTemplate = $compile(templatePeer);
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
var peers = {};
var events = $({});
$scope.container = $element.get(0);
$scope.layoutparent = $element.parent();
$scope.remoteVideos = $element.find(".remoteVideos").get(0);
$scope.localVideo = $element.find(".localVideo").get(0);
$scope.miniVideo = $element.find(".miniVideo").get(0);
$scope.mini = $element.find(".miniContainer").get(0);
$scope.hasUsermedia = false;
$scope.isActive = false;
$scope.rendererName = $scope.defaultRendererName = "onepeople";
//console.log("audiovideo", localVideo, miniVideo);
$scope.addRemoteStream = function(stream, currentcall) {
//console.log("Add remote stream to scope", pc.id, stream);
var subscope = $scope.$new(true);
var peerid = subscope.peerid = currentcall.id;
buddyData.push(peerid);
subscope.withvideo = false;
subscope.onlyaudio = false;
subscope.talking = false;
subscope.applyTalking = function(talking) {
subscope.talking = !! talking;
safeApply(subscope);
};
subscope.$on("active", function() {
console.log("Stream scope is now active", peerid);
events.triggerHandler("active." + peerid, [subscope, currentcall, stream]);
});
console.log("Created stream scope", peerid);
peerTemplate(subscope, function(clonedElement, scope) {
$($scope.remoteVideos).append(clonedElement);
clonedElement.data("peerid", scope.peerid);
scope.element = clonedElement;
var video = clonedElement.find("video").get(0);
$window.attachMediaStream(video, stream);
// Waiter callbacks also count as connected, as browser support (FireFox 25) is not setting state changes properly.
videoWaiter.wait(video, stream, function(withvideo) {
peers[peerid] = scope;
if (withvideo) {
scope.$apply(function($scope) {
$scope.withvideo = true;
});
} else {
console.info("Incoming stream has no video tracks.");
scope.$apply(function($scope) {
$scope.onlyaudio = true;
});
}
scope.$emit("active", currentcall);
$scope.redraw();
}, function() {
peers[peerid] = scope;
console.warn("We did not receive video data for remote stream", currentcall, stream, video);
scope.$emit("active", currentcall);
$scope.redraw();
});
scope.doChat = function() {
$scope.$emit("startchat", currentcall.id, {
autofocus: true,
restore: true
});
};
});
};
$scope.removeRemoteStream = function(stream, currentcall) {
var subscope = peers[currentcall.id];
if (subscope) {
buddyData.pop(currentcall.id);
delete peers[currentcall.id];
//console.log("remove scope", subscope);
if (subscope.element) {
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);
if (scope) {
scope.applyTalking(talking);
} else {
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.isActive = true;
$scope.remoteVideos.style.opacity = 1;
$element.addClass("active");
//console.log("active 3");
_.delay(function() {
$scope.localVideo.style.opacity = 0;
$scope.localVideo.src = "";
}, 500);
_.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");
BigScreen.toggle($scope.layoutparent.get(0));
}
};
mediaStream.webrtc.e.on("usermedia", function(event, usermedia) {
//console.log("XXXXXXXXXXXXXXXXXXXXXXXXX usermedia event", usermedia);
$scope.hasUsermedia = true;
usermedia.attachMediaStream($scope.localVideo);
var count = 0;
var waitForLocalVideo = function() {
if (!$scope.hasUsermedia) {
return;
}
if ($scope.localVideo.videoWidth > 0) {
$scope.localVideo.style.opacity = 1;
$scope.redraw();
} else {
count++;
if (count < 100) {
setTimeout(waitForLocalVideo, 100);
} else {
console.warn("Timeout while waiting for local video.")
}
}
};
waitForLocalVideo();
});
mediaStream.webrtc.e.on("done", function() {
$scope.hasUsermedia = false;
$scope.isActive = false;
if (BigScreen.enabled) {
BigScreen.exit();
}
_.delay(function() {
if ($scope.isActive) {
return;
}
$scope.localVideo.src = '';
$scope.miniVideo.src = '';
$($scope.remoteVideos).empty();
}, 1500);
$($scope.mini).removeClass("visible");
$scope.localVideo.style.opacity = 0;
$scope.remoteVideos.style.opacity = 0;
$element.removeClass('active');
_.each(peers, function(scope, k) {
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)) {
//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);
});
return {
peers: peers
};
}];
var compile = function(tElement, tAttr) {
return function(scope, iElement, iAttrs, controller) {
//console.log("compile", arguments)
iElement.on("doubletap dblclick", _.debounce(scope.toggleFullscreen, 100, true));
var rendererName = null;
var getRendererName = function() {
// Return name of current renderer.
if (rendererName !== null) {
return rendererName;
} else {
return scope.rendererName;
}
};
scope.setRenderer = function(name) {
scope.rendererName = name;
};
var needsRedraw = false;
scope.redraw = function() {
needsRedraw = true;
};
var redraw = function() {
var size = {
width: scope.layoutparent.width(),
height: scope.layoutparent.height()
}
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) {
// Force smally renderer when we have a main view.
rendererName = "smally"
} else if (rendererName) {
rendererName = null;
}
_.defer(scope.redraw);
});
scope.redraw();
// Make sure we draw when the renderer was changed.
scope.$watch("rendererName", function() {
_.defer(scope.redraw);
});
// Update function run in rendering thread.
var update = function() {
if (needsRedraw) {
needsRedraw = false;
redraw();
}
requestAnimationFrame(update);
}
_.defer(update);
}
};
return {
restrict: 'E',
replace: true,
scope: true,
template: template,
controller: controller,
compile: compile
}
}];
});

222
static/js/directives/buddylist.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,111 +20,117 @@ @@ -20,111 +20,117 @@
*/
define(['underscore', 'text!partials/buddylist.html'], function(_, template) {
// buddyList
return ["$compile", "buddyList", "mediaStream", function($compile, buddyList, mediaStream) {
//console.log("buddyList directive");
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
$scope.layout.buddylist = false;
$scope.enabled = false;
$scope.doCall = function(id) {
mediaStream.webrtc.doCall(id);
};
$scope.doChat = function(id) {
//console.log("doChat", id);
$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.setRoomStatus = function(status) {
if (status !== $scope.enabled) {
$scope.enabled = status;
$scope.$emit("roomStatus", status);
}
if (status && !$scope.layout.buddylistAutoHide) {
$scope.layout.buddylist = true
}
};
//XXX(longsleep): Debug leftover ?? Remove this.
window.doAudioConference = $scope.doAudioConference;
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);
mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) {
if (dataType === "Left") {
onLeft(data);
} else {
onJoined(data);
}
});
mediaStream.api.e.on("received.users", function(event, data) {
$scope.setRoomStatus(true);
var selfId = $scope.id;
_.each(data, function(p) {
if (p.Id !== selfId) {
onJoined(p);
}
});
$scope.$apply();
});
mediaStream.api.e.on("received.status", function(event, data) {
onStatus(data);
});
mediaStream.connector.e.on("closed error", function() {
$scope.setRoomStatus(false);
buddylist.onClosed();
});
// Request user list whenever the connection comes ready.
mediaStream.connector.ready(function() {
mediaStream.api.requestUsers();
});
}];
var link = function(scope, iElement, iAttrs, controller) {
// 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;
} else {
if (scope.layout.buddylistAutoHide) {
scope.layout.buddylist = false;
}
}
scope.$apply();
});
};
return {
restrict: 'E',
replace: true,
scope: true,
template: template,
controller: controller,
link: link
}
}];
// buddyList
return ["$compile", "buddyList", "mediaStream", function($compile, buddyList, mediaStream) {
//console.log("buddyList directive");
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
$scope.layout.buddylist = false;
$scope.enabled = false;
$scope.doCall = function(id) {
mediaStream.webrtc.doCall(id);
};
$scope.doChat = function(id) {
//console.log("doChat", id);
$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.setRoomStatus = function(status) {
if (status !== $scope.enabled) {
$scope.enabled = status;
$scope.$emit("roomStatus", status);
}
if (status && !$scope.layout.buddylistAutoHide) {
$scope.layout.buddylist = true
}
};
//XXX(longsleep): Debug leftover ?? Remove this.
window.doAudioConference = $scope.doAudioConference;
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);
mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) {
if (dataType === "Left") {
onLeft(data);
} else {
onJoined(data);
}
});
mediaStream.api.e.on("received.users", function(event, data) {
$scope.setRoomStatus(true);
var selfId = $scope.id;
_.each(data, function(p) {
if (p.Id !== selfId) {
onJoined(p);
}
});
$scope.$apply();
});
mediaStream.api.e.on("received.status", function(event, data) {
onStatus(data);
});
mediaStream.connector.e.on("closed error", function() {
$scope.setRoomStatus(false);
buddylist.onClosed();
});
// Request user list whenever the connection comes ready.
mediaStream.connector.ready(function() {
mediaStream.api.requestUsers();
});
}];
var link = function(scope, iElement, iAttrs, controller) {
// 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;
} else {
if (scope.layout.buddylistAutoHide) {
scope.layout.buddylist = false;
}
}
scope.$apply();
});
};
return {
restrict: 'E',
replace: true,
scope: true,
template: template,
controller: controller,
link: link
}
}];
});

893
static/js/directives/chat.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,425 +20,474 @@ @@ -20,425 +20,474 @@
*/
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) {
var displayName = safeDisplayName;
var group_chat_id = "";
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
$scope.layout.chat = false;
$scope.layout.chatMaximized = false;
var ctrl = this;
var rooms = ctrl.rooms = {};
ctrl.visibleRooms = [];
ctrl.group = group_chat_id;
ctrl.get = function(id) {
return ctrl.rooms[id];
}
$scope.currentRoom = null;
$scope.currentRoomActive = false;
$scope.getVisibleRooms = function() {
var res = [];
for (var i=0; i<ctrl.visibleRooms.length; i++) {
var r = rooms[ctrl.visibleRooms[i]];
if (!r || r.id === ctrl.group) {
continue;
}
res.push(r);
}
return res;
};
$scope.getGroupRoom = function() {
return rooms[ctrl.group];
};
mediaStream.api.e.on("received.chat", function(event, id, from, data, p2p) {
//console.log("received", data, id, from);
var roomid = id;
if (roomid === mediaStream.api.id) {
roomid = from;
} else {
if (roomid !== ctrl.group && from !== mediaStream.api.id) {
console.log("Received chat message for invalid room", roomid, id, from);
return;
}
}
var with_message = !!data.Message;
var room = rooms[roomid];
if (!room) {
if (!with_message) {
return;
}
// No room with this id, get one with the from id
$scope.$emit("startchat", from, {restore: with_message});
room = rooms[from];
}
if (with_message && from !== mediaStream.api.id) {
room.newmessage = true;
room.peerIsTyping = "no";
room.p2p(!!p2p);
}
room.$broadcast("received", from, data);
safeApply(room);
});
mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) {
var room = rooms[data.Id];
if (room) {
switch (dataType) {
case "Left":
if (data.Status !== "soft") {
room.enabled = false;
room.$broadcast("received", data.Id, {Type: "LeftOrJoined", "LeftOrJoined": "left"});
safeApply(room);
}
break;
case "Joined":
if (!room.enabled) {
room.enabled = true;
_.delay(function() {
room.$broadcast("received", data.Id, {Type: "LeftOrJoined", "LeftOrJoined": "joined"});
safeApply(room);
}, 1000);
}
break;
default:
break;
}
}
});
$scope.$parent.$on("startchat", function(event, id, options) {
//console.log("startchat requested", event, id);
if (id === group_chat_id) {
$scope.showGroupRoom(null, options);
} else {
$scope.showRoom(id, {title: translation._("Chat with")}, options);
}
});
}];
var compile = function(tElement, tAttrs) {
var chat = $compile(templateChatroom);
return function(scope, iElement, iAttrs, controller) {
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);
};
scope.showRoom = function(id, settings, options) {
var options = $.extend({}, options);
var subscope = controller.rooms[id];
var index = controller.visibleRooms.length;
if (!subscope) {
console.log("Create new chatroom", [id]);
controller.visibleRooms.push(id);
subscope = controller.rooms[id] = scope.$new();
translation.inject(subscope);
subscope.id = id;
subscope.isgroupchat = id === controller.group ? true : false;
subscope.index = index;
subscope.settings = settings;
subscope.visible = false;
subscope.newmessage = false;
subscope.enabled = true;
subscope.peerIsTyping = "no";
subscope.firstmessage = true;
subscope.p2pstate = false;
subscope.active = false;
subscope.pending = 0;
if (!subscope.isgroupchat) {
buddyData.push(id);
}
subscope.hide = function() {
scope.hideRoom(id);
};
//TODO(longsleep): This is currently never called. Find a suitable way to clean up old chats.
subscope.kill = function() {
if (!subscope.isgroupchat) {
buddyData.pop(id);
}
scope.killRoom(id);
};
subscope.seen = function() {
subscope.pending = 0;
scope.$emit("chatseen", subscope.id);
if (subscope.newmessage) {
subscope.newmessage = false;
subscope.$broadcast("seen");
}
};
subscope.deactivate =function() {
scope.deactivateRoom();
};
subscope.toggleMax = function() {
scope.toggleMax();
};
subscope.sendChat = function(to, message, status, mid, noloop) {
//console.log("send chat", to, scope.peer);
var peercall = mediaStream.webrtc.findTargetCall(to);
if (message && !mid) {
mid = randomGen.random({hex: true});
};
if (peercall && peercall.peerconnection.datachannelReady) {
subscope.p2p(true);
// Send out stuff through data channel.
_.delay(function() {
mediaStream.api.apply("sendChat", {
send: function(type, data) {
// We also send to self, to display our own stuff.
if (!noloop) {
mediaStream.api.received({Type: data.Type, Data: data, From: mediaStream.api.id, To: peercall.id});
}
return peercall.peerconnection.send(data);
}
})(to, message, status, mid);
}, 100);
} else {
subscope.p2p(false);
_.delay(function() {
mediaStream.api.send2("sendChat", function(type, data) {
if (!noloop) {
//console.log("looped to self", type, data);
mediaStream.api.received({Type: data.Type, Data: data, From: mediaStream.api.id, To: to});
}
})(to, message, status, mid);
}, 100);
}
return mid;
};
subscope.p2p = function(state) {
if (state !== subscope.p2pstate) {
subscope.p2pstate = state;
subscope.$broadcast("p2p", state);
}
};
//console.log("Creating new chat room", controller, subscope, index);
subscope.$on("submit", function(event, input) {
subscope.seen();
var mid = subscope.sendChat(event.targetScope.id, input);
event.targetScope.$broadcast("received", null, {Type: "Message", Status: {State: "sent", "Mid": mid}});
});
subscope.$on("submitseen", function(event, pending) {
//console.log("submitseen", pending);
subscope.sendChat(event.targetScope.id, null, {SeenMids: pending}, null, true);
});
subscope.$on("submitreceived", function(event, mid) {
subscope.sendChat(event.targetScope.id, null, {State: "delivered", Mid: mid}, null, true);
});
subscope.$on("typing", function(event, params) {
if (params.who === "local") {
var room = event.targetScope.id;
subscope.seen();
//console.log("typing event", params.status);
if (!subscope.isgroupchat) {
// Transmit typing events to private chats.
subscope.sendChat(event.targetScope.id, null, {Typing: params.status});
}
} else {
subscope.peerIsTyping = params.status;
//console.log("peer typing event", params.status, subscope.peerIsTyping);
}
safeApply(subscope);
});
subscope.$on("incoming", function(event, message, from, userid) {
if (from !== userid) {
subscope.pending++;
scope.$emit("chatincoming", subscope.id);
}
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.
if (!subscope.isgroupchat && from !== userid) {
playSound.play("message1");
desktopNotify.notify(translation._("Message from ")+displayName(from), message);
}
subscope.firstmessage = false;
}
});
chat(subscope, function(clonedElement, $scope) {
pane.append(clonedElement);
$scope.element=clonedElement;
$scope.visible = true;
if (options.autofocus) {
_.defer(function() {
$scope.$broadcast("focus");
});
}
// 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);
_.each(files, _.bind(function(f) {
var info = $.extend({id: f.id}, f.info);
console.log("Advertising file", f, info);
$scope.sendChat(subscope.id, "File", {FileInfo: info});
}, this));
}, this));
binder.namespace = function() {
// Inject own id into namespace.
return namespace+"_"+scope.myid;
};
});
} else {
if (options.restore) {
if (!subscope.visible) {
controller.visibleRooms.push(id);
subscope.index = index;
subscope.visible = true;
}
}
if (options.autofocus && subscope.visible) {
subscope.$broadcast("focus");
}
}
if (!options.noactivate) {
scope.activateRoom(subscope.id, true);
}
if (options.restore && !options.noenable) {
if (!scope.layout.chat) {
scope.layout.chat = true;
}
}
safeApply(subscope);
return subscope;
};
scope.hideRoom = function(id) {
var subscope = controller.rooms[id];
if (!subscope) {
console.log("hideRoom called for unknown room", id);
return;
}
var element = subscope.element;
var index = subscope.index;
controller.visibleRooms.splice(index, 1);
subscope.visible=false;
subscope.firstmessage=true;
// Refresh index of the rest of the rooms.
_.each(controller.visibleRooms, function(id, idx) {
var s = controller.rooms[id];
//console.log("updated idx", idx, s.index);
s.index = idx;
});
if (scope.currentRoom === subscope) {
scope.currentRoom = null;
scope.currentRoomActive = false;
}
if (!controller.visibleRooms.length) {
scope.showGroupRoom(null, {restore: true, noenable: true, noactivate: true});
// If last visible room was removed, hide chat.
scope.layout.chat = false;
}
};
scope.killRoom = function(id) {
scope.hideRoom(id);
var subscope = controller.rooms[id];
if (!subscope) {
return;
}
delete controller.rooms[id];
$timeout(function() {
subscope.$destroy();
}, 0);
};
scope.toggleMax = function() {
scope.layout.chatMaximized = !scope.layout.chatMaximized;
};
scope.activateRoom = function(id, active) {
var subscope = controller.rooms[id];
if (!subscope) {
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;
if (visible) {
flip = true;
}
} else {
if (scope.currentRoom) {
scope.currentRoom.active = false;
//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
}
}];
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 group_chat_id = "";
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
$scope.layout.chat = false;
$scope.layout.chatMaximized = false;
var ctrl = this;
var rooms = ctrl.rooms = {};
ctrl.visibleRooms = [];
ctrl.group = group_chat_id;
ctrl.get = function(id) {
return ctrl.rooms[id];
}
$scope.currentRoom = null;
$scope.currentRoomActive = false;
$scope.getVisibleRooms = function() {
var res = [];
for (var i = 0; i < ctrl.visibleRooms.length; i++) {
var r = rooms[ctrl.visibleRooms[i]];
if (!r || r.id === ctrl.group) {
continue;
}
res.push(r);
}
return res;
};
$scope.getGroupRoom = function() {
return rooms[ctrl.group];
};
mediaStream.api.e.on("received.chat", function(event, id, from, data, p2p) {
//console.log("received", data, id, from);
var roomid = id;
if (roomid === mediaStream.api.id) {
roomid = from;
} else {
if (roomid !== ctrl.group && from !== mediaStream.api.id) {
console.log("Received chat message for invalid room", roomid, id, from);
return;
}
}
var with_message = !! data.Message;
var room = rooms[roomid];
if (!room) {
if (!with_message) {
return;
}
// No room with this id, get one with the from id
$scope.$emit("startchat", from, {
restore: with_message
});
room = rooms[from];
}
if (with_message && from !== mediaStream.api.id) {
room.newmessage = true;
room.peerIsTyping = "no";
room.p2p( !! p2p);
}
room.$broadcast("received", from, data);
safeApply(room);
});
mediaStream.api.e.on("received.userleftorjoined", function(event, dataType, data) {
var room = rooms[data.Id];
if (room) {
switch (dataType) {
case "Left":
if (data.Status !== "soft") {
room.enabled = false;
room.$broadcast("received", data.Id, {
Type: "LeftOrJoined",
"LeftOrJoined": "left"
});
safeApply(room);
}
break;
case "Joined":
if (!room.enabled) {
room.enabled = true;
_.delay(function() {
room.$broadcast("received", data.Id, {
Type: "LeftOrJoined",
"LeftOrJoined": "joined"
});
safeApply(room);
}, 1000);
}
break;
default:
break;
}
}
});
$scope.$parent.$on("startchat", function(event, id, options) {
//console.log("startchat requested", event, id);
if (id === group_chat_id) {
$scope.showGroupRoom(null, options);
} else {
$scope.showRoom(id, {
title: translation._("Chat with")
}, options);
}
});
}];
var compile = function(tElement, tAttrs) {
var chat = $compile(templateChatroom);
return function(scope, iElement, iAttrs, controller) {
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);
};
scope.showRoom = function(id, settings, opts) {
var options = $.extend({}, opts);
var subscope = controller.rooms[id];
var index = controller.visibleRooms.length;
if (!subscope) {
console.log("Create new chatroom", [id]);
controller.visibleRooms.push(id);
subscope = controller.rooms[id] = scope.$new();
translation.inject(subscope);
subscope.id = id;
subscope.isgroupchat = id === controller.group ? true : false;
subscope.index = index;
subscope.settings = settings;
subscope.visible = false;
subscope.newmessage = false;
subscope.enabled = true;
subscope.peerIsTyping = "no";
subscope.firstmessage = true;
subscope.p2pstate = false;
subscope.active = false;
subscope.pending = 0;
if (!subscope.isgroupchat) {
buddyData.push(id);
}
subscope.hide = function() {
scope.hideRoom(id);
};
//TODO(longsleep): This is currently never called. Find a suitable way to clean up old chats.
subscope.kill = function() {
if (!subscope.isgroupchat) {
buddyData.pop(id);
}
scope.killRoom(id);
};
subscope.seen = function() {
subscope.pending = 0;
scope.$emit("chatseen", subscope.id);
if (subscope.newmessage) {
subscope.newmessage = false;
subscope.$broadcast("seen");
}
};
subscope.deactivate = function() {
scope.deactivateRoom();
};
subscope.toggleMax = function() {
scope.toggleMax();
};
subscope.sendChat = function(to, message, status, mid, noloop) {
//console.log("send chat", to, scope.peer);
var peercall = mediaStream.webrtc.findTargetCall(to);
if (message && !mid) {
mid = randomGen.random({
hex: true
});
}
if (peercall && peercall.peerconnection.datachannelReady) {
subscope.p2p(true);
// Send out stuff through data channel.
_.delay(function() {
mediaStream.api.apply("sendChat", {
send: function(type, data) {
// We also send to self, to display our own stuff.
if (!noloop) {
mediaStream.api.received({
Type: data.Type,
Data: data,
From: mediaStream.api.id,
To: peercall.id
});
}
return peercall.peerconnection.send(data);
}
})(to, message, status, mid);
}, 100);
} else {
subscope.p2p(false);
_.delay(function() {
mediaStream.api.send2("sendChat", function(type, data) {
if (!noloop) {
//console.log("looped to self", type, data);
mediaStream.api.received({
Type: data.Type,
Data: data,
From: mediaStream.api.id,
To: to
});
}
})(to, message, status, mid);
}, 100);
}
return mid;
};
subscope.p2p = function(state) {
if (state !== subscope.p2pstate) {
subscope.p2pstate = state;
subscope.$broadcast("p2p", state);
}
};
//console.log("Creating new chat room", controller, subscope, index);
subscope.$on("submit", function(event, input) {
subscope.seen();
var mid = subscope.sendChat(event.targetScope.id, input);
event.targetScope.$broadcast("received", null, {
Type: "Message",
Status: {
State: "sent",
"Mid": mid
}
});
});
subscope.$on("submitseen", function(event, pending) {
//console.log("submitseen", pending);
subscope.sendChat(event.targetScope.id, null, {
SeenMids: pending
}, null, true);
});
subscope.$on("submitreceived", function(event, mid) {
subscope.sendChat(event.targetScope.id, null, {
State: "delivered",
Mid: mid
}, null, true);
});
subscope.$on("typing", function(event, params) {
if (params.who === "local") {
var room = event.targetScope.id;
subscope.seen();
//console.log("typing event", params.status);
if (!subscope.isgroupchat) {
// Transmit typing events to private chats.
subscope.sendChat(event.targetScope.id, null, {
Typing: params.status
});
}
} else {
subscope.peerIsTyping = params.status;
//console.log("peer typing event", params.status, subscope.peerIsTyping);
}
safeApply(subscope);
});
subscope.$on("incoming", function(event, message, from, userid) {
if (from !== userid) {
subscope.pending++;
scope.$emit("chatincoming", subscope.id);
}
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.
if (!subscope.isgroupchat && from !== userid) {
playSound.play("message1");
desktopNotify.notify(translation._("Message from ") + displayName(from), message);
}
subscope.firstmessage = false;
}
});
chat(subscope, function(clonedElement, $scope) {
pane.append(clonedElement);
$scope.element = clonedElement;
$scope.visible = true;
if (options.autofocus) {
_.defer(function() {
$scope.$broadcast("focus");
});
}
// 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);
_.each(files, _.bind(function(f) {
var info = $.extend({
id: f.id
}, f.info);
console.log("Advertising file", f, info);
$scope.sendChat(subscope.id, "File", {
FileInfo: info
});
}, this));
}, this));
binder.namespace = function() {
// Inject own id into namespace.
return namespace + "_" + scope.myid;
};
});
} else {
if (options.restore) {
if (!subscope.visible) {
controller.visibleRooms.push(id);
subscope.index = index;
subscope.visible = true;
}
}
if (options.autofocus && subscope.visible) {
subscope.$broadcast("focus");
}
}
if (!options.noactivate) {
scope.activateRoom(subscope.id, true);
}
if (options.restore && !options.noenable) {
if (!scope.layout.chat) {
scope.layout.chat = true;
}
}
safeApply(subscope);
return subscope;
};
scope.hideRoom = function(id) {
var subscope = controller.rooms[id];
if (!subscope) {
console.log("hideRoom called for unknown room", id);
return;
}
var element = subscope.element;
var index = subscope.index;
controller.visibleRooms.splice(index, 1);
subscope.visible = false;
subscope.firstmessage = true;
// Refresh index of the rest of the rooms.
_.each(controller.visibleRooms, function(id, idx) {
var s = controller.rooms[id];
//console.log("updated idx", idx, s.index);
s.index = idx;
});
if (scope.currentRoom === subscope) {
scope.currentRoom = null;
scope.currentRoomActive = false;
}
if (!controller.visibleRooms.length) {
scope.showGroupRoom(null, {
restore: true,
noenable: true,
noactivate: true
});
// If last visible room was removed, hide chat.
scope.layout.chat = false;
}
};
scope.killRoom = function(id) {
scope.hideRoom(id);
var subscope = controller.rooms[id];
if (!subscope) {
return;
}
delete controller.rooms[id];
$timeout(function() {
subscope.$destroy();
}, 0);
};
scope.toggleMax = function() {
scope.layout.chatMaximized = !scope.layout.chatMaximized;
};
scope.activateRoom = function(id, active) {
var subscope = controller.rooms[id];
if (!subscope) {
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;
if (visible) {
flip = true;
}
} else {
if (scope.currentRoom) {
scope.currentRoom.active = false;
//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 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -19,49 +19,48 @@ @@ -19,49 +19,48 @@
*
*/
define([
'underscore',
'underscore',
'directives/onenter',
'directives/onescape',
'directives/statusmessage',
'directives/buddylist',
'directives/settings',
'directives/chat',
'directives/audiovideo',
'directives/usability',
'directives/audiolevel',
'directives/fileinfo',
'directives/screenshare',
'directives/roombar',
'directives/socialshare',
'directives/page'
], function(_, onEnter, onEscape, statusMessage, buddyList, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page) {
'directives/onenter',
'directives/onescape',
'directives/statusmessage',
'directives/buddylist',
'directives/settings',
'directives/chat',
'directives/audiovideo',
'directives/usability',
'directives/audiolevel',
'directives/fileinfo',
'directives/screenshare',
'directives/roombar',
'directives/socialshare',
'directives/page'], function(_, onEnter, onEscape, statusMessage, buddyList, settings, chat, audioVideo, usability, audioLevel, fileInfo, screenshare, roomBar, socialShare, page) {
var directives = {
onEnter: onEnter,
onEscape: onEscape,
statusMessage: statusMessage,
buddyList: buddyList,
settings: settings,
chat: chat,
audioVideo: audioVideo,
usability: usability,
audioLevel: audioLevel,
fileInfo: fileInfo,
screenshare: screenshare,
roomBar: roomBar,
socialShare: socialShare,
page: page
};
var directives = {
onEnter: onEnter,
onEscape: onEscape,
statusMessage: statusMessage,
buddyList: buddyList,
settings: settings,
chat: chat,
audioVideo: audioVideo,
usability: usability,
audioLevel: audioLevel,
fileInfo: fileInfo,
screenshare: screenshare,
roomBar: roomBar,
socialShare: socialShare,
page: page
};
var initialize = function (angModule) {
_.each(directives, function(directive, name) {
angModule.directive(name, directive);
})
};
var initialize = function(angModule) {
_.each(directives, function(directive, name) {
angModule.directive(name, directive);
})
};
return {
initialize: initialize
};
return {
initialize: initialize
};
});

16
static/js/directives/fileinfo.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -46,10 +46,10 @@ define(['jquery', 'underscore'], function($, _) { @@ -46,10 +46,10 @@ define(['jquery', 'underscore'], function($, _) {
var progressBar = progressBars[0];
var progressBarDownload = progressBars[1];
$scope.$watch("progress", function() {
progressBar.style.width=($scope.progress)+"%";
progressBar.style.width = ($scope.progress) + "%";
});
$scope.$watch("progressDownload", function() {
progressBarDownload.style.width=($scope.progressDownload)+"%";
progressBarDownload.style.width = ($scope.progressDownload) + "%";
});
$scope.$watch("error", function() {
@ -85,7 +85,7 @@ define(['jquery', 'underscore'], function($, _) { @@ -85,7 +85,7 @@ define(['jquery', 'underscore'], function($, _) {
}
// 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.bytesPerSecond = _.reduce(bytesPerSecond, function(memo, num) {
@ -177,8 +177,8 @@ define(['jquery', 'underscore'], function($, _) { @@ -177,8 +177,8 @@ define(['jquery', 'underscore'], function($, _) {
if ($scope.cancelled) {
return;
}
$scope.progress = Math.ceil((written / ($scope.info.chunks-1)) * 100);
if (written >= $scope.info.chunks-1) {
$scope.progress = Math.ceil((written / ($scope.info.chunks - 1)) * 100);
if (written >= $scope.info.chunks - 1) {
$scope.progress = 100;
}
});
@ -189,7 +189,7 @@ define(['jquery', 'underscore'], function($, _) { @@ -189,7 +189,7 @@ define(['jquery', 'underscore'], function($, _) {
return;
}
bytesIn.push(bytesLength);
$scope.progressDownload = Math.ceil((chunk / ($scope.info.chunks-1)) * 100);
$scope.progressDownload = Math.ceil((chunk / ($scope.info.chunks - 1)) * 100);
chunk++;
});

40
static/js/directives/onenter.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,22 +20,22 @@ @@ -20,22 +20,22 @@
*/
define([], function() {
// onEnter
return [function() {
return {
restrict: "A",
link: function(scope, element, attrs) {
var c = attrs.onEnter;
element.bind("keydown keypress", function(event) {
if (event.which === 13 && !event.shiftKey && !event.ctrlKey) {
// On enter whithout shift or ctrl.
event.preventDefault();
scope.$eval(c);
scope.$apply();
}
});
}
}
}];
// onEnter
return [function() {
return {
restrict: "A",
link: function(scope, element, attrs) {
var c = attrs.onEnter;
element.bind("keydown keypress", function(event) {
if (event.which === 13 && !event.shiftKey && !event.ctrlKey) {
// On enter whithout shift or ctrl.
event.preventDefault();
scope.$eval(c);
scope.$apply();
}
});
}
}
}];
});
});

40
static/js/directives/onescape.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,22 +20,22 @@ @@ -20,22 +20,22 @@
*/
define([], function() {
// onEscape
return [function() {
return {
restrict: "A",
link: function(scope, element, attrs) {
var c = attrs.onEscape;
element.bind("keydown keypress", function(event) {
if (event.which === 27) {
// On escape.
event.preventDefault();
scope.$eval(c);
scope.$apply();
}
});
}
}
}];
// onEscape
return [function() {
return {
restrict: "A",
link: function(scope, element, attrs) {
var c = attrs.onEscape;
element.bind("keydown keypress", function(event) {
if (event.which === 27) {
// On escape.
event.preventDefault();
scope.$eval(c);
scope.$apply();
}
});
}
}
}];
});
});

4
static/js/directives/page.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by

90
static/js/directives/roombar.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -20,58 +20,58 @@ @@ -20,58 +20,58 @@
*/
define(['underscore', 'text!partials/roombar.html'], function(_, template) {
// roomBar
return ["$window", "$rootScope", "$location", function($window, $rootScope, $location) {
// roomBar
return ["$window", "$rootScope", "$location", function($window, $rootScope, $location) {
var link = function($scope) {
var link = function($scope) {
//console.log("roomBar directive link", arguments);
$scope.newroomid = $rootScope.roomid;
$scope.hideRoomBar = true;
//console.log("roomBar directive link", arguments);
$scope.newroomid = $rootScope.roomid;
$scope.hideRoomBar = true;
$scope.save = function() {
var roomid = $scope.changeRoomToId($scope.newroomid);
if (roomid !== $rootScope.roomid) {
$scope.roombarform.$setPristine();
}
$scope.hideRoomBar = true;
};
$scope.save = function() {
var roomid = $scope.changeRoomToId($scope.newroomid);
if (roomid !== $rootScope.roomid) {
$scope.roombarform.$setPristine();
}
$scope.hideRoomBar = true;
};
$scope.hitEnter = function(evt){
if(angular.equals(evt.keyCode, 13)) {
$scope.save();
}
};
$scope.hitEnter = function(evt) {
if (angular.equals(evt.keyCode, 13)) {
$scope.save();
}
};
$scope.exit = function() {
$scope.newroomid = "";
$scope.save();
};
$scope.exit = function() {
$scope.newroomid = "";
$scope.save();
};
$rootScope.$watch("roomid", function(newroomid, roomid) {
if (!newroomid) {
newroomid = "";
}
$scope.newroomid = newroomid;
});
$rootScope.$watch("roomid", function(newroomid, roomid) {
if (!newroomid) {
newroomid = "";
}
$scope.newroomid = newroomid;
});
$scope.$watch("newroomid", function(newroomid) {
if (newroomid === $rootScope.roomid) {
$scope.roombarform.$setPristine();
}
});
$scope.$watch("newroomid", function(newroomid) {
if (newroomid === $rootScope.roomid) {
$scope.roombarform.$setPristine();
}
});
};
};
return {
restrict: 'E',
replace: true,
scope: true,
template: template,
controller: "RoomchangeController",
link: link
}
return {
restrict: 'E',
replace: true,
scope: true,
template: template,
controller: "RoomchangeController",
link: link
}
}];
}];
});

60
static/js/directives/screenshare.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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 @@ -48,22 +48,24 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
return;
}
// Control data request.
var msg;
try {
var msg = JSON.parse(data);
} catch(e) {
msg = JSON.parse(data);
} catch (e) {
// Invalid JSON.
console.warn("Invalid JSON received from screen share channel.", data);
peerscreenshare.close()
peerscreenshare.close();
return;
}
switch (msg.m) {
case "bye":
// Close this screen share.
peerscreenshare.close();
break;
default:
console.log("Unknown screen share control request", msg.m, msg);
break;
case "bye":
// Close this screen share.
peerscreenshare.close();
break;
default:
console.log("Unknown screen share control request", msg.m, msg);
break;
}
} else {
@ -163,7 +165,7 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials @@ -163,7 +165,7 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
if ($scope.layout.screenshare) {
$scope.stopScreenshare();
};
}
$scope.layout.screenshare = true;
@ -193,15 +195,15 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials @@ -193,15 +195,15 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
scope.usermedia = usermedia;
// Create token to register with us and send token out to all peers.
// 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.
var updater = function(event, state, currentcall) {
switch (state) {
case "completed":
case "connected":
connector(token, currentcall);
break;
case "completed":
case "connected":
connector(token, currentcall);
break;
}
};
@ -227,7 +229,9 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials @@ -227,7 +229,9 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
updated = null;
// Send by to all connected peers.
_.each(screenshares, function(peerscreenshare) {
peerscreenshare.send({m: "bye"});
peerscreenshare.send({
m: "bye"
});
$timeout(function() {
peerscreenshare.close();
}, 0);
@ -274,17 +278,17 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials @@ -274,17 +278,17 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
} else {
BigScreen.toggle(pane.get(0));
}
}
}
};
$scope.$watch("layout.screenshare", function(newval, oldval) {
if (newval && !oldval) {
$scope.doScreenshare();
} else if(!newval && oldval) {
$scope.stopScreenshare();
}
});
$scope.$watch("layout.screenshare", function(newval, oldval) {
if (newval && !oldval) {
$scope.doScreenshare();
} else if (!newval && oldval) {
$scope.stopScreenshare();
}
});
}];
@ -307,4 +311,4 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials @@ -307,4 +311,4 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials
}];
});
});

452
static/js/directives/settings.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* it under the terms of the GNU Affero General Public License as published by
@ -18,244 +18,252 @@ @@ -18,244 +18,252 @@
* 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) {
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.showAdvancedSettings = true;
$scope.showTakePicture = false;
$scope.previewPicture = false;
$scope.showTakePictureReady = true;
$scope.rememberSettings = true;
$scope.desktopNotify = desktopNotify;
$scope.mediaSources = mediaSources;
$scope.availableLanguages = [
{
code: "",
name: translation._("Use browser language")
}
];
$scope.withUsers = mediaStream.config.UsersEnabled;
$scope.withUsersRegistration = mediaStream.config.UsersAllowRegistration;
$scope.withUsersMode = mediaStream.config.UsersMode;
$scope.layout.settings = false;
$scope.showAdvancedSettings = true;
$scope.showTakePicture = false;
$scope.showTakePictureReady = true;
$scope.previewPicture = false;
$scope.rememberSettings = true;
$scope.desktopNotify = desktopNotify;
$scope.mediaSources = mediaSources;
$scope.availableLanguages = [{
code: "",
name: translation._("Use browser language")
}];
$scope.withUsers = mediaStream.config.UsersEnabled;
$scope.withUsersRegistration = mediaStream.config.UsersAllowRegistration;
$scope.withUsersMode = mediaStream.config.UsersMode;
_.each(availableLanguages, function(name, code) {
$scope.availableLanguages.push({
code: code,
name: name
});
});
_.each(availableLanguages, function(name, code) {
$scope.availableLanguages.push({
code: code,
name: name
});
});
var localStream = null;
var localStream = null;
$scope.saveSettings = function() {
var user = $scope.user;
$scope.update(user);
$scope.layout.settings = false;
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);
};
// Make sure to save settings when they are open and the page is reloaded.
$(window).on("unload", function() {
if ($scope.layout.settings) {
$scope.saveSettings();
}
});
if (stop) {
$scope.showTakePicture = false;
$scope.previewPicture = false;
if (localStream) {
localStream.stop();
localStream = null;
}
return;
}
$scope.saveSettings = function() {
var user = $scope.user;
$scope.update(user);
$scope.layout.settings = false;
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);
};
var video = $(element).parent().parent().find("video").get(0);
var makePicture = function() {
takePictureCountDown();
$timeout(function() {
$scope.previewPicture = true;
video.pause();
}, delayToTakePicture);
};
if (stop) {
$scope.showTakePicture = false;
$scope.previewPicture = false;
if (localStream) {
localStream.stop();
localStream = null;
}
return;
}
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 video = $(element).parent().parent().find("video").get(0);
var makePicture = function() {
takePictureCountDown();
$timeout(function() {
$scope.previewPicture = true;
video.pause();
}, delayToTakePicture);
};
$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) {
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;
};
$scope.registerUserid = function(btn) {
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);
});
var successHandler = function(data) {
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 ...");
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() {
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();
}
});
}];
$scope.forgetUserid = function() {
mediaStream.users.forget();
mediaStream.connector.forgetAndReconnect();
};
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 {
scope: true,
restrict: 'E',
replace: true,
template: template,
controller: controller,
link: link
}
var link = function($scope, $element) {};
}];
return {
scope: true,
restrict: 'E',
replace: true,
template: template,
controller: controller,
link: link
};
}];
});

10
static/js/directives/socialshare.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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) { @@ -50,11 +50,11 @@ define(['jquery', 'text!partials/socialshare.html'], function($, template) {
var nw = $(event.currentTarget).data("nw");
var url = makeUrl(nw, $scope.roomlink);
if (url) {
if (nw==="email") {
if (nw === "email") {
// Hack our way to disable unload popup for mail links.
$scope.manualReloadApp(url);
} 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) { @@ -63,4 +63,4 @@ define(['jquery', 'text!partials/socialshare.html'], function($, template) {
}];
});
});

4
static/js/directives/statusmessage.js

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
/*
* Spreed Speak Freely.
* Spreed WebRTC.
* 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
* 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