├── .gitignore ├── README.md ├── books1.php ├── books2.php ├── css ├── bootstrap.min.css ├── style.css └── style.css~ ├── database.sql ├── db_connect.php ├── fonts ├── glyphicons-halflings-regular.eot ├── glyphicons-halflings-regular.svg ├── glyphicons-halflings-regular.ttf └── glyphicons-halflings-regular.woff ├── footer.php ├── index.php ├── js ├── bootstrap.js └── bootstrap.min.js ├── login1.php ├── login2.php ├── login3.php ├── login4.php ├── mobile-navbar.php └── regexp.php /.gitignore: -------------------------------------------------------------------------------- 1 | /nbproject/private/ 2 | db_connect.php 3 | /db_connect.php 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a demonstration about SQL-Injection for an universitary project, you can view the demo at: 2 | 3 | http://sqlidemo.altervista.org 4 | 5 | - All vulnerabilities are explained in vulnerable pages 6 | 7 | - Database content is available in 'database.sql' file -------------------------------------------------------------------------------- /books1.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | SQL Injection Demo 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 54 | 55 | 56 |

57 | Vulnerable Search


58 | 59 |
60 |
61 |
62 |
63 | 64 | 65 |
66 |
67 | 68 | 69 |
70 | 71 |
72 |
73 |
74 |   75 | 76 |
77 |
78 | 79 |
80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | ", $row[0], $row[1], $row[2]); 106 | } 107 | } 108 | ?> 109 |
#IDTitleAuthor
%s%s%s
110 | 111 |
112 |
113 |
114 |

Query Executed:

115 |
116 |
117 | 118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | 126 |
127 |
128 |
129 |

PHP Code:

130 |
131 |
132 | 133 |
134 |
135 |
136 |
137 | if ($_GET['all'] == 1)
138 | {
139 |     $query = "SELECT * FROM books;";
140 | }
141 | else if ($_GET['title'] || $_GET['author'])
142 | {
143 |     $query = sprintf("SELECT * FROM books WHERE title = '%s' OR author = '%s';",
144 |                              $_GET['title'],
145 |                              $_GET['author']);
146 | }
147 | 
148 | if ($query != null)
149 | {
150 |     $result = mysqli_query($connection, $query);
151 | 
152 |     while (($row = mysqli_fetch_row($result)) != null)
153 |     {
154 |         printf("<tr><td>%s</td><td>%s</td><td>%s</td></tr>", $row[0], $row[1], $row[2]);
155 |     }
156 | }
157 |             
158 |
159 |
160 |
161 | 162 |
163 |
164 |
165 |

Vulnerability:

166 |
167 |
168 | 169 |
170 |
171 |
172 |
173 | Pass ' UNION SELECT * FROM users WHERE '1'='1 as author to get all users data.
174 | The same result is obtained by using url books1.php?author='+UNION+SELECT+*+FROM+users+WHERE '1'='1. 175 |
176 |
177 |
178 |
179 | 180 |
181 | 182 | 183 | 184 |
185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /books2.php: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | SQL Injection Demo 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 54 | 55 | 56 |

57 | Secure Search


58 | 59 |
60 |
61 |
62 |
63 | 64 | 65 |
66 |
67 | 68 | 69 |
70 | 71 |
72 |
73 |
74 |   75 | 76 |
77 |
78 | 79 |
80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | ", $row[0], $row[1], $row[2]); 106 | } 107 | } 108 | ?> 109 |
#IDTitleAuthor
%s%s%s
110 | 111 |
112 |
113 |
114 |

Query Executed:

115 |
116 |
117 | 118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | 126 |
127 |
128 |
129 |

PHP Code:

