diff --git a/.gitignore b/.gitignore index 1c1b8b0..7316b02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,13 @@ -tmp/temp.tdata sitemap.xml - +node_modules/ +npm-debug.log +yarn-error.log +.yarn/* +!.yarn/releases +!.yarn/plugins +!.yarn/sdks +!.yarn/versions +assets/bundle/* +!assets/bundle/.gitkeep +config/site.php +includes/config.php diff --git a/.htaccess b/.htaccess deleted file mode 100644 index 39c72ad..0000000 --- a/.htaccess +++ /dev/null @@ -1,52 +0,0 @@ -Options +FollowSymLinks -RewriteEngine on - - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule ^page/([a-zA-Z0-9]+)/? pages.php?page=$1 [L] - RewriteRule ^archive archive.php [L] - RewriteRule ^discover discover.php [L] - RewriteRule ^profile profile.php [L] - RewriteRule ^user/([^/]+)/?$ user.php?user=$1 [L] - RewriteRule ^user/([^/]+)/([^/]+)/?$ user.php?user=$1&q=$2 [L] - RewriteRule ^contact contact.php [L] - RewriteRule ^download/(.*)$ paste.php?download&id=$1 [L] - RewriteRule ^raw/(.*)$ paste.php?raw&id=$1 [L] - RewriteRule ^embed/(.*)$ paste.php?embed&id=$1 [L] - RewriteRule ^report report.php [L] - RewriteRule ^event event.php [L] -Options +FollowSymLinks -RewriteBase / -RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0" [OR] -RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0" [OR] -RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.2; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0" [OR] -RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.2; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0" [OR] -RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36" [OR] -RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0" [OR] -RewriteCond %{HTTP_USER_AGENT} "=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0" [OR] -RewriteCond %{HTTP_USER_AGENT} Mb2345Browser|LieBaoFast|zh-CN|MicroMessenger|zh_CN|Kinza|Datanyze|serpstatbot|spaziodati|OPPO\sA33|AspiegelBot|aspiegel|PetalBot|SemrushBot/7~bl [NC] -RewriteRule ^ - [F,L] - - - - - RewriteCond %{REQUEST_FILENAME} !-f - RewriteCond %{REQUEST_FILENAME} !-d - RewriteRule ^(.*)$ paste.php?id=$1 [L] - - -# compress text, html, javascript, css, xml: -AddOutputFilterByType DEFLATE text/plain -AddOutputFilterByType DEFLATE text/html -AddOutputFilterByType DEFLATE text/xml -AddOutputFilterByType DEFLATE text/css -AddOutputFilterByType DEFLATE application/xml -AddOutputFilterByType DEFLATE application/xhtml+xml -AddOutputFilterByType DEFLATE application/rss+xml -AddOutputFilterByType DEFLATE application/javascript -AddOutputFilterByType DEFLATE application/x-javascript - -# Or, compress certain file types by extension: - -SetOutputFilter DEFLATE - \ No newline at end of file diff --git a/README.md b/README.md index 2ce0479..2d047cd 100644 --- a/README.md +++ b/README.md @@ -1 +1,12 @@ -# punishedponepaste \ No newline at end of file +punishedponepaste +================= + +# Requirements +* An HTTP server that can perform URL rewriting and execute PHP 8 code (eg: nginx with php8-fpm,) and the following PHP extensions: pdo, openssl, gd, mbstring, redis. +* A MySQL-compatible server (eg: MariaDB 10.) +* A Redis server. + +# Building the JS +When you change the JS, you need to rebuild it. `assets/bundle.js` is used in dev, `assets/bundle.min.js` is used in production. + +You need Yarn (version 1, not version 2 - 2 may work, but I haven't tried it.) After that, whenever you change anything under `js/`, you need to run `yarn rollup --config`. Good luck! \ No newline at end of file diff --git a/admin/ads.php b/admin/ads.php deleted file mode 100644 index 359bbb9..0000000 --- a/admin/ads.php +++ /dev/null @@ -1,141 +0,0 @@ - - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License in GPL.txt for more details. - */ - -define('IN_PONEPASTE', 1); -require_once('common.php'); - -updateAdminHistory($conn); - -$row = $conn->query('SELECT text_ads, ads_1, ads_2 FROM ads LIMIT 1')->fetch(); - -if ($row) { - $text_ads = trim($row['text_ads']); - $ads_1 = trim($row['ads_1']); - $ads_2 = trim($row['ads_2']); -} else { - $text_ads = ''; - $ads_1 = ''; - $ads_2 = ''; -} - -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $text_ads = trim($_POST['text_ads']); - $ads_1 = trim($_POST['ads_1']); - $ads_2 = trim($_POST['ads_2']); - - $conn->prepare('UPDATE ads SET text_ads = ?, ads_1 = ?, ads_2 = ? WHERE id = 1')->execute([$text_ads, $ads_1, $ads_2]); - $msg = '
- Ads saved -
'; -} -?> - - - - - - - Paste - Ads - - - - - -
- - - - - - - -
- - -
- -
- - - - -
-
-
-
-
Manage Ads
- -
-
- -
- -
-
-
- -
- -
-
- -
- -
- -
-
- -
-
-
-
-
- -
- - - - - -
- - - - - - \ No newline at end of file diff --git a/admin/ajax_pastes.php b/admin/ajax_pastes.php deleted file mode 100644 index 1de5207..0000000 --- a/admin/ajax_pastes.php +++ /dev/null @@ -1,53 +0,0 @@ - 'id', 'dt' => 0), - array('db' => 'member', 'dt' => 1), - array('db' => 'ip', 'dt' => 2), - array('db' => 'visible', 'dt' => 3) -); - -$columns2 = array( - array('db' => 'id', 'dt' => 0), - array('db' => 'member', 'dt' => 1), - array('db' => 'ip', 'dt' => 2), - array('db' => 'visible', 'dt' => 3), - array('db' => 'details', 'dt' => 4), - array('db' => 'view', 'dt' => 5), - array('db' => 'delete', 'dt' => 6) -); - - -// SQL server connection information -$sql_details = array( - 'user' => $db_user, - 'pass' => $db_pass, - 'db' => $db_schema, - 'host' => $db_host -); - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * If you just want to use the basic configuration for DataTables with PHP - * server-side, there is no need to edit below this line. - */ - -require('ssp.pastes.php'); - -echo json_encode( - SSP::simple($_GET, $sql_details, $table, $primaryKey, $columns, $columns2) -); diff --git a/admin/ajax_reports.php b/admin/ajax_reports.php deleted file mode 100644 index 0f4765e..0000000 --- a/admin/ajax_reports.php +++ /dev/null @@ -1,65 +0,0 @@ - 'id', 'dt' => 0), - array('db' => 'm_report', 'dt' => 1), - array('db' => 'p_report', 'dt' => 2), - array('db' => 't_report', 'dt' => 3) -); - -$columns2 = array( - array('db' => 'id', 'dt' => 0), - array('db' => 'm_report', 'dt' => 1), - array('db' => 'p_report', 'dt' => 2), - array('db' => 't_report', 'dt' => 3), - array('db' => 'details', 'dt' => 4), - array('db' => 'view', 'dt' => 5), - array('db' => 'delete', 'dt' => 6) -); - - -// SQL server connection information -$sql_details = array( - 'user' => $dbuser, - 'pass' => $dbpassword, - 'db' => $dbname, - 'host' => $dbhost -); - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * If you just want to use the basic configuration for DataTables with PHP - * server-side, there is no need to edit below this line. - */ - -require('ssp.reports.php'); - -echo json_encode( - SSP::simple($_GET, $sql_details, $table, $primaryKey, $columns, $columns2) -); diff --git a/admin/ajax_users.php b/admin/ajax_users.php deleted file mode 100644 index bd21bc9..0000000 --- a/admin/ajax_users.php +++ /dev/null @@ -1,57 +0,0 @@ - 'id', 'dt' => 0), - array('db' => 'username', 'dt' => 1), - array('db' => 'date', 'dt' => 3), - array('db' => 'platform', 'dt' => 4), - array('db' => 'id', 'dt' => 5), - array('db' => 'verified', 'dt' => 7) -); - -$columns2 = array( - array('db' => 'id', 'dt' => 0), - array('db' => 'username', 'dt' => 1), - array('db' => 'date', 'dt' => 3), - array('db' => 'platform', 'dt' => 4), - array('db' => 'ban', 'dt' => 5), - array('db' => 'view', 'dt' => 6), - array('db' => 'delete', 'dt' => 7) -); - - -// SQL server connection information -$sql_details = array( - 'user' => $db_user, - 'pass' => $db_pass, - 'db' => $db_schema, - 'host' => $db_host -); - - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * If you just want to use the basic configuration for DataTables with PHP - * server-side, there is no need to edit below this line. - */ - -require('ssp.users.php'); - -echo json_encode( - SSP::simple($_GET, $sql_details, $table, $primaryKey, $columns, $columns2) -); - -if ($_SERVER['HTTP_X_REQUESTED_WITH'] != "XMLHttpRequest") { - header("Location: http://ponepaste.org/SVOtaKqJZh4nT9Z"); - die(); -} - diff --git a/admin/common.php b/admin/common.php deleted file mode 100644 index 7076f49..0000000 --- a/admin/common.php +++ /dev/null @@ -1,38 +0,0 @@ -query('SELECT ip, last_date FROM admin_history ORDER BY ID DESC LIMIT 1'); - - if ($row = $query->fetch()) { - $last_date = $row['last_date']; - $last_ip = $row['ip']; - } - - if ($last_ip !== $ip || $last_date !== $date) { - $conn->prepare('INSERT INTO admin_history (ip, last_date) VALUES (?, ?)')->execute([$date, $ip]); - } -} - -if (!isset($_SESSION['login'])) { - header('Location: .'); - exit(); -} - -if (isset($_GET['logout'])) { - if (isset($_SESSION['login'])) - unset($_SESSION['login']); - - session_destroy(); - header("Location: ."); - exit(); -} - diff --git a/admin/dashboard.php b/admin/dashboard.php deleted file mode 100644 index b596cf9..0000000 --- a/admin/dashboard.php +++ /dev/null @@ -1,322 +0,0 @@ - - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License in GPL.txt for more details. - */ - -define('IN_PONEPASTE', 1); -require_once('common.php'); - -$today_users_count = 0; -$today_pastes_count = 0; - -require_once('../includes/common.php'); -require_once('../includes/functions.php'); - -updateAdminHistory($conn); - -$query = $conn->query("SELECT @last_id := MAX(id) FROM page_view"); -$row = $query->fetch(PDO::FETCH_NUM); -$page_last_id = intval($row[0]); - - -$query = $conn->prepare('SELECT tpage, tvisit FROM page_view WHERE id = ?'); -$query->execute([$page_last_id]); - -while ($row = $query->fetch()) { - $today_page = $row['tpage']; - $today_visit = $row['tvisit']; -} - -$admin_email = getSiteInfo()['site_info']['email']; -$c_date = date('jS F Y'); - -/* Number of users today */ -$query = $conn->prepare('SELECT COUNT(*) FROM users WHERE `date` = ?'); -$query->execute([$c_date]); -$today_users_count = intval($query->fetch(PDO::FETCH_NUM)[0]); - -/* Number of pastes today */ -$query = $conn->query('SELECT COUNT(*) FROM pastes where DATE(created_at) = DATE(NOW())'); -$today_pastes_count = intval($query->fetch(PDO::FETCH_NUM)[0]); - -for ($loop = 0; $loop <= 6; $loop++) { - $myid = $page_last_id - $loop; - $query = $conn->prepare("SELECT date, tpage, tvisit FROM page_view WHERE id = ?"); - $query->execute([$myid]); - - while ($row = $query->fetch()) { - $sdate = $row['date']; - $sdate = str_replace(date('Y'), '', $sdate); - $sdate = str_replace('January', 'Jan', $sdate); - $sdate = str_replace('February', 'Feb', $sdate); - $sdate = str_replace('March', 'Mar', $sdate); - $sdate = str_replace('April', 'Apr', $sdate); - $sdate = str_replace('August', 'Aug', $sdate); - $sdate = str_replace('September', 'Sep', $sdate); - $sdate = str_replace('October', 'Oct', $sdate); - $sdate = str_replace('November', 'Nov', $sdate); - $sdate = str_replace('December', 'Dec', $sdate); - - $ldate[$loop] = $sdate; - $tpage[$loop] = $row['tpage']; - $tvisit[$loop] = $row['tvisit']; - } -} -?> - - - - - - - Ponepaste - Dashboard - - - - - -
- - - - - - - -
- - -
- -
- - - - - -
-
-
    -
  • - Views -

    - Today -
  • -
  • - Pastes -

    - Today -
  • -
  • - Users -

    - Today -
  • -
  • - Unique Views -

    - Today -
  • -
