├── README.md ├── addons └── whmcspf │ ├── hooks.php │ ├── static │ ├── css │ │ ├── jquery-confirm.css │ │ └── jquery-confirm.less │ └── js │ │ └── jquery-confirm.js │ ├── templates.admin.php │ └── whmcspf.php ├── pfnode ├── composer.json ├── config.php ├── database.db ├── forward_service │ └── ForwardSystem ├── service_file_template.php ├── start.php ├── start_autoload.php ├── start_http.php ├── start_report.php └── start_service.php └── servers └── portforward ├── portforward.php ├── templates └── clientarea.tpl └── theme ├── base64.js ├── flags.css ├── flags.png ├── jquery-confirm.css ├── jquery-confirm.js └── style.css /README.md: -------------------------------------------------------------------------------- 1 | # WhmcsPortForward 2 | 可以对接Whmcs进行销售的端口转发系统,支持TCP/UDP及Ipv6/Ipv4端口转发 3 | 4 | 自定义字段列表: 5 | 6 | ptype|转发协议 7 | 8 | sport 9 | 10 | rsip|源服务器IP 11 | 12 | rport|源服务器端口 13 | 14 | bandwidth 15 | 16 | forwardstatus 17 | 18 | 除'ptype|转发协议'、'rsip|源服务器IP'、'rport|源服务器端口'以外请全部设置为仅管理员可见! 19 | 20 | 'ptype|转发协议'、'rsip|源服务器IP'、'rport|源服务器端口'请设置为必填、在订单上时显示、在账单上显示! 21 | 22 | 安装: 23 | 24 | 1.安装Redis 25 | 26 | 2.apt update 27 | 28 | 3.apt install php php-posix php-pdo-sqlite php-curl 29 | 30 | 4.编辑config.php 31 | 32 | 5.Debug : php start.php start Daemon: php start.php start -d 33 | 34 | 6.Whmcs后台启用流量监控插件 35 | 36 | 7.添加服务器 37 | 38 | 8.添加产品 39 | 40 | 9.开通测试 41 | 42 | 服务器可选Hash 43 | 44 | 10.0.1.1,10.0.1.2,10.0.0.3,10.0.0.4,10.0.0.5,10.0.0.6,10.0.0.7 45 | -------------------------------------------------------------------------------- /addons/whmcspf/hooks.php: -------------------------------------------------------------------------------- 1 | where('untime',date("Y-m-d"))->get(); 5 | if($todayunsusp){ 6 | foreach ( $todayunsusp as $listone){ 7 | localAPI('ModuleUnsuspend', array('serviceid' => $listone->serviceid), Capsule::table('tbladmins')->first()->id); 8 | Capsule::table('tblhosting')->where('id',$listone->serviceid)->update(['domainstatus' => 'Active']); 9 | whmcspf_setCustomfieldsValue('forwardstatus','Active',$listone->serviceid,null); 10 | Capsule::table('mod_whmcspf_suspservice')->where('serviceid',$listone->serviceid)->delete(); 11 | } 12 | } 13 | }); 14 | add_hook('AfterModuleTerminate', 1, function($vars) { 15 | Capsule::table('mod_whmcspf_suspservice')->where('serviceid',$vars['serviceid'])->delete(); 16 | }); -------------------------------------------------------------------------------- /addons/whmcspf/static/css/jquery-confirm.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * jquery-confirm v3.3.0 (http://craftpip.github.io/jquery-confirm/) 3 | * Author: boniface pereira 4 | * Website: www.craftpip.com 5 | * Contact: hey@craftpip.com 6 | * 7 | * Copyright 2013-2017 jquery-confirm 8 | * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) 9 | */ 10 | @-webkit-keyframes jconfirm-spin { 11 | from { 12 | -webkit-transform: rotate(0deg); 13 | transform: rotate(0deg); 14 | } 15 | to { 16 | -webkit-transform: rotate(360deg); 17 | transform: rotate(360deg); 18 | } 19 | } 20 | @keyframes jconfirm-spin { 21 | from { 22 | -webkit-transform: rotate(0deg); 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | -webkit-transform: rotate(360deg); 27 | transform: rotate(360deg); 28 | } 29 | } 30 | body[class*=jconfirm-no-scroll-] { 31 | overflow: hidden !important; 32 | } 33 | .jconfirm { 34 | position: fixed; 35 | top: 0; 36 | left: 0; 37 | right: 0; 38 | bottom: 0; 39 | z-index: 99999999; 40 | font-family: inherit; 41 | overflow: hidden; 42 | } 43 | .jconfirm .jconfirm-bg { 44 | position: fixed; 45 | top: 0; 46 | left: 0; 47 | right: 0; 48 | bottom: 0; 49 | -webkit-transition: opacity .4s; 50 | transition: opacity .4s; 51 | } 52 | .jconfirm .jconfirm-bg.jconfirm-bg-h { 53 | opacity: 0 !important; 54 | } 55 | .jconfirm .jconfirm-scrollpane { 56 | -webkit-perspective: 500px; 57 | perspective: 500px; 58 | -webkit-perspective-origin: center; 59 | perspective-origin: center; 60 | display: table; 61 | width: 100%; 62 | height: 100%; 63 | } 64 | .jconfirm .jconfirm-row { 65 | display: table-row; 66 | width: 100%; 67 | } 68 | .jconfirm .jconfirm-cell { 69 | display: table-cell; 70 | vertical-align: middle; 71 | } 72 | .jconfirm .jconfirm-holder { 73 | max-height: 100%; 74 | padding: 50px 0; 75 | } 76 | .jconfirm .jconfirm-box-container { 77 | -webkit-transition: -webkit-transform; 78 | transition: -webkit-transform; 79 | transition: transform; 80 | transition: transform, -webkit-transform; 81 | } 82 | .jconfirm .jconfirm-box-container.jconfirm-no-transition { 83 | -webkit-transition: none !important; 84 | transition: none !important; 85 | } 86 | .jconfirm .jconfirm-box { 87 | background: white; 88 | border-radius: 4px; 89 | position: relative; 90 | outline: none; 91 | padding: 15px 15px 0; 92 | overflow: hidden; 93 | margin-left: auto; 94 | margin-right: auto; 95 | } 96 | @-webkit-keyframes type-blue { 97 | 1%, 98 | 100% { 99 | border-color: #3498db; 100 | } 101 | 50% { 102 | border-color: #5faee3; 103 | } 104 | } 105 | @keyframes type-blue { 106 | 1%, 107 | 100% { 108 | border-color: #3498db; 109 | } 110 | 50% { 111 | border-color: #5faee3; 112 | } 113 | } 114 | @-webkit-keyframes type-green { 115 | 1%, 116 | 100% { 117 | border-color: #2ecc71; 118 | } 119 | 50% { 120 | border-color: #54d98c; 121 | } 122 | } 123 | @keyframes type-green { 124 | 1%, 125 | 100% { 126 | border-color: #2ecc71; 127 | } 128 | 50% { 129 | border-color: #54d98c; 130 | } 131 | } 132 | @-webkit-keyframes type-red { 133 | 1%, 134 | 100% { 135 | border-color: #e74c3c; 136 | } 137 | 50% { 138 | border-color: #ed7669; 139 | } 140 | } 141 | @keyframes type-red { 142 | 1%, 143 | 100% { 144 | border-color: #e74c3c; 145 | } 146 | 50% { 147 | border-color: #ed7669; 148 | } 149 | } 150 | @-webkit-keyframes type-orange { 151 | 1%, 152 | 100% { 153 | border-color: #f1c40f; 154 | } 155 | 50% { 156 | border-color: #f4d03f; 157 | } 158 | } 159 | @keyframes type-orange { 160 | 1%, 161 | 100% { 162 | border-color: #f1c40f; 163 | } 164 | 50% { 165 | border-color: #f4d03f; 166 | } 167 | } 168 | @-webkit-keyframes type-purple { 169 | 1%, 170 | 100% { 171 | border-color: #9b59b6; 172 | } 173 | 50% { 174 | border-color: #b07cc6; 175 | } 176 | } 177 | @keyframes type-purple { 178 | 1%, 179 | 100% { 180 | border-color: #9b59b6; 181 | } 182 | 50% { 183 | border-color: #b07cc6; 184 | } 185 | } 186 | @-webkit-keyframes type-dark { 187 | 1%, 188 | 100% { 189 | border-color: #34495e; 190 | } 191 | 50% { 192 | border-color: #46627f; 193 | } 194 | } 195 | @keyframes type-dark { 196 | 1%, 197 | 100% { 198 | border-color: #34495e; 199 | } 200 | 50% { 201 | border-color: #46627f; 202 | } 203 | } 204 | .jconfirm .jconfirm-box.jconfirm-type-animated { 205 | -webkit-animation-duration: 2s; 206 | animation-duration: 2s; 207 | -webkit-animation-iteration-count: infinite; 208 | animation-iteration-count: infinite; 209 | } 210 | .jconfirm .jconfirm-box.jconfirm-type-blue { 211 | border-top: solid 7px #3498db; 212 | -webkit-animation-name: type-blue; 213 | animation-name: type-blue; 214 | } 215 | .jconfirm .jconfirm-box.jconfirm-type-green { 216 | border-top: solid 7px #2ecc71; 217 | -webkit-animation-name: type-green; 218 | animation-name: type-green; 219 | } 220 | .jconfirm .jconfirm-box.jconfirm-type-red { 221 | border-top: solid 7px #e74c3c; 222 | -webkit-animation-name: type-red; 223 | animation-name: type-red; 224 | } 225 | .jconfirm .jconfirm-box.jconfirm-type-orange { 226 | border-top: solid 7px #f1c40f; 227 | -webkit-animation-name: type-orange; 228 | animation-name: type-orange; 229 | } 230 | .jconfirm .jconfirm-box.jconfirm-type-purple { 231 | border-top: solid 7px #9b59b6; 232 | -webkit-animation-name: type-purple; 233 | animation-name: type-purple; 234 | } 235 | .jconfirm .jconfirm-box.jconfirm-type-dark { 236 | border-top: solid 7px #34495e; 237 | -webkit-animation-name: type-dark; 238 | animation-name: type-dark; 239 | } 240 | .jconfirm .jconfirm-box.loading { 241 | height: 120px; 242 | } 243 | .jconfirm .jconfirm-box.loading:before { 244 | content: ''; 245 | position: absolute; 246 | left: 0; 247 | background: white; 248 | right: 0; 249 | top: 0; 250 | bottom: 0; 251 | border-radius: 10px; 252 | z-index: 1; 253 | } 254 | .jconfirm .jconfirm-box.loading:after { 255 | opacity: 0.6; 256 | content: ''; 257 | height: 30px; 258 | width: 30px; 259 | border: solid 3px transparent; 260 | position: absolute; 261 | left: 50%; 262 | margin-left: -15px; 263 | border-radius: 50%; 264 | -webkit-animation: jconfirm-spin 1s infinite linear; 265 | animation: jconfirm-spin 1s infinite linear; 266 | border-bottom-color: dodgerblue; 267 | top: 50%; 268 | margin-top: -15px; 269 | z-index: 2; 270 | } 271 | .jconfirm .jconfirm-box div.jconfirm-closeIcon { 272 | height: 20px; 273 | width: 20px; 274 | position: absolute; 275 | top: 10px; 276 | right: 10px; 277 | cursor: pointer; 278 | opacity: .6; 279 | text-align: center; 280 | font-size: 27px !important; 281 | line-height: 14px !important; 282 | display: none; 283 | z-index: 1; 284 | } 285 | .jconfirm .jconfirm-box div.jconfirm-closeIcon:empty { 286 | display: none; 287 | } 288 | .jconfirm .jconfirm-box div.jconfirm-closeIcon .fa { 289 | font-size: 16px; 290 | } 291 | .jconfirm .jconfirm-box div.jconfirm-closeIcon .glyphicon { 292 | font-size: 16px; 293 | } 294 | .jconfirm .jconfirm-box div.jconfirm-closeIcon .zmdi { 295 | font-size: 16px; 296 | } 297 | .jconfirm .jconfirm-box div.jconfirm-closeIcon:hover { 298 | opacity: 1; 299 | } 300 | .jconfirm .jconfirm-box div.jconfirm-title-c { 301 | display: block; 302 | font-size: 22px; 303 | line-height: 20px; 304 | -webkit-user-select: none; 305 | -moz-user-select: none; 306 | -ms-user-select: none; 307 | user-select: none; 308 | cursor: default; 309 | padding-bottom: 15px; 310 | } 311 | .jconfirm .jconfirm-box div.jconfirm-title-c.jconfirm-hand { 312 | cursor: move; 313 | } 314 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 315 | font-size: inherit; 316 | display: inline-block; 317 | vertical-align: middle; 318 | } 319 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c i { 320 | vertical-align: middle; 321 | } 322 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c:empty { 323 | display: none; 324 | } 325 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title { 326 | -webkit-user-select: none; 327 | -moz-user-select: none; 328 | -ms-user-select: none; 329 | user-select: none; 330 | font-size: inherit; 331 | font-family: inherit; 332 | display: inline-block; 333 | vertical-align: middle; 334 | } 335 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title:empty { 336 | display: none; 337 | } 338 | .jconfirm .jconfirm-box div.jconfirm-content-pane { 339 | margin-bottom: 15px; 340 | height: auto; 341 | -webkit-transition: height 0.4s ease-in; 342 | transition: height 0.4s ease-in; 343 | display: inline-block; 344 | width: 100%; 345 | position: relative; 346 | overflow-x: hidden; 347 | overflow-y: auto; 348 | } 349 | .jconfirm .jconfirm-box div.jconfirm-content-pane.no-scroll { 350 | overflow-y: hidden; 351 | } 352 | .jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar { 353 | width: 3px; 354 | } 355 | .jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-track { 356 | background: rgba(0, 0, 0, 0.1); 357 | } 358 | .jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-thumb { 359 | background: #666; 360 | border-radius: 3px; 361 | } 362 | .jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content { 363 | overflow: auto; 364 | } 365 | .jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content img { 366 | max-width: 100%; 367 | height: auto; 368 | } 369 | .jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content:empty { 370 | display: none; 371 | } 372 | .jconfirm .jconfirm-box .jconfirm-buttons { 373 | padding-bottom: 11px; 374 | } 375 | .jconfirm .jconfirm-box .jconfirm-buttons > button { 376 | margin-bottom: 4px; 377 | margin-left: 2px; 378 | margin-right: 2px; 379 | } 380 | .jconfirm .jconfirm-box .jconfirm-buttons button { 381 | display: inline-block; 382 | padding: 6px 12px; 383 | font-size: 14px; 384 | font-weight: 400; 385 | line-height: 1.42857143; 386 | text-align: center; 387 | white-space: nowrap; 388 | vertical-align: middle; 389 | -ms-touch-action: manipulation; 390 | touch-action: manipulation; 391 | cursor: pointer; 392 | -webkit-user-select: none; 393 | -moz-user-select: none; 394 | -ms-user-select: none; 395 | user-select: none; 396 | border-radius: 4px; 397 | min-height: 1em; 398 | -webkit-transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, background 0.1s ease, -webkit-box-shadow 0.1s ease; 399 | transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, background 0.1s ease, -webkit-box-shadow 0.1s ease; 400 | transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, background 0.1s ease; 401 | transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, background 0.1s ease, -webkit-box-shadow 0.1s ease; 402 | -webkit-tap-highlight-color: transparent; 403 | border: none; 404 | background-image: none; 405 | } 406 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue { 407 | background-color: #3498db; 408 | color: #FFF; 409 | text-shadow: none; 410 | -webkit-transition: background .2s; 411 | transition: background .2s; 412 | } 413 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue:hover { 414 | background-color: #2980b9; 415 | color: #FFF; 416 | } 417 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-green { 418 | background-color: #2ecc71; 419 | color: #FFF; 420 | text-shadow: none; 421 | -webkit-transition: background .2s; 422 | transition: background .2s; 423 | } 424 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-green:hover { 425 | background-color: #27ae60; 426 | color: #FFF; 427 | } 428 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-red { 429 | background-color: #e74c3c; 430 | color: #FFF; 431 | text-shadow: none; 432 | -webkit-transition: background .2s; 433 | transition: background .2s; 434 | } 435 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-red:hover { 436 | background-color: #c0392b; 437 | color: #FFF; 438 | } 439 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange { 440 | background-color: #f1c40f; 441 | color: #FFF; 442 | text-shadow: none; 443 | -webkit-transition: background .2s; 444 | transition: background .2s; 445 | } 446 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange:hover { 447 | background-color: #f39c12; 448 | color: #FFF; 449 | } 450 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-default { 451 | background-color: #ecf0f1; 452 | color: #000; 453 | text-shadow: none; 454 | -webkit-transition: background .2s; 455 | transition: background .2s; 456 | } 457 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-default:hover { 458 | background-color: #bdc3c7; 459 | color: #000; 460 | } 461 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple { 462 | background-color: #9b59b6; 463 | color: #FFF; 464 | text-shadow: none; 465 | -webkit-transition: background .2s; 466 | transition: background .2s; 467 | } 468 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple:hover { 469 | background-color: #8e44ad; 470 | color: #FFF; 471 | } 472 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark { 473 | background-color: #34495e; 474 | color: #FFF; 475 | text-shadow: none; 476 | -webkit-transition: background .2s; 477 | transition: background .2s; 478 | } 479 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark:hover { 480 | background-color: #2c3e50; 481 | color: #FFF; 482 | } 483 | .jconfirm .jconfirm-box.jconfirm-type-red .jconfirm-title-c .jconfirm-icon-c { 484 | color: #e74c3c !important; 485 | } 486 | .jconfirm .jconfirm-box.jconfirm-type-blue .jconfirm-title-c .jconfirm-icon-c { 487 | color: #3498db !important; 488 | } 489 | .jconfirm .jconfirm-box.jconfirm-type-green .jconfirm-title-c .jconfirm-icon-c { 490 | color: #2ecc71 !important; 491 | } 492 | .jconfirm .jconfirm-box.jconfirm-type-purple .jconfirm-title-c .jconfirm-icon-c { 493 | color: #9b59b6 !important; 494 | } 495 | .jconfirm .jconfirm-box.jconfirm-type-orange .jconfirm-title-c .jconfirm-icon-c { 496 | color: #f1c40f !important; 497 | } 498 | .jconfirm .jconfirm-box.jconfirm-type-dark .jconfirm-title-c .jconfirm-icon-c { 499 | color: #34495e !important; 500 | } 501 | .jconfirm .jconfirm-clear { 502 | clear: both; 503 | } 504 | .jconfirm.jconfirm-rtl { 505 | direction: rtl; 506 | } 507 | .jconfirm.jconfirm-rtl div.jconfirm-closeIcon { 508 | left: 5px; 509 | right: auto; 510 | } 511 | .jconfirm.jconfirm-white .jconfirm-bg, 512 | .jconfirm.jconfirm-light .jconfirm-bg { 513 | background-color: #444; 514 | opacity: .2; 515 | } 516 | .jconfirm.jconfirm-white .jconfirm-box, 517 | .jconfirm.jconfirm-light .jconfirm-box { 518 | -webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); 519 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); 520 | border-radius: 5px; 521 | } 522 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-title-c .jconfirm-icon-c, 523 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 524 | margin-right: 8px; 525 | margin-left: 0px; 526 | } 527 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons, 528 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons { 529 | float: right; 530 | } 531 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button, 532 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button { 533 | text-transform: uppercase; 534 | font-size: 14px; 535 | font-weight: bold; 536 | text-shadow: none; 537 | } 538 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default, 539 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default { 540 | -webkit-box-shadow: none; 541 | box-shadow: none; 542 | color: #333; 543 | } 544 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default:hover, 545 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default:hover { 546 | background: #ddd; 547 | } 548 | .jconfirm.jconfirm-white.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c, 549 | .jconfirm.jconfirm-light.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { 550 | margin-left: 8px; 551 | margin-right: 0px; 552 | } 553 | .jconfirm.jconfirm-black .jconfirm-bg, 554 | .jconfirm.jconfirm-dark .jconfirm-bg { 555 | background-color: darkslategray; 556 | opacity: .4; 557 | } 558 | .jconfirm.jconfirm-black .jconfirm-box, 559 | .jconfirm.jconfirm-dark .jconfirm-box { 560 | -webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); 561 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); 562 | background: #444; 563 | border-radius: 5px; 564 | color: white; 565 | } 566 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-title-c .jconfirm-icon-c, 567 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 568 | margin-right: 8px; 569 | margin-left: 0px; 570 | } 571 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons, 572 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons { 573 | float: right; 574 | } 575 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button, 576 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button { 577 | border: none; 578 | background-image: none; 579 | text-transform: uppercase; 580 | font-size: 14px; 581 | font-weight: bold; 582 | text-shadow: none; 583 | -webkit-transition: background .1s; 584 | transition: background .1s; 585 | color: white; 586 | } 587 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default, 588 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default { 589 | -webkit-box-shadow: none; 590 | box-shadow: none; 591 | color: #fff; 592 | background: none; 593 | } 594 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default:hover, 595 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default:hover { 596 | background: #666; 597 | } 598 | .jconfirm.jconfirm-black.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c, 599 | .jconfirm.jconfirm-dark.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { 600 | margin-left: 8px; 601 | margin-right: 0px; 602 | } 603 | .jconfirm .jconfirm-box.hilight.jconfirm-hilight-shake { 604 | -webkit-animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; 605 | animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; 606 | -webkit-transform: translate3d(0, 0, 0); 607 | transform: translate3d(0, 0, 0); 608 | } 609 | .jconfirm .jconfirm-box.hilight.jconfirm-hilight-glow { 610 | -webkit-animation: glow 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; 611 | animation: glow 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; 612 | -webkit-transform: translate3d(0, 0, 0); 613 | transform: translate3d(0, 0, 0); 614 | } 615 | @-webkit-keyframes shake { 616 | 10%, 617 | 90% { 618 | -webkit-transform: translate3d(-2px, 0, 0); 619 | transform: translate3d(-2px, 0, 0); 620 | } 621 | 20%, 622 | 80% { 623 | -webkit-transform: translate3d(4px, 0, 0); 624 | transform: translate3d(4px, 0, 0); 625 | } 626 | 30%, 627 | 50%, 628 | 70% { 629 | -webkit-transform: translate3d(-8px, 0, 0); 630 | transform: translate3d(-8px, 0, 0); 631 | } 632 | 40%, 633 | 60% { 634 | -webkit-transform: translate3d(8px, 0, 0); 635 | transform: translate3d(8px, 0, 0); 636 | } 637 | } 638 | @keyframes shake { 639 | 10%, 640 | 90% { 641 | -webkit-transform: translate3d(-2px, 0, 0); 642 | transform: translate3d(-2px, 0, 0); 643 | } 644 | 20%, 645 | 80% { 646 | -webkit-transform: translate3d(4px, 0, 0); 647 | transform: translate3d(4px, 0, 0); 648 | } 649 | 30%, 650 | 50%, 651 | 70% { 652 | -webkit-transform: translate3d(-8px, 0, 0); 653 | transform: translate3d(-8px, 0, 0); 654 | } 655 | 40%, 656 | 60% { 657 | -webkit-transform: translate3d(8px, 0, 0); 658 | transform: translate3d(8px, 0, 0); 659 | } 660 | } 661 | @-webkit-keyframes glow { 662 | 0%, 663 | 100% { 664 | -webkit-box-shadow: 0 0 0px red; 665 | box-shadow: 0 0 0px red; 666 | } 667 | 50% { 668 | -webkit-box-shadow: 0 0 30px red; 669 | box-shadow: 0 0 30px red; 670 | } 671 | } 672 | @keyframes glow { 673 | 0%, 674 | 100% { 675 | -webkit-box-shadow: 0 0 0px red; 676 | box-shadow: 0 0 0px red; 677 | } 678 | 50% { 679 | -webkit-box-shadow: 0 0 30px red; 680 | box-shadow: 0 0 30px red; 681 | } 682 | } 683 | /*Transition rules*/ 684 | .jconfirm { 685 | -webkit-perspective: 400px; 686 | perspective: 400px; 687 | } 688 | .jconfirm .jconfirm-box { 689 | opacity: 1; 690 | -webkit-transition-property: all; 691 | transition-property: all; 692 | } 693 | .jconfirm .jconfirm-box.jconfirm-animation-top, 694 | .jconfirm .jconfirm-box.jconfirm-animation-left, 695 | .jconfirm .jconfirm-box.jconfirm-animation-right, 696 | .jconfirm .jconfirm-box.jconfirm-animation-bottom, 697 | .jconfirm .jconfirm-box.jconfirm-animation-opacity, 698 | .jconfirm .jconfirm-box.jconfirm-animation-zoom, 699 | .jconfirm .jconfirm-box.jconfirm-animation-scale, 700 | .jconfirm .jconfirm-box.jconfirm-animation-none, 701 | .jconfirm .jconfirm-box.jconfirm-animation-rotate, 702 | .jconfirm .jconfirm-box.jconfirm-animation-rotatex, 703 | .jconfirm .jconfirm-box.jconfirm-animation-rotatey, 704 | .jconfirm .jconfirm-box.jconfirm-animation-scaley, 705 | .jconfirm .jconfirm-box.jconfirm-animation-scalex { 706 | opacity: 0; 707 | } 708 | .jconfirm .jconfirm-box.jconfirm-animation-rotate { 709 | -webkit-transform: rotate(90deg); 710 | transform: rotate(90deg); 711 | } 712 | .jconfirm .jconfirm-box.jconfirm-animation-rotatex { 713 | -webkit-transform: rotateX(90deg); 714 | transform: rotateX(90deg); 715 | -webkit-transform-origin: center; 716 | transform-origin: center; 717 | } 718 | .jconfirm .jconfirm-box.jconfirm-animation-rotatexr { 719 | -webkit-transform: rotateX(-90deg); 720 | transform: rotateX(-90deg); 721 | -webkit-transform-origin: center; 722 | transform-origin: center; 723 | } 724 | .jconfirm .jconfirm-box.jconfirm-animation-rotatey { 725 | -webkit-transform: rotatey(90deg); 726 | transform: rotatey(90deg); 727 | -webkit-transform-origin: center; 728 | transform-origin: center; 729 | } 730 | .jconfirm .jconfirm-box.jconfirm-animation-rotateyr { 731 | -webkit-transform: rotatey(-90deg); 732 | transform: rotatey(-90deg); 733 | -webkit-transform-origin: center; 734 | transform-origin: center; 735 | } 736 | .jconfirm .jconfirm-box.jconfirm-animation-scaley { 737 | -webkit-transform: scaley(1.5); 738 | transform: scaley(1.5); 739 | -webkit-transform-origin: center; 740 | transform-origin: center; 741 | } 742 | .jconfirm .jconfirm-box.jconfirm-animation-scalex { 743 | -webkit-transform: scalex(1.5); 744 | transform: scalex(1.5); 745 | -webkit-transform-origin: center; 746 | transform-origin: center; 747 | } 748 | .jconfirm .jconfirm-box.jconfirm-animation-top { 749 | -webkit-transform: translate(0px, -100px); 750 | transform: translate(0px, -100px); 751 | } 752 | .jconfirm .jconfirm-box.jconfirm-animation-left { 753 | -webkit-transform: translate(-100px, 0px); 754 | transform: translate(-100px, 0px); 755 | } 756 | .jconfirm .jconfirm-box.jconfirm-animation-right { 757 | -webkit-transform: translate(100px, 0px); 758 | transform: translate(100px, 0px); 759 | } 760 | .jconfirm .jconfirm-box.jconfirm-animation-bottom { 761 | -webkit-transform: translate(0px, 100px); 762 | transform: translate(0px, 100px); 763 | } 764 | .jconfirm .jconfirm-box.jconfirm-animation-zoom { 765 | -webkit-transform: scale(1.2); 766 | transform: scale(1.2); 767 | } 768 | .jconfirm .jconfirm-box.jconfirm-animation-scale { 769 | -webkit-transform: scale(0.5); 770 | transform: scale(0.5); 771 | } 772 | .jconfirm .jconfirm-box.jconfirm-animation-none { 773 | visibility: hidden; 774 | } 775 | .jconfirm.jconfirm-supervan .jconfirm-bg { 776 | background-color: rgba(54, 70, 93, 0.95); 777 | } 778 | .jconfirm.jconfirm-supervan .jconfirm-box { 779 | background-color: transparent; 780 | } 781 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-blue { 782 | border: none; 783 | } 784 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-green { 785 | border: none; 786 | } 787 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-red { 788 | border: none; 789 | } 790 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-orange { 791 | border: none; 792 | } 793 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-purple { 794 | border: none; 795 | } 796 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-dark { 797 | border: none; 798 | } 799 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-closeIcon { 800 | color: white; 801 | } 802 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c { 803 | text-align: center; 804 | color: white; 805 | font-size: 28px; 806 | font-weight: normal; 807 | } 808 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c > * { 809 | padding-bottom: 25px; 810 | } 811 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 812 | margin-right: 8px; 813 | margin-left: 0px; 814 | } 815 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content-pane { 816 | margin-bottom: 25px; 817 | } 818 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content { 819 | text-align: center; 820 | color: white; 821 | } 822 | .jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons { 823 | text-align: center; 824 | } 825 | .jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons button { 826 | font-size: 16px; 827 | border-radius: 2px; 828 | background: #303f53; 829 | text-shadow: none; 830 | border: none; 831 | color: white; 832 | padding: 10px; 833 | min-width: 100px; 834 | } 835 | .jconfirm.jconfirm-supervan.jconfirm-rtl .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 836 | margin-left: 8px; 837 | margin-right: 0px; 838 | } 839 | .jconfirm.jconfirm-material .jconfirm-bg { 840 | background-color: rgba(0, 0, 0, 0.67); 841 | } 842 | .jconfirm.jconfirm-material .jconfirm-box { 843 | background-color: white; 844 | -webkit-box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 13px 19px 2px rgba(0, 0, 0, 0.14), 0 5px 24px 4px rgba(0, 0, 0, 0.12); 845 | box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 13px 19px 2px rgba(0, 0, 0, 0.14), 0 5px 24px 4px rgba(0, 0, 0, 0.12); 846 | padding: 30px 25px 10px 25px; 847 | } 848 | .jconfirm.jconfirm-material .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 849 | margin-right: 8px; 850 | margin-left: 0px; 851 | } 852 | .jconfirm.jconfirm-material .jconfirm-box div.jconfirm-closeIcon { 853 | color: rgba(0, 0, 0, 0.87); 854 | } 855 | .jconfirm.jconfirm-material .jconfirm-box div.jconfirm-title-c { 856 | color: rgba(0, 0, 0, 0.87); 857 | font-size: 22px; 858 | font-weight: bold; 859 | } 860 | .jconfirm.jconfirm-material .jconfirm-box div.jconfirm-content { 861 | color: rgba(0, 0, 0, 0.87); 862 | } 863 | .jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons { 864 | text-align: right; 865 | } 866 | .jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons button { 867 | text-transform: uppercase; 868 | font-weight: 500; 869 | } 870 | .jconfirm.jconfirm-material.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { 871 | margin-left: 8px; 872 | margin-right: 0px; 873 | } 874 | .jconfirm.jconfirm-bootstrap .jconfirm-bg { 875 | background-color: rgba(0, 0, 0, 0.21); 876 | } 877 | .jconfirm.jconfirm-bootstrap .jconfirm-box { 878 | background-color: white; 879 | -webkit-box-shadow: 0 3px 8px 0px rgba(0, 0, 0, 0.2); 880 | box-shadow: 0 3px 8px 0px rgba(0, 0, 0, 0.2); 881 | border: solid 1px rgba(0, 0, 0, 0.4); 882 | padding: 15px 0 0; 883 | } 884 | .jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 885 | margin-right: 8px; 886 | margin-left: 0px; 887 | } 888 | .jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-closeIcon { 889 | color: rgba(0, 0, 0, 0.87); 890 | } 891 | .jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-title-c { 892 | color: rgba(0, 0, 0, 0.87); 893 | font-size: 22px; 894 | font-weight: bold; 895 | padding-left: 15px; 896 | padding-right: 15px; 897 | } 898 | .jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-content { 899 | color: rgba(0, 0, 0, 0.87); 900 | padding: 0px 15px; 901 | } 902 | .jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons { 903 | text-align: right; 904 | padding: 10px; 905 | margin: -5px 0 0px; 906 | border-top: solid 1px #ddd; 907 | overflow: hidden; 908 | border-radius: 0 0 4px 4px; 909 | } 910 | .jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons button { 911 | font-weight: 500; 912 | } 913 | .jconfirm.jconfirm-bootstrap.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { 914 | margin-left: 8px; 915 | margin-right: 0px; 916 | } 917 | .jconfirm.jconfirm-modern .jconfirm-bg { 918 | background-color: slategray; 919 | opacity: .6; 920 | } 921 | .jconfirm.jconfirm-modern .jconfirm-box { 922 | background-color: white; 923 | -webkit-box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 13px 19px 2px rgba(0, 0, 0, 0.14), 0 5px 24px 4px rgba(0, 0, 0, 0.12); 924 | box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 13px 19px 2px rgba(0, 0, 0, 0.14), 0 5px 24px 4px rgba(0, 0, 0, 0.12); 925 | padding: 30px 30px 15px; 926 | } 927 | .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-closeIcon { 928 | color: rgba(0, 0, 0, 0.87); 929 | top: 15px; 930 | right: 15px; 931 | } 932 | .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c { 933 | color: rgba(0, 0, 0, 0.87); 934 | font-size: 24px; 935 | font-weight: bold; 936 | text-align: center; 937 | margin-bottom: 10px; 938 | } 939 | .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 940 | -webkit-transition: -webkit-transform .5s; 941 | transition: -webkit-transform .5s; 942 | transition: transform .5s; 943 | transition: transform .5s, -webkit-transform .5s; 944 | -webkit-transform: scale(0); 945 | transform: scale(0); 946 | display: block; 947 | margin-right: 0px; 948 | margin-left: 0px; 949 | margin-bottom: 10px; 950 | font-size: 69px; 951 | color: #aaa; 952 | } 953 | .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-content { 954 | text-align: center; 955 | font-size: 15px; 956 | color: #777; 957 | margin-bottom: 25px; 958 | } 959 | .jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons { 960 | text-align: center; 961 | } 962 | .jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button { 963 | font-weight: bold; 964 | text-transform: uppercase; 965 | -webkit-transition: background .1s; 966 | transition: background .1s; 967 | padding: 10px 20px; 968 | } 969 | .jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button + button { 970 | margin-left: 4px; 971 | } 972 | .jconfirm.jconfirm-modern.jconfirm-open .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 973 | -webkit-transform: scale(1); 974 | transform: scale(1); 975 | } 976 | -------------------------------------------------------------------------------- /addons/whmcspf/static/css/jquery-confirm.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * jquery-confirm v3.3.0 (http://craftpip.github.io/jquery-confirm/) 3 | * Author: boniface pereira 4 | * Website: www.craftpip.com 5 | * Contact: hey@craftpip.com 6 | * 7 | * Copyright 2013-2017 jquery-confirm 8 | * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) 9 | */ 10 | @blue: #3498db; 11 | @blueHover: #2980b9; 12 | @green: #2ecc71; 13 | @greenHover: #27ae60; 14 | @red: #e74c3c; 15 | @redHover: #c0392b; 16 | @orange: #f1c40f; 17 | @orangeHover: #f39c12; 18 | @purple: #9b59b6; 19 | @purpleHover: #8e44ad; 20 | @default: #ecf0f1; 21 | @defaultHover: #bdc3c7; 22 | @dark: #34495e; 23 | @darkHover: #2c3e50; 24 | 25 | @keyframes jconfirm-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | 34 | body[class*=jconfirm-no-scroll-] { 35 | overflow: hidden !important; 36 | } 37 | 38 | .jconfirm { 39 | position: fixed; 40 | top: 0; 41 | left: 0; 42 | right: 0; 43 | bottom: 0; 44 | z-index: 99999999; 45 | font-family: inherit; 46 | overflow: hidden; 47 | 48 | .jconfirm-bg { 49 | position: fixed; 50 | top: 0; 51 | left: 0; 52 | right: 0; 53 | bottom: 0; 54 | transition: opacity .4s; 55 | 56 | &.jconfirm-bg-h { 57 | opacity: 0 !important; 58 | } 59 | } 60 | .jconfirm-scrollpane { 61 | //overflow-y: auto; 62 | perspective: 500px; 63 | perspective-origin: center; 64 | 65 | display: table; 66 | width: 100%; 67 | height: 100%; 68 | } 69 | .jconfirm-row { 70 | display: table-row; 71 | width: 100%; 72 | } 73 | .jconfirm-cell { 74 | //height: 100%; 75 | display: table-cell; 76 | vertical-align: middle; 77 | } 78 | .jconfirm-holder { 79 | max-height: 100%; 80 | padding: 50px 0; 81 | } 82 | .jconfirm-box-container { 83 | transition: transform; 84 | 85 | &.jconfirm-no-transition { 86 | transition: none !important; 87 | } 88 | } 89 | .jconfirm-box { 90 | background: white; 91 | border-radius: 4px; 92 | position: relative; 93 | outline: none; 94 | padding: 15px 15px 0; 95 | overflow: hidden; 96 | margin-left: auto; 97 | margin-right: auto; 98 | 99 | @keyframes type-blue { 100 | 1%, 100% { 101 | border-color: @blue; 102 | } 103 | 50% { 104 | border-color: lighten(@blue, 10%); 105 | } 106 | } 107 | @keyframes type-green { 108 | 1%, 100% { 109 | border-color: @green; 110 | } 111 | 50% { 112 | border-color: lighten(@green, 10%); 113 | } 114 | } 115 | @keyframes type-red { 116 | 1%, 100% { 117 | border-color: @red; 118 | } 119 | 50% { 120 | border-color: lighten(@red, 10%); 121 | } 122 | } 123 | @keyframes type-orange { 124 | 1%, 100% { 125 | border-color: @orange; 126 | } 127 | 50% { 128 | border-color: lighten(@orange, 10%); 129 | } 130 | } 131 | @keyframes type-purple { 132 | 1%, 100% { 133 | border-color: @purple; 134 | } 135 | 50% { 136 | border-color: lighten(@purple, 10%); 137 | } 138 | } 139 | @keyframes type-dark { 140 | 1%, 100% { 141 | border-color: @dark; 142 | } 143 | 50% { 144 | border-color: lighten(@dark, 10%); 145 | } 146 | } 147 | &.jconfirm-type-animated { 148 | animation-duration: 2s; 149 | animation-iteration-count: infinite; 150 | } 151 | &.jconfirm-type-blue { 152 | border-top: solid 7px @blue; 153 | animation-name: type-blue; 154 | } 155 | &.jconfirm-type-green { 156 | border-top: solid 7px @green; 157 | animation-name: type-green; 158 | } 159 | &.jconfirm-type-red { 160 | border-top: solid 7px @red; 161 | animation-name: type-red; 162 | } 163 | &.jconfirm-type-orange { 164 | border-top: solid 7px @orange; 165 | animation-name: type-orange; 166 | } 167 | &.jconfirm-type-purple { 168 | border-top: solid 7px @purple; 169 | animation-name: type-purple; 170 | } 171 | &.jconfirm-type-dark { 172 | border-top: solid 7px @dark; 173 | animation-name: type-dark; 174 | } 175 | &.loading { 176 | height: 120px; 177 | 178 | &:before { 179 | content: ''; 180 | position: absolute; 181 | left: 0; 182 | background: white; 183 | right: 0; 184 | top: 0; 185 | bottom: 0; 186 | border-radius: 10px; 187 | z-index: 1; 188 | } 189 | &:after { 190 | opacity: 0.6; 191 | content: ''; 192 | height: 30px; 193 | width: 30px; 194 | border: solid 3px transparent; 195 | position: absolute; 196 | left: 50%; 197 | margin-left: -15px; 198 | border-radius: 50%; 199 | animation: jconfirm-spin 1s infinite linear; 200 | border-bottom-color: dodgerblue; 201 | top: 50%; 202 | margin-top: -15px; 203 | z-index: 2; 204 | } 205 | } 206 | 207 | div.jconfirm-closeIcon { 208 | height: 20px; 209 | width: 20px; 210 | position: absolute; 211 | top: 10px; 212 | right: 10px; 213 | cursor: pointer; 214 | opacity: .6; 215 | text-align: center; 216 | font-size: 27px !important; 217 | line-height: 14px !important; 218 | display: none; 219 | z-index: 1; 220 | 221 | &:empty { 222 | display: none; 223 | } 224 | 225 | .fa { 226 | font-size: 16px; 227 | } 228 | .glyphicon { 229 | font-size: 16px; 230 | } 231 | .zmdi { 232 | font-size: 16px; 233 | } 234 | 235 | &:hover { 236 | opacity: 1; 237 | } 238 | } 239 | div.jconfirm-title-c { 240 | display: block; 241 | font-size: 22px; 242 | line-height: 20px; 243 | user-select: none; 244 | cursor: default; 245 | padding-bottom: 15px; 246 | 247 | &.jconfirm-hand { 248 | cursor: move; 249 | } 250 | .jconfirm-icon-c { 251 | font-size: inherit; 252 | //padding-bottom: 15px; 253 | display: inline-block; 254 | vertical-align: middle; 255 | i { 256 | vertical-align: middle; 257 | } 258 | &:empty { 259 | display: none; 260 | } 261 | } 262 | .jconfirm-title { 263 | user-select: none; 264 | font-size: inherit; 265 | font-family: inherit; 266 | display: inline-block; 267 | vertical-align: middle; 268 | //padding-bottom: 15px; 269 | &:empty { 270 | display: none; 271 | } 272 | } 273 | } 274 | 275 | div.jconfirm-content-pane { 276 | margin-bottom: 15px; 277 | height: auto; 278 | transition: height .4s ease-in; 279 | display: inline-block; 280 | width: 100%; 281 | position: relative; 282 | overflow-x: hidden; 283 | overflow-y: auto; 284 | 285 | &.no-scroll { 286 | overflow-y: hidden; 287 | } 288 | &::-webkit-scrollbar { 289 | width: 3px; 290 | } 291 | 292 | &::-webkit-scrollbar-track { 293 | background: rgba(0, 0, 0, .1); 294 | } 295 | 296 | &::-webkit-scrollbar-thumb { 297 | background: #666; 298 | border-radius: 3px; 299 | } 300 | 301 | .jconfirm-content { 302 | overflow: auto; 303 | 304 | img { 305 | max-width: 100%; 306 | height: auto; 307 | } 308 | &:empty { 309 | display: none; 310 | } 311 | } 312 | } 313 | 314 | .jconfirm-buttons { 315 | padding-bottom: 11px; 316 | > button { 317 | margin-bottom: 4px; 318 | margin-left: 2px; 319 | margin-right: 2px; 320 | } 321 | 322 | button { 323 | display: inline-block; 324 | padding: 6px 12px; 325 | font-size: 14px; 326 | font-weight: 400; 327 | line-height: 1.42857143; 328 | text-align: center; 329 | white-space: nowrap; 330 | vertical-align: middle; 331 | -ms-touch-action: manipulation; 332 | touch-action: manipulation; 333 | cursor: pointer; 334 | -webkit-user-select: none; 335 | -moz-user-select: none; 336 | -ms-user-select: none; 337 | user-select: none; 338 | border-radius: 4px; 339 | min-height: 1em; 340 | //outline: blue; 341 | //user-select: none; 342 | transition: opacity .1s ease, background-color .1s ease, color .1s ease, box-shadow .1s ease, background .1s ease; 343 | -webkit-tap-highlight-color: transparent; 344 | border: none; 345 | background-image: none; 346 | 347 | &.btn-blue { 348 | background-color: @blue; 349 | color: #FFF; 350 | text-shadow: none; 351 | transition: background .2s; 352 | &:hover { 353 | background-color: @blueHover; 354 | color: #FFF; 355 | } 356 | } 357 | 358 | &.btn-green { 359 | background-color: @green; 360 | color: #FFF; 361 | text-shadow: none; 362 | transition: background .2s; 363 | &:hover { 364 | background-color: @greenHover; 365 | color: #FFF; 366 | } 367 | } 368 | 369 | &.btn-red { 370 | background-color: @red; 371 | color: #FFF; 372 | text-shadow: none; 373 | transition: background .2s; 374 | &:hover { 375 | background-color: @redHover; 376 | color: #FFF; 377 | } 378 | } 379 | 380 | &.btn-orange { 381 | background-color: @orange; 382 | color: #FFF; 383 | text-shadow: none; 384 | transition: background .2s; 385 | &:hover { 386 | background-color: @orangeHover; 387 | color: #FFF; 388 | } 389 | } 390 | 391 | &.btn-default { 392 | background-color: @default; 393 | color: #000; 394 | text-shadow: none; 395 | transition: background .2s; 396 | &:hover { 397 | background-color: @defaultHover; 398 | color: #000; 399 | } 400 | } 401 | 402 | &.btn-purple { 403 | background-color: @purple; 404 | color: #FFF; 405 | text-shadow: none; 406 | transition: background .2s; 407 | &:hover { 408 | background-color: @purpleHover; 409 | color: #FFF; 410 | } 411 | } 412 | 413 | &.btn-dark { 414 | background-color: @dark; 415 | color: #FFF; 416 | text-shadow: none; 417 | transition: background .2s; 418 | &:hover { 419 | background-color: @darkHover; 420 | color: #FFF; 421 | } 422 | } 423 | } 424 | } 425 | 426 | &.jconfirm-type-red .jconfirm-title-c .jconfirm-icon-c { 427 | color: @red !important; 428 | } 429 | &.jconfirm-type-blue .jconfirm-title-c .jconfirm-icon-c { 430 | color: @blue !important; 431 | } 432 | &.jconfirm-type-green .jconfirm-title-c .jconfirm-icon-c { 433 | color: @green !important; 434 | } 435 | &.jconfirm-type-purple .jconfirm-title-c .jconfirm-icon-c { 436 | color: @purple !important; 437 | } 438 | &.jconfirm-type-orange .jconfirm-title-c .jconfirm-icon-c { 439 | color: @orange !important; 440 | } 441 | &.jconfirm-type-dark .jconfirm-title-c .jconfirm-icon-c { 442 | color: @dark !important; 443 | } 444 | } 445 | 446 | .jconfirm-clear { 447 | clear: both; 448 | } 449 | 450 | &.jconfirm-rtl { 451 | direction: rtl; 452 | div.jconfirm-closeIcon { 453 | left: 5px; 454 | right: auto; 455 | } 456 | } 457 | 458 | &.jconfirm-white, &.jconfirm-light { 459 | .jconfirm-bg { 460 | background-color: #444; 461 | opacity: .2; 462 | } 463 | .jconfirm-box { 464 | box-shadow: 0 2px 6px rgba(0, 0, 0, .2); 465 | border-radius: 5px; 466 | 467 | .jconfirm-title-c .jconfirm-icon-c { 468 | margin-right: 8px; 469 | margin-left: 0px; 470 | } 471 | .jconfirm-buttons { 472 | float: right; 473 | 474 | button { 475 | text-transform: uppercase; 476 | font-size: 14px; 477 | font-weight: bold; 478 | text-shadow: none; 479 | } 480 | button.btn-default { 481 | box-shadow: none; 482 | color: #333; 483 | 484 | &:hover { 485 | background: #ddd; 486 | } 487 | } 488 | } 489 | } 490 | &.jconfirm-rtl { 491 | .jconfirm-title-c .jconfirm-icon-c { 492 | margin-left: 8px; 493 | margin-right: 0px; 494 | } 495 | } 496 | } 497 | 498 | &.jconfirm-black, &.jconfirm-dark { 499 | .jconfirm-bg { 500 | background-color: darkslategray; 501 | opacity: .4; 502 | } 503 | .jconfirm-box { 504 | box-shadow: 0 2px 6px rgba(0, 0, 0, .2); 505 | background: #444; 506 | border-radius: 5px; 507 | color: white; 508 | 509 | .jconfirm-title-c .jconfirm-icon-c { 510 | margin-right: 8px; 511 | margin-left: 0px; 512 | } 513 | 514 | .jconfirm-buttons { 515 | float: right; 516 | 517 | button { 518 | border: none; 519 | background-image: none; 520 | text-transform: uppercase; 521 | font-size: 14px; 522 | font-weight: bold; 523 | text-shadow: none; 524 | transition: background .1s; 525 | color: white; 526 | } 527 | button.btn-default { 528 | box-shadow: none; 529 | color: #fff; 530 | background: none; 531 | 532 | &:hover { 533 | background: #666; 534 | } 535 | } 536 | } 537 | } 538 | 539 | &.jconfirm-rtl { 540 | .jconfirm-title-c .jconfirm-icon-c { 541 | margin-left: 8px; 542 | margin-right: 0px; 543 | } 544 | } 545 | } 546 | 547 | .jconfirm-box.hilight { 548 | &.jconfirm-hilight-shake { 549 | animation: shake 0.82s cubic-bezier(.36, .07, .19, .97) both; 550 | transform: translate3d(0, 0, 0); 551 | } 552 | &.jconfirm-hilight-glow { 553 | animation: glow 0.82s cubic-bezier(.36, .07, .19, .97) both; 554 | transform: translate3d(0, 0, 0); 555 | } 556 | } 557 | } 558 | 559 | @keyframes shake { 560 | 10%, 90% { 561 | transform: translate3d(-2px, 0, 0); 562 | } 563 | 20%, 80% { 564 | transform: translate3d(4px, 0, 0); 565 | } 566 | 30%, 50%, 70% { 567 | transform: translate3d(-8px, 0, 0); 568 | } 569 | 40%, 60% { 570 | transform: translate3d(8px, 0, 0); 571 | } 572 | } 573 | 574 | @keyframes glow { 575 | 0%, 100% { 576 | box-shadow: 0 0 0px red; 577 | } 578 | 50% { 579 | box-shadow: 0 0 30px red; 580 | } 581 | } 582 | 583 | /*Transition rules*/ 584 | .jconfirm { 585 | perspective: 400px; 586 | 587 | .jconfirm-box { 588 | opacity: 1; 589 | transition-property: all; 590 | 591 | &.jconfirm-animation-top, &.jconfirm-animation-left, &.jconfirm-animation-right, &.jconfirm-animation-bottom, &.jconfirm-animation-opacity, &.jconfirm-animation-zoom, &.jconfirm-animation-scale, &.jconfirm-animation-none, &.jconfirm-animation-rotate, &.jconfirm-animation-rotatex, &.jconfirm-animation-rotatey, &.jconfirm-animation-scaley, &.jconfirm-animation-scalex { 592 | opacity: 0; 593 | } 594 | &.jconfirm-animation-rotate { 595 | transform: rotate(90deg); 596 | } 597 | &.jconfirm-animation-rotatex { 598 | transform: rotateX(90deg); 599 | transform-origin: center; 600 | } 601 | &.jconfirm-animation-rotatexr { 602 | transform: rotateX(-90deg); 603 | transform-origin: center; 604 | } 605 | &.jconfirm-animation-rotatey { 606 | transform: rotatey(90deg); 607 | transform-origin: center; 608 | } 609 | &.jconfirm-animation-rotateyr { 610 | transform: rotatey(-90deg); 611 | transform-origin: center; 612 | } 613 | &.jconfirm-animation-scaley { 614 | transform: scaley(1.5); 615 | transform-origin: center; 616 | } 617 | &.jconfirm-animation-scalex { 618 | transform: scalex(1.5); 619 | transform-origin: center; 620 | } 621 | &.jconfirm-animation-top { 622 | transform: translate(0px, -100px); 623 | } 624 | &.jconfirm-animation-left { 625 | transform: translate(-100px, 0px); 626 | } 627 | &.jconfirm-animation-right { 628 | transform: translate(100px, 0px); 629 | } 630 | &.jconfirm-animation-bottom { 631 | transform: translate(0px, 100px); 632 | } 633 | &.jconfirm-animation-opacity { 634 | 635 | } 636 | &.jconfirm-animation-zoom { 637 | transform: scale(1.2); 638 | } 639 | &.jconfirm-animation-scale { 640 | transform: scale(0.5); 641 | } 642 | &.jconfirm-animation-none { 643 | visibility: hidden; 644 | } 645 | } 646 | } 647 | 648 | .jconfirm.jconfirm-supervan { 649 | .jconfirm-bg { 650 | background-color: rgba(54, 70, 93, .95); 651 | } 652 | 653 | .jconfirm-box { 654 | background-color: transparent; 655 | 656 | &.jconfirm-type-blue { 657 | border: none; 658 | } 659 | &.jconfirm-type-green { 660 | border: none; 661 | } 662 | &.jconfirm-type-red { 663 | border: none; 664 | } 665 | &.jconfirm-type-orange { 666 | border: none; 667 | } 668 | &.jconfirm-type-purple { 669 | border: none; 670 | } 671 | &.jconfirm-type-dark { 672 | border: none; 673 | } 674 | 675 | div.jconfirm-closeIcon { 676 | color: white; 677 | } 678 | 679 | div.jconfirm-title-c { 680 | text-align: center; 681 | color: white; 682 | font-size: 28px; 683 | font-weight: normal; 684 | > * { 685 | padding-bottom: 25px; 686 | } 687 | 688 | .jconfirm-icon-c { 689 | margin-right: 8px; 690 | margin-left: 0px; 691 | } 692 | } 693 | div.jconfirm-content-pane { 694 | margin-bottom: 25px; 695 | } 696 | div.jconfirm-content { 697 | text-align: center; 698 | color: white; 699 | 700 | &:empty { 701 | &:before { 702 | 703 | } 704 | &:after { 705 | 706 | } 707 | } 708 | } 709 | .jconfirm-buttons { 710 | text-align: center; 711 | 712 | button { 713 | font-size: 16px; 714 | border-radius: 2px; 715 | background: darken(#36465D, 3%); 716 | text-shadow: none; 717 | border: none; 718 | color: white; 719 | padding: 10px; 720 | min-width: 100px; 721 | } 722 | button + button { 723 | 724 | } 725 | } 726 | &.hilight { 727 | 728 | } 729 | } 730 | 731 | &.jconfirm-rtl { 732 | .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 733 | margin-left: 8px; 734 | margin-right: 0px; 735 | } 736 | } 737 | } 738 | 739 | .jconfirm.jconfirm-material { 740 | .jconfirm-bg { 741 | background-color: rgba(0, 0, 0, .67); 742 | } 743 | .jconfirm-box { 744 | background-color: white; 745 | box-shadow: 0 7px 8px -4px rgba(0, 0, 0, .2), 0 13px 19px 2px rgba(0, 0, 0, .14), 0 5px 24px 4px rgba(0, 0, 0, .12); 746 | padding: 30px 25px 10px 25px; 747 | 748 | .jconfirm-title-c .jconfirm-icon-c { 749 | margin-right: 8px; 750 | margin-left: 0px; 751 | } 752 | 753 | div.jconfirm-closeIcon { 754 | color: rgba(0, 0, 0, .87); 755 | } 756 | 757 | div.jconfirm-title-c { 758 | color: rgba(0, 0, 0, .87); 759 | font-size: 22px; 760 | font-weight: bold; 761 | } 762 | div.jconfirm-content { 763 | color: rgba(0, 0, 0, .87); 764 | 765 | &:empty { 766 | &:before { 767 | 768 | } 769 | &:after { 770 | 771 | } 772 | } 773 | } 774 | .jconfirm-buttons { 775 | text-align: right; 776 | 777 | button { 778 | text-transform: uppercase; 779 | font-weight: 500; 780 | } 781 | button + button { 782 | 783 | } 784 | } 785 | &.hilight { 786 | 787 | } 788 | } 789 | 790 | &.jconfirm-rtl { 791 | .jconfirm-title-c .jconfirm-icon-c { 792 | margin-left: 8px; 793 | margin-right: 0px; 794 | } 795 | } 796 | } 797 | 798 | .jconfirm.jconfirm-bootstrap { 799 | .jconfirm-bg { 800 | background-color: rgba(0, 0, 0, .21); 801 | } 802 | 803 | .jconfirm-box { 804 | background-color: white; 805 | box-shadow: 0 3px 8px 0px rgba(0, 0, 0, 0.2); 806 | border: solid 1px rgba(0, 0, 0, 0.4); 807 | padding: 15px 0 0; 808 | 809 | .jconfirm-title-c .jconfirm-icon-c { 810 | margin-right: 8px; 811 | margin-left: 0px; 812 | } 813 | 814 | div.jconfirm-closeIcon { 815 | color: rgba(0, 0, 0, 0.87); 816 | } 817 | 818 | div.jconfirm-title-c { 819 | color: rgba(0, 0, 0, 0.87); 820 | font-size: 22px; 821 | font-weight: bold; 822 | padding-left: 15px; 823 | padding-right: 15px; 824 | } 825 | div.jconfirm-content-pane { 826 | 827 | } 828 | div.jconfirm-content { 829 | color: rgba(0, 0, 0, 0.87); 830 | padding: 0px 15px; 831 | 832 | &:empty { 833 | &:before { 834 | 835 | } 836 | &:after { 837 | 838 | } 839 | } 840 | } 841 | .jconfirm-buttons { 842 | text-align: right; 843 | padding: 10px; 844 | margin: -5px 0 0px; 845 | border-top: solid 1px #ddd; 846 | overflow: hidden; 847 | border-radius: 0 0 4px 4px; 848 | 849 | button { 850 | font-weight: 500; 851 | } 852 | button + button { 853 | 854 | } 855 | } 856 | &.hilight { 857 | 858 | } 859 | } 860 | 861 | &.jconfirm-rtl { 862 | .jconfirm-title-c .jconfirm-icon-c { 863 | margin-left: 8px; 864 | margin-right: 0px; 865 | } 866 | } 867 | } 868 | 869 | .jconfirm.jconfirm-modern { 870 | .jconfirm-bg { 871 | background-color: slategray; 872 | opacity: .6; 873 | } 874 | 875 | .jconfirm-box { 876 | background-color: white; 877 | box-shadow: 0 7px 8px -4px rgba(0, 0, 0, .2), 0 13px 19px 2px rgba(0, 0, 0, .14), 0 5px 24px 4px rgba(0, 0, 0, .12); 878 | padding: 30px 30px 15px; 879 | 880 | div.jconfirm-closeIcon { 881 | color: rgba(0, 0, 0, 0.87); 882 | top: 15px; 883 | right: 15px; 884 | } 885 | 886 | div.jconfirm-title-c { 887 | color: rgba(0, 0, 0, .87); 888 | font-size: 24px; 889 | font-weight: bold; 890 | text-align: center; 891 | margin-bottom: 10px; 892 | 893 | .jconfirm-icon-c { 894 | transition: transform .5s; 895 | transform: scale(0); 896 | display: block; 897 | margin-right: 0px; 898 | margin-left: 0px; 899 | margin-bottom: 10px; 900 | font-size: 69px; 901 | color: #aaa; 902 | } 903 | } 904 | 905 | div.jconfirm-content { 906 | text-align: center; 907 | font-size: 15px; 908 | color: #777; 909 | margin-bottom: 25px; 910 | 911 | &:empty { 912 | &:before { 913 | 914 | } 915 | &:after { 916 | 917 | } 918 | } 919 | } 920 | .jconfirm-buttons { 921 | text-align: center; 922 | 923 | button { 924 | font-weight: bold; 925 | text-transform: uppercase; 926 | transition: background .1s; 927 | padding: 10px 20px; 928 | 929 | &.btn-success { 930 | 931 | } 932 | } 933 | button + button { 934 | margin-left: 4px; 935 | } 936 | } 937 | } 938 | &.jconfirm-open { 939 | .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 940 | transform: scale(1); 941 | } 942 | } 943 | } -------------------------------------------------------------------------------- /addons/whmcspf/templates.admin.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 25 | 26 | 27 | 30 |
31 | Header; 32 | $Footer = <<
38 | 39 | 65 | 66 | 67 |

当前运行版本: v1.5

68 | Footer; 69 | $info_management = << 71 |
72 |

73 | 请稍后 , 正在加载数据 74 |

75 |
76 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 113 | 114 | 213 | 214 | 217 | info_managementtemp; 218 | $HelloWorld = null; -------------------------------------------------------------------------------- /addons/whmcspf/whmcspf.php: -------------------------------------------------------------------------------- 1 | '端口转发流量统计', 10 | 'description' => '端口转发流量统计', 11 | 'author' => 'Flyqie', 12 | 'version' => '1.5', 13 | 'fields' => array( 14 | 'authkey' => array( 15 | 'FriendlyName' => '验证密钥', 16 | 'Type' => 'text', 17 | 'Size' => '500' 18 | ) 19 | ) 20 | ); 21 | } 22 | function whmcspf_activate() 23 | { 24 | try { 25 | if (!Capsule::schema()->hasTable('mod_whmcspf')) { 26 | Capsule::schema()->create('mod_whmcspf', function ($table) { 27 | $table->increments('id'); 28 | $table->text('serviceid'); 29 | $table->text('bandwidth'); 30 | $table->text('updatetime'); 31 | }); 32 | } 33 | if (!Capsule::schema()->hasTable('mod_whmcspf_suspservice')) { 34 | Capsule::schema()->create('mod_whmcspf_suspservice', function ($table) { 35 | $table->increments('id'); 36 | $table->text('serviceid'); 37 | $table->datetime('untime'); 38 | $table->datetime('addtime'); 39 | }); 40 | } 41 | } catch (Exception $e) { 42 | return [ 43 | 'status' => 'error', 44 | 'description' => '不能创建表 : ' . $e->getMessage() 45 | ]; 46 | } 47 | return array('status' => 'success','description' => '插件已经成功激活'); 48 | } 49 | function whmcspf_deactivate() 50 | { 51 | Capsule::schema()->dropIfExists('mod_whmcspf'); 52 | Capsule::schema()->dropIfExists('mod_whmcspf_suspservice'); 53 | 54 | return [ 55 | 'status' => 'success', 56 | 'description' => '模块卸载成功,你不爱老夏了' 57 | ]; 58 | } 59 | function whmcspf_output($vars) 60 | { 61 | if($_REQUEST['action'] == 'get_info_list'){ 62 | if(@$_REQUEST['ajax'] != 'true'){ 63 | exit('禁止直接访问'); 64 | } 65 | $infolist = Capsule::table('mod_whmcspf')->get(); 66 | $infolistarray = array(); 67 | $num = 0; 68 | foreach ($infolist as $values) { 69 | $suspfind = Capsule::table('mod_whmcspf_suspservice')->where('serviceid',$values->serviceid)->first(); 70 | $PackAgeINfo = Capsule::table('tblproducts')->where('id',Capsule::table('tblhosting')->where('id',$values->serviceid)->first()->packageid)->first(); 71 | if($PackAgeINfo){ 72 | $AllBandwidth = $PackAgeINfo->configoption1; 73 | }else{ 74 | $AllBandwidth = 0; 75 | } 76 | //$AllBandwidth = $PackAgeINfo->configoption1; 77 | $FreeBandwidth = $AllBandwidth - $values->bandwidth; 78 | if($FreeBandwidth < 0){ 79 | $FreeBandwidth = '0'; 80 | } 81 | if($suspfind){ 82 | $Status = '流量超限'; 83 | $unsptime = $suspfind->untime; 84 | }else{ 85 | $Status = '正常'; 86 | $unsptime = '无'; 87 | } 88 | $infolistarray[$num]['id'] = $values->id; 89 | $infolistarray[$num]['serviceid'] = '#'.$values->serviceid.''; 90 | $infolistarray[$num]['usedbandwidth'] = $values->bandwidth; 91 | $infolistarray[$num]['freebandwidth'] = $FreeBandwidth; 92 | $infolistarray[$num]['allbandwidth'] = $AllBandwidth; 93 | $infolistarray[$num]['updatetime'] = date('Y-m-d H:i:s', $values->updatetime); 94 | $infolistarray[$num]['unsptime'] = $unsptime; 95 | $infolistarray[$num]['status'] = $Status; 96 | $num++; 97 | } 98 | $Infoarray['result'] = 'success'; 99 | $Infoarray['info'] = $infolistarray; 100 | header('Content-Type: text/json; charset=utf-8'); 101 | exit(json_encode($Infoarray)); 102 | }else{ 103 | include 'templates.admin.php'; 104 | if(@$_REQUEST['ajax'] != 'true'){ 105 | echo $Header.PHP_EOL.$info_management.PHP_EOL.$Footer.PHP_EOL; 106 | }else{ 107 | exit($info_management.PHP_EOL); 108 | } 109 | } 110 | } 111 | function whmcspf_clientarea($vars) 112 | { 113 | if(@$_REQUEST['authkey'] != $vars['authkey']){ 114 | exit('验证密钥错误'); 115 | }else{ 116 | $PackAgeINfo = Capsule::table('tblproducts')->where('id',Capsule::table('tblhosting')->where('id',$_REQUEST['serviceid'])->first()->packageid)->first(); 117 | if(!$PackAgeINfo){ 118 | exit('产品找不到'); 119 | } 120 | if(!@$_REQUEST['serviceid'] || !@$_REQUEST['updatetime'] || !@$_REQUEST['bandwidth']){ 121 | exit('参数不完整'); 122 | } 123 | if(Capsule::table('tblhosting')->where('id',$_REQUEST['serviceid'])->first()->domainstatus != 'Active'){ 124 | //说明已经被暂停了,可以直接不进行下面的操作 125 | exit('success'); 126 | } 127 | if(Capsule::table('mod_whmcspf')->where('serviceid',$_REQUEST['serviceid'])->first()){ 128 | Capsule::table('mod_whmcspf')->where('serviceid',$_REQUEST['serviceid'])->update(['updatetime' => $_REQUEST['updatetime'],'bandwidth' => $_REQUEST['bandwidth']]); 129 | }else{ 130 | Capsule::table('mod_whmcspf')->insert(['serviceid' => $_REQUEST['serviceid'],'updatetime' => $_REQUEST['updatetime'],'serviceid' => $_REQUEST['serviceid'],'bandwidth' => $_REQUEST['bandwidth']]); 131 | } 132 | if(($PackAgeINfo->configoption1 < $_REQUEST['bandwidth'])){ 133 | //流量超额 134 | $unsusptime = date("Y-m", strtotime("+1 months")).'-1'; 135 | localAPI('ModuleSuspend', array('serviceid' => $_REQUEST['serviceid'],'suspendreason' => '流量超额'), Capsule::table('tbladmins')->first()->id); 136 | Capsule::table('tblhosting')->where('id',$_REQUEST['serviceid'])->update(['domainstatus' => 'Suspended']); 137 | whmcspf_setCustomfieldsValue('forwardstatus','maxtra',$_REQUEST['serviceid'],null); 138 | //如果产品到期时间小于解除暂停的时间,那么不作处理 139 | if(strtotime($unsusptime) < strtotime(Capsule::table('tblhosting')->where('id',$_REQUEST['serviceid'])->first()->nextduedate)){ 140 | Capsule::table('mod_whmcspf_suspservice')->insert(['serviceid' => $_REQUEST['serviceid'],'untime' => $unsusptime,'addtime' => date("Y-m-d")]); 141 | } 142 | } 143 | whmcspf_setCustomfieldsValue('bandwidth',$_REQUEST['bandwidth'],$_REQUEST['serviceid'],null); 144 | exit('success'); 145 | } 146 | } 147 | 148 | function whmcspf_setCustomfieldsValue($field,$value,$servid,$uid){ 149 | $ownerRow = Capsule::table('tblhosting')->where('id',$servid)->first(); 150 | if (!$ownerRow){ 151 | return false; 152 | } 153 | if (!is_null($uid) && $uid != $ownerRow->userid){ 154 | return false; 155 | } 156 | $res = Capsule::table('tblcustomfields')->where('relid',$ownerRow->packageid)->where('fieldname',$field)->first(); 157 | if ($res) { 158 | $fieldValue = Capsule::table('tblcustomfieldsvalues')->where('relid',$ownerRow->id)->where('fieldid',$res->id)->first(); 159 | if ($fieldValue) { 160 | if($fieldValue->value != $value) { 161 | Capsule::table('tblcustomfieldsvalues')->where('relid',$ownerRow->id)->where('fieldid', $res->id)->update(['value' => $value,]); 162 | }else{ 163 | Capsule::table('tblcustomfieldsvalues')->insert(['relid' => $ownerRow->id,'fieldid' => $res->id,'value' => $value]); 164 | } 165 | }else{ 166 | Capsule::table('tblcustomfieldsvalues')->insert(['relid' => $ownerRow->id,'fieldid' => $res->id,'value' => $value]); 167 | } 168 | } 169 | } -------------------------------------------------------------------------------- /pfnode/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "workerman/workerman": "^3.5", 4 | "topthink/think-orm": "^1.2", 5 | "predis/predis": "^1.1" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /pfnode/config.php: -------------------------------------------------------------------------------- 1 | 3 | //验证用户名 4 | $authusername = 'admin'; 5 | //验证密码 6 | $authpassword = 'admin'; 7 | //端口最大 8 | $portmax = 4095; 9 | //端口最小 10 | $portmin = 1000; 11 | //端口单次最大生成次数 12 | $portmakemax = 30; 13 | //当前服务器IP 14 | $serverip = '127.0.0.1'; 15 | //网站地址 16 | $websiteurl = 'http://www.baidu.com'; 17 | //与网站上的插件验证密钥一致 18 | $WebsiteAuthkey = ''; 19 | //Redis IP 20 | $RedisIP = ''; 21 | //Redis Port 22 | $RedisPort = 6379; 23 | //Redis Auth Pass 24 | $RedisPass = ''; 25 | //<------- 信息填写结束! ------> -------------------------------------------------------------------------------- /pfnode/database.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TachibanaSuzume/WhmcsPortForward/ebdbb8119bd8d3604636a5b99a57c6ff20c27f4d/pfnode/database.db -------------------------------------------------------------------------------- /pfnode/forward_service/ForwardSystem: -------------------------------------------------------------------------------- 1 | Hello,world! -------------------------------------------------------------------------------- /pfnode/service_file_template.php: -------------------------------------------------------------------------------- 1 | 'tcp','host' => $RedisIP,'port' => $RedisPort,'parameters'=>['password' => $RedisPass]]); 8 | if('[PTYPE]' == 'udp'){ 9 | $GlobalProxyService[[SERID]]['raddress'] = 'udp://[RSIP]:[RPORT]'; 10 | }else{ 11 | $GlobalProxyService[[SERID]]['raddress'] = 'tcp://[RSIP]:[RPORT]'; 12 | } 13 | if('[PTYPE]' == 'udp'){ 14 | $GlobalProxyService[[SERID]]['worker'] = new Worker('udp://0.0.0.0:[SPORT]'); 15 | }else{ 16 | $GlobalProxyService[[SERID]]['worker'] = new Worker('tcp://0.0.0.0:[SPORT]'); 17 | } 18 | ($GlobalProxyService[[SERID]]['worker'])->name = 'Service [SERID] Forward Worker'; 19 | if('[PTYPE]' == 'udp'){ 20 | ($GlobalProxyService[[SERID]]['worker'])->onConnect = function($connection)use($GlobalProxyService){ 21 | $connection_to_r = new AsyncUdpConnection($GlobalProxyService[[SERID]]['raddress']); 22 | $connection_to_r->onMessage = function($connection_to_r, $buffer)use($connection,$GlobalProxyService){ 23 | ($GlobalProxyService[[SERID]]['client'])->set('[SERID]_download',(($GlobalProxyService[[SERID]]['client'])->get('[SERID]_download'))+strlen($buffer)); 24 | $connection->send($buffer); 25 | }; 26 | $connection_to_r->onClose = function($connection_to_r)use($connection){ 27 | $connection->close(); 28 | }; 29 | $connection_to_r->connect(); 30 | $connection->onMessage = function($connection, $buffer)use($connection_to_r,$GlobalProxyService){ 31 | ($GlobalProxyService[[SERID]]['client'])->set('[SERID]_upload',(($GlobalProxyService[[SERID]]['client'])->get('[SERID]_upload'))+strlen($buffer)); 32 | $connection_to_r->send($buffer); 33 | }; 34 | $connection->onClose = function($connection)use($connection_to_r){ 35 | $connection_to_r->close(); 36 | }; 37 | $connection->onError = function($connection)use($connection_to_r){ 38 | @$connection_to_r->close(); 39 | }; 40 | }; 41 | }else{ 42 | ($GlobalProxyService[[SERID]]['worker'])->onConnect = function($connection)use($GlobalProxyService){ 43 | $connection_to_r = new AsyncTcpConnection($GlobalProxyService[[SERID]]['raddress']); 44 | $connection_to_r->onMessage = function($connection_to_r, $buffer)use($connection,$GlobalProxyService){ 45 | ($GlobalProxyService[[SERID]]['client'])->set('[SERID]_download',(($GlobalProxyService[[SERID]]['client'])->get('[SERID]_download'))+strlen($buffer)); 46 | $connection->send($buffer); 47 | }; 48 | $connection_to_r->onClose = function($connection_to_r)use($connection){ 49 | $connection->close(); 50 | }; 51 | $connection_to_r->onError = function($connection_to_r)use($connection){ 52 | $connection->close(); 53 | }; 54 | $connection_to_r->connect(); 55 | $connection->onMessage = function($connection, $buffer)use($connection_to_r,$GlobalProxyService){ 56 | ($GlobalProxyService[[SERID]]['client'])->set('[SERID]_upload',(($GlobalProxyService[[SERID]]['client'])->get('[SERID]_upload'))+strlen($buffer)); 57 | $connection_to_r->send($buffer); 58 | }; 59 | $connection_to_r->onBufferFull = function($connection_to_r)use($connection){ 60 | $connection->pauseRecv(); 61 | }; 62 | $connection->onBufferFull = function($connection)use($connection_to_r){ 63 | $connection_to_r->pauseRecv(); 64 | }; 65 | $connection->onBufferDrain = function($connection)use($connection_to_r){ 66 | $connection_to_r->resumeRecv(); 67 | }; 68 | $connection_to_r->onBufferDrain = function($connection_to_r)use($connection){ 69 | $connection->resumeRecv(); 70 | }; 71 | $connection->onClose = function($connection)use($connection_to_r){ 72 | $connection_to_r->close(); 73 | }; 74 | $connection->onError = function($connection)use($connection_to_r){ 75 | $connection_to_r->close(); 76 | }; 77 | }; 78 | } 79 | /** 80 | if(!defined('GLOBAL_START')){ 81 | Worker::runAll(); 82 | } 83 | **/ 84 | ($GlobalProxyService[[SERID]]['worker'])->listen(); 85 | /** 86 | $GlobalProxyService[[SERID]]['workerstop'] = false; 87 | ($GlobalProxyService[[SERID]]['worker'])->listen(); 88 | $Service_[SERID]_Timer = Timer::add(1, function()use(&$Service_[SERID]_Timer){ 89 | global $GlobalProxyService; 90 | $StopService = $GlobalProxyService[[SERID]]['workerstop']; 91 | if($StopService){ 92 | ($GlobalProxyService[[SERID]]['worker'])->stop(); 93 | echo 'Worker[SERID]STOP!!'.PHP_EOL; 94 | unset($GlobalProxyService[[SERID]]); 95 | Timer::del($Service_[SERID]_Timer); 96 | } 97 | }); 98 | **/ -------------------------------------------------------------------------------- /pfnode/start.php: -------------------------------------------------------------------------------- 1 | name = 'Forword Serice Autoloader'; 8 | $autoload_worker->reloadable = false; 9 | $autoload_tmp_file_info_main = json_decode(@file_get_contents(__DIR__.'/autoload.tmp'),true); 10 | if(!$autoload_tmp_file_info_main){ 11 | $autoload_last_mtime = time(); 12 | }else{ 13 | $autoload_last_mtime = $autoload_tmp_file_info_main['lastmtime']; 14 | } 15 | $autoload_last_file_list = array(); 16 | $autoload_worker->onWorkerStart = function(){ 17 | global $autoload_monitor_dir; 18 | Timer::add(10, 'autoload_check_files_change', array($autoload_monitor_dir)); 19 | }; 20 | if(!function_exists('autoload_check_files_change')){ 21 | function autoload_check_files_change($monitor_dir){ 22 | global $autoload_last_mtime,$autoload_last_file_list; 23 | $autoload_tmp_file_info = json_decode(@file_get_contents(__DIR__.'/autoload.tmp'),true); 24 | $dir_iterator = new RecursiveDirectoryIterator($monitor_dir); 25 | $iterator = new RecursiveIteratorIterator($dir_iterator); 26 | $tmplist = array(); 27 | foreach($iterator as $ListOne){ 28 | $tmplist[] = (string)$ListOne; 29 | } 30 | if(!@$autoload_tmp_file_info['list']){ 31 | $autoload_last_file_list = $tmplist; 32 | }else{ 33 | $autoload_last_file_list = $autoload_tmp_file_info['list']; 34 | } 35 | $NeedReloadFile = array(); 36 | foreach ($iterator as $file){ 37 | $Keys = array_keys($autoload_last_file_list,(string)$file); 38 | if(pathinfo($file, PATHINFO_EXTENSION) != 'php'){ 39 | unset($autoload_last_file_list[($Keys[0])]); 40 | continue; 41 | } 42 | if(empty(@$Keys[0]) && @$Keys[0] != 0){ 43 | echo $file." update and reload#1\n"; 44 | $NeedReloadFile[] = (string)$file; 45 | continue; 46 | } 47 | if($autoload_last_mtime < $file->getMTime()){ 48 | echo $file." update and reload#2\n"; 49 | $NeedReloadFile[] = (string)$file; 50 | continue; 51 | } 52 | unset($autoload_last_file_list[($Keys[0])]); 53 | } 54 | if(!empty($autoload_last_file_list)){ 55 | foreach($autoload_last_file_list as $_autoload_last_file_list){ 56 | if(!array_keys($NeedReloadFile,$_autoload_last_file_list)){ 57 | $NeedReloadFile[] = $_autoload_last_file_list; 58 | } 59 | } 60 | } 61 | if(count($NeedReloadFile) > 0){ 62 | echo "All update and reload\n"; 63 | $autoload_last_mtime = time(); 64 | file_put_contents(__DIR__.'/autoload.tmp',json_encode(array('list' => $tmplist,'lastmtime' => $autoload_last_mtime))); 65 | file_put_contents(__DIR__.'/autoreload.tmp',json_encode(array('reloadfile' => $NeedReloadFile))); 66 | posix_kill(posix_getppid(), SIGUSR1); 67 | sleep(2); 68 | return ; 69 | }else{ 70 | $autoload_last_mtime = time(); 71 | $autoload_last_file_list = $tmplist; 72 | } 73 | file_put_contents(__DIR__.'/autoload.tmp',json_encode(array('list' => $autoload_last_file_list,'lastmtime' => $autoload_last_mtime))); 74 | if(!file_exists(__DIR__.'/autoreload.tmp')){ 75 | file_put_contents(__DIR__.'/autoreload.tmp',json_encode(array('reloadfile' => array()))); 76 | } 77 | clearstatcache(); 78 | } 79 | } -------------------------------------------------------------------------------- /pfnode/start_http.php: -------------------------------------------------------------------------------- 1 | name = 'Http Api Server'; 7 | $http_worker->count = 4; 8 | include __DIR__.'/config.php'; 9 | $api_redis_client = new Predis\Client(['scheme' => 'tcp','host' => $RedisIP,'port' => $RedisPort,'parameters'=>['password' => $RedisPass]]); 10 | Db::setConfig(['type'=> 'sqlite','database'=> 'database.db','prefix'=> '','debug'=> true]); 11 | $http_worker->onMessage = function($connection, $data){ 12 | global $api_redis_client; 13 | include __DIR__.'/config.php'; 14 | if(!@$_REQUEST['username'] || !@$_REQUEST['password'] || !@$_REQUEST['action'] || !@$_REQUEST['serviceid']){ 15 | $connection->send(json_encode(array('code' => 403,'msg' => '参数不全#1'))); 16 | return ; 17 | } 18 | if((trim($_REQUEST['username']) != $authusername) || (trim($_REQUEST['password']) != $authpassword)){ 19 | $connection->send(json_encode(array('code' => 403,'msg' => '鉴权错误'))); 20 | return ; 21 | } 22 | if(trim($_REQUEST['action']) == 'add'){ 23 | if(!@$_REQUEST['ptype'] || !@$_REQUEST['rport'] || !@$_REQUEST['rsip']){ 24 | $connection->send(json_encode(array('code' => 500,'msg' => '参数不全#2'))); 25 | return ; 26 | } 27 | if(Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->find()){ 28 | $connection->send(json_encode(array('code' => 500,'msg' => 'ServiceID已经存在'))); 29 | return ; 30 | } 31 | if(trim($_REQUEST['ptype']) != 'tcp' && trim($_REQUEST['ptype']) != 'udp'){ 32 | $connection->send(json_encode(array('code' => 500,'msg' => '转发类别错误'))); 33 | return ; 34 | } 35 | while(true){ 36 | $makenum = 0; 37 | $portnum = mt_rand($portmin,$portmax); 38 | if($makenum >= $portmakemax){ 39 | $portnum = null; 40 | break; 41 | } 42 | if(!(Db::table('pfinfo')->where('sport',$portnum)->find())){ 43 | break; 44 | } 45 | $makenum++; 46 | } 47 | if(!$portnum){ 48 | $connection->send(json_encode(array('code' => 500,'msg' => '端口生成次数已经超过限制,请稍候重试'))); 49 | return ; 50 | } 51 | $ServiceFileInfo = pf_gen_service_php(trim($_REQUEST['ptype']),trim($_REQUEST['serviceid']),trim($_REQUEST['rsip']),trim($_REQUEST['rport']),$portnum); 52 | file_put_contents(__DIR__.'/forward_service/'.trim($_REQUEST['serviceid']).'.php',$ServiceFileInfo); 53 | $sqlreturn = Db::table('pfinfo')->insert(["bandwidth" => '0',"status" => 'ok',"updatetime" => time(),"addtime" => time(),"serviceid" => trim($_REQUEST['serviceid']),"ptype" => trim($_REQUEST['ptype']),"rsip" => trim($_REQUEST['rsip']),"rport" => trim($_REQUEST['rport']),"sport" => $portnum]); 54 | if($sqlreturn){ 55 | $api_redis_client->set(trim($_REQUEST['serviceid']).'_upload','0'); 56 | $api_redis_client->set(trim($_REQUEST['serviceid']).'_download','0'); 57 | $connection->send(json_encode(array('code' => 200,'msg' => '添加成功','sport' => $portnum))); 58 | }else{ 59 | $connection->send(json_encode(array('code' => 500,'msg' => '数据库操作失败'))); 60 | @unlink(__DIR__.'/forward_service/'.trim($_REQUEST['serviceid']).'.php'); 61 | } 62 | return ; 63 | }elseif(trim($_REQUEST['action']) == 'del'){ 64 | $DelInfo = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->find(); 65 | if(!$DelInfo){ 66 | $connection->send(json_encode(array('code' => 500,'msg' => 'ServiceID不存在'))); 67 | return ; 68 | } 69 | @unlink(__DIR__.'/forward_service/'.trim($_REQUEST['serviceid']).'.php'); 70 | $sqlreturn = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->delete(); 71 | if($sqlreturn){ 72 | $api_redis_client->del(trim($_REQUEST['serviceid']).'_upload'); 73 | $api_redis_client->del(trim($_REQUEST['serviceid']).'_download'); 74 | $connection->send(json_encode(array('code' => 200,'msg' => '删除成功'))); 75 | }else{ 76 | $connection->send(json_encode(array('code' => 500,'msg' => '数据库操作失败'))); 77 | } 78 | return ; 79 | }elseif(trim($_REQUEST['action']) == 'update'){ 80 | $ServiceInfo = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->find(); 81 | if(!$ServiceInfo){ 82 | $connection->send(json_encode(array('code' => 500,'msg' => 'ServiceID不存在'))); 83 | return ; 84 | } 85 | if(!@$_REQUEST['ptype'] || !@$_REQUEST['rport'] || !@$_REQUEST['rsip']){ 86 | $connection->send(json_encode(array('code' => 500,'msg' => '参数不全#2'))); 87 | return ; 88 | } 89 | if(trim($_REQUEST['ptype']) != 'tcp' && trim($_REQUEST['ptype']) != 'udp'){ 90 | $connection->send(json_encode(array('code' => 500,'msg' => '转发类别错误'))); 91 | return ; 92 | } 93 | $ServiceFileInfo = pf_gen_service_php(trim($_REQUEST['ptype']),trim($ServiceInfo['serviceid']),trim($_REQUEST['rsip']),trim($_REQUEST['rport']),trim($ServiceInfo['sport'])); 94 | file_put_contents(__DIR__.'/forward_service/'.trim($_REQUEST['serviceid']).'.php',$ServiceFileInfo); 95 | $sqlreturn = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->update(["rsip" => trim($_REQUEST['rsip']),"rport" => trim($_REQUEST['rport']),"ptype" => trim($_REQUEST['ptype'])]); 96 | if($sqlreturn){ 97 | $connection->send(json_encode(array('code' => 200,'msg' => '更新成功'))); 98 | }else{ 99 | $connection->send(json_encode(array('code' => 500,'msg' => '数据库操作失败'))); 100 | } 101 | return ; 102 | }elseif(trim($_REQUEST['action']) == 'unsusp'){ 103 | $ServiceInfo = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->find(); 104 | if(!$ServiceInfo){ 105 | $connection->send(json_encode(array('code' => 500,'msg' => 'ServiceID不存在'))); 106 | return ; 107 | } 108 | $ServiceFileInfo = pf_gen_service_php(trim($ServiceInfo['ptype']),trim($ServiceInfo['serviceid']),trim($ServiceInfo['rsip']),trim($ServiceInfo['rport']),trim($ServiceInfo['sport'])); 109 | file_put_contents(__DIR__.'/forward_service/'.trim($_REQUEST['serviceid']).'.php',$ServiceFileInfo); 110 | $sqlreturn = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->update(["status" => 'ok']); 111 | if($sqlreturn){ 112 | $connection->send(json_encode(array('code' => 200,'msg' => '解除暂停成功'))); 113 | }else{ 114 | $connection->send(json_encode(array('code' => 500,'msg' => '数据库操作失败'))); 115 | } 116 | return ; 117 | }elseif(trim($_REQUEST['action']) == 'rebuild'){ 118 | $ServiceInfo = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->find(); 119 | if(!$ServiceInfo){ 120 | $connection->send(json_encode(array('code' => 500,'msg' => 'ServiceID不存在'))); 121 | return ; 122 | } 123 | $ServiceFileInfo = pf_gen_service_php(trim($ServiceInfo['ptype']),trim($ServiceInfo['serviceid']),trim($ServiceInfo['rsip']),trim($ServiceInfo['rport']),trim($ServiceInfo['sport'])); 124 | file_put_contents(__DIR__.'/forward_service/'.trim($_REQUEST['serviceid']).'.php',$ServiceFileInfo); 125 | $connection->send(json_encode(array('code' => 200,'msg' => '重建成功'))); 126 | return ; 127 | }elseif(trim($_REQUEST['action']) == 'susp'){ 128 | $ServiceInfo = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->find(); 129 | if(!$ServiceInfo){ 130 | $connection->send(json_encode(array('code' => 500,'msg' => 'ServiceID不存在'))); 131 | return ; 132 | } 133 | @unlink(__DIR__.'/forward_service/'.trim($_REQUEST['serviceid']).'.php'); 134 | $sqlreturn = Db::table('pfinfo')->where('serviceid',trim($_REQUEST['serviceid']))->update(["status" => 'susp']); 135 | if($sqlreturn){ 136 | $connection->send(json_encode(array('code' => 200,'msg' => '暂停成功'))); 137 | }else{ 138 | $connection->send(json_encode(array('code' => 500,'msg' => '数据库操作失败'))); 139 | } 140 | return ; 141 | }elseif(trim($_REQUEST['action']) == 'test'){ 142 | $connection->send(json_encode(array('code' => 200,'msg' => '对接成功'))); 143 | return ; 144 | }else{ 145 | $connection->send(json_encode(array('code' => 404,'msg' => '动作不存在'))); 146 | return ; 147 | } 148 | }; 149 | if(!function_exists('pf_gen_service_php')){ 150 | function pf_gen_service_php($ptype,$serviceid,$rsip,$rport,$sport){ 151 | if(filter_var(trim($rsip), FILTER_VALIDATE_IP,FILTER_FLAG_IPV6)){ 152 | $rsip = '['.trim($rsip).']'; 153 | } 154 | $info = file_get_contents(__DIR__.'/service_file_template.php'); 155 | $info = str_replace("[PTYPE]",$ptype,$info); 156 | $info = str_replace("[SERID]",$serviceid,$info); 157 | $info = str_replace("[RSIP]",$rsip,$info); 158 | $info = str_replace("[RPORT]",$rport,$info); 159 | $info = str_replace("[SPORT]",$sport,$info); 160 | return $info; 161 | } 162 | } 163 | if(!defined('GLOBAL_START')) 164 | { 165 | Worker::runAll(); 166 | } -------------------------------------------------------------------------------- /pfnode/start_report.php: -------------------------------------------------------------------------------- 1 | 'tcp','host' => $RedisIP,'port' => $RedisPort,'parameters'=>['password' => $RedisPass]]); 23 | $report_worker = new Worker(); 24 | $report_worker->count = 1; 25 | $report_worker->name = 'Report Service'; 26 | $report_worker->onWorkerStart = function($report_worker) 27 | { 28 | Db::setConfig(['type'=> 'sqlite','database'=> 'database.db','prefix'=> '','debug'=> true]); 29 | //流量统计上报 30 | \Workerman\Lib\Timer::add(30, function(){ 31 | include __DIR__.'/config.php'; 32 | try { 33 | $data = Db::table('pfinfo')->where('status','ok')->select(); 34 | } catch (Exception $e) { 35 | return ; 36 | } 37 | foreach ($data as $dataone){ 38 | $returnstatus = report_curl_post_https($websiteurl.'/?m=whmcspf&action=reporttraffic',array('serviceid' => $dataone['serviceid'],'authkey' => $WebsiteAuthkey,'updatetime' => $dataone['updatetime'],'bandwidth' => $dataone['bandwidth'])); 39 | if(trim($returnstatus) != 'success'){ 40 | echo '['.date("Y-m-d h:i:sa").'] '.'上报'.json_encode(array('serviceid' => $dataone['serviceid'],'updatetime' => $dataone['updatetime'],'bandwidth' => $dataone['bandwidth'])).'时失败,服务器返回'.$returnstatus.PHP_EOL; 41 | file_put_contents('error.log','['.date("Y-m-d h:i:sa").'] '.'上报'.json_encode(array('serviceid' => $dataone['serviceid'],'updatetime' => $dataone['updatetime'],'bandwidth' => $dataone['bandwidth'])).'时失败,服务器返回'.$returnstatus.PHP_EOL,FILE_APPEND); 42 | } 43 | } 44 | unset($data); 45 | }); 46 | //流量实时统计 47 | \Workerman\Lib\Timer::add(17, function(){ 48 | global $report_redis_client; 49 | include __DIR__.'/config.php'; 50 | try { 51 | $data = Db::table('pfinfo')->where('status','ok')->select(); 52 | } catch (Exception $e) { 53 | return ; 54 | } 55 | foreach ($data as $dataone){ 56 | $UploadByte = @$report_redis_client->get($dataone['serviceid'].'_upload'); 57 | @$report_redis_client->set($dataone['serviceid'].'_upload','0'); 58 | if(!$UploadByte){ 59 | $UploadByte = 0; 60 | } 61 | $UploadMb = round($UploadByte/1024/1024, 2); 62 | $DownloadByte = @$report_redis_client->get($dataone['serviceid'].'_download'); 63 | @$report_redis_client->set($dataone['serviceid'].'_download','0'); 64 | if(!$DownloadByte){ 65 | $DownloadByte = 0; 66 | } 67 | $DownloadMb = round($DownloadByte/1024/1024, 2); 68 | $NewBandWidth = $UploadMb + $DownloadMb; 69 | //入库 70 | try { 71 | Db::table('pfinfo')->where('id',$dataone['id'])->update(["bandwidth" => $dataone['bandwidth'] + $NewBandWidth,"updatetime" => time()]); 72 | } catch (Exception $e) { 73 | } 74 | } 75 | unset($data); 76 | }); 77 | }; 78 | if(!defined('GLOBAL_START')) 79 | { 80 | Worker::runAll(); 81 | } -------------------------------------------------------------------------------- /pfnode/start_service.php: -------------------------------------------------------------------------------- 1 | name = 'Forword Serice Main'; 6 | $service_worker->reloadable = false; 7 | if(!@$GlobalProxyService){ 8 | $GlobalProxyService = array(); 9 | } 10 | $service_worker->onWorkerStart = function(){ 11 | global $GlobalProxyService; 12 | foreach(glob(__DIR__.'/forward_service/*.php') as $start_filet){ 13 | require $start_filet; 14 | } 15 | }; 16 | $service_worker->onWorkerReload = function($worker){ 17 | global $GlobalProxyService; 18 | $autoreload_tmp_file_info_main = json_decode(@file_get_contents(__DIR__.'/autoreload.tmp'),true); 19 | if(@$autoreload_tmp_file_info_main['reloadfile']){ 20 | $reloadfile = $autoreload_tmp_file_info_main['reloadfile']; 21 | foreach($reloadfile as $_reloadfile){ 22 | $_reloadfile_name = pathinfo($_reloadfile, PATHINFO_BASENAME); 23 | $_reloadfile_name = @(explode('.',$_reloadfile_name))[0]; 24 | if(@$GlobalProxyService[$_reloadfile_name]){ 25 | echo $_reloadfile_name.'STOP!!!'.PHP_EOL; 26 | ($GlobalProxyService[$_reloadfile_name]['worker'])->stop(); 27 | unset($GlobalProxyService[$_reloadfile_name]); 28 | } 29 | if(file_exists($_reloadfile)){ 30 | require $_reloadfile; 31 | echo $_reloadfile.'START!!!'.PHP_EOL; 32 | } 33 | } 34 | } 35 | @unlink(__DIR__.'/autoreload.tmp'); 36 | }; -------------------------------------------------------------------------------- /servers/portforward/portforward.php: -------------------------------------------------------------------------------- 1 | 'PortForward', 12 | 'APIVersion' => '1.1', 13 | 'RequiresServer' => true, 14 | ); 15 | } 16 | 17 | function portforward_ConfigOptions() 18 | { 19 | return array( 20 | '每月流量(Mb)' => array( 21 | 'Type' => 'text', 22 | 'Size' => '500' 23 | ) 24 | ); 25 | } 26 | 27 | function portforward_CreateAccount(array $params) 28 | { 29 | try { 30 | $postfields['username'] = $params['serverusername']; 31 | $postfields['password'] = $params['serverpassword']; 32 | $postfields['action'] = 'add'; 33 | $postfields['serviceid'] = $params['serviceid']; 34 | if(!filter_var(trim($params['customfields']['rsip']), FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) && !filter_var(trim($params['customfields']['rsip']), FILTER_VALIDATE_IP)){ 35 | throw new Exception('IP不正确'); 36 | } 37 | if(!is_numeric(trim($params['customfields']['rport'])) || trim($params['customfields']['rport']) > 25535 || trim($params['customfields']['rport']) < 1){ 38 | throw new Exception('端口不正确'); 39 | } 40 | $postfields['ptype'] = trim($params['customfields']['ptype']); 41 | $postfields['rport'] = trim($params['customfields']['rport']); 42 | $postfields['rsip'] = trim($params['customfields']['rsip']); 43 | $ReturnInfo = json_decode(portforward_curlconnect('http://'.$params['serverip'].':1388/',$postfields),true); 44 | if(!$ReturnInfo){ 45 | throw new Exception('服务器返回信息为空'); 46 | } 47 | if($ReturnInfo['code'] == 200){ 48 | Capsule::table('tblhosting')->where('id',$params['serviceid'])->update(['domain' => $params['customfields']['rsip'].':'.trim($params['customfields']['rport'])]); 49 | portforward_setCustomfieldsValue('sport',$ReturnInfo['sport'],$params['serviceid'],null); 50 | return 'success'; 51 | }else{ 52 | throw new Exception('开通失败,'.$ReturnInfo['msg']); 53 | } 54 | } catch (Exception $e) { 55 | logModuleCall( 56 | 'portforward', 57 | __FUNCTION__, 58 | $params, 59 | $e->getMessage(), 60 | $e->getTraceAsString() 61 | ); 62 | return $e->getMessage(); 63 | } 64 | } 65 | 66 | function portforward_SuspendAccount(array $params) 67 | { 68 | try { 69 | $postfields['username'] = $params['serverusername']; 70 | $postfields['password'] = $params['serverpassword']; 71 | $postfields['action'] = 'susp'; 72 | $postfields['serviceid'] = $params['serviceid']; 73 | $ReturnInfo = json_decode(portforward_curlconnect('http://'.$params['serverip'].':1388/',$postfields),true); 74 | if(!$ReturnInfo){ 75 | throw new Exception('服务器返回信息为空'); 76 | } 77 | if($ReturnInfo['code'] == 200){ 78 | return 'success'; 79 | }else{ 80 | throw new Exception('暂停失败,'.$ReturnInfo['msg']); 81 | } 82 | } catch (Exception $e) { 83 | logModuleCall( 84 | 'portforward', 85 | __FUNCTION__, 86 | $params, 87 | $e->getMessage(), 88 | $e->getTraceAsString() 89 | ); 90 | return $e->getMessage(); 91 | } 92 | } 93 | 94 | function portforward_RebuildConf(array $params) 95 | { 96 | try { 97 | $postfields['username'] = $params['serverusername']; 98 | $postfields['password'] = $params['serverpassword']; 99 | $postfields['action'] = 'rebuild'; 100 | $postfields['serviceid'] = $params['serviceid']; 101 | $ReturnInfo = json_decode(portforward_curlconnect('http://'.$params['serverip'].':1388/',$postfields),true); 102 | if(!$ReturnInfo){ 103 | throw new Exception('服务器返回信息为空'); 104 | } 105 | if($ReturnInfo['code'] == 200){ 106 | return 'success'; 107 | }else{ 108 | throw new Exception('重建失败,'.$ReturnInfo['msg']); 109 | } 110 | } catch (Exception $e) { 111 | logModuleCall( 112 | 'portforward', 113 | __FUNCTION__, 114 | $params, 115 | $e->getMessage(), 116 | $e->getTraceAsString() 117 | ); 118 | return $e->getMessage(); 119 | } 120 | } 121 | 122 | function portforward_AdminCustomButtonArray(){ 123 | return array( 124 | "重建" => "RebuildConf" 125 | ); 126 | } 127 | 128 | function portforward_UnsuspendAccount(array $params) 129 | { 130 | try { 131 | $postfields['username'] = $params['serverusername']; 132 | $postfields['password'] = $params['serverpassword']; 133 | $postfields['action'] = 'unsusp'; 134 | $postfields['serviceid'] = $params['serviceid']; 135 | $ReturnInfo = json_decode(portforward_curlconnect('http://'.$params['serverip'].':1388/',$postfields),true); 136 | if(!$ReturnInfo){ 137 | throw new Exception('服务器返回信息为空'); 138 | } 139 | if($ReturnInfo['code'] == 200){ 140 | return 'success'; 141 | }else{ 142 | throw new Exception('解除暂停失败,'.$ReturnInfo['msg']); 143 | } 144 | } catch (Exception $e) { 145 | logModuleCall( 146 | 'portforward', 147 | __FUNCTION__, 148 | $params, 149 | $e->getMessage(), 150 | $e->getTraceAsString() 151 | ); 152 | return $e->getMessage(); 153 | } 154 | } 155 | 156 | function portforward_TerminateAccount(array $params) 157 | { 158 | try { 159 | $postfields['username'] = $params['serverusername']; 160 | $postfields['password'] = $params['serverpassword']; 161 | $postfields['action'] = 'del'; 162 | $postfields['serviceid'] = $params['serviceid']; 163 | $ReturnInfo = json_decode(portforward_curlconnect('http://'.$params['serverip'].':1388/',$postfields),true); 164 | if(!$ReturnInfo){ 165 | throw new Exception('服务器返回信息为空'); 166 | } 167 | if($ReturnInfo['code'] == 200){ 168 | return 'success'; 169 | }else{ 170 | throw new Exception('删除失败,'.$ReturnInfo['msg']); 171 | } 172 | } catch (Exception $e) { 173 | logModuleCall( 174 | 'portforward', 175 | __FUNCTION__, 176 | $params, 177 | $e->getMessage(), 178 | $e->getTraceAsString() 179 | ); 180 | 181 | return $e->getMessage(); 182 | } 183 | } 184 | 185 | function portforward_ClientArea(array $params) 186 | { 187 | if($_REQUEST['pfaction'] == 'changevalue'){ 188 | if(!$_REQUEST['rsip'] || !$_REQUEST['rport']){ 189 | exit(json_encode(array('result' => 'failed','msg' => '转发到的IP和端口不得为空'))); 190 | } 191 | if(!filter_var(trim($_REQUEST['rsip']), FILTER_VALIDATE_IP,FILTER_FLAG_IPV6) && !filter_var(trim($_REQUEST['rsip']), FILTER_VALIDATE_IP)){ 192 | exit(json_encode(array('result' => 'failed','msg' => 'IP不正确'))); 193 | } 194 | if(!is_numeric(trim($_REQUEST['rport'])) || trim($_REQUEST['rport']) > 25535 || trim($_REQUEST['rport']) < 1){ 195 | exit(json_encode(array('result' => 'failed','msg' => '端口不正确'))); 196 | } 197 | $postfields['username'] = $params['serverusername']; 198 | $postfields['password'] = $params['serverpassword']; 199 | $postfields['action'] = 'update'; 200 | $postfields['serviceid'] = $params['serviceid']; 201 | $postfields['rsip'] = trim($_REQUEST['rsip']); 202 | $postfields['rport'] = trim($_REQUEST['rport']); 203 | $postfields['ptype'] = trim($params['customfields']['ptype']); 204 | $ReturnInfo = json_decode(portforward_curlconnect('http://'.$params['serverip'].':1388/',$postfields),true); 205 | if(!$ReturnInfo){ 206 | exit(json_encode(array('result' => 'failed','msg' => 'ServiceID不存在'))); 207 | } 208 | if($ReturnInfo['code'] == 200){ 209 | portforward_setCustomfieldsValue('rsip|源服务器IP',trim($_REQUEST['rsip']),$params['serviceid'],null); 210 | portforward_setCustomfieldsValue('rport|源服务器端口',trim($_REQUEST['rport']),$params['serviceid'],null); 211 | Capsule::table('tblhosting')->where('id',$params['serviceid'])->update(['domain' => trim($_REQUEST['rsip']).':'.trim($_REQUEST['rport'])]); 212 | exit(json_encode(array('result' => 'success','msg' => ''))); 213 | }else{ 214 | exit(json_encode(array('result' => 'failed','msg' => $ReturnInfo['msg']))); 215 | } 216 | } 217 | if(trim($params['customfields']['forwardstatus']) == 'maxtra'){ 218 | $templatevar['forwardstatus'] = '流量超额'; 219 | }else{ 220 | $templatevar['forwardstatus'] = '正常'; 221 | } 222 | $ProxyIP = null; 223 | $HashInfo = portforward_gethashinfo($params['serveraccesshash']); 224 | if(@$HashInfo['proxyip']){ 225 | $ProxyIPArray = explode(',',trim($HashInfo['proxyip'])); 226 | foreach($ProxyIPArray as $ProxyIPOne){ 227 | $ProxyIP .= $ProxyIPOne.'
'; 228 | } 229 | $ProxyIP = rtrim($ProxyIP,'
'); 230 | }else{ 231 | $ProxyIP .= $params['serverip']; 232 | } 233 | $ProxyIP = base64_encode($ProxyIP); 234 | $templatevar['ptype'] = trim($params['customfields']['ptype']); 235 | $templatevar['sport'] = trim($params['customfields']['sport']); 236 | $templatevar['sip'] = $ProxyIP; 237 | $templatevar['rsip'] = trim($params['customfields']['rsip']); 238 | $templatevar['rport'] = trim($params['customfields']['rport']); 239 | $templatevar['usedbandwidth'] = trim($params['customfields']['bandwidth']); 240 | $templatevar['alldbandwidth'] = trim($params['configoption1']); 241 | $templatevar['freedbandwidth'] = $templatevar['alldbandwidth'] - $templatevar['usedbandwidth']; 242 | if((int)$templatevar['freedbandwidth'] < 0){ 243 | $templatevar['freedbandwidth'] = '0'; 244 | } 245 | return array( 246 | 'tabOverviewReplacementTemplate' => 'templates/clientarea.tpl', 247 | 'templateVariables' => $templatevar, 248 | ); 249 | } 250 | 251 | function portforward_curlconnect($url,$postfields){ 252 | $ch = curl_init(); 253 | curl_setopt($ch, CURLOPT_URL, $url); 254 | curl_setopt($ch, CURLOPT_POST, 1); 255 | curl_setopt($ch, CURLOPT_TIMEOUT, 20); 256 | curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1); 257 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 258 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 259 | curl_setopt($ch, CURLOPT_HEADER, 0); 260 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 261 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields); 262 | $data = curl_exec($ch); 263 | curl_close($ch); 264 | return $data; 265 | } 266 | 267 | function portforward_TestConnection($params){ 268 | $postfields['username'] = $params['serverusername']; 269 | $postfields['password'] = $params['serverpassword']; 270 | $postfields['action'] = 'test'; 271 | $postfields['serviceid'] = 'none'; 272 | $ReturnInfo = json_decode(portforward_curlconnect('http://'.$params['serverip'].':1388/',$postfields),true); 273 | if(!$ReturnInfo){ 274 | return array('success' => false,'error' => '服务器返回信息为空'); 275 | } 276 | if($ReturnInfo['code'] == 200){ 277 | return array('success' => true,'error' => ''); 278 | }else{ 279 | return array('success' => false,'error' => $ReturnInfo['msg']); 280 | } 281 | } 282 | 283 | function portforward_setCustomfieldsValue($field,$value,$servid,$uid){ 284 | $ownerRow = Capsule::table('tblhosting')->where('id',$servid)->first(); 285 | if (!$ownerRow){ 286 | return false; 287 | } 288 | if (!is_null($uid) && $uid != $ownerRow->userid){ 289 | return false; 290 | } 291 | $res = Capsule::table('tblcustomfields')->where('relid',$ownerRow->packageid)->where('fieldname',$field)->first(); 292 | if ($res) { 293 | $fieldValue = Capsule::table('tblcustomfieldsvalues')->where('relid',$ownerRow->id)->where('fieldid',$res->id)->first(); 294 | if ($fieldValue) { 295 | if($fieldValue->value != $value) { 296 | Capsule::table('tblcustomfieldsvalues')->where('relid',$ownerRow->id)->where('fieldid', $res->id)->update(['value' => $value,]); 297 | }else{ 298 | Capsule::table('tblcustomfieldsvalues')->insert(['relid' => $ownerRow->id,'fieldid' => $res->id,'value' => $value]); 299 | } 300 | }else{ 301 | Capsule::table('tblcustomfieldsvalues')->insert(['relid' => $ownerRow->id,'fieldid' => $res->id,'value' => $value]); 302 | } 303 | } 304 | } 305 | 306 | function portforward_gethashinfo($data){ 307 | preg_match_all( '/<(.*?)>([^<]+)<\/\\1>/i', $data, $matches ); 308 | $result = array(); 309 | foreach($matches[1] as $k => $v){ 310 | $result[$v] = $matches[2][$k]; 311 | } 312 | return $result; 313 | } -------------------------------------------------------------------------------- /servers/portforward/templates/clientarea.tpl: -------------------------------------------------------------------------------- 1 | {if $rawstatus eq 'active'} 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

服务信息 Service Detail

10 |
11 |
12 |
13 | 51 |
52 |
53 |
54 | 57 |
58 |
59 |

产品信息 Product Detail

60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | 转发类型 68 |
69 |
70 | {$ptype} 71 |
72 |
73 |
74 |
75 |
76 |
77 | 转发IP 78 |
79 |
80 | 点我获取IP 81 |
82 |
83 |
84 |
85 |
86 |
87 | 转发端口 88 |
89 |
90 | {$sport} 91 |
92 |
93 |
94 |
95 |
96 |
97 | 源IP 98 |
99 |
100 | {$rsip} 101 |
102 |
103 |
104 |
105 |
106 |
107 | 源端口 108 |
109 |
110 | {$rport} 111 |
112 |
113 |
114 |
115 |
116 |
117 | 转发状态 118 |
119 |
120 | {$forwardstatus} 121 |
122 |
123 |
124 |
125 |
126 |
127 | 已用流量 128 |
129 |
130 | {$usedbandwidth} Mb 131 |
132 |
133 |
134 |
135 |
136 |
137 | 可用流量 138 |
139 |
140 | {$freedbandwidth} Mb 141 |
142 |
143 |
144 |
145 |
146 |
147 | 总流量 148 |
149 |
150 | {$alldbandwidth} Mb 151 |
152 |
153 |
154 |
155 |
156 | {literal} 157 | 238 | {else} 239 | 抱歉,该产品目前无法管理({$status}) 240 | {if $suspendreason} 241 | ,原因:{$suspendreason} 242 | {/if} 243 | {/if} -------------------------------------------------------------------------------- /servers/portforward/theme/base64.js: -------------------------------------------------------------------------------- 1 | /* 2 | * base64.js 3 | * 4 | * Licensed under the BSD 3-Clause License. 5 | * http://opensource.org/licenses/BSD-3-Clause 6 | * 7 | * References: 8 | * http://en.wikipedia.org/wiki/Base64 9 | */ 10 | ;(function (global, factory) { 11 | typeof exports === 'object' && typeof module !== 'undefined' 12 | ? module.exports = factory(global) 13 | : typeof define === 'function' && define.amd 14 | ? define(factory) : factory(global) 15 | }(( 16 | typeof self !== 'undefined' ? self 17 | : typeof window !== 'undefined' ? window 18 | : typeof global !== 'undefined' ? global 19 | : this 20 | ), function(global) { 21 | 'use strict'; 22 | // existing version for noConflict() 23 | global = global || {}; 24 | var _Base64 = global.Base64; 25 | var version = "2.5.1"; 26 | // if node.js and NOT React Native, we use Buffer 27 | var buffer; 28 | if (typeof module !== 'undefined' && module.exports) { 29 | try { 30 | buffer = eval("require('buffer').Buffer"); 31 | } catch (err) { 32 | buffer = undefined; 33 | } 34 | } 35 | // constants 36 | var b64chars 37 | = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 38 | var b64tab = function(bin) { 39 | var t = {}; 40 | for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; 41 | return t; 42 | }(b64chars); 43 | var fromCharCode = String.fromCharCode; 44 | // encoder stuff 45 | var cb_utob = function(c) { 46 | if (c.length < 2) { 47 | var cc = c.charCodeAt(0); 48 | return cc < 0x80 ? c 49 | : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) 50 | + fromCharCode(0x80 | (cc & 0x3f))) 51 | : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) 52 | + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) 53 | + fromCharCode(0x80 | ( cc & 0x3f))); 54 | } else { 55 | var cc = 0x10000 56 | + (c.charCodeAt(0) - 0xD800) * 0x400 57 | + (c.charCodeAt(1) - 0xDC00); 58 | return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) 59 | + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) 60 | + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) 61 | + fromCharCode(0x80 | ( cc & 0x3f))); 62 | } 63 | }; 64 | var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; 65 | var utob = function(u) { 66 | return u.replace(re_utob, cb_utob); 67 | }; 68 | var cb_encode = function(ccc) { 69 | var padlen = [0, 2, 1][ccc.length % 3], 70 | ord = ccc.charCodeAt(0) << 16 71 | | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) 72 | | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), 73 | chars = [ 74 | b64chars.charAt( ord >>> 18), 75 | b64chars.charAt((ord >>> 12) & 63), 76 | padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), 77 | padlen >= 1 ? '=' : b64chars.charAt(ord & 63) 78 | ]; 79 | return chars.join(''); 80 | }; 81 | var btoa = global.btoa ? function(b) { 82 | return global.btoa(b); 83 | } : function(b) { 84 | return b.replace(/[\s\S]{1,3}/g, cb_encode); 85 | }; 86 | var _encode = buffer ? 87 | buffer.from && Uint8Array && buffer.from !== Uint8Array.from 88 | ? function (u) { 89 | return (u.constructor === buffer.constructor ? u : buffer.from(u)) 90 | .toString('base64') 91 | } 92 | : function (u) { 93 | return (u.constructor === buffer.constructor ? u : new buffer(u)) 94 | .toString('base64') 95 | } 96 | : function (u) { return btoa(utob(u)) } 97 | ; 98 | var encode = function(u, urisafe) { 99 | return !urisafe 100 | ? _encode(String(u)) 101 | : _encode(String(u)).replace(/[+\/]/g, function(m0) { 102 | return m0 == '+' ? '-' : '_'; 103 | }).replace(/=/g, ''); 104 | }; 105 | var encodeURI = function(u) { return encode(u, true) }; 106 | // decoder stuff 107 | var re_btou = new RegExp([ 108 | '[\xC0-\xDF][\x80-\xBF]', 109 | '[\xE0-\xEF][\x80-\xBF]{2}', 110 | '[\xF0-\xF7][\x80-\xBF]{3}' 111 | ].join('|'), 'g'); 112 | var cb_btou = function(cccc) { 113 | switch(cccc.length) { 114 | case 4: 115 | var cp = ((0x07 & cccc.charCodeAt(0)) << 18) 116 | | ((0x3f & cccc.charCodeAt(1)) << 12) 117 | | ((0x3f & cccc.charCodeAt(2)) << 6) 118 | | (0x3f & cccc.charCodeAt(3)), 119 | offset = cp - 0x10000; 120 | return (fromCharCode((offset >>> 10) + 0xD800) 121 | + fromCharCode((offset & 0x3FF) + 0xDC00)); 122 | case 3: 123 | return fromCharCode( 124 | ((0x0f & cccc.charCodeAt(0)) << 12) 125 | | ((0x3f & cccc.charCodeAt(1)) << 6) 126 | | (0x3f & cccc.charCodeAt(2)) 127 | ); 128 | default: 129 | return fromCharCode( 130 | ((0x1f & cccc.charCodeAt(0)) << 6) 131 | | (0x3f & cccc.charCodeAt(1)) 132 | ); 133 | } 134 | }; 135 | var btou = function(b) { 136 | return b.replace(re_btou, cb_btou); 137 | }; 138 | var cb_decode = function(cccc) { 139 | var len = cccc.length, 140 | padlen = len % 4, 141 | n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) 142 | | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) 143 | | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) 144 | | (len > 3 ? b64tab[cccc.charAt(3)] : 0), 145 | chars = [ 146 | fromCharCode( n >>> 16), 147 | fromCharCode((n >>> 8) & 0xff), 148 | fromCharCode( n & 0xff) 149 | ]; 150 | chars.length -= [0, 0, 2, 1][padlen]; 151 | return chars.join(''); 152 | }; 153 | var _atob = global.atob ? function(a) { 154 | return global.atob(a); 155 | } : function(a){ 156 | return a.replace(/\S{1,4}/g, cb_decode); 157 | }; 158 | var atob = function(a) { 159 | return _atob(String(a).replace(/[^A-Za-z0-9\+\/]/g, '')); 160 | }; 161 | var _decode = buffer ? 162 | buffer.from && Uint8Array && buffer.from !== Uint8Array.from 163 | ? function(a) { 164 | return (a.constructor === buffer.constructor 165 | ? a : buffer.from(a, 'base64')).toString(); 166 | } 167 | : function(a) { 168 | return (a.constructor === buffer.constructor 169 | ? a : new buffer(a, 'base64')).toString(); 170 | } 171 | : function(a) { return btou(_atob(a)) }; 172 | var decode = function(a){ 173 | return _decode( 174 | String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' }) 175 | .replace(/[^A-Za-z0-9\+\/]/g, '') 176 | ); 177 | }; 178 | var noConflict = function() { 179 | var Base64 = global.Base64; 180 | global.Base64 = _Base64; 181 | return Base64; 182 | }; 183 | // export Base64 184 | global.Base64 = { 185 | VERSION: version, 186 | atob: atob, 187 | btoa: btoa, 188 | fromBase64: decode, 189 | toBase64: encode, 190 | utob: utob, 191 | encode: encode, 192 | encodeURI: encodeURI, 193 | btou: btou, 194 | decode: decode, 195 | noConflict: noConflict, 196 | __buffer__: buffer 197 | }; 198 | // if ES5 is available, make Base64.extendString() available 199 | if (typeof Object.defineProperty === 'function') { 200 | var noEnum = function(v){ 201 | return {value:v,enumerable:false,writable:true,configurable:true}; 202 | }; 203 | global.Base64.extendString = function () { 204 | Object.defineProperty( 205 | String.prototype, 'fromBase64', noEnum(function () { 206 | return decode(this) 207 | })); 208 | Object.defineProperty( 209 | String.prototype, 'toBase64', noEnum(function (urisafe) { 210 | return encode(this, urisafe) 211 | })); 212 | Object.defineProperty( 213 | String.prototype, 'toBase64URI', noEnum(function () { 214 | return encode(this, true) 215 | })); 216 | }; 217 | } 218 | // 219 | // export Base64 to the namespace 220 | // 221 | if (global['Meteor']) { // Meteor.js 222 | Base64 = global.Base64; 223 | } 224 | // module.exports and AMD are mutually exclusive. 225 | // module.exports has precedence. 226 | if (typeof module !== 'undefined' && module.exports) { 227 | module.exports.Base64 = global.Base64; 228 | } 229 | else if (typeof define === 'function' && define.amd) { 230 | // AMD. Register as an anonymous module. 231 | define([], function(){ return global.Base64 }); 232 | } 233 | // that's it! 234 | return {Base64: global.Base64} 235 | })); 236 | -------------------------------------------------------------------------------- /servers/portforward/theme/flags.css: -------------------------------------------------------------------------------- 1 | .flag { 2 | width: 16px; 3 | height: 11px; 4 | background:url(flags.png) no-repeat 5 | } 6 | 7 | .flag.flag-ad {background-position: -16px 0} 8 | .flag.flag-ae {background-position: -32px 0} 9 | .flag.flag-af {background-position: -48px 0} 10 | .flag.flag-ag {background-position: -64px 0} 11 | .flag.flag-ai {background-position: -80px 0} 12 | .flag.flag-al {background-position: -96px 0} 13 | .flag.flag-am {background-position: -112px 0} 14 | .flag.flag-an {background-position: -128px 0} 15 | .flag.flag-ao {background-position: -144px 0} 16 | .flag.flag-ar {background-position: -160px 0} 17 | .flag.flag-as {background-position: -176px 0} 18 | .flag.flag-at {background-position: -192px 0} 19 | .flag.flag-au {background-position: -208px 0} 20 | .flag.flag-aw {background-position: -224px 0} 21 | .flag.flag-az {background-position: -240px 0} 22 | .flag.flag-ba {background-position: 0 -11px} 23 | .flag.flag-bb {background-position: -16px -11px} 24 | .flag.flag-bd {background-position: -32px -11px} 25 | .flag.flag-be {background-position: -48px -11px} 26 | .flag.flag-bf {background-position: -64px -11px} 27 | .flag.flag-bg {background-position: -80px -11px} 28 | .flag.flag-bh {background-position: -96px -11px} 29 | .flag.flag-bi {background-position: -112px -11px} 30 | .flag.flag-bj {background-position: -128px -11px} 31 | .flag.flag-bm {background-position: -144px -11px} 32 | .flag.flag-bn {background-position: -160px -11px} 33 | .flag.flag-bo {background-position: -176px -11px} 34 | .flag.flag-br {background-position: -192px -11px} 35 | .flag.flag-bs {background-position: -208px -11px} 36 | .flag.flag-bt {background-position: -224px -11px} 37 | .flag.flag-bv {background-position: -240px -11px} 38 | .flag.flag-bw {background-position: 0 -22px} 39 | .flag.flag-by {background-position: -16px -22px} 40 | .flag.flag-bz {background-position: -32px -22px} 41 | .flag.flag-ca {background-position: -48px -22px} 42 | .flag.flag-catalonia {background-position: -64px -22px} 43 | .flag.flag-cd {background-position: -80px -22px} 44 | .flag.flag-cf {background-position: -96px -22px} 45 | .flag.flag-cg {background-position: -112px -22px} 46 | .flag.flag-ch {background-position: -128px -22px} 47 | .flag.flag-ci {background-position: -144px -22px} 48 | .flag.flag-ck {background-position: -160px -22px} 49 | .flag.flag-cl {background-position: -176px -22px} 50 | .flag.flag-cm {background-position: -192px -22px} 51 | .flag.flag-cn {background-position: -208px -22px} 52 | .flag.flag-co {background-position: -224px -22px} 53 | .flag.flag-cr {background-position: -240px -22px} 54 | .flag.flag-cu {background-position: 0 -33px} 55 | .flag.flag-cv {background-position: -16px -33px} 56 | .flag.flag-cw {background-position: -32px -33px} 57 | .flag.flag-cy {background-position: -48px -33px} 58 | .flag.flag-cz {background-position: -64px -33px} 59 | .flag.flag-de {background-position: -80px -33px} 60 | .flag.flag-dj {background-position: -96px -33px} 61 | .flag.flag-dk {background-position: -112px -33px} 62 | .flag.flag-dm {background-position: -128px -33px} 63 | .flag.flag-do {background-position: -144px -33px} 64 | .flag.flag-dz {background-position: -160px -33px} 65 | .flag.flag-ec {background-position: -176px -33px} 66 | .flag.flag-ee {background-position: -192px -33px} 67 | .flag.flag-eg {background-position: -208px -33px} 68 | .flag.flag-eh {background-position: -224px -33px} 69 | .flag.flag-england {background-position: -240px -33px} 70 | .flag.flag-er {background-position: 0 -44px} 71 | .flag.flag-es {background-position: -16px -44px} 72 | .flag.flag-et {background-position: -32px -44px} 73 | .flag.flag-eu {background-position: -48px -44px} 74 | .flag.flag-fi {background-position: -64px -44px} 75 | .flag.flag-fj {background-position: -80px -44px} 76 | .flag.flag-fk {background-position: -96px -44px} 77 | .flag.flag-fm {background-position: -112px -44px} 78 | .flag.flag-fo {background-position: -128px -44px} 79 | .flag.flag-fr {background-position: -144px -44px} 80 | .flag.flag-ga {background-position: -160px -44px} 81 | .flag.flag-gb {background-position: -176px -44px} 82 | .flag.flag-gd {background-position: -192px -44px} 83 | .flag.flag-ge {background-position: -208px -44px} 84 | .flag.flag-gf {background-position: -224px -44px} 85 | .flag.flag-gg {background-position: -240px -44px} 86 | .flag.flag-gh {background-position: 0 -55px} 87 | .flag.flag-gi {background-position: -16px -55px} 88 | .flag.flag-gl {background-position: -32px -55px} 89 | .flag.flag-gm {background-position: -48px -55px} 90 | .flag.flag-gn {background-position: -64px -55px} 91 | .flag.flag-gp {background-position: -80px -55px} 92 | .flag.flag-gq {background-position: -96px -55px} 93 | .flag.flag-gr {background-position: -112px -55px} 94 | .flag.flag-gs {background-position: -128px -55px} 95 | .flag.flag-gt {background-position: -144px -55px} 96 | .flag.flag-gu {background-position: -160px -55px} 97 | .flag.flag-gw {background-position: -176px -55px} 98 | .flag.flag-gy {background-position: -192px -55px} 99 | .flag.flag-hk {background-position: -208px -55px} 100 | .flag.flag-hm {background-position: -224px -55px} 101 | .flag.flag-hn {background-position: -240px -55px} 102 | .flag.flag-hr {background-position: 0 -66px} 103 | .flag.flag-ht {background-position: -16px -66px} 104 | .flag.flag-hu {background-position: -32px -66px} 105 | .flag.flag-ic {background-position: -48px -66px} 106 | .flag.flag-id {background-position: -64px -66px} 107 | .flag.flag-ie {background-position: -80px -66px} 108 | .flag.flag-il {background-position: -96px -66px} 109 | .flag.flag-im {background-position: -112px -66px} 110 | .flag.flag-in {background-position: -128px -66px} 111 | .flag.flag-io {background-position: -144px -66px} 112 | .flag.flag-iq {background-position: -160px -66px} 113 | .flag.flag-ir {background-position: -176px -66px} 114 | .flag.flag-is {background-position: -192px -66px} 115 | .flag.flag-it {background-position: -208px -66px} 116 | .flag.flag-je {background-position: -224px -66px} 117 | .flag.flag-jm {background-position: -240px -66px} 118 | .flag.flag-jo {background-position: 0 -77px} 119 | .flag.flag-jp {background-position: -16px -77px} 120 | .flag.flag-ke {background-position: -32px -77px} 121 | .flag.flag-kg {background-position: -48px -77px} 122 | .flag.flag-kh {background-position: -64px -77px} 123 | .flag.flag-ki {background-position: -80px -77px} 124 | .flag.flag-km {background-position: -96px -77px} 125 | .flag.flag-kn {background-position: -112px -77px} 126 | .flag.flag-kp {background-position: -128px -77px} 127 | .flag.flag-kr {background-position: -144px -77px} 128 | .flag.flag-kurdistan {background-position: -160px -77px} 129 | .flag.flag-kw {background-position: -176px -77px} 130 | .flag.flag-ky {background-position: -192px -77px} 131 | .flag.flag-kz {background-position: -208px -77px} 132 | .flag.flag-la {background-position: -224px -77px} 133 | .flag.flag-lb {background-position: -240px -77px} 134 | .flag.flag-lc {background-position: 0 -88px} 135 | .flag.flag-li {background-position: -16px -88px} 136 | .flag.flag-lk {background-position: -32px -88px} 137 | .flag.flag-lr {background-position: -48px -88px} 138 | .flag.flag-ls {background-position: -64px -88px} 139 | .flag.flag-lt {background-position: -80px -88px} 140 | .flag.flag-lu {background-position: -96px -88px} 141 | .flag.flag-lv {background-position: -112px -88px} 142 | .flag.flag-ly {background-position: -128px -88px} 143 | .flag.flag-ma {background-position: -144px -88px} 144 | .flag.flag-mc {background-position: -160px -88px} 145 | .flag.flag-md {background-position: -176px -88px} 146 | .flag.flag-me {background-position: -192px -88px} 147 | .flag.flag-mg {background-position: -208px -88px} 148 | .flag.flag-mh {background-position: -224px -88px} 149 | .flag.flag-mk {background-position: -240px -88px} 150 | .flag.flag-ml {background-position: 0 -99px} 151 | .flag.flag-mm {background-position: -16px -99px} 152 | .flag.flag-mn {background-position: -32px -99px} 153 | .flag.flag-mo {background-position: -48px -99px} 154 | .flag.flag-mp {background-position: -64px -99px} 155 | .flag.flag-mq {background-position: -80px -99px} 156 | .flag.flag-mr {background-position: -96px -99px} 157 | .flag.flag-ms {background-position: -112px -99px} 158 | .flag.flag-mt {background-position: -128px -99px} 159 | .flag.flag-mu {background-position: -144px -99px} 160 | .flag.flag-mv {background-position: -160px -99px} 161 | .flag.flag-mw {background-position: -176px -99px} 162 | .flag.flag-mx {background-position: -192px -99px} 163 | .flag.flag-my {background-position: -208px -99px} 164 | .flag.flag-mz {background-position: -224px -99px} 165 | .flag.flag-na {background-position: -240px -99px} 166 | .flag.flag-nc {background-position: 0 -110px} 167 | .flag.flag-ne {background-position: -16px -110px} 168 | .flag.flag-nf {background-position: -32px -110px} 169 | .flag.flag-ng {background-position: -48px -110px} 170 | .flag.flag-ni {background-position: -64px -110px} 171 | .flag.flag-nl {background-position: -80px -110px} 172 | .flag.flag-no {background-position: -96px -110px} 173 | .flag.flag-np {background-position: -112px -110px} 174 | .flag.flag-nr {background-position: -128px -110px} 175 | .flag.flag-nu {background-position: -144px -110px} 176 | .flag.flag-nz {background-position: -160px -110px} 177 | .flag.flag-om {background-position: -176px -110px} 178 | .flag.flag-pa {background-position: -192px -110px} 179 | .flag.flag-pe {background-position: -208px -110px} 180 | .flag.flag-pf {background-position: -224px -110px} 181 | .flag.flag-pg {background-position: -240px -110px} 182 | .flag.flag-ph {background-position: 0 -121px} 183 | .flag.flag-pk {background-position: -16px -121px} 184 | .flag.flag-pl {background-position: -32px -121px} 185 | .flag.flag-pm {background-position: -48px -121px} 186 | .flag.flag-pn {background-position: -64px -121px} 187 | .flag.flag-pr {background-position: -80px -121px} 188 | .flag.flag-ps {background-position: -96px -121px} 189 | .flag.flag-pt {background-position: -112px -121px} 190 | .flag.flag-pw {background-position: -128px -121px} 191 | .flag.flag-py {background-position: -144px -121px} 192 | .flag.flag-qa {background-position: -160px -121px} 193 | .flag.flag-re {background-position: -176px -121px} 194 | .flag.flag-ro {background-position: -192px -121px} 195 | .flag.flag-rs {background-position: -208px -121px} 196 | .flag.flag-ru {background-position: -224px -121px} 197 | .flag.flag-rw {background-position: -240px -121px} 198 | .flag.flag-sa {background-position: 0 -132px} 199 | .flag.flag-sb {background-position: -16px -132px} 200 | .flag.flag-sc {background-position: -32px -132px} 201 | .flag.flag-scotland {background-position: -48px -132px} 202 | .flag.flag-sd {background-position: -64px -132px} 203 | .flag.flag-se {background-position: -80px -132px} 204 | .flag.flag-sg {background-position: -96px -132px} 205 | .flag.flag-sh {background-position: -112px -132px} 206 | .flag.flag-si {background-position: -128px -132px} 207 | .flag.flag-sk {background-position: -144px -132px} 208 | .flag.flag-sl {background-position: -160px -132px} 209 | .flag.flag-sm {background-position: -176px -132px} 210 | .flag.flag-sn {background-position: -192px -132px} 211 | .flag.flag-so {background-position: -208px -132px} 212 | .flag.flag-somaliland {background-position: -224px -132px} 213 | .flag.flag-sr {background-position: -240px -132px} 214 | .flag.flag-ss {background-position: 0 -143px} 215 | .flag.flag-st {background-position: -16px -143px} 216 | .flag.flag-sv {background-position: -32px -143px} 217 | .flag.flag-sx {background-position: -48px -143px} 218 | .flag.flag-sy {background-position: -64px -143px} 219 | .flag.flag-sz {background-position: -80px -143px} 220 | .flag.flag-tc {background-position: -96px -143px} 221 | .flag.flag-td {background-position: -112px -143px} 222 | .flag.flag-tf {background-position: -128px -143px} 223 | .flag.flag-tg {background-position: -144px -143px} 224 | .flag.flag-th {background-position: -160px -143px} 225 | .flag.flag-tibet {background-position: -176px -143px} 226 | .flag.flag-tj {background-position: -192px -143px} 227 | .flag.flag-tk {background-position: -208px -143px} 228 | .flag.flag-tl {background-position: -224px -143px} 229 | .flag.flag-tm {background-position: -240px -143px} 230 | .flag.flag-tn {background-position: 0 -154px} 231 | .flag.flag-to {background-position: -16px -154px} 232 | .flag.flag-tr {background-position: -32px -154px} 233 | .flag.flag-tt {background-position: -48px -154px} 234 | .flag.flag-tv {background-position: -64px -154px} 235 | .flag.flag-tw {background-position: -80px -154px} 236 | .flag.flag-tz {background-position: -96px -154px} 237 | .flag.flag-ua {background-position: -112px -154px} 238 | .flag.flag-ug {background-position: -128px -154px} 239 | .flag.flag-um {background-position: -144px -154px} 240 | .flag.flag-us {background-position: -160px -154px} 241 | .flag.flag-uy {background-position: -176px -154px} 242 | .flag.flag-uz {background-position: -192px -154px} 243 | .flag.flag-va {background-position: -208px -154px} 244 | .flag.flag-vc {background-position: -224px -154px} 245 | .flag.flag-ve {background-position: -240px -154px} 246 | .flag.flag-vg {background-position: 0 -165px} 247 | .flag.flag-vi {background-position: -16px -165px} 248 | .flag.flag-vn {background-position: -32px -165px} 249 | .flag.flag-vu {background-position: -48px -165px} 250 | .flag.flag-wales {background-position: -64px -165px} 251 | .flag.flag-wf {background-position: -80px -165px} 252 | .flag.flag-ws {background-position: -96px -165px} 253 | .flag.flag-xk {background-position: -112px -165px} 254 | .flag.flag-ye {background-position: -128px -165px} 255 | .flag.flag-yt {background-position: -144px -165px} 256 | .flag.flag-za {background-position: -160px -165px} 257 | .flag.flag-zanzibar {background-position: -176px -165px} 258 | .flag.flag-zm {background-position: -192px -165px} 259 | .flag.flag-zw {background-position: -208px -165px} 260 | -------------------------------------------------------------------------------- /servers/portforward/theme/flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TachibanaSuzume/WhmcsPortForward/ebdbb8119bd8d3604636a5b99a57c6ff20c27f4d/servers/portforward/theme/flags.png -------------------------------------------------------------------------------- /servers/portforward/theme/jquery-confirm.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * jquery-confirm v3.2.3 (http://craftpip.github.io/jquery-confirm/) 3 | * Author: boniface pereira 4 | * Website: www.craftpip.com 5 | * Contact: hey@craftpip.com 6 | * 7 | * Copyright 2013-2017 jquery-confirm 8 | * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) 9 | */ 10 | @-webkit-keyframes jconfirm-spin { 11 | from { 12 | -webkit-transform: rotate(0deg); 13 | transform: rotate(0deg); 14 | } 15 | to { 16 | -webkit-transform: rotate(360deg); 17 | transform: rotate(360deg); 18 | } 19 | } 20 | @keyframes jconfirm-spin { 21 | from { 22 | -webkit-transform: rotate(0deg); 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | -webkit-transform: rotate(360deg); 27 | transform: rotate(360deg); 28 | } 29 | } 30 | body[class*=jconfirm-no-scroll-] { 31 | overflow: hidden !important; 32 | } 33 | .jconfirm { 34 | position: fixed; 35 | top: 0; 36 | left: 0; 37 | right: 0; 38 | bottom: 0; 39 | z-index: 99999999; 40 | font-family: inherit; 41 | overflow: hidden; 42 | } 43 | .jconfirm .jconfirm-bg { 44 | position: fixed; 45 | top: 0; 46 | left: 0; 47 | right: 0; 48 | bottom: 0; 49 | -webkit-transition: opacity .4s; 50 | transition: opacity .4s; 51 | } 52 | .jconfirm .jconfirm-bg.jconfirm-bg-h { 53 | opacity: 0 !important; 54 | } 55 | .jconfirm .jconfirm-scrollpane { 56 | position: fixed; 57 | top: 0; 58 | left: 0; 59 | right: 0; 60 | bottom: 0; 61 | overflow-y: auto; 62 | -webkit-perspective: 500px; 63 | perspective: 500px; 64 | -webkit-perspective-origin: center; 65 | perspective-origin: center; 66 | } 67 | .jconfirm .jconfirm-box { 68 | background: white; 69 | border-radius: 4px; 70 | position: relative; 71 | outline: none; 72 | padding: 15px 15px 0; 73 | overflow: hidden; 74 | margin-left: auto; 75 | margin-right: auto; 76 | } 77 | @-webkit-keyframes type-blue { 78 | 1%, 79 | 100% { 80 | border-color: #3498db; 81 | } 82 | 50% { 83 | border-color: #5faee3; 84 | } 85 | } 86 | @keyframes type-blue { 87 | 1%, 88 | 100% { 89 | border-color: #3498db; 90 | } 91 | 50% { 92 | border-color: #5faee3; 93 | } 94 | } 95 | @-webkit-keyframes type-green { 96 | 1%, 97 | 100% { 98 | border-color: #2ecc71; 99 | } 100 | 50% { 101 | border-color: #54d98c; 102 | } 103 | } 104 | @keyframes type-green { 105 | 1%, 106 | 100% { 107 | border-color: #2ecc71; 108 | } 109 | 50% { 110 | border-color: #54d98c; 111 | } 112 | } 113 | @-webkit-keyframes type-red { 114 | 1%, 115 | 100% { 116 | border-color: #e74c3c; 117 | } 118 | 50% { 119 | border-color: #ed7669; 120 | } 121 | } 122 | @keyframes type-red { 123 | 1%, 124 | 100% { 125 | border-color: #e74c3c; 126 | } 127 | 50% { 128 | border-color: #ed7669; 129 | } 130 | } 131 | @-webkit-keyframes type-orange { 132 | 1%, 133 | 100% { 134 | border-color: #f1c40f; 135 | } 136 | 50% { 137 | border-color: #f4d03f; 138 | } 139 | } 140 | @keyframes type-orange { 141 | 1%, 142 | 100% { 143 | border-color: #f1c40f; 144 | } 145 | 50% { 146 | border-color: #f4d03f; 147 | } 148 | } 149 | @-webkit-keyframes type-purple { 150 | 1%, 151 | 100% { 152 | border-color: #9b59b6; 153 | } 154 | 50% { 155 | border-color: #b07cc6; 156 | } 157 | } 158 | @keyframes type-purple { 159 | 1%, 160 | 100% { 161 | border-color: #9b59b6; 162 | } 163 | 50% { 164 | border-color: #b07cc6; 165 | } 166 | } 167 | @-webkit-keyframes type-dark { 168 | 1%, 169 | 100% { 170 | border-color: #34495e; 171 | } 172 | 50% { 173 | border-color: #46627f; 174 | } 175 | } 176 | @keyframes type-dark { 177 | 1%, 178 | 100% { 179 | border-color: #34495e; 180 | } 181 | 50% { 182 | border-color: #46627f; 183 | } 184 | } 185 | .jconfirm .jconfirm-box.jconfirm-type-animated { 186 | -webkit-animation-duration: 2s; 187 | animation-duration: 2s; 188 | -webkit-animation-iteration-count: infinite; 189 | animation-iteration-count: infinite; 190 | } 191 | .jconfirm .jconfirm-box.jconfirm-type-blue { 192 | border-top: solid 7px #3498db; 193 | -webkit-animation-name: type-blue; 194 | animation-name: type-blue; 195 | } 196 | .jconfirm .jconfirm-box.jconfirm-type-green { 197 | border-top: solid 7px #2ecc71; 198 | -webkit-animation-name: type-green; 199 | animation-name: type-green; 200 | } 201 | .jconfirm .jconfirm-box.jconfirm-type-red { 202 | border-top: solid 7px #e74c3c; 203 | -webkit-animation-name: type-red; 204 | animation-name: type-red; 205 | } 206 | .jconfirm .jconfirm-box.jconfirm-type-orange { 207 | border-top: solid 7px #f1c40f; 208 | -webkit-animation-name: type-orange; 209 | animation-name: type-orange; 210 | } 211 | .jconfirm .jconfirm-box.jconfirm-type-purple { 212 | border-top: solid 7px #9b59b6; 213 | -webkit-animation-name: type-purple; 214 | animation-name: type-purple; 215 | } 216 | .jconfirm .jconfirm-box.jconfirm-type-dark { 217 | border-top: solid 7px #34495e; 218 | -webkit-animation-name: type-dark; 219 | animation-name: type-dark; 220 | } 221 | .jconfirm .jconfirm-box.loading { 222 | height: 120px; 223 | } 224 | .jconfirm .jconfirm-box.loading:before { 225 | content: ''; 226 | position: absolute; 227 | left: 0; 228 | background: white; 229 | right: 0; 230 | top: 0; 231 | bottom: 0; 232 | border-radius: 10px; 233 | z-index: 1; 234 | } 235 | .jconfirm .jconfirm-box.loading:after { 236 | opacity: 0.6; 237 | content: ''; 238 | height: 30px; 239 | width: 30px; 240 | border: solid 3px transparent; 241 | position: absolute; 242 | left: 50%; 243 | margin-left: -15px; 244 | border-radius: 50%; 245 | -webkit-animation: jconfirm-spin 1s infinite linear; 246 | animation: jconfirm-spin 1s infinite linear; 247 | border-bottom-color: dodgerblue; 248 | top: 50%; 249 | margin-top: -15px; 250 | z-index: 2; 251 | } 252 | .jconfirm .jconfirm-box div.jconfirm-closeIcon { 253 | height: 20px; 254 | width: 20px; 255 | position: absolute; 256 | top: 5px; 257 | right: 5px; 258 | cursor: pointer; 259 | opacity: .6; 260 | text-align: center; 261 | -webkit-transition: opacity 0.3s ease-in; 262 | transition: opacity 0.3s ease-in; 263 | font-size: 27px !important; 264 | line-height: 14px !important; 265 | display: none; 266 | } 267 | .jconfirm .jconfirm-box div.jconfirm-closeIcon:empty { 268 | display: none; 269 | } 270 | .jconfirm .jconfirm-box div.jconfirm-closeIcon .fa { 271 | font-size: 16px; 272 | } 273 | .jconfirm .jconfirm-box div.jconfirm-closeIcon .glyphicon { 274 | font-size: 16px; 275 | } 276 | .jconfirm .jconfirm-box div.jconfirm-closeIcon .zmdi { 277 | font-size: 16px; 278 | } 279 | .jconfirm .jconfirm-box div.jconfirm-closeIcon:hover { 280 | opacity: 1; 281 | } 282 | .jconfirm .jconfirm-box div.jconfirm-title-c { 283 | display: block; 284 | font-size: 22px; 285 | line-height: 20px; 286 | -webkit-user-select: none; 287 | -moz-user-select: none; 288 | -ms-user-select: none; 289 | user-select: none; 290 | } 291 | .jconfirm .jconfirm-box div.jconfirm-title-c.jconfirm-hand { 292 | cursor: move; 293 | } 294 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 295 | font-size: inherit; 296 | padding-bottom: 15px; 297 | display: inline-block; 298 | vertical-align: middle; 299 | } 300 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c i { 301 | vertical-align: middle; 302 | } 303 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c:empty { 304 | display: none; 305 | } 306 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title { 307 | -webkit-user-select: none; 308 | -moz-user-select: none; 309 | -ms-user-select: none; 310 | user-select: none; 311 | font-size: inherit; 312 | font-family: inherit; 313 | display: inline-block; 314 | vertical-align: middle; 315 | padding-bottom: 15px; 316 | } 317 | .jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title:empty { 318 | display: none; 319 | } 320 | .jconfirm .jconfirm-box div.jconfirm-content-pane { 321 | margin-bottom: 15px; 322 | height: auto; 323 | -webkit-transition: height 0.4s ease-in; 324 | transition: height 0.4s ease-in; 325 | display: inline-block; 326 | width: 100%; 327 | position: relative; 328 | overflow: hidden; 329 | } 330 | .jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content img { 331 | max-width: 100%; 332 | height: auto; 333 | } 334 | .jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content:empty { 335 | display: none; 336 | } 337 | .jconfirm .jconfirm-box .jconfirm-buttons { 338 | padding-bottom: 11px; 339 | } 340 | .jconfirm .jconfirm-box .jconfirm-buttons > button { 341 | margin-bottom: 4px; 342 | margin-left: 2px; 343 | margin-right: 2px; 344 | } 345 | .jconfirm .jconfirm-box .jconfirm-buttons button { 346 | display: inline-block; 347 | padding: 6px 12px; 348 | font-size: 14px; 349 | font-weight: 400; 350 | line-height: 1.42857143; 351 | text-align: center; 352 | white-space: nowrap; 353 | vertical-align: middle; 354 | -ms-touch-action: manipulation; 355 | touch-action: manipulation; 356 | cursor: pointer; 357 | -webkit-user-select: none; 358 | -moz-user-select: none; 359 | -ms-user-select: none; 360 | border-radius: 4px; 361 | min-height: 1em; 362 | outline: 0; 363 | -webkit-user-select: none; 364 | -moz-user-select: none; 365 | -ms-user-select: none; 366 | user-select: none; 367 | -webkit-transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, background 0.1s ease; 368 | transition: opacity 0.1s ease, background-color 0.1s ease, color 0.1s ease, box-shadow 0.1s ease, background 0.1s ease; 369 | -webkit-tap-highlight-color: transparent; 370 | border: none; 371 | background-image: none; 372 | } 373 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue { 374 | background-color: #3498db; 375 | color: #FFF; 376 | text-shadow: none; 377 | -webkit-transition: background .2s; 378 | transition: background .2s; 379 | } 380 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue:hover { 381 | background-color: #2980b9; 382 | color: #FFF; 383 | } 384 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-green { 385 | background-color: #2ecc71; 386 | color: #FFF; 387 | text-shadow: none; 388 | -webkit-transition: background .2s; 389 | transition: background .2s; 390 | } 391 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-green:hover { 392 | background-color: #27ae60; 393 | color: #FFF; 394 | } 395 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-red { 396 | background-color: #e74c3c; 397 | color: #FFF; 398 | text-shadow: none; 399 | -webkit-transition: background .2s; 400 | transition: background .2s; 401 | } 402 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-red:hover { 403 | background-color: #c0392b; 404 | color: #FFF; 405 | } 406 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange { 407 | background-color: #f1c40f; 408 | color: #FFF; 409 | text-shadow: none; 410 | -webkit-transition: background .2s; 411 | transition: background .2s; 412 | } 413 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange:hover { 414 | background-color: #f39c12; 415 | color: #FFF; 416 | } 417 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-default { 418 | background-color: #ecf0f1; 419 | color: #000; 420 | text-shadow: none; 421 | -webkit-transition: background .2s; 422 | transition: background .2s; 423 | } 424 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-default:hover { 425 | background-color: #bdc3c7; 426 | color: #000; 427 | } 428 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple { 429 | background-color: #9b59b6; 430 | color: #FFF; 431 | text-shadow: none; 432 | -webkit-transition: background .2s; 433 | transition: background .2s; 434 | } 435 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple:hover { 436 | background-color: #8e44ad; 437 | color: #FFF; 438 | } 439 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark { 440 | background-color: #34495e; 441 | color: #FFF; 442 | text-shadow: none; 443 | -webkit-transition: background .2s; 444 | transition: background .2s; 445 | } 446 | .jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark:hover { 447 | background-color: #2c3e50; 448 | color: #FFF; 449 | } 450 | .jconfirm .jconfirm-box.jconfirm-type-red .jconfirm-title-c .jconfirm-icon-c { 451 | color: #e74c3c !important; 452 | } 453 | .jconfirm .jconfirm-box.jconfirm-type-blue .jconfirm-title-c .jconfirm-icon-c { 454 | color: #3498db !important; 455 | } 456 | .jconfirm .jconfirm-box.jconfirm-type-green .jconfirm-title-c .jconfirm-icon-c { 457 | color: #2ecc71 !important; 458 | } 459 | .jconfirm .jconfirm-box.jconfirm-type-purple .jconfirm-title-c .jconfirm-icon-c { 460 | color: #9b59b6 !important; 461 | } 462 | .jconfirm .jconfirm-box.jconfirm-type-orange .jconfirm-title-c .jconfirm-icon-c { 463 | color: #f1c40f !important; 464 | } 465 | .jconfirm .jconfirm-box.jconfirm-type-dark .jconfirm-title-c .jconfirm-icon-c { 466 | color: #34495e !important; 467 | } 468 | .jconfirm .jconfirm-clear { 469 | clear: both; 470 | } 471 | .jconfirm.jconfirm-rtl { 472 | direction: rtl; 473 | } 474 | .jconfirm.jconfirm-rtl div.jconfirm-closeIcon { 475 | left: 5px; 476 | right: auto; 477 | } 478 | .jconfirm.jconfirm-white .jconfirm-bg, 479 | .jconfirm.jconfirm-light .jconfirm-bg { 480 | background-color: #444; 481 | opacity: .2; 482 | } 483 | .jconfirm.jconfirm-white .jconfirm-box, 484 | .jconfirm.jconfirm-light .jconfirm-box { 485 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); 486 | border-radius: 5px; 487 | } 488 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-title-c .jconfirm-icon-c, 489 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 490 | margin-right: 8px; 491 | margin-left: 0px; 492 | } 493 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons, 494 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons { 495 | float: right; 496 | } 497 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button, 498 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button { 499 | text-transform: uppercase; 500 | font-size: 14px; 501 | font-weight: bold; 502 | text-shadow: none; 503 | } 504 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default, 505 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default { 506 | box-shadow: none; 507 | color: #333; 508 | } 509 | .jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default:hover, 510 | .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default:hover { 511 | background: #ddd; 512 | } 513 | .jconfirm.jconfirm-white.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c, 514 | .jconfirm.jconfirm-light.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { 515 | margin-left: 8px; 516 | margin-right: 0px; 517 | } 518 | .jconfirm.jconfirm-black .jconfirm-bg, 519 | .jconfirm.jconfirm-dark .jconfirm-bg { 520 | background-color: darkslategray; 521 | opacity: .4; 522 | } 523 | .jconfirm.jconfirm-black .jconfirm-box, 524 | .jconfirm.jconfirm-dark .jconfirm-box { 525 | box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); 526 | background: #444; 527 | border-radius: 5px; 528 | color: white; 529 | } 530 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-title-c .jconfirm-icon-c, 531 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 532 | margin-right: 8px; 533 | margin-left: 0px; 534 | } 535 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons, 536 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons { 537 | float: right; 538 | } 539 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button, 540 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button { 541 | border: none; 542 | background-image: none; 543 | text-transform: uppercase; 544 | font-size: 14px; 545 | font-weight: bold; 546 | text-shadow: none; 547 | -webkit-transition: background .1s; 548 | transition: background .1s; 549 | color: white; 550 | } 551 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default, 552 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default { 553 | box-shadow: none; 554 | color: #fff; 555 | background: none; 556 | } 557 | .jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default:hover, 558 | .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default:hover { 559 | background: #666; 560 | } 561 | .jconfirm.jconfirm-black.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c, 562 | .jconfirm.jconfirm-dark.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { 563 | margin-left: 8px; 564 | margin-right: 0px; 565 | } 566 | .jconfirm .jconfirm-box.hilight.jconfirm-hilight-shake { 567 | -webkit-animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; 568 | animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; 569 | -webkit-transform: translate3d(0, 0, 0); 570 | transform: translate3d(0, 0, 0); 571 | } 572 | .jconfirm .jconfirm-box.hilight.jconfirm-hilight-glow { 573 | -webkit-animation: glow 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; 574 | animation: glow 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; 575 | -webkit-transform: translate3d(0, 0, 0); 576 | transform: translate3d(0, 0, 0); 577 | } 578 | @-webkit-keyframes shake { 579 | 10%, 580 | 90% { 581 | -webkit-transform: translate3d(-2px, 0, 0); 582 | transform: translate3d(-2px, 0, 0); 583 | } 584 | 20%, 585 | 80% { 586 | -webkit-transform: translate3d(4px, 0, 0); 587 | transform: translate3d(4px, 0, 0); 588 | } 589 | 30%, 590 | 50%, 591 | 70% { 592 | -webkit-transform: translate3d(-8px, 0, 0); 593 | transform: translate3d(-8px, 0, 0); 594 | } 595 | 40%, 596 | 60% { 597 | -webkit-transform: translate3d(8px, 0, 0); 598 | transform: translate3d(8px, 0, 0); 599 | } 600 | } 601 | @keyframes shake { 602 | 10%, 603 | 90% { 604 | -webkit-transform: translate3d(-2px, 0, 0); 605 | transform: translate3d(-2px, 0, 0); 606 | } 607 | 20%, 608 | 80% { 609 | -webkit-transform: translate3d(4px, 0, 0); 610 | transform: translate3d(4px, 0, 0); 611 | } 612 | 30%, 613 | 50%, 614 | 70% { 615 | -webkit-transform: translate3d(-8px, 0, 0); 616 | transform: translate3d(-8px, 0, 0); 617 | } 618 | 40%, 619 | 60% { 620 | -webkit-transform: translate3d(8px, 0, 0); 621 | transform: translate3d(8px, 0, 0); 622 | } 623 | } 624 | @-webkit-keyframes glow { 625 | 0%, 626 | 100% { 627 | box-shadow: 0 0 3px red; 628 | } 629 | 50% { 630 | box-shadow: 0 0 30px red; 631 | } 632 | } 633 | @keyframes glow { 634 | 0%, 635 | 100% { 636 | box-shadow: 0 0 3px red; 637 | } 638 | 50% { 639 | box-shadow: 0 0 30px red; 640 | } 641 | } 642 | /*Transition rules*/ 643 | .jconfirm { 644 | -webkit-perspective: 400px; 645 | perspective: 400px; 646 | } 647 | .jconfirm .jconfirm-box { 648 | opacity: 1; 649 | -webkit-transition-property: all; 650 | transition-property: all; 651 | } 652 | .jconfirm .jconfirm-box.jconfirm-animation-top, 653 | .jconfirm .jconfirm-box.jconfirm-animation-left, 654 | .jconfirm .jconfirm-box.jconfirm-animation-right, 655 | .jconfirm .jconfirm-box.jconfirm-animation-bottom, 656 | .jconfirm .jconfirm-box.jconfirm-animation-opacity, 657 | .jconfirm .jconfirm-box.jconfirm-animation-zoom, 658 | .jconfirm .jconfirm-box.jconfirm-animation-scale, 659 | .jconfirm .jconfirm-box.jconfirm-animation-none, 660 | .jconfirm .jconfirm-box.jconfirm-animation-rotate, 661 | .jconfirm .jconfirm-box.jconfirm-animation-rotatex, 662 | .jconfirm .jconfirm-box.jconfirm-animation-rotatey, 663 | .jconfirm .jconfirm-box.jconfirm-animation-scaley, 664 | .jconfirm .jconfirm-box.jconfirm-animation-scalex { 665 | opacity: 0; 666 | } 667 | .jconfirm .jconfirm-box.jconfirm-animation-rotate { 668 | -webkit-transform: rotate(90deg); 669 | -ms-transform: rotate(90deg); 670 | transform: rotate(90deg); 671 | } 672 | .jconfirm .jconfirm-box.jconfirm-animation-rotatex { 673 | -webkit-transform: rotateX(90deg); 674 | transform: rotateX(90deg); 675 | -webkit-transform-origin: center; 676 | -ms-transform-origin: center; 677 | transform-origin: center; 678 | } 679 | .jconfirm .jconfirm-box.jconfirm-animation-rotatexr { 680 | -webkit-transform: rotateX(-90deg); 681 | transform: rotateX(-90deg); 682 | -webkit-transform-origin: center; 683 | -ms-transform-origin: center; 684 | transform-origin: center; 685 | } 686 | .jconfirm .jconfirm-box.jconfirm-animation-rotatey { 687 | -webkit-transform: rotatey(90deg); 688 | -ms-transform: rotatey(90deg); 689 | transform: rotatey(90deg); 690 | -webkit-transform-origin: center; 691 | -ms-transform-origin: center; 692 | transform-origin: center; 693 | } 694 | .jconfirm .jconfirm-box.jconfirm-animation-rotateyr { 695 | -webkit-transform: rotatey(-90deg); 696 | -ms-transform: rotatey(-90deg); 697 | transform: rotatey(-90deg); 698 | -webkit-transform-origin: center; 699 | -ms-transform-origin: center; 700 | transform-origin: center; 701 | } 702 | .jconfirm .jconfirm-box.jconfirm-animation-scaley { 703 | -webkit-transform: scaley(1.5); 704 | -ms-transform: scaley(1.5); 705 | transform: scaley(1.5); 706 | -webkit-transform-origin: center; 707 | -ms-transform-origin: center; 708 | transform-origin: center; 709 | } 710 | .jconfirm .jconfirm-box.jconfirm-animation-scalex { 711 | -webkit-transform: scalex(1.5); 712 | -ms-transform: scalex(1.5); 713 | transform: scalex(1.5); 714 | -webkit-transform-origin: center; 715 | -ms-transform-origin: center; 716 | transform-origin: center; 717 | } 718 | .jconfirm .jconfirm-box.jconfirm-animation-top { 719 | -webkit-transform: translate(0px, -100px); 720 | -ms-transform: translate(0px, -100px); 721 | transform: translate(0px, -100px); 722 | } 723 | .jconfirm .jconfirm-box.jconfirm-animation-left { 724 | -webkit-transform: translate(-100px, 0px); 725 | -ms-transform: translate(-100px, 0px); 726 | transform: translate(-100px, 0px); 727 | } 728 | .jconfirm .jconfirm-box.jconfirm-animation-right { 729 | -webkit-transform: translate(100px, 0px); 730 | -ms-transform: translate(100px, 0px); 731 | transform: translate(100px, 0px); 732 | } 733 | .jconfirm .jconfirm-box.jconfirm-animation-bottom { 734 | -webkit-transform: translate(0px, 100px); 735 | -ms-transform: translate(0px, 100px); 736 | transform: translate(0px, 100px); 737 | } 738 | .jconfirm .jconfirm-box.jconfirm-animation-zoom { 739 | -webkit-transform: scale(1.2); 740 | -ms-transform: scale(1.2); 741 | transform: scale(1.2); 742 | } 743 | .jconfirm .jconfirm-box.jconfirm-animation-scale { 744 | -webkit-transform: scale(0.5); 745 | -ms-transform: scale(0.5); 746 | transform: scale(0.5); 747 | } 748 | .jconfirm .jconfirm-box.jconfirm-animation-none { 749 | visibility: hidden; 750 | } 751 | .jconfirm.jconfirm-supervan .jconfirm-bg { 752 | background-color: rgba(54, 70, 93, 0.95); 753 | } 754 | .jconfirm.jconfirm-supervan .jconfirm-box { 755 | background-color: transparent; 756 | } 757 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-blue { 758 | border: none; 759 | } 760 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-green { 761 | border: none; 762 | } 763 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-red { 764 | border: none; 765 | } 766 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-orange { 767 | border: none; 768 | } 769 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-purple { 770 | border: none; 771 | } 772 | .jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-dark { 773 | border: none; 774 | } 775 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-closeIcon { 776 | color: white; 777 | } 778 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c { 779 | text-align: center; 780 | color: white; 781 | font-size: 28px; 782 | font-weight: normal; 783 | } 784 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c > * { 785 | padding-bottom: 25px; 786 | } 787 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 788 | margin-right: 8px; 789 | margin-left: 0px; 790 | } 791 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content-pane { 792 | margin-bottom: 25px; 793 | } 794 | .jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content { 795 | text-align: center; 796 | color: white; 797 | } 798 | .jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons { 799 | text-align: center; 800 | } 801 | .jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons button { 802 | font-size: 16px; 803 | border-radius: 2px; 804 | background: #303f53; 805 | text-shadow: none; 806 | border: none; 807 | color: white; 808 | padding: 10px; 809 | min-width: 100px; 810 | } 811 | .jconfirm.jconfirm-supervan.jconfirm-rtl .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 812 | margin-left: 8px; 813 | margin-right: 0px; 814 | } 815 | .jconfirm.jconfirm-material .jconfirm-bg { 816 | background-color: rgba(0, 0, 0, 0.67); 817 | } 818 | .jconfirm.jconfirm-material .jconfirm-box { 819 | background-color: white; 820 | box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 13px 19px 2px rgba(0, 0, 0, 0.14), 0 5px 24px 4px rgba(0, 0, 0, 0.12); 821 | padding: 30px 25px 10px 25px; 822 | } 823 | .jconfirm.jconfirm-material .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 824 | margin-right: 8px; 825 | margin-left: 0px; 826 | } 827 | .jconfirm.jconfirm-material .jconfirm-box div.jconfirm-closeIcon { 828 | color: rgba(0, 0, 0, 0.87); 829 | } 830 | .jconfirm.jconfirm-material .jconfirm-box div.jconfirm-title-c { 831 | color: rgba(0, 0, 0, 0.87); 832 | font-size: 22px; 833 | font-weight: bold; 834 | } 835 | .jconfirm.jconfirm-material .jconfirm-box div.jconfirm-content { 836 | color: rgba(0, 0, 0, 0.87); 837 | } 838 | .jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons { 839 | text-align: right; 840 | } 841 | .jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons button { 842 | text-transform: uppercase; 843 | font-weight: 500; 844 | } 845 | .jconfirm.jconfirm-material.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { 846 | margin-left: 8px; 847 | margin-right: 0px; 848 | } 849 | .jconfirm.jconfirm-bootstrap .jconfirm-bg { 850 | background-color: rgba(0, 0, 0, 0.21); 851 | } 852 | .jconfirm.jconfirm-bootstrap .jconfirm-box { 853 | background-color: white; 854 | box-shadow: 0 3px 8px 0px rgba(0, 0, 0, 0.2); 855 | border: solid 1px rgba(0, 0, 0, 0.4); 856 | padding: 15px 0 0; 857 | } 858 | .jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 859 | margin-right: 8px; 860 | margin-left: 0px; 861 | } 862 | .jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-closeIcon { 863 | color: rgba(0, 0, 0, 0.87); 864 | } 865 | .jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-title-c { 866 | color: rgba(0, 0, 0, 0.87); 867 | font-size: 22px; 868 | font-weight: bold; 869 | padding-left: 15px; 870 | padding-right: 15px; 871 | } 872 | .jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-content { 873 | color: rgba(0, 0, 0, 0.87); 874 | padding: 0px 15px; 875 | } 876 | .jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons { 877 | text-align: right; 878 | padding: 10px; 879 | margin: -5px 0 0px; 880 | border-top: solid 1px #ddd; 881 | overflow: hidden; 882 | border-radius: 0 0 4px 4px; 883 | } 884 | .jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons button { 885 | font-weight: 500; 886 | } 887 | .jconfirm.jconfirm-bootstrap.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { 888 | margin-left: 8px; 889 | margin-right: 0px; 890 | } 891 | .jconfirm.jconfirm-modern .jconfirm-bg { 892 | background-color: slategray; 893 | opacity: .6; 894 | } 895 | .jconfirm.jconfirm-modern .jconfirm-box { 896 | background-color: white; 897 | box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 13px 19px 2px rgba(0, 0, 0, 0.14), 0 5px 24px 4px rgba(0, 0, 0, 0.12); 898 | padding: 30px 30px 15px; 899 | } 900 | .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-closeIcon { 901 | color: rgba(0, 0, 0, 0.87); 902 | top: 15px; 903 | right: 15px; 904 | } 905 | .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c { 906 | color: rgba(0, 0, 0, 0.87); 907 | font-size: 24px; 908 | font-weight: bold; 909 | text-align: center; 910 | margin-bottom: 10px; 911 | } 912 | .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { 913 | -webkit-transition: -webkit-transform .5s; 914 | transition: transform .5s; 915 | -webkit-transform: scale(0); 916 | -ms-transform: scale(0); 917 | transform: scale(0); 918 | display: block; 919 | margin-right: 0px; 920 | margin-left: 0px; 921 | margin-bottom: 10px; 922 | font-size: 69px; 923 | color: #aaa; 924 | } 925 | .jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-content { 926 | text-align: center; 927 | font-size: 15px; 928 | color: #777; 929 | margin-bottom: 25px; 930 | } 931 | .jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons { 932 | text-align: center; 933 | } 934 | .jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button { 935 | font-weight: bold; 936 | text-transform: uppercase; 937 | -webkit-transition: background .1s; 938 | transition: background .1s; 939 | padding: 10px 20px; 940 | } 941 | .jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button + button { 942 | margin-left: 4px; 943 | } 944 | .jconfirm.jconfirm-modern.jconfirm-open .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { 945 | -webkit-transform: scale(1); 946 | -ms-transform: scale(1); 947 | transform: scale(1); 948 | } 949 | -------------------------------------------------------------------------------- /servers/portforward/theme/jquery-confirm.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jquery-confirm v3.2.3 (http://craftpip.github.io/jquery-confirm/) 3 | * Author: Boniface Pereira 4 | * Website: www.craftpip.com 5 | * Contact: hey@craftpip.com 6 | * 7 | * Copyright 2013-2017 jquery-confirm 8 | * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) 9 | */ 10 | 11 | if (typeof jQuery === 'undefined') { 12 | throw new Error('jquery-confirm requires jQuery'); 13 | } 14 | 15 | var jconfirm, Jconfirm; 16 | (function ($, window) { 17 | "use strict"; 18 | 19 | $.fn.confirm = function (options, option2) { 20 | if (typeof options === 'undefined') options = {}; 21 | if (typeof options === 'string') { 22 | options = { 23 | content: options, 24 | title: (option2) ? option2 : false 25 | }; 26 | } 27 | /* 28 | * Alias of $.confirm to emulate native confirm() 29 | */ 30 | $(this).each(function () { 31 | var $this = $(this); 32 | $this.on('click', function (e) { 33 | e.preventDefault(); 34 | var jcOption = $.extend({}, options); 35 | if ($this.attr('data-title')) 36 | jcOption['title'] = $this.attr('data-title'); 37 | if ($this.attr('data-content')) 38 | jcOption['content'] = $this.attr('data-content'); 39 | if (typeof jcOption['buttons'] == 'undefined') 40 | jcOption['buttons'] = {}; 41 | 42 | jcOption['$target'] = $this; 43 | if ($this.attr('href') && Object.keys(jcOption['buttons']).length == 0) { 44 | var buttons = $.extend(true, {}, jconfirm.pluginDefaults.defaultButtons, (jconfirm.defaults || {}).defaultButtons || {}); 45 | var firstBtn = Object.keys(buttons)[0]; 46 | jcOption['buttons'] = buttons; 47 | jcOption.buttons[firstBtn].action = function () { 48 | location.href = $this.attr('href'); 49 | }; 50 | } 51 | jcOption['closeIcon'] = false; 52 | $.confirm(jcOption); 53 | }); 54 | }); 55 | return $(this); 56 | }; 57 | $.confirm = function (options, option2) { 58 | if (typeof options === 'undefined') options = {}; 59 | if (typeof options === 'string') { 60 | options = { 61 | content: options, 62 | title: (option2) ? option2 : false 63 | }; 64 | } 65 | 66 | if (typeof options['buttons'] != 'object') 67 | options['buttons'] = {}; 68 | 69 | if (Object.keys(options['buttons']).length == 0) { 70 | var buttons = $.extend(true, {}, jconfirm.pluginDefaults.defaultButtons, (jconfirm.defaults || {}).defaultButtons || {}); 71 | options['buttons'] = buttons; 72 | } 73 | 74 | /* 75 | * Alias of jconfirm 76 | */ 77 | return jconfirm(options); 78 | }; 79 | $.alert = function (options, option2) { 80 | if (typeof options === 'undefined') options = {}; 81 | if (typeof options === 'string') { 82 | options = { 83 | content: options, 84 | title: (option2) ? option2 : false 85 | }; 86 | } 87 | 88 | if (typeof options.buttons != 'object') 89 | options.buttons = {}; 90 | 91 | if (Object.keys(options['buttons']).length == 0) { 92 | var buttons = $.extend(true, {}, jconfirm.pluginDefaults.defaultButtons, (jconfirm.defaults || {}).defaultButtons || {}); 93 | var firstBtn = Object.keys(buttons)[0]; 94 | options['buttons'][firstBtn] = buttons[firstBtn]; 95 | } 96 | /* 97 | * Alias of jconfirm 98 | */ 99 | return jconfirm(options); 100 | }; 101 | $.dialog = function (options, option2) { 102 | if (typeof options === 'undefined') options = {}; 103 | if (typeof options === 'string') { 104 | options = { 105 | content: options, 106 | title: (option2) ? option2 : false, 107 | closeIcon: function () { 108 | // Just close the modal 109 | } 110 | }; 111 | } 112 | 113 | options['buttons'] = {}; // purge buttons 114 | 115 | if (typeof options['closeIcon'] == 'undefined') { 116 | // Dialog must have a closeIcon. 117 | options['closeIcon'] = function () { 118 | } 119 | } 120 | /* 121 | * Alias of jconfirm 122 | */ 123 | options.confirmKeys = [13]; 124 | return jconfirm(options); 125 | }; 126 | 127 | jconfirm = function (options) { 128 | if (typeof options === 'undefined') options = {}; 129 | /* 130 | * initial function for calling. 131 | */ 132 | var pluginOptions = $.extend(true, {}, jconfirm.pluginDefaults); 133 | if (jconfirm.defaults) { 134 | pluginOptions = $.extend(true, pluginOptions, jconfirm.defaults); 135 | } 136 | 137 | /* 138 | * merge options with plugin defaults. 139 | */ 140 | pluginOptions = $.extend(true, {}, pluginOptions, options); 141 | var instance = new Jconfirm(pluginOptions); 142 | jconfirm.instances.push(instance); 143 | return instance; 144 | }; 145 | Jconfirm = function (options) { 146 | /* 147 | * constructor function Jconfirm, 148 | * options = user options. 149 | */ 150 | $.extend(this, options); 151 | this._init(); 152 | }; 153 | Jconfirm.prototype = { 154 | _init: function () { 155 | var that = this; 156 | 157 | if (!jconfirm.instances.length) 158 | jconfirm.lastFocused = $('body').find(':focus'); 159 | 160 | this._id = Math.round(Math.random() * 99999); 161 | 162 | if (!this.lazyOpen) { 163 | setTimeout(function () { 164 | that.open(); 165 | }, 0); 166 | } 167 | }, 168 | _buildHTML: function () { 169 | var that = this; 170 | 171 | // prefix the animation string and store in animationParsed 172 | this._parseAnimation(this.animation, 'o'); 173 | this._parseAnimation(this.closeAnimation, 'c'); 174 | this._parseBgDismissAnimation(this.backgroundDismissAnimation); 175 | this._parseColumnClass(this.columnClass); 176 | this._parseTheme(this.theme); 177 | this._parseType(this.type); 178 | 179 | /* 180 | * Append html. 181 | */ 182 | var template = $(this.template); 183 | template.find('.jconfirm-box').addClass(this.animationParsed).addClass(this.backgroundDismissAnimationParsed).addClass(this.typeParsed); 184 | 185 | if (this.typeAnimated) 186 | template.find('.jconfirm-box').addClass('jconfirm-type-animated'); 187 | 188 | if (this.useBootstrap) { 189 | template.find('.jc-bs3-row').addClass(this.bootstrapClasses.row); 190 | template.find('.jc-bs3-row').addClass('justify-content-md-center justify-content-sm-center justify-content-xs-center justify-content-lg-center'); 191 | 192 | template.find('.jconfirm-box-container').addClass(this.columnClassParsed); 193 | 194 | if (this.containerFluid) 195 | template.find('.jc-bs3-container').addClass(this.bootstrapClasses.containerFluid); 196 | else 197 | template.find('.jc-bs3-container').addClass(this.bootstrapClasses.container); 198 | } else { 199 | template.find('.jconfirm-box').css('width', this.boxWidth); 200 | } 201 | 202 | if (this.titleClass) 203 | template.find('.jconfirm-title-c').addClass(this.titleClass); 204 | 205 | template.addClass(this.themeParsed); 206 | var ariaLabel = 'jconfirm-box' + this._id; 207 | template.find('.jconfirm-box').attr('aria-labelledby', ariaLabel).attr('tabindex', -1); 208 | template.find('.jconfirm-content').attr('id', ariaLabel); 209 | if (this.bgOpacity != null) 210 | template.find('.jconfirm-bg').css('opacity', this.bgOpacity); 211 | if (this.rtl) 212 | template.addClass('jconfirm-rtl'); 213 | 214 | this.$el = template.appendTo(this.container); 215 | this.$jconfirmBoxContainer = this.$el.find('.jconfirm-box-container'); 216 | this.$jconfirmBox = this.$body = this.$el.find('.jconfirm-box'); 217 | this.$jconfirmBg = this.$el.find('.jconfirm-bg'); 218 | this.$title = this.$el.find('.jconfirm-title'); 219 | this.$titleContainer = this.$el.find('.jconfirm-title-c'); 220 | this.$content = this.$el.find('div.jconfirm-content'); 221 | this.$contentPane = this.$el.find('.jconfirm-content-pane'); 222 | this.$icon = this.$el.find('.jconfirm-icon-c'); 223 | this.$closeIcon = this.$el.find('.jconfirm-closeIcon'); 224 | // this.$content.css(this._getCSS(this.animationSpeed, this.animationBounce)); 225 | this.$btnc = this.$el.find('.jconfirm-buttons'); 226 | this.$scrollPane = this.$el.find('.jconfirm-scrollpane'); 227 | 228 | // for loading content via URL 229 | this._contentReady = $.Deferred(); 230 | this._modalReady = $.Deferred(); 231 | 232 | this.setTitle(); 233 | this.setIcon(); 234 | this._setButtons(); 235 | this._parseContent(); 236 | this.initDraggable(); 237 | 238 | if (this.isAjax) 239 | this.showLoading(false); 240 | 241 | $.when(this._contentReady, this._modalReady).then(function () { 242 | if (that.isAjaxLoading) 243 | setTimeout(function () { 244 | that.isAjaxLoading = false; 245 | that.setContent(); 246 | that.setTitle(); 247 | that.setIcon(); 248 | setTimeout(function () { 249 | that.hideLoading(false); 250 | }, 100); 251 | if (typeof that.onContentReady == 'function') 252 | that.onContentReady(); 253 | }, 50); 254 | else { 255 | that.setContent(); 256 | that.setTitle(); 257 | that.setIcon(); 258 | if (typeof that.onContentReady == 'function') 259 | that.onContentReady(); 260 | } 261 | 262 | // start countdown after content has loaded. 263 | if (that.autoClose) 264 | that._startCountDown(); 265 | }); 266 | 267 | // initial hash for comparison 268 | that._contentHash = this._hash(that.$content.html()); 269 | that._contentHeight = this.$content.height(); 270 | 271 | this._watchContent(); 272 | this.setDialogCenter(); 273 | 274 | if (this.animation == 'none') { 275 | this.animationSpeed = 1; 276 | this.animationBounce = 1; 277 | } 278 | 279 | this.$body.css(this._getCSS(this.animationSpeed, this.animationBounce)); 280 | this.$contentPane.css(this._getCSS(this.animationSpeed, 1)); 281 | this.$jconfirmBg.css(this._getCSS(this.animationSpeed, 1)); 282 | }, 283 | _typePrefix: 'jconfirm-type-', 284 | typeParsed: '', 285 | _parseType: function (type) { 286 | this.typeParsed = this._typePrefix + type; 287 | }, 288 | setType: function (type) { 289 | var oldClass = this.typeParsed; 290 | this._parseType(type); 291 | this.$jconfirmBox.removeClass(oldClass).addClass(this.typeParsed); 292 | }, 293 | themeParsed: '', 294 | _themePrefix: 'jconfirm-', 295 | setTheme: function (theme) { 296 | var previous = this.theme; 297 | this.theme = theme || this.theme; 298 | this._parseTheme(this.theme); 299 | if (previous) 300 | this.$el.removeClass(previous); 301 | this.$el.addClass(this.themeParsed); 302 | this.theme = theme; 303 | }, 304 | _parseTheme: function (theme) { 305 | var that = this; 306 | theme = theme.split(','); 307 | $.each(theme, function (k, a) { 308 | if (a.indexOf(that._themePrefix) == -1) 309 | theme[k] = that._themePrefix + $.trim(a); 310 | }); 311 | this.themeParsed = theme.join(' ').toLowerCase(); 312 | }, 313 | backgroundDismissAnimationParsed: '', 314 | _bgDismissPrefix: 'jconfirm-hilight-', 315 | _parseBgDismissAnimation: function (bgDismissAnimation) { 316 | var animation = bgDismissAnimation.split(','); 317 | var that = this; 318 | $.each(animation, function (k, a) { 319 | if (a.indexOf(that._bgDismissPrefix) == -1) 320 | animation[k] = that._bgDismissPrefix + $.trim(a); 321 | }); 322 | this.backgroundDismissAnimationParsed = animation.join(' ').toLowerCase(); 323 | }, 324 | animationParsed: '', 325 | closeAnimationParsed: '', 326 | _animationPrefix: 'jconfirm-animation-', 327 | setAnimation: function (animation) { 328 | this.animation = animation || this.animation; 329 | this._parseAnimation(this.animation, 'o'); 330 | }, 331 | _parseAnimation: function (animation, which) { 332 | which = which || 'o'; // parse what animation and store where. open or close? 333 | var animations = animation.split(','); 334 | var that = this; 335 | $.each(animations, function (k, a) { 336 | if (a.indexOf(that._animationPrefix) == -1) 337 | animations[k] = that._animationPrefix + $.trim(a); 338 | }); 339 | var a_string = animations.join(' ').toLowerCase(); 340 | if (which == 'o') 341 | this.animationParsed = a_string; 342 | else 343 | this.closeAnimationParsed = a_string; 344 | 345 | return a_string; 346 | }, 347 | setCloseAnimation: function (closeAnimation) { 348 | this.closeAnimation = closeAnimation || this.closeAnimation; 349 | this._parseAnimation(this.closeAnimation, 'c'); 350 | }, 351 | setAnimationSpeed: function (speed) { 352 | this.animationSpeed = speed || this.animationSpeed; 353 | // this.$body.css(this._getCSS(this.animationSpeed, this.animationBounce)); 354 | }, 355 | columnClassParsed: '', 356 | setColumnClass: function (colClass) { 357 | if (!this.useBootstrap) { 358 | console.warn("cannot set columnClass, useBootstrap is set to false"); 359 | return; 360 | } 361 | this.columnClass = colClass || this.columnClass; 362 | this._parseColumnClass(this.columnClass); 363 | this.$jconfirmBoxContainer.addClass(this.columnClassParsed); 364 | }, 365 | setBoxWidth: function () { 366 | if (this.useBootstrap) { 367 | console.warn("cannot set boxWidth, useBootstrap is set to true"); 368 | return; 369 | } 370 | this.$jconfirmBox.css('width', this.boxWidth); 371 | }, 372 | _parseColumnClass: function (colClass) { 373 | colClass = colClass.toLowerCase(); 374 | var p; 375 | switch (colClass) { 376 | case 'xl': 377 | case 'xlarge': 378 | p = 'col-md-12'; 379 | break; 380 | case 'l': 381 | case 'large': 382 | p = 'col-md-8 col-md-offset-2'; 383 | break; 384 | case 'm': 385 | case 'medium': 386 | p = 'col-md-6 col-md-offset-3'; 387 | break; 388 | case 's': 389 | case 'small': 390 | p = 'col-md-4 col-md-offset-4'; 391 | break; 392 | case 'xs': 393 | case 'xsmall': 394 | p = 'col-md-2 col-md-offset-5'; 395 | break; 396 | default: 397 | p = colClass; 398 | } 399 | this.columnClassParsed = p; 400 | }, 401 | initDraggable: function () { 402 | var that = this; 403 | var $t = this.$titleContainer; 404 | 405 | this.resetDrag(); 406 | if (this.draggable) { 407 | $t.addClass('jconfirm-hand'); 408 | $t.on('mousedown', function (e) { 409 | that.mouseX = e.clientX; 410 | that.mouseY = e.clientY; 411 | that.isDrag = true; 412 | }); 413 | $(window).on('mousemove.' + this._id, function (e) { 414 | if (that.isDrag) { 415 | that.movingX = e.clientX - that.mouseX + that.initialX; 416 | that.movingY = e.clientY - that.mouseY + that.initialY; 417 | that.setDrag(); 418 | } 419 | }); 420 | 421 | $(window).on('mouseup.' + this._id, function () { 422 | if (that.isDrag) { 423 | that.isDrag = false; 424 | that.initialX = that.movingX; 425 | that.initialY = that.movingY; 426 | } 427 | }) 428 | } 429 | }, 430 | resetDrag: function () { 431 | this.isDrag = false; 432 | this.initialX = 0; 433 | this.initialY = 0; 434 | this.movingX = 0; 435 | this.movingY = 0; 436 | this.movingXCurrent = 0; 437 | this.movingYCurrent = 0; 438 | this.mouseX = 0; 439 | this.mouseY = 0; 440 | this.$jconfirmBoxContainer.css('transform', 'translate(' + 0 + 'px, ' + 0 + 'px)'); 441 | }, 442 | setDrag: function () { 443 | if (!this.draggable) 444 | return; 445 | 446 | this.alignMiddle = false; 447 | this._boxWidth = this.$jconfirmBox.outerWidth(); 448 | var ww = $(window).width(); 449 | var that = this; 450 | if (that.movingX % 2 == 0 || that.movingY % 2 == 0) { 451 | var tb = that._boxTopMargin - that.dragWindowGap; 452 | 453 | if (tb + that.movingY < 0) { 454 | that.movingY = -tb; 455 | } else { 456 | that.movingYCurrent = that.movingY; 457 | } 458 | var lb = (ww / 2) - that._boxWidth / 2; 459 | var rb = (ww / 2) + (that._boxWidth / 2) - that._boxWidth; 460 | rb -= that.dragWindowGap; 461 | lb -= that.dragWindowGap; 462 | 463 | if (lb + that.movingX < 0) { 464 | that.movingX = -lb; 465 | } else if (rb - that.movingX < 0) { 466 | that.movingX = rb; 467 | } else { 468 | that.movingXCurrent = that.movingX; 469 | } 470 | 471 | that.$jconfirmBoxContainer.css('transform', 'translate(' + that.movingX + 'px, ' + that.movingY + 'px)'); 472 | } 473 | }, 474 | _hash: function (a) { 475 | var string = a.toString(); 476 | var h = 0; 477 | if (string.length == 0) return h; 478 | for (var i = 0; i < string.length; i++) { 479 | var c = string.toString().charCodeAt(i); 480 | h = ((h << 5) - h) + c; 481 | h = h & h; // Convert to 32bit integer 482 | } 483 | return h; 484 | }, 485 | _watchContent: function () { 486 | var that = this; 487 | if (this._timer) clearInterval(this._timer); 488 | this._timer = setInterval(function () { 489 | var now = that._hash(that.$content.html()); 490 | var nowHeight = that.$content.height(); 491 | if (that._contentHash != now || that._contentHeight != nowHeight) { 492 | that._contentHash = now; 493 | that._contentHeight = nowHeight; 494 | that.setDialogCenter(); 495 | that._imagesLoaded(); 496 | } 497 | }, this.watchInterval); 498 | }, 499 | _hilightAnimating: false, 500 | _hiLightModal: function () { 501 | var that = this; 502 | if (this._hilightAnimating) 503 | return; 504 | 505 | that.$body.addClass('hilight'); 506 | // var duration = parseFloat(that.$body.css('animation-duration')) || 0; 507 | var duration = 2; // 2 seconds default 508 | this._hilightAnimating = true; 509 | setTimeout(function () { 510 | that._hilightAnimating = false; 511 | that.$body.removeClass('hilight'); 512 | }, duration * 1000); 513 | }, 514 | _bindEvents: function () { 515 | var that = this; 516 | this.boxClicked = false; 517 | 518 | this.$scrollPane.click(function (e) { // Ignore propagated clicks 519 | if (!that.boxClicked) { // Background clicked 520 | /* 521 | If backgroundDismiss is a function and its return value is truthy 522 | proceed to close the modal. 523 | */ 524 | var buttonName = false; 525 | var shouldClose = false; 526 | var str; 527 | 528 | if (typeof that.backgroundDismiss == 'function') 529 | str = that.backgroundDismiss(); 530 | else 531 | str = that.backgroundDismiss; 532 | 533 | if (typeof str == 'string' && typeof that.buttons[str] != 'undefined') { 534 | buttonName = str; 535 | shouldClose = false; 536 | } else if (typeof str == 'undefined' || !!(str) == true) { 537 | shouldClose = true; 538 | } else { 539 | shouldClose = false; 540 | } 541 | 542 | if (buttonName) { 543 | var btnResponse = that.buttons[buttonName].action.apply(that); 544 | shouldClose = (typeof btnResponse == 'undefined') || !!(btnResponse); 545 | } 546 | 547 | if (shouldClose) 548 | that.close(); 549 | else 550 | that._hiLightModal(); 551 | } 552 | that.boxClicked = false; 553 | }); 554 | 555 | this.$jconfirmBox.click(function (e) { 556 | that.boxClicked = true; 557 | }); 558 | 559 | var isKeyDown = false; 560 | $(window).on('jcKeyDown.' + that._id, function (e) { 561 | if (!isKeyDown) { 562 | isKeyDown = true; 563 | } 564 | }); 565 | $(window).on('keyup.' + that._id, function (e) { 566 | if (isKeyDown) { 567 | that.reactOnKey(e); 568 | isKeyDown = false; 569 | } 570 | }); 571 | 572 | $(window).on('resize.' + this._id, function () { 573 | that.setDialogCenter(true); 574 | setTimeout(function () { 575 | that.resetDrag(); 576 | }, 100); 577 | }); 578 | }, 579 | _cubic_bezier: '0.36, 0.55, 0.19', 580 | _getCSS: function (speed, bounce) { 581 | return { 582 | '-webkit-transition-duration': speed / 1000 + 's', 583 | 'transition-duration': speed / 1000 + 's', 584 | '-webkit-transition-timing-function': 'cubic-bezier(' + this._cubic_bezier + ', ' + bounce + ')', 585 | 'transition-timing-function': 'cubic-bezier(' + this._cubic_bezier + ', ' + bounce + ')' 586 | }; 587 | }, 588 | _imagesLoaded: function () { 589 | // detect if the image is loaded by checking on its height. 590 | var that = this; 591 | if (that.imageLoadInterval) 592 | clearInterval(that.imageLoadInterval); 593 | 594 | $.each(this.$content.find('img:not(.loaded)'), function (i, a) { 595 | that.imageLoadInterval = setInterval(function () { 596 | var h = $(a).css('height'); 597 | if (h !== '0px') { 598 | $(a).addClass('loaded'); 599 | clearInterval(that.imageLoadInterval); 600 | that.setDialogCenter(); 601 | } 602 | }, 40); 603 | }); 604 | }, 605 | _setButtons: function () { 606 | var that = this; 607 | /* 608 | * Settings up buttons 609 | */ 610 | 611 | var total_buttons = 0; 612 | if (typeof this.buttons !== 'object') 613 | this.buttons = {}; 614 | 615 | $.each(this.buttons, function (key, button) { 616 | total_buttons += 1; 617 | if (typeof button === 'function') { 618 | that.buttons[key] = button = { 619 | action: button 620 | }; 621 | } 622 | 623 | that.buttons[key].text = button.text || key; 624 | that.buttons[key].btnClass = button.btnClass || 'btn-default'; 625 | that.buttons[key].action = button.action || function () { 626 | }; 627 | that.buttons[key].keys = button.keys || []; 628 | that.buttons[key].isHidden = button.isHidden || false; 629 | that.buttons[key].isDisabled = button.isDisabled || false; 630 | 631 | $.each(that.buttons[key].keys, function (i, a) { 632 | that.buttons[key].keys[i] = a.toLowerCase(); 633 | }); 634 | 635 | var button_element = $('') 636 | .html(that.buttons[key].text) 637 | .addClass(that.buttons[key].btnClass) 638 | .prop('disabled', that.buttons[key].isDisabled) 639 | .css('display', that.buttons[key].isHidden ? 'none' : '') 640 | .click(function (e) { 641 | e.preventDefault(); 642 | var res = that.buttons[key].action.apply(that); 643 | that.onAction(key); 644 | that._stopCountDown(); 645 | if (typeof res === 'undefined' || res) 646 | that.close(); 647 | }); 648 | 649 | that.buttons[key].el = button_element; 650 | that.buttons[key].setText = function (text) { 651 | button_element.html(text); 652 | }; 653 | that.buttons[key].addClass = function (className) { 654 | button_element.addClass(className); 655 | }; 656 | that.buttons[key].removeClass = function (className) { 657 | button_element.removeClass(className); 658 | }; 659 | that.buttons[key].disable = function () { 660 | that.buttons[key].isDisabled = true; 661 | button_element.prop('disabled', true); 662 | }; 663 | that.buttons[key].enable = function () { 664 | that.buttons[key].isDisabled = false; 665 | button_element.prop('disabled', false); 666 | }; 667 | that.buttons[key].show = function () { 668 | that.buttons[key].isHidden = false; 669 | button_element.css('display', ''); 670 | that.setDialogCenter(); 671 | }; 672 | that.buttons[key].hide = function () { 673 | that.buttons[key].isHidden = true; 674 | button_element.css('display', 'none'); 675 | that.setDialogCenter(); 676 | }; 677 | /* 678 | Buttons are prefixed with $_ or $$ for quick access 679 | */ 680 | that['$_' + key] = that['$$' + key] = button_element; 681 | that.$btnc.append(button_element); 682 | }); 683 | 684 | if (total_buttons === 0) this.$btnc.hide(); 685 | if (this.closeIcon === null && total_buttons === 0) { 686 | /* 687 | in case when no buttons are present & closeIcon is null, closeIcon is set to true, 688 | set closeIcon to true to explicitly tell to hide the close icon 689 | */ 690 | this.closeIcon = true; 691 | } 692 | 693 | if (this.closeIcon) { 694 | if (this.closeIconClass) { 695 | // user requires a custom class. 696 | var closeHtml = ''; 697 | this.$closeIcon.html(closeHtml); 698 | } 699 | 700 | this.$closeIcon.click(function (e) { 701 | e.preventDefault(); 702 | 703 | var buttonName = false; 704 | var shouldClose = false; 705 | var str; 706 | 707 | if (typeof that.closeIcon == 'function') { 708 | str = that.closeIcon(); 709 | } else { 710 | str = that.closeIcon; 711 | } 712 | 713 | if (typeof str == 'string' && typeof that.buttons[str] != 'undefined') { 714 | buttonName = str; 715 | shouldClose = false; 716 | } else if (typeof str == 'undefined' || !!(str) == true) { 717 | shouldClose = true; 718 | } else { 719 | shouldClose = false; 720 | } 721 | if (buttonName) { 722 | var btnResponse = that.buttons[buttonName].action.apply(that); 723 | shouldClose = (typeof btnResponse == 'undefined') || !!(btnResponse); 724 | } 725 | if (shouldClose) { 726 | that.close(); 727 | } 728 | }); 729 | this.$closeIcon.show(); 730 | } else { 731 | this.$closeIcon.hide(); 732 | } 733 | }, 734 | setTitle: function (string, force) { 735 | force = force || false; 736 | 737 | if (typeof string !== 'undefined') 738 | if (typeof string == 'string') 739 | this.title = string; 740 | else if (typeof string == 'function') { 741 | if (typeof string.promise == 'function') 742 | console.error('Promise was returned from title function, this is not supported.'); 743 | 744 | var response = string(); 745 | if (typeof response == 'string') 746 | this.title = response; 747 | else 748 | this.title = false; 749 | } else 750 | this.title = false; 751 | 752 | if (this.isAjaxLoading && !force) 753 | return; 754 | 755 | this.$title.html(this.title || ''); 756 | }, 757 | setIcon: function (iconClass, force) { 758 | force = force || false; 759 | 760 | if (typeof iconClass !== 'undefined') 761 | if (typeof iconClass == 'string') 762 | this.icon = iconClass; 763 | else if (typeof iconClass === 'function') { 764 | var response = iconClass(); 765 | if (typeof response == 'string') 766 | this.icon = response; 767 | else 768 | this.icon = false; 769 | } 770 | else 771 | this.icon = false; 772 | 773 | if (this.isAjaxLoading && !force) 774 | return; 775 | 776 | this.$icon.html(this.icon ? '' : ''); 777 | }, 778 | setContentPrepend: function (string, force) { 779 | this.contentParsed = string + this.contentParsed; 780 | if (this.isAjaxLoading && !force) 781 | return; 782 | 783 | this.$content.prepend(string); 784 | }, 785 | setContentAppend: function (string, force) { 786 | this.contentParsed = this.contentParsed + string; 787 | if (this.isAjaxLoading && !force) 788 | return; 789 | 790 | this.$content.append(string); 791 | }, 792 | setContent: function (string, force) { 793 | force = force || false; 794 | var that = this; 795 | this.contentParsed = (typeof string == 'undefined') ? this.contentParsed : string; 796 | if (this.isAjaxLoading && !force) 797 | return; 798 | 799 | this.$content.html(this.contentParsed); 800 | this.setDialogCenter(); 801 | setTimeout(function () { 802 | that.$body.find('input[autofocus]:visible:first').focus(); 803 | }, 100); 804 | }, 805 | loadingSpinner: false, 806 | showLoading: function (disableButtons) { 807 | this.loadingSpinner = true; 808 | this.$jconfirmBox.addClass('loading'); 809 | if (disableButtons) 810 | this.$btnc.find('button').prop('disabled', true); 811 | 812 | this.setDialogCenter(); 813 | }, 814 | hideLoading: function (enableButtons) { 815 | this.loadingSpinner = false; 816 | this.$jconfirmBox.removeClass('loading'); 817 | if (enableButtons) 818 | this.$btnc.find('button').prop('disabled', false); 819 | 820 | this.setDialogCenter(); 821 | }, 822 | ajaxResponse: false, 823 | contentParsed: '', 824 | isAjax: false, 825 | isAjaxLoading: false, 826 | _parseContent: function () { 827 | var that = this; 828 | var e = ' '; 829 | 830 | if (typeof this.content == 'function') { 831 | var res = this.content.apply(this); 832 | if (typeof res == 'string') { 833 | this.content = res; 834 | } 835 | else if (typeof res == 'object' && typeof res.always == 'function') { 836 | // this is ajax loading via promise 837 | this.isAjax = true; 838 | this.isAjaxLoading = true; 839 | res.always(function (data, status, xhr) { 840 | that.ajaxResponse = { 841 | data: data, 842 | status: status, 843 | xhr: xhr 844 | }; 845 | that._contentReady.resolve(data, status, xhr); 846 | if (typeof that.contentLoaded == 'function') 847 | that.contentLoaded(data, status, xhr); 848 | }); 849 | this.content = e; 850 | } else { 851 | this.content = e; 852 | } 853 | } 854 | 855 | if (typeof this.content == 'string' && this.content.substr(0, 4).toLowerCase() === 'url:') { 856 | this.isAjax = true; 857 | this.isAjaxLoading = true; 858 | var u = this.content.substring(4, this.content.length); 859 | $.get(u).done(function (html) { 860 | that.contentParsed = html; 861 | }).always(function (data, status, xhr) { 862 | that.ajaxResponse = { 863 | data: data, 864 | status: status, 865 | xhr: xhr 866 | }; 867 | that._contentReady.resolve(data, status, xhr); 868 | if (typeof that.contentLoaded == 'function') 869 | that.contentLoaded(data, status, xhr); 870 | }); 871 | } 872 | 873 | if (!this.content) 874 | this.content = e; 875 | 876 | if (!this.isAjax) { 877 | this.contentParsed = this.content; 878 | this.setContent(this.contentParsed); 879 | that._contentReady.resolve(); 880 | } 881 | }, 882 | _stopCountDown: function () { 883 | clearInterval(this.autoCloseInterval); 884 | if (this.$cd) 885 | this.$cd.remove(); 886 | }, 887 | _startCountDown: function () { 888 | var that = this; 889 | var opt = this.autoClose.split('|'); 890 | if (opt.length !== 2) { 891 | console.error('Invalid option for autoClose. example \'close|10000\''); 892 | return false; 893 | } 894 | 895 | var button_key = opt[0]; 896 | var time = parseInt(opt[1]); 897 | if (typeof this.buttons[button_key] === 'undefined') { 898 | console.error('Invalid button key \'' + button_key + '\' for autoClose'); 899 | return false; 900 | } 901 | 902 | var seconds = Math.ceil(time / 1000); 903 | this.$cd = $(' (' + seconds + ')') 904 | .appendTo(this['$_' + button_key]); 905 | 906 | this.autoCloseInterval = setInterval(function () { 907 | that.$cd.html(' (' + (seconds -= 1) + ') '); 908 | if (seconds <= 0) { 909 | that['$$' + button_key].trigger('click'); 910 | that._stopCountDown(); 911 | } 912 | }, 1000); 913 | }, 914 | _getKey: function (key) { 915 | // very necessary keys. 916 | switch (key) { 917 | case 192: 918 | return 'tilde'; 919 | case 13: 920 | return 'enter'; 921 | case 16: 922 | return 'shift'; 923 | case 9: 924 | return 'tab'; 925 | case 20: 926 | return 'capslock'; 927 | case 17: 928 | return 'ctrl'; 929 | case 91: 930 | return 'win'; 931 | case 18: 932 | return 'alt'; 933 | case 27: 934 | return 'esc'; 935 | case 32: 936 | return 'space'; 937 | } 938 | 939 | // only trust alphabets with this. 940 | var initial = String.fromCharCode(key); 941 | if (/^[A-z0-9]+$/.test(initial)) 942 | return initial.toLowerCase(); 943 | else 944 | return false; 945 | }, 946 | reactOnKey: function (e) { 947 | var that = this; 948 | 949 | /* 950 | Prevent keyup event if the dialog is not last! 951 | */ 952 | var a = $('.jconfirm'); 953 | if (a.eq(a.length - 1)[0] !== this.$el[0]) 954 | return false; 955 | 956 | var key = e.which; 957 | /* 958 | Do not react if Enter or Space is pressed on input elements 959 | */ 960 | if (this.$content.find(':input').is(':focus') && /13|32/.test(key)) 961 | return false; 962 | 963 | var keyChar = this._getKey(key); 964 | 965 | // If esc is pressed 966 | if (keyChar === 'esc' && this.escapeKey) { 967 | if (this.escapeKey === true) { 968 | this.$scrollPane.trigger('click'); 969 | } 970 | else if (typeof this.escapeKey === 'string' || typeof this.escapeKey === 'function') { 971 | var buttonKey; 972 | if (typeof this.escapeKey === 'function') { 973 | buttonKey = this.escapeKey(); 974 | } else { 975 | buttonKey = this.escapeKey; 976 | } 977 | 978 | if (buttonKey) 979 | if (typeof this.buttons[buttonKey] === 'undefined') { 980 | console.warn('Invalid escapeKey, no buttons found with key ' + buttonKey); 981 | } else { 982 | this['$_' + buttonKey].trigger('click'); 983 | } 984 | } 985 | } 986 | 987 | // check if any button is listening to this key. 988 | $.each(this.buttons, function (key, button) { 989 | if (button.keys.indexOf(keyChar) != -1) { 990 | that['$_' + key].trigger('click'); 991 | } 992 | }); 993 | }, 994 | _boxTopMargin: 0, 995 | _boxBottomMargin: 0, 996 | _boxWidth: 0, 997 | setDialogCenter: function () { 998 | var contentHeight; 999 | var paneHeight; 1000 | var style; 1001 | contentHeight = 0; 1002 | paneHeight = 0; 1003 | if (this.$contentPane.css('display') != 'none') { 1004 | contentHeight = this.$content.outerHeight() || 0; 1005 | paneHeight = this.$contentPane.height() || 0; 1006 | } 1007 | 1008 | // if the child has margin top 1009 | var children = this.$content.children(); 1010 | if (children.length != 0) { 1011 | var marginTopChild = parseInt(children.eq(0).css('margin-top')); 1012 | if (marginTopChild) 1013 | contentHeight += marginTopChild; 1014 | } 1015 | 1016 | if (paneHeight == 0) { 1017 | paneHeight = contentHeight; 1018 | } 1019 | 1020 | var windowHeight = $(window).height(); 1021 | var boxHeight; 1022 | 1023 | boxHeight = (this.$body.outerHeight() - paneHeight) + contentHeight; 1024 | 1025 | var topMargin = (windowHeight - boxHeight) / 2; 1026 | if (boxHeight > (windowHeight - (this.offsetTop + this.offsetBottom)) || !this.alignMiddle) { 1027 | style = { 1028 | 'margin-top': this.offsetTop, 1029 | 'margin-bottom': this.offsetBottom 1030 | }; 1031 | this._boxTopMargin = this.offsetTop; 1032 | this._boxBottomMargin = this.offsetBottom; 1033 | $('body').addClass('jconfirm-no-scroll-' + this._id); 1034 | } else { 1035 | style = { 1036 | 'margin-top': topMargin, 1037 | 'margin-bottom': this.offsetBottom 1038 | }; 1039 | this._boxTopMargin = topMargin; 1040 | this._boxBottomMargin = this.offsetBottom; 1041 | $('body').removeClass('jconfirm-no-scroll-' + this._id); 1042 | } 1043 | 1044 | this.$contentPane.css({ 1045 | 'height': contentHeight 1046 | }).scrollTop(0); 1047 | this.$body.css(style); 1048 | 1049 | this.setDrag(); 1050 | }, 1051 | _unwatchContent: function () { 1052 | clearInterval(this._timer); 1053 | }, 1054 | close: function () { 1055 | var that = this; 1056 | 1057 | if (typeof this.onClose === 'function') 1058 | this.onClose(); 1059 | 1060 | this._unwatchContent(); 1061 | clearInterval(this.imageLoadInterval); 1062 | 1063 | /* 1064 | unbind the window resize & keyup event. 1065 | */ 1066 | $(window).unbind('resize.' + this._id); 1067 | $(window).unbind('keyup.' + this._id); 1068 | $(window).unbind('jcKeyDown.' + this._id); 1069 | 1070 | if (this.draggable) { 1071 | $(window).unbind('mousemove.' + this._id); 1072 | $(window).unbind('mouseup.' + this._id); 1073 | this.$titleContainer.unbind('mousedown'); 1074 | } 1075 | $('body').removeClass('jconfirm-no-scroll-' + this._id); 1076 | this.$body.addClass(this.closeAnimationParsed); 1077 | this.$jconfirmBg.addClass('jconfirm-bg-h'); 1078 | var closeTimer = (this.closeAnimation == 'none') ? 1 : this.animationSpeed; 1079 | that.$el.removeClass(that.loadedClass); 1080 | setTimeout(function () { 1081 | that.$el.remove(); 1082 | 1083 | var l = jconfirm.instances; 1084 | var i = jconfirm.instances.length - 1; 1085 | for (i; i >= 0; i--) { 1086 | if (jconfirm.instances[i]._id == that._id) { 1087 | jconfirm.instances.splice(i, 1); 1088 | } 1089 | } 1090 | 1091 | // Focusing a element, scrolls automatically to that element. 1092 | // no instances should be open, lastFocused should be true, the lastFocused element must exists in DOM 1093 | if (!jconfirm.instances.length) { 1094 | if (that.scrollToPreviousElement && jconfirm.lastFocused && jconfirm.lastFocused.length && $.contains(document, jconfirm.lastFocused[0])) { 1095 | var $lf = jconfirm.lastFocused; 1096 | if (that.scrollToPreviousElementAnimate) { 1097 | var st = $(window).scrollTop(); 1098 | var ot = jconfirm.lastFocused.offset().top; 1099 | var wh = $(window).height(); 1100 | if (!(ot > st && ot < (st + wh))) { 1101 | var scrollTo = (ot - Math.round((wh / 3))); 1102 | $('html, body').animate({ 1103 | scrollTop: scrollTo 1104 | }, that.animationSpeed, 'swing', function () { 1105 | // gracefully scroll and then focus. 1106 | $lf.focus(); 1107 | }); 1108 | } else { 1109 | // the element to be focused is already in view. 1110 | $lf.focus(); 1111 | } 1112 | } else { 1113 | $lf.focus(); 1114 | } 1115 | jconfirm.lastFocused = false; 1116 | } 1117 | } 1118 | 1119 | if (typeof that.onDestroy == 'function') 1120 | that.onDestroy(); 1121 | 1122 | }, closeTimer * 0.40); 1123 | 1124 | return true; 1125 | }, 1126 | open: function () { 1127 | if (this.isOpen()) 1128 | return false; 1129 | 1130 | // var that = this; 1131 | this._buildHTML(); 1132 | this._bindEvents(); 1133 | this._open(); 1134 | 1135 | return true; 1136 | }, 1137 | _open: function () { 1138 | var that = this; 1139 | if (typeof that.onOpenBefore == 'function') 1140 | that.onOpenBefore(); 1141 | this.$body.removeClass(this.animationParsed); 1142 | this.$jconfirmBg.removeClass('jconfirm-bg-h'); 1143 | this.$body.focus(); 1144 | setTimeout(function () { 1145 | that.$body.css(that._getCSS(that.animationSpeed, 1)); 1146 | that.$body.css({ 1147 | 'transition-property': that.$body.css('transition-property') + ', margin' 1148 | }); 1149 | that._modalReady.resolve(); 1150 | if (typeof that.onOpen === 'function') 1151 | that.onOpen(); 1152 | 1153 | that.$el.addClass(that.loadedClass); 1154 | }, this.animationSpeed); 1155 | }, 1156 | loadedClass: 'jconfirm-open', 1157 | isClosed: function () { 1158 | return !this.$el || this.$el.css('display') === ''; 1159 | }, 1160 | isOpen: function () { 1161 | return !this.isClosed(); 1162 | }, 1163 | toggle: function () { 1164 | if (!this.isOpen()) 1165 | this.open(); 1166 | else 1167 | this.close(); 1168 | } 1169 | }; 1170 | 1171 | jconfirm.instances = []; 1172 | jconfirm.lastFocused = false; 1173 | jconfirm.pluginDefaults = { 1174 | template: '' + 1175 | '
' + 1176 | '
' + 1177 | '
' + 1178 | '
' + 1179 | '
' + 1180 | '
' + 1181 | '
', 1193 | title: 'Hello', 1194 | titleClass: '', 1195 | type: 'default', 1196 | typeAnimated: true, 1197 | draggable: false, 1198 | alignMiddle: true, 1199 | content: 'Are you sure to continue?', 1200 | buttons: {}, 1201 | defaultButtons: { 1202 | ok: { 1203 | action: function () { 1204 | } 1205 | }, 1206 | close: { 1207 | action: function () { 1208 | } 1209 | } 1210 | }, 1211 | contentLoaded: function () { 1212 | }, 1213 | icon: '', 1214 | lazyOpen: false, 1215 | bgOpacity: null, 1216 | theme: 'light', 1217 | animation: 'zoom', 1218 | closeAnimation: 'scale', 1219 | animationSpeed: 400, 1220 | animationBounce: 1.2, 1221 | escapeKey: true, 1222 | rtl: false, 1223 | container: 'body', 1224 | containerFluid: false, 1225 | backgroundDismiss: false, 1226 | backgroundDismissAnimation: 'shake', 1227 | autoClose: false, 1228 | closeIcon: null, 1229 | closeIconClass: false, 1230 | watchInterval: 100, 1231 | columnClass: 'col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3 col-xs-10 col-xs-offset-1', 1232 | boxWidth: '50%', 1233 | scrollToPreviousElement: true, 1234 | scrollToPreviousElementAnimate: true, 1235 | useBootstrap: true, 1236 | offsetTop: 50, 1237 | offsetBottom: 50, 1238 | dragWindowGap: 15, 1239 | bootstrapClasses: { 1240 | container: 'container', 1241 | containerFluid: 'container-fluid', 1242 | row: 'row' 1243 | }, 1244 | onContentReady: function () { 1245 | 1246 | }, 1247 | onOpenBefore: function () { 1248 | 1249 | }, 1250 | onOpen: function () { 1251 | 1252 | }, 1253 | onClose: function () { 1254 | 1255 | }, 1256 | onDestroy: function () { 1257 | 1258 | }, 1259 | onAction: function () { 1260 | 1261 | } 1262 | }; 1263 | 1264 | /** 1265 | * This refers to the issue #241 and #246 1266 | * 1267 | * Problem: 1268 | * Button A is clicked (keydown) using the Keyboard ENTER key 1269 | * A opens the jconfirm modal B, 1270 | * B has registered ENTER key for one of its button C 1271 | * A is released (keyup), B gets the keyup event and triggers C. 1272 | * 1273 | * Solution: 1274 | * Register a global keydown event, that tells jconfirm if the keydown originated inside jconfirm 1275 | */ 1276 | var keyDown = false; 1277 | $(window).on('keydown', function (e) { 1278 | if (!keyDown) { 1279 | var $target = $(e.target); 1280 | var pass = false; 1281 | if ($target.closest('.jconfirm-box').length) 1282 | pass = true; 1283 | if (pass) 1284 | $(window).trigger('jcKeyDown'); 1285 | 1286 | keyDown = true; 1287 | } 1288 | }); 1289 | $(window).on('keyup', function (e) { 1290 | keyDown = false; 1291 | }); 1292 | })(jQuery, window); 1293 | -------------------------------------------------------------------------------- /servers/portforward/theme/style.css: -------------------------------------------------------------------------------- 1 | #YVSY * { 2 | font-family: 'Helvetica Neue','Hiragino Sans GB','Helvetica Neue','Hiragino Sans GB','Microsoft YaHei','Open Sans',sans-serif !important; 3 | color: #555; 4 | } 5 | #YVSY a { 6 | text-decoration: none; 7 | } 8 | #YVSY small { 9 | color: #999; 10 | } 11 | #YVSY ul, li { 12 | list-style: none; 13 | } 14 | #YVSY .fa { 15 | font-family: 'FontAwesome' !important; 16 | } 17 | #YVSY .mdi { 18 | font-family: "Material Design Icons" !important; 19 | } 20 | #YVSY .glyphicon { 21 | font-family: 'Glyphicons Halflings', 'Open Sans',sans-serif !important; 22 | } 23 | #YVSY .box { 24 | border: 1px solid #DDD; 25 | display:block; 26 | width:100%; 27 | border-radius: 4px; 28 | padding:20px; 29 | margin-bottom: 16px; 30 | } 31 | #YVSY .box:hover { 32 | border: 1px solid #337ab7; 33 | } 34 | #YVSY .boxTitle { 35 | font-weight:300; 36 | color:#9da2a6; 37 | margin-bottom:4px; 38 | } 39 | #YVSY .boxContent { 40 | color:#363b40; 41 | font-size:26px; 42 | font-weight:500; 43 | line-height:32px; 44 | } 45 | #YVSY .p-0 { 46 | padding: 0 !important; 47 | } 48 | #YVSY .p-20 { 49 | padding: 20px !important; 50 | } 51 | #YVSY .p-30 { 52 | padding: 30px !important; 53 | } 54 | #YVSY .p-l-0 { 55 | padding-left: 0 !important; 56 | } 57 | #YVSY .p-r-0 { 58 | padding-right: 0 !important; 59 | } 60 | #YVSY .p-t-0 { 61 | padding-top: 0 !important; 62 | } 63 | #YVSY .p-b-0 { 64 | padding-bottom: 0 !important; 65 | } 66 | #YVSY .p-t-10 { 67 | padding-top: 10px !important; 68 | } 69 | #YVSY .p-b-10 { 70 | padding-bottom: 10px !important; 71 | } 72 | #YVSY .p-l-r-10 { 73 | padding-left: 10px; 74 | padding-right: 10px; 75 | } 76 | #YVSY .m-0 { 77 | margin: 0 !important; 78 | } 79 | #YVSY .m-r-5 { 80 | margin-right: 5px !important; 81 | } 82 | #YVSY .m-r-10 { 83 | margin-right: 10px !important; 84 | } 85 | #YVSY .m-r-15 { 86 | margin-right: 15px !important; 87 | } 88 | #YVSY .m-l-5 { 89 | margin-left: 5px !important; 90 | } 91 | #YVSY .m-l-10 { 92 | margin-left: 10px !important; 93 | } 94 | #YVSY .m-l-15 { 95 | margin-left: 15px !important; 96 | } 97 | #YVSY .m-t-5 { 98 | margin-top: 5px !important; 99 | } 100 | #YVSY .m-t-0 { 101 | margin-top: 0 !important; 102 | } 103 | #YVSY .m-t-10 { 104 | margin-top: 10px !important; 105 | } 106 | #YVSY .m-t-15 { 107 | margin-top: 15px !important; 108 | } 109 | #YVSY .m-t-20 { 110 | margin-top: 20px !important; 111 | } 112 | #YVSY .m-t-30 { 113 | margin-top: 30px !important; 114 | } 115 | #YVSY .m-t-40 { 116 | margin-top: 40px !important; 117 | } 118 | #YVSY .m-t-50 { 119 | margin-top: 50px !important; 120 | } 121 | #YVSY .m-b-0 { 122 | margin-bottom: 0 !important; 123 | } 124 | #YVSY .m-b-5 { 125 | margin-bottom: 5px !important; 126 | } 127 | #YVSY .m-b-10 { 128 | margin-bottom: 10px !important; 129 | } 130 | #YVSY .m-b-15 { 131 | margin-bottom: 15px !important; 132 | } 133 | #YVSY .m-b-20 { 134 | margin-bottom: 20px !important; 135 | } 136 | #YVSY .m-b-25 { 137 | margin-bottom: 25px !important; 138 | } 139 | #YVSY .m-b-30 { 140 | margin-bottom: 30px !important; 141 | } --------------------------------------------------------------------------------