Blacklist
This commit is contained in:
parent
b9faad4175
commit
8f41184f74
@ -1,7 +1,6 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/app/http/template"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database/table"
|
||||
@ -50,23 +49,63 @@ func BlacklistHandler(ctx *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
curid, err := strconv.ParseInt("210105426849562625", 10, 64)
|
||||
table.RemoveBlacklist(guildId, curid)
|
||||
fmt.Println(table.IsBlacklisted(guildId, curid))
|
||||
blacklistedUsers := table.GetBlacklistNodes(guildId)
|
||||
|
||||
//blacklistedUsers := table.GetBlacklistNodes(guildId)
|
||||
//var blacklisted []map[string]interface{}
|
||||
//for _, node := range blacklistedUsers {
|
||||
var blacklistedIds []int64
|
||||
for _, user := range blacklistedUsers {
|
||||
blacklistedIds = append(blacklistedIds, user.User)
|
||||
}
|
||||
|
||||
//}
|
||||
usernames := table.GetUsernames(blacklistedIds)
|
||||
|
||||
fmt.Println(len(guild.Members))
|
||||
var blacklisted []map[string]interface{}
|
||||
for _, node := range blacklistedUsers {
|
||||
blacklisted = append(blacklisted, map[string]interface{}{
|
||||
"userId": node.User,
|
||||
"username": usernames[node.User],
|
||||
})
|
||||
}
|
||||
|
||||
userNotFound := false
|
||||
isStaff := false
|
||||
if store.Get("csrf").(string) == ctx.Query("csrf") { // CSRF is correct *and* set
|
||||
targetIdStr := ctx.Query("userid")
|
||||
targetId, err := strconv.ParseInt(targetIdStr, 10, 64)
|
||||
|
||||
if err != nil {
|
||||
userNotFound = true
|
||||
} else {
|
||||
// Verify that the user ID is real and in a shared guild
|
||||
username := table.GetUsername(targetId)
|
||||
exists := username != ""
|
||||
|
||||
if exists {
|
||||
if guild.OwnerId == targetIdStr || table.IsSupport(guildId, targetId) { // Prevent users from blacklisting staff
|
||||
isStaff = true
|
||||
} else {
|
||||
if !utils.Contains(blacklistedIds, targetId) { // Prevent duplicates
|
||||
table.AddBlacklist(guildId, targetId)
|
||||
blacklisted = append(blacklisted, map[string]interface{}{
|
||||
"userId": targetIdStr,
|
||||
"username": username,
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
userNotFound = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
utils.Respond(ctx, template.TemplateBlacklist.Render(map[string]interface{}{
|
||||
"name": store.Get("name").(string),
|
||||
"guildId": guildIdStr,
|
||||
"csrf": store.Get("csrf").(string),
|
||||
"avatar": store.Get("avatar").(string),
|
||||
"baseUrl": config.Conf.Server.BaseUrl,
|
||||
"blacklisted": blacklisted,
|
||||
"userNotFound": userNotFound,
|
||||
"isStaff": isStaff,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
63
app/http/endpoints/manage/blacklistremove.go
Normal file
63
app/http/endpoints/manage/blacklistremove.go
Normal file
@ -0,0 +1,63 @@
|
||||
package manage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/database/table"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func BlacklistRemoveHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
userIdStr := store.Get("userid").(string)
|
||||
userId, err := utils.GetUserId(store)
|
||||
if err != nil {
|
||||
ctx.String(500, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Verify the guild exists
|
||||
guildIdStr := ctx.Param("id")
|
||||
guildId, err := strconv.ParseInt(guildIdStr, 10, 64)
|
||||
if err != nil {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 404 Page
|
||||
return
|
||||
}
|
||||
|
||||
// Get object for selected guild
|
||||
var guild objects.Guild
|
||||
for _, g := range table.GetGuilds(userIdStr) {
|
||||
if g.Id == guildIdStr {
|
||||
guild = g
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the user has permissions to be here
|
||||
if !guild.Owner && !table.IsAdmin(guildId, userId) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl) // TODO: 403 Page
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Query("c") == store.Get("csrf").(string) {
|
||||
targetIdStr := ctx.Param("user")
|
||||
targetId, err := strconv.ParseInt(targetIdStr, 10, 64)
|
||||
|
||||
if err == nil { // If it's a real ID
|
||||
table.RemoveBlacklist(guildId, targetId)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Redirect(302, fmt.Sprintf("/manage/%s/blacklist", guildIdStr))
|
||||
}
|
||||
}
|
@ -59,6 +59,9 @@ func StartServer() {
|
||||
// /manage/:id/blacklist
|
||||
router.GET("/manage/:id/blacklist", manage.BlacklistHandler)
|
||||
|
||||
// /manage/:id/blacklist/remove/:user
|
||||
router.GET("/manage/:id/blacklist/remove/:user", manage.BlacklistRemoveHandler)
|
||||
|
||||
if err := router.Run(config.Conf.Server.Host); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -25,8 +25,20 @@ func GetAdminGuilds(userId int64) []int64 {
|
||||
return ids
|
||||
}
|
||||
|
||||
func IsSupport(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsSupport
|
||||
}
|
||||
|
||||
func IsAdmin(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsAdmin
|
||||
}
|
||||
|
||||
func IsStaff(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsAdmin || node.IsSupport
|
||||
}
|
||||
|
40
database/table/username.go
Normal file
40
database/table/username.go
Normal file
@ -0,0 +1,40 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type UsernameNode struct {
|
||||
Id int64 `gorm:"column:USERID;primary_key"`
|
||||
Name string `gorm:"column:USERNAME;type:text"` // Base 64 encoded
|
||||
}
|
||||
|
||||
func (UsernameNode) TableName() string {
|
||||
return "usernames"
|
||||
}
|
||||
|
||||
func GetUsername(id int64) string {
|
||||
node := UsernameNode{Name: "Unknown"}
|
||||
database.Database.Where(&UsernameNode{Id: id}).First(&node)
|
||||
return base64Decode(node.Name)
|
||||
}
|
||||
|
||||
func GetUsernames(ids []int64) map[int64]string {
|
||||
var nodes []UsernameNode
|
||||
database.Database.Where(ids).Find(&nodes)
|
||||
|
||||
m := make(map[int64]string)
|
||||
for _, node := range nodes {
|
||||
m[node.Id] = base64Decode(node.Name)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func base64Decode(s string) string {
|
||||
b, err := base64.StdEncoding.DecodeString(s); if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
}
|
6
public/static/css/animate.min.css
vendored
Normal file
6
public/static/css/animate.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
5
public/static/css/bootstrap.min.css
vendored
Normal file
5
public/static/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
3869
public/static/css/light-bootstrap-dashboard.css
Normal file
3869
public/static/css/light-bootstrap-dashboard.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
public/static/img/favicon.ico
Normal file
BIN
public/static/img/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
14
public/static/img/loading-bubbles.svg
Normal file
14
public/static/img/loading-bubbles.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="white">
|
||||
<circle transform="translate(8 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
<circle transform="translate(16 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0.3"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
<circle transform="translate(24 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0.6"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
</svg>
|
After Width: | Height: | Size: 950 B |
BIN
public/static/img/sidebar-2.jpg
Normal file
BIN
public/static/img/sidebar-2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 127 KiB |
404
public/static/js/bootstrap-notify.js
vendored
Normal file
404
public/static/js/bootstrap-notify.js
vendored
Normal file
@ -0,0 +1,404 @@
|
||||
/*
|
||||
|
||||
|
||||
|
||||
Creative Tim Modifications
|
||||
|
||||
Lines: 239, 240 was changed from top: 5px to top: 50% and we added margin-top: -13px. In this way the close button will be aligned vertically
|
||||
Line:242 - modified when the icon is set, we add the class "alert-with-icon", so there will be enough space for the icon.
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Project: Bootstrap Notify = v3.1.5
|
||||
* Description: Turns standard Bootstrap alerts into "Growl-like" notifications.
|
||||
* Author: Mouse0270 aka Robert McIntosh
|
||||
* License: MIT License
|
||||
* Website: https://github.com/mouse0270/bootstrap-growl
|
||||
*/
|
||||
|
||||
/* global define:false, require: false, jQuery:false */
|
||||
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['jquery'], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node/CommonJS
|
||||
factory(require('jquery'));
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
// Create the defaults once
|
||||
var defaults = {
|
||||
element: 'body',
|
||||
position: null,
|
||||
type: "info",
|
||||
allow_dismiss: true,
|
||||
allow_duplicates: true,
|
||||
newest_on_top: false,
|
||||
showProgressbar: false,
|
||||
placement: {
|
||||
from: "top",
|
||||
align: "right"
|
||||
},
|
||||
offset: 20,
|
||||
spacing: 10,
|
||||
z_index: 1031,
|
||||
delay: 5000,
|
||||
timer: 1000,
|
||||
url_target: '_blank',
|
||||
mouse_over: null,
|
||||
animate: {
|
||||
enter: 'animated fadeInDown',
|
||||
exit: 'animated fadeOutUp'
|
||||
},
|
||||
onShow: null,
|
||||
onShown: null,
|
||||
onClose: null,
|
||||
onClosed: null,
|
||||
icon_type: 'class',
|
||||
template: '<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss">×</button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'
|
||||
};
|
||||
|
||||
String.format = function () {
|
||||
var str = arguments[0];
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
str = str.replace(RegExp("\\{" + (i - 1) + "\\}", "gm"), arguments[i]);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
function isDuplicateNotification(notification) {
|
||||
var isDupe = false;
|
||||
|
||||
$('[data-notify="container"]').each(function (i, el) {
|
||||
var $el = $(el);
|
||||
var title = $el.find('[data-notify="title"]').text().trim();
|
||||
var message = $el.find('[data-notify="message"]').html().trim();
|
||||
|
||||
// The input string might be different than the actual parsed HTML string!
|
||||
// (<br> vs <br /> for example)
|
||||
// So we have to force-parse this as HTML here!
|
||||
var isSameTitle = title === $("<div>" + notification.settings.content.title + "</div>").html().trim();
|
||||
var isSameMsg = message === $("<div>" + notification.settings.content.message + "</div>").html().trim();
|
||||
var isSameType = $el.hasClass('alert-' + notification.settings.type);
|
||||
|
||||
if (isSameTitle && isSameMsg && isSameType) {
|
||||
//we found the dupe. Set the var and stop checking.
|
||||
isDupe = true;
|
||||
}
|
||||
return !isDupe;
|
||||
});
|
||||
|
||||
return isDupe;
|
||||
}
|
||||
|
||||
function Notify(element, content, options) {
|
||||
// Setup Content of Notify
|
||||
var contentObj = {
|
||||
content: {
|
||||
message: typeof content === 'object' ? content.message : content,
|
||||
title: content.title ? content.title : '',
|
||||
icon: content.icon ? content.icon : '',
|
||||
url: content.url ? content.url : '#',
|
||||
target: content.target ? content.target : '-'
|
||||
}
|
||||
};
|
||||
|
||||
options = $.extend(true, {}, contentObj, options);
|
||||
this.settings = $.extend(true, {}, defaults, options);
|
||||
this._defaults = defaults;
|
||||
if (this.settings.content.target === "-") {
|
||||
this.settings.content.target = this.settings.url_target;
|
||||
}
|
||||
this.animations = {
|
||||
start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
|
||||
end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
|
||||
};
|
||||
|
||||
if (typeof this.settings.offset === 'number') {
|
||||
this.settings.offset = {
|
||||
x: this.settings.offset,
|
||||
y: this.settings.offset
|
||||
};
|
||||
}
|
||||
|
||||
//if duplicate messages are not allowed, then only continue if this new message is not a duplicate of one that it already showing
|
||||
if (this.settings.allow_duplicates || (!this.settings.allow_duplicates && !isDuplicateNotification(this))) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
|
||||
$.extend(Notify.prototype, {
|
||||
init: function () {
|
||||
var self = this;
|
||||
|
||||
this.buildNotify();
|
||||
if (this.settings.content.icon) {
|
||||
this.setIcon();
|
||||
}
|
||||
if (this.settings.content.url != "#") {
|
||||
this.styleURL();
|
||||
}
|
||||
this.styleDismiss();
|
||||
this.placement();
|
||||
this.bind();
|
||||
|
||||
this.notify = {
|
||||
$ele: this.$ele,
|
||||
update: function (command, update) {
|
||||
var commands = {};
|
||||
if (typeof command === "string") {
|
||||
commands[command] = update;
|
||||
} else {
|
||||
commands = command;
|
||||
}
|
||||
for (var cmd in commands) {
|
||||
switch (cmd) {
|
||||
case "type":
|
||||
this.$ele.removeClass('alert-' + self.settings.type);
|
||||
this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type);
|
||||
self.settings.type = commands[cmd];
|
||||
this.$ele.addClass('alert-' + commands[cmd]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[cmd]);
|
||||
break;
|
||||
case "icon":
|
||||
var $icon = this.$ele.find('[data-notify="icon"]');
|
||||
if (self.settings.icon_type.toLowerCase() === 'class') {
|
||||
$icon.removeClass(self.settings.content.icon).addClass(commands[cmd]);
|
||||
} else {
|
||||
if (!$icon.is('img')) {
|
||||
$icon.find('img');
|
||||
}
|
||||
$icon.attr('src', commands[cmd]);
|
||||
}
|
||||
break;
|
||||
case "progress":
|
||||
var newDelay = self.settings.delay - (self.settings.delay * (commands[cmd] / 100));
|
||||
this.$ele.data('notify-delay', newDelay);
|
||||
this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[cmd]).css('width', commands[cmd] + '%');
|
||||
break;
|
||||
case "url":
|
||||
this.$ele.find('[data-notify="url"]').attr('href', commands[cmd]);
|
||||
break;
|
||||
case "target":
|
||||
this.$ele.find('[data-notify="url"]').attr('target', commands[cmd]);
|
||||
break;
|
||||
default:
|
||||
this.$ele.find('[data-notify="' + cmd + '"]').html(commands[cmd]);
|
||||
}
|
||||
}
|
||||
var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
|
||||
self.reposition(posX);
|
||||
},
|
||||
close: function () {
|
||||
self.close();
|
||||
}
|
||||
};
|
||||
|
||||
},
|
||||
buildNotify: function () {
|
||||
var content = this.settings.content;
|
||||
this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target));
|
||||
this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align);
|
||||
if (!this.settings.allow_dismiss) {
|
||||
this.$ele.find('[data-notify="dismiss"]').css('display', 'none');
|
||||
}
|
||||
if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) {
|
||||
this.$ele.find('[data-notify="progressbar"]').remove();
|
||||
}
|
||||
},
|
||||
setIcon: function () {
|
||||
|
||||
this.$ele.addClass('alert-with-icon');
|
||||
|
||||
if (this.settings.icon_type.toLowerCase() === 'class') {
|
||||
this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon);
|
||||
} else {
|
||||
if (this.$ele.find('[data-notify="icon"]').is('img')) {
|
||||
this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon);
|
||||
} else {
|
||||
this.$ele.find('[data-notify="icon"]').append('<img src="' + this.settings.content.icon + '" alt="Notify Icon" />');
|
||||
}
|
||||
}
|
||||
},
|
||||
styleDismiss: function () {
|
||||
this.$ele.find('[data-notify="dismiss"]').css({
|
||||
position: 'absolute',
|
||||
right: '10px',
|
||||
top: '50%',
|
||||
marginTop: '-13px',
|
||||
zIndex: this.settings.z_index + 2
|
||||
});
|
||||
},
|
||||
styleURL: function () {
|
||||
this.$ele.find('[data-notify="url"]').css({
|
||||
backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)',
|
||||
height: '100%',
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
width: '100%',
|
||||
zIndex: this.settings.z_index + 1
|
||||
});
|
||||
},
|
||||
placement: function () {
|
||||
var self = this,
|
||||
offsetAmt = this.settings.offset.y,
|
||||
css = {
|
||||
display: 'inline-block',
|
||||
margin: '0px auto',
|
||||
position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'),
|
||||
transition: 'all .5s ease-in-out',
|
||||
zIndex: this.settings.z_index
|
||||
},
|
||||
hasAnimation = false,
|
||||
settings = this.settings;
|
||||
|
||||
$('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function () {
|
||||
offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing));
|
||||
});
|
||||
if (this.settings.newest_on_top === true) {
|
||||
offsetAmt = this.settings.offset.y;
|
||||
}
|
||||
css[this.settings.placement.from] = offsetAmt + 'px';
|
||||
|
||||
switch (this.settings.placement.align) {
|
||||
case "left":
|
||||
case "right":
|
||||
css[this.settings.placement.align] = this.settings.offset.x + 'px';
|
||||
break;
|
||||
case "center":
|
||||
css.left = 0;
|
||||
css.right = 0;
|
||||
break;
|
||||
}
|
||||
this.$ele.css(css).addClass(this.settings.animate.enter);
|
||||
$.each(Array('webkit-', 'moz-', 'o-', 'ms-', ''), function (index, prefix) {
|
||||
self.$ele[0].style[prefix + 'AnimationIterationCount'] = 1;
|
||||
});
|
||||
|
||||
$(this.settings.element).append(this.$ele);
|
||||
|
||||
if (this.settings.newest_on_top === true) {
|
||||
offsetAmt = (parseInt(offsetAmt) + parseInt(this.settings.spacing)) + this.$ele.outerHeight();
|
||||
this.reposition(offsetAmt);
|
||||
}
|
||||
|
||||
if ($.isFunction(self.settings.onShow)) {
|
||||
self.settings.onShow.call(this.$ele);
|
||||
}
|
||||
|
||||
this.$ele.one(this.animations.start, function () {
|
||||
hasAnimation = true;
|
||||
}).one(this.animations.end, function () {
|
||||
if ($.isFunction(self.settings.onShown)) {
|
||||
self.settings.onShown.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
if (!hasAnimation) {
|
||||
if ($.isFunction(self.settings.onShown)) {
|
||||
self.settings.onShown.call(this);
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
bind: function () {
|
||||
var self = this;
|
||||
|
||||
this.$ele.find('[data-notify="dismiss"]').on('click', function () {
|
||||
self.close();
|
||||
});
|
||||
|
||||
this.$ele.mouseover(function () {
|
||||
$(this).data('data-hover', "true");
|
||||
}).mouseout(function () {
|
||||
$(this).data('data-hover', "false");
|
||||
});
|
||||
this.$ele.data('data-hover', "false");
|
||||
|
||||
if (this.settings.delay > 0) {
|
||||
self.$ele.data('notify-delay', self.settings.delay);
|
||||
var timer = setInterval(function () {
|
||||
var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer;
|
||||
if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over === "pause") || self.settings.mouse_over != "pause") {
|
||||
var percent = ((self.settings.delay - delay) / self.settings.delay) * 100;
|
||||
self.$ele.data('notify-delay', delay);
|
||||
self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%');
|
||||
}
|
||||
if (delay <= -(self.settings.timer)) {
|
||||
clearInterval(timer);
|
||||
self.close();
|
||||
}
|
||||
}, self.settings.timer);
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
var self = this,
|
||||
posX = parseInt(this.$ele.css(this.settings.placement.from)),
|
||||
hasAnimation = false;
|
||||
|
||||
this.$ele.data('closing', 'true').addClass(this.settings.animate.exit);
|
||||
self.reposition(posX);
|
||||
|
||||
if ($.isFunction(self.settings.onClose)) {
|
||||
self.settings.onClose.call(this.$ele);
|
||||
}
|
||||
|
||||
this.$ele.one(this.animations.start, function () {
|
||||
hasAnimation = true;
|
||||
}).one(this.animations.end, function () {
|
||||
$(this).remove();
|
||||
if ($.isFunction(self.settings.onClosed)) {
|
||||
self.settings.onClosed.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
if (!hasAnimation) {
|
||||
self.$ele.remove();
|
||||
if (self.settings.onClosed) {
|
||||
self.settings.onClosed(self.$ele);
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
reposition: function (posX) {
|
||||
var self = this,
|
||||
notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])',
|
||||
$elements = this.$ele.nextAll(notifies);
|
||||
if (this.settings.newest_on_top === true) {
|
||||
$elements = this.$ele.prevAll(notifies);
|
||||
}
|
||||
$elements.each(function () {
|
||||
$(this).css(self.settings.placement.from, posX);
|
||||
posX = (parseInt(posX) + parseInt(self.settings.spacing)) + $(this).outerHeight();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.notify = function (content, options) {
|
||||
var plugin = new Notify(this, content, options);
|
||||
return plugin.notify;
|
||||
};
|
||||
$.notifyDefaults = function (options) {
|
||||
defaults = $.extend(true, {}, defaults, options);
|
||||
return defaults;
|
||||
};
|
||||
$.notifyClose = function (command) {
|
||||
if (typeof command === "undefined" || command === "all") {
|
||||
$('[data-notify]').find('[data-notify="dismiss"]').trigger('click');
|
||||
} else {
|
||||
$('[data-notify-position="' + command + '"]').find('[data-notify="dismiss"]').trigger('click');
|
||||
}
|
||||
};
|
||||
|
||||
}));
|
438
public/static/js/bootstrap-select.js
vendored
Normal file
438
public/static/js/bootstrap-select.js
vendored
Normal file
@ -0,0 +1,438 @@
|
||||
!function($) {
|
||||
var Selectpicker = function(element, options, e) {
|
||||
if (e ) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
this.$element = $(element);
|
||||
this.$newElement = null;
|
||||
this.button = null;
|
||||
|
||||
//Merge defaults, options and data-attributes to make our options
|
||||
this.options = $.extend({}, $.fn.selectpicker.defaults, this.$element.data(), typeof options == 'object' && options);
|
||||
|
||||
//If we have no title yet, check the attribute 'title' (this is missed by jq as its 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.init();
|
||||
};
|
||||
|
||||
Selectpicker.prototype = {
|
||||
|
||||
constructor: Selectpicker,
|
||||
|
||||
init: function (e) {
|
||||
var _this = this;
|
||||
this.$element.hide();
|
||||
this.multiple = this.$element.prop('multiple');
|
||||
|
||||
|
||||
var classList = this.$element.attr('class') !== undefined ? this.$element.attr('class').split(/\s+/) : '';
|
||||
var id = this.$element.attr('id');
|
||||
this.$element.after( this.createView() );
|
||||
this.$newElement = this.$element.next('.select');
|
||||
var select = this.$newElement;
|
||||
var menu = this.$newElement.find('.dropdown-menu');
|
||||
var menuArrow = this.$newElement.find('.dropdown-arrow');
|
||||
var menuA = menu.find('li > a');
|
||||
var liHeight = select.addClass('open').find('.dropdown-menu li > a').outerHeight();
|
||||
select.removeClass('open');
|
||||
var divHeight = menu.find('li .divider').outerHeight(true);
|
||||
var selectOffset_top = this.$newElement.offset().top;
|
||||
var size = 0;
|
||||
var menuHeight = 0;
|
||||
var selectHeight = this.$newElement.outerHeight();
|
||||
this.button = this.$newElement.find('> button');
|
||||
if (id !== undefined) {
|
||||
this.button.attr('id', id);
|
||||
$('label[for="' + id + '"]').click(function(){ select.find('button#'+id).focus(); })
|
||||
}
|
||||
for (var i = 0; i < classList.length; i++) {
|
||||
if(classList[i] != 'selectpicker') {
|
||||
this.$newElement.addClass(classList[i]);
|
||||
}
|
||||
}
|
||||
//If we are multiple, then add the show-tick class by default
|
||||
if(this.multiple) {
|
||||
this.$newElement.addClass('select-multiple');
|
||||
}
|
||||
this.button.addClass(this.options.style);
|
||||
menu.addClass(this.options.menuStyle);
|
||||
menuArrow.addClass(function() {
|
||||
if (_this.options.menuStyle) {
|
||||
return _this.options.menuStyle.replace('dropdown-', 'dropdown-arrow-');
|
||||
}
|
||||
});
|
||||
this.checkDisabled();
|
||||
this.checkTabIndex();
|
||||
this.clickListener();
|
||||
var menuPadding = parseInt(menu.css('padding-top')) + parseInt(menu.css('padding-bottom')) + parseInt(menu.css('border-top-width')) + parseInt(menu.css('border-bottom-width'));
|
||||
if (this.options.size == 'auto') {
|
||||
|
||||
// Creative Tim Changes: We changed the regular function made in bootstrap-select with this function so the getSize() will not be triggered one million times per second while you scroll.
|
||||
|
||||
var getSize = debounce(function() {
|
||||
var selectOffset_top_scroll = selectOffset_top - $(window).scrollTop();
|
||||
var windowHeight = $(window).innerHeight();
|
||||
var menuExtras = menuPadding + parseInt(menu.css('margin-top')) + parseInt(menu.css('margin-bottom')) + 2;
|
||||
var selectOffset_bot = windowHeight - selectOffset_top_scroll - selectHeight - menuExtras;
|
||||
menuHeight = selectOffset_bot;
|
||||
if (select.hasClass('dropup')) {
|
||||
menuHeight = selectOffset_top_scroll - menuExtras;
|
||||
}
|
||||
//limit menuHeight to 300px to have a smooth transition with cubic bezier on dropdown
|
||||
if(menuHeight >= 300){
|
||||
menuHeight = 300;
|
||||
}
|
||||
|
||||
menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'auto', 'min-height' : liHeight * 3 + 'px'});
|
||||
|
||||
}, 50);
|
||||
|
||||
getSize;
|
||||
$(window).on('scroll', getSize);
|
||||
$(window).on('resize', getSize);
|
||||
|
||||
if (window.MutationObserver) {
|
||||
new MutationObserver(getSize).observe(this.$element.get(0), {
|
||||
childList: true
|
||||
});
|
||||
} else {
|
||||
this.$element.bind('DOMNodeInserted', getSize);
|
||||
}
|
||||
} else if (this.options.size && this.options.size != 'auto' && menu.find('li').length > this.options.size) {
|
||||
var optIndex = menu.find("li > *").filter(':not(.divider)').slice(0,this.options.size).last().parent().index();
|
||||
var divLength = menu.find("li").slice(0,optIndex + 1).find('.divider').length;
|
||||
menuHeight = liHeight*this.options.size + divLength*divHeight + menuPadding;
|
||||
menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'scroll'});
|
||||
//console.log('sunt in if');
|
||||
}
|
||||
|
||||
// Listen for updates to the DOM and re render... (Use Mutation Observer when availiable)
|
||||
if (window.MutationObserver) {
|
||||
new MutationObserver($.proxy(this.reloadLi, this)).observe(this.$element.get(0), {
|
||||
childList: true
|
||||
});
|
||||
} else {
|
||||
this.$element.bind('DOMNodeInserted', $.proxy(this.reloadLi, this));
|
||||
}
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
createDropdown: function() {
|
||||
var drop =
|
||||
"<div class='btn-group select'>" +
|
||||
"<button class='btn dropdown-toggle clearfix' data-toggle='dropdown'>" +
|
||||
"<span class='filter-option'></span> " +
|
||||
"<span class='caret'></span>" +
|
||||
"</button>" +
|
||||
"<span class='dropdown-arrow'></span>" +
|
||||
"<ul class='dropdown-menu' role='menu'>" +
|
||||
"</ul>" +
|
||||
"</div>";
|
||||
|
||||
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
|
||||
$li = this.createLi();
|
||||
this.$newElement.find('ul').append( $li );
|
||||
//render view
|
||||
this.render();
|
||||
},
|
||||
|
||||
destroyLi:function() {
|
||||
this.$newElement.find('li').remove();
|
||||
},
|
||||
|
||||
createLi: function() {
|
||||
|
||||
var _this = this;
|
||||
var _li = [];
|
||||
var _liA = [];
|
||||
var _liHtml = '';
|
||||
|
||||
this.$element.find('option').each(function(){
|
||||
_li.push($(this).text());
|
||||
});
|
||||
|
||||
this.$element.find('option').each(function(index) {
|
||||
//Get the class and text for the option
|
||||
var optionClass = $(this).attr("class") !== undefined ? $(this).attr("class") : '';
|
||||
var text = $(this).text();
|
||||
var subtext = $(this).data('subtext') !== undefined ? '<small class="muted">'+$(this).data('subtext')+'</small>' : '';
|
||||
|
||||
//Append any subtext to the main text.
|
||||
text+=subtext;
|
||||
|
||||
if ($(this).parent().is('optgroup') && $(this).data('divider') != true) {
|
||||
if ($(this).index() == 0) {
|
||||
//Get the opt group label
|
||||
var label = $(this).parent().attr('label');
|
||||
var labelSubtext = $(this).parent().data('subtext') !== undefined ? '<small class="muted">'+$(this).parent().data('subtext')+'</small>' : '';
|
||||
label += labelSubtext;
|
||||
|
||||
if ($(this)[0].index != 0) {
|
||||
_liA.push(
|
||||
'<div class="divider"></div>'+
|
||||
'<dt>'+label+'</dt>'+
|
||||
_this.createA(text, "opt " + optionClass )
|
||||
);
|
||||
} else {
|
||||
_liA.push(
|
||||
'<dt>'+label+'</dt>'+
|
||||
_this.createA(text, "opt " + optionClass ));
|
||||
}
|
||||
} else {
|
||||
_liA.push( _this.createA(text, "opt " + optionClass ) );
|
||||
}
|
||||
} else if ($(this).data('divider') == true) {
|
||||
_liA.push('<div class="divider"></div>');
|
||||
} else if ($(this).data('hidden') == true) {
|
||||
_liA.push('');
|
||||
} else {
|
||||
_liA.push( _this.createA(text, optionClass ) );
|
||||
}
|
||||
});
|
||||
|
||||
if (_li.length > 0) {
|
||||
for (var i = 0; i < _li.length; i++) {
|
||||
var $option = this.$element.find('option').eq(i);
|
||||
_liHtml += "<li rel=" + i + ">" + _liA[i] + "</li>";
|
||||
}
|
||||
}
|
||||
|
||||
//If we dont have a selected item, and we dont have a title, select the first element so something is set in the button
|
||||
if(this.$element.find('option:selected').length==0 && !_this.options.title) {
|
||||
this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
|
||||
return $(_liHtml);
|
||||
},
|
||||
|
||||
createA:function(test, classes) {
|
||||
return '<a tabindex="-1" href="#" class="'+classes+'">' +
|
||||
'<span class="">' + test + '</span>' +
|
||||
'</a>';
|
||||
|
||||
},
|
||||
|
||||
render:function() {
|
||||
var _this = this;
|
||||
|
||||
//Set width of select
|
||||
if (this.options.width == 'auto') {
|
||||
var ulWidth = this.$newElement.find('.dropdown-menu').css('width');
|
||||
this.$newElement.css('width',ulWidth);
|
||||
} else if (this.options.width && this.options.width != 'auto') {
|
||||
this.$newElement.css('width',this.options.width);
|
||||
}
|
||||
|
||||
//Update the LI to match the SELECT
|
||||
this.$element.find('option').each(function(index) {
|
||||
_this.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled') );
|
||||
_this.setSelected(index, $(this).is(':selected') );
|
||||
});
|
||||
|
||||
|
||||
|
||||
var selectedItems = this.$element.find('option:selected').map(function(index,value) {
|
||||
if($(this).attr('title')!=undefined) {
|
||||
return $(this).attr('title');
|
||||
} else {
|
||||
return $(this).text();
|
||||
}
|
||||
}).toArray();
|
||||
|
||||
//Convert all the values into a comma delimited string
|
||||
var title = selectedItems.join(", ");
|
||||
|
||||
//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)) {
|
||||
title = selectedItems.length +' of ' + this.$element.find('option').length + ' selected';
|
||||
}
|
||||
}
|
||||
|
||||
//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 = _this.options.title != undefined ? _this.options.title : _this.options.noneSelectedText;
|
||||
}
|
||||
|
||||
this.$element.next('.select').find('.filter-option').html( title );
|
||||
},
|
||||
|
||||
|
||||
|
||||
setSelected:function(index, selected) {
|
||||
if(selected) {
|
||||
this.$newElement.find('li').eq(index).addClass('selected');
|
||||
} else {
|
||||
this.$newElement.find('li').eq(index).removeClass('selected');
|
||||
}
|
||||
},
|
||||
|
||||
setDisabled:function(index, disabled) {
|
||||
if(disabled) {
|
||||
this.$newElement.find('li').eq(index).addClass('disabled');
|
||||
} else {
|
||||
this.$newElement.find('li').eq(index).removeClass('disabled');
|
||||
}
|
||||
},
|
||||
|
||||
checkDisabled: function() {
|
||||
if (this.$element.is(':disabled')) {
|
||||
this.button.addClass('disabled');
|
||||
this.button.click(function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
checkTabIndex: function() {
|
||||
if (this.$element.is('[tabindex]')) {
|
||||
var tabindex = this.$element.attr("tabindex");
|
||||
this.button.attr('tabindex', tabindex);
|
||||
}
|
||||
},
|
||||
|
||||
clickListener: function() {
|
||||
var _this = this;
|
||||
|
||||
$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });
|
||||
|
||||
|
||||
|
||||
this.$newElement.on('click', 'li a', function(e){
|
||||
var clickedIndex = $(this).parent().index(),
|
||||
$this = $(this).parent(),
|
||||
$select = $this.parents('.select');
|
||||
|
||||
|
||||
//Dont close on multi choice menu
|
||||
if(_this.multiple) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
//Dont run if we have been disabled
|
||||
if ($select.prev('select').not(':disabled') && !$(this).parent().hasClass('disabled')){
|
||||
//Deselect all others if not multi select box
|
||||
if (!_this.multiple) {
|
||||
$select.prev('select').find('option').removeAttr('selected');
|
||||
$select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
//Else toggle the one we have chosen if we are multi selet.
|
||||
else {
|
||||
var selected = $select.prev('select').find('option').eq(clickedIndex).prop('selected');
|
||||
|
||||
if(selected) {
|
||||
$select.prev('select').find('option').eq(clickedIndex).removeAttr('selected');
|
||||
} else {
|
||||
$select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$select.find('.filter-option').html($this.text());
|
||||
$select.find('button').focus();
|
||||
|
||||
// Trigger select 'change'
|
||||
$select.prev('select').trigger('change');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.$newElement.on('click', 'li.disabled a, li dt, li .divider', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$select = $(this).parent().parents('.select');
|
||||
$select.find('button').focus();
|
||||
});
|
||||
|
||||
this.$element.on('change', function(e) {
|
||||
_this.render();
|
||||
});
|
||||
},
|
||||
|
||||
val:function(value) {
|
||||
|
||||
if(value!=undefined) {
|
||||
this.$element.val( value );
|
||||
|
||||
this.$element.trigger('change');
|
||||
return this.$element;
|
||||
} else {
|
||||
return this.$element.val();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn.selectpicker = function(option, event) {
|
||||
//get the args of the outer function..
|
||||
var args = arguments;
|
||||
var value;
|
||||
var chain = this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('selectpicker'),
|
||||
options = typeof option == 'object' && option;
|
||||
|
||||
if (!data) {
|
||||
$this.data('selectpicker', (data = new Selectpicker(this, options, event)));
|
||||
} else {
|
||||
for(var i in option) {
|
||||
data[i]=option[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof option == 'string') {
|
||||
//Copy the value of option, as once we shift the arguments
|
||||
//it also shifts the value of option.
|
||||
property = option;
|
||||
if(data[property] instanceof Function) {
|
||||
[].shift.apply(args);
|
||||
value = data[property].apply(data, args);
|
||||
} else {
|
||||
value = data[property];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(value!=undefined) {
|
||||
return value;
|
||||
} else {
|
||||
return chain;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.selectpicker.defaults = {
|
||||
style: null,
|
||||
size: 'auto',
|
||||
title: null,
|
||||
selectedTextFormat : 'values',
|
||||
noneSelectedText : 'Nothing selected',
|
||||
width: null,
|
||||
menuStyle: null,
|
||||
toggleSize: null
|
||||
}
|
||||
|
||||
}(window.jQuery);
|
7
public/static/js/bootstrap.min.js
vendored
Normal file
7
public/static/js/bootstrap.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
9
public/static/js/chartist.min.js
vendored
Normal file
9
public/static/js/chartist.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
263
public/static/js/demo.js
Normal file
263
public/static/js/demo.js
Normal file
@ -0,0 +1,263 @@
|
||||
type = ['','info','success','warning','danger'];
|
||||
|
||||
|
||||
demo = {
|
||||
initPickColor: function(){
|
||||
$('.pick-class-label').click(function(){
|
||||
var new_class = $(this).attr('new-class');
|
||||
var old_class = $('#display-buttons').attr('data-class');
|
||||
var display_div = $('#display-buttons');
|
||||
if(display_div.length) {
|
||||
var display_buttons = display_div.find('.btn');
|
||||
display_buttons.removeClass(old_class);
|
||||
display_buttons.addClass(new_class);
|
||||
display_div.attr('data-class', new_class);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
checkScrollForTransparentNavbar: debounce(function() {
|
||||
$navbar = $('.navbar[color-on-scroll]');
|
||||
scroll_distance = $navbar.attr('color-on-scroll') || 500;
|
||||
|
||||
if($(document).scrollTop() > scroll_distance ) {
|
||||
if(transparent) {
|
||||
transparent = false;
|
||||
$('.navbar[color-on-scroll]').removeClass('navbar-transparent');
|
||||
$('.navbar[color-on-scroll]').addClass('navbar-default');
|
||||
}
|
||||
} else {
|
||||
if( !transparent ) {
|
||||
transparent = true;
|
||||
$('.navbar[color-on-scroll]').addClass('navbar-transparent');
|
||||
$('.navbar[color-on-scroll]').removeClass('navbar-default');
|
||||
}
|
||||
}
|
||||
}, 17),
|
||||
|
||||
initDocChartist: function(){
|
||||
var dataSales = {
|
||||
labels: ['9:00AM', '12:00AM', '3:00PM', '6:00PM', '9:00PM', '12:00PM', '3:00AM', '6:00AM'],
|
||||
series: [
|
||||
[287, 385, 490, 492, 554, 586, 698, 695, 752, 788, 846, 944],
|
||||
[67, 152, 143, 240, 287, 335, 435, 437, 539, 542, 544, 647],
|
||||
[23, 113, 67, 108, 190, 239, 307, 308, 439, 410, 410, 509]
|
||||
]
|
||||
};
|
||||
|
||||
var optionsSales = {
|
||||
lineSmooth: false,
|
||||
low: 0,
|
||||
high: 800,
|
||||
showArea: true,
|
||||
height: "245px",
|
||||
axisX: {
|
||||
showGrid: false,
|
||||
},
|
||||
lineSmooth: Chartist.Interpolation.simple({
|
||||
divisor: 3
|
||||
}),
|
||||
showLine: false,
|
||||
showPoint: false,
|
||||
};
|
||||
|
||||
var responsiveSales = [
|
||||
['screen and (max-width: 640px)', {
|
||||
axisX: {
|
||||
labelInterpolationFnc: function (value) {
|
||||
return value[0];
|
||||
}
|
||||
}
|
||||
}]
|
||||
];
|
||||
|
||||
Chartist.Line('#chartHours', dataSales, optionsSales, responsiveSales);
|
||||
|
||||
|
||||
var data = {
|
||||
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
||||
series: [
|
||||
[542, 443, 320, 780, 553, 453, 326, 434, 568, 610, 756, 895],
|
||||
[412, 243, 280, 580, 453, 353, 300, 364, 368, 410, 636, 695]
|
||||
]
|
||||
};
|
||||
|
||||
var options = {
|
||||
seriesBarDistance: 10,
|
||||
axisX: {
|
||||
showGrid: false
|
||||
},
|
||||
height: "245px"
|
||||
};
|
||||
|
||||
var responsiveOptions = [
|
||||
['screen and (max-width: 640px)', {
|
||||
seriesBarDistance: 5,
|
||||
axisX: {
|
||||
labelInterpolationFnc: function (value) {
|
||||
return value[0];
|
||||
}
|
||||
}
|
||||
}]
|
||||
];
|
||||
|
||||
Chartist.Bar('#chartActivity', data, options, responsiveOptions);
|
||||
|
||||
var dataPreferences = {
|
||||
series: [
|
||||
[25, 30, 20, 25]
|
||||
]
|
||||
};
|
||||
|
||||
var optionsPreferences = {
|
||||
donut: true,
|
||||
donutWidth: 40,
|
||||
startAngle: 0,
|
||||
total: 100,
|
||||
showLabel: false,
|
||||
axisX: {
|
||||
showGrid: false
|
||||
}
|
||||
};
|
||||
|
||||
Chartist.Pie('#chartPreferences', dataPreferences, optionsPreferences);
|
||||
|
||||
Chartist.Pie('#chartPreferences', {
|
||||
labels: ['62%','32%','6%'],
|
||||
series: [62, 32, 6]
|
||||
});
|
||||
},
|
||||
|
||||
initChartist: function(){
|
||||
|
||||
var dataSales = {
|
||||
labels: ['9:00AM', '12:00AM', '3:00PM', '6:00PM', '9:00PM', '12:00PM', '3:00AM', '6:00AM'],
|
||||
series: [
|
||||
[287, 385, 490, 492, 554, 586, 698, 695, 752, 788, 846, 944],
|
||||
[67, 152, 143, 240, 287, 335, 435, 437, 539, 542, 544, 647],
|
||||
[23, 113, 67, 108, 190, 239, 307, 308, 439, 410, 410, 509]
|
||||
]
|
||||
};
|
||||
|
||||
var optionsSales = {
|
||||
lineSmooth: false,
|
||||
low: 0,
|
||||
high: 800,
|
||||
showArea: true,
|
||||
height: "245px",
|
||||
axisX: {
|
||||
showGrid: false,
|
||||
},
|
||||
lineSmooth: Chartist.Interpolation.simple({
|
||||
divisor: 3
|
||||
}),
|
||||
showLine: false,
|
||||
showPoint: false,
|
||||
};
|
||||
|
||||
var responsiveSales = [
|
||||
['screen and (max-width: 640px)', {
|
||||
axisX: {
|
||||
labelInterpolationFnc: function (value) {
|
||||
return value[0];
|
||||
}
|
||||
}
|
||||
}]
|
||||
];
|
||||
|
||||
Chartist.Line('#chartHours', dataSales, optionsSales, responsiveSales);
|
||||
|
||||
|
||||
var data = {
|
||||
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
||||
series: [
|
||||
[542, 443, 320, 780, 553, 453, 326, 434, 568, 610, 756, 895],
|
||||
[412, 243, 280, 580, 453, 353, 300, 364, 368, 410, 636, 695]
|
||||
]
|
||||
};
|
||||
|
||||
var options = {
|
||||
seriesBarDistance: 10,
|
||||
axisX: {
|
||||
showGrid: false
|
||||
},
|
||||
height: "245px"
|
||||
};
|
||||
|
||||
var responsiveOptions = [
|
||||
['screen and (max-width: 640px)', {
|
||||
seriesBarDistance: 5,
|
||||
axisX: {
|
||||
labelInterpolationFnc: function (value) {
|
||||
return value[0];
|
||||
}
|
||||
}
|
||||
}]
|
||||
];
|
||||
|
||||
Chartist.Bar('#chartActivity', data, options, responsiveOptions);
|
||||
|
||||
var dataPreferences = {
|
||||
series: [
|
||||
[25, 30, 20, 25]
|
||||
]
|
||||
};
|
||||
|
||||
var optionsPreferences = {
|
||||
donut: true,
|
||||
donutWidth: 40,
|
||||
startAngle: 0,
|
||||
total: 100,
|
||||
showLabel: false,
|
||||
axisX: {
|
||||
showGrid: false
|
||||
}
|
||||
};
|
||||
|
||||
Chartist.Pie('#chartPreferences', dataPreferences, optionsPreferences);
|
||||
|
||||
Chartist.Pie('#chartPreferences', {
|
||||
labels: ['62%','32%','6%'],
|
||||
series: [62, 32, 6]
|
||||
});
|
||||
},
|
||||
|
||||
initGoogleMaps: function(){
|
||||
var myLatlng = new google.maps.LatLng(40.748817, -73.985428);
|
||||
var mapOptions = {
|
||||
zoom: 13,
|
||||
center: myLatlng,
|
||||
scrollwheel: false, //we disable de scroll over the map, it is a really annoing when you scroll through page
|
||||
styles: [{"featureType":"water","stylers":[{"saturation":43},{"lightness":-11},{"hue":"#0088ff"}]},{"featureType":"road","elementType":"geometry.fill","stylers":[{"hue":"#ff0000"},{"saturation":-100},{"lightness":99}]},{"featureType":"road","elementType":"geometry.stroke","stylers":[{"color":"#808080"},{"lightness":54}]},{"featureType":"landscape.man_made","elementType":"geometry.fill","stylers":[{"color":"#ece2d9"}]},{"featureType":"poi.park","elementType":"geometry.fill","stylers":[{"color":"#ccdca1"}]},{"featureType":"road","elementType":"labels.text.fill","stylers":[{"color":"#767676"}]},{"featureType":"road","elementType":"labels.text.stroke","stylers":[{"color":"#ffffff"}]},{"featureType":"poi","stylers":[{"visibility":"off"}]},{"featureType":"landscape.natural","elementType":"geometry.fill","stylers":[{"visibility":"on"},{"color":"#b8cb93"}]},{"featureType":"poi.park","stylers":[{"visibility":"on"}]},{"featureType":"poi.sports_complex","stylers":[{"visibility":"on"}]},{"featureType":"poi.medical","stylers":[{"visibility":"on"}]},{"featureType":"poi.business","stylers":[{"visibility":"simplified"}]}]
|
||||
|
||||
}
|
||||
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
|
||||
|
||||
var marker = new google.maps.Marker({
|
||||
position: myLatlng,
|
||||
title:"Hello World!"
|
||||
});
|
||||
|
||||
// To add the marker to the map, call setMap();
|
||||
marker.setMap(map);
|
||||
},
|
||||
|
||||
showNotification: function(from, align){
|
||||
color = Math.floor((Math.random() * 4) + 1);
|
||||
|
||||
$.notify({
|
||||
icon: "pe-7s-gift",
|
||||
message: "Welcome to <b>Light Bootstrap Dashboard</b> - a beautiful freebie for every web developer."
|
||||
|
||||
},{
|
||||
type: type[color],
|
||||
timer: 4000,
|
||||
placement: {
|
||||
from: from,
|
||||
align: align
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
4
public/static/js/jquery.3.2.1.min.js
vendored
Normal file
4
public/static/js/jquery.3.2.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
154
public/static/js/light-bootstrap-dashboard.js
Normal file
154
public/static/js/light-bootstrap-dashboard.js
Normal file
@ -0,0 +1,154 @@
|
||||
/*!
|
||||
|
||||
=========================================================
|
||||
* Light Bootstrap Dashboard - v1.4.0
|
||||
=========================================================
|
||||
|
||||
* Product Page: http://www.creative-tim.com/product/light-bootstrap-dashboard
|
||||
* Copyright 2017 Creative Tim (http://www.creative-tim.com)
|
||||
* Licensed under MIT (https://github.com/creativetimofficial/light-bootstrap-dashboard/blob/master/LICENSE.md)
|
||||
|
||||
=========================================================
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
*/
|
||||
|
||||
var searchVisible = 0;
|
||||
var transparent = true;
|
||||
|
||||
var transparentDemo = true;
|
||||
var fixedTop = false;
|
||||
|
||||
var navbar_initialized = false;
|
||||
|
||||
$(document).ready(function(){
|
||||
window_width = $(window).width();
|
||||
|
||||
// check if there is an image set for the sidebar's background
|
||||
lbd.checkSidebarImage();
|
||||
|
||||
// Init navigation toggle for small screens
|
||||
lbd.initRightMenu();
|
||||
|
||||
// Activate the tooltips
|
||||
$('[rel="tooltip"]').tooltip();
|
||||
|
||||
$('.form-control').on("focus", function(){
|
||||
$(this).parent('.input-group').addClass("input-group-focus");
|
||||
}).on("blur", function(){
|
||||
$(this).parent(".input-group").removeClass("input-group-focus");
|
||||
});
|
||||
|
||||
// Fixes sub-nav not working as expected on IOS
|
||||
$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });
|
||||
});
|
||||
|
||||
$(document).on('click', '.navbar-toggle', function(){
|
||||
$toggle = $(this);
|
||||
|
||||
if(lbd.misc.navbar_menu_visible == 1) {
|
||||
$('html').removeClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 0;
|
||||
$('#bodyClick').remove();
|
||||
setTimeout(function(){
|
||||
$toggle.removeClass('toggled');
|
||||
}, 550);
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
$toggle.addClass('toggled');
|
||||
}, 580);
|
||||
div = '<div id="bodyClick"></div>';
|
||||
$(div).appendTo('body').click(function() {
|
||||
$('html').removeClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 0;
|
||||
setTimeout(function(){
|
||||
$toggle.removeClass('toggled');
|
||||
$('#bodyClick').remove();
|
||||
}, 550);
|
||||
});
|
||||
|
||||
$('html').addClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 1;
|
||||
}
|
||||
});
|
||||
|
||||
$(window).on('resize', function(){
|
||||
if(navbar_initialized){
|
||||
lbd.initRightMenu();
|
||||
navbar_initialized = true;
|
||||
}
|
||||
});
|
||||
|
||||
lbd = {
|
||||
misc:{
|
||||
navbar_menu_visible: 0
|
||||
},
|
||||
|
||||
checkSidebarImage: function(){
|
||||
$sidebar = $('.sidebar');
|
||||
image_src = $sidebar.data('image');
|
||||
|
||||
if(image_src !== undefined){
|
||||
sidebar_container = '<div class="sidebar-background" style="background-image: url(' + image_src + ') "/>'
|
||||
$sidebar.append(sidebar_container);
|
||||
}
|
||||
},
|
||||
|
||||
initRightMenu: debounce(function(){
|
||||
if(!navbar_initialized){
|
||||
$sidebar_wrapper = $('.sidebar-wrapper');
|
||||
$navbar = $('nav').find('.navbar-collapse').html();
|
||||
|
||||
mobile_menu_content = '';
|
||||
|
||||
nav_content = $navbar;
|
||||
|
||||
nav_content = '<ul class="nav nav-mobile-menu">' + nav_content + '</ul>';
|
||||
|
||||
// navbar_form = $('nav').find('.navbar-form').get(0).outerHTML;
|
||||
|
||||
$sidebar_nav = $sidebar_wrapper.find(' > .nav');
|
||||
|
||||
// insert the navbar form before the sidebar list
|
||||
$nav_content = $(nav_content);
|
||||
// $navbar_form = $(navbar_form);
|
||||
$nav_content.insertBefore($sidebar_nav);
|
||||
// $navbar_form.insertBefore($nav_content);
|
||||
|
||||
$(".sidebar-wrapper .dropdown .dropdown-menu > li > a").click(function(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
});
|
||||
|
||||
mobile_menu_initialized = true;
|
||||
} else {
|
||||
if($(window).width() > 991){
|
||||
// reset all the additions that we made for the sidebar wrapper only if the screen is bigger than 991px
|
||||
// $sidebar_wrapper.find('.navbar-form').remove();
|
||||
$sidebar_wrapper.find('.nav-mobile-menu').remove();
|
||||
|
||||
mobile_menu_initialized = false;
|
||||
}
|
||||
}
|
||||
},200)
|
||||
}
|
||||
|
||||
|
||||
// Returns a function, that, as long as it continues to be invoked, will not
|
||||
// be triggered. The function will be called after it stops being called for
|
||||
// N milliseconds. If `immediate` is passed, trigger the function on the
|
||||
// leading edge, instead of the trailing.
|
||||
|
||||
function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
}, wait);
|
||||
if (immediate && !timeout) func.apply(context, args);
|
||||
};
|
||||
};
|
@ -8,22 +8,59 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body table-responsive">
|
||||
<div id="accordion">
|
||||
<div class="card">
|
||||
<div class="card-header collapsed filterCard" id="addBlacklistHeader" data-toggle="collapse" data-target="#addBlacklist" aria-expanded="false" aria-controls="addBlacklist">
|
||||
<span class="align-middle" data-toggle="collapse" data-target="#addBlacklist" aria-expanded="false" aria-controls="addBlacklist">
|
||||
<i class="fas fa-plus"></i> Add New User
|
||||
</span>
|
||||
</div>
|
||||
<div id="addBlacklist" class="collapse" aria-labelledby="addBlacklistHeader" data-parent="#accordion">
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col-md-8 pr-1">
|
||||
<div class="form-group">
|
||||
<label>User ID</label>
|
||||
<input name="userid" type="text" class="form-control" placeholder="User ID">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 px-1">
|
||||
<label></label>
|
||||
<div class="alert alert-success" role="alert">
|
||||
Click <a href="https://support.discordapp.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-">here</a> for a guide on how to retreive user IDs.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input name="csrf" type="hidden" value="{{csrf}}">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary mx-auto"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ticket ID</th>
|
||||
<th>Username</th>
|
||||
<th>User ID</th>
|
||||
<th>Log URL</th>
|
||||
<th>Username</th>
|
||||
<th>Remove</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#blacklisted}}
|
||||
<tr>
|
||||
<td>{{ticketid}}</td>
|
||||
<td>{{userId}}</td>
|
||||
<td>{{username}}</td>
|
||||
<td>{{userid}}</td>
|
||||
<td><a href="{{baseUrl}}/manage/{{guildId}}/logs/view/{{uuid}}">{{uuid}}</a></td>
|
||||
<td><a href="{{baseUrl}}/manage/{{guildId}}/blacklist/remove/{{userId}}?c={{csrf}}">Remove</a></td>
|
||||
</tr>
|
||||
{{/blacklisted}}
|
||||
</tbody>
|
||||
@ -34,4 +71,40 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{#userNotFound}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The user you specified couldn't be found
|
||||
</div>
|
||||
</div>
|
||||
{{/userNotFound}}
|
||||
{{#isStaff}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
You cannot blacklist a staff member
|
||||
</div>
|
||||
</div>
|
||||
{{/isStaff}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
|
@ -33,7 +33,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1">
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary mx-auto"><i class="fas fa-paper-plane"></i> Filter</button>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user