-
-
- - -
- -
-
-
- Recent Pastes -
- -
- - - - - - - - - - - - - format('jS F Y h:i:s A'); - $p_ip = Trim($row['ip']); - $p_member = Trim($row['member']); - $p_view = Trim($row['views']); - $p_time = friendlyDateDifference($p_date, new DateTime()); - $title = truncate($title, 5, 30); - echo " - - - - - - - "; - } - ?> - -
IDUsernameDateIPViews
$p_id$p_member$p_date_formatted$p_ip$p_view
- -
-
-
- - - -
-
-
- Recent Users -
- -
- - - - - - - - - - - - query('SELECT id, username, date, ip FROM users ORDER BY id DESC LIMIT 7')->fetchAll(); - $last_id = intval( - $conn->query('SELECT MAX(id) FROM users')->fetch(PDO::FETCH_NUM)[0] - ); - - foreach ($most_recent_users as $user) { - echo " - - - - - - "; - } - - ?> - -
IDUsernameDateIP
${user['id']}${user['username']}${user['date']}${user['ip']}
- -
-
-
- -
- -
- -
-
-
- Admin History -
- -
- - - - - - - - - - - - - - - - - - - '; - } - ?> - -
IDLast Login DateIPIDLast Login Date
' . $r_id . '' . $r_paste . '' . $m_report . '' . $r_date . '' . $r_reason . '
- -
-
-
- - -
-
-
-
-

-
You have the latest version - -

-
-
-
-
- - - - - - -
- - - - - - - diff --git a/admin/index.php b/admin/index.php deleted file mode 100644 index 964dd89..0000000 --- a/admin/index.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License in GPL.txt for more details. - */ -define('IN_PONEPASTE', 1); -require_once(__DIR__ . '/../includes/common.php'); - -$row = $conn->querySelectOne('SELECT user, pass FROM admin LIMIT 1'); -$adminid = $row['user']; -$password = $row['pass']; - -if ($_SERVER['REQUEST_METHOD'] == 'POST') { - if ($adminid === trim($_POST['username']) && password_verify($_POST['password'], $password)) { - $_SESSION['login'] = true; - header("Location: dashboard.php"); - exit(); - } else { - $msg = '
- Wrong User/Password -
'; - } -} -?> - - - - - - - - Paste - Login - - - - -
- -
-
-

Paste

-
-
-
- - -
-
- - -
- - -
-
-
- - \ No newline at end of file diff --git a/admin/interface.php b/admin/interface.php deleted file mode 100644 index 1c92433..0000000 --- a/admin/interface.php +++ /dev/null @@ -1,256 +0,0 @@ - - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 3 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License in GPL.txt for more details. - */ -session_start(); - -if (!isset($_SESSION['login'])) { - header("Location: ."); - exit(); -} - -if (isset($_GET['logout'])) { - if (isset($_SESSION['login'])) - unset($_SESSION['login']); - - session_destroy(); - header("Location: ."); - exit(); -} - -$date = date('jS F Y'); -$ip = $_SERVER['REMOTE_ADDR']; -require_once('../includes/config.php'); -$con = mysqli_connect($dbhost, $dbuser, $dbpassword, $dbname); - -if (mysqli_connect_errno()) { - $sql_error = mysqli_connect_error(); - die("Unable connect to database"); -} - -$query = "SELECT @last_id := MAX(id) FROM admin_history"; - -$result = mysqli_query($con, $query); - -while ($row = mysqli_fetch_array($result)) { - $last_id = $row['@last_id := MAX(id)']; -} - -$query = "SELECT * FROM admin_history WHERE id=" . Trim($last_id); -$result = mysqli_query($con, $query); - -while ($row = mysqli_fetch_array($result)) { - $last_date = $row['last_date']; - $last_ip = $row['ip']; -} - -if ($last_ip == $ip) { - if ($last_date != $date) { - $query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')"; - mysqli_query($con, $query); - } -} else { - $query = "INSERT INTO admin_history (last_date,ip) VALUES ('$date','$ip')"; - mysqli_query($con, $query); -} - -?> - - - - - - - Paste - Interface - - - - - -
- - - - - - - -
- - -
- -
- -
-
- -
-
- - - - ' . mysqli_error($con) . ' -
'; - - } else { - $msg = '
- Settings saved -
'; - } - } - ?> - - -
-
-
-
- -
-
-
-
- - -
- - - - - - - - - - - - - \ No newline at end of file diff --git a/admin/js/bootstrap-select.js b/admin/js/bootstrap-select.js deleted file mode 100644 index 5006159..0000000 --- a/admin/js/bootstrap-select.js +++ /dev/null @@ -1,1218 +0,0 @@ -/*! - * Bootstrap-select v1.6.3 (http://silviomoreto.github.io/bootstrap-select/) - * - * Copyright 2013-2014 bootstrap-select - * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE) - */ -(function ($) { - 'use strict'; - - // Case insensitive search - $.expr[':'].icontains = function (obj, index, meta) { - return icontains($(obj).text(), meta[3]); - }; - - // Case and accent insensitive search - $.expr[':'].aicontains = function (obj, index, meta) { - return icontains($(obj).data('normalizedText') || $(obj).text(), meta[3]); - }; - - /** - * Actual implementation of the case insensitive search. - * @access private - * @param {String} haystack - * @param {String} needle - * @returns {boolean} - */ - function icontains(haystack, needle) { - return haystack.toUpperCase().indexOf(needle.toUpperCase()) > -1; - } - - /** - * Remove all diatrics from the given text. - * @access private - * @param {String} text - * @returns {String} - */ - function normalizeToBase(text) { - var rExps = [ - {re: /[\xC0-\xC6]/g, ch: "A"}, - {re: /[\xE0-\xE6]/g, ch: "a"}, - {re: /[\xC8-\xCB]/g, ch: "E"}, - {re: /[\xE8-\xEB]/g, ch: "e"}, - {re: /[\xCC-\xCF]/g, ch: "I"}, - {re: /[\xEC-\xEF]/g, ch: "i"}, - {re: /[\xD2-\xD6]/g, ch: "O"}, - {re: /[\xF2-\xF6]/g, ch: "o"}, - {re: /[\xD9-\xDC]/g, ch: "U"}, - {re: /[\xF9-\xFC]/g, ch: "u"}, - {re: /[\xC7-\xE7]/g, ch: "c"}, - {re: /[\xD1]/g, ch: "N"}, - {re: /[\xF1]/g, ch: "n"} - ]; - $.each(rExps, function () { - text = text.replace(this.re, this.ch); - }); - return text; - } - - - function htmlEscape(html) { - var escapeMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`' - }; - var source = '(?:' + Object.keys(escapeMap).join('|') + ')', - testRegexp = new RegExp(source), - replaceRegexp = new RegExp(source, 'g'), - string = html == null ? '' : '' + html; - return testRegexp.test(string) ? string.replace(replaceRegexp, function (match) { - return escapeMap[match]; - }) : string; - } - - var Selectpicker = function (element, options, e) { - if (e) { - e.stopPropagation(); - e.preventDefault(); - } - - this.$element = $(element); - this.$newElement = null; - this.$button = null; - this.$menu = null; - this.$lis = null; - this.options = options; - - // If we have no title yet, try to pull it from the html title attribute (jQuery doesnt' pick it up as it's not a - // data-attribute) - if (this.options.title === null) { - this.options.title = this.$element.attr('title'); - } - - //Expose public methods - this.val = Selectpicker.prototype.val; - this.render = Selectpicker.prototype.render; - this.refresh = Selectpicker.prototype.refresh; - this.setStyle = Selectpicker.prototype.setStyle; - this.selectAll = Selectpicker.prototype.selectAll; - this.deselectAll = Selectpicker.prototype.deselectAll; - this.destroy = Selectpicker.prototype.remove; - this.remove = Selectpicker.prototype.remove; - this.show = Selectpicker.prototype.show; - this.hide = Selectpicker.prototype.hide; - - this.init(); - }; - - Selectpicker.VERSION = '1.6.3'; - - // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both. - Selectpicker.DEFAULTS = { - noneSelectedText: 'Nothing selected', - noneResultsText: 'No results match', - countSelectedText: function (numSelected, numTotal) { - return (numSelected == 1) ? "{0} item selected" : "{0} items selected"; - }, - maxOptionsText: function (numAll, numGroup) { - var arr = []; - - arr[0] = (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)'; - arr[1] = (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'; - - return arr; - }, - selectAllText: 'Select All', - deselectAllText: 'Deselect All', - multipleSeparator: ', ', - style: 'btn-light', - size: 'auto', - title: null, - selectedTextFormat: 'values', - width: false, - container: false, - hideDisabled: false, - showSubtext: false, - showIcon: true, - showContent: true, - dropupAuto: true, - header: false, - liveSearch: false, - actionsBox: false, - iconBase: 'fa', - tickIcon: 'fa-check', - maxOptions: false, - mobile: false, - selectOnTab: false, - dropdownAlignRight: false, - searchAccentInsensitive: false - }; - - Selectpicker.prototype = { - - constructor: Selectpicker, - - init: function () { - var that = this, - id = this.$element.attr('id'); - - this.$element.hide(); - this.multiple = this.$element.prop('multiple'); - this.autofocus = this.$element.prop('autofocus'); - this.$newElement = this.createView(); - this.$element.after(this.$newElement); - this.$menu = this.$newElement.find('> .dropdown-menu'); - this.$button = this.$newElement.find('> button'); - this.$searchbox = this.$newElement.find('input'); - - if (this.options.dropdownAlignRight) - this.$menu.addClass('dropdown-menu-right'); - - if (typeof id !== 'undefined') { - this.$button.attr('data-id', id); - $('label[for="' + id + '"]').click(function (e) { - e.preventDefault(); - that.$button.focus(); - }); - } - - this.checkDisabled(); - this.clickListener(); - if (this.options.liveSearch) this.liveSearchListener(); - this.render(); - this.liHeight(); - this.setStyle(); - this.setWidth(); - if (this.options.container) this.selectPosition(); - this.$menu.data('this', this); - this.$newElement.data('this', this); - if (this.options.mobile) this.mobile(); - }, - - createDropdown: function () { - // Options - // If we are multiple, then add the show-tick class by default - var multiple = this.multiple ? ' show-tick' : '', - inputGroup = this.$element.parent().hasClass('input-group') ? ' input-group-btn' : '', - autofocus = this.autofocus ? ' autofocus' : '', - btnSize = this.$element.parents().hasClass('form-group-lg') ? ' btn-lg' : (this.$element.parents().hasClass('form-group-sm') ? ' btn-sm' : ''); - // Elements - var header = this.options.header ? '
' + this.options.header + '
' : ''; - var searchbox = this.options.liveSearch ? '' : ''; - var actionsbox = this.options.actionsBox ? '
' + - '
' + - '' + - '' + - '
' + - '
' : ''; - var drop = - '
' + - '' + - '' + - '
'; - - return $(drop); - }, - - createView: function () { - var $drop = this.createDropdown(); - var $li = this.createLi(); - $drop.find('ul').append($li); - return $drop; - }, - - reloadLi: function () { - //Remove all children. - this.destroyLi(); - //Re build - var $li = this.createLi(); - this.$menu.find('ul').append($li); - }, - - destroyLi: function () { - this.$menu.find('li').remove(); - }, - - createLi: function () { - var that = this, - _li = [], - optID = 0; - - // Helper functions - /** - * @param content - * @param [index] - * @param [classes] - * @returns {string} - */ - var generateLI = function (content, index, classes) { - return '' + content + ''; - }; - - /** - * @param text - * @param [classes] - * @param [inline] - * @param [optgroup] - * @returns {string} - */ - var generateA = function (text, classes, inline, optgroup) { - var normText = normalizeToBase(htmlEscape(text)); - return '' + text + - '' + - ''; - }; - - this.$element.find('option').each(function () { - var $this = $(this); - - // Get the class and text for the option - var optionClass = $this.attr('class') || '', - inline = $this.attr('style'), - text = $this.data('content') ? $this.data('content') : $this.html(), - subtext = typeof $this.data('subtext') !== 'undefined' ? '' + $this.data('subtext') + '' : '', - icon = typeof $this.data('icon') !== 'undefined' ? ' ' : '', - isDisabled = $this.is(':disabled') || $this.parent().is(':disabled'), - index = $this[0].index; - if (icon !== '' && isDisabled) { - icon = '' + icon + ''; - } - - if (!$this.data('content')) { - // Prepend any icon and append any subtext to the main text. - text = icon + '' + text + subtext + ''; - } - - if (that.options.hideDisabled && isDisabled) { - return; - } - - if ($this.parent().is('optgroup') && $this.data('divider') !== true) { - if ($this.index() === 0) { // Is it the first option of the optgroup? - optID += 1; - - // Get the opt group label - var label = $this.parent().attr('label'); - var labelSubtext = typeof $this.parent().data('subtext') !== 'undefined' ? '' + $this.parent().data('subtext') + '' : ''; - var labelIcon = $this.parent().data('icon') ? ' ' : ''; - label = labelIcon + '' + label + labelSubtext + ''; - - if (index !== 0 && _li.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown? - _li.push(generateLI('', null, 'divider')); - } - - _li.push(generateLI(label, null, 'dropdown-header')); - } - - _li.push(generateLI(generateA(text, 'opt ' + optionClass, inline, optID), index)); - } else if ($this.data('divider') === true) { - _li.push(generateLI('', index, 'divider')); - } else if ($this.data('hidden') === true) { - _li.push(generateLI(generateA(text, optionClass, inline), index, 'hide is-hidden')); - } else { - _li.push(generateLI(generateA(text, optionClass, inline), index)); - } - }); - - //If we are not multiple, we don't have a selected item, and we don't have a title, select the first element so something is set in the button - if (!this.multiple && this.$element.find('option:selected').length === 0 && !this.options.title) { - this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected'); - } - - return $(_li.join('')); - }, - - findLis: function () { - if (this.$lis == null) this.$lis = this.$menu.find('li'); - return this.$lis; - }, - - /** - * @param [updateLi] defaults to true - */ - render: function (updateLi) { - var that = this; - - //Update the LI to match the SELECT - if (updateLi !== false) { - this.$element.find('option').each(function (index) { - that.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled')); - that.setSelected(index, $(this).is(':selected')); - }); - } - - this.tabIndex(); - var notDisabled = this.options.hideDisabled ? ':not([disabled])' : ''; - var selectedItems = this.$element.find('option:selected' + notDisabled).map(function () { - var $this = $(this); - var icon = $this.data('icon') && that.options.showIcon ? ' ' : ''; - var subtext; - if (that.options.showSubtext && $this.attr('data-subtext') && !that.multiple) { - subtext = ' ' + $this.data('subtext') + ''; - } else { - subtext = ''; - } - if ($this.data('content') && that.options.showContent) { - return $this.data('content'); - } else if (typeof $this.attr('title') !== 'undefined') { - return $this.attr('title'); - } else { - return icon + $this.html() + subtext; - } - }).toArray(); - - //Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled - //Convert all the values into a comma delimited string - var title = !this.multiple ? selectedItems[0] : selectedItems.join(this.options.multipleSeparator); - - //If this is multi select, and the selectText type is count, the show 1 of 2 selected etc.. - if (this.multiple && this.options.selectedTextFormat.indexOf('count') > -1) { - var max = this.options.selectedTextFormat.split('>'); - if ((max.length > 1 && selectedItems.length > max[1]) || (max.length == 1 && selectedItems.length >= 2)) { - notDisabled = this.options.hideDisabled ? ', [disabled]' : ''; - var totalCount = this.$element.find('option').not('[data-divider="true"], [data-hidden="true"]' + notDisabled).length, - tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedItems.length, totalCount) : this.options.countSelectedText; - title = tr8nText.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString()); - } - } - - this.options.title = this.$element.attr('title'); - - if (this.options.selectedTextFormat == 'static') { - title = this.options.title; - } - - //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text - if (!title) { - title = typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText; - } - - this.$button.attr('title', htmlEscape(title)); - this.$newElement.find('.filter-option').html(title); - }, - - /** - * @param [style] - * @param [status] - */ - setStyle: function (style, status) { - if (this.$element.attr('class')) { - this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|validate\[.*\]/gi, '')); - } - - var buttonClass = style ? style : this.options.style; - - if (status == 'add') { - this.$button.addClass(buttonClass); - } else if (status == 'remove') { - this.$button.removeClass(buttonClass); - } else { - this.$button.removeClass(this.options.style); - this.$button.addClass(buttonClass); - } - }, - - liHeight: function () { - if (this.options.size === false) return; - - var $selectClone = this.$menu.parent().clone().find('> .dropdown-toggle').prop('autofocus', false).end().appendTo('body'), - $menuClone = $selectClone.addClass('open').find('> .dropdown-menu'), - liHeight = $menuClone.find('li').not('.divider').not('.dropdown-header').filter(':visible').children('a').outerHeight(), - headerHeight = this.options.header ? $menuClone.find('.popover-title').outerHeight() : 0, - searchHeight = this.options.liveSearch ? $menuClone.find('.bs-searchbox').outerHeight() : 0, - actionsHeight = this.options.actionsBox ? $menuClone.find('.bs-actionsbox').outerHeight() : 0; - - $selectClone.remove(); - - this.$newElement - .data('liHeight', liHeight) - .data('headerHeight', headerHeight) - .data('searchHeight', searchHeight) - .data('actionsHeight', actionsHeight); - }, - - setSize: function () { - this.findLis(); - var that = this, - menu = this.$menu, - menuInner = menu.find('.inner'), - selectHeight = this.$newElement.outerHeight(), - liHeight = this.$newElement.data('liHeight'), - headerHeight = this.$newElement.data('headerHeight'), - searchHeight = this.$newElement.data('searchHeight'), - actionsHeight = this.$newElement.data('actionsHeight'), - divHeight = this.$lis.filter('.divider').outerHeight(true), - menuPadding = parseInt(menu.css('padding-top')) + - parseInt(menu.css('padding-bottom')) + - parseInt(menu.css('border-top-width')) + - parseInt(menu.css('border-bottom-width')), - notDisabled = this.options.hideDisabled ? ', .disabled' : '', - $window = $(window), - menuExtras = menuPadding + parseInt(menu.css('margin-top')) + parseInt(menu.css('margin-bottom')) + 2, - menuHeight, - selectOffsetTop, - selectOffsetBot, - posVert = function () { - // JQuery defines a scrollTop function, but in pure JS it's a property - //noinspection JSValidateTypes - selectOffsetTop = that.$newElement.offset().top - $window.scrollTop(); - selectOffsetBot = $window.height() - selectOffsetTop - selectHeight; - }; - posVert(); - if (this.options.header) menu.css('padding-top', 0); - - if (this.options.size == 'auto') { - var getSize = function () { - var minHeight, - lisVis = that.$lis.not('.hide'); - - posVert(); - menuHeight = selectOffsetBot - menuExtras; - - if (that.options.dropupAuto) { - that.$newElement.toggleClass('dropup', (selectOffsetTop > selectOffsetBot) && ((menuHeight - menuExtras) < menu.height())); - } - if (that.$newElement.hasClass('dropup')) { - menuHeight = selectOffsetTop - menuExtras; - } - - if ((lisVis.length + lisVis.filter('.dropdown-header').length) > 3) { - minHeight = liHeight * 3 + menuExtras - 2; - } else { - minHeight = 0; - } - - menu.css({ - 'max-height': menuHeight + 'px', - 'overflow': 'hidden', - 'min-height': minHeight + headerHeight + searchHeight + actionsHeight + 'px' - }); - menuInner.css({ - 'max-height': menuHeight - headerHeight - searchHeight - actionsHeight - menuPadding + 'px', - 'overflow-y': 'auto', - 'min-height': Math.max(minHeight - menuPadding, 0) + 'px' - }); - }; - getSize(); - this.$searchbox.off('input.getSize propertychange.getSize').on('input.getSize propertychange.getSize', getSize); - $(window).off('resize.getSize').on('resize.getSize', getSize); - $(window).off('scroll.getSize').on('scroll.getSize', getSize); - } else if (this.options.size && this.options.size != 'auto' && menu.find('li' + notDisabled).length > this.options.size) { - var optIndex = this.$lis.not('.divider' + notDisabled).find(' > *').slice(0, this.options.size).last().parent().index(); - var divLength = this.$lis.slice(0, optIndex + 1).filter('.divider').length; - menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding; - if (that.options.dropupAuto) { - //noinspection JSUnusedAssignment - this.$newElement.toggleClass('dropup', (selectOffsetTop > selectOffsetBot) && (menuHeight < menu.height())); - } - menu.css({ - 'max-height': menuHeight + headerHeight + searchHeight + actionsHeight + 'px', - 'overflow': 'hidden' - }); - menuInner.css({'max-height': menuHeight - menuPadding + 'px', 'overflow-y': 'auto'}); - } - }, - - setWidth: function () { - if (this.options.width == 'auto') { - this.$menu.css('min-width', '0'); - - // Get correct width if element hidden - var selectClone = this.$newElement.clone().appendTo('body'); - var ulWidth = selectClone.find('> .dropdown-menu').css('width'); - var btnWidth = selectClone.css('width', 'auto').find('> button').css('width'); - selectClone.remove(); - - // Set width to whatever's larger, button title or longest option - this.$newElement.css('width', Math.max(parseInt(ulWidth), parseInt(btnWidth)) + 'px'); - } else if (this.options.width == 'fit') { - // Remove inline min-width so width can be changed from 'auto' - this.$menu.css('min-width', ''); - this.$newElement.css('width', '').addClass('fit-width'); - } else if (this.options.width) { - // Remove inline min-width so width can be changed from 'auto' - this.$menu.css('min-width', ''); - this.$newElement.css('width', this.options.width); - } else { - // Remove inline min-width/width so width can be changed - this.$menu.css('min-width', ''); - this.$newElement.css('width', ''); - } - // Remove fit-width class if width is changed programmatically - if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') { - this.$newElement.removeClass('fit-width'); - } - }, - - selectPosition: function () { - var that = this, - drop = '
', - $drop = $(drop), - pos, - actualHeight, - getPlacement = function ($element) { - $drop.addClass($element.attr('class').replace(/form-control/gi, '')).toggleClass('dropup', $element.hasClass('dropup')); - pos = $element.offset(); - actualHeight = $element.hasClass('dropup') ? 0 : $element[0].offsetHeight; - $drop.css({ - 'top': pos.top + actualHeight, - 'left': pos.left, - 'width': $element[0].offsetWidth, - 'position': 'absolute' - }); - }; - this.$newElement.on('click', function () { - if (that.isDisabled()) { - return; - } - getPlacement($(this)); - $drop.appendTo(that.options.container); - $drop.toggleClass('open', !$(this).hasClass('open')); - $drop.append(that.$menu); - }); - $(window).resize(function () { - getPlacement(that.$newElement); - }); - $(window).on('scroll', function () { - getPlacement(that.$newElement); - }); - $('html').on('click', function (e) { - if ($(e.target).closest(that.$newElement).length < 1) { - $drop.removeClass('open'); - } - }); - }, - - setSelected: function (index, selected) { - this.findLis(); - this.$lis.filter('[data-original-index="' + index + '"]').toggleClass('selected', selected); - }, - - setDisabled: function (index, disabled) { - this.findLis(); - if (disabled) { - this.$lis.filter('[data-original-index="' + index + '"]').addClass('disabled').find('a').attr('href', '#').attr('tabindex', -1); - } else { - this.$lis.filter('[data-original-index="' + index + '"]').removeClass('disabled').find('a').removeAttr('href').attr('tabindex', 0); - } - }, - - isDisabled: function () { - return this.$element.is(':disabled'); - }, - - checkDisabled: function () { - var that = this; - - if (this.isDisabled()) { - this.$button.addClass('disabled').attr('tabindex', -1); - } else { - if (this.$button.hasClass('disabled')) { - this.$button.removeClass('disabled'); - } - - if (this.$button.attr('tabindex') == -1) { - if (!this.$element.data('tabindex')) this.$button.removeAttr('tabindex'); - } - } - - this.$button.click(function () { - return !that.isDisabled(); - }); - }, - - tabIndex: function () { - if (this.$element.is('[tabindex]')) { - this.$element.data('tabindex', this.$element.attr('tabindex')); - this.$button.attr('tabindex', this.$element.data('tabindex')); - } - }, - - clickListener: function () { - var that = this; - - this.$newElement.on('touchstart.dropdown', '.dropdown-menu', function (e) { - e.stopPropagation(); - }); - - this.$newElement.on('click', function () { - that.setSize(); - if (!that.options.liveSearch && !that.multiple) { - setTimeout(function () { - that.$menu.find('.selected a').focus(); - }, 10); - } - }); - - this.$menu.on('click', 'li a', function (e) { - var $this = $(this), - clickedIndex = $this.parent().data('originalIndex'), - prevValue = that.$element.val(), - prevIndex = that.$element.prop('selectedIndex'); - - // Don't close on multi choice menu - if (that.multiple) { - e.stopPropagation(); - } - - e.preventDefault(); - - //Don't run if we have been disabled - if (!that.isDisabled() && !$this.parent().hasClass('disabled')) { - var $options = that.$element.find('option'), - $option = $options.eq(clickedIndex), - state = $option.prop('selected'), - $optgroup = $option.parent('optgroup'), - maxOptions = that.options.maxOptions, - maxOptionsGrp = $optgroup.data('maxOptions') || false; - - if (!that.multiple) { // Deselect all others if not multi select box - $options.prop('selected', false); - $option.prop('selected', true); - that.$menu.find('.selected').removeClass('selected'); - that.setSelected(clickedIndex, true); - } else { // Toggle the one we have chosen if we are multi select. - $option.prop('selected', !state); - that.setSelected(clickedIndex, !state); - $this.blur(); - - if ((maxOptions !== false) || (maxOptionsGrp !== false)) { - var maxReached = maxOptions < $options.filter(':selected').length, - maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length; - - if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) { - if (maxOptions && maxOptions == 1) { - $options.prop('selected', false); - $option.prop('selected', true); - that.$menu.find('.selected').removeClass('selected'); - that.setSelected(clickedIndex, true); - } else if (maxOptionsGrp && maxOptionsGrp == 1) { - $optgroup.find('option:selected').prop('selected', false); - $option.prop('selected', true); - var optgroupID = $this.data('optgroup'); - - that.$menu.find('.selected').has('a[data-optgroup="' + optgroupID + '"]').removeClass('selected'); - - that.setSelected(clickedIndex, true); - } else { - var maxOptionsArr = (typeof that.options.maxOptionsText === 'function') ? - that.options.maxOptionsText(maxOptions, maxOptionsGrp) : that.options.maxOptionsText, - maxTxt = maxOptionsArr[0].replace('{n}', maxOptions), - maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp), - $notify = $('
'); - // If {var} is set in array, replace it - /** @deprecated */ - if (maxOptionsArr[2]) { - maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]); - maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]); - } - - $option.prop('selected', false); - - that.$menu.append($notify); - - if (maxOptions && maxReached) { - $notify.append($('
' + maxTxt + '
')); - that.$element.trigger('maxReached.bs.select'); - } - - if (maxOptionsGrp && maxReachedGrp) { - $notify.append($('
' + maxTxtGrp + '
')); - that.$element.trigger('maxReachedGrp.bs.select'); - } - - setTimeout(function () { - that.setSelected(clickedIndex, false); - }, 10); - - $notify.delay(750).fadeOut(300, function () { - $(this).remove(); - }); - } - } - } - } - - if (!that.multiple) { - that.$button.focus(); - } else if (that.options.liveSearch) { - that.$searchbox.focus(); - } - - // Trigger select 'change' - if ((prevValue != that.$element.val() && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) { - that.$element.change(); - } - } - }); - - this.$menu.on('click', 'li.disabled a, .popover-title, .popover-title :not(.close)', function (e) { - if (e.target == this) { - e.preventDefault(); - e.stopPropagation(); - if (!that.options.liveSearch) { - that.$button.focus(); - } else { - that.$searchbox.focus(); - } - } - }); - - this.$menu.on('click', 'li.divider, li.dropdown-header', function (e) { - e.preventDefault(); - e.stopPropagation(); - if (!that.options.liveSearch) { - that.$button.focus(); - } else { - that.$searchbox.focus(); - } - }); - - this.$menu.on('click', '.popover-title .close', function () { - that.$button.focus(); - }); - - this.$searchbox.on('click', function (e) { - e.stopPropagation(); - }); - - - this.$menu.on('click', '.actions-btn', function (e) { - if (that.options.liveSearch) { - that.$searchbox.focus(); - } else { - that.$button.focus(); - } - - e.preventDefault(); - e.stopPropagation(); - - if ($(this).is('.bs-select-all')) { - that.selectAll(); - } else { - that.deselectAll(); - } - that.$element.change(); - }); - - this.$element.change(function () { - that.render(false); - }); - }, - - liveSearchListener: function () { - var that = this, - no_results = $('
  • '); - - this.$newElement.on('click.dropdown.data-api touchstart.dropdown.data-api', function () { - that.$menu.find('.active').removeClass('active'); - if (!!that.$searchbox.val()) { - that.$searchbox.val(''); - that.$lis.not('.is-hidden').removeClass('hide'); - if (!!no_results.parent().length) no_results.remove(); - } - if (!that.multiple) that.$menu.find('.selected').addClass('active'); - setTimeout(function () { - that.$searchbox.focus(); - }, 10); - }); - - this.$searchbox.on('click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api', function (e) { - e.stopPropagation(); - }); - - this.$searchbox.on('input propertychange', function () { - if (that.$searchbox.val()) { - - if (that.options.searchAccentInsensitive) { - that.$lis.not('.is-hidden').removeClass('hide').find('a').not(':aicontains(' + normalizeToBase(that.$searchbox.val()) + ')').parent().addClass('hide'); - } else { - that.$lis.not('.is-hidden').removeClass('hide').find('a').not(':icontains(' + that.$searchbox.val() + ')').parent().addClass('hide'); - } - - if (!that.$menu.find('li').filter(':visible:not(.no-results)').length) { - if (!!no_results.parent().length) no_results.remove(); - no_results.html(that.options.noneResultsText + ' "' + htmlEscape(that.$searchbox.val()) + '"').show(); - that.$menu.find('li').last().after(no_results); - } else if (!!no_results.parent().length) { - no_results.remove(); - } - - } else { - that.$lis.not('.is-hidden').removeClass('hide'); - if (!!no_results.parent().length) no_results.remove(); - } - - that.$menu.find('li.active').removeClass('active'); - that.$menu.find('li').filter(':visible:not(.divider)').eq(0).addClass('active').find('a').focus(); - $(this).focus(); - }); - }, - - val: function (value) { - if (typeof value !== 'undefined') { - this.$element.val(value); - this.render(); - - return this.$element; - } else { - return this.$element.val(); - } - }, - - selectAll: function () { - this.findLis(); - this.$lis.not('.divider').not('.disabled').not('.selected').filter(':visible').find('a').click(); - }, - - deselectAll: function () { - this.findLis(); - this.$lis.not('.divider').not('.disabled').filter('.selected').filter(':visible').find('a').click(); - }, - - keydown: function (e) { - var $this = $(this), - $parent = ($this.is('input')) ? $this.parent().parent() : $this.parent(), - $items, - that = $parent.data('this'), - index, - next, - first, - last, - prev, - nextPrev, - prevIndex, - isActive, - keyCodeMap = { - 32: ' ', - 48: '0', - 49: '1', - 50: '2', - 51: '3', - 52: '4', - 53: '5', - 54: '6', - 55: '7', - 56: '8', - 57: '9', - 59: ';', - 65: 'a', - 66: 'b', - 67: 'c', - 68: 'd', - 69: 'e', - 70: 'f', - 71: 'g', - 72: 'h', - 73: 'i', - 74: 'j', - 75: 'k', - 76: 'l', - 77: 'm', - 78: 'n', - 79: 'o', - 80: 'p', - 81: 'q', - 82: 'r', - 83: 's', - 84: 't', - 85: 'u', - 86: 'v', - 87: 'w', - 88: 'x', - 89: 'y', - 90: 'z', - 96: '0', - 97: '1', - 98: '2', - 99: '3', - 100: '4', - 101: '5', - 102: '6', - 103: '7', - 104: '8', - 105: '9' - }; - - if (that.options.liveSearch) $parent = $this.parent().parent(); - - if (that.options.container) $parent = that.$menu; - - $items = $('[role=menu] li a', $parent); - - isActive = that.$menu.parent().hasClass('open'); - - if (!isActive && /([0-9]|[A-z])/.test(String.fromCharCode(e.keyCode))) { - if (!that.options.container) { - that.setSize(); - that.$menu.parent().addClass('open'); - isActive = true; - } else { - that.$newElement.trigger('click'); - } - that.$searchbox.focus(); - } - - if (that.options.liveSearch) { - if (/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && that.$menu.find('.active').length === 0) { - e.preventDefault(); - that.$menu.parent().removeClass('open'); - that.$button.focus(); - } - $items = $('[role=menu] li:not(.divider):not(.dropdown-header):visible', $parent); - if (!$this.val() && !/(38|40)/.test(e.keyCode.toString(10))) { - if ($items.filter('.active').length === 0) { - if (that.options.searchAccentInsensitive) { - $items = that.$newElement.find('li').filter(':aicontains(' + normalizeToBase(keyCodeMap[e.keyCode]) + ')'); - } else { - $items = that.$newElement.find('li').filter(':icontains(' + keyCodeMap[e.keyCode] + ')'); - } - } - } - } - - if (!$items.length) return; - - if (/(38|40)/.test(e.keyCode.toString(10))) { - index = $items.index($items.filter(':focus')); - first = $items.parent(':not(.disabled):visible').first().index(); - last = $items.parent(':not(.disabled):visible').last().index(); - next = $items.eq(index).parent().nextAll(':not(.disabled):visible').eq(0).index(); - prev = $items.eq(index).parent().prevAll(':not(.disabled):visible').eq(0).index(); - nextPrev = $items.eq(next).parent().prevAll(':not(.disabled):visible').eq(0).index(); - - if (that.options.liveSearch) { - $items.each(function (i) { - if ($(this).is(':not(.disabled)')) { - $(this).data('index', i); - } - }); - index = $items.index($items.filter('.active')); - first = $items.filter(':not(.disabled):visible').first().data('index'); - last = $items.filter(':not(.disabled):visible').last().data('index'); - next = $items.eq(index).nextAll(':not(.disabled):visible').eq(0).data('index'); - prev = $items.eq(index).prevAll(':not(.disabled):visible').eq(0).data('index'); - nextPrev = $items.eq(next).prevAll(':not(.disabled):visible').eq(0).data('index'); - } - - prevIndex = $this.data('prevIndex'); - - if (e.keyCode == 38) { - if (that.options.liveSearch) index -= 1; - if (index != nextPrev && index > prev) index = prev; - if (index < first) index = first; - if (index == prevIndex) index = last; - } - - if (e.keyCode == 40) { - if (that.options.liveSearch) index += 1; - if (index == -1) index = 0; - if (index != nextPrev && index < next) index = next; - if (index > last) index = last; - if (index == prevIndex) index = first; - } - - $this.data('prevIndex', index); - - if (!that.options.liveSearch) { - $items.eq(index).focus(); - } else { - e.preventDefault(); - if (!$this.is('.dropdown-toggle')) { - $items.removeClass('active'); - $items.eq(index).addClass('active').find('a').focus(); - $this.focus(); - } - } - - } else if (!$this.is('input')) { - var keyIndex = [], - count, - prevKey; - - $items.each(function () { - if ($(this).parent().is(':not(.disabled)')) { - if ($.trim($(this).text().toLowerCase()).substring(0, 1) == keyCodeMap[e.keyCode]) { - keyIndex.push($(this).parent().index()); - } - } - }); - - count = $(document).data('keycount'); - count++; - $(document).data('keycount', count); - - prevKey = $.trim($(':focus').text().toLowerCase()).substring(0, 1); - - if (prevKey != keyCodeMap[e.keyCode]) { - count = 1; - $(document).data('keycount', count); - } else if (count >= keyIndex.length) { - $(document).data('keycount', 0); - if (count > keyIndex.length) count = 1; - } - - $items.eq(keyIndex[count - 1]).focus(); - } - - // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu. - if ((/(13|32)/.test(e.keyCode.toString(10)) || (/(^9$)/.test(e.keyCode.toString(10)) && that.options.selectOnTab)) && isActive) { - if (!/(32)/.test(e.keyCode.toString(10))) e.preventDefault(); - if (!that.options.liveSearch) { - $(':focus').click(); - } else if (!/(32)/.test(e.keyCode.toString(10))) { - that.$menu.find('.active a').click(); - $this.focus(); - } - $(document).data('keycount', 0); - } - - if ((/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && (that.multiple || that.options.liveSearch)) || (/(27)/.test(e.keyCode.toString(10)) && !isActive)) { - that.$menu.parent().removeClass('open'); - that.$button.focus(); - } - }, - - mobile: function () { - this.$element.addClass('mobile-device').appendTo(this.$newElement); - if (this.options.container) this.$menu.hide(); - }, - - refresh: function () { - this.$lis = null; - this.reloadLi(); - this.render(); - this.setWidth(); - this.setStyle(); - this.checkDisabled(); - this.liHeight(); - }, - - update: function () { - this.reloadLi(); - this.setWidth(); - this.setStyle(); - this.checkDisabled(); - this.liHeight(); - }, - - hide: function () { - this.$newElement.hide(); - }, - - show: function () { - this.$newElement.show(); - }, - - remove: function () { - this.$newElement.remove(); - this.$element.remove(); - } - }; - - // SELECTPICKER PLUGIN DEFINITION - // ============================== - function Plugin(option, event) { - // get the args of the outer function.. - var args = arguments; - // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them - // to get lost - //noinspection JSDuplicatedDeclaration - var _option = option, - option = args[0], - event = args[1]; - [].shift.apply(args); - - // This fixes a bug in the js implementation on android 2.3 #715 - if (typeof option == 'undefined') { - option = _option; - } - - var value; - var chain = this.each(function () { - var $this = $(this); - if ($this.is('select')) { - var data = $this.data('selectpicker'), - options = typeof option == 'object' && option; - - if (!data) { - var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, $this.data(), options); - $this.data('selectpicker', (data = new Selectpicker(this, config, event))); - } else if (options) { - for (var i in options) { - if (options.hasOwnProperty(i)) { - data.options[i] = options[i]; - } - } - } - - if (typeof option == 'string') { - if (data[option] instanceof Function) { - value = data[option].apply(data, args); - } else { - value = data.options[option]; - } - } - } - }); - - if (typeof value !== 'undefined') { - //noinspection JSUnusedAssignment - return value; - } else { - return chain; - } - } - - var old = $.fn.selectpicker; - $.fn.selectpicker = Plugin; - $.fn.selectpicker.Constructor = Selectpicker; - - // SELECTPICKER NO CONFLICT - // ======================== - $.fn.selectpicker.noConflict = function () { - $.fn.selectpicker = old; - return this; - }; - - $(document) - .data('keycount', 0) - .on('keydown', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bs-searchbox input', Selectpicker.prototype.keydown) - .on('focusin.modal', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bs-searchbox input', function (e) { - e.stopPropagation(); - }); - - // SELECTPICKER DATA-API - // ===================== - $(window).on('load.bs.select.data-api', function () { - $('.selectpicker').each(function () { - var $selectpicker = $(this); - Plugin.call($selectpicker, $selectpicker.data()); - }) - }); -})(jQuery); \ No newline at end of file diff --git a/admin/js/bootstrap.min.js b/admin/js/bootstrap.min.js deleted file mode 100644 index c6d3692..0000000 --- a/admin/js/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v3.3.2 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.2",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.2",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.2",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.2",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.2",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('