130 |
131 |
132 | 133 |
134 |
135 |
136 |
137 | if ($_GET['all'] == 1)
138 | {
139 |     $query = "SELECT * FROM books;";
140 | }
141 | else if ($_GET['title'] || $_GET['author'])
142 | {
143 |     $query = sprintf("SELECT * FROM books WHERE title = '%s' OR author = '%s';",
144 |                              mysqli_real_escape_string($connection, $_GET['title']),
145 |                              mysqli_real_escape_string($connection, $_GET['author']));
146 | }
147 | 
148 | if ($query != null)
149 | {
150 | 	$result = mysqli_query($connection, $query);
151 | 
152 | 	while (($row = mysqli_fetch_row($result)) != null)
153 | 	{
154 | 		printf("<tr><td>%s</td><td>%s</td><td>%s</td></tr>", $row[0], $row[1], $row[2]);
155 | 	}
156 | }
157 |             
158 |
159 |
160 |
161 | 162 |
163 | 164 | 165 | 166 |
167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | /* Space out content a bit */ 2 | body { 3 | padding-top: 20px; 4 | padding-bottom: 20px; 5 | } 6 | 7 | /* Everything but the jumbotron gets side spacing for mobile first views */ 8 | .header, 9 | .marketing, 10 | .footer { 11 | padding-right: 15px; 12 | padding-left: 15px; 13 | } 14 | 15 | /* Custom page header */ 16 | .header { 17 | border-bottom: 1px solid #e5e5e5; 18 | } 19 | /* Make the masthead heading the same height as the navigation */ 20 | .header h3 { 21 | padding-bottom: 19px; 22 | margin-top: 0; 23 | margin-bottom: 0; 24 | line-height: 40px; 25 | } 26 | 27 | .header a{ 28 | text-decoration: none; 29 | } 30 | 31 | /* Custom page footer */ 32 | .footer { 33 | padding-top: 19px; 34 | color: #777; 35 | border-top: 1px solid #e5e5e5; 36 | } 37 | 38 | /* Customize container */ 39 | @media (min-width: 768px) { 40 | .container { 41 | max-width: 730px; 42 | } 43 | } 44 | .container-narrow > hr { 45 | margin: 30px 0; 46 | } 47 | 48 | /* Main marketing message and sign up button */ 49 | .jumbotron { 50 | text-align: center; 51 | border-bottom: 1px solid #e5e5e5; 52 | } 53 | .jumbotron .btn { 54 | padding: 14px 24px; 55 | font-size: 21px; 56 | } 57 | 58 | /* Supporting marketing content */ 59 | .marketing { 60 | margin: 40px 0; 61 | } 62 | .marketing p + h4 { 63 | margin-top: 28px; 64 | } 65 | 66 | /* Responsive: Portrait tablets and up */ 67 | @media screen and (min-width: 768px) { 68 | /* Remove the padding we set earlier */ 69 | .header, 70 | .marketing, 71 | .footer { 72 | padding-right: 0; 73 | padding-left: 0; 74 | } 75 | /* Space out the masthead */ 76 | .header { 77 | margin-bottom: 30px; 78 | } 79 | /* Remove the bottom border on the jumbotron for visual effect */ 80 | .jumbotron { 81 | border-bottom: 0; 82 | } 83 | } 84 | 85 | .nonclickable { 86 | pointer-events: none; 87 | cursor: not-allowed; 88 | } 89 | -------------------------------------------------------------------------------- /css/style.css~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBorzi/sql-injection-demo/7ad64570e2268936d041ec2d1212d5ed39179836/css/style.css~ -------------------------------------------------------------------------------- /database.sql: -------------------------------------------------------------------------------- 1 | -- Create database 2 | DROP DATABASE IF EXISTS `sqli`; 3 | CREATE DATABASE IF NOT EXISTS `sqli` /*!40100 DEFAULT CHARACTER SET latin1 */; 4 | USE `sqli`; 5 | 6 | 7 | -- Create `users` table 8 | DROP TABLE IF EXISTS `users`; 9 | CREATE TABLE IF NOT EXISTS `users` ( 10 | `id` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT, 11 | `username` varchar(50) NOT NULL, 12 | `password` varchar(50) NOT NULL, 13 | PRIMARY KEY (`id`) 14 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 15 | 16 | -- table `users` content 17 | DELETE FROM `users`; 18 | INSERT INTO `users` (`id`, `username`, `password`) VALUES 19 | (1, 'admin', 'pwd1'), 20 | (2, 'danilo', 'gasd12'), 21 | (3, 'filippo', 'postuy666'), 22 | (4, 'oreste', 'tmrchio82'), 23 | (5, 'luca', 'kd2jam'), 24 | (6, 'dario', '31lowrem'), 25 | (7, 'sebastiano', '4muniz4'), 26 | (8, 'antonio', 'ciuppi75'), 27 | (9, 'cristina', 'berfectqui2'), 28 | (10, 'jessica', 'ioryunzfrunz'); 29 | 30 | 31 | -- Create `books` table 32 | DROP TABLE IF EXISTS `books`; 33 | CREATE TABLE IF NOT EXISTS `books` ( 34 | `id` INT(11) NOT NULL AUTO_INCREMENT, 35 | `title` VARCHAR(50) NOT NULL DEFAULT '0', 36 | `author` VARCHAR(50) NOT NULL DEFAULT '0', 37 | PRIMARY KEY (`id`) 38 | ) 39 | COLLATE='latin1_swedish_ci' 40 | ENGINE=InnoDB 41 | AUTO_INCREMENT=3; 42 | 43 | -- table `books` content 44 | DELETE FROM `books`; 45 | INSERT INTO `books` (`id`, `title`, `author`) VALUES 46 | (1, 'A Game of Thrones', 'George R. R. Martin'), 47 | (2, 'A Clash of Kings', 'George R. R. Martin'), 48 | (3, 'A Storm of Swords', 'George R. R. Martin'), 49 | (4, 'A Feast for Crows', 'George R. R. Martin'), 50 | (5, 'A Dance with Dragons', 'George R. R. Martin'), 51 | (6, 'The Winds of Winter', 'George R. R. Martin'), 52 | (7, 'A Dream of Spring', 'George R. R. Martin'), 53 | (8, 'Software libero pensiero libero', 'Richard Stallman'), 54 | (9, 'Perche\' sono vegetariana', 'Margherita hack'), 55 | (10, 'I miei primi novant\'anni laici e ribelli', 'Margherita hack'), 56 | (11, 'A caccia dei misteri spaventosi del cielo', 'Margherita hack'), 57 | (12, 'In piena liberta\' e consapevolezza', 'Margherita hack'), 58 | (13, 'La mia vita in bicicletta', 'Margherita hack'); 59 | 60 | -- Create `clients` table 61 | DROP TABLE IF EXISTS `clients`; 62 | CREATE TABLE IF NOT EXISTS `clients` ( 63 | `id` int(11) NOT NULL AUTO_INCREMENT, 64 | `pin` int(11) NOT NULL DEFAULT '0', 65 | PRIMARY KEY (`id`) 66 | ) ENGINE=InnoDB AUTO_INCREMENT=112 DEFAULT CHARSET=latin1; 67 | 68 | -- table `clients` content 69 | DELETE FROM `clients`; 70 | INSERT INTO `clients` (`id`, `pin`) VALUES 71 | (110, 123456789), 72 | (111, 432342198); -------------------------------------------------------------------------------- /db_connect.php: -------------------------------------------------------------------------------- 1 | " . mysqli_connect_error() . ""); 8 | } 9 | ?> -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBorzi/sql-injection-demo/7ad64570e2268936d041ec2d1212d5ed39179836/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBorzi/sql-injection-demo/7ad64570e2268936d041ec2d1212d5ed39179836/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FrancescoBorzi/sql-injection-demo/7ad64570e2268936d041ec2d1212d5ed39179836/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /footer.php: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | SQL Injection Demo 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 51 | 52 | 53 |
54 |

SQL Injection

55 |

Demonstration Project

56 |

The code of this demo is available at:

57 | 58 |

github.com/ShinDarth/sql-injection-demo

59 |
60 | 61 | 62 | 63 |
64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /js/bootstrap.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.1.1 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') } 8 | 9 | /* ======================================================================== 10 | * Bootstrap: transition.js v3.1.1 11 | * http://getbootstrap.com/javascript/#transitions 12 | * ======================================================================== 13 | * Copyright 2011-2014 Twitter, Inc. 14 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 15 | * ======================================================================== */ 16 | 17 | 18 | +function ($) { 19 | 'use strict'; 20 | 21 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 22 | // ============================================================ 23 | 24 | function transitionEnd() { 25 | var el = document.createElement('bootstrap') 26 | 27 | var transEndEventNames = { 28 | 'WebkitTransition' : 'webkitTransitionEnd', 29 | 'MozTransition' : 'transitionend', 30 | 'OTransition' : 'oTransitionEnd otransitionend', 31 | 'transition' : 'transitionend' 32 | } 33 | 34 | for (var name in transEndEventNames) { 35 | if (el.style[name] !== undefined) { 36 | return { end: transEndEventNames[name] } 37 | } 38 | } 39 | 40 | return false // explicit for ie8 ( ._.) 41 | } 42 | 43 | // http://blog.alexmaccaw.com/css-transitions 44 | $.fn.emulateTransitionEnd = function (duration) { 45 | var called = false, $el = this 46 | $(this).one($.support.transition.end, function () { called = true }) 47 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 48 | setTimeout(callback, duration) 49 | return this 50 | } 51 | 52 | $(function () { 53 | $.support.transition = transitionEnd() 54 | }) 55 | 56 | }(jQuery); 57 | 58 | /* ======================================================================== 59 | * Bootstrap: alert.js v3.1.1 60 | * http://getbootstrap.com/javascript/#alerts 61 | * ======================================================================== 62 | * Copyright 2011-2014 Twitter, Inc. 63 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 64 | * ======================================================================== */ 65 | 66 | 67 | +function ($) { 68 | 'use strict'; 69 | 70 | // ALERT CLASS DEFINITION 71 | // ====================== 72 | 73 | var dismiss = '[data-dismiss="alert"]' 74 | var Alert = function (el) { 75 | $(el).on('click', dismiss, this.close) 76 | } 77 | 78 | Alert.prototype.close = function (e) { 79 | var $this = $(this) 80 | var selector = $this.attr('data-target') 81 | 82 | if (!selector) { 83 | selector = $this.attr('href') 84 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 85 | } 86 | 87 | var $parent = $(selector) 88 | 89 | if (e) e.preventDefault() 90 | 91 | if (!$parent.length) { 92 | $parent = $this.hasClass('alert') ? $this : $this.parent() 93 | } 94 | 95 | $parent.trigger(e = $.Event('close.bs.alert')) 96 | 97 | if (e.isDefaultPrevented()) return 98 | 99 | $parent.removeClass('in') 100 | 101 | function removeElement() { 102 | $parent.trigger('closed.bs.alert').remove() 103 | } 104 | 105 | $.support.transition && $parent.hasClass('fade') ? 106 | $parent 107 | .one($.support.transition.end, removeElement) 108 | .emulateTransitionEnd(150) : 109 | removeElement() 110 | } 111 | 112 | 113 | // ALERT PLUGIN DEFINITION 114 | // ======================= 115 | 116 | var old = $.fn.alert 117 | 118 | $.fn.alert = function (option) { 119 | return this.each(function () { 120 | var $this = $(this) 121 | var data = $this.data('bs.alert') 122 | 123 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 124 | if (typeof option == 'string') data[option].call($this) 125 | }) 126 | } 127 | 128 | $.fn.alert.Constructor = Alert 129 | 130 | 131 | // ALERT NO CONFLICT 132 | // ================= 133 | 134 | $.fn.alert.noConflict = function () { 135 | $.fn.alert = old 136 | return this 137 | } 138 | 139 | 140 | // ALERT DATA-API 141 | // ============== 142 | 143 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 144 | 145 | }(jQuery); 146 | 147 | /* ======================================================================== 148 | * Bootstrap: button.js v3.1.1 149 | * http://getbootstrap.com/javascript/#buttons 150 | * ======================================================================== 151 | * Copyright 2011-2014 Twitter, Inc. 152 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 153 | * ======================================================================== */ 154 | 155 | 156 | +function ($) { 157 | 'use strict'; 158 | 159 | // BUTTON PUBLIC CLASS DEFINITION 160 | // ============================== 161 | 162 | var Button = function (element, options) { 163 | this.$element = $(element) 164 | this.options = $.extend({}, Button.DEFAULTS, options) 165 | this.isLoading = false 166 | } 167 | 168 | Button.DEFAULTS = { 169 | loadingText: 'loading...' 170 | } 171 | 172 | Button.prototype.setState = function (state) { 173 | var d = 'disabled' 174 | var $el = this.$element 175 | var val = $el.is('input') ? 'val' : 'html' 176 | var data = $el.data() 177 | 178 | state = state + 'Text' 179 | 180 | if (!data.resetText) $el.data('resetText', $el[val]()) 181 | 182 | $el[val](data[state] || this.options[state]) 183 | 184 | // push to event loop to allow forms to submit 185 | setTimeout($.proxy(function () { 186 | if (state == 'loadingText') { 187 | this.isLoading = true 188 | $el.addClass(d).attr(d, d) 189 | } else if (this.isLoading) { 190 | this.isLoading = false 191 | $el.removeClass(d).removeAttr(d) 192 | } 193 | }, this), 0) 194 | } 195 | 196 | Button.prototype.toggle = function () { 197 | var changed = true 198 | var $parent = this.$element.closest('[data-toggle="buttons"]') 199 | 200 | if ($parent.length) { 201 | var $input = this.$element.find('input') 202 | if ($input.prop('type') == 'radio') { 203 | if ($input.prop('checked') && this.$element.hasClass('active')) changed = false 204 | else $parent.find('.active').removeClass('active') 205 | } 206 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 207 | } 208 | 209 | if (changed) this.$element.toggleClass('active') 210 | } 211 | 212 | 213 | // BUTTON PLUGIN DEFINITION 214 | // ======================== 215 | 216 | var old = $.fn.button 217 | 218 | $.fn.button = function (option) { 219 | return this.each(function () { 220 | var $this = $(this) 221 | var data = $this.data('bs.button') 222 | var options = typeof option == 'object' && option 223 | 224 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 225 | 226 | if (option == 'toggle') data.toggle() 227 | else if (option) data.setState(option) 228 | }) 229 | } 230 | 231 | $.fn.button.Constructor = Button 232 | 233 | 234 | // BUTTON NO CONFLICT 235 | // ================== 236 | 237 | $.fn.button.noConflict = function () { 238 | $.fn.button = old 239 | return this 240 | } 241 | 242 | 243 | // BUTTON DATA-API 244 | // =============== 245 | 246 | $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) { 247 | var $btn = $(e.target) 248 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 249 | $btn.button('toggle') 250 | e.preventDefault() 251 | }) 252 | 253 | }(jQuery); 254 | 255 | /* ======================================================================== 256 | * Bootstrap: carousel.js v3.1.1 257 | * http://getbootstrap.com/javascript/#carousel 258 | * ======================================================================== 259 | * Copyright 2011-2014 Twitter, Inc. 260 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 261 | * ======================================================================== */ 262 | 263 | 264 | +function ($) { 265 | 'use strict'; 266 | 267 | // CAROUSEL CLASS DEFINITION 268 | // ========================= 269 | 270 | var Carousel = function (element, options) { 271 | this.$element = $(element) 272 | this.$indicators = this.$element.find('.carousel-indicators') 273 | this.options = options 274 | this.paused = 275 | this.sliding = 276 | this.interval = 277 | this.$active = 278 | this.$items = null 279 | 280 | this.options.pause == 'hover' && this.$element 281 | .on('mouseenter', $.proxy(this.pause, this)) 282 | .on('mouseleave', $.proxy(this.cycle, this)) 283 | } 284 | 285 | Carousel.DEFAULTS = { 286 | interval: 5000, 287 | pause: 'hover', 288 | wrap: true 289 | } 290 | 291 | Carousel.prototype.cycle = function (e) { 292 | e || (this.paused = false) 293 | 294 | this.interval && clearInterval(this.interval) 295 | 296 | this.options.interval 297 | && !this.paused 298 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 299 | 300 | return this 301 | } 302 | 303 | Carousel.prototype.getActiveIndex = function () { 304 | this.$active = this.$element.find('.item.active') 305 | this.$items = this.$active.parent().children() 306 | 307 | return this.$items.index(this.$active) 308 | } 309 | 310 | Carousel.prototype.to = function (pos) { 311 | var that = this 312 | var activeIndex = this.getActiveIndex() 313 | 314 | if (pos > (this.$items.length - 1) || pos < 0) return 315 | 316 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) 317 | if (activeIndex == pos) return this.pause().cycle() 318 | 319 | return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) 320 | } 321 | 322 | Carousel.prototype.pause = function (e) { 323 | e || (this.paused = true) 324 | 325 | if (this.$element.find('.next, .prev').length && $.support.transition) { 326 | this.$element.trigger($.support.transition.end) 327 | this.cycle(true) 328 | } 329 | 330 | this.interval = clearInterval(this.interval) 331 | 332 | return this 333 | } 334 | 335 | Carousel.prototype.next = function () { 336 | if (this.sliding) return 337 | return this.slide('next') 338 | } 339 | 340 | Carousel.prototype.prev = function () { 341 | if (this.sliding) return 342 | return this.slide('prev') 343 | } 344 | 345 | Carousel.prototype.slide = function (type, next) { 346 | var $active = this.$element.find('.item.active') 347 | var $next = next || $active[type]() 348 | var isCycling = this.interval 349 | var direction = type == 'next' ? 'left' : 'right' 350 | var fallback = type == 'next' ? 'first' : 'last' 351 | var that = this 352 | 353 | if (!$next.length) { 354 | if (!this.options.wrap) return 355 | $next = this.$element.find('.item')[fallback]() 356 | } 357 | 358 | if ($next.hasClass('active')) return this.sliding = false 359 | 360 | var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction }) 361 | this.$element.trigger(e) 362 | if (e.isDefaultPrevented()) return 363 | 364 | this.sliding = true 365 | 366 | isCycling && this.pause() 367 | 368 | if (this.$indicators.length) { 369 | this.$indicators.find('.active').removeClass('active') 370 | this.$element.one('slid.bs.carousel', function () { 371 | var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) 372 | $nextIndicator && $nextIndicator.addClass('active') 373 | }) 374 | } 375 | 376 | if ($.support.transition && this.$element.hasClass('slide')) { 377 | $next.addClass(type) 378 | $next[0].offsetWidth // force reflow 379 | $active.addClass(direction) 380 | $next.addClass(direction) 381 | $active 382 | .one($.support.transition.end, function () { 383 | $next.removeClass([type, direction].join(' ')).addClass('active') 384 | $active.removeClass(['active', direction].join(' ')) 385 | that.sliding = false 386 | setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0) 387 | }) 388 | .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000) 389 | } else { 390 | $active.removeClass('active') 391 | $next.addClass('active') 392 | this.sliding = false 393 | this.$element.trigger('slid.bs.carousel') 394 | } 395 | 396 | isCycling && this.cycle() 397 | 398 | return this 399 | } 400 | 401 | 402 | // CAROUSEL PLUGIN DEFINITION 403 | // ========================== 404 | 405 | var old = $.fn.carousel 406 | 407 | $.fn.carousel = function (option) { 408 | return this.each(function () { 409 | var $this = $(this) 410 | var data = $this.data('bs.carousel') 411 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 412 | var action = typeof option == 'string' ? option : options.slide 413 | 414 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 415 | if (typeof option == 'number') data.to(option) 416 | else if (action) data[action]() 417 | else if (options.interval) data.pause().cycle() 418 | }) 419 | } 420 | 421 | $.fn.carousel.Constructor = Carousel 422 | 423 | 424 | // CAROUSEL NO CONFLICT 425 | // ==================== 426 | 427 | $.fn.carousel.noConflict = function () { 428 | $.fn.carousel = old 429 | return this 430 | } 431 | 432 | 433 | // CAROUSEL DATA-API 434 | // ================= 435 | 436 | $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { 437 | var $this = $(this), href 438 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 439 | var options = $.extend({}, $target.data(), $this.data()) 440 | var slideIndex = $this.attr('data-slide-to') 441 | if (slideIndex) options.interval = false 442 | 443 | $target.carousel(options) 444 | 445 | if (slideIndex = $this.attr('data-slide-to')) { 446 | $target.data('bs.carousel').to(slideIndex) 447 | } 448 | 449 | e.preventDefault() 450 | }) 451 | 452 | $(window).on('load', function () { 453 | $('[data-ride="carousel"]').each(function () { 454 | var $carousel = $(this) 455 | $carousel.carousel($carousel.data()) 456 | }) 457 | }) 458 | 459 | }(jQuery); 460 | 461 | /* ======================================================================== 462 | * Bootstrap: collapse.js v3.1.1 463 | * http://getbootstrap.com/javascript/#collapse 464 | * ======================================================================== 465 | * Copyright 2011-2014 Twitter, Inc. 466 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 467 | * ======================================================================== */ 468 | 469 | 470 | +function ($) { 471 | 'use strict'; 472 | 473 | // COLLAPSE PUBLIC CLASS DEFINITION 474 | // ================================ 475 | 476 | var Collapse = function (element, options) { 477 | this.$element = $(element) 478 | this.options = $.extend({}, Collapse.DEFAULTS, options) 479 | this.transitioning = null 480 | 481 | if (this.options.parent) this.$parent = $(this.options.parent) 482 | if (this.options.toggle) this.toggle() 483 | } 484 | 485 | Collapse.DEFAULTS = { 486 | toggle: true 487 | } 488 | 489 | Collapse.prototype.dimension = function () { 490 | var hasWidth = this.$element.hasClass('width') 491 | return hasWidth ? 'width' : 'height' 492 | } 493 | 494 | Collapse.prototype.show = function () { 495 | if (this.transitioning || this.$element.hasClass('in')) return 496 | 497 | var startEvent = $.Event('show.bs.collapse') 498 | this.$element.trigger(startEvent) 499 | if (startEvent.isDefaultPrevented()) return 500 | 501 | var actives = this.$parent && this.$parent.find('> .panel > .in') 502 | 503 | if (actives && actives.length) { 504 | var hasData = actives.data('bs.collapse') 505 | if (hasData && hasData.transitioning) return 506 | actives.collapse('hide') 507 | hasData || actives.data('bs.collapse', null) 508 | } 509 | 510 | var dimension = this.dimension() 511 | 512 | this.$element 513 | .removeClass('collapse') 514 | .addClass('collapsing') 515 | [dimension](0) 516 | 517 | this.transitioning = 1 518 | 519 | var complete = function () { 520 | this.$element 521 | .removeClass('collapsing') 522 | .addClass('collapse in') 523 | [dimension]('auto') 524 | this.transitioning = 0 525 | this.$element.trigger('shown.bs.collapse') 526 | } 527 | 528 | if (!$.support.transition) return complete.call(this) 529 | 530 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 531 | 532 | this.$element 533 | .one($.support.transition.end, $.proxy(complete, this)) 534 | .emulateTransitionEnd(350) 535 | [dimension](this.$element[0][scrollSize]) 536 | } 537 | 538 | Collapse.prototype.hide = function () { 539 | if (this.transitioning || !this.$element.hasClass('in')) return 540 | 541 | var startEvent = $.Event('hide.bs.collapse') 542 | this.$element.trigger(startEvent) 543 | if (startEvent.isDefaultPrevented()) return 544 | 545 | var dimension = this.dimension() 546 | 547 | this.$element 548 | [dimension](this.$element[dimension]()) 549 | [0].offsetHeight 550 | 551 | this.$element 552 | .addClass('collapsing') 553 | .removeClass('collapse') 554 | .removeClass('in') 555 | 556 | this.transitioning = 1 557 | 558 | var complete = function () { 559 | this.transitioning = 0 560 | this.$element 561 | .trigger('hidden.bs.collapse') 562 | .removeClass('collapsing') 563 | .addClass('collapse') 564 | } 565 | 566 | if (!$.support.transition) return complete.call(this) 567 | 568 | this.$element 569 | [dimension](0) 570 | .one($.support.transition.end, $.proxy(complete, this)) 571 | .emulateTransitionEnd(350) 572 | } 573 | 574 | Collapse.prototype.toggle = function () { 575 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 576 | } 577 | 578 | 579 | // COLLAPSE PLUGIN DEFINITION 580 | // ========================== 581 | 582 | var old = $.fn.collapse 583 | 584 | $.fn.collapse = function (option) { 585 | return this.each(function () { 586 | var $this = $(this) 587 | var data = $this.data('bs.collapse') 588 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 589 | 590 | if (!data && options.toggle && option == 'show') option = !option 591 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 592 | if (typeof option == 'string') data[option]() 593 | }) 594 | } 595 | 596 | $.fn.collapse.Constructor = Collapse 597 | 598 | 599 | // COLLAPSE NO CONFLICT 600 | // ==================== 601 | 602 | $.fn.collapse.noConflict = function () { 603 | $.fn.collapse = old 604 | return this 605 | } 606 | 607 | 608 | // COLLAPSE DATA-API 609 | // ================= 610 | 611 | $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { 612 | var $this = $(this), href 613 | var target = $this.attr('data-target') 614 | || e.preventDefault() 615 | || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 616 | var $target = $(target) 617 | var data = $target.data('bs.collapse') 618 | var option = data ? 'toggle' : $this.data() 619 | var parent = $this.attr('data-parent') 620 | var $parent = parent && $(parent) 621 | 622 | if (!data || !data.transitioning) { 623 | if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed') 624 | $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed') 625 | } 626 | 627 | $target.collapse(option) 628 | }) 629 | 630 | }(jQuery); 631 | 632 | /* ======================================================================== 633 | * Bootstrap: dropdown.js v3.1.1 634 | * http://getbootstrap.com/javascript/#dropdowns 635 | * ======================================================================== 636 | * Copyright 2011-2014 Twitter, Inc. 637 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 638 | * ======================================================================== */ 639 | 640 | 641 | +function ($) { 642 | 'use strict'; 643 | 644 | // DROPDOWN CLASS DEFINITION 645 | // ========================= 646 | 647 | var backdrop = '.dropdown-backdrop' 648 | var toggle = '[data-toggle=dropdown]' 649 | var Dropdown = function (element) { 650 | $(element).on('click.bs.dropdown', this.toggle) 651 | } 652 | 653 | Dropdown.prototype.toggle = function (e) { 654 | var $this = $(this) 655 | 656 | if ($this.is('.disabled, :disabled')) return 657 | 658 | var $parent = getParent($this) 659 | var isActive = $parent.hasClass('open') 660 | 661 | clearMenus() 662 | 663 | if (!isActive) { 664 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 665 | // if mobile we use a backdrop because click events don't delegate 666 | $('