Archived
1
0
Fork 0

Prepare for 2.0.0 release

This commit is contained in:
Varakh 2019-08-06 20:25:50 +02:00
parent f947c51a79
commit 8a0cb391fe
139 changed files with 44117 additions and 6310 deletions

40
CHANGELOG.md Normal file
View file

@ -0,0 +1,40 @@
# CHANGELOG
## 2.0.0 - UNRELEASED
* Replace material design with bootstrap4 theme
* Update deployment and release documentation and examples
* Update dependencies and force PHP 7.3
* Add fallback for values for `env` file
## 1.2.4 - 2019/01/18
* No info text
## 1.2.3 - 2019/01/18
* No info text
## 1.2.2 - 2018/09/01
* No info text
## 1.2.1 - 2018/06/04
* No info text
## 1.2.0 - 2018/06/04
* No info text
## 1.1.1 - 2018/05/04
* No info text
## 1.1.0 - 2018/05/04
* No info text
## 1.0.3 - 2018/04/04
* No info text
## 1.0.2 - 2018/04/04
* No info text
## 1.0.1 - 2018/04/03
* No info text
## 1.0.0 - 2018/04/03
* No info text

218
README.md
View file

@ -1,118 +1,156 @@
# README # README
**ts3web** is a web interface for any TeamSpeak 3 Server used with serverQuery login. **ts3web** is a web interface for any TeamSpeak 3 Server used with serverQuery login. Sources can be viewed
[here](https://git.myservermanager.com/alexander.schaeferdiek/ts3web).
This web interface aims to be as simple as possible. The minimalistic approach is intentional. This web interface aims to be as simple as possible. The minimalistic approach is intentional.
If you like to help (to translate or implement features), open an issue first. If possible, you should use existing code to implement new features. PRs will be merged after a code review. Feel free to submit pull requests if you like to help.
Features which are currently not supported: Features which are currently **not supported**:
* Permissions Management (except for viewing) * modify permissions (only viewing)
* File Management (except for viewing) * modify files (only viewing)
**ts3web** can be deployed in different ways. See below for more information. For each deployment type a running
TeamSpeak 3 server is a prerequisite (except for the `docker-compose.yml` type which will start also the server if
needed).
## Configuration ## Configuration
The main configuration file is the `env` file located in `config/`. There's an example file called `env.example` which you The main configuration file is the `env` file located in `config/`. There's an example file called `env.example`
need to copy to `config/env`. which you can copy to `config/env`. Defaults will assume you're running your TeamSpeak server on `localhost` with
default port. Docker deployments can host bind this file into the container directly and just maintain the `env` file.
**Information for docker users**: it's possible to have the `env` file persistent and not within the container so ## Usage with docker-compose
that rebuilding the image isn't required. Create a host volume `/path/from/host/env` and map it to
`/var/www/html/application/config/env`. Changes will show up after restarting the container.
## Install / Deployment The recommended way is to use docker-compose. The `network_mode = "host"` is required in order to show correct IP
addresses of connected users.
You can either use docker or manual deployment. Please read the following section carefully. 1. The web interface will not be able to use `localhost` as TeamSpeak 3 server address because it's not available in a
docker container not using the `host` network. Thus the`whitelist.txt` **must** include your public TeamSpeak 3 server
IP for this example setup.
2. The public address also has to match the environment variable `teamspeak_host=your-public-address` within
the `env` file referenced in the example `docker-compose`.
### Automatic installation and deployment with docker or docker-compose ```
version: '2'
networks:
teamspeak:
external: false
services:
app:
container_name: teamspeak_app
image: teamspeak:latest
volumes:
- ./app:/var/ts3server
- ./whitelist.txt:/whitelist.txt
ports:
- 10011:10011
- 30033:30033
- 9987:9987/udp
environment:
- TS3SERVER_LICENSE=accept
- TS3SERVER_IP_WHITELIST=/whitelist.txt
restart: always
network_mode: "host"
web:
container_name: teamspeak_web
image: teamspeak_web:latest
volumes:
- ./env:/var/www/html/application/config/env
ports:
- 127.0.0.1:8181:80
depends_on:
- app
restart: always
networks:
- teamspeak
```
##### Install Now execute `docker-compose up -d` to start those containers. If you like to update, do `docker-compose down`,
`docker-compose pull` and then `docker-compose up -d` again.
###### docker Your TeamSpeak 3 Server will be available under `public-server-ip:9987`. The web interface will be available on
`127.0.0.1:8181`. You need to add a reverse proxy and probably you also want SSL configured if you expose it via domain.
For testing purposes, change `- 127.0.0.1:8181:80` to `- 8181:80`. The web interface will then be available under
`public-server-ip:8181`. This is **not recommended**! Secure your setup properly via reverse proxy and SSL.
* Clone repository ## Usage as single docker container
* Copy either `config/env.example` to `config/env` and adjust to your needs or make it persistent outside if the container. To do so take a look at the configuration section first). Ensure that if you share the same docker network, the environment variable `teamspeak_default_host` should be the name of your teamspeak docker container.
* Build the docker image from the project home with `docker build -t teamspeak_web:latest -f docker/Dockerfile .` * Copy `env.example` to `env` and adjust to your needs. It's recommended to make it persistent outside of the container.
* Create a container with the image, e.g. `docker run --name teamspeak_web -p 8181:80 slimblog_app:latest`. Make sure that if teamspeak and ts3web share the same docker instance they should be put into one network and the subnet **needs be added to teamspeak's query whitelist**. The web interface won't work otherwise. * Create a container with the image, e.g. `docker run --name teamspeak_web -v ./env:/var/www/html/application/config/env -p 8181:80 varakh/ts3web:latest`.
* Make sure that if teamspeak and ts3web share the same docker instance they should be put into one network and the subnet **needs be added to teamspeak's query whitelist**.
* Point your browser to `8181` to see the web interface. * Point your browser to `8181` to see the web interface.
###### docker-compose ## Usage as native application
**Prerequisite**: `php`, `composer` and probably `php-fpm` installed on the server.
There's an example `docker-compose.yml` in the `docker-compose/` directory.
* Adjust `docker-compose/env` if you need to change something.
* Build the docker image from the project home with `docker build -t teamspeak_web:latest -f docker/Dockerfile .`
* Change directory to `docker-compose/` folder
* Execute `docker-compose up -d`
* Point your browser to `8080` to see the web interface.
##### Upgrade
###### docker
* Change directory to project home
* `git pull`
* Build the docker image from the project home with `docker build -t teamspeak_web:latest -f docker/Dockerfile .`
* Re-create app container with latest image
###### docker-compose
* Change directory to project home
* `git pull`
* Build the docker image from the project home with `docker build -t teamspeak_web:latest -f docker/Dockerfile .`
* Change directory to `docker-compose/` folder
* Execute `docker-compose down`
* Execute `docker-compose up -d`
### Manual installation and deployment
#### Install
To install:
* Clone repository * Clone repository
* Install composer
* Change directory to project home * Change directory to project home
* Execute `composer install` * Execute `composer install`
* `composer install` * `composer install`
* Use a web server or run directly via PHP server: `php -S localhost:8080 -t public public/index.php` (point browser to [localhost:8080](http://localhost:8080))
#### Web server To upgrade:
* Configure nginx or apache.
* Point your document root to `public/`.
* Example `nginx.conf`:
```
root .../public;
index index.php;
rewrite_log on;
location / {
try_files $uri $uri/ @ee;
}
location @ee {
rewrite ^(.*) /index.php?$1 last;
}
# php fpm
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
include fastcgi_params;
}
```
* Everything should be up and running. Point your browser to `8080` to see the web interface.
#### Upgrade
* Change directory to project home * Change directory to project home
* `git pull` * `git pull`
* `composer update` * `composer update`
### Contributions & Development ## Web server setup
* Follow manual install guide but use the internal server with `php -S localhost:8080 -t public public/index.php` * Example `nginx.conf` for **standalone** deployment without SSL:
* Point browser to [localhost:8080](http://localhost:8080)
#### Helpers ```
root .../public;
index index.php;
rewrite_log on;
location / {
try_files $uri $uri/ @ee;
}
location @ee {
rewrite ^(.*) /index.php?$1 last;
}
# php fpm
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
include fastcgi_params;
}
```
* Example `nginx.conf` as **reverse proxy** with SSL:
```
server {
listen 443 ssl http2;
server_name teamspeak.domain.tld;
ssl on;
ssl_certificate fullchain.pem;
ssl_certificate_key privkey.pem;
location / {
proxy_pass http://localhost:8181;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
```
## Development
### Release
* Set a date in the `CHANGELOG.md` file
* Build the docker image from the project home with `docker build -t varakh/ts3web:latest -f docker/Dockerfile .` and publish it
* Tag the release git commit and create a new release in the VCS web interface
### Helpers
Attributes can be defined when including `table`, `keyvalues` and `form` templates of twig. This helps to generate tables and forms without the need to specify all attributes. Attributes can be defined when including `table`, `keyvalues` and `form` templates of twig. This helps to generate tables and forms without the need to specify all attributes.
@ -126,11 +164,13 @@ attributesEditable // define editable attributes in the key value view
fields // define fields for a form fields // define fields for a form
``` ```
See example usage in the folder `View/material`. See example usage in the folder `View/bootstrap4`.
#### Translations ### Translations
- This app uses Symfony Translator. It's bootstrapped in `Util\BootstrapHelper` and locales are placed under `data/locale/`. Adjust to your needs or help translating. - This app uses Symfony Translator. It's bootstrapped in `Util\BootstrapHelper` and locales are placed under `data/locale/`. Adjust to your needs or help translating.
- Form fields (name/id should be the same) are also translated. For a field named `content` or `ConT enT` translate `form_field_content`. - Form fields (name/id should be the same) are also translated. For a field named `content` or `ConT enT` translate `form_field_content`.
#### Theme ### Theme
Themes can be chosen in the `env` file by editing the `theme` variable. Templates are mapped to the corresponding view folder in `src/View/<themeName>`. `.css`, `.js` and other style files like `.ttf` or `.woff2` for fonts should be placed in `public/theme/<themeName>` and accessed accordingly. See an example in `src/View/boostrap4/layout.twig`. Themes can be chosen in the `env` file by editing the `theme` variable. Templates are mapped to the corresponding view
folder in `src/View/<themeName>`. `.css`, `.js` and other style files like `.ttf` or `.woff2` for fonts should be placed
in `public/theme/<themeName>` and accessed accordingly. See an example in `src/View/boostrap4/layout.twig`.

View file

@ -1,30 +1,33 @@
{ {
"require": { "require": {
"slim/slim": "^3.0", "php": ">= 7.3",
"monolog/monolog": "^1.18", "slim/slim": "^3.0",
"slim/twig-view": "^2.1", "monolog/monolog": "^1.18",
"slim/flash": "^0.1.0", "slim/twig-view": "^2.1",
"wixel/gump": "^1.3", "slim/flash": "^0.1.0",
"symfony/translation": "^3.1", "wixel/gump": "^1.3",
"symfony/twig-bridge": "^3.1", "symfony/translation": "^3.1",
"symfony/yaml": "*", "symfony/twig-bridge": "^3.1",
"vlucas/phpdotenv": "^2.3", "symfony/yaml": "*",
"jeremykendall/slim-auth": "dev-slim-3.x", "vlucas/phpdotenv": "^2.3",
"par0noid/ts3admin": "^1.0", "jeremykendall/slim-auth": "dev-slim-3.x",
"nesbot/carbon": "^1.25", "par0noid/ts3admin": "^1.0",
"bryanjhv/slim-session": "^3.5", "nesbot/carbon": "^2.0.0",
"symfony/filesystem": "^4.0", "bryanjhv/slim-session": "^3.5",
"symfony/finder": "^4.0" "symfony/filesystem": "^4.0",
}, "symfony/finder": "^4.0"
"config": { },
"bin-dir": "bin/" "config": {
}, "bin-dir": "bin/"
"autoload": { },
"classmap": [ "autoload": {
"src/", "classmap": [
"config/", "src/",
"data/", "config/",
"vendor/" "data/",
] "vendor/"
} ]
},
"require-dev": {
}
} }

67
config/EnvConstants.php Normal file
View file

@ -0,0 +1,67 @@
<?php
/**
* Class EnvConstants
*/
class EnvConstants
{
/**
* Default env file loaded
*/
const ENV_FILE_DEFAULT = "env.default";
/**
* Custom env file
*/
const ENV_FILE_CUSTOM = "env";
/**
* Site title
*/
const SITE_TITLE = "site_title";
/**
* Site language
*/
const SITE_LANGUAGE = "site_language";
/**
* Site date format
*/
const SITE_DATE_FORMAT = "site_date_format";
/**
* THeme
*/
const THEME = "theme";
/**
* Cache
*/
const THEME_CACHE = "theme_cache";
/**
* TeamSpeak host
*/
const TEAMSPEAK_HOST = "teamspeak_host";
/**
* TeamSpeak query port
*/
const TEAMSPEAK_QUERY_PORT = "teamspeak_query_port";
/**
* TeamSpeak default user
*/
const TEAMSPEAK_USER = "teamspeak_user";
/**
* Log name
*/
const LOG_NAME = "log_name";
/**
* Log level
*/
const LOG_LEVEL = "log_level";
}

17
config/env.default Normal file
View file

@ -0,0 +1,17 @@
# site
site_title="Teamspeak 3 Web"
site_language="en" # values: each yml you specified in data/locale/
site_date_format="d.m.Y H:i:s" # values: all possible for Date::class
# theme
theme="bootstrap4" # values: material (foldernames are used to determine theme in src/View/)
theme_cache=false # values: true|false (cache view/twig. makes it faster, disable for debug)
# teamspeak
teamspeak_host="localhost" # 'localhost' or 'name_of_docker_container' if running locally
teamspeak_query_port=10011
teamspeak_user="serveradmin"
# log
log_name="ts3web" # values: all strings
log_level="INFO" # values: DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, EMERGENCY

View file

@ -4,13 +4,13 @@ site_language="en" # values: each yml you specified in data/locale/
site_date_format="d.m.Y H:i:s" # values: all possible for Date::class site_date_format="d.m.Y H:i:s" # values: all possible for Date::class
# theme # theme
theme="material" # values: material (foldernames are used to determine theme in src/View/) theme="bootstrap4" # values: bootstrap4 (foldernames are used to determine theme in src/View/)
theme_cache=false # values: true|false (cache view/twig. makes it faster, disable for debug) theme_cache=false # values: true|false (cache view/twig. makes it faster, disable for debug)
# teamspeak # teamspeak
teamspeak_default_host="localhost" # 'localhost' or 'name_of_docker_container' if running locally teamspeak_host="localhost" # 'localhost' or 'name_of_docker_container' if running locally
teamspeak_default_query_port=10011 teamspeak_query_port=10011
teamspeak_default_user="serveradmin" teamspeak_user="serveradmin"
# log # log
log_name="ts3web" # values: all strings log_name="ts3web" # values: all strings

View file

@ -8,16 +8,21 @@ error.500.content: "Internal application error."
error.500.title: "500" error.500.title: "500"
login.flash.success: "Logged in as %username% successfully." login.flash.success: "Logged in as %username% successfully."
login.flash.wrong_credentials: "Cannot login. Wrong credentials." login.flash.wrong_credentials: "Cannot login. Wrong credentials."
login.form.button: "Login" login.form.button: "Sign in"
login.form.host: "Host"
login.form.username: "User"
login.form.password: "Password"
login.form.password.placeholder: "Password" login.form.password.placeholder: "Password"
login.form.username.placeholder: "Username" login.form.username.placeholder: "Username"
log.internal.application.error: "Internal application error." log.internal.application.error: "Internal application error."
login.title: "Login" login.title: "Please login"
logout.flash.success: "Logged out successfully." logout.flash.success: "Logged out successfully."
logout.title: "Logout" logout.title: "Logout"
menu.currentlyloggedin: "Logged in as: %username%" menu.currentlyloggedin: "%username%"
menu.login: "Login" menu.login: "Login"
menu.logout: "Logout" menu.logout: "Logout"
menu.servers.select: "Select a server"
menu.servers.deselect: "Deselect server"
mismatch: "There is no validation rule for %field%." mismatch: "There is no validation rule for %field%."
no_entities.message: "Nothing to show." no_entities.message: "Nothing to show."
validate_alpha_dash: "The %field% field may only contain alpha characters and dashes." validate_alpha_dash: "The %field% field may only contain alpha characters and dashes."
@ -155,6 +160,8 @@ channel_info.h.details: "Details"
channel_info.h.clients: "Clients" channel_info.h.clients: "Clients"
channel_info.send: "Send a message" channel_info.send: "Send a message"
channel_info.send.message: "Message" channel_info.send.message: "Message"
channel_info.client: "Client"
channel_info.files.delete: "Delete"
# groups # groups
groups.delete: "Delete" groups.delete: "Delete"
@ -175,6 +182,8 @@ channelgroups.delete: "Delete"
channelgroup_info.h.clients: "Clients" channelgroup_info.h.clients: "Clients"
channelgroup_info.h.permissions: "Permissions" channelgroup_info.h.permissions: "Permissions"
channelgroup_info.remove: "Remove" channelgroup_info.remove: "Remove"
channelgroup_info.client: "Client"
channelgroup_info.channel: "Channel"
# server group info # server group info
servergroup_info.h.clients_add: "Add" servergroup_info.h.clients_add: "Add"
@ -201,6 +210,8 @@ client_info.send: "Send a message"
client_info.send.subject: "Subject" client_info.send.subject: "Subject"
client_info.send.message: "Message" client_info.send.message: "Message"
client_info.sent.success: "Sent message to client %cldbid%." client_info.sent.success: "Sent message to client %cldbid%."
client_info.channel: "Channel"
client_info.channelgroup: "Channelgroup"
# online info # online info
online_info.h.actions: "Actions" online_info.h.actions: "Actions"
@ -229,6 +240,8 @@ online.send.message: "Message"
online.poked.success: "Poked client %clid%." online.poked.success: "Poked client %clid%."
online.kicked.success: "Kicked client %clid%." online.kicked.success: "Kicked client %clid%."
online.banned.success: "Banned client %clid%." online.banned.success: "Banned client %clid%."
online.client: "Client"
online.channel: "Channel"
# tokens # tokens
tokens.delete: "Delete" tokens.delete: "Delete"

View file

@ -4,13 +4,13 @@ site_language="en" # values: each yml you specified in data/locale/
site_date_format="d.m.Y H:i:s" # values: all possible for Date::class site_date_format="d.m.Y H:i:s" # values: all possible for Date::class
# theme # theme
theme="material" # values: material (foldernames are used to determine theme in src/View/) theme="bootstrap4" # values: bootstrap4 (foldernames are used to determine theme in src/View/)
theme_cache=false # values: true|false (cache view/twig. makes it faster, disable for debug) theme_cache=false # values: true|false (cache view/twig. makes it faster, disable for debug)
# teamspeak # teamspeak
teamspeak_default_host="teamspeak_app" # 'localhost' or 'name_of_docker_container' if running locally teamspeak_host="teamspeak_app" # 'localhost' or 'name_of_docker_container' if running locally
teamspeak_default_query_port=10011 teamspeak_query_port=10011
teamspeak_default_user="serveradmin" teamspeak_user="serveradmin"
# log # log
log_name="ts3web" # values: all strings log_name="ts3web" # values: all strings

View file

@ -49,8 +49,8 @@ $container['translator'] = function () use ($translator) {
}; };
// date // date
Carbon::setLocale(getenv('site_language')); Carbon::setLocale(getenv(EnvConstants::SITE_LANGUAGE));
Carbon::setToStringFormat(getenv('site_date_format')); Carbon::setToStringFormat(getenv(EnvConstants::SITE_DATE_FORMAT));
// logger // logger
try { try {
@ -70,7 +70,8 @@ $container['ts'] = function () use ($logger) {
// auth // auth
$container['authAdapter'] = function ($container) { $container['authAdapter'] = function ($container) {
$adapter = new TSAuthAdapter(getenv('teamspeak_default_host'), getenv('teamspeak_default_query_port'), $container['logger'], $container['ts']); $adapter = new TSAuthAdapter(getenv(EnvConstants::TEAMSPEAK_HOST),
getenv(EnvConstants::TEAMSPEAK_QUERY_PORT), $container['logger'], $container['ts']);
return $adapter; return $adapter;
}; };
$container['acl'] = function () { $container['acl'] = function () {
@ -94,10 +95,9 @@ $container['flash'] = function () {
return new Slim\Flash\Messages; return new Slim\Flash\Messages;
}; };
$container['view'] = function ($container) use ($app) { $container['view'] = function ($container) use ($app) {
// theme $themeDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'View' . DIRECTORY_SEPARATOR . getenv(EnvConstants::THEME);
$themeDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'View' . DIRECTORY_SEPARATOR . getenv('theme');
if (!empty(getenv('theme_cache')) && getenv('theme_cache') == 'true') { if (!empty(getenv(EnvConstants::THEME_CACHE) && getenv(EnvConstants::THEME_CACHE) == 'true')) {
$themeCacheDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'cache'; $themeCacheDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'cache';
} else { } else {
$themeCacheDir = false; $themeCacheDir = false;
@ -121,7 +121,7 @@ $container['view'] = function ($container) use ($app) {
// translation // translation
$view->addExtension(new \Symfony\Bridge\Twig\Extension\TranslationExtension($container['translator'])); $view->addExtension(new \Symfony\Bridge\Twig\Extension\TranslationExtension($container['translator']));
$view->getEnvironment()->getExtension('Twig_Extension_Core')->setDateFormat(getenv('site_date_format')); $view->getEnvironment()->getExtension('Twig_Extension_Core')->setDateFormat(getenv(EnvConstants::SITE_DATE_FORMAT));
// env // env
$view->getEnvironment()->addFunction(new Twig_SimpleFunction('getenv', function($value) { $view->getEnvironment()->addFunction(new Twig_SimpleFunction('getenv', function($value) {

8981
public/theme/bootstrap4/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,57 @@
html {
position: relative;
min-height: 100%;
}
body {
padding-top: 5rem;
margin-bottom: 60px; /* Margin bottom by footer height */
}
@media (min-width: 992px) {
body {
padding-top: 56px;
}
}
img {
display: block;
max-width: 100%;
height: auto;
}
.mainContainer {
margin-top: 1rem;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
height: 60px;
line-height: 60px;
background-color: #f5f5f5;
}
.footer > .container {
padding-right: 15px;
padding-left: 15px;
}
blockquote {
border-left: 10px solid #ccc;
margin: 1.5em 10px;
padding: 0.5em 10px;
quotes: "\201C""\201D""\2018""\2019";
}
blockquote:before {
color: #ccc;
content: open-quote;
font-size: 4em;
line-height: 0.1em;
margin-right: 0.25em;
vertical-align: -0.4em;
}
blockquote p {
display: inline;
}

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
.blocker{position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:100%;overflow:auto;z-index:1;padding:20px;box-sizing:border-box;background-color:#000;background-color:rgba(0,0,0,0.75);text-align:center}.blocker:before{content:"";display:inline-block;height:100%;vertical-align:middle;margin-right:-0.05em}.blocker.behind{background-color:transparent}.modal{display:none;vertical-align:middle;position:relative;z-index:2;max-width:500px;box-sizing:border-box;width:90%;background:#fff;padding:15px 30px;-webkit-border-radius:8px;-moz-border-radius:8px;-o-border-radius:8px;-ms-border-radius:8px;border-radius:8px;-webkit-box-shadow:0 0 10px #000;-moz-box-shadow:0 0 10px #000;-o-box-shadow:0 0 10px #000;-ms-box-shadow:0 0 10px #000;box-shadow:0 0 10px #000;text-align:left}.modal a.close-modal{position:absolute;top:-12.5px;right:-12.5px;display:block;width:30px;height:30px;text-indent:-9999px;background-size:contain;background-repeat:no-repeat;background-position:center center;background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAAAXNSR0IArs4c6QAAA3hJREFUaAXlm8+K00Acx7MiCIJH/yw+gA9g25O49SL4AO3Bp1jw5NvktC+wF88qevK4BU97EmzxUBCEolK/n5gp3W6TTJPfpNPNF37MNsl85/vN/DaTmU6PknC4K+pniqeKJ3k8UnkvDxXJzzy+q/yaxxeVHxW/FNHjgRSeKt4rFoplzaAuHHDBGR2eS9G54reirsmienDCTRt7xwsp+KAoEmt9nLaGitZxrBbPFNaGfPloGw2t4JVamSt8xYW6Dg1oCYo3Yv+rCGViV160oMkcd8SYKnYV1Nb1aEOjCe6L5ZOiLfF120EjWhuBu3YIZt1NQmujnk5F4MgOpURzLfAwOBSTmzp3fpDxuI/pabxpqOoz2r2HLAb0GMbZKlNV5/Hg9XJypguryA7lPF5KMdTZQzHjqxNPhWhzIuAruOl1eNqKEx1tSh5rfbxdw7mOxCq4qS68ZTjKS1YVvilu559vWvFHhh4rZrdyZ69Vmpgdj8fJbDZLJpNJ0uv1cnr/gjrUhQMuI+ANjyuwftQ0bbL6Erp0mM/ny8Fg4M3LtdRxgMtKl3jwmIHVxYXChFy94/Rmpa/pTbNUhstKV+4Rr8lLQ9KlUvJKLyG8yvQ2s9SBy1Jb7jV5a0yapfF6apaZLjLLcWtd4sNrmJUMHyM+1xibTjH82Zh01TNlhsrOhdKTe00uAzZQmN6+KW+sDa/JD2PSVQ873m29yf+1Q9VDzfEYlHi1G5LKBBWZbtEsHbFwb1oYDwr1ZiF/2bnCSg1OBE/pfr9/bWx26UxJL3ONPISOLKUvQza0LZUxSKyjpdTGa/vDEr25rddbMM0Q3O6Lx3rqFvU+x6UrRKQY7tyrZecmD9FODy8uLizTmilwNj0kraNcAJhOp5aGVwsAGD5VmJBrWWbJSgWT9zrzWepQF47RaGSiKfeGx6Szi3gzmX/HHbihwBser4B9UJYpFBNX4R6vTn3VQnez0SymnrHQMsRYGTr1dSk34ljRqS/EMd2pLQ8YBp3a1PLfcqCpo8gtHkZFHKkTX6fs3MY0blKnth66rKCnU0VRGu37ONrQaA4eZDFtWAu2fXj9zjFkxTBOo8F7t926gTp/83Kyzzcy2kZD6xiqxTYnHLRFm3vHiRSwNSjkz3hoIzo8lCKWUlg/YtGs7tObunDAZfpDLbfEI15zsEIY3U/x/gHHc/G1zltnAgAAAABJRU5ErkJggg==')}.modal-spinner{display:none;position:fixed;top:50%;left:50%;transform:translateY(-50%) translateX(-50%);padding:12px 16px;border-radius:5px;background-color:#111;height:20px}.modal-spinner>div{border-radius:100px;background-color:#fff;height:20px;width:2px;margin:0 1px;display:inline-block;-webkit-animation:sk-stretchdelay 1.2s infinite ease-in-out;animation:sk-stretchdelay 1.2s infinite ease-in-out}.modal-spinner .rect2{-webkit-animation-delay:-1.1s;animation-delay:-1.1s}.modal-spinner .rect3{-webkit-animation-delay:-1.0s;animation-delay:-1.0s}.modal-spinner .rect4{-webkit-animation-delay:-0.9s;animation-delay:-0.9s}@-webkit-keyframes sk-stretchdelay{0%,40%,100%{-webkit-transform:scaleY(0.5)}20%{-webkit-transform:scaleY(1.0)}}@keyframes sk-stretchdelay{0%,40%,100%{transform:scaleY(0.5);-webkit-transform:scaleY(0.5)}20%{transform:scaleY(1.0);-webkit-transform:scaleY(1.0)}}

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3927
public/theme/bootstrap4/js/bootstrap.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

10364
public/theme/bootstrap4/js/jquery.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,5 @@
/*
A simple jQuery modal (http://github.com/kylefox/jquery-modal)
Version 0.9.1
*/
!function(o){"object"==typeof module&&"object"==typeof module.exports?o(require("jquery"),window,document):o(jQuery,window,document)}(function(o,t,i,e){var s=[],l=function(){return s.length?s[s.length-1]:null},n=function(){var o,t=!1;for(o=s.length-1;o>=0;o--)s[o].$blocker&&(s[o].$blocker.toggleClass("current",!t).toggleClass("behind",t),t=!0)};o.modal=function(t,i){var e,n;if(this.$body=o("body"),this.options=o.extend({},o.modal.defaults,i),this.options.doFade=!isNaN(parseInt(this.options.fadeDuration,10)),this.$blocker=null,this.options.closeExisting)for(;o.modal.isActive();)o.modal.close();if(s.push(this),t.is("a"))if(n=t.attr("href"),this.anchor=t,/^#/.test(n)){if(this.$elm=o(n),1!==this.$elm.length)return null;this.$body.append(this.$elm),this.open()}else this.$elm=o("<div>"),this.$body.append(this.$elm),e=function(o,t){t.elm.remove()},this.showSpinner(),t.trigger(o.modal.AJAX_SEND),o.get(n).done(function(i){if(o.modal.isActive()){t.trigger(o.modal.AJAX_SUCCESS);var s=l();s.$elm.empty().append(i).on(o.modal.CLOSE,e),s.hideSpinner(),s.open(),t.trigger(o.modal.AJAX_COMPLETE)}}).fail(function(){t.trigger(o.modal.AJAX_FAIL);var i=l();i.hideSpinner(),s.pop(),t.trigger(o.modal.AJAX_COMPLETE)});else this.$elm=t,this.anchor=t,this.$body.append(this.$elm),this.open()},o.modal.prototype={constructor:o.modal,open:function(){var t=this;this.block(),this.anchor.blur(),this.options.doFade?setTimeout(function(){t.show()},this.options.fadeDuration*this.options.fadeDelay):this.show(),o(i).off("keydown.modal").on("keydown.modal",function(o){var t=l();27===o.which&&t.options.escapeClose&&t.close()}),this.options.clickClose&&this.$blocker.click(function(t){t.target===this&&o.modal.close()})},close:function(){s.pop(),this.unblock(),this.hide(),o.modal.isActive()||o(i).off("keydown.modal")},block:function(){this.$elm.trigger(o.modal.BEFORE_BLOCK,[this._ctx()]),this.$body.css("overflow","hidden"),this.$blocker=o('<div class="'+this.options.blockerClass+' blocker current"></div>').appendTo(this.$body),n(),this.options.doFade&&this.$blocker.css("opacity",0).animate({opacity:1},this.options.fadeDuration),this.$elm.trigger(o.modal.BLOCK,[this._ctx()])},unblock:function(t){!t&&this.options.doFade?this.$blocker.fadeOut(this.options.fadeDuration,this.unblock.bind(this,!0)):(this.$blocker.children().appendTo(this.$body),this.$blocker.remove(),this.$blocker=null,n(),o.modal.isActive()||this.$body.css("overflow",""))},show:function(){this.$elm.trigger(o.modal.BEFORE_OPEN,[this._ctx()]),this.options.showClose&&(this.closeButton=o('<a href="#close-modal" rel="modal:close" class="close-modal '+this.options.closeClass+'">'+this.options.closeText+"</a>"),this.$elm.append(this.closeButton)),this.$elm.addClass(this.options.modalClass).appendTo(this.$blocker),this.options.doFade?this.$elm.css({opacity:0,display:"inline-block"}).animate({opacity:1},this.options.fadeDuration):this.$elm.css("display","inline-block"),this.$elm.trigger(o.modal.OPEN,[this._ctx()])},hide:function(){this.$elm.trigger(o.modal.BEFORE_CLOSE,[this._ctx()]),this.closeButton&&this.closeButton.remove();var t=this;this.options.doFade?this.$elm.fadeOut(this.options.fadeDuration,function(){t.$elm.trigger(o.modal.AFTER_CLOSE,[t._ctx()])}):this.$elm.hide(0,function(){t.$elm.trigger(o.modal.AFTER_CLOSE,[t._ctx()])}),this.$elm.trigger(o.modal.CLOSE,[this._ctx()])},showSpinner:function(){this.options.showSpinner&&(this.spinner=this.spinner||o('<div class="'+this.options.modalClass+'-spinner"></div>').append(this.options.spinnerHtml),this.$body.append(this.spinner),this.spinner.show())},hideSpinner:function(){this.spinner&&this.spinner.remove()},_ctx:function(){return{elm:this.$elm,$elm:this.$elm,$blocker:this.$blocker,options:this.options}}},o.modal.close=function(t){if(o.modal.isActive()){t&&t.preventDefault();var i=l();return i.close(),i.$elm}},o.modal.isActive=function(){return s.length>0},o.modal.getCurrent=l,o.modal.defaults={closeExisting:!0,escapeClose:!0,clickClose:!0,closeText:"Close",closeClass:"",modalClass:"modal",blockerClass:"jquery-modal",spinnerHtml:'<div class="rect1"></div><div class="rect2"></div><div class="rect3"></div><div class="rect4"></div>',showSpinner:!0,showClose:!0,fadeDuration:null,fadeDelay:1},o.modal.BEFORE_BLOCK="modal:before-block",o.modal.BLOCK="modal:block",o.modal.BEFORE_OPEN="modal:before-open",o.modal.OPEN="modal:open",o.modal.BEFORE_CLOSE="modal:before-close",o.modal.CLOSE="modal:close",o.modal.AFTER_CLOSE="modal:after-close",o.modal.AJAX_SEND="modal:ajax:send",o.modal.AJAX_SUCCESS="modal:ajax:success",o.modal.AJAX_FAIL="modal:ajax:fail",o.modal.AJAX_COMPLETE="modal:ajax:complete",o.fn.modal=function(t){return 1===this.length&&new o.modal(this,t),this},o(i).on("click.modal",'a[rel~="modal:close"]',o.modal.close),o(i).on("click.modal",'a[rel~="modal:open"]',function(t){t.preventDefault(),o(this).modal()})});

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,23 +0,0 @@
/* fallback */
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url('../fonts/MaterialIcons.woff2') format('woff2');
}
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
}

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,400 +0,0 @@
/* START: for rendering within block you should keep the following */
img {
max-width: 100%;
height: auto;
}
/* END: for rendering within block you should keep the following */
/* Sticky footer styles */
html {
position: relative;
min-height: 100%;
}
body {
/* Margin bottom by footer height */
margin-bottom: 60px;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 10px;
line-height: 60px; /* Vertically center the text there */
background-color: #f5f5f5;
}
* {
box-sizing: border-box;
}
.header-panel {
background-color: #009587;
height: 90px;
position: relative;
z-index: 3;
}
.header-panel div {
position: relative;
height: 100%;
}
.header-panel h1 {
color: #FFF;
/*font-size: 20px;*/
/*font-weight: 400;*/
position: absolute;
bottom: 10px;
padding-left: 35px;
}
.header-panel h1 a, a:active, a:visited, a:focus, a:hover {
color: #FFF;
text-decoration: none;
}
.menu {
overflow: auto;
padding: 0;
}
.menu a, a:hover, a:focus {
color: #009688;
}
a:active, a:visited, a:focus, a:hover {
color: #009688;
}
.menu, .menu * {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.menu ul {
padding: 0;
margin: 7px 0;
}
.menu ul li {
list-style: none;
padding: 20px 0 20px 20px;
font-size: 15px;
font-weight: normal;
cursor: pointer;
}
.menu ul li.active {
background-color: #dedede;
position: relative;
}
.menu ul li a {
color: rgb(51, 51, 51);
text-decoration: none;
}
.pages {
position: absolute;
top: 0;
right: 0;
z-index: 4;
padding: 0;
overflow: auto;
overflow-x: hidden;
}
.pages > div {
padding: 0 5px;
padding-top: 64px;
}
.pages .header {
color: rgb(82, 101, 162);
/*font-size: 24px;*/
/*font-weight: normal;*/
/*margin-top: 5px;*/
/*margin-bottom: 60px;*/
/*letter-spacing: 1.20000004768372px;*/
}
.page {
transform: translateY(1080px);
transition: transform 0 linear;
display: none;
opacity: 0;
font-size: 16px;
}
.page.active {
transform: translateY(0px);
transition: all 0.3s ease-out;
display: block;
opacity: 1;
}
.opensource {
color: rgba(0, 0, 0, 0.62);
position: fixed;
margin-top: 50px;
margin-left: 50px;
z-index: 100;
}
#source-modal h4 {
color: black;
}
#paypal .btn {
padding: 5px 30px 6px 30px;
}
#paypal input {
background: transparent;
border: 0;
}
.cbwrapper div {
display: none;
}
.cbwrapper div:nth-child(2) {
display: block;
}
#carbonads, #fakecb {
border: 1px solid #d5d5d5;
font-size: 11px;
line-height: 15px;
overflow: hidden;
width: 340px;
padding: 20px;
margin: auto;
height: 142px;
border-radius: 2px;
}
#carbonads .carbon-img {
float: left;
display: block;
}
#carbonads .carbon-text, #carbonads .carbon-poweredby {
float: left;
width: 150px;
padding: 0 10px 10px 10px;
}
#carbonads .carbon-text:hover, #carbonads .carbon-poweredby:hover {
text-decoration: none;
}
#carbonads .carbon-poweredby {
color: #9D9D9D;
}
/*#checkbox .sample1 label {*/
/*font-weight: bold;*/
/*}*/
/*#checkbox .hint {*/
/*padding-left: 45px;*/
/*padding-top: 20px;*/
/*font-weight: 400;*/
/*}*/
/*#checkbox .sample1 {*/
/*padding-bottom: 20px;*/
/*}*/
/*#checkbox h2 {*/
/*font-size: 18.7199993133545px;*/
/*font-weight: bold;*/
/*margin-bottom: 30px;*/
/*}*/
/*#checkbox .sample2 {*/
/*width: 300px;*/
/*clear: both;*/
/*font-weight: 400;*/
/*}*/
/*#checkbox .sample2 {*/
/*padding: 10px 0;*/
/*}*/
/*#checkbox .sample2 .text {*/
/*display: inline-block;*/
/*}*/
/*#checkbox .sample2 .checkbox {*/
/*float: right;*/
/*margin: 0;*/
/*}*/
/*#progress-bar h2 {*/
/*font-size: 18.7199993133545px;*/
/*font-weight: bold;*/
/*margin-bottom: 30px;*/
/*}*/
/*#dialog h2 {*/
/*padding: 14px;*/
/*margin: 0;*/
/*font-size: 16px;*/
/*font-weight: 400;*/
/*}*/
/*#shadow h2 {*/
/*padding: 14px;*/
/*margin: 0;*/
/*font-size: 16px;*/
/*font-weight: 400;*/
/*}*/
#shadow .sample {
width: 100px;
height: 100px;
margin: 16px;
padding: 16px;
display: inline-block;
}
#shadow-sample2 {
display: inline-block;
width: 100px;
height: 100px;
margin: 16px;
padding: 16px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
#shadow-sample3 {
display: inline-block;
width: 100px;
height: 100px;
margin: 16px;
padding: 16px;
border-radius: 100px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
/*#radio-button h2 {*/
/*font-size: 18.7199993133545px;*/
/*font-weight: bold;*/
/*margin-bottom: 30px;*/
/*margin-top: 50px;*/
/*}*/
/*#radio-button .radio {*/
/*margin: 20px 10px;*/
/*}*/
/*#input h2 {*/
/*padding: 14px;*/
/*font-size: 16px;*/
/*font-weight: 400;*/
/*}*/
#input .inputs {
width: 80%;
}
/*#input .form-group {*/
/*margin: 30px 0;*/
/*}*/
/*#slider .sample1, #slider .sample2 {*/
/*padding: 20px 0;*/
/*background-color: #f0f0f0;*/
/*margin-bottom: 20px;*/
/*}*/
#slider .sample2 {
height: 150px;
}
/*#slider .sample2 .slider {*/
/*margin: 0 40px;*/
/*}*/
/*#slider h2 {*/
/*padding: 14px;*/
/*margin: 0;*/
/*font-size: 16px;*/
/*font-weight: 400;*/
/*}*/
/*#slider .slider {*/
/*margin: 15px;*/
/*}*/
/*#button h2 {*/
/*padding: 14px;*/
/*margin: 0;*/
/*font-size: 16px;*/
/*font-weight: 400;*/
/*}*/
/*#floating-action-button .btn {*/
/*margin: 20px;*/
/*}*/
/*#floating-action-button h2 {*/
/*padding: 14px;*/
/*margin: 0;*/
/*font-size: 16px;*/
/*font-weight: 400;*/
/*}*/
/*#dropdown h2 {*/
/*padding: 14px;*/
/*margin: 0;*/
/*font-size: 16px;*/
/*font-weight: 400;*/
/*}*/
/*#dropdown .dropdown {*/
/*font-size: 30px;*/
/*padding: 20px;*/
/*}*/
/*#dropdown-menu h2 {*/
/*padding: 14px;*/
/*margin: 0;*/
/*font-size: 16px;*/
/*font-weight: 400;*/
/*}*/
/*#dropdown-menu .sample {*/
/*width: 200px;*/
/*}*/
/*#dropdown-menu .form-group {*/
/*margin: 30px 0;*/
/*}*/
/*#toggle-button h2 {*/
/*font-size: 18.7199993133545px;*/
/*font-weight: bold;*/
/*margin-bottom: 30px;*/
/*margin-top: 50px;*/
/*}*/
/*#toggle-button .togglebutton label {*/
/*margin: 20px 10px;*/
/*width: 200px;*/
/*}*/
/*#toggle-button .togglebutton .toggle {*/
/*float: right;*/
/*}*/

View file

@ -1,124 +0,0 @@
.dropdownjs {
position: relative;
}
.dropdownjs * {
box-sizing: border-box;
}
.dropdownjs > input {
width: 100%;
padding-right: 30px;
text-overflow: ellipsis;
}
.dropdownjs > input.focus ~ ul {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
.dropdownjs > ul {
position: absolute;
padding: 0;
margin: 0;
min-width: 200px;
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
z-index: 10000;
}
.dropdownjs > ul[placement=top-left] {
-webkit-transform-origin: bottom left;
-ms-transform-origin: bottom left;
transform-origin: bottom left;
bottom: 0;
left: 0;
}
.dropdownjs > ul[placement=bottom-left] {
-webkit-transform-origin: top left;
-ms-transform-origin: top left;
transform-origin: top left;
top: 0;
left: 0;
}
.dropdownjs > ul > li {
list-style: none;
padding: 10px 20px;
}
.dropdownjs > ul > li.dropdownjs-add {
padding: 0;
}
.dropdownjs > ul > li.dropdownjs-add > input {
border: 0;
padding: 10px 20px;
width: 100%;
}
/* Theme */
.dropdownjs > input[readonly] {
cursor: pointer;
}
select[data-dropdownjs][disabled] + .dropdownjs > input[readonly] {
cursor: default;
}
.dropdownjs > ul {
background: #FFF;
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 6px rgba(0, 0, 0, 0.12);
-webkit-transition: -webkit-transform 0.2s ease-out;
transition: transform 0.2s ease-out;
padding: 10px;
overflow: auto;
max-width: 500px;
}
.dropdownjs > ul > li {
cursor: pointer;
word-wrap: break-word;
}
.dropdownjs > ul > li.selected,
.dropdownjs > ul > li:active {
background-color: #eaeaea;
}
.dropdownjs > ul > li:focus {
outline: 0;
outline: 1px solid #d4d4d4;
}
.dropdownjs > ul > li > .close:before {
content: "\00d7";
display: block;
position: absolute;
right: 15px;
float: right;
font-size: 21px;
font-weight: 700;
line-height: 1;
color: #000;
text-shadow: 0 1px 0 #fff;
opacity: .6;
}
.dropdownjs > ul > li:hover > .close:hover:before {
opacity: .9;
}
.rtl .dropdownjs > input{
padding-right: 0;
padding-left: 30px;
}
.rtl .dropdownjs > ul[placement=top-right] {
-webkit-transform-origin: bottom right;
-ms-transform-origin: bottom right;
transform-origin: bottom right;
bottom: 0;
left: auto;
right: 0;
}
.rtl .dropdownjs > ul[placement=bottom-right] {
-webkit-transform-origin: top right;
-ms-transform-origin: top right;
transform-origin: top right;
top: 0;
left: auto;
right: 0;
}
.rtl .dropdownjs > ul > li > .close:before {
right: auto;
left: 15px;
float: left;
}

View file

@ -1,47 +0,0 @@
.withripple {
position: relative;
}
.ripple-container {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
overflow: hidden;
border-radius: inherit;
pointer-events: none;
}
.ripple {
position: absolute;
width: 20px;
height: 20px;
margin-left: -10px;
margin-top: -10px;
border-radius: 100%;
background-color: #000;
background-color: rgba(0, 0, 0, 0.05);
-webkit-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1);
-webkit-transform-origin: 50%;
-ms-transform-origin: 50%;
-o-transform-origin: 50%;
transform-origin: 50%;
opacity: 0;
pointer-events: none;
}
.ripple.ripple-on {
-webkit-transition: opacity 0.15s ease-in 0s, -webkit-transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
-o-transition: opacity 0.15s ease-in 0s, -o-transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;
opacity: 0.1;
}
.ripple.ripple-out {
-webkit-transition: opacity 0.1s linear 0s !important;
-o-transition: opacity 0.1s linear 0s !important;
transition: opacity 0.1s linear 0s !important;
opacity: 0;
}
/*# sourceMappingURL=ripples.css.map */

View file

@ -1 +0,0 @@
{"version":3,"sources":["/less/ripples.less","ripples.css"],"names":[],"mappings":"AAAA;EACI,mBAAA;CCCH;ADCD;EACI,mBAAA;EACA,OAAA;EACA,QAAA;EACA,WAAA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;EACA,uBAAA;EACA,qBAAA;CCCH;ADCD;EACI,mBAAA;EACA,YAAA;EACA,aAAA;EACA,mBAAA;EACA,kBAAA;EACA,oBAAA;EACA,uBAAA;EACA,sCAAA;EACA,4BAAA;MAAA,wBAAA;OAAA,uBAAA;UAAA,oBAAA;EACA,8BAAA;MAAA,0BAAA;OAAA,yBAAA;UAAA,sBAAA;EACA,WAAA;EACA,qBAAA;CCCH;ADCD;EACI,uGAAA;OAAA,6FAAA;UAAA,uFAAA;EACA,aAAA;CCCH;ADCD;EACI,sDAAA;OAAA,iDAAA;UAAA,8CAAA;EACA,WAAA;CCCH","file":"ripples.css","sourcesContent":[".withripple {\n position: relative;\n}\n.ripple-container {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1;\n width: 100%;\n height: 100%;\n overflow: hidden;\n border-radius: inherit;\n pointer-events: none;\n}\n.ripple {\n position: absolute;\n width: 20px;\n height: 20px;\n margin-left: -10px;\n margin-top: -10px;\n border-radius: 100%;\n background-color: #000; // fallback color\n background-color: rgba(0,0,0,0.05);\n transform: scale(1);\n transform-origin: 50%;\n opacity: 0;\n pointer-events: none;\n}\n.ripple.ripple-on {\n transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;\n opacity: 0.1;\n}\n.ripple.ripple-out {\n transition: opacity 0.1s linear 0s !important;\n opacity: 0;\n}\n",".withripple {\n position: relative;\n}\n.ripple-container {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1;\n width: 100%;\n height: 100%;\n overflow: hidden;\n border-radius: inherit;\n pointer-events: none;\n}\n.ripple {\n position: absolute;\n width: 20px;\n height: 20px;\n margin-left: -10px;\n margin-top: -10px;\n border-radius: 100%;\n background-color: #000;\n background-color: rgba(0, 0, 0, 0.05);\n transform: scale(1);\n transform-origin: 50%;\n opacity: 0;\n pointer-events: none;\n}\n.ripple.ripple-on {\n transition: opacity 0.15s ease-in 0s, transform 0.5s cubic-bezier(0.4, 0, 0.2, 1) 0.1s;\n opacity: 0.1;\n}\n.ripple.ripple-out {\n transition: opacity 0.1s linear 0s !important;\n opacity: 0;\n}\n/*# sourceMappingURL=ripples.css.map */"]}

View file

@ -1,2 +0,0 @@
.withripple{position:relative}.ripple-container{position:absolute;top:0;left:0;z-index:1;width:100%;height:100%;overflow:hidden;border-radius:inherit;pointer-events:none}.ripple{position:absolute;width:20px;height:20px;margin-left:-10px;margin-top:-10px;border-radius:100%;background-color:#000;background-color:rgba(0,0,0,.05);-webkit-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1);-webkit-transform-origin:50%;-ms-transform-origin:50%;-o-transform-origin:50%;transform-origin:50%;opacity:0;pointer-events:none}.ripple.ripple-on{-webkit-transition:opacity .15s ease-in 0s,-webkit-transform .5s cubic-bezier(.4,0,.2,1) .1s;-o-transition:opacity .15s ease-in 0s,-o-transform .5s cubic-bezier(.4,0,.2,1) .1s;transition:opacity .15s ease-in 0s,transform .5s cubic-bezier(.4,0,.2,1) .1s;opacity:.1}.ripple.ripple-out{-webkit-transition:opacity .1s linear 0s!important;-o-transition:opacity .1s linear 0s!important;transition:opacity .1s linear 0s!important;opacity:0}
/*# sourceMappingURL=ripples.min.css.map */

View file

@ -1 +0,0 @@
{"version":3,"sources":["less/ripples.less"],"names":[],"mappings":"AAAA,YACI,SAAA,SAEJ,kBACI,SAAA,SACA,IAAA,EACA,KAAA,EACA,QAAA,EACA,MAAA,KACA,OAAA,KACA,SAAA,OACA,cAAA,QACA,eAAA,KAEJ,QACI,SAAA,SACA,MAAA,KACA,OAAA,KACA,YAAA,MACA,WAAA,MACA,cAAA,KACA,iBAAA,KACA,iBAAA,gBACA,kBAAA,SAAA,cAAA,SAAA,aAAA,SAAA,UAAA,SACA,yBAAA,IAAA,qBAAA,IAAA,oBAAA,IAAA,iBAAA,IACA,QAAA,EACA,eAAA,KAEJ,kBACI,mBAAA,QAAA,KAAA,QAAA,GAAA,kBAAA,IAAA,wBAAA,IAAA,cAAA,QAAA,KAAA,QAAA,GAAA,aAAA,IAAA,wBAAA,IAAA,WAAA,QAAA,KAAA,QAAA,GAAA,UAAA,IAAA,wBAAA,IACA,QAAA,GAEJ,mBACI,mBAAA,QAAA,IAAA,OAAA,aAAA,cAAA,QAAA,IAAA,OAAA,aAAA,WAAA,QAAA,IAAA,OAAA,aACA,QAAA"}

View file

@ -1,224 +0,0 @@
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/roboto/0eC6fl06luXEYWpBSJvXCBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/roboto/Fl4y0QdOxyyTHEGMXX8kcRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/roboto/-L14Jk06m6pUHB-5mXQQnRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/roboto/I3S1wsgSg9YCurV6PUkTORJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/roboto/NYDWBdD4gIq26G5XYbHsFBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/roboto/Pru33qjShpZSmG3z6VYwnRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url(../fonts/roboto/Hgo13k-tfSpn0qi1SFdUfVtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/ek4gzZ-GeXAPcSbHtCeQI_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/mErvLBYg_cXG3rLvUsKT_fesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/-2n2p-_Y08sg57CNWQfKNvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/u0TOpm082MNkS5K0Q4rhqvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/NdF9MtnOpLzo-noMoG0miPesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/Fcx7Wwv8OzT71A3E1XOAjvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/CWB0XYA8bzo0kSThX0UTuA.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/roboto/ZLqKeelYbATG60EpZBSDyxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/roboto/oHi30kwQWvpCWqAhzHcCSBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/roboto/rGvHdJnr2l75qb0YND9NyBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/roboto/mx9Uck6uB63VIKFYnEMXrRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/roboto/mbmhprMH69Zi6eEPBYVFhRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/roboto/oOeFwZNlrTefzLYmlVV1UBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url(../fonts/roboto/RxZJdnzeo3R5zSexge8UUVtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
}
/* cyrillic-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/roboto/77FXFjRbGzN4aCrSFhlh3hJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/roboto/isZ-wbCXNKAbnjo6_TwHThJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/roboto/UX6i4JxQDm3fVTc1CPuwqhJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/roboto/jSN2CGVDbcVyCnfJfjSdfBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/roboto/PwZc-YbIL414wB9rB1IAPRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0102-0103, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/roboto/97uahxiqZRoncBaCEI3aWxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url(../fonts/roboto/d-6IYplOFocCacKzxwXSOFtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215;
}

View file

@ -1,90 +0,0 @@
/* line 2, ../sass/_sortable.sass */
table[data-sortable] {
border-collapse: collapse;
border-spacing: 0;
}
/* line 6, ../sass/_sortable.sass */
table[data-sortable] th {
vertical-align: bottom;
font-weight: bold;
}
/* line 10, ../sass/_sortable.sass */
table[data-sortable] th, table[data-sortable] td {
text-align: left;
padding: 10px;
}
/* line 14, ../sass/_sortable.sass */
table[data-sortable] th:not([data-sortable="false"]) {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-touch-callout: none;
cursor: pointer;
}
/* line 26, ../sass/_sortable.sass */
table[data-sortable] th:after {
content: "";
visibility: hidden;
display: inline-block;
vertical-align: inherit;
height: 0;
width: 0;
border-width: 5px;
border-style: solid;
border-color: transparent;
margin-right: 1px;
margin-left: 10px;
float: right;
}
/* line 40, ../sass/_sortable.sass */
table[data-sortable] th[data-sorted="true"]:after {
visibility: visible;
}
/* line 43, ../sass/_sortable.sass */
table[data-sortable] th[data-sorted-direction="descending"]:after {
border-top-color: inherit;
margin-top: 8px;
}
/* line 47, ../sass/_sortable.sass */
table[data-sortable] th[data-sorted-direction="ascending"]:after {
border-bottom-color: inherit;
margin-top: 3px;
}
/* line 5, ../sass/sortable-theme-bootstrap.sass */
table[data-sortable].sortable-theme-bootstrap {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 20px;
color: #333333;
background: white;
}
/* line 12, ../sass/sortable-theme-bootstrap.sass */
table[data-sortable].sortable-theme-bootstrap thead th {
border-bottom: 2px solid #e0e0e0;
}
/* line 15, ../sass/sortable-theme-bootstrap.sass */
table[data-sortable].sortable-theme-bootstrap tbody td {
border-top: 1px solid #e0e0e0;
}
/* line 18, ../sass/sortable-theme-bootstrap.sass */
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"] {
color: #3a87ad;
background: #d9edf7;
border-bottom-color: #bce8f1;
}
/* line 23, ../sass/sortable-theme-bootstrap.sass */
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="descending"]:after {
border-top-color: #3a87ad;
}
/* line 26, ../sass/sortable-theme-bootstrap.sass */
table[data-sortable].sortable-theme-bootstrap th[data-sorted="true"][data-sorted-direction="ascending"]:after {
border-bottom-color: #3a87ad;
}
/* line 31, ../sass/sortable-theme-bootstrap.sass */
table[data-sortable].sortable-theme-bootstrap.sortable-theme-bootstrap-striped tbody > tr:nth-child(odd) > td {
background-color: #f9f9f9;
}

File diff suppressed because one or more lines are too long

View file

@ -1,2 +0,0 @@
$.material.init();
$("#dropdown-menu select").dropdown();

View file

@ -1,431 +0,0 @@
/* globals jQuery, window, document */
(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS
module.exports = factory(require('jquery'));
} else {
// Browser globals
factory(jQuery);
}
}(function($) {
var methods = {
options : {
"optionClass": "",
"dropdownClass": "",
"autoinit": false,
"callback": false,
"onSelected": false,
"destroy": function(element) {
this.destroy(element);
},
"dynamicOptLabel": "Add a new option..."
},
init: function(options) {
// Apply user options if user has defined some
if (options) {
options = $.extend(methods.options, options);
} else {
options = methods.options;
}
function initElement($select) {
// Don't do anything if this is not a select or if this select was already initialized
if ($select.data("dropdownjs") || !$select.is("select")) {
return;
}
// Is it a multi select?
var multi = $select.attr("multiple");
// Does it allow to create new options dynamically?
var dynamicOptions = $select.attr("data-dynamic-opts"),
$dynamicInput = $();
// Create the dropdown wrapper
var $dropdown = $("<div></div>");
$dropdown.addClass("dropdownjs").addClass(options.dropdownClass);
$dropdown.data("select", $select);
// Create the fake input used as "select" element and cache it as $input
var $input = $("<input type=text readonly class=fakeinput>");
if ($.material) { $input.data("mdproc", true); }
// Append it to the dropdown wrapper
$dropdown.append($input);
// Create the UL that will be used as dropdown and cache it AS $ul
var $ul = $("<ul></ul>");
$ul.data("select", $select);
// Append it to the dropdown
$dropdown.append($ul);
// Transfer the placeholder attribute
$input.attr("placeholder", $select.attr("placeholder"));
// Loop trough options and transfer them to the dropdown menu
$select.find("option").each(function() {
// Cache $(this)
var $this = $(this);
methods._addOption($ul, $this);
});
// If this select allows dynamic options add the widget
if (dynamicOptions) {
$dynamicInput = $("<li class=dropdownjs-add></li>");
$dynamicInput.append("<input>");
$dynamicInput.find("input").attr("placeholder", options.dynamicOptLabel);
$ul.append($dynamicInput);
}
// Cache the dropdown options
var selectOptions = $dropdown.find("li");
// If is a single select, selected the first one or the last with selected attribute
if (!multi) {
var $selected;
if ($select.find(":selected").length) {
$selected = $select.find(":selected").last();
}
else {
$selected = $select.find("option, li").first();
// $selected = $select.find("option").first();
}
methods._select($dropdown, $selected);
} else {
var selectors = [], val = $select.val()
for (var i in val) {
selectors.push(val[i]);
}
if (selectors.length > 0) {
var $target = $dropdown.find(function() { return $.inArray($(this).data("value"), selectors) !== -1; });
$target.removeClass("selected");
methods._select($dropdown, $target);
}
}
// Transfer the classes of the select to the input dropdown
$input.addClass($select[0].className);
// Hide the old and ugly select
$select.hide().attr("data-dropdownjs", true);
// Bring to life our awesome dropdownjs
$select.after($dropdown);
// Call the callback
if (options.callback) {
options.callback($dropdown);
}
//---------------------------------------//
// DROPDOWN EVENTS //
//---------------------------------------//
// On click, set the clicked one as selected
$ul.on("click", "li:not(.dropdownjs-add)", function(e) {
methods._select($dropdown, $(this));
// trigger change event, if declared on the original selector
$select.change();
});
$ul.on("keydown", "li:not(.dropdownjs-add)", function(e) {
if (e.which === 27) {
$(".dropdownjs > ul > li").attr("tabindex", -1);
return $input.removeClass("focus").blur();
}
if (e.which === 32 && !$(e.target).is("input")) {
methods._select($dropdown, $(this));
return false;
}
});
$ul.on("focus", "li:not(.dropdownjs-add)", function() {
if ($select.is(":disabled")) {
return;
}
$input.addClass("focus");
});
// Add new options when the widget is used
if (dynamicOptions && dynamicOptions.length) {
$dynamicInput.on("keydown", function(e) {
if(e.which !== 13) return;
var $option = $("<option>"),
val = $dynamicInput.find("input").val();
$dynamicInput.find("input").val("");
$option.attr("value", val);
$option.text(val);
$select.append($option);
});
}
// Listen for new added options and update dropdown if needed
$select.on("DOMNodeInserted", function(e) {
var $this = $(e.target);
if (!$this.val().length) return;
methods._addOption($ul, $this);
$ul.find("li").not(".dropdownjs-add").attr("tabindex", 0);
});
$select.on("DOMNodeRemoved", function(e) {
var deletedValue = $(e.target).attr('value');
$ul.find("li").filter(function() { return $(this).data("value") === deletedValue; }).remove();
var $selected;
setTimeout(function () {
if ($select.find(":selected").length) {
$selected = $select.find(":selected").last();
}
else {
$selected = $select.find("option, li").first();
}
methods._select($dropdown, $selected);
}, 100);
});
// Update dropdown when using val, need to use .val("value").trigger("change");
$select.on("change", function(e) {
var $this = $(e.target);
if (!multi) {
var $selected;
if ($select.find(":selected").length) {
$selected = $select.find(":selected").last();
}
else {
$selected = $select.find("option, li").first();
}
methods._select($dropdown, $selected);
} else {
var target = $select.find(":selected"),
values = $(this).val();
// Unselect all options
selectOptions.removeClass("selected");
// Select options
target.each(function () {
var selected = selectOptions.filter(function() { return $.inArray($(this).data("value"), values) !== -1; });
selected.addClass("selected");
});
}
});
// Used to make the dropdown menu more dropdown-ish
$input.on("click focus", function(e) {
e.stopPropagation();
if ($select.is(":disabled")) {
return;
}
$(".dropdownjs > ul > li").attr("tabindex", -1);
$(".dropdownjs > input").not($(this)).removeClass("focus").blur();
$(".dropdownjs > ul > li").not(".dropdownjs-add").attr("tabindex", 0);
// Set height of the dropdown
var coords = {
top: $(this).offset().top - $(document).scrollTop(),
left: $(this).offset().left - $(document).scrollLeft(),
bottom: $(window).height() - ($(this).offset().top - $(document).scrollTop()),
right: $(window).width() - ($(this).offset().left - $(document).scrollLeft())
};
var height = coords.bottom;
// Decide if place the dropdown below or above the input
if (height < 200 && coords.top > coords.bottom) {
height = coords.top;
$ul.attr("placement", $("body").hasClass("rtl") ? "top-right" : "top-left");
} else {
$ul.attr("placement", $("body").hasClass("rtl") ? "bottom-right" : "bottom-left");
}
$(this).next("ul").css("max-height", height - 20);
$(this).addClass("focus");
});
// Close every dropdown on click outside
$(document).on("click", function(e) {
// Don't close the multi dropdown if user is clicking inside it
if (multi && $(e.target).parents(".dropdownjs").length) return;
// Don't close the dropdown if user is clicking inside the dynamic-opts widget
if ($(e.target).parents(".dropdownjs-add").length || $(e.target).is(".dropdownjs-add")) return;
// Close opened dropdowns
$(".dropdownjs > ul > li").attr("tabindex", -1);
if ($(e.target).hasClass('disabled')) {
return;
}
$input.removeClass("focus");
});
}
if (options.autoinit) {
$(document).on("DOMNodeInserted", function(e) {
var $this = $(e.target);
if (!$this.is("select")) {
$this = $this.find('select');
}
$this.each(function() {
if ($(this).is(options.autoinit)) {
initElement($(this));
}
});
});
}
// Loop trough elements
$(this).each(function() {
initElement($(this));
});
},
select: function(target) {
var $target = $(this).find(function() { return $(this).data("value") === target; });
methods._select($(this), $target);
},
_select: function($dropdown, $target) {
if ($target.is(".dropdownjs-add")) return;
// Get dropdown's elements
var $select = $dropdown.data("select"),
$input = $dropdown.find("input.fakeinput");
// Is it a multi select?
var multi = $select.attr("multiple");
// Cache the dropdown options
var selectOptions = $dropdown.find("li");
// Behavior for multiple select
if (multi) {
// Toggle option state
$target.toggleClass("selected");
// Toggle selection of the clicked option in native select
$target.each(function(){
var value = $(this).prop("tagName") === "OPTION" ? $(this).val() : $(this).data("value"),
$selected = $select.find("[value=\"" + value + "\"]");
$selected.prop("selected", $(this).hasClass("selected"));
});
// Add or remove the value from the input
var text = [];
selectOptions.each(function() {
if ($(this).hasClass("selected")) {
text.push($(this).text());
}
});
$input.val(text.join(", "));
}
// Behavior for single select
if (!multi) {
if ($target.hasClass("disabled")) {
return;
}
// Unselect options except the one that will be selected
if ($target.is("li")) {
selectOptions.not($target).removeClass("selected");
}
// Select the selected option
$target.addClass("selected");
// Set the value to the input
$input.val($target.text().trim());
var value = $target.prop("tagName") === "OPTION" ? $target.val() : $target.data("value");
// When val is set below on $select, it will fire change event,
// which ends up back here, make sure to not end up in an infinite loop.
// This is done last so text input is initialized on first load when condition is true.
if (value === $select.val()) {
return;
}
// Set the value to the native select
$select.val(value);
}
// This is used only if Material Design for Bootstrap is selected
if ($.material) {
if ($input.val().trim()) {
$select.removeClass("empty");
} else {
$select.addClass("empty");
}
}
// Call the callback
if (this.options.onSelected) {
this.options.onSelected($target.data("value"));
}
},
_addOption: function($ul, $this) {
// Create the option
var $option = $("<li></li>");
// Style the option
$option.addClass(this.options.optionClass);
// If the option has some text then transfer it
if ($this.text()) {
$option.text($this.text());
}
// Otherwise set the empty label and set it as an empty option
else {
$option.html("&nbsp;");
}
// Set the value of the option
$option.data("value", $this.val());
// Will user be able to remove this option?
if ($ul.data("select").attr("data-dynamic-opts")) {
$option.append("<span class=close></span>");
$option.find(".close").on("click", function() {
$option.remove();
$this.remove();
});
}
// Ss it selected?
if ($this.prop("selected")) {
$option.attr("selected", true);
$option.addClass("selected");
}
if ($this.prop("disabled")) {
$option.addClass("disabled");
}
// Append option to our dropdown
if ($ul.find(".dropdownjs-add").length) {
$ul.find(".dropdownjs-add").before($option);
} else {
$ul.append($option);
}
},
destroy: function($e) {
$($e).show().removeAttr('data-dropdownjs').next('.dropdownjs').remove();
}
};
$.fn.dropdown = function(params) {
if( typeof methods[params] == 'function' ) methods[params](this);
if (methods[params]) {
return methods[params].apply(this, Array.prototype.slice.call(arguments,1));
} else if (typeof params === "object" | !params) {
return methods.init.apply(this, arguments);
} else {
$.error("Method " + params + " does not exists on jQuery.dropdown");
}
};
}));

File diff suppressed because one or more lines are too long

View file

@ -1,31 +0,0 @@
/*
$.Link (part of noUiSlider) - WTFPL */
(function(c){function m(a,c,d){if((a[c]||a[d])&&a[c]===a[d])throw Error("(Link) '"+c+"' can't match '"+d+"'.'");}function r(a){void 0===a&&(a={});if("object"!==typeof a)throw Error("(Format) 'format' option must be an object.");var h={};c(u).each(function(c,n){if(void 0===a[n])h[n]=A[c];else if(typeof a[n]===typeof A[c]){if("decimals"===n&&(0>a[n]||7<a[n]))throw Error("(Format) 'format.decimals' option must be between 0 and 7.");h[n]=a[n]}else throw Error("(Format) 'format."+n+"' must be a "+typeof A[c]+
".");});m(h,"mark","thousand");m(h,"prefix","negative");m(h,"prefix","negativeBefore");this.r=h}function k(a,h){"object"!==typeof a&&c.error("(Link) Initialize with an object.");return new k.prototype.p(a.target||function(){},a.method,a.format||{},h)}var u="decimals mark thousand prefix postfix encoder decoder negative negativeBefore to from".split(" "),A=[2,".","","","",function(a){return a},function(a){return a},"-","",function(a){return a},function(a){return a}];r.prototype.a=function(a){return this.r[a]};
r.prototype.L=function(a){function c(a){return a.split("").reverse().join("")}a=this.a("encoder")(a);var d=this.a("decimals"),n="",k="",m="",r="";0===parseFloat(a.toFixed(d))&&(a="0");0>a&&(n=this.a("negative"),k=this.a("negativeBefore"));a=Math.abs(a).toFixed(d).toString();a=a.split(".");this.a("thousand")?(m=c(a[0]).match(/.{1,3}/g),m=c(m.join(c(this.a("thousand"))))):m=a[0];this.a("mark")&&1<a.length&&(r=this.a("mark")+a[1]);return this.a("to")(k+this.a("prefix")+n+m+r+this.a("postfix"))};r.prototype.w=
function(a){function c(a){return a.replace(/[\-\/\\\^$*+?.()|\[\]{}]/g,"\\$&")}var d;if(null===a||void 0===a)return!1;a=this.a("from")(a);a=a.toString();d=a.replace(RegExp("^"+c(this.a("negativeBefore"))),"");a!==d?(a=d,d="-"):d="";a=a.replace(RegExp("^"+c(this.a("prefix"))),"");this.a("negative")&&(d="",a=a.replace(RegExp("^"+c(this.a("negative"))),"-"));a=a.replace(RegExp(c(this.a("postfix"))+"$"),"").replace(RegExp(c(this.a("thousand")),"g"),"").replace(this.a("mark"),".");a=this.a("decoder")(parseFloat(d+
a));return isNaN(a)?!1:a};k.prototype.K=function(a,h){this.method=h||"html";this.j=c(a.replace("-tooltip-","")||"<div/>")[0]};k.prototype.H=function(a){this.method="val";this.j=document.createElement("input");this.j.name=a;this.j.type="hidden"};k.prototype.G=function(a){function h(a,c){return[c?null:a,c?a:null]}var d=this;this.method="val";this.target=a.on("change",function(a){d.B.val(h(c(a.target).val(),d.t),{link:d,set:!0})})};k.prototype.p=function(a,h,d,k){this.g=d;this.update=!k;if("string"===
typeof a&&0===a.indexOf("-tooltip-"))this.K(a,h);else if("string"===typeof a&&0!==a.indexOf("-"))this.H(a);else if("function"===typeof a)this.target=!1,this.method=a;else{if(a instanceof c||c.zepto&&c.zepto.isZ(a)){if(!h){if(a.is("input, select, textarea")){this.G(a);return}h="html"}if("function"===typeof h||"string"===typeof h&&a[h]){this.method=h;this.target=a;return}}throw new RangeError("(Link) Invalid Link.");}};k.prototype.write=function(a,c,d,k){if(!this.update||!1!==k)if(this.u=a,this.F=a=
this.format(a),"function"===typeof this.method)this.method.call(this.target[0]||d[0],a,c,d);else this.target[this.method](a,c,d)};k.prototype.q=function(a){this.g=new r(c.extend({},a,this.g instanceof r?this.g.r:this.g))};k.prototype.J=function(a){this.B=a};k.prototype.I=function(a){this.t=a};k.prototype.format=function(a){return this.g.L(a)};k.prototype.A=function(a){return this.g.w(a)};k.prototype.p.prototype=k.prototype;c.Link=k})(window.jQuery||window.Zepto);/*
$.fn.noUiSlider - WTFPL - refreshless.com/nouislider/ */
(function(c){function m(e){return"number"===typeof e&&!isNaN(e)&&isFinite(e)}function r(e){return c.isArray(e)?e:[e]}function k(e,b){e.addClass(b);setTimeout(function(){e.removeClass(b)},300)}function u(e,b){return 100*b/(e[1]-e[0])}function A(e,b){if(b>=e.d.slice(-1)[0])return 100;for(var a=1,c,f,d;b>=e.d[a];)a++;c=e.d[a-1];f=e.d[a];d=e.c[a-1];c=[c,f];return d+u(c,0>c[0]?b+Math.abs(c[0]):b-c[0])/(100/(e.c[a]-d))}function a(e,b){if(100<=b)return e.d.slice(-1)[0];for(var a=1,c,f,d;b>=e.c[a];)a++;c=
e.d[a-1];f=e.d[a];d=e.c[a-1];c=[c,f];return 100/(e.c[a]-d)*(b-d)*(c[1]-c[0])/100+c[0]}function h(a,b){for(var c=1,g;(a.dir?100-b:b)>=a.c[c];)c++;if(a.m)return g=a.c[c-1],c=a.c[c],b-g>(c-g)/2?c:g;a.h[c-1]?(g=a.h[c-1],c=a.c[c-1]+Math.round((b-a.c[c-1])/g)*g):c=b;return c}function d(a,b){if(!m(b))throw Error("noUiSlider: 'step' is not numeric.");a.h[0]=b}function n(a,b){if("object"!==typeof b||c.isArray(b))throw Error("noUiSlider: 'range' is not an object.");if(void 0===b.min||void 0===b.max)throw Error("noUiSlider: Missing 'min' or 'max' in 'range'.");
c.each(b,function(b,g){var d;"number"===typeof g&&(g=[g]);if(!c.isArray(g))throw Error("noUiSlider: 'range' contains invalid value.");d="min"===b?0:"max"===b?100:parseFloat(b);if(!m(d)||!m(g[0]))throw Error("noUiSlider: 'range' value isn't numeric.");a.c.push(d);a.d.push(g[0]);d?a.h.push(isNaN(g[1])?!1:g[1]):isNaN(g[1])||(a.h[0]=g[1])});c.each(a.h,function(b,c){if(!c)return!0;a.h[b]=u([a.d[b],a.d[b+1]],c)/(100/(a.c[b+1]-a.c[b]))})}function E(a,b){"number"===typeof b&&(b=[b]);if(!c.isArray(b)||!b.length||
2<b.length)throw Error("noUiSlider: 'start' option is incorrect.");a.b=b.length;a.start=b}function I(a,b){a.m=b;if("boolean"!==typeof b)throw Error("noUiSlider: 'snap' option must be a boolean.");}function J(a,b){if("lower"===b&&1===a.b)a.i=1;else if("upper"===b&&1===a.b)a.i=2;else if(!0===b&&2===a.b)a.i=3;else if(!1===b)a.i=0;else throw Error("noUiSlider: 'connect' option doesn't match handle count.");}function D(a,b){switch(b){case "horizontal":a.k=0;break;case "vertical":a.k=1;break;default:throw Error("noUiSlider: 'orientation' option is invalid.");
}}function K(a,b){if(2<a.c.length)throw Error("noUiSlider: 'margin' option is only supported on linear sliders.");a.margin=u(a.d,b);if(!m(b))throw Error("noUiSlider: 'margin' option must be numeric.");}function L(a,b){switch(b){case "ltr":a.dir=0;break;case "rtl":a.dir=1;a.i=[0,2,1,3][a.i];break;default:throw Error("noUiSlider: 'direction' option was not recognized.");}}function M(a,b){if("string"!==typeof b)throw Error("noUiSlider: 'behaviour' must be a string containing options.");var c=0<=b.indexOf("snap");
a.n={s:0<=b.indexOf("tap")||c,extend:0<=b.indexOf("extend"),v:0<=b.indexOf("drag"),fixed:0<=b.indexOf("fixed"),m:c}}function N(a,b,d){a.o=[b.lower,b.upper];a.g=b.format;c.each(a.o,function(a,e){if(!c.isArray(e))throw Error("noUiSlider: 'serialization."+(a?"upper":"lower")+"' must be an array.");c.each(e,function(){if(!(this instanceof c.Link))throw Error("noUiSlider: 'serialization."+(a?"upper":"lower")+"' can only contain Link instances.");this.I(a);this.J(d);this.q(b.format)})});a.dir&&1<a.b&&a.o.reverse()}
function O(a,b){var f={c:[],d:[],h:[!1],margin:0},g;g={step:{e:!1,f:d},start:{e:!0,f:E},connect:{e:!0,f:J},direction:{e:!0,f:L},range:{e:!0,f:n},snap:{e:!1,f:I},orientation:{e:!1,f:D},margin:{e:!1,f:K},behaviour:{e:!0,f:M},serialization:{e:!0,f:N}};a=c.extend({connect:!1,direction:"ltr",behaviour:"tap",orientation:"horizontal"},a);a.serialization=c.extend({lower:[],upper:[],format:{}},a.serialization);c.each(g,function(c,d){if(void 0===a[c]){if(d.e)throw Error("noUiSlider: '"+c+"' is required.");
return!0}d.f(f,a[c],b)});f.style=f.k?"top":"left";return f}function P(a,b){var d=c("<div><div/></div>").addClass(f[2]),g=["-lower","-upper"];a.dir&&g.reverse();d.children().addClass(f[3]+" "+f[3]+g[b]);return d}function Q(a,b){b.j&&(b=new c.Link({target:c(b.j).clone().appendTo(a),method:b.method,format:b.g},!0));return b}function R(a,b){var d,f=[];for(d=0;d<a.b;d++){var k=f,h=d,m=a.o[d],n=b[d].children(),r=a.g,s=void 0,v=[],s=new c.Link({},!0);s.q(r);v.push(s);for(s=0;s<m.length;s++)v.push(Q(n,m[s]));
k[h]=v}return f}function S(a,b,c){switch(a){case 1:b.addClass(f[7]);c[0].addClass(f[6]);break;case 3:c[1].addClass(f[6]);case 2:c[0].addClass(f[7]);case 0:b.addClass(f[6])}}function T(a,b){var c,d=[];for(c=0;c<a.b;c++)d.push(P(a,c).appendTo(b));return d}function U(a,b){b.addClass([f[0],f[8+a.dir],f[4+a.k]].join(" "));return c("<div/>").appendTo(b).addClass(f[1])}function V(d,b,m){function g(){return t[["width","height"][b.k]]()}function n(a){var b,c=[q.val()];for(b=0;b<a.length;b++)q.trigger(a[b],
c)}function u(d,p,e){var g=d[0]!==l[0][0]?1:0,H=x[0]+b.margin,k=x[1]-b.margin;e&&1<l.length&&(p=g?Math.max(p,H):Math.min(p,k));100>p&&(p=h(b,p));p=Math.max(Math.min(parseFloat(p.toFixed(7)),100),0);if(p===x[g])return 1===l.length?!1:p===H||p===k?0:!1;d.css(b.style,p+"%");d.is(":first-child")&&d.toggleClass(f[17],50<p);x[g]=p;b.dir&&(p=100-p);c(y[g]).each(function(){this.write(a(b,p),d.children(),q)});return!0}function B(a,b,c){c||k(q,f[14]);u(a,b,!1);n(["slide","set","change"])}function w(a,c,d,e){a=
a.replace(/\s/g,".nui ")+".nui";c.on(a,function(a){var c=q.attr("disabled");if(q.hasClass(f[14])||void 0!==c&&null!==c)return!1;a.preventDefault();var c=0===a.type.indexOf("touch"),p=0===a.type.indexOf("mouse"),F=0===a.type.indexOf("pointer"),g,k,l=a;0===a.type.indexOf("MSPointer")&&(F=!0);a.originalEvent&&(a=a.originalEvent);c&&(g=a.changedTouches[0].pageX,k=a.changedTouches[0].pageY);if(p||F)F||void 0!==window.pageXOffset||(window.pageXOffset=document.documentElement.scrollLeft,window.pageYOffset=
document.documentElement.scrollTop),g=a.clientX+window.pageXOffset,k=a.clientY+window.pageYOffset;l.C=[g,k];l.cursor=p;a=l;a.l=a.C[b.k];d(a,e)})}function C(a,c){var b=c.b||l,d,e=!1,e=100*(a.l-c.start)/g(),f=b[0][0]!==l[0][0]?1:0;var k=c.D;d=e+k[0];e+=k[1];1<b.length?(0>d&&(e+=Math.abs(d)),100<e&&(d-=e-100),d=[Math.max(Math.min(d,100),0),Math.max(Math.min(e,100),0)]):d=[d,e];e=u(b[0],d[f],1===b.length);1<b.length&&(e=u(b[1],d[f?0:1],!1)||e);e&&n(["slide"])}function s(a){c("."+f[15]).removeClass(f[15]);
a.cursor&&c("body").css("cursor","").off(".nui");G.off(".nui");q.removeClass(f[12]);n(["set","change"])}function v(a,b){1===b.b.length&&b.b[0].children().addClass(f[15]);a.stopPropagation();w(z.move,G,C,{start:a.l,b:b.b,D:[x[0],x[l.length-1]]});w(z.end,G,s,null);a.cursor&&(c("body").css("cursor",c(a.target).css("cursor")),1<l.length&&q.addClass(f[12]),c("body").on("selectstart.nui",!1))}function D(a){var d=a.l,e=0;a.stopPropagation();c.each(l,function(){e+=this.offset()[b.style]});e=d<e/2||1===l.length?
0:1;d-=t.offset()[b.style];d=100*d/g();B(l[e],d,b.n.m);b.n.m&&v(a,{b:[l[e]]})}function E(a){var c=(a=a.l<t.offset()[b.style])?0:100;a=a?0:l.length-1;B(l[a],c,!1)}var q=c(d),x=[-1,-1],t,y,l;if(q.hasClass(f[0]))throw Error("Slider was already initialized.");t=U(b,q);l=T(b,t);y=R(b,l);S(b.i,q,l);(function(a){var b;if(!a.fixed)for(b=0;b<l.length;b++)w(z.start,l[b].children(),v,{b:[l[b]]});a.s&&w(z.start,t,D,{b:l});a.extend&&(q.addClass(f[16]),a.s&&w(z.start,q,E,{b:l}));a.v&&(b=t.find("."+f[7]).addClass(f[10]),
a.fixed&&(b=b.add(t.children().not(b).children())),w(z.start,b,v,{b:l}))})(b.n);d.vSet=function(){var a=Array.prototype.slice.call(arguments,0),d,e,g,h,m,s,t=r(a[0]);"object"===typeof a[1]?(d=a[1].set,e=a[1].link,g=a[1].update,h=a[1].animate):!0===a[1]&&(d=!0);b.dir&&1<b.b&&t.reverse();h&&k(q,f[14]);a=1<l.length?3:1;1===t.length&&(a=1);for(m=0;m<a;m++)h=e||y[m%2][0],h=h.A(t[m%2]),!1!==h&&(h=A(b,h),b.dir&&(h=100-h),!0!==u(l[m%2],h,!0)&&c(y[m%2]).each(function(a){if(!a)return s=this.u,!0;this.write(s,
l[m%2].children(),q,g)}));!0===d&&n(["set"]);return this};d.vGet=function(){var a,c=[];for(a=0;a<b.b;a++)c[a]=y[a][0].F;return 1===c.length?c[0]:b.dir?c.reverse():c};d.destroy=function(){c.each(y,function(){c.each(this,function(){this.target&&this.target.off(".nui")})});c(this).off(".nui").removeClass(f.join(" ")).empty();return m};q.val(b.start)}function W(a){if(!this.length)throw Error("noUiSlider: Can't initialize slider on empty selection.");var b=O(a,this);return this.each(function(){V(this,
b,a)})}function X(a){return this.each(function(){var b=c(this).val(),d=this.destroy(),f=c.extend({},d,a);c(this).noUiSlider(f);d.start===f.start&&c(this).val(b)})}function B(){return this[0][arguments.length?"vSet":"vGet"].apply(this[0],arguments)}var G=c(document),C=c.fn.val,z=window.navigator.pointerEnabled?{start:"pointerdown",move:"pointermove",end:"pointerup"}:window.navigator.msPointerEnabled?{start:"MSPointerDown",move:"MSPointerMove",end:"MSPointerUp"}:{start:"mousedown touchstart",move:"mousemove touchmove",
end:"mouseup touchend"},f="noUi-target noUi-base noUi-origin noUi-handle noUi-horizontal noUi-vertical noUi-background noUi-connect noUi-ltr noUi-rtl noUi-dragable noUi-state-drag noUi-state-tap noUi-active noUi-extended noUi-stacking".split(" ");c.fn.val=function(){var a=arguments,b=c(this[0]);return arguments.length?this.each(function(){(c(this).hasClass(f[0])?B:C).apply(c(this),a)}):(b.hasClass(f[0])?B:C).call(b)};c.noUiSlider={Link:c.Link};c.fn.noUiSlider=function(a,b){return(b?X:W).call(this,
a)}})(window.jQuery||window.Zepto);

View file

@ -1,352 +0,0 @@
/* globals jQuery */
(function ($) {
// Selector to select only not already processed elements
$.expr[":"].notmdproc = function (obj) {
if ($(obj).data("mdproc")) {
return false;
} else {
return true;
}
};
function _isChar(evt) {
if (typeof evt.which == "undefined") {
return true;
} else if (typeof evt.which == "number" && evt.which > 0) {
return (
!evt.ctrlKey
&& !evt.metaKey
&& !evt.altKey
&& evt.which != 8 // backspace
&& evt.which != 9 // tab
&& evt.which != 13 // enter
&& evt.which != 16 // shift
&& evt.which != 17 // ctrl
&& evt.which != 20 // caps lock
&& evt.which != 27 // escape
);
}
return false;
}
function _addFormGroupFocus(element) {
var $element = $(element);
if (!$element.prop('disabled')) { // this is showing as undefined on chrome but works fine on firefox??
$element.closest(".form-group").addClass("is-focused");
}
}
function _toggleDisabledState($element, state) {
var $target;
if ($element.hasClass('checkbox-inline') || $element.hasClass('radio-inline')) {
$target = $element;
} else {
$target = $element.closest('.checkbox').length ? $element.closest('.checkbox') : $element.closest('.radio');
}
return $target.toggleClass('disabled', state);
}
function _toggleTypeFocus($input) {
var disabledToggleType = false;
if ($input.is($.material.options.checkboxElements) || $input.is($.material.options.radioElements)) {
disabledToggleType = true;
}
$input.closest('label').hover(function () {
var $i = $(this).find('input');
var isDisabled = $i.prop('disabled'); // hack because the _addFormGroupFocus() wasn't identifying the property on chrome
if (disabledToggleType) {
_toggleDisabledState($(this), isDisabled);
}
if (!isDisabled) {
_addFormGroupFocus($i); // need to find the input so we can check disablement
}
},
function () {
_removeFormGroupFocus($(this).find('input'));
});
}
function _removeFormGroupFocus(element) {
$(element).closest(".form-group").removeClass("is-focused"); // remove class from form-group
}
$.material = {
"options": {
// These options set what will be started by $.material.init()
"validate": true,
"input": true,
"ripples": true,
"checkbox": true,
"togglebutton": true,
"radio": true,
"arrive": true,
"autofill": false,
"withRipples": [
".btn:not(.btn-link)",
".card-image",
".navbar a:not(.withoutripple)",
".dropdown-menu a",
".nav-tabs a:not(.withoutripple)",
".withripple",
".pagination li:not(.active):not(.disabled) a:not(.withoutripple)"
].join(","),
"inputElements": "input.form-control, textarea.form-control, select.form-control",
"checkboxElements": ".checkbox > label > input[type=checkbox], label.checkbox-inline > input[type=checkbox]",
"togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio], label.radio-inline > input[type=radio]"
},
"checkbox": function (selector) {
// Add fake-checkbox to material checkboxes
var $input = $((selector) ? selector : this.options.checkboxElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class='checkbox-material'><span class='check'></span></span>");
_toggleTypeFocus($input);
},
"togglebutton": function (selector) {
// Add fake-checkbox to material checkboxes
var $input = $((selector) ? selector : this.options.togglebuttonElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class='toggle'></span>");
_toggleTypeFocus($input);
},
"radio": function (selector) {
// Add fake-radio to material radios
var $input = $((selector) ? selector : this.options.radioElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class='circle'></span><span class='check'></span>");
_toggleTypeFocus($input);
},
"input": function (selector) {
$((selector) ? selector : this.options.inputElements)
.filter(":notmdproc")
.data("mdproc", true)
.each(function () {
var $input = $(this);
// Requires form-group standard markup (will add it if necessary)
var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group
if ($formGroup.length === 0 && $input.attr('type') !== "hidden" && !$input.attr('hidden')) {
$input.wrap("<div class='form-group'></div>");
$formGroup = $input.closest(".form-group"); // find node after attached (otherwise additional attachments don't work)
}
// Legacy - Add hint label if using the old shorthand data-hint attribute on the input
if ($input.attr("data-hint")) {
$input.after("<p class='help-block'>" + $input.attr("data-hint") + "</p>");
$input.removeAttr("data-hint");
}
// Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
var legacySizes = {
"input-lg": "form-group-lg",
"input-sm": "form-group-sm"
};
$.each(legacySizes, function (legacySize, standardSize) {
if ($input.hasClass(legacySize)) {
$input.removeClass(legacySize);
$formGroup.addClass(standardSize);
}
});
// Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo">
if ($input.hasClass("floating-label")) {
var placeholder = $input.attr("placeholder");
$input.attr("placeholder", null).removeClass("floating-label");
var id = $input.attr("id");
var forAttribute = "";
if (id) {
forAttribute = "for='" + id + "'";
}
$formGroup.addClass("label-floating");
$input.after("<label " + forAttribute + "class='control-label'>" + placeholder + "</label>");
}
// Set as empty if is empty (damn I must improve this...)
if ($input.val() === null || $input.val() == "undefined" || $input.val() === "") {
$formGroup.addClass("is-empty");
}
// Support for file input
if ($formGroup.find("input[type=file]").length > 0) {
$formGroup.addClass("is-fileinput");
}
});
},
"attachInputEventHandlers": function () {
var validate = this.options.validate;
$(document)
.on("keydown paste", ".form-control", function (e) {
if (_isChar(e)) {
$(this).closest(".form-group").removeClass("is-empty");
}
})
.on("keyup change", ".form-control", function () {
var $input = $(this);
var $formGroup = $input.closest(".form-group");
var isValid = (typeof $input[0].checkValidity === "undefined" || $input[0].checkValidity());
if ($input.val() === "") {
$formGroup.addClass("is-empty");
}
else {
$formGroup.removeClass("is-empty");
}
// Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
// Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
// the form-group on change.
//
// NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
// BUT, I've left it here for backwards compatibility.
if (validate) {
if (isValid) {
$formGroup.removeClass("has-error");
}
else {
$formGroup.addClass("has-error");
}
}
})
.on("focus", ".form-control, .form-group.is-fileinput", function () {
_addFormGroupFocus(this);
})
.on("blur", ".form-control, .form-group.is-fileinput", function () {
_removeFormGroupFocus(this);
})
// make sure empty is added back when there is a programmatic value change.
// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
.on("change", ".form-group input", function () {
var $input = $(this);
if ($input.attr("type") == "file") {
return;
}
var $formGroup = $input.closest(".form-group");
var value = $input.val();
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
})
// set the fileinput readonly field with the name of the file
.on("change", ".form-group.is-fileinput input[type='file']", function () {
var $input = $(this);
var $formGroup = $input.closest(".form-group");
var value = "";
$.each(this.files, function (i, file) {
value += file.name + ", ";
});
value = value.substring(0, value.length - 2);
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
$formGroup.find("input.form-control[readonly]").val(value);
});
},
"ripples": function (selector) {
$((selector) ? selector : this.options.withRipples).ripples();
},
"autofill": function () {
// This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function () {
$("input[type!=checkbox]").each(function () {
var $this = $(this);
if ($this.val() && $this.val() !== $this.attr("value")) {
$this.trigger("change");
}
});
}, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function () {
clearInterval(loading);
}, 10000);
},
"attachAutofillEventHandlers": function () {
// Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
var focused;
$(document)
.on("focus", "input", function () {
var $inputs = $(this).parents("form").find("input").not("[type=file]");
focused = setInterval(function () {
$inputs.each(function () {
var $this = $(this);
if ($this.val() !== $this.attr("value")) {
$this.trigger("change");
}
});
}, 100);
})
.on("blur", ".form-group input", function () {
clearInterval(focused);
});
},
"init": function (options) {
this.options = $.extend({}, this.options, options);
var $document = $(document);
if ($.fn.ripples && this.options.ripples) {
this.ripples();
}
if (this.options.input) {
this.input();
this.attachInputEventHandlers();
}
if (this.options.checkbox) {
this.checkbox();
}
if (this.options.togglebutton) {
this.togglebutton();
}
if (this.options.radio) {
this.radio();
}
if (this.options.autofill) {
this.autofill();
this.attachAutofillEventHandlers();
}
if (document.arrive && this.options.arrive) {
if ($.fn.ripples && this.options.ripples) {
$document.arrive(this.options.withRipples, function () {
$.material.ripples($(this));
});
}
if (this.options.input) {
$document.arrive(this.options.inputElements, function () {
$.material.input($(this));
});
}
if (this.options.checkbox) {
$document.arrive(this.options.checkboxElements, function () {
$.material.checkbox($(this));
});
}
if (this.options.radio) {
$document.arrive(this.options.radioElements, function () {
$.material.radio($(this));
});
}
if (this.options.togglebutton) {
$document.arrive(this.options.togglebuttonElements, function () {
$.material.togglebutton($(this));
});
}
}
}
};
})(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,324 +0,0 @@
/* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
/* globals jQuery, navigator */
(function($, window, document, undefined) {
"use strict";
/**
* Define the name of the plugin
*/
var ripples = "ripples";
/**
* Get an instance of the plugin
*/
var self = null;
/**
* Define the defaults of the plugin
*/
var defaults = {};
/**
* Create the main plugin function
*/
function Ripples(element, options) {
self = this;
this.element = $(element);
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = ripples;
this.init();
}
/**
* Initialize the plugin
*/
Ripples.prototype.init = function() {
var $element = this.element;
$element.on("mousedown touchstart", function(event) {
/**
* Verify if the user is just touching on a device and return if so
*/
if(self.isTouch() && event.type === "mousedown") {
return;
}
/**
* Verify if the current element already has a ripple wrapper element and
* creates if it doesn't
*/
if(!($element.find(".ripple-container").length)) {
$element.append("<div class=\"ripple-container\"></div>");
}
/**
* Find the ripple wrapper
*/
var $wrapper = $element.children(".ripple-container");
/**
* Get relY and relX positions
*/
var relY = self.getRelY($wrapper, event);
var relX = self.getRelX($wrapper, event);
/**
* If relY and/or relX are false, return the event
*/
if(!relY && !relX) {
return;
}
/**
* Get the ripple color
*/
var rippleColor = self.getRipplesColor($element);
/**
* Create the ripple element
*/
var $ripple = $("<div></div>");
$ripple
.addClass("ripple")
.css({
"left": relX,
"top": relY,
"background-color": rippleColor
});
/**
* Append the ripple to the wrapper
*/
$wrapper.append($ripple);
/**
* Make sure the ripple has the styles applied (ugly hack but it works)
*/
(function() { return window.getComputedStyle($ripple[0]).opacity; })();
/**
* Turn on the ripple animation
*/
self.rippleOn($element, $ripple);
/**
* Call the rippleEnd function when the transition "on" ends
*/
setTimeout(function() {
self.rippleEnd($ripple);
}, 500);
/**
* Detect when the user leaves the element
*/
$element.on("mouseup mouseleave touchend", function() {
$ripple.data("mousedown", "off");
if($ripple.data("animating") === "off") {
self.rippleOut($ripple);
}
});
});
};
/**
* Get the new size based on the element height/width and the ripple width
*/
Ripples.prototype.getNewSize = function($element, $ripple) {
return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5;
};
/**
* Get the relX
*/
Ripples.prototype.getRelX = function($wrapper, event) {
var wrapperOffset = $wrapper.offset();
if(!self.isTouch()) {
/**
* Get the mouse position relative to the ripple wrapper
*/
return event.pageX - wrapperOffset.left;
} else {
/**
* Make sure the user is using only one finger and then get the touch
* position relative to the ripple wrapper
*/
event = event.originalEvent;
if(event.touches.length === 1) {
return event.touches[0].pageX - wrapperOffset.left;
}
return false;
}
};
/**
* Get the relY
*/
Ripples.prototype.getRelY = function($wrapper, event) {
var wrapperOffset = $wrapper.offset();
if(!self.isTouch()) {
/**
* Get the mouse position relative to the ripple wrapper
*/
return event.pageY - wrapperOffset.top;
} else {
/**
* Make sure the user is using only one finger and then get the touch
* position relative to the ripple wrapper
*/
event = event.originalEvent;
if(event.touches.length === 1) {
return event.touches[0].pageY - wrapperOffset.top;
}
return false;
}
};
/**
* Get the ripple color
*/
Ripples.prototype.getRipplesColor = function($element) {
var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color;
return color;
};
/**
* Verify if the client browser has transistion support
*/
Ripples.prototype.hasTransitionSupport = function() {
var thisBody = document.body || document.documentElement;
var thisStyle = thisBody.style;
var support = (
thisStyle.transition !== undefined ||
thisStyle.WebkitTransition !== undefined ||
thisStyle.MozTransition !== undefined ||
thisStyle.MsTransition !== undefined ||
thisStyle.OTransition !== undefined
);
return support;
};
/**
* Verify if the client is using a mobile device
*/
Ripples.prototype.isTouch = function() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
};
/**
* End the animation of the ripple
*/
Ripples.prototype.rippleEnd = function($ripple) {
$ripple.data("animating", "off");
if($ripple.data("mousedown") === "off") {
self.rippleOut($ripple);
}
};
/**
* Turn off the ripple effect
*/
Ripples.prototype.rippleOut = function($ripple) {
$ripple.off();
if(self.hasTransitionSupport()) {
$ripple.addClass("ripple-out");
} else {
$ripple.animate({"opacity": 0}, 100, function() {
$ripple.trigger("transitionend");
});
}
$ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
$ripple.remove();
});
};
/**
* Turn on the ripple effect
*/
Ripples.prototype.rippleOn = function($element, $ripple) {
var size = self.getNewSize($element, $ripple);
if(self.hasTransitionSupport()) {
$ripple
.css({
"-ms-transform": "scale(" + size + ")",
"-moz-transform": "scale(" + size + ")",
"-webkit-transform": "scale(" + size + ")",
"transform": "scale(" + size + ")"
})
.addClass("ripple-on")
.data("animating", "on")
.data("mousedown", "on");
} else {
$ripple.animate({
"width": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
"height": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
"margin-left": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
"margin-top": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
"opacity": 0.2
}, 500, function() {
$ripple.trigger("transitionend");
});
}
};
/**
* Create the jquery plugin function
*/
$.fn.ripples = function(options) {
return this.each(function() {
if(!$.data(this, "plugin_" + ripples)) {
$.data(this, "plugin_" + ripples, new Ripples(this, options));
}
});
};
})(jQuery, window, document);

View file

@ -1,2 +0,0 @@
!function(a,b,c,d){"use strict";function e(b,c){g=this,this.element=a(b),this.options=a.extend({},h,c),this._defaults=h,this._name=f,this.init()}var f="ripples",g=null,h={};e.prototype.init=function(){var c=this.element;c.on("mousedown touchstart",function(d){if(!g.isTouch()||"mousedown"!==d.type){c.find(".ripple-container").length||c.append('<div class="ripple-container"></div>');var e=c.children(".ripple-container"),f=g.getRelY(e,d),h=g.getRelX(e,d);if(f||h){var i=g.getRipplesColor(c),j=a("<div></div>");j.addClass("ripple").css({left:h,top:f,"background-color":i}),e.append(j),function(){return b.getComputedStyle(j[0]).opacity}(),g.rippleOn(c,j),setTimeout(function(){g.rippleEnd(j)},500),c.on("mouseup mouseleave touchend",function(){j.data("mousedown","off"),"off"===j.data("animating")&&g.rippleOut(j)})}}})},e.prototype.getNewSize=function(a,b){return Math.max(a.outerWidth(),a.outerHeight())/b.outerWidth()*2.5},e.prototype.getRelX=function(a,b){var c=a.offset();return g.isTouch()?(b=b.originalEvent,1===b.touches.length?b.touches[0].pageX-c.left:!1):b.pageX-c.left},e.prototype.getRelY=function(a,b){var c=a.offset();return g.isTouch()?(b=b.originalEvent,1===b.touches.length?b.touches[0].pageY-c.top:!1):b.pageY-c.top},e.prototype.getRipplesColor=function(a){var c=a.data("ripple-color")?a.data("ripple-color"):b.getComputedStyle(a[0]).color;return c},e.prototype.hasTransitionSupport=function(){var a=c.body||c.documentElement,b=a.style,e=b.transition!==d||b.WebkitTransition!==d||b.MozTransition!==d||b.MsTransition!==d||b.OTransition!==d;return e},e.prototype.isTouch=function(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)},e.prototype.rippleEnd=function(a){a.data("animating","off"),"off"===a.data("mousedown")&&g.rippleOut(a)},e.prototype.rippleOut=function(a){a.off(),g.hasTransitionSupport()?a.addClass("ripple-out"):a.animate({opacity:0},100,function(){a.trigger("transitionend")}),a.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd",function(){a.remove()})},e.prototype.rippleOn=function(a,b){var c=g.getNewSize(a,b);g.hasTransitionSupport()?b.css({"-ms-transform":"scale("+c+")","-moz-transform":"scale("+c+")","-webkit-transform":"scale("+c+")",transform:"scale("+c+")"}).addClass("ripple-on").data("animating","on").data("mousedown","on"):b.animate({width:2*Math.max(a.outerWidth(),a.outerHeight()),height:2*Math.max(a.outerWidth(),a.outerHeight()),"margin-left":-1*Math.max(a.outerWidth(),a.outerHeight()),"margin-top":-1*Math.max(a.outerWidth(),a.outerHeight()),opacity:.2},500,function(){b.trigger("transitionend")})},a.fn.ripples=function(b){return this.each(function(){a.data(this,"plugin_"+f)||a.data(this,"plugin_"+f,new e(this,b))})}}(jQuery,window,document);
//# sourceMappingURL=ripples.min.js.map

View file

@ -1 +0,0 @@
{"version":3,"sources":["ripples.js"],"names":["$","window","document","undefined","Ripples","element","options","self","this","extend","defaults","_defaults","_name","ripples","init","prototype","$element","on","event","isTouch","type","find","append","$wrapper","children","relY","getRelY","relX","getRelX","rippleColor","getRipplesColor","$ripple","addClass","css","left","top","background-color","getComputedStyle","opacity","rippleOn","setTimeout","rippleEnd","data","rippleOut","getNewSize","Math","max","outerWidth","outerHeight","wrapperOffset","offset","originalEvent","touches","length","pageX","pageY","color","hasTransitionSupport","thisBody","body","documentElement","thisStyle","style","support","transition","WebkitTransition","MozTransition","MsTransition","OTransition","test","navigator","userAgent","off","animate","trigger","remove","size","-ms-transform","-moz-transform","-webkit-transform","transform","width","height","margin-left","margin-top","fn","each","jQuery"],"mappings":"CAGA,SAAUA,EAAGC,EAAQC,EAAUC,GAE7B,YAuBA,SAASC,GAAQC,EAASC,GACxBC,EAAOC,KAEPA,KAAKH,QAAUL,EAAEK,GAEjBG,KAAKF,QAAUN,EAAES,UAAWC,EAAUJ,GAEtCE,KAAKG,UAAYD,EACjBF,KAAKI,MAAQC,EAEbL,KAAKM,OA5BP,GAAID,GAAU,UAMVN,EAAO,KAMPG,IAuBJN,GAAQW,UAAUD,KAAO,WACvB,GAAIE,GAAYR,KAAKH,OAErBW,GAASC,GAAG,uBAAwB,SAASC,GAI3C,IAAGX,EAAKY,WAA4B,cAAfD,EAAME,KAA3B,CASKJ,EAASK,KAAK,qBAA2B,QAC5CL,EAASM,OAAO,uCAOlB,IAAIC,GAAWP,EAASQ,SAAS,qBAM7BC,EAAOlB,EAAKmB,QAAQH,EAAUL,GAC9BS,EAAOpB,EAAKqB,QAAQL,EAAUL,EAMlC,IAAIO,GAASE,EAAb,CAQA,GAAIE,GAActB,EAAKuB,gBAAgBd,GAMnCe,EAAU/B,EAAE,cAEhB+B,GACCC,SAAS,UACTC,KACCC,KAAQP,EACRQ,IAAOV,EACPW,mBAAoBP,IAOtBN,EAASD,OAAOS,GAMhB,WAAc,MAAO9B,GAAOoC,iBAAiBN,EAAQ,IAAIO,WAMzD/B,EAAKgC,SAASvB,EAAUe,GAMxBS,WAAW,WACTjC,EAAKkC,UAAUV,IACd,KAMHf,EAASC,GAAG,8BAA+B,WACzCc,EAAQW,KAAK,YAAa,OAEO,QAA9BX,EAAQW,KAAK,cACdnC,EAAKoC,UAAUZ,UAWvB3B,EAAQW,UAAU6B,WAAa,SAAS5B,EAAUe,GAEhD,MAAQc,MAAKC,IAAI9B,EAAS+B,aAAc/B,EAASgC,eAAiBjB,EAAQgB,aAAgB,KAO5F3C,EAAQW,UAAUa,QAAU,SAASL,EAAWL,GAC9C,GAAI+B,GAAgB1B,EAAS2B,QAE7B,OAAI3C,GAAKY,WAUPD,EAAQA,EAAMiC,cAEc,IAAzBjC,EAAMkC,QAAQC,OACRnC,EAAMkC,QAAQ,GAAGE,MAAQL,EAAcf,MAGzC,GAZAhB,EAAMoC,MAAQL,EAAcf,MAoBvC9B,EAAQW,UAAUW,QAAU,SAASH,EAAUL,GAC7C,GAAI+B,GAAgB1B,EAAS2B,QAE7B,OAAI3C,GAAKY,WAUPD,EAAQA,EAAMiC,cAEc,IAAzBjC,EAAMkC,QAAQC,OACRnC,EAAMkC,QAAQ,GAAGG,MAAQN,EAAcd,KAGzC,GAZAjB,EAAMqC,MAAQN,EAAcd,KAoBvC/B,EAAQW,UAAUe,gBAAkB,SAASd,GAE3C,GAAIwC,GAAQxC,EAAS0B,KAAK,gBAAkB1B,EAAS0B,KAAK,gBAAkBzC,EAAOoC,iBAAiBrB,EAAS,IAAIwC,KAEjH,OAAOA,IAOTpD,EAAQW,UAAU0C,qBAAuB,WACvC,GAAIC,GAAYxD,EAASyD,MAAQzD,EAAS0D,gBACtCC,EAAYH,EAASI,MAErBC,EACFF,EAAUG,aAAe7D,GACzB0D,EAAUI,mBAAqB9D,GAC/B0D,EAAUK,gBAAkB/D,GAC5B0D,EAAUM,eAAiBhE,GAC3B0D,EAAUO,cAAgBjE,CAG5B,OAAO4D,IAOT3D,EAAQW,UAAUI,QAAU,WAC1B,MAAO,iEAAiEkD,KAAKC,UAAUC,YAOzFnE,EAAQW,UAAU0B,UAAY,SAASV,GACrCA,EAAQW,KAAK,YAAa,OAEO,QAA9BX,EAAQW,KAAK,cACdnC,EAAKoC,UAAUZ,IAQnB3B,EAAQW,UAAU4B,UAAY,SAASZ,GACrCA,EAAQyC,MAELjE,EAAKkD,uBACN1B,EAAQC,SAAS,cAEjBD,EAAQ0C,SAASnC,QAAW,GAAI,IAAK,WACnCP,EAAQ2C,QAAQ,mBAIpB3C,EAAQd,GAAG,mEAAoE,WAC7Ec,EAAQ4C,YAQZvE,EAAQW,UAAUwB,SAAW,SAASvB,EAAUe,GAC9C,GAAI6C,GAAOrE,EAAKqC,WAAW5B,EAAUe,EAElCxB,GAAKkD,uBACN1B,EACCE,KACC4C,gBAAiB,SAAWD,EAAO,IACnCE,iBAAkB,SAAWF,EAAO,IACpCG,oBAAqB,SAAWH,EAAO,IACvCI,UAAa,SAAWJ,EAAO,MAEhC5C,SAAS,aACTU,KAAK,YAAa,MAClBA,KAAK,YAAa,MAEnBX,EAAQ0C,SACNQ,MAAmE,EAA1DpC,KAAKC,IAAI9B,EAAS+B,aAAc/B,EAASgC,eAClDkC,OAAoE,EAA1DrC,KAAKC,IAAI9B,EAAS+B,aAAc/B,EAASgC,eACnDmC,cAAyE,GAA1DtC,KAAKC,IAAI9B,EAAS+B,aAAc/B,EAASgC,eACxDoC,aAAwE,GAA1DvC,KAAKC,IAAI9B,EAAS+B,aAAc/B,EAASgC,eACvDV,QAAW,IACV,IAAK,WACNP,EAAQ2C,QAAQ,oBAStB1E,EAAEqF,GAAGxE,QAAU,SAASP,GACtB,MAAOE,MAAK8E,KAAK,WACXtF,EAAE0C,KAAKlC,KAAM,UAAYK,IAC3Bb,EAAE0C,KAAKlC,KAAM,UAAYK,EAAS,GAAIT,GAAQI,KAAMF,QAKzDiF,OAAQtF,OAAQC","file":"ripples.min.js"}

View file

@ -15,6 +15,7 @@ final class ServerSelectAction extends AbstractAction
$this->session->set('sid', $sid); $this->session->set('sid', $sid);
$this->session->set('sname', $this->ts->getInstance()->getElement('data', $dataResult)['virtualserver_name']); $this->session->set('sname', $this->ts->getInstance()->getElement('data', $dataResult)['virtualserver_name']);
$this->session->set('sport', $this->ts->getInstance()->getElement('data', $dataResult)['virtualserver_port']);
$this->flash->addMessage('success', $this->translator->trans('done')); $this->flash->addMessage('success', $this->translator->trans('done'));
return $response->withRedirect('/servers'); return $response->withRedirect('/servers');

View file

@ -1,7 +1,10 @@
<?php <?php
use Dotenv\Dotenv; use Dotenv\Dotenv;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger; use Monolog\Logger;
use Monolog\Processor\UidProcessor;
use Symfony\Component\Translation\Loader\YamlFileLoader; use Symfony\Component\Translation\Loader\YamlFileLoader;
use Symfony\Component\Translation\MessageSelector; use Symfony\Component\Translation\MessageSelector;
use Symfony\Component\Translation\Translator; use Symfony\Component\Translation\Translator;
@ -17,34 +20,20 @@ class BootstrapHelper
public static function bootEnvironment() public static function bootEnvironment()
{ {
$envPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'config'; $envPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'config';
$envFile = 'env';
$exists = is_file($envPath . DIRECTORY_SEPARATOR . $envFile); $defaultEnv = new Dotenv($envPath, EnvConstants::ENV_FILE_DEFAULT);
if (!$exists) { $defaultEnvRes = $defaultEnv->load();
die('Configure your environment in ' . $envPath . '.');
} else {
$env = new Dotenv($envPath, $envFile);
$res = $env->load();
try { $envFile = $envPath . DIRECTORY_SEPARATOR . EnvConstants::ENV_FILE_CUSTOM;
$env->required([ $envRes = [];
'site_title', if (file_exists($envFile)) {
'site_language', $env = new Dotenv($envPath, EnvConstants::ENV_FILE_CUSTOM);
'site_date_format', $envRes = $env->load();
'theme',
'theme_cache',
'teamspeak_default_host',
'teamspeak_default_query_port',
'teamspeak_default_user',
'log_name',
'log_level'
]);
} catch (\Dotenv\Exception\ValidationException $e) {
die($e->getMessage());
}
return $res;
} }
$res = array_merge_recursive($defaultEnvRes, $envRes);
return $res;
} }
/** /**
@ -54,7 +43,7 @@ class BootstrapHelper
*/ */
public static function bootTranslator() public static function bootTranslator()
{ {
$translator = new Translator(getenv('site_language'), new MessageSelector()); $translator = new Translator(getenv(EnvConstants::SITE_LANGUAGE), new MessageSelector());
$translator->addLoader('yaml', new YamlFileLoader()); $translator->addLoader('yaml', new YamlFileLoader());
$localeDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'locale'; $localeDir = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'locale';
@ -64,7 +53,7 @@ class BootstrapHelper
$translator->addResource('yaml', $locale, basename($locale, '.yml')); $translator->addResource('yaml', $locale, basename($locale, '.yml'));
} }
$translator->setFallbackLocales([getenv('site_language'), 'en']); $translator->setFallbackLocales([getenv(EnvConstants::SITE_LANGUAGE), 'en']);
return $translator; return $translator;
} }
@ -72,13 +61,13 @@ class BootstrapHelper
/** /**
* Bootstrap logger * Bootstrap logger
* *
* @return \Monolog\Logger * @return Logger
* @throws Exception * @throws Exception
*/ */
public static function bootLogger() public static function bootLogger()
{ {
$logName = getenv('log_name'); $logName = getenv(EnvConstants::LOG_NAME);
$logLevel = getenv('log_level'); $logLevel = getenv(EnvConstants::LOG_LEVEL);
switch ($logLevel) { switch ($logLevel) {
case 'DEBUG': case 'DEBUG':
@ -110,11 +99,11 @@ class BootstrapHelper
} }
$logger = new Monolog\Logger($logName); $logger = new Monolog\Logger($logName);
$logger->pushProcessor(new \Monolog\Processor\UidProcessor()); $logger->pushProcessor(new UidProcessor());
$logger->pushHandler(new \Monolog\Handler\ErrorLogHandler(NULL, $logLevelTranslated)); $logger->pushHandler(new ErrorLogHandler(NULL, $logLevelTranslated));
$logPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR . 'application.log'; $logPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR . 'application.log';
$logger->pushHandler(new \Monolog\Handler\StreamHandler($logPath, $logLevelTranslated)); $logger->pushHandler(new StreamHandler($logPath, $logLevelTranslated));
return $logger; return $logger;
} }

View file

@ -1,5 +1,7 @@
<?php <?php
use Psr\Log\LoggerInterface;
class TS3AdminProxy class TS3AdminProxy
{ {
private $object; private $object;
@ -8,7 +10,7 @@ class TS3AdminProxy
/** /**
* TS3AdminProxy constructor. * TS3AdminProxy constructor.
* @param ts3admin $object * @param ts3admin $object
* @param $logger \Psr\Log\LoggerInterface * @param $logger LoggerInterface
*/ */
public function __construct(ts3admin $object, $logger) { public function __construct(ts3admin $object, $logger) {
$this->object = $object; $this->object = $object;

View file

@ -1,5 +1,7 @@
<?php <?php
use Psr\Log\LoggerInterface;
class TSInstance class TSInstance
{ {
/** /**
@ -18,7 +20,7 @@ class TSInstance
private $queryPort; private $queryPort;
/** /**
* @var \Psr\Log\LoggerInterface * @var LoggerInterface
*/ */
private $logger; private $logger;
@ -30,8 +32,8 @@ class TSInstance
{ {
$this->logger = $logger; $this->logger = $logger;
$this->host = getenv('teamspeak_default_host'); $this->host = getenv(EnvConstants::TEAMSPEAK_HOST);
$this->queryPort = getenv('teamspeak_default_query_port'); $this->queryPort = getenv(EnvConstants::TEAMSPEAK_QUERY_PORT);
$ts = new ts3admin($this->host, $this->queryPort); $ts = new ts3admin($this->host, $this->queryPort);
$ts = new TS3AdminProxy($ts, $logger); $ts = new TS3AdminProxy($ts, $logger);

View file

@ -163,7 +163,6 @@ class Validator extends GUMP
case 'validate_set_min_len': case 'validate_set_min_len':
$resp[$field] = $this->translator->trans($e['rule'], ['%field%' => $this->translator->trans('form_field_' . strtolower(str_replace([' '], '', $field))), '%param%' => $param]); $resp[$field] = $this->translator->trans($e['rule'], ['%field%' => $this->translator->trans('form_field_' . strtolower(str_replace([' '], '', $field))), '%param%' => $param]);
break; break;
default: default:
$resp[$field] = $this->translator->trans($e['rule'], ['%field%' => $field, '%param%' => $param]); $resp[$field] = $this->translator->trans($e['rule'], ['%field%' => $field, '%param%' => $param]);
} }

View file

@ -1,7 +1,7 @@
{% extends 'layout.twig' %} {% extends 'layout.twig' %}
{% block content %} {% block content %}
<h1 class="header">{{ title }}</h1> <h3>{{ title }}</h3>
{% if data|length > 0 %} {% if data|length > 0 %}
{% include 'table.twig' with {'data': data, {% include 'table.twig' with {'data': data,
'filters': [ 'filters': [
@ -11,7 +11,7 @@
'additional_links': [ 'additional_links': [
{ {
'header_label': 'bans.delete'|trans, 'header_label': 'bans.delete'|trans,
'label': '<i class="material-icons">delete</i>', 'label': '<i class="fa fa-trash"></i>',
'uri': '/bans/delete/' ~ sid, 'uri': '/bans/delete/' ~ sid,
'uri_param': 'banid' 'uri_param': 'banid'
} }

View file

@ -1,14 +1,14 @@
{% extends 'layout.twig' %} {% extends 'layout.twig' %}
{% block content %} {% block content %}
<h1 class="header">{{ title }}</h1> <h3>{{ title }}</h3>
<h2 class="header">{% trans %}channel_info.h.actions{% endtrans %}</h2> <h5>{% trans %}channel_info.h.actions{% endtrans %}</h5>
{% include 'form.twig' with { {% include 'form.twig' with {
'fields': [ 'fields': [
{ {
'header_label': 'channel_info.send'|trans, 'header_label': 'channel_info.send'|trans,
'label': '<i class="material-icons">check_circle</i>', 'label': '<i class="fa fa-check"></i>',
'uri': '/channels/send/' ~ sid ~ '/' ~ cid, 'uri': '/channels/send/' ~ sid ~ '/' ~ cid,
'uri_method': 'post', 'uri_method': 'post',
'fields': [ 'fields': [
@ -18,42 +18,58 @@
} %} } %}
{% if clients|length > 0 %} {% if clients|length > 0 %}
<h2 class="header">{% trans %}channel_info.h.clients{% endtrans %}</h2> <h5>{% trans %}channel_info.h.clients{% endtrans %}</h5>
{% include 'table.twig' with {'data': clients, {% include 'table.twig' with {'data': clients,
'hiddenDependingOnAttribute': [{'key': 'client_type', 'values': ['1']}], 'hiddenDependingOnAttribute': [{'key': 'client_type', 'values': ['1']}],
'hiddenColumns': ['clid', 'cid', 'client_type', 'client_database_id'],
'links': [ 'links': [
{'key': 'clid', 'uri': '/online/' ~ sid}, {'key': 'client_nickname', 'uri': '/online/' ~ sid, 'uri_param': 'clid'},
{'key': 'client_database_id', 'uri': '/clients/' ~ sid, 'uri_param': 'client_database_id'} ],
]} %} 'additional_links': [
{
'header_label': 'channel_info.client'|trans,
'label': '<i class="fa fa-user-plus"></i>',
'uri': '/clients/' ~ sid,
'uri_param': 'client_database_id'
}
]
} %}
{% endif %} {% endif %}
{% if files|length > 0 %} {% if files|length > 0 %}
<h2 class="header">{% trans %}channel_info.h.files{% endtrans %}</h2> <h5>{% trans %}channel_info.h.files{% endtrans %}</h5>
{% include 'files.twig' with {'data': files} %} {% include 'table.twig' with {'data': files,
'filters': [
{'key': 'datetime', 'apply': 'timestamp'},
{'key': 'size', 'apply': 'file'},
],
'hiddenColumns': ['cid', 'type']
} %}
{% endif %} {% endif %}
<h2 class="header">{% trans %}channel_info.h.details{% endtrans %}</h2> <h5>{% trans %}channel_info.h.details{% endtrans %}</h5>
{% include 'keyvalue.twig' with {'data': channel, {% include 'keyvalue.twig' with {'data': channel,
'attributesEditable': [ 'attributesEditable': [
{'key': 'channel_name', 'type': 'text', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_name', 'type': 'text', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_topic', 'type': 'text', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_topic', 'type': 'text', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_description', 'type': 'text', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_description', 'type': 'text', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_password', 'type': 'text', 'blank': true,'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_password', 'type': 'text', 'blank': true,'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_maxclients', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_maxclients', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_flag_maxclients_unlimited', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_flag_maxclients_unlimited', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_maxfamilyclients', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_maxfamilyclients', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_flag_maxfamilyclients_unlimited', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_flag_maxfamilyclients_unlimited', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_flag_maxfamilyclients_inherited', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_flag_maxfamilyclients_inherited', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_flag_permanent', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_flag_permanent', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_flag_semi_permanent', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_flag_semi_permanent', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_flag_default', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_flag_default', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_order', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_order', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_needed_talk_power', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_needed_talk_power', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_name_phonetic', 'type': 'text', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_name_phonetic', 'type': 'text', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_codec', 'type': 'select', 'options': codecs, 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_codec', 'type': 'select', 'options': codecs, 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_codec_quality', 'type': 'select', 'options': codecsquality, 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_codec_quality', 'type': 'select', 'options': codecsquality, 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_codec_is_unencrypted', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_codec_is_unencrypted', 'type': 'checkbox', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
{'key': 'channel_icon_id', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="material-icons">check_circle</i>'}, {'key': 'channel_icon_id', 'type': 'number', 'uri': '/channels/edit/' ~ sid ~ '/' ~ cid , 'uri_method': 'post', 'submit_label': '<i class="fa fa-check"></i>'},
] ]
} %} } %}
{% endblock %} {% endblock %}

View file

@ -0,0 +1,36 @@
{% extends 'layout.twig' %}
{% block content %}
<h3>{{ title }}</h3>
{% if clients|length > 0 %}
<h5>{% trans %}channelgroup_info.h.clients{% endtrans %}</h5>
{% include 'table.twig' with {'data': clients,
'links': [
{'key': 'cldbid', 'uri': '/clients/' ~ sid, 'uri_param': 'cldbid'},
{'key': 'cid', 'uri': '/channels/' ~ sid, 'uri_param': 'cid'}
],
'hiddenColumns': ['cgid', 'cid', 'cldbid'],
'additional_links': [
{
'header_label': 'channelgroup_info.client'|trans,
'label': '<i class="fa fa-user-plus"></i>',
'uri': '/clients/' ~ sid,
'uri_param': 'cldbid'
},
{
'header_label': 'channelgroup_info.channel'|trans,
'label': '<i class="fa fa-tv"></i>',
'uri': '/channels/' ~ sid,
'uri_param': 'cid'
}
]
} %}
{% endif %}
{% if permissions|length > 0 %}
<h5>{% trans %}channelgroup_info.h.permissions{% endtrans %}</h5>
{% include 'table.twig' with {'data': permissions} %}
{% endif %}
{% endblock %}

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