├── .gitignore ├── LICENSE ├── README.md ├── handlers.js ├── package.json ├── server.js └── tpl ├── auth.html ├── client.js ├── favicon.ico ├── img ├── delete.png ├── edit.png ├── lan.png ├── load.png ├── logout.png ├── logs.png ├── make.png ├── portmap.png ├── reset.png ├── save.png ├── settings.png ├── tcpdump.png ├── ui-bg_flat_0_aaaaaa_40x100.png ├── ui-icons_222222_256x240.png └── ui-icons_454545_256x240.png ├── index.html ├── jquery-ui.css ├── jquery-ui.min.js ├── jquery.min.js ├── styles ├── config.scss └── style.scss ├── template.js ├── theme ├── DarkGray.css ├── Navajo.css └── Silver.css └── tools.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node 3 | 4 | .sass-cache 5 | 6 | ### Node ### 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log* 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | 24 | # nyc test coverage 25 | .nyc_output 26 | 27 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 28 | .grunt 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (http://nodejs.org/api/addons.html) 34 | build/Release 35 | 36 | # Dependency directories 37 | node_modules 38 | jspm_packages 39 | 40 | # Optional npm cache directory 41 | .npm 42 | 43 | # Optional eslint cache 44 | .eslintcache 45 | 46 | # Optional REPL history 47 | .node_repl_history 48 | 49 | # Output of 'npm pack' 50 | *.tgz 51 | 52 | # Yarn Integrity file 53 | .yarn-integrity 54 | 55 | 56 | # End of https://www.gitignore.io/api/node 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | iptables WEB gui 2 | 3 | ![ScreenShot](http://i.mcgl.ru/RGGJv4MAvA) 4 | 5 | ### Howto install ### 6 | 7 | In first time you need to Download and install Node.js 8 | 9 | ### Howto use ### 10 | 11 | * Clone repository: 12 | ```bash 13 | git clone https://github.com/puux/iptables.git 14 | ``` 15 | * Run server: 16 | ```bash 17 | cd iptables 18 | # only for first time you, need to download dependancies 19 | npm install 20 | # and then you can start the server 21 | node server.js 22 | ``` 23 | * Open browser and goto http://127.0.0.1:1337/ 24 | 25 | ### Howto create own theme ### 26 | 27 | * cd ./tpl/styles/ 28 | * open and change config.scss 29 | * compile: scss --sourcemap=none style.scss ../theme/MyTheme.css 30 | * select theme in Settings->Theme 31 | 32 | ### Default user and password ### 33 | 34 | User: admin 35 | Pass: (empty) 36 | 37 | You can change this here https://github.com/puux/iptables/blob/master/handlers.js#L14 38 | -------------------------------------------------------------------------------- /handlers.js: -------------------------------------------------------------------------------- 1 | var proc = require('child_process'); 2 | var fs = require("fs"); 3 | var url = require("url"); 4 | var querystring = require("querystring"); 5 | 6 | module.exports = { 7 | 8 | auth: false, 9 | authUsers: {}, 10 | 11 | settingsDir: "/etc/iptables/config.json", 12 | _settings: { 13 | savePath: "/etc/iptables/rules.save", 14 | user: "admin", 15 | pass: "", 16 | theme: "Silver", 17 | themes: [] 18 | }, 19 | 20 | loadSettings: function() { 21 | fs.exists(this.settingsDir, function(ex){ 22 | if(ex) { 23 | fs.readFile(module.exports.settingsDir, [], function(err, data) { 24 | // Restore new settings after load from file 25 | var s = module.exports._settings; 26 | module.exports._settings = JSON.parse(data); 27 | for(var key in s) { 28 | if(!module.exports._settings[key]) { 29 | module.exports._settings[key] = s[key]; 30 | } 31 | } 32 | module.exports.auth = module.exports._settings.pass === ""; 33 | console.log("Load settings from " + module.exports.settingsDir); 34 | }); 35 | } 36 | }); 37 | }, 38 | 39 | saveSettings: function() { 40 | fs.writeFile(this.settingsDir, JSON.stringify(this._settings), function(err) { 41 | if(err) { 42 | return console.log(err); 43 | } 44 | 45 | console.log("The file was saved!"); 46 | }); 47 | }, 48 | 49 | index: function(req, res) { 50 | fs.readFile('./tpl/index.html', [], function(err, data) { 51 | //res.writeHead(320, {"Content-Type": "text/plain"}); 52 | res.end(data); 53 | }); 54 | }, 55 | 56 | showChannel: function(req, res) { 57 | var query = url.parse(req.url).query; 58 | var args = querystring.parse(query); 59 | 60 | var run = "iptables -t " + args.t + " -S " + args.c.toUpperCase(); 61 | proc.exec(run, function(error, stdout, stderr) { 62 | var arr = stdout.split("\n"); 63 | 64 | res.end(JSON.stringify(arr)); 65 | }); 66 | }, 67 | 68 | deleteRule: function(req, res) { 69 | var query = url.parse(req.url).query; 70 | var args = querystring.parse(query); 71 | 72 | proc.exec("iptables -t " + args.t + " -D " + args.c.toUpperCase() + " " + args.i, function(error, stdout, stderr) { 73 | module.exports.showChannel(req, res); 74 | }); 75 | }, 76 | 77 | insertRule: function (req, res) { 78 | var body = ''; 79 | req.on('data', function (data) { 80 | body += data; 81 | }); 82 | req.on('end', function () { 83 | var post = querystring.parse(body); 84 | 85 | var rule = post['rule']; 86 | console.log(rule); 87 | proc.exec("iptables " + rule, function(error, stdout, stderr) { 88 | if(stderr) { 89 | res.end(stderr); 90 | } 91 | else { 92 | module.exports.showChannel(req, res); 93 | } 94 | }); 95 | }); 96 | }, 97 | 98 | monitor: function(req, res) { 99 | var query = url.parse(req.url).query; 100 | var args = querystring.parse(query); 101 | 102 | var run = "iptables -t " + args.t + " -L " + args.c.toUpperCase() + " -vn"; 103 | proc.exec(run, function(error, stdout, stderr) { 104 | var arr = stdout.split("\n"); 105 | 106 | res.writeHead(200, {"Cache-Control": "no-cache"}); 107 | res.end(JSON.stringify(arr)); 108 | }); 109 | }, 110 | 111 | chainList: function(req, res) { 112 | var new_arr = []; 113 | var n = 0; 114 | 115 | proc.exec("iptables -S", function(error, stdout, stderr) { 116 | var arr = stdout.split("\n"); 117 | 118 | var n = 0; 119 | for(var i = 0; i < arr.length; i++) { 120 | var item = arr[i]; 121 | if(item.indexOf("-N") === 0) { 122 | new_arr[n++] = item.substring(3) + " (filter)"; 123 | } 124 | } 125 | 126 | proc.exec("iptables -t nat -S", function(error, stdout, stderr) { 127 | var arr = stdout.split("\n"); 128 | 129 | for(var i = 0; i < arr.length; i++) { 130 | var item = arr[i]; 131 | if(item.indexOf("-N") === 0) { 132 | new_arr[n++] = item.substring(3) + " (nat)"; 133 | } 134 | } 135 | 136 | proc.exec("iptables -t mangle -S", function(error, stdout, stderr) { 137 | var arr = stdout.split("\n"); 138 | 139 | for(var i = 0; i < arr.length; i++) { 140 | var item = arr[i]; 141 | if(item.indexOf("-N") === 0) { 142 | new_arr[n++] = item.substring(3) + " (mangle)"; 143 | } 144 | } 145 | 146 | res.end(JSON.stringify(new_arr)); 147 | }); 148 | }); 149 | }); 150 | }, 151 | 152 | save: function(req, res) { 153 | proc.exec("iptables-save > " + module.exports._settings.savePath, function(error, stdout, stderr) { 154 | 155 | res.end(stderr); 156 | }); 157 | }, 158 | 159 | load: function(req, res) { 160 | proc.exec("iptables-restore < " + module.exports._settings.savePath, function(error, stdout, stderr) { 161 | 162 | res.end(stderr); 163 | }); 164 | }, 165 | 166 | settings: function(req, res) { 167 | var query = url.parse(req.url).query; 168 | var args = querystring.parse(query); 169 | 170 | if(args.c === "save") { 171 | var body = ''; 172 | req.on('data', function (data) { 173 | body += data; 174 | }); 175 | req.on('end', function () { 176 | var post = querystring.parse(body); 177 | var data = post['data']; 178 | 179 | module.exports._settings = JSON.parse(data); 180 | module.exports.saveSettings(); 181 | }); 182 | res.end(); 183 | } 184 | else { 185 | var themes = []; 186 | var items = fs.readdirSync("./tpl/theme"); 187 | for (var item of items) { 188 | themes.push(item.substring(0, item.length-4)); 189 | } 190 | module.exports._settings.themes = themes; 191 | res.end(JSON.stringify(module.exports._settings)); 192 | } 193 | }, 194 | 195 | authMe: function(req, res) { 196 | var pathname = url.parse(req.url).pathname; 197 | 198 | if(pathname === "/login") { 199 | var body = ''; 200 | req.on('data', function (data) { 201 | body += data; 202 | }); 203 | req.on('end', function () { 204 | var post = querystring.parse(body); 205 | var login = post['login']; 206 | var pass = post['pass']; 207 | 208 | var auth = login === module.exports._settings.user && pass === module.exports._settings.pass; 209 | if(auth) { 210 | var ip = req.connection.remoteAddress; 211 | module.exports.authUsers[ip] = 1; 212 | res.writeHead(301, {"Location": "/"}); 213 | res.end(); 214 | } 215 | else { 216 | res.end("Error!"); 217 | } 218 | }); 219 | } 220 | else { 221 | res.writeHead(301, {"Location": "auth.html", "Cache-Control": "no-cache"}); 222 | res.end(); 223 | } 224 | }, 225 | 226 | isAuth: function(req) { 227 | var ip = req.connection.remoteAddress; 228 | return module.exports.auth || module.exports.authUsers[ip]; 229 | }, 230 | 231 | logout: function(req, res) { 232 | var ip = req.connection.remoteAddress; 233 | module.exports.authUsers[ip] = 0; 234 | res.writeHead(301, {"Location": "auth.html", "Cache-Control": "no-cache"}); 235 | res.end(); 236 | }, 237 | 238 | userList: function(req, res) { 239 | for(var ip in module.exports.authUsers) { 240 | res.write("IP: " + ip + " " + (module.exports.authUsers[ip] ? "auth" : "none")); 241 | } 242 | res.end(); 243 | } 244 | }; 245 | 246 | module.exports.loadSettings(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iptables", 3 | "version": "1.0.0", 4 | "description": "iptables WEB gui ", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/puux/iptables.git" 13 | }, 14 | "keywords": [ 15 | "iptables", 16 | "web", 17 | "gui" 18 | ], 19 | "author": "puux", 20 | "license": "GPL-2.0", 21 | "bugs": { 22 | "url": "https://github.com/puux/iptables/issues" 23 | }, 24 | "homepage": "https://github.com/puux/iptables#readme", 25 | "dependencies": { 26 | "nodejs-websocket": "^1.7.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var handle = require('./handlers'); 3 | var url = require("url"); 4 | var fs = require("fs"); 5 | 6 | var handles = {}; 7 | handles["/"] = handle.index; 8 | handles["/channel"] = handle.showChannel; 9 | handles["/delete"] = handle.deleteRule; 10 | handles["/insert"] = handle.insertRule; 11 | handles["/mon"] = handle.monitor; 12 | handles["/save"] = handle.save; 13 | handles["/load"] = handle.load; 14 | handles["/settings"] = handle.settings; 15 | handles["/chainlist"] = handle.chainList; 16 | handles["/login"] = handle.authMe; 17 | handles["/logout"] = handle.logout; 18 | handles["/users"] = handle.userList; 19 | 20 | http.createServer(function handler(req, res) { 21 | var pathname = url.parse(req.url).pathname; 22 | 23 | req.setEncoding("utf8"); 24 | 25 | if (handles[pathname]) { 26 | if(handle.isAuth(req)) { 27 | handles[pathname](req, res); 28 | } 29 | else { 30 | handle.authMe(req, res); 31 | } 32 | } 33 | else { 34 | var file = "./tpl" + pathname; 35 | 36 | fs.exists(file, function(ex) { 37 | if(ex) { 38 | fs.readFile(file, [], function(err, data) { 39 | //res.writeHead(320, {"Content-Type": "text/plain"}); 40 | res.end(data); 41 | }); 42 | } 43 | else { 44 | console.log("No request handler found for " + pathname); 45 | res.writeHead(404, {"Content-Type": "text/plain"}); 46 | res.write("404 Not found"); 47 | res.end(); 48 | } 49 | }); 50 | } 51 | }).listen(1337); 52 | console.log('Server running at http://*:1337/'); 53 | 54 | 55 | // ------------------ WebSocket ------------------------------------------------ 56 | var proc = require('child_process'); 57 | var ws = require("nodejs-websocket"); 58 | var log = null; 59 | var dump = null; 60 | 61 | function closeLogs() { 62 | if(log) { 63 | log.kill('SIGHUP'); 64 | log = null; 65 | } 66 | } 67 | 68 | function closeDump() { 69 | if(dump) { 70 | dump.kill('SIGHUP'); 71 | dump = null; 72 | } 73 | } 74 | 75 | var server = ws.createServer(function (conn) { 76 | conn.on("text", function (data) { 77 | var params = JSON.parse(data); 78 | if(params.name == "syslog") { 79 | log = proc.spawn("tail", ["-f", "/var/log/syslog"]); 80 | log.stdout.on('data', function (lines) { 81 | var outData = {name: params.name, data: lines.toString().split("\n")}; 82 | if(log) 83 | conn.sendText(JSON.stringify(outData)); 84 | }); 85 | } 86 | else if(params.name == "dump") { 87 | var args = ["-i", params.eth, "-n", "-l"]; 88 | if(params.port) 89 | args.push("port", params.port); 90 | if(params.src) 91 | args.push("src", params.src); 92 | if(params.dst) { 93 | if(params.src) 94 | args.push("or"); 95 | args.push("dst", params.dst); 96 | } 97 | conn.sendText(JSON.stringify({name: params.name, data: ["Exec tcpdump with args: " + args.toString()]})); 98 | dump = proc.spawn("tcpdump", args); 99 | dump.stdout.on('data', function (lines) { 100 | var outData = {name: params.name, data: lines.toString().split("\n")}; 101 | if(dump) 102 | conn.sendText(JSON.stringify(outData)); 103 | }); 104 | } 105 | else if(params.name == "closelog") { 106 | closeLogs(); 107 | } 108 | else if(params.name == "closedump") { 109 | closeDump(); 110 | } 111 | }); 112 | conn.on("close", function (code, reason) { 113 | closeLogs(); 114 | closeDump(); 115 | }); 116 | }).listen(8001); 117 | -------------------------------------------------------------------------------- /tpl/auth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Login 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 |
Login:
Password:
15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /tpl/client.js: -------------------------------------------------------------------------------- 1 | var channel = ""; 2 | var table = ""; 3 | var webSocket; 4 | var chainPath = []; 5 | 6 | $(document).ready(function(){ 7 | rules.showListWithPath("input", "filter"); 8 | 9 | $.get("/chainlist", function(data) { 10 | var arr = JSON.parse(data); 11 | $("#customchains").html(""); 12 | for(var i = 0; i < arr.length; i++) { 13 | var item = arr[i]; 14 | var index = item.indexOf(" "); 15 | var rName = item.substr(0, index); 16 | var rTable = item.substr(index+2, item.length - index - 3); 17 | $("#customchains").append(window.tpl.customChain(rName, rTable)); 18 | } 19 | $("#customchains").append(window.tpl.customChainAddNew); 20 | }); 21 | 22 | setInterval(rules.monitor, 1000); 23 | tools.selectPage(1); 24 | }); 25 | 26 | $(function () { 27 | $('.dropdown').each(function () { 28 | var id = 0; 29 | $(this).parent().eq(0).hoverIntent({ 30 | timeout: 100, 31 | over: function () { 32 | var obj = this; 33 | id = setTimeout(function() { 34 | $('.dropdown:eq(0)', obj).slideDown(100); 35 | }, 500); 36 | }, 37 | out: function () { 38 | clearTimeout(id); 39 | $('.dropdown:eq(0)', this).fadeOut(200); 40 | } 41 | }); 42 | }); 43 | 44 | $('.dropdown').each(function(i, it){ 45 | var list = $(it).find('li'); 46 | if(list.length > 12){ 47 | list.parent().addClass('large'); 48 | list.each(function(index, item){ 49 | if(index >= list.length / 2){ 50 | $(item).addClass('second'); 51 | } 52 | else{ 53 | $(item).addClass('first'); 54 | } 55 | }); 56 | $(it).find('.first').wrapAll('
'); 57 | $(it).find('.second').wrapAll('
'); 58 | } 59 | }); 60 | }); 61 | 62 | var parser = { 63 | 64 | parseChannels: function (data) { 65 | 66 | this.editRuleRow = null; 67 | 68 | var arr = JSON.parse(data); 69 | 70 | $("#main").html(''); 71 | 72 | var index = 0; 73 | for(var line in arr) { 74 | var val = arr[line]; 75 | if(val) { 76 | $("#main").append(parser.makeRuleTpl(index, val)); 77 | } 78 | index++; 79 | } 80 | 81 | $("#main").append('New rule:
'); 82 | }, 83 | 84 | makeRuleTpl: function (index, text) { 85 | var ntext = this.makeRuleText(text); 86 | return tpl.ruleRow(index, ntext); 87 | }, 88 | 89 | FIN_RULES: {DROP:1, ACCEPT:1, LOG:1, TCPMSS:1, RETURN:1, DNAT:1, SNAT:1, MASQUERADE:1, CONNMARK:1, TOS:1, TTL:1}, 90 | makeRuleText: function (text) { 91 | text = text 92 | // strings 93 | .replace(/(--log-prefix) "(.*)"/g, function(str, pref, comment){ 94 | return pref + ' "' + comment + "\""; 95 | }) 96 | // comment 97 | .replace(/(-m comment --comment) "(.*)" (.*)/g, function(str, param, comment, other){ 98 | return other + ' //' + comment + ""; 99 | }) 100 | .replace(/(-m comment --comment) ([\w]+) (.*)/g, function(str, param, comment, other){ 101 | return other + ' //' + comment + ""; 102 | }) 103 | // network interfaces 104 | .replace(/(-[o|i]) ([a-z0-9]+)/g, function(str, dir, int){ 105 | return dir + ' ' + (window._settings.LANS[int] || int) + ''; 106 | }) 107 | // networks 108 | .replace(/(\-d|\-s|\-\-to\-destination) ([0-9\.\/\:]+)/g, '$1 $2') 109 | // ports 110 | .replace(/(--dport|--sport) ([0-9\.\/\:]+)/g, function(str, param, port){ 111 | return param + ' ' + (window._settings.PORTS[port] || port) + ''; 112 | }) 113 | // rule chain 114 | .replace(/-j (ACCEPT|DROP)($| )/g, '-j $1$2') 115 | .replace(/-j ([A-Z\_0-9]+)/g, function(str, name) { 116 | var lname = name.toLowerCase(); 117 | if(parser.FIN_RULES[name]) { 118 | return "-j " + name; 119 | } 120 | return '-j ' + name + ""; 121 | }); 122 | 123 | return text; 124 | }, 125 | 126 | editRuleRow: null, 127 | editRuleRowText: "", 128 | editRuleRowIndex: "", 129 | editRuleAction: function (key) { 130 | if(key === 27) { 131 | if(this.editRuleRow) { 132 | this.editRuleRow.html(this.editRuleRowText); 133 | this.endEditRule(); 134 | } 135 | } 136 | else if(key === 13) { 137 | this.editRuleRow.html(this.makeRuleText(text = this.editRuleRow.children().val())); 138 | this.endEditRule(); 139 | text = text.replace("-A " + channel.toUpperCase(), "-R " + channel.toUpperCase() + " " + this.editRuleRowIndex); 140 | rules.insertText(text); 141 | } 142 | }, 143 | 144 | editRule: function (index) { 145 | var rule = $("#rule" + index); 146 | if(this.editRuleRow === null || rule.attr("id") !== this.editRuleRow.attr("id")) { 147 | if(this.editRuleRow) { 148 | this.editRuleRow.html(this.editRuleRowText); 149 | } 150 | var value = rule.text(); 151 | this.editRuleRowText = rule.html(); 152 | rule.html('').children().val(value); 153 | rule.children().focus(); 154 | 155 | this.editRuleRow = rule; 156 | this.editRuleRowIndex = index; 157 | } 158 | }, 159 | 160 | endEditRule: function() { 161 | this.editRuleRow = null; 162 | } 163 | 164 | }; 165 | 166 | var rules = { 167 | showList: function (name, chainTable) { 168 | channel = name; 169 | table = chainTable; 170 | 171 | $(".itemselect").removeClass("itemselect").addClass("item"); 172 | $(".item").each(function(index, obj) { 173 | if($(obj).text() === name.toUpperCase()) { 174 | $(obj).removeClass("item").addClass("itemselect"); 175 | } 176 | }); 177 | 178 | parser.endEditRule(); 179 | $.get("channel?c=" + channel + "&t=" + table, parser.parseChannels); 180 | }, 181 | 182 | showListWithPath: function (name, chainTable, addPath) { 183 | rules.showList(name, chainTable); 184 | 185 | var obj = {chain: name.toUpperCase(), table: chainTable}; 186 | if(addPath) { 187 | chainPath.push(obj); 188 | } 189 | else { 190 | chainPath = [obj]; 191 | } 192 | 193 | rules.updatePath(); 194 | }, 195 | 196 | updatePath: function() { 197 | var code = ""; 198 | for(var o of chainPath) { 199 | if(code) code += " / "; 200 | code += '' + o.chain + (code ? "" : "[" + o.table + "]") + ""; 201 | } 202 | tools.setChainPath(code); 203 | }, 204 | 205 | showBackPath: function (name) { 206 | var index = 0; 207 | for(var o of chainPath) { 208 | index++; 209 | if(o.chain == name) { 210 | chainPath = chainPath.slice(0, index); 211 | rules.showList(o.chain, o.table); 212 | break; 213 | } 214 | } 215 | rules.updatePath(); 216 | }, 217 | 218 | remove: function (index) { 219 | $.get("delete?i=" + index + "&c=" + channel + "&t=" + table, parser.parseChannels); 220 | return false; 221 | }, 222 | 223 | insert: function () { 224 | this.insertText($("#rule").val()); 225 | 226 | return false; 227 | }, 228 | 229 | insertText: function (text) { 230 | if(text.search(/-[A|I|R]/g) === -1) { 231 | text = "-A " + channel.toLocaleUpperCase() + " " + text ; 232 | } 233 | 234 | text = "-t " + table + " " + text; 235 | 236 | for(var lan in window._settings.LANS) { 237 | text = text.replace(new RegExp("(-[o|i]) " + window._settings.LANS[lan] + " ", 'g'), function(str, dir, int){ 238 | return dir + " " + lan + " "; 239 | }); 240 | } 241 | for(var port in window._settings.PORTS) { 242 | text = text.replace(new RegExp("(--dport|--sport) " + window._settings.PORTS[port] + " ", 'g'), function(str, dir, _port){ 243 | return dir + " " + port + " "; 244 | }); 245 | } 246 | 247 | text = text.replace(/\/\/(.*)/g, '-m comment --comment "$1"'); 248 | 249 | $.post("insert?c=" + channel + "&t=" + table, {rule: text}, function(data){ 250 | if(data) { 251 | if(data.substr(0, 1) === "[") { 252 | parser.parseChannels(data); 253 | } 254 | else { 255 | showError(data); 256 | } 257 | } 258 | }); 259 | 260 | return false; 261 | }, 262 | 263 | monitor: function() { 264 | $.get("/mon?c=" + channel + "&t=" + table, function(data){ 265 | var arr = JSON.parse(data); 266 | var index = 0; 267 | for(var i = 0; i < arr.length; i++) { 268 | var items = arr[i].trim().replace(/[ ]+/g, ' ').split(" "); 269 | 270 | if(i === 0) { 271 | pkts = 4; 272 | bytes = 6; 273 | } 274 | else { 275 | pkts = 0; 276 | bytes = 1; 277 | } 278 | 279 | $("#pkts" + index).html(items[pkts]); 280 | $("#bytes" + index).html(items[bytes]); 281 | if(i !== 1) { 282 | index++; 283 | } 284 | } 285 | }); 286 | }, 287 | 288 | addChainName: function(name, _table) { 289 | channel = name; 290 | table = _table; 291 | $.post("insert?c=" + name + "&t=" + table, {rule: "-t " + table + " -N " + name.toUpperCase()}, function(data){ 292 | if(data) { 293 | if(data.substr(0, 1) === "[") { 294 | parser.parseChannels(data); 295 | //$(".dropdown").append(window.tpl.customChain(name.toUpperCase())); 296 | $(window.tpl.customChain(name.toUpperCase(), _table)).prependTo(".newchain"); 297 | } 298 | else { 299 | showError(data); 300 | } 301 | } 302 | }); 303 | }, 304 | 305 | addChain: function() { 306 | $(".addchain").dialog({ 307 | title:"Create new chain", 308 | modal:true, 309 | resizable:false, 310 | width: 400, 311 | buttons: [ 312 | { 313 | text: "Create", 314 | click: function() { 315 | rules.addChainName($("#chainname").val(), $("#chaintable").val()); 316 | $(".addchain").dialog("close"); 317 | } 318 | } 319 | ] 320 | }); 321 | }, 322 | 323 | removeChain: function(obj) { 324 | var rName = $(obj).attr("chainname"); 325 | var rTable = $(obj).attr("chaintable"); 326 | 327 | $.post("insert?t=" + rTable + "&c=" + rName, {rule: "-t " + rTable + " -X " + rName.toUpperCase()}, function(data){ 328 | if(data) { 329 | if(data.substr(0, 1) === "[") { 330 | parser.parseChannels(data); 331 | $(obj).parent().parent().remove(); 332 | } 333 | else { 334 | showError(data); 335 | } 336 | } 337 | }); 338 | }, 339 | 340 | resetCounters: function() { 341 | $.post("insert?t=" + table + "&c=" + channel, {rule: "-t " + table + " -Z " + channel.toUpperCase()}, function(data){ 342 | if(data) { 343 | if(data.substr(0, 1) === "[") { 344 | parser.parseChannels(data); 345 | } 346 | else { 347 | showError(data); 348 | } 349 | } 350 | }); 351 | } 352 | }; 353 | 354 | var tools = { 355 | pageIndex: 1, 356 | 357 | save: function() { 358 | $.get("/save", function(data) { 359 | if(data) { 360 | showError(data); 361 | } 362 | else { 363 | showInfo("Save complite!"); 364 | } 365 | }); 366 | }, 367 | 368 | load: function() { 369 | $.get("/load", function(data) { 370 | if(data) { 371 | showError(data); 372 | } 373 | else { 374 | showInfo("Load complite!"); 375 | rules.showList(channel, table); 376 | } 377 | }); 378 | }, 379 | 380 | oldIndex: -1, 381 | selectPage: function(index) { 382 | $("#settings-page" + tools.pageIndex).hide(); 383 | tools.pageIndex = index; 384 | $("#settings-page" + index).show(); 385 | if(tools.oldIndex !== -1) { 386 | $("#page" + tools.oldIndex).removeClass("itemselected").addClass("item"); 387 | } 388 | $("#page" + index).removeClass("item").addClass("itemselected"); 389 | tools.oldIndex = index; 390 | }, 391 | 392 | addLan: function() { 393 | $("#lans").append(window.tpl.settingsLan("", "")); 394 | }, 395 | 396 | removeLan: function(obj) { 397 | $(obj).parent().parent().remove(); 398 | }, 399 | 400 | addPort: function() { 401 | $("#ports").append(window.tpl.settingsPort("", "")); 402 | }, 403 | 404 | settingsDlg: function() { 405 | $(".settings").dialog({ 406 | title:"Iptables settings", 407 | modal:true, 408 | resizable:false, 409 | width: 600, 410 | buttons: [ 411 | { 412 | text: "Save", 413 | click: function() { 414 | $(".param").each(function(index, obj){ 415 | window._settings[obj.id] = $(obj).val(); 416 | }); 417 | window._settings.LANS = {}; 418 | $(".lan").each(function(index, obj){ 419 | window._settings.LANS[$(obj).children()[0].firstChild.value] = $(obj).children()[1].firstChild.value; 420 | }); 421 | window._settings.PORTS = {}; 422 | $(".port").each(function(index, obj){ 423 | window._settings.PORTS[$(obj).children()[0].firstChild.value] = $(obj).children()[1].firstChild.value; 424 | }); 425 | $.post("/settings?c=save", {data: JSON.stringify(window._settings)}, function(data) { 426 | if(data) { 427 | showError(data); 428 | } 429 | }); 430 | $(".settings").dialog("close"); 431 | 432 | rules.showList(channel, table); 433 | } 434 | } 435 | ] 436 | }); 437 | }, 438 | 439 | ruleBuilder: { 440 | new_proto: { def: "none", pref: " -p ", name: "Proto", list: ["none", "TCP", "UDP", "ICMP", "GRE"] }, 441 | new_in: { def: "", pref: " -i ", name: "Input", hint: "eth0" }, 442 | new_out: { def: "", pref: " -o ", name: "Output", hint: "wlan0" }, 443 | new_dest: { def: "", pref: " -d ", name: "Dest", hint: "8.8.0.0/16", pdef: true, sub: { new_dst_port_from: { def: "", pref: " --dport ", name: "from", size: 40, sub: { new_dst_port_to: { def: "", pref: ":", name: "to", size: 40 } } } } }, 444 | new_src: { def: "", pref: " -s ", name: "Source", hint: "10.10.0.0/16", pdef: true, sub: { new_src_port_from: { def: "", pref: " --sport ", name: "from", size: 40, sub: { new_src_port_to: { def: "", pref: ":", name: "to", size: 40 } } } } }, 445 | new_state: { def: "none", pref: " -m state --state ", name: "State", list: ["none", "NEW", "ESTABLISHED", "RELATED", "INVALID"] }, 446 | new_limit: { def: "", pref: " -m limit --limit ", name: "Limit" }, 447 | new_action: { def: "", pref: " -j ", name: "Action", list: ["ACCEPT", "DROP", "DNAT", "SNAT", "MARK", "LOG", "MASQUERADE", "MIRROR", "REDIRECT", "RETURN", "TOS", "TTL"], 448 | asvalue: { 449 | DNAT: { new_to_destination: { def: "", pref: " --to-destination ", name: "destination"} }, 450 | SNAT: { new_to_source: { def: "", pref: " --to-source ", name: "source"} }, 451 | MARK: { new_set_mark: { def: "", pref: " --set-mark ", name: "mark"} }, 452 | REDIRECT: { new_to_ports: { def: "", pref: " --to-ports ", name: "to ports"} }, 453 | TOS: { new_tos: { def: "", pref: " --set-tos ", name: "tos"} }, 454 | TTL: { new_ttl: { def: "", pref: " --ttl-set ", name: "ttl"} }, 455 | LOG: { 456 | new_log_prefix: { def: "", pref: " --log-prefix \"", suff: "\"", name: "prefix", size: 60}, 457 | new_log_level: { def: "", pref: " --log-level ", name: "level", size: 40} 458 | } 459 | } 460 | } 461 | }, 462 | 463 | makeTextField: function(name, rule) { 464 | var value = ''; 488 | for(var item in obj.list) { 489 | value += ''; 490 | } 491 | value += ''; 492 | if(obj.asvalue) { 493 | value += ' '; 494 | } 495 | } 496 | else { 497 | value = tools.makeTextField(rule, obj); 498 | } 499 | text += '' + obj.name + '' + value + ''; 500 | } 501 | $("#ruleTable").html(text); 502 | 503 | $("#makeRule").dialog({ 504 | title:"Make rule", 505 | modal:true, 506 | resizable:false, 507 | width: 500, 508 | buttons: [ 509 | { 510 | text: "Add", 511 | click: function() { 512 | var maker = function(rules) { 513 | var rule = ""; 514 | for(var field in rules) { 515 | var obj = rules[field]; 516 | var value = $("#" + field).val(); 517 | if(value !== obj.def) { 518 | rule += obj.pref + value; 519 | if(obj.suff) { 520 | rule += obj.suff; 521 | } 522 | if(obj.asvalue) { 523 | rule += maker(obj.asvalue[value]); 524 | } 525 | } 526 | if(obj.sub && (obj.pdef || value !== obj.def)) { 527 | rule += maker(obj.sub); 528 | } 529 | } 530 | return rule; 531 | }; 532 | 533 | var rule = maker(tools.ruleBuilder); 534 | $("#rule").val(rule); 535 | 536 | $("#makeRule").dialog("close"); 537 | } 538 | }, 539 | { 540 | text: "Reset", 541 | click: function() { 542 | var reset = function(rules) { 543 | for(var field in rules) { 544 | var obj = rules[field]; 545 | $("#" + field).val(obj.def); 546 | if(obj.sub) { 547 | reset(obj.sub); 548 | } 549 | if(obj.asvalue) { 550 | $("#" + field).change(); 551 | for(var field2 in obj.asvalue) { 552 | reset(obj.asvalue[field2]); 553 | } 554 | } 555 | } 556 | }; 557 | reset(tools.ruleBuilder); 558 | } 559 | } 560 | ] 561 | }); 562 | }, 563 | 564 | setAction: function(obj) { 565 | var id = obj.id; 566 | if($("#" + id + "_sub").size() !== 0) { 567 | var text = ""; 568 | for(var field in tools.ruleBuilder[id].asvalue[$("#" + id).val()]) { 569 | var obj = tools.ruleBuilder[id].asvalue[$("#" + id).val()][field]; 570 | text += " " + obj.name + " " + tools.makeTextField(field, obj); 571 | } 572 | $("#" + id + "_sub").html(text); 573 | } 574 | }, 575 | 576 | initWS: function(hello) { 577 | if(!webSocket) { 578 | var addr = window.location.toString().substr(7); 579 | addr = addr.substr(0, addr.indexOf(":")); 580 | addr = "ws://" + addr + ":8001"; 581 | 582 | webSocket = new WebSocket(addr); 583 | webSocket.onopen = function(event) { 584 | webSocket.send(hello); 585 | }; 586 | 587 | webSocket.onmessage = function(event) { 588 | var channel = JSON.parse(event.data); 589 | if(channel.name == "syslog") { 590 | for(var i = 0; i < channel.data.length; i++) { 591 | if(channel.data[i]) { 592 | $("#logs").append('
' + channel.data[i] + '
'); 593 | } 594 | } 595 | $("#logs").parent().scrollTop(64536); 596 | } 597 | else if(channel.name == "dump") { 598 | for(var i = 0; i < channel.data.length; i++) { 599 | if(channel.data[i]) { 600 | var text = channel.data[i].replace(/IP ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/g, function(str, ip){ 601 | return '' + ip + ""; 602 | }).replace(/> ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/g, function(str, ip){ 603 | return '> ' + ip + ""; 604 | }); 605 | $("#dump").append('
' + text + '
'); 606 | } 607 | } 608 | $("#dump").scrollTop(64536); 609 | } 610 | }; 611 | 612 | webSocket.onclose = function(event) { 613 | webSocket = null; 614 | }; 615 | } 616 | else { 617 | webSocket.send(hello); 618 | } 619 | }, 620 | 621 | closeWS: function(name){ 622 | if(webSocket) { 623 | webSocket.send(name); 624 | } 625 | }, 626 | 627 | showLogs: function() { 628 | $("#syslog").dialog({ 629 | title:"System logs", 630 | modal:false, 631 | resizable:true, 632 | width: 800, 633 | height: 400 634 | }).on('dialogclose', function(event) { 635 | tools.closeWS(JSON.stringify({name: "closelog"})); 636 | }); 637 | tools.initWS(JSON.stringify({name: "syslog"})); 638 | }, 639 | 640 | showTCPDump: function() { 641 | $("#tcpdump").dialog({ 642 | title:"TCP dump", 643 | modal:false, 644 | resizable:true, 645 | width: 800, 646 | height: 400 647 | }).on('dialogclose', function(event) { 648 | tools.closeWS(JSON.stringify({name: "closedump"})); 649 | $("#dump").html(""); 650 | }); 651 | }, 652 | 653 | dumpParams: function() { 654 | $("#dump").html(""); 655 | tools.closeWS(JSON.stringify({name: "closedump"})); 656 | tools.initWS(JSON.stringify({name: "dump", eth: $("#eth").val(), src: $("#src").val(), dst: $("#dst").val(), port: $("#port").val()})); 657 | }, 658 | 659 | setChainPath: function(path) { 660 | $("#chainpath").html(path); 661 | } 662 | }; -------------------------------------------------------------------------------- /tpl/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/favicon.ico -------------------------------------------------------------------------------- /tpl/img/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/delete.png -------------------------------------------------------------------------------- /tpl/img/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/edit.png -------------------------------------------------------------------------------- /tpl/img/lan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/lan.png -------------------------------------------------------------------------------- /tpl/img/load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/load.png -------------------------------------------------------------------------------- /tpl/img/logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/logout.png -------------------------------------------------------------------------------- /tpl/img/logs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/logs.png -------------------------------------------------------------------------------- /tpl/img/make.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/make.png -------------------------------------------------------------------------------- /tpl/img/portmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/portmap.png -------------------------------------------------------------------------------- /tpl/img/reset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/reset.png -------------------------------------------------------------------------------- /tpl/img/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/save.png -------------------------------------------------------------------------------- /tpl/img/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/settings.png -------------------------------------------------------------------------------- /tpl/img/tcpdump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/tcpdump.png -------------------------------------------------------------------------------- /tpl/img/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /tpl/img/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /tpl/img/ui-icons_454545_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/puux/iptables/74b47195a8ba51663e1a6d0eee7f3b37fe580e5e/tpl/img/ui-icons_454545_256x240.png -------------------------------------------------------------------------------- /tpl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | iptables 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 |
26 | 70 | 71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 |
IDpktsbytesRULECMD
81 | 82 |
83 | 84 | TcpDump 85 | SysLogs 86 | Load 87 | Save 88 | Settings 89 | Reset 90 |
91 | 92 |
93 |
94 |
Global
95 |
Networks map
96 |
Ports map
97 |
98 |
99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 |
Paths
Save rule path
Appearance
Theme
Security
Login
Password
116 |
117 | 123 | 129 |
130 | 131 |
132 |
133 | 134 | 135 | 136 |
Name:
Table:
137 |
138 |
139 |
140 | 141 |
142 |
143 |
144 |
145 | 146 |
147 |
148 |
149 |
150 |
151 | Dev: 152 | 153 | Src: 154 | 155 | Dest: 156 | 157 | Port: 158 | 159 | 160 | 161 |
162 |
163 | 164 |
165 |
166 |
167 |
168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /tpl/jquery-ui.css: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery UI CSS Framework @VERSION 3 | * 4 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 5 | * Dual licensed under the MIT or GPL Version 2 licenses. 6 | * http://jquery.org/license 7 | * 8 | * http://docs.jquery.com/UI/Theming/API 9 | */ 10 | 11 | /* Layout helpers 12 | ----------------------------------*/ 13 | .ui-helper-hidden { display: none; } 14 | .ui-helper-hidden-accessible { position: absolute; left: -99999999px; } 15 | .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } 16 | .ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } 17 | .ui-helper-clearfix { display: inline-block; } 18 | /* required comment for clearfix to work in Opera \*/ 19 | * html .ui-helper-clearfix { height:1%; } 20 | .ui-helper-clearfix { display:block; } 21 | /* end clearfix */ 22 | .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } 23 | 24 | 25 | /* Interaction Cues 26 | ----------------------------------*/ 27 | .ui-state-disabled { cursor: default !important; } 28 | 29 | 30 | /* Icons 31 | ----------------------------------*/ 32 | 33 | /* states and images */ 34 | .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } 35 | 36 | 37 | /* Misc visuals 38 | ----------------------------------*/ 39 | 40 | /* Overlays */ 41 | .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } 42 | /* 43 | * jQuery UI Accordion @VERSION 44 | * 45 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 46 | * Dual licensed under the MIT or GPL Version 2 licenses. 47 | * http://jquery.org/license 48 | * 49 | * http://docs.jquery.com/UI/Accordion#theming 50 | */ 51 | /* IE/Win - Fix animation bug - #4615 */ 52 | .ui-accordion { width: 100%; } 53 | .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } 54 | .ui-accordion .ui-accordion-li-fix { display: inline; } 55 | .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } 56 | .ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } 57 | .ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } 58 | .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } 59 | .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } 60 | .ui-accordion .ui-accordion-content-active { display: block; }/* 61 | * jQuery UI Autocomplete @VERSION 62 | * 63 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 64 | * Dual licensed under the MIT or GPL Version 2 licenses. 65 | * http://jquery.org/license 66 | * 67 | * http://docs.jquery.com/UI/Autocomplete#theming 68 | */ 69 | .ui-autocomplete { position: absolute; cursor: default; } 70 | 71 | /* workarounds */ 72 | * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ 73 | 74 | /* 75 | * jQuery UI Menu @VERSION 76 | * 77 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 78 | * Dual licensed under the MIT or GPL Version 2 licenses. 79 | * http://jquery.org/license 80 | * 81 | * http://docs.jquery.com/UI/Menu#theming 82 | */ 83 | .ui-menu { 84 | list-style:none; 85 | padding: 2px; 86 | margin: 0; 87 | display:block; 88 | float: left; 89 | } 90 | .ui-menu .ui-menu { 91 | margin-top: -3px; 92 | } 93 | .ui-menu .ui-menu-item { 94 | margin:0; 95 | padding: 0; 96 | zoom: 1; 97 | float: left; 98 | clear: left; 99 | width: 100%; 100 | } 101 | .ui-menu .ui-menu-item a { 102 | text-decoration:none; 103 | display:block; 104 | padding:.2em .4em; 105 | line-height:1.5; 106 | zoom:1; 107 | } 108 | .ui-menu .ui-menu-item a.ui-state-hover, 109 | .ui-menu .ui-menu-item a.ui-state-active { 110 | font-weight: normal; 111 | margin: -1px; 112 | } 113 | /* 114 | * jQuery UI Button @VERSION 115 | * 116 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 117 | * Dual licensed under the MIT or GPL Version 2 licenses. 118 | * http://jquery.org/license 119 | * 120 | * http://docs.jquery.com/UI/Button#theming 121 | */ 122 | .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ 123 | .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ 124 | button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ 125 | .ui-button-icons-only { width: 3.4em; } 126 | button.ui-button-icons-only { width: 3.7em; } 127 | 128 | /*button text element */ 129 | .ui-button .ui-button-text { display: block; line-height: 1.4; } 130 | .ui-button-text-only .ui-button-text { padding: .4em 1em; } 131 | .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } 132 | .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } 133 | .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } 134 | .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } 135 | /* no icon support for input elements, provide padding by default */ 136 | input.ui-button { padding: .4em 1em; } 137 | 138 | /*button icon element(s) */ 139 | .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } 140 | .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } 141 | .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } 142 | .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } 143 | .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } 144 | 145 | /*button sets*/ 146 | .ui-buttonset { margin-right: 7px; } 147 | .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } 148 | 149 | /* workarounds */ 150 | button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ 151 | /* 152 | * jQuery UI Datepicker @VERSION 153 | * 154 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 155 | * Dual licensed under the MIT or GPL Version 2 licenses. 156 | * http://jquery.org/license 157 | * 158 | * http://docs.jquery.com/UI/Datepicker#theming 159 | */ 160 | .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } 161 | .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } 162 | .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } 163 | .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } 164 | .ui-datepicker .ui-datepicker-prev { left:2px; } 165 | .ui-datepicker .ui-datepicker-next { right:2px; } 166 | .ui-datepicker .ui-datepicker-prev-hover { left:1px; } 167 | .ui-datepicker .ui-datepicker-next-hover { right:1px; } 168 | .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } 169 | .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } 170 | .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } 171 | .ui-datepicker select.ui-datepicker-month-year {width: 100%;} 172 | .ui-datepicker select.ui-datepicker-month, 173 | .ui-datepicker select.ui-datepicker-year { width: 49%;} 174 | .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } 175 | .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } 176 | .ui-datepicker td { border: 0; padding: 1px; } 177 | .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } 178 | .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } 179 | .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } 180 | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } 181 | 182 | /* with multiple calendars */ 183 | .ui-datepicker.ui-datepicker-multi { width:auto; } 184 | .ui-datepicker-multi .ui-datepicker-group { float:left; } 185 | .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } 186 | .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } 187 | .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } 188 | .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } 189 | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } 190 | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } 191 | .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } 192 | .ui-datepicker-row-break { clear:both; width:100%; } 193 | 194 | /* RTL support */ 195 | .ui-datepicker-rtl { direction: rtl; } 196 | .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } 197 | .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } 198 | .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } 199 | .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } 200 | .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } 201 | .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } 202 | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } 203 | .ui-datepicker-rtl .ui-datepicker-group { float:right; } 204 | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } 205 | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } 206 | 207 | /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ 208 | .ui-datepicker-cover { 209 | display: none; /*sorry for IE5*/ 210 | display/**/: block; /*sorry for IE5*/ 211 | position: absolute; /*must have*/ 212 | z-index: -1; /*must have*/ 213 | filter: mask(); /*must have*/ 214 | top: -4px; /*must have*/ 215 | left: -4px; /*must have*/ 216 | width: 200px; /*must have*/ 217 | height: 200px; /*must have*/ 218 | }/* 219 | * jQuery UI Dialog @VERSION 220 | * 221 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 222 | * Dual licensed under the MIT or GPL Version 2 licenses. 223 | * http://jquery.org/license 224 | * 225 | * http://docs.jquery.com/UI/Dialog#theming 226 | */ 227 | .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; box-shadow: 5px 5px 10px #000000; } 228 | .ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; } 229 | .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } 230 | .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } 231 | .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } 232 | .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } 233 | .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } 234 | .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } 235 | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } 236 | .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } 237 | .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } 238 | .ui-draggable .ui-dialog-titlebar { cursor: move; } 239 | /* 240 | * jQuery UI Progressbar @VERSION 241 | * 242 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 243 | * Dual licensed under the MIT or GPL Version 2 licenses. 244 | * http://jquery.org/license 245 | * 246 | * http://docs.jquery.com/UI/Progressbar#theming 247 | */ 248 | .ui-progressbar { height:2em; text-align: left; } 249 | .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/* 250 | * jQuery UI Resizable @VERSION 251 | * 252 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 253 | * Dual licensed under the MIT or GPL Version 2 licenses. 254 | * http://jquery.org/license 255 | * 256 | * http://docs.jquery.com/UI/Resizable#theming 257 | */ 258 | .ui-resizable { position: relative;} 259 | .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} 260 | .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } 261 | .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } 262 | .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } 263 | .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } 264 | .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } 265 | .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } 266 | .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } 267 | .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } 268 | .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* 269 | * jQuery UI Selectable @VERSION 270 | * 271 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 272 | * Dual licensed under the MIT or GPL Version 2 licenses. 273 | * http://jquery.org/license 274 | * 275 | * http://docs.jquery.com/UI/Selectable#theming 276 | */ 277 | .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } 278 | /* 279 | * jQuery UI Slider @VERSION 280 | * 281 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 282 | * Dual licensed under the MIT or GPL Version 2 licenses. 283 | * http://jquery.org/license 284 | * 285 | * http://docs.jquery.com/UI/Slider#theming 286 | */ 287 | .ui-slider { position: relative; text-align: left; } 288 | .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } 289 | .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } 290 | 291 | .ui-slider-horizontal { height: .8em; } 292 | .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } 293 | .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } 294 | .ui-slider-horizontal .ui-slider-range-min { left: 0; } 295 | .ui-slider-horizontal .ui-slider-range-max { right: 0; } 296 | 297 | .ui-slider-vertical { width: .8em; height: 100px; } 298 | .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } 299 | .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } 300 | .ui-slider-vertical .ui-slider-range-min { bottom: 0; } 301 | .ui-slider-vertical .ui-slider-range-max { top: 0; }/* 302 | * jQuery UI Tabs @VERSION 303 | * 304 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 305 | * Dual licensed under the MIT or GPL Version 2 licenses. 306 | * http://jquery.org/license 307 | * 308 | * http://docs.jquery.com/UI/Tabs#theming 309 | */ 310 | .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ 311 | .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } 312 | .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } 313 | .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } 314 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } 315 | .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } 316 | .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ 317 | .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } 318 | .ui-tabs .ui-tabs-hide { display: none !important; } 319 | /* 320 | * jQuery UI CSS Framework @VERSION 321 | * 322 | * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) 323 | * Dual licensed under the MIT or GPL Version 2 licenses. 324 | * http://jquery.org/license 325 | * 326 | * http://docs.jquery.com/UI/Theming/API 327 | * 328 | * To view and modify this theme, visit http://jqueryui.com/themeroller/ 329 | */ 330 | 331 | 332 | /* Component containers 333 | ----------------------------------*/ 334 | .ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } 335 | .ui-widget .ui-widget { font-size: 1em; } 336 | .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } 337 | .ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #222/*{bgColorContent}*/; color: white/*{fcContent}*/; } 338 | .ui-widget-content a { color: white/*{fcContent}*/; } 339 | /*.ui-widget-header { border: 1px solid #aaaaaa{borderColorHeader}; background: #cccccc{bgColorHeader} url(img/ui-bg_highlight-soft_75_cccccc_1x100.png){bgImgUrlHeader} 50%{bgHeaderXPos} 50%{bgHeaderYPos} repeat-x{bgHeaderRepeat}; color: black{fcHeader}; font-weight: bold; }*/ 340 | .ui-widget-header { 341 | font-weight: bold; 342 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#555), to(#333)); 343 | background: -moz-linear-gradient(top, #555, #333); 344 | background-image: -o-linear-gradient(top, #555, #333); 345 | background: -ms-linear-gradient(top, #555, #333); 346 | } 347 | .ui-widget-header a { color: white/*{fcHeader}*/; } 348 | 349 | /* Interaction states 350 | ----------------------------------*/ 351 | /*.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3{borderColorDefault}; background: #e6e6e6{bgColorDefault} url(img/ui-bg_glass_75_e6e6e6_1x400.png){bgImgUrlDefault} 50%{bgDefaultXPos} 50%{bgDefaultYPos} repeat-x{bgDefaultRepeat}; font-weight: normal{fwDefault}; color: #555555{fcDefault}; }*/ 352 | .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { 353 | border: 1px solid gray; color: white; text-decoration: none; float:right; cursor: pointer; border-radius: 5px; 354 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#333), to(#222)); 355 | background: -moz-linear-gradient(top, #333, #222); 356 | background-image: -o-linear-gradient(top, #333, #222); 357 | background: -ms-linear-gradient(top, #333, #222); 358 | border: 1px solid #444; 359 | box-shadow: 0 0 5px #000; 360 | } 361 | .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; } 362 | /*.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999{borderColorHover}; background: #dadada{bgColorHover} url(img/ui-bg_glass_75_dadada_1x400.png){bgImgUrlHover} 50%{bgHoverXPos} 50%{bgHoverYPos} repeat-x{bgHoverRepeat}; font-weight: normal{fwDefault}; color: #212121{fcHover}; }*/ 363 | .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { 364 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#333)); 365 | background: -moz-linear-gradient(top, #444, #333); 366 | background-image: -o-linear-gradient(top, #444, #333); 367 | background: -ms-linear-gradient(top, #444, #333); 368 | border: 1px solid #444; 369 | box-shadow: 0 0 5px #000; 370 | } 371 | .ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; } 372 | /*.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa{borderColorActive}; background: #ffffff{bgColorActive} url(img/ui-bg_glass_65_ffffff_1x400.png){bgImgUrlActive} 50%{bgActiveXPos} 50%{bgActiveYPos} repeat-x{bgActiveRepeat}; font-weight: normal{fwDefault}; color: #212121{fcActive}; }*/ 373 | .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { 374 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#333)); 375 | background: -moz-linear-gradient(top, #444, #333); 376 | background-image: -o-linear-gradient(top, #444, #333); 377 | background: -ms-linear-gradient(top, #444, #333); 378 | border: 1px solid #444; 379 | box-shadow: 0 0 5px #000; 380 | } 381 | .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; } 382 | .ui-widget :active { outline: none; } 383 | 384 | /* Interaction Cues 385 | ----------------------------------*/ 386 | .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(img/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } 387 | .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } 388 | .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(img/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } 389 | .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; } 390 | .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } 391 | .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } 392 | .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } 393 | .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } 394 | 395 | /* Icons 396 | ----------------------------------*/ 397 | 398 | /* states and images */ 399 | .ui-icon { width: 16px; height: 16px; background-image: url(img/ui-icons_222222_256x240.png)/*{iconsContent}*/; } 400 | .ui-widget-content .ui-icon {background-image: url(img/ui-icons_222222_256x240.png)/*{iconsContent}*/; } 401 | .ui-widget-header .ui-icon {background-image: url(img/ui-icons_222222_256x240.png)/*{iconsHeader}*/; } 402 | .ui-state-default .ui-icon { background-image: url(img/ui-icons_888888_256x240.png)/*{iconsDefault}*/; } 403 | .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(img/ui-icons_454545_256x240.png)/*{iconsHover}*/; } 404 | .ui-state-active .ui-icon {background-image: url(img/ui-icons_454545_256x240.png)/*{iconsActive}*/; } 405 | .ui-state-highlight .ui-icon {background-image: url(img/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; } 406 | .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(img/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; } 407 | 408 | /* positioning */ 409 | .ui-icon-carat-1-n { background-position: 0 0; } 410 | .ui-icon-carat-1-ne { background-position: -16px 0; } 411 | .ui-icon-carat-1-e { background-position: -32px 0; } 412 | .ui-icon-carat-1-se { background-position: -48px 0; } 413 | .ui-icon-carat-1-s { background-position: -64px 0; } 414 | .ui-icon-carat-1-sw { background-position: -80px 0; } 415 | .ui-icon-carat-1-w { background-position: -96px 0; } 416 | .ui-icon-carat-1-nw { background-position: -112px 0; } 417 | .ui-icon-carat-2-n-s { background-position: -128px 0; } 418 | .ui-icon-carat-2-e-w { background-position: -144px 0; } 419 | .ui-icon-triangle-1-n { background-position: 0 -16px; } 420 | .ui-icon-triangle-1-ne { background-position: -16px -16px; } 421 | .ui-icon-triangle-1-e { background-position: -32px -16px; } 422 | .ui-icon-triangle-1-se { background-position: -48px -16px; } 423 | .ui-icon-triangle-1-s { background-position: -64px -16px; } 424 | .ui-icon-triangle-1-sw { background-position: -80px -16px; } 425 | .ui-icon-triangle-1-w { background-position: -96px -16px; } 426 | .ui-icon-triangle-1-nw { background-position: -112px -16px; } 427 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } 428 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } 429 | .ui-icon-arrow-1-n { background-position: 0 -32px; } 430 | .ui-icon-arrow-1-ne { background-position: -16px -32px; } 431 | .ui-icon-arrow-1-e { background-position: -32px -32px; } 432 | .ui-icon-arrow-1-se { background-position: -48px -32px; } 433 | .ui-icon-arrow-1-s { background-position: -64px -32px; } 434 | .ui-icon-arrow-1-sw { background-position: -80px -32px; } 435 | .ui-icon-arrow-1-w { background-position: -96px -32px; } 436 | .ui-icon-arrow-1-nw { background-position: -112px -32px; } 437 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } 438 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } 439 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } 440 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } 441 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } 442 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } 443 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } 444 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } 445 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; } 446 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } 447 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } 448 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } 449 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } 450 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } 451 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } 452 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } 453 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } 454 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } 455 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } 456 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } 457 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } 458 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } 459 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } 460 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } 461 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } 462 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } 463 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } 464 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } 465 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } 466 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } 467 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } 468 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } 469 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } 470 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } 471 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } 472 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } 473 | .ui-icon-arrow-4 { background-position: 0 -80px; } 474 | .ui-icon-arrow-4-diag { background-position: -16px -80px; } 475 | .ui-icon-extlink { background-position: -32px -80px; } 476 | .ui-icon-newwin { background-position: -48px -80px; } 477 | .ui-icon-refresh { background-position: -64px -80px; } 478 | .ui-icon-shuffle { background-position: -80px -80px; } 479 | .ui-icon-transfer-e-w { background-position: -96px -80px; } 480 | .ui-icon-transferthick-e-w { background-position: -112px -80px; } 481 | .ui-icon-folder-collapsed { background-position: 0 -96px; } 482 | .ui-icon-folder-open { background-position: -16px -96px; } 483 | .ui-icon-document { background-position: -32px -96px; } 484 | .ui-icon-document-b { background-position: -48px -96px; } 485 | .ui-icon-note { background-position: -64px -96px; } 486 | .ui-icon-mail-closed { background-position: -80px -96px; } 487 | .ui-icon-mail-open { background-position: -96px -96px; } 488 | .ui-icon-suitcase { background-position: -112px -96px; } 489 | .ui-icon-comment { background-position: -128px -96px; } 490 | .ui-icon-person { background-position: -144px -96px; } 491 | .ui-icon-print { background-position: -160px -96px; } 492 | .ui-icon-trash { background-position: -176px -96px; } 493 | .ui-icon-locked { background-position: -192px -96px; } 494 | .ui-icon-unlocked { background-position: -208px -96px; } 495 | .ui-icon-bookmark { background-position: -224px -96px; } 496 | .ui-icon-tag { background-position: -240px -96px; } 497 | .ui-icon-home { background-position: 0 -112px; } 498 | .ui-icon-flag { background-position: -16px -112px; } 499 | .ui-icon-calendar { background-position: -32px -112px; } 500 | .ui-icon-cart { background-position: -48px -112px; } 501 | .ui-icon-pencil { background-position: -64px -112px; } 502 | .ui-icon-clock { background-position: -80px -112px; } 503 | .ui-icon-disk { background-position: -96px -112px; } 504 | .ui-icon-calculator { background-position: -112px -112px; } 505 | .ui-icon-zoomin { background-position: -128px -112px; } 506 | .ui-icon-zoomout { background-position: -144px -112px; } 507 | .ui-icon-search { background-position: -160px -112px; } 508 | .ui-icon-wrench { background-position: -176px -112px; } 509 | .ui-icon-gear { background-position: -192px -112px; } 510 | .ui-icon-heart { background-position: -208px -112px; } 511 | .ui-icon-star { background-position: -224px -112px; } 512 | .ui-icon-link { background-position: -240px -112px; } 513 | .ui-icon-cancel { background-position: 0 -128px; } 514 | .ui-icon-plus { background-position: -16px -128px; } 515 | .ui-icon-plusthick { background-position: -32px -128px; } 516 | .ui-icon-minus { background-position: -48px -128px; } 517 | .ui-icon-minusthick { background-position: -64px -128px; } 518 | .ui-icon-close { background-position: -80px -128px; } 519 | .ui-icon-closethick { background-position: -96px -128px; } 520 | .ui-icon-key { background-position: -112px -128px; } 521 | .ui-icon-lightbulb { background-position: -128px -128px; } 522 | .ui-icon-scissors { background-position: -144px -128px; } 523 | .ui-icon-clipboard { background-position: -160px -128px; } 524 | .ui-icon-copy { background-position: -176px -128px; } 525 | .ui-icon-contact { background-position: -192px -128px; } 526 | .ui-icon-image { background-position: -208px -128px; } 527 | .ui-icon-video { background-position: -224px -128px; } 528 | .ui-icon-script { background-position: -240px -128px; } 529 | .ui-icon-alert { background-position: 0 -144px; } 530 | .ui-icon-info { background-position: -16px -144px; } 531 | .ui-icon-notice { background-position: -32px -144px; } 532 | .ui-icon-help { background-position: -48px -144px; } 533 | .ui-icon-check { background-position: -64px -144px; } 534 | .ui-icon-bullet { background-position: -80px -144px; } 535 | .ui-icon-radio-off { background-position: -96px -144px; } 536 | .ui-icon-radio-on { background-position: -112px -144px; } 537 | .ui-icon-pin-w { background-position: -128px -144px; } 538 | .ui-icon-pin-s { background-position: -144px -144px; } 539 | .ui-icon-play { background-position: 0 -160px; } 540 | .ui-icon-pause { background-position: -16px -160px; } 541 | .ui-icon-seek-next { background-position: -32px -160px; } 542 | .ui-icon-seek-prev { background-position: -48px -160px; } 543 | .ui-icon-seek-end { background-position: -64px -160px; } 544 | .ui-icon-seek-start { background-position: -80px -160px; } 545 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ 546 | .ui-icon-seek-first { background-position: -80px -160px; } 547 | .ui-icon-stop { background-position: -96px -160px; } 548 | .ui-icon-eject { background-position: -112px -160px; } 549 | .ui-icon-volume-off { background-position: -128px -160px; } 550 | .ui-icon-volume-on { background-position: -144px -160px; } 551 | .ui-icon-power { background-position: 0 -176px; } 552 | .ui-icon-signal-diag { background-position: -16px -176px; } 553 | .ui-icon-signal { background-position: -32px -176px; } 554 | .ui-icon-battery-0 { background-position: -48px -176px; } 555 | .ui-icon-battery-1 { background-position: -64px -176px; } 556 | .ui-icon-battery-2 { background-position: -80px -176px; } 557 | .ui-icon-battery-3 { background-position: -96px -176px; } 558 | .ui-icon-circle-plus { background-position: 0 -192px; } 559 | .ui-icon-circle-minus { background-position: -16px -192px; } 560 | .ui-icon-circle-close { background-position: -32px -192px; } 561 | .ui-icon-circle-triangle-e { background-position: -48px -192px; } 562 | .ui-icon-circle-triangle-s { background-position: -64px -192px; } 563 | .ui-icon-circle-triangle-w { background-position: -80px -192px; } 564 | .ui-icon-circle-triangle-n { background-position: -96px -192px; } 565 | .ui-icon-circle-arrow-e { background-position: -112px -192px; } 566 | .ui-icon-circle-arrow-s { background-position: -128px -192px; } 567 | .ui-icon-circle-arrow-w { background-position: -144px -192px; } 568 | .ui-icon-circle-arrow-n { background-position: -160px -192px; } 569 | .ui-icon-circle-zoomin { background-position: -176px -192px; } 570 | .ui-icon-circle-zoomout { background-position: -192px -192px; } 571 | .ui-icon-circle-check { background-position: -208px -192px; } 572 | .ui-icon-circlesmall-plus { background-position: 0 -208px; } 573 | .ui-icon-circlesmall-minus { background-position: -16px -208px; } 574 | .ui-icon-circlesmall-close { background-position: -32px -208px; } 575 | .ui-icon-squaresmall-plus { background-position: -48px -208px; } 576 | .ui-icon-squaresmall-minus { background-position: -64px -208px; } 577 | .ui-icon-squaresmall-close { background-position: -80px -208px; } 578 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } 579 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } 580 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } 581 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } 582 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } 583 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } 584 | 585 | 586 | /* Misc visuals 587 | ----------------------------------*/ 588 | 589 | /* Corner radius */ 590 | .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; } 591 | .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } 592 | .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } 593 | .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } 594 | .ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } 595 | .ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } 596 | .ui-corner-right { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } 597 | .ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } 598 | .ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; border-radius: 4px/*{cornerRadius}*/; } 599 | 600 | /* Overlays */ 601 | .ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(img/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } 602 | .ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(img/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } -------------------------------------------------------------------------------- /tpl/styles/config.scss: -------------------------------------------------------------------------------- 1 | // theme config 2 | // Navajo 3 | $mainColor: NavajoWhite; 4 | $borderColor: darken($mainColor, 20%); 5 | $shadowColor: #ccc; 6 | $documentBgColor: lighten($mainColor, 10%); 7 | $textColor: black; 8 | // Silver 9 | $mainColor: #eee; 10 | $borderColor: darken($mainColor, 20%); 11 | $documentBgColor: lighten($mainColor, 2%); 12 | // Dark gray 13 | // $mainColor: #444; 14 | // $borderColor: darken($mainColor, 20%); 15 | // $textColor: white; 16 | // $documentBgColor: #333; 17 | // $shadowColor: #111; 18 | // $ruleChannel: #8e8eda; 19 | // $rulePort: #8e8eda; 20 | // $ruleComment: #8e8eda; 21 | // $ruleDrop: #d44f4f; 22 | 23 | $fontSize: 12px; 24 | 25 | // table 26 | $tableTextColor: $textColor; 27 | $tableBgColor: $mainColor; 28 | $tableHeaderColor: white; 29 | $tableHeaderBgColor: darken($mainColor, 40%); 30 | $tableRowBgColor: darken($mainColor, 5%); 31 | 32 | // rule highlight 33 | $ruleDrop: red; 34 | $ruleAccept: green; 35 | $ruleNetworkAddress: gray; 36 | $rulePort: blue; 37 | $ruleComment: blue; 38 | $ruleChannel: blue; 39 | 40 | // info panels 41 | $errorTextColor: white; 42 | $errorBgColor: #f88; 43 | $infoTextColor: black; 44 | $infoBgColor: lightgreen; 45 | 46 | // menu 47 | $menuTextColor: $textColor; 48 | $menuBorderColor: $borderColor; 49 | $menuLightBgColor: $mainColor; 50 | $menuDarkBgColor: darken($menuLightBgColor, 7%); 51 | $menuSelectedBgColor: darken($menuLightBgColor, 30%); 52 | $subMenuBgColor: $mainColor; 53 | $subMenuBorderColor: $borderColor; 54 | $subMenuItemColor: darken($subMenuBgColor, 10%); 55 | 56 | // tool buttons 57 | $btnTextColor: $textColor; 58 | $btnBorderColor: $borderColor; 59 | $btnLightBgColor: $mainColor; 60 | $btnDarkBgColor: darken($menuLightBgColor, 7%); 61 | 62 | // ui dialogs 63 | $dlgTextColor: $textColor; 64 | $dlgBgColor: $mainColor; 65 | $dlgCaptionBgColor: darken($mainColor, 40%); 66 | 67 | $listItemActiveBgColor: darken($mainColor, 5%); 68 | $listItemSelectedBgColor: darken($mainColor, 15%); 69 | -------------------------------------------------------------------------------- /tpl/styles/style.scss: -------------------------------------------------------------------------------- 1 | @import "config.scss"; 2 | 3 | html, body { 4 | padding: 0; 5 | margin: 0; 6 | font-size: $fontSize; 7 | background-color: $documentBgColor; 8 | } 9 | 10 | .content { 11 | width: 1000px; 12 | margin: auto; 13 | } 14 | 15 | input { 16 | margin: 0; 17 | border: 1px solid $borderColor; 18 | color: $textColor; 19 | background-color: $documentBgColor; 20 | } 21 | 22 | .chainpath { 23 | padding: 4px; 24 | color: $textColor; 25 | } 26 | 27 | // table style 28 | .main { 29 | border: 1px solid $borderColor; 30 | background-color: $tableBgColor; 31 | color: $tableTextColor; 32 | width: 100%; 33 | 34 | .ruleeditor { 35 | font-family: monospace; 36 | } 37 | input { 38 | width: 100%; 39 | } 40 | 41 | // columns title 42 | th { color: $tableHeaderColor; background-color: $tableHeaderBgColor; } 43 | .id { 44 | width: 30px; 45 | text-align: center; 46 | } 47 | .mon { 48 | width: 46px; 49 | text-align: center; 50 | } 51 | .rule { 52 | text-align: center; 53 | } 54 | .cmd { 55 | width: 35px; 56 | text-align: center; 57 | } 58 | 59 | // rows body 60 | .row { 61 | background-color: $tableRowBgColor; 62 | height: 21px; 63 | padding: 0 5px; 64 | 65 | .edit { 66 | display: none; 67 | cursor: pointer; 68 | position: absolute; 69 | margin-top: 0px; 70 | } 71 | .edittext:hover .edit { 72 | display: inherit; 73 | } 74 | } 75 | .rowright { 76 | background-color: $tableRowBgColor; 77 | text-align: right; 78 | } 79 | .rowcenter { 80 | background-color: $tableRowBgColor; 81 | text-align: center; 82 | } 83 | 84 | .newrulerow { 85 | td:nth-child(1) { text-align: right; } 86 | td:nth-child(3) { text-align: center; } 87 | } 88 | } 89 | 90 | // Highlight styles 91 | .ipt-DROP { 92 | color: $ruleDrop; 93 | } 94 | 95 | .ipt-ACCEPT { 96 | color: $ruleAccept; 97 | } 98 | 99 | .ipt-net { 100 | color: $ruleNetworkAddress; 101 | } 102 | 103 | .ipt-port { 104 | color: $rulePort; 105 | } 106 | 107 | .ipt-channel { 108 | color: $ruleChannel; 109 | } 110 | 111 | .ipt-comment { 112 | color: $ruleComment; 113 | font-style: italic; 114 | } 115 | 116 | // panels 117 | .error { 118 | color: $errorTextColor; 119 | padding: 15px; 120 | text-align: center; 121 | display: none; 122 | border: 1px solid darken($errorBgColor, 15%); 123 | background-color: $errorBgColor; 124 | cursor: pointer; 125 | position: static; 126 | } 127 | 128 | .info { 129 | color: $infoTextColor; 130 | padding: 15px; 131 | text-align: center; 132 | display: none; 133 | border: 1px solid darken($infoBgColor, 15%); 134 | background-color: $infoBgColor; 135 | cursor: pointer; 136 | position: static; 137 | } 138 | 139 | @mixin gradient($from, $to) { 140 | background: -webkit-gradient(linear, 0 0, 0 100%, from($from), to($to)); 141 | background: -moz-linear-gradient(top, $from, $to); 142 | background-image: -o-linear-gradient(top, $from, $to); 143 | background: -ms-linear-gradient(top, $from, $to); 144 | } 145 | 146 | /* Main menu */ 147 | .mainmenu { 148 | border: 1px solid $menuBorderColor; color: $menuTextColor; 149 | margin: 5px auto 0; 150 | border-radius: 5px; 151 | padding: 3px; 152 | text-align: center; 153 | @include gradient($menuLightBgColor, $menuDarkBgColor); 154 | } 155 | 156 | ul { 157 | &.tabs { 158 | display: table; padding: 0 0px; list-style: none; position: relative; 159 | li { 160 | margin: 0; padding: 0; list-style: none; display: table-cell; float: left; position: relative; 161 | &:hover { 162 | @include gradient(lighten($menuLightBgColor, 7%), lighten($menuDarkBgColor, 7%)); 163 | &:first-child { border-top-left-radius: 5px; border-bottom-left-radius: 5px; } 164 | &:last-child { border-top-right-radius: 5px; border-bottom-right-radius: 5px; } 165 | } 166 | } 167 | a { position: relative; display: block; cursor: pointer; } 168 | .item { 169 | padding: 4px 15px; 170 | text-decoration: none; 171 | } 172 | .itemselect { 173 | padding: 4px 15px; 174 | text-decoration: none; 175 | background-color: $menuSelectedBgColor; 176 | } 177 | } 178 | 179 | &.dropdown { 180 | margin: 0 0 0 -36px; 181 | padding: 0px; 182 | display: block; 183 | position: absolute; 184 | z-index: 999; 185 | top: 100%; left: 0; 186 | display: none; 187 | border: 1px solid $subMenuBorderColor; 188 | background-color: $subMenuBgColor; 189 | box-shadow: 0 0 4px $shadowColor; 190 | 191 | ul.dropdown { top: 0; left: 95%; } 192 | li { 193 | margin: 0; padding: 1px; float: none; position: relative; list-style: none; display: block; 194 | &:hover { background: none; } 195 | a { 196 | display: block; padding: 5px 15px; text-decoration: none; text-align: center; width: 200px; 197 | background-color: $subMenuItemColor; 198 | &:hover { background-color: lighten($subMenuItemColor, 7%); } 199 | } 200 | } 201 | .first-row { float:left; } 202 | .second-row { float:right; } 203 | .large { width: 284px; left:-60px; } 204 | } 205 | } 206 | 207 | /* Tool buttons */ 208 | .tools { 209 | padding: 10px; 210 | height: 24px; 211 | text-align: center; 212 | 213 | .button { 214 | color: $btnTextColor; 215 | padding: 5px 11px; 216 | text-decoration: none; 217 | float:right; 218 | cursor: pointer; 219 | height: 15px; 220 | margin-left: 5px; 221 | border-radius: 5px; 222 | @include gradient($btnLightBgColor, $btnDarkBgColor); 223 | border: 1px solid $btnBorderColor; 224 | box-shadow: 0 0 5px $shadowColor; 225 | 226 | &:hover { 227 | @include gradient(lighten($btnLightBgColor, 7%), lighten($btnDarkBgColor, 7%)); 228 | } 229 | 230 | &[disabled=disabled] { 231 | background-color: #ccc; 232 | color:#999; 233 | @include gradient(darken($btnLightBgColor, 7%), darken($btnDarkBgColor, 7%)); 234 | cursor: default; 235 | } 236 | .icon { float: right; margin: 0 4px; } 237 | } 238 | } 239 | 240 | /* Dialogs */ 241 | .settings { 242 | display: none; 243 | 244 | .splitter { 245 | background-color: darken($mainColor, 5%); 246 | padding: 3px; 247 | font-weight: bold; 248 | } 249 | } 250 | 251 | .addchain { 252 | display: none; 253 | } 254 | 255 | .dialog { 256 | display: none; 257 | .content { 258 | display: flex; 259 | flex-direction: column; 260 | height: 100%; 261 | width: 100%; 262 | 263 | .params { 264 | padding-bottom: 10px; 265 | input { 266 | margin: 3px; 267 | width: 115px; 268 | } 269 | } 270 | .logpanel { 271 | overflow: auto; 272 | white-space: nowrap; 273 | flex-grow: 1; 274 | } 275 | } 276 | } 277 | 278 | #user-select-category { 279 | height: 200px; width: 140px; 280 | border: 1px solid $borderColor; 281 | vertical-align: top; float: left; 282 | 283 | .item { 284 | padding: 3px; 285 | &:hover { background-color: $listItemActiveBgColor; cursor: pointer; } 286 | } 287 | .itemselected { padding: 3px; background-color: $listItemSelectedBgColor; } 288 | .item-icon { float: left; margin-right: 5px; } 289 | } 290 | 291 | #settings-page1, #settings-page2, #settings-page3 { 292 | height: 200px; padding: 0px; display: none; 293 | border: 1px solid $borderColor; 294 | vertical-align: top; margin-left: 145px; overflow: auto; 295 | } 296 | 297 | .authform { 298 | border: 1px solid gray; 299 | background-color: #ccc; 300 | margin: auto; 301 | margin-top: 100px; 302 | padding: 15px; 303 | 304 | td { 305 | text-align: right; 306 | } 307 | } 308 | 309 | .ui-dialog { 310 | background-color: $dlgBgColor !important; 311 | box-shadow: 5px 5px 10px $shadowColor; 312 | .ui-widget-header { background: $dlgCaptionBgColor !important; } 313 | .ui-widget-content { background: transparent !important; color: $dlgTextColor !important; } 314 | .ui-dialog-buttonpane { padding: 0; } 315 | .ui-state-hover { 316 | background: darken($mainColor, 30%); 317 | box-shadow: inherit; 318 | border-color: $borderColor; 319 | } 320 | .ui-button { 321 | box-shadow: 0 0 5px $shadowColor; 322 | color: $btnTextColor; 323 | margin-left: 5px; 324 | border-radius: 5px; 325 | border: 1px solid $btnBorderColor; 326 | @include gradient($btnLightBgColor, $btnDarkBgColor); 327 | &:hover { @include gradient(lighten($btnLightBgColor, 7%), lighten($btnDarkBgColor, 7%)); } 328 | } 329 | .main { border: 0; margin-top: 0; } 330 | } 331 | 332 | @media(max-width:1000px) { 333 | .content { width: inherit; } 334 | .button { margin-bottom: 5px; } 335 | .ui-dialog { left: 0; max-width: 95%; } 336 | #logs div { white-space: nowrap; } 337 | } -------------------------------------------------------------------------------- /tpl/template.js: -------------------------------------------------------------------------------- 1 | var tpl = { 2 | // settings 3 | settingsLan: function (interface, name) { 4 | return '\n\ 5 | \n\ 6 | \n\ 7 | \n\ 8 | '; 9 | }, 10 | 11 | settingsPort: function (port, name) { 12 | return '\n\ 13 | \n\ 14 | \n\ 15 | \n\ 16 | '; 17 | }, 18 | 19 | // custom chains menu 20 | customChain: function (name, table) { 21 | return '
  • ' + name + " (" + table + ')
  • '; 22 | }, 23 | 24 | customChainAddNew: '
  • Add new ...
  • ', 25 | 26 | // rules 27 | ruleRow: function (index, text) { 28 | return "" + 29 | '' + index + "" + 30 | '' + 31 | '' + 32 | '' + text + '' + 33 | (index ? '' + "" : '') + 34 | ""; 35 | }, 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /tpl/theme/DarkGray.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | padding: 0; 3 | margin: 0; 4 | font-size: 12px; 5 | background-color: #333; 6 | } 7 | 8 | .content { 9 | width: 1000px; 10 | margin: auto; 11 | } 12 | 13 | input { 14 | margin: 0; 15 | border: 1px solid #111111; 16 | color: white; 17 | background-color: #333; 18 | } 19 | 20 | .chainpath { 21 | padding: 4px; 22 | color: white; 23 | } 24 | 25 | .main { 26 | border: 1px solid #111111; 27 | background-color: #444; 28 | color: white; 29 | width: 100%; 30 | } 31 | .main .ruleeditor { 32 | font-family: monospace; 33 | } 34 | .main input { 35 | width: 100%; 36 | } 37 | .main th { 38 | color: white; 39 | background-color: black; 40 | } 41 | .main .id { 42 | width: 30px; 43 | text-align: center; 44 | } 45 | .main .mon { 46 | width: 46px; 47 | text-align: center; 48 | } 49 | .main .rule { 50 | text-align: center; 51 | } 52 | .main .cmd { 53 | width: 35px; 54 | text-align: center; 55 | } 56 | .main .row { 57 | background-color: #373737; 58 | height: 21px; 59 | padding: 0 5px; 60 | } 61 | .main .row .edit { 62 | display: none; 63 | cursor: pointer; 64 | position: absolute; 65 | margin-top: 0px; 66 | } 67 | .main .row .edittext:hover .edit { 68 | display: inherit; 69 | } 70 | .main .rowright { 71 | background-color: #373737; 72 | text-align: right; 73 | } 74 | .main .rowcenter { 75 | background-color: #373737; 76 | text-align: center; 77 | } 78 | .main .newrulerow td:nth-child(1) { 79 | text-align: right; 80 | } 81 | .main .newrulerow td:nth-child(3) { 82 | text-align: center; 83 | } 84 | 85 | .ipt-DROP { 86 | color: #d44f4f; 87 | } 88 | 89 | .ipt-ACCEPT { 90 | color: green; 91 | } 92 | 93 | .ipt-net { 94 | color: gray; 95 | } 96 | 97 | .ipt-port { 98 | color: #8e8eda; 99 | } 100 | 101 | .ipt-channel { 102 | color: #8e8eda; 103 | } 104 | 105 | .ipt-comment { 106 | color: #8e8eda; 107 | font-style: italic; 108 | } 109 | 110 | .error { 111 | color: white; 112 | padding: 15px; 113 | text-align: center; 114 | display: none; 115 | border: 1px solid #ff3c3c; 116 | background-color: #f88; 117 | cursor: pointer; 118 | position: static; 119 | } 120 | 121 | .info { 122 | color: black; 123 | padding: 15px; 124 | text-align: center; 125 | display: none; 126 | border: 1px solid #4ee44e; 127 | background-color: lightgreen; 128 | cursor: pointer; 129 | position: static; 130 | } 131 | 132 | /* Main menu */ 133 | .mainmenu { 134 | border: 1px solid #111111; 135 | color: white; 136 | margin: 5px auto 0; 137 | border-radius: 5px; 138 | padding: 3px; 139 | text-align: center; 140 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#323232)); 141 | background: -moz-linear-gradient(top, #444, #323232); 142 | background-image: -o-linear-gradient(top, #444, #323232); 143 | background: -ms-linear-gradient(top, #444, #323232); 144 | } 145 | 146 | ul.tabs { 147 | display: table; 148 | padding: 0 0px; 149 | list-style: none; 150 | position: relative; 151 | } 152 | ul.tabs li { 153 | margin: 0; 154 | padding: 0; 155 | list-style: none; 156 | display: table-cell; 157 | float: left; 158 | position: relative; 159 | } 160 | ul.tabs li:hover { 161 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#565656), to(#444444)); 162 | background: -moz-linear-gradient(top, #565656, #444444); 163 | background-image: -o-linear-gradient(top, #565656, #444444); 164 | background: -ms-linear-gradient(top, #565656, #444444); 165 | } 166 | ul.tabs li:hover:first-child { 167 | border-top-left-radius: 5px; 168 | border-bottom-left-radius: 5px; 169 | } 170 | ul.tabs li:hover:last-child { 171 | border-top-right-radius: 5px; 172 | border-bottom-right-radius: 5px; 173 | } 174 | ul.tabs a { 175 | position: relative; 176 | display: block; 177 | cursor: pointer; 178 | } 179 | ul.tabs .item { 180 | padding: 4px 15px; 181 | text-decoration: none; 182 | } 183 | ul.tabs .itemselect { 184 | padding: 4px 15px; 185 | text-decoration: none; 186 | background-color: black; 187 | } 188 | ul.dropdown { 189 | margin: 0 0 0 -36px; 190 | padding: 0px; 191 | display: block; 192 | position: absolute; 193 | z-index: 999; 194 | top: 100%; 195 | left: 0; 196 | display: none; 197 | border: 1px solid #111111; 198 | background-color: #444; 199 | box-shadow: 0 0 4px #111; 200 | } 201 | ul.dropdown ul.dropdown { 202 | top: 0; 203 | left: 95%; 204 | } 205 | ul.dropdown li { 206 | margin: 0; 207 | padding: 1px; 208 | float: none; 209 | position: relative; 210 | list-style: none; 211 | display: block; 212 | } 213 | ul.dropdown li:hover { 214 | background: none; 215 | } 216 | ul.dropdown li a { 217 | display: block; 218 | padding: 5px 15px; 219 | text-decoration: none; 220 | text-align: center; 221 | width: 200px; 222 | background-color: #2b2b2b; 223 | } 224 | ul.dropdown li a:hover { 225 | background-color: #3c3c3c; 226 | } 227 | ul.dropdown .first-row { 228 | float: left; 229 | } 230 | ul.dropdown .second-row { 231 | float: right; 232 | } 233 | ul.dropdown .large { 234 | width: 284px; 235 | left: -60px; 236 | } 237 | 238 | /* Tool buttons */ 239 | .tools { 240 | padding: 10px; 241 | height: 24px; 242 | text-align: center; 243 | } 244 | .tools .button { 245 | color: white; 246 | padding: 5px 11px; 247 | text-decoration: none; 248 | float: right; 249 | cursor: pointer; 250 | height: 15px; 251 | margin-left: 5px; 252 | border-radius: 5px; 253 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#323232)); 254 | background: -moz-linear-gradient(top, #444, #323232); 255 | background-image: -o-linear-gradient(top, #444, #323232); 256 | background: -ms-linear-gradient(top, #444, #323232); 257 | border: 1px solid #111111; 258 | box-shadow: 0 0 5px #111; 259 | } 260 | .tools .button:hover { 261 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#565656), to(#444444)); 262 | background: -moz-linear-gradient(top, #565656, #444444); 263 | background-image: -o-linear-gradient(top, #565656, #444444); 264 | background: -ms-linear-gradient(top, #565656, #444444); 265 | } 266 | .tools .button[disabled=disabled] { 267 | background-color: #ccc; 268 | color: #999; 269 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#323232), to(#202020)); 270 | background: -moz-linear-gradient(top, #323232, #202020); 271 | background-image: -o-linear-gradient(top, #323232, #202020); 272 | background: -ms-linear-gradient(top, #323232, #202020); 273 | cursor: default; 274 | } 275 | .tools .button .icon { 276 | float: right; 277 | margin: 0 4px; 278 | } 279 | 280 | /* Dialogs */ 281 | .settings { 282 | display: none; 283 | } 284 | .settings .splitter { 285 | background-color: #373737; 286 | padding: 3px; 287 | font-weight: bold; 288 | } 289 | 290 | .addchain { 291 | display: none; 292 | } 293 | 294 | .dialog { 295 | display: none; 296 | } 297 | .dialog .content { 298 | display: flex; 299 | flex-direction: column; 300 | height: 100%; 301 | width: 100%; 302 | } 303 | .dialog .content .params { 304 | padding-bottom: 10px; 305 | } 306 | .dialog .content .params input { 307 | margin: 3px; 308 | width: 115px; 309 | } 310 | .dialog .content .logpanel { 311 | overflow: auto; 312 | white-space: nowrap; 313 | flex-grow: 1; 314 | } 315 | 316 | #user-select-category { 317 | height: 200px; 318 | width: 140px; 319 | border: 1px solid #111111; 320 | vertical-align: top; 321 | float: left; 322 | } 323 | #user-select-category .item { 324 | padding: 3px; 325 | } 326 | #user-select-category .item:hover { 327 | background-color: #373737; 328 | cursor: pointer; 329 | } 330 | #user-select-category .itemselected { 331 | padding: 3px; 332 | background-color: #1e1e1e; 333 | } 334 | #user-select-category .item-icon { 335 | float: left; 336 | margin-right: 5px; 337 | } 338 | 339 | #settings-page1, #settings-page2, #settings-page3 { 340 | height: 200px; 341 | padding: 0px; 342 | display: none; 343 | border: 1px solid #111111; 344 | vertical-align: top; 345 | margin-left: 145px; 346 | overflow: auto; 347 | } 348 | 349 | .authform { 350 | border: 1px solid gray; 351 | background-color: #ccc; 352 | margin: auto; 353 | margin-top: 100px; 354 | padding: 15px; 355 | } 356 | .authform td { 357 | text-align: right; 358 | } 359 | 360 | .ui-dialog { 361 | background-color: #444 !important; 362 | box-shadow: 5px 5px 10px #111; 363 | } 364 | .ui-dialog .ui-widget-header { 365 | background: black !important; 366 | } 367 | .ui-dialog .ui-widget-content { 368 | background: transparent !important; 369 | color: white !important; 370 | } 371 | .ui-dialog .ui-dialog-buttonpane { 372 | padding: 0; 373 | } 374 | .ui-dialog .ui-state-hover { 375 | background: black; 376 | box-shadow: inherit; 377 | border-color: #111111; 378 | } 379 | .ui-dialog .ui-button { 380 | box-shadow: 0 0 5px #111; 381 | color: white; 382 | margin-left: 5px; 383 | border-radius: 5px; 384 | border: 1px solid #111111; 385 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#444), to(#323232)); 386 | background: -moz-linear-gradient(top, #444, #323232); 387 | background-image: -o-linear-gradient(top, #444, #323232); 388 | background: -ms-linear-gradient(top, #444, #323232); 389 | } 390 | .ui-dialog .ui-button:hover { 391 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#565656), to(#444444)); 392 | background: -moz-linear-gradient(top, #565656, #444444); 393 | background-image: -o-linear-gradient(top, #565656, #444444); 394 | background: -ms-linear-gradient(top, #565656, #444444); 395 | } 396 | .ui-dialog .main { 397 | border: 0; 398 | margin-top: 0; 399 | } 400 | 401 | @media (max-width: 1000px) { 402 | .content { 403 | width: inherit; 404 | } 405 | 406 | .button { 407 | margin-bottom: 5px; 408 | } 409 | 410 | .ui-dialog { 411 | left: 0; 412 | max-width: 95%; 413 | } 414 | 415 | #logs div { 416 | white-space: nowrap; 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /tpl/theme/Navajo.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | padding: 0; 3 | margin: 0; 4 | font-size: 12px; 5 | background-color: #fff3e0; 6 | } 7 | 8 | .content { 9 | width: 1000px; 10 | margin: auto; 11 | } 12 | 13 | input { 14 | margin: 0; 15 | border: 1px solid #ffb547; 16 | color: black; 17 | background-color: #fff3e0; 18 | } 19 | 20 | .chainpath { 21 | padding: 4px; 22 | color: black; 23 | } 24 | 25 | .main { 26 | border: 1px solid #ffb547; 27 | background-color: NavajoWhite; 28 | color: black; 29 | width: 100%; 30 | } 31 | .main .ruleeditor { 32 | font-family: monospace; 33 | } 34 | .main input { 35 | width: 100%; 36 | } 37 | .main th { 38 | color: white; 39 | background-color: #e08600; 40 | } 41 | .main .id { 42 | width: 30px; 43 | text-align: center; 44 | } 45 | .main .mon { 46 | width: 46px; 47 | text-align: center; 48 | } 49 | .main .rule { 50 | text-align: center; 51 | } 52 | .main .cmd { 53 | width: 35px; 54 | text-align: center; 55 | } 56 | .main .row { 57 | background-color: #ffd494; 58 | height: 21px; 59 | padding: 0 5px; 60 | } 61 | .main .row .edit { 62 | display: none; 63 | cursor: pointer; 64 | position: absolute; 65 | margin-top: 0px; 66 | } 67 | .main .row .edittext:hover .edit { 68 | display: inherit; 69 | } 70 | .main .rowright { 71 | background-color: #ffd494; 72 | text-align: right; 73 | } 74 | .main .rowcenter { 75 | background-color: #ffd494; 76 | text-align: center; 77 | } 78 | .main .newrulerow td:nth-child(1) { 79 | text-align: right; 80 | } 81 | .main .newrulerow td:nth-child(3) { 82 | text-align: center; 83 | } 84 | 85 | .ipt-DROP { 86 | color: red; 87 | } 88 | 89 | .ipt-ACCEPT { 90 | color: green; 91 | } 92 | 93 | .ipt-net { 94 | color: gray; 95 | } 96 | 97 | .ipt-port { 98 | color: blue; 99 | } 100 | 101 | .ipt-channel { 102 | color: blue; 103 | } 104 | 105 | .ipt-comment { 106 | color: blue; 107 | font-style: italic; 108 | } 109 | 110 | .error { 111 | color: white; 112 | padding: 15px; 113 | text-align: center; 114 | display: none; 115 | border: 1px solid #ff3c3c; 116 | background-color: #f88; 117 | cursor: pointer; 118 | position: static; 119 | } 120 | 121 | .info { 122 | color: black; 123 | padding: 15px; 124 | text-align: center; 125 | display: none; 126 | border: 1px solid #4ee44e; 127 | background-color: lightgreen; 128 | cursor: pointer; 129 | position: static; 130 | } 131 | 132 | /* Main menu */ 133 | .mainmenu { 134 | border: 1px solid #ffb547; 135 | color: black; 136 | margin: 5px auto 0; 137 | border-radius: 5px; 138 | padding: 3px; 139 | text-align: center; 140 | background: -webkit-gradient(linear, 0 0, 0 100%, from(NavajoWhite), to(#ffd089)); 141 | background: -moz-linear-gradient(top, NavajoWhite, #ffd089); 142 | background-image: -o-linear-gradient(top, NavajoWhite, #ffd089); 143 | background: -ms-linear-gradient(top, NavajoWhite, #ffd089); 144 | } 145 | 146 | ul.tabs { 147 | display: table; 148 | padding: 0 0px; 149 | list-style: none; 150 | position: relative; 151 | } 152 | ul.tabs li { 153 | margin: 0; 154 | padding: 0; 155 | list-style: none; 156 | display: table-cell; 157 | float: left; 158 | position: relative; 159 | } 160 | ul.tabs li:hover { 161 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#ffecd1), to(navajowhite)); 162 | background: -moz-linear-gradient(top, #ffecd1, navajowhite); 163 | background-image: -o-linear-gradient(top, #ffecd1, navajowhite); 164 | background: -ms-linear-gradient(top, #ffecd1, navajowhite); 165 | } 166 | ul.tabs li:hover:first-child { 167 | border-top-left-radius: 5px; 168 | border-bottom-left-radius: 5px; 169 | } 170 | ul.tabs li:hover:last-child { 171 | border-top-right-radius: 5px; 172 | border-bottom-right-radius: 5px; 173 | } 174 | ul.tabs a { 175 | position: relative; 176 | display: block; 177 | cursor: pointer; 178 | } 179 | ul.tabs .item { 180 | padding: 4px 15px; 181 | text-decoration: none; 182 | } 183 | ul.tabs .itemselect { 184 | padding: 4px 15px; 185 | text-decoration: none; 186 | background-color: #ffa014; 187 | } 188 | ul.dropdown { 189 | margin: 0 0 0 -36px; 190 | padding: 0px; 191 | display: block; 192 | position: absolute; 193 | z-index: 999; 194 | top: 100%; 195 | left: 0; 196 | display: none; 197 | border: 1px solid #ffb547; 198 | background-color: NavajoWhite; 199 | box-shadow: 0 0 4px #ccc; 200 | } 201 | ul.dropdown ul.dropdown { 202 | top: 0; 203 | left: 95%; 204 | } 205 | ul.dropdown li { 206 | margin: 0; 207 | padding: 1px; 208 | float: none; 209 | position: relative; 210 | list-style: none; 211 | display: block; 212 | } 213 | ul.dropdown li:hover { 214 | background: none; 215 | } 216 | ul.dropdown li a { 217 | display: block; 218 | padding: 5px 15px; 219 | text-decoration: none; 220 | text-align: center; 221 | width: 200px; 222 | background-color: #ffc97a; 223 | } 224 | ul.dropdown li a:hover { 225 | background-color: #ffd89e; 226 | } 227 | ul.dropdown .first-row { 228 | float: left; 229 | } 230 | ul.dropdown .second-row { 231 | float: right; 232 | } 233 | ul.dropdown .large { 234 | width: 284px; 235 | left: -60px; 236 | } 237 | 238 | /* Tool buttons */ 239 | .tools { 240 | padding: 10px; 241 | height: 24px; 242 | text-align: center; 243 | } 244 | .tools .button { 245 | color: black; 246 | padding: 5px 11px; 247 | text-decoration: none; 248 | float: right; 249 | cursor: pointer; 250 | height: 15px; 251 | margin-left: 5px; 252 | border-radius: 5px; 253 | background: -webkit-gradient(linear, 0 0, 0 100%, from(NavajoWhite), to(#ffd089)); 254 | background: -moz-linear-gradient(top, NavajoWhite, #ffd089); 255 | background-image: -o-linear-gradient(top, NavajoWhite, #ffd089); 256 | background: -ms-linear-gradient(top, NavajoWhite, #ffd089); 257 | border: 1px solid #ffb547; 258 | box-shadow: 0 0 5px #ccc; 259 | } 260 | .tools .button:hover { 261 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#ffecd1), to(navajowhite)); 262 | background: -moz-linear-gradient(top, #ffecd1, navajowhite); 263 | background-image: -o-linear-gradient(top, #ffecd1, navajowhite); 264 | background: -ms-linear-gradient(top, #ffecd1, navajowhite); 265 | } 266 | .tools .button[disabled=disabled] { 267 | background-color: #ccc; 268 | color: #999; 269 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#ffd089), to(#ffc166)); 270 | background: -moz-linear-gradient(top, #ffd089, #ffc166); 271 | background-image: -o-linear-gradient(top, #ffd089, #ffc166); 272 | background: -ms-linear-gradient(top, #ffd089, #ffc166); 273 | cursor: default; 274 | } 275 | .tools .button .icon { 276 | float: right; 277 | margin: 0 4px; 278 | } 279 | 280 | /* Dialogs */ 281 | .settings { 282 | display: none; 283 | } 284 | .settings .splitter { 285 | background-color: #ffd494; 286 | padding: 3px; 287 | font-weight: bold; 288 | } 289 | 290 | .addchain { 291 | display: none; 292 | } 293 | 294 | .dialog { 295 | display: none; 296 | } 297 | .dialog .content { 298 | display: flex; 299 | flex-direction: column; 300 | height: 100%; 301 | width: 100%; 302 | } 303 | .dialog .content .params { 304 | padding-bottom: 10px; 305 | } 306 | .dialog .content .params input { 307 | margin: 3px; 308 | width: 115px; 309 | } 310 | .dialog .content .logpanel { 311 | overflow: auto; 312 | white-space: nowrap; 313 | flex-grow: 1; 314 | } 315 | 316 | #user-select-category { 317 | height: 200px; 318 | width: 140px; 319 | border: 1px solid #ffb547; 320 | vertical-align: top; 321 | float: left; 322 | } 323 | #user-select-category .item { 324 | padding: 3px; 325 | } 326 | #user-select-category .item:hover { 327 | background-color: #ffd494; 328 | cursor: pointer; 329 | } 330 | #user-select-category .itemselected { 331 | padding: 3px; 332 | background-color: #ffbf61; 333 | } 334 | #user-select-category .item-icon { 335 | float: left; 336 | margin-right: 5px; 337 | } 338 | 339 | #settings-page1, #settings-page2, #settings-page3 { 340 | height: 200px; 341 | padding: 0px; 342 | display: none; 343 | border: 1px solid #ffb547; 344 | vertical-align: top; 345 | margin-left: 145px; 346 | overflow: auto; 347 | } 348 | 349 | .authform { 350 | border: 1px solid gray; 351 | background-color: #ccc; 352 | margin: auto; 353 | margin-top: 100px; 354 | padding: 15px; 355 | } 356 | .authform td { 357 | text-align: right; 358 | } 359 | 360 | .ui-dialog { 361 | background-color: NavajoWhite !important; 362 | box-shadow: 5px 5px 10px #ccc; 363 | } 364 | .ui-dialog .ui-widget-header { 365 | background: #e08600 !important; 366 | } 367 | .ui-dialog .ui-widget-content { 368 | background: transparent !important; 369 | color: black !important; 370 | } 371 | .ui-dialog .ui-dialog-buttonpane { 372 | padding: 0; 373 | } 374 | .ui-dialog .ui-state-hover { 375 | background: #ffa014; 376 | box-shadow: inherit; 377 | border-color: #ffb547; 378 | } 379 | .ui-dialog .ui-button { 380 | box-shadow: 0 0 5px #ccc; 381 | color: black; 382 | margin-left: 5px; 383 | border-radius: 5px; 384 | border: 1px solid #ffb547; 385 | background: -webkit-gradient(linear, 0 0, 0 100%, from(NavajoWhite), to(#ffd089)); 386 | background: -moz-linear-gradient(top, NavajoWhite, #ffd089); 387 | background-image: -o-linear-gradient(top, NavajoWhite, #ffd089); 388 | background: -ms-linear-gradient(top, NavajoWhite, #ffd089); 389 | } 390 | .ui-dialog .ui-button:hover { 391 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#ffecd1), to(navajowhite)); 392 | background: -moz-linear-gradient(top, #ffecd1, navajowhite); 393 | background-image: -o-linear-gradient(top, #ffecd1, navajowhite); 394 | background: -ms-linear-gradient(top, #ffecd1, navajowhite); 395 | } 396 | .ui-dialog .main { 397 | border: 0; 398 | margin-top: 0; 399 | } 400 | 401 | @media (max-width: 1000px) { 402 | .content { 403 | width: inherit; 404 | } 405 | 406 | .button { 407 | margin-bottom: 5px; 408 | } 409 | 410 | .ui-dialog { 411 | left: 0; 412 | max-width: 95%; 413 | } 414 | 415 | #logs div { 416 | white-space: nowrap; 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /tpl/theme/Silver.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | padding: 0; 3 | margin: 0; 4 | font-size: 12px; 5 | background-color: #f3f3f3; 6 | } 7 | 8 | .content { 9 | width: 1000px; 10 | margin: auto; 11 | } 12 | 13 | input { 14 | margin: 0; 15 | border: 1px solid #bbbbbb; 16 | color: black; 17 | background-color: #f3f3f3; 18 | } 19 | 20 | .chainpath { 21 | padding: 4px; 22 | color: black; 23 | } 24 | 25 | .main { 26 | border: 1px solid #bbbbbb; 27 | background-color: #eee; 28 | color: black; 29 | width: 100%; 30 | } 31 | .main .ruleeditor { 32 | font-family: monospace; 33 | } 34 | .main input { 35 | width: 100%; 36 | } 37 | .main th { 38 | color: white; 39 | background-color: #888888; 40 | } 41 | .main .id { 42 | width: 30px; 43 | text-align: center; 44 | } 45 | .main .mon { 46 | width: 46px; 47 | text-align: center; 48 | } 49 | .main .rule { 50 | text-align: center; 51 | } 52 | .main .cmd { 53 | width: 35px; 54 | text-align: center; 55 | } 56 | .main .row { 57 | background-color: #e1e1e1; 58 | height: 21px; 59 | padding: 0 5px; 60 | } 61 | .main .row .edit { 62 | display: none; 63 | cursor: pointer; 64 | position: absolute; 65 | margin-top: 0px; 66 | } 67 | .main .row .edittext:hover .edit { 68 | display: inherit; 69 | } 70 | .main .rowright { 71 | background-color: #e1e1e1; 72 | text-align: right; 73 | } 74 | .main .rowcenter { 75 | background-color: #e1e1e1; 76 | text-align: center; 77 | } 78 | .main .newrulerow td:nth-child(1) { 79 | text-align: right; 80 | } 81 | .main .newrulerow td:nth-child(3) { 82 | text-align: center; 83 | } 84 | 85 | .ipt-DROP { 86 | color: red; 87 | } 88 | 89 | .ipt-ACCEPT { 90 | color: green; 91 | } 92 | 93 | .ipt-net { 94 | color: gray; 95 | } 96 | 97 | .ipt-port { 98 | color: blue; 99 | } 100 | 101 | .ipt-channel { 102 | color: blue; 103 | } 104 | 105 | .ipt-comment { 106 | color: blue; 107 | font-style: italic; 108 | } 109 | 110 | .error { 111 | color: white; 112 | padding: 15px; 113 | text-align: center; 114 | display: none; 115 | border: 1px solid #ff3c3c; 116 | background-color: #f88; 117 | cursor: pointer; 118 | position: static; 119 | } 120 | 121 | .info { 122 | color: black; 123 | padding: 15px; 124 | text-align: center; 125 | display: none; 126 | border: 1px solid #4ee44e; 127 | background-color: lightgreen; 128 | cursor: pointer; 129 | position: static; 130 | } 131 | 132 | /* Main menu */ 133 | .mainmenu { 134 | border: 1px solid #bbbbbb; 135 | color: black; 136 | margin: 5px auto 0; 137 | border-radius: 5px; 138 | padding: 3px; 139 | text-align: center; 140 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#eee), to(gainsboro)); 141 | background: -moz-linear-gradient(top, #eee, gainsboro); 142 | background-image: -o-linear-gradient(top, #eee, gainsboro); 143 | background: -ms-linear-gradient(top, #eee, gainsboro); 144 | } 145 | 146 | ul.tabs { 147 | display: table; 148 | padding: 0 0px; 149 | list-style: none; 150 | position: relative; 151 | } 152 | ul.tabs li { 153 | margin: 0; 154 | padding: 0; 155 | list-style: none; 156 | display: table-cell; 157 | float: left; 158 | position: relative; 159 | } 160 | ul.tabs li:hover { 161 | background: -webkit-gradient(linear, 0 0, 0 100%, from(white), to(#eeeeee)); 162 | background: -moz-linear-gradient(top, white, #eeeeee); 163 | background-image: -o-linear-gradient(top, white, #eeeeee); 164 | background: -ms-linear-gradient(top, white, #eeeeee); 165 | } 166 | ul.tabs li:hover:first-child { 167 | border-top-left-radius: 5px; 168 | border-bottom-left-radius: 5px; 169 | } 170 | ul.tabs li:hover:last-child { 171 | border-top-right-radius: 5px; 172 | border-bottom-right-radius: 5px; 173 | } 174 | ul.tabs a { 175 | position: relative; 176 | display: block; 177 | cursor: pointer; 178 | } 179 | ul.tabs .item { 180 | padding: 4px 15px; 181 | text-decoration: none; 182 | } 183 | ul.tabs .itemselect { 184 | padding: 4px 15px; 185 | text-decoration: none; 186 | background-color: #a2a2a2; 187 | } 188 | ul.dropdown { 189 | margin: 0 0 0 -36px; 190 | padding: 0px; 191 | display: block; 192 | position: absolute; 193 | z-index: 999; 194 | top: 100%; 195 | left: 0; 196 | display: none; 197 | border: 1px solid #bbbbbb; 198 | background-color: #eee; 199 | box-shadow: 0 0 4px #ccc; 200 | } 201 | ul.dropdown ul.dropdown { 202 | top: 0; 203 | left: 95%; 204 | } 205 | ul.dropdown li { 206 | margin: 0; 207 | padding: 1px; 208 | float: none; 209 | position: relative; 210 | list-style: none; 211 | display: block; 212 | } 213 | ul.dropdown li:hover { 214 | background: none; 215 | } 216 | ul.dropdown li a { 217 | display: block; 218 | padding: 5px 15px; 219 | text-decoration: none; 220 | text-align: center; 221 | width: 200px; 222 | background-color: #d5d5d5; 223 | } 224 | ul.dropdown li a:hover { 225 | background-color: #e6e6e6; 226 | } 227 | ul.dropdown .first-row { 228 | float: left; 229 | } 230 | ul.dropdown .second-row { 231 | float: right; 232 | } 233 | ul.dropdown .large { 234 | width: 284px; 235 | left: -60px; 236 | } 237 | 238 | /* Tool buttons */ 239 | .tools { 240 | padding: 10px; 241 | height: 24px; 242 | text-align: center; 243 | } 244 | .tools .button { 245 | color: black; 246 | padding: 5px 11px; 247 | text-decoration: none; 248 | float: right; 249 | cursor: pointer; 250 | height: 15px; 251 | margin-left: 5px; 252 | border-radius: 5px; 253 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#eee), to(gainsboro)); 254 | background: -moz-linear-gradient(top, #eee, gainsboro); 255 | background-image: -o-linear-gradient(top, #eee, gainsboro); 256 | background: -ms-linear-gradient(top, #eee, gainsboro); 257 | border: 1px solid #bbbbbb; 258 | box-shadow: 0 0 5px #ccc; 259 | } 260 | .tools .button:hover { 261 | background: -webkit-gradient(linear, 0 0, 0 100%, from(white), to(#eeeeee)); 262 | background: -moz-linear-gradient(top, white, #eeeeee); 263 | background-image: -o-linear-gradient(top, white, #eeeeee); 264 | background: -ms-linear-gradient(top, white, #eeeeee); 265 | } 266 | .tools .button[disabled=disabled] { 267 | background-color: #ccc; 268 | color: #999; 269 | background: -webkit-gradient(linear, 0 0, 0 100%, from(gainsboro), to(#cacaca)); 270 | background: -moz-linear-gradient(top, gainsboro, #cacaca); 271 | background-image: -o-linear-gradient(top, gainsboro, #cacaca); 272 | background: -ms-linear-gradient(top, gainsboro, #cacaca); 273 | cursor: default; 274 | } 275 | .tools .button .icon { 276 | float: right; 277 | margin: 0 4px; 278 | } 279 | 280 | /* Dialogs */ 281 | .settings { 282 | display: none; 283 | } 284 | .settings .splitter { 285 | background-color: #e1e1e1; 286 | padding: 3px; 287 | font-weight: bold; 288 | } 289 | 290 | .addchain { 291 | display: none; 292 | } 293 | 294 | .dialog { 295 | display: none; 296 | } 297 | .dialog .content { 298 | display: flex; 299 | flex-direction: column; 300 | height: 100%; 301 | width: 100%; 302 | } 303 | .dialog .content .params { 304 | padding-bottom: 10px; 305 | } 306 | .dialog .content .params input { 307 | margin: 3px; 308 | width: 115px; 309 | } 310 | .dialog .content .logpanel { 311 | overflow: auto; 312 | white-space: nowrap; 313 | flex-grow: 1; 314 | } 315 | 316 | #user-select-category { 317 | height: 200px; 318 | width: 140px; 319 | border: 1px solid #bbbbbb; 320 | vertical-align: top; 321 | float: left; 322 | } 323 | #user-select-category .item { 324 | padding: 3px; 325 | } 326 | #user-select-category .item:hover { 327 | background-color: #e1e1e1; 328 | cursor: pointer; 329 | } 330 | #user-select-category .itemselected { 331 | padding: 3px; 332 | background-color: #c8c8c8; 333 | } 334 | #user-select-category .item-icon { 335 | float: left; 336 | margin-right: 5px; 337 | } 338 | 339 | #settings-page1, #settings-page2, #settings-page3 { 340 | height: 200px; 341 | padding: 0px; 342 | display: none; 343 | border: 1px solid #bbbbbb; 344 | vertical-align: top; 345 | margin-left: 145px; 346 | overflow: auto; 347 | } 348 | 349 | .authform { 350 | border: 1px solid gray; 351 | background-color: #ccc; 352 | margin: auto; 353 | margin-top: 100px; 354 | padding: 15px; 355 | } 356 | .authform td { 357 | text-align: right; 358 | } 359 | 360 | .ui-dialog { 361 | background-color: #eee !important; 362 | box-shadow: 5px 5px 10px #ccc; 363 | } 364 | .ui-dialog .ui-widget-header { 365 | background: #888888 !important; 366 | } 367 | .ui-dialog .ui-widget-content { 368 | background: transparent !important; 369 | color: black !important; 370 | } 371 | .ui-dialog .ui-dialog-buttonpane { 372 | padding: 0; 373 | } 374 | .ui-dialog .ui-state-hover { 375 | background: #a2a2a2; 376 | box-shadow: inherit; 377 | border-color: #bbbbbb; 378 | } 379 | .ui-dialog .ui-button { 380 | box-shadow: 0 0 5px #ccc; 381 | color: black; 382 | margin-left: 5px; 383 | border-radius: 5px; 384 | border: 1px solid #bbbbbb; 385 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#eee), to(gainsboro)); 386 | background: -moz-linear-gradient(top, #eee, gainsboro); 387 | background-image: -o-linear-gradient(top, #eee, gainsboro); 388 | background: -ms-linear-gradient(top, #eee, gainsboro); 389 | } 390 | .ui-dialog .ui-button:hover { 391 | background: -webkit-gradient(linear, 0 0, 0 100%, from(white), to(#eeeeee)); 392 | background: -moz-linear-gradient(top, white, #eeeeee); 393 | background-image: -o-linear-gradient(top, white, #eeeeee); 394 | background: -ms-linear-gradient(top, white, #eeeeee); 395 | } 396 | .ui-dialog .main { 397 | border: 0; 398 | margin-top: 0; 399 | } 400 | 401 | @media (max-width: 1000px) { 402 | .content { 403 | width: inherit; 404 | } 405 | 406 | .button { 407 | margin-bottom: 5px; 408 | } 409 | 410 | .ui-dialog { 411 | left: 0; 412 | max-width: 95%; 413 | } 414 | 415 | #logs div { 416 | white-space: nowrap; 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /tpl/tools.js: -------------------------------------------------------------------------------- 1 | _settings = {}; 2 | 3 | $(document).ready(function(){ 4 | $.get("/settings", function(data){ 5 | _settings = JSON.parse(data); 6 | $(".param").each(function(index, obj){ 7 | $(obj).val(_settings[obj.id]); 8 | }); 9 | 10 | if(_settings.LANS) { 11 | for(var lan in _settings.LANS) { 12 | $("#lans").append(window.tpl.settingsLan(lan, _settings.LANS[lan])); 13 | } 14 | } 15 | else { 16 | _settings.LANS = {}; 17 | } 18 | if(_settings.PORTS) { 19 | for(var port in _settings.PORTS) { 20 | $("#ports").append(window.tpl.settingsPort(port, _settings.PORTS[port])); 21 | } 22 | } 23 | else { 24 | _settings.PORTS = {}; 25 | } 26 | 27 | if(_settings.pass) { 28 | $("#logout").show(); 29 | } 30 | 31 | $("#theme").attr("href", "theme/" + _settings.theme + ".css"); 32 | for(var i in _settings.themes) { 33 | var theme = _settings.themes[i]; 34 | $("#themeSelector").append(""); 35 | } 36 | $("#themeSelector").on("change", function(){ 37 | $("#theme").attr("href", "theme/" + this.value + ".css"); 38 | _settings.theme = this.value; 39 | }); 40 | }); 41 | }); 42 | 43 | function showError(text) { 44 | $(".error").html(text).fadeIn().click(function(){ 45 | $(this).fadeOut(); 46 | }); 47 | } 48 | 49 | function showInfo(text) { 50 | $(".info").html(text).fadeIn().click(function(){ 51 | $(this).fadeOut(); 52 | }); 53 | } --------------------------------------------------------------------------------