├── Kairos.php ├── LICENSE ├── README.md ├── examples ├── assets │ ├── css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── styles.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── images │ │ ├── loading.gif │ │ └── sample.jpg │ └── js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── scripts.js ├── controller.php └── methods_test.php ├── simple-detect ├── form-post.php └── index.html └── simple-viewSubjects ├── form-post.php └── index.html /Kairos.php: -------------------------------------------------------------------------------- 1 | hostname = 'http://api.kairos.com/'; 20 | $this->app_id = $app_id; 21 | $this->app_key = $app_key; 22 | } 23 | 24 | 25 | private function authenticationProvided() 26 | { 27 | if(count($this->app_key) > 0 && count($this->app_id) > 0) 28 | { 29 | return true; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | public function viewGalleries($args = array()) 36 | { 37 | 38 | if($this->authenticationProvided() == false) 39 | { 40 | return 'set your app_id and app_key before calling this method'; 41 | } 42 | 43 | $request_params = array(); 44 | 45 | // build request string 46 | $request = json_encode($request_params); 47 | 48 | try 49 | { 50 | 51 | $ch = curl_init(); 52 | 53 | curl_setopt($ch, CURLOPT_URL, $this->hostname . "gallery/list_all" ); 54 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 55 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 56 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 57 | curl_setopt($ch, CURLOPT_HTTPHEADER, 58 | array( 59 | 'Content-Type: application/json', 60 | 'Content-Length: ' . strlen($request), 61 | 'app_id: ' . $this->app_id, 62 | 'app_key: '. $this->app_key) 63 | ); 64 | 65 | $response = curl_exec($ch); 66 | 67 | curl_close($ch); 68 | 69 | } 70 | catch(Exception $ex) 71 | { 72 | return 'there was a problem'; 73 | } 74 | 75 | return $response; 76 | } 77 | 78 | 79 | public function enroll($args = array()) 80 | { 81 | 82 | // to get base64 83 | // $image_data = base64_encode(file_get_contents($args["image_path"])); 84 | 85 | if($this->authenticationProvided() == false) 86 | { 87 | return 'set your app_id and app_key before calling this method'; 88 | } 89 | 90 | 91 | $request_params = array( 92 | "image" => $args["image"], 93 | "gallery_name" => $args["gallery_name"], 94 | "subject_id" => $args["subject_id"] ); 95 | 96 | // build request string 97 | $request = json_encode($request_params); 98 | 99 | try 100 | { 101 | 102 | $ch = curl_init(); 103 | 104 | curl_setopt($ch, CURLOPT_URL, $this->hostname . "enroll" ); 105 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 106 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 107 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 108 | curl_setopt($ch, CURLOPT_HTTPHEADER, 109 | array( 110 | 'Content-Type: application/json', 111 | 'Content-Length: ' . strlen($request), 112 | 'app_id: ' . $this->app_id, 113 | 'app_key: '. $this->app_key) 114 | ); 115 | 116 | $response = curl_exec($ch); 117 | 118 | curl_close($ch); 119 | 120 | } 121 | catch(Exception $ex) 122 | { 123 | return 'there was a problem'; 124 | } 125 | 126 | return $response; 127 | } 128 | 129 | 130 | public function viewSubjectsInGallery($args = array()) 131 | { 132 | 133 | if($this->authenticationProvided() == false) 134 | { 135 | return 'set your app_id and app_key before calling this method'; 136 | } 137 | 138 | $request_params = array( 139 | "gallery_name" => $args["gallery_name"], 140 | ); 141 | 142 | // build request string 143 | $request = json_encode($request_params); 144 | 145 | try 146 | { 147 | 148 | $ch = curl_init(); 149 | 150 | curl_setopt($ch, CURLOPT_URL, $this->hostname . "gallery/view" ); 151 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 152 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 153 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 154 | curl_setopt($ch, CURLOPT_HTTPHEADER, 155 | array( 156 | 'Content-Type: application/json', 157 | 'Content-Length: ' . strlen($request), 158 | 'app_id: ' . $this->app_id, 159 | 'app_key: '. $this->app_key) 160 | ); 161 | 162 | $response = curl_exec($ch); 163 | 164 | curl_close($ch); 165 | 166 | } 167 | catch(Exception $ex) 168 | { 169 | return 'there was a problem'; 170 | } 171 | 172 | return $response; 173 | 174 | } 175 | 176 | 177 | 178 | public function removeSubjectFromGallery($args = array()) 179 | { 180 | 181 | if($this->authenticationProvided() == false) 182 | { 183 | return 'set your app_id and app_key before calling this method'; 184 | } 185 | 186 | $request_params = array( 187 | "gallery_name" => $args["gallery_name"], 188 | "subject_id" => $args["subject_id"], 189 | ); 190 | 191 | // build request string 192 | $request = json_encode($request_params); 193 | 194 | try 195 | { 196 | 197 | $ch = curl_init(); 198 | 199 | curl_setopt($ch, CURLOPT_URL, $this->hostname . "gallery/remove_subject" ); 200 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 201 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 202 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 203 | curl_setopt($ch, CURLOPT_HTTPHEADER, 204 | array( 205 | 'Content-Type: application/json', 206 | 'Content-Length: ' . strlen($request), 207 | 'app_id: ' . $this->app_id, 208 | 'app_key: '. $this->app_key) 209 | ); 210 | 211 | $response = curl_exec($ch); 212 | 213 | curl_close($ch); 214 | 215 | } 216 | catch(Exception $ex) 217 | { 218 | return 'there was a problem'; 219 | } 220 | 221 | return $response; 222 | } 223 | 224 | public function removeGallery($args = array()) 225 | { 226 | 227 | 228 | if($this->authenticationProvided() == false) 229 | { 230 | return 'set your app_id and app_key before calling this method'; 231 | } 232 | 233 | $request_params = array( 234 | "gallery_name" => $args["gallery_name"] 235 | ); 236 | 237 | 238 | // build request string 239 | $request = json_encode($request_params); 240 | 241 | try 242 | { 243 | 244 | $ch = curl_init(); 245 | 246 | curl_setopt($ch, CURLOPT_URL, $this->hostname . "gallery/remove" ); 247 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 248 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 249 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 250 | curl_setopt($ch, CURLOPT_HTTPHEADER, 251 | array( 252 | 'Content-Type: application/json', 253 | 'Content-Length: ' . strlen($request), 254 | 'app_id: ' . $this->app_id, 255 | 'app_key: '. $this->app_key) 256 | ); 257 | 258 | $response = curl_exec($ch); 259 | 260 | curl_close($ch); 261 | 262 | } 263 | catch(Exception $ex) 264 | { 265 | return 'there was a problem'; 266 | } 267 | 268 | return $response; 269 | 270 | } 271 | 272 | 273 | public function recognize($args = array()) 274 | { 275 | 276 | if($this->authenticationProvided() == false) 277 | { 278 | return 'set your app_id and app_key before calling this method'; 279 | } 280 | 281 | $request_params = array( 282 | "image" => $args["image"], 283 | "gallery_name" => $args["gallery_name"] 284 | ); 285 | 286 | // build request string 287 | $request = json_encode($request_params); 288 | 289 | try 290 | { 291 | 292 | $ch = curl_init(); 293 | 294 | curl_setopt($ch, CURLOPT_URL, $this->hostname . "recognize" ); 295 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 296 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 297 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 298 | curl_setopt($ch, CURLOPT_HTTPHEADER, 299 | array( 300 | 'Content-Type: application/json', 301 | 'Content-Length: ' . strlen($request), 302 | 'app_id: ' . $this->app_id, 303 | 'app_key: '. $this->app_key) 304 | ); 305 | 306 | $response = curl_exec($ch); 307 | 308 | curl_close($ch); 309 | 310 | } 311 | catch(Exception $ex) 312 | { 313 | return 'there was a problem'; 314 | } 315 | 316 | return $response; 317 | } 318 | 319 | public function detect($args = array()) 320 | { 321 | 322 | if($this->authenticationProvided() == false) 323 | { 324 | return 'set your app_id and app_key before calling this method'; 325 | } 326 | 327 | $request_params = array( 328 | "image" => $args["image"] 329 | ); 330 | 331 | // build request string 332 | $request = json_encode($request_params); 333 | 334 | try 335 | { 336 | 337 | $ch = curl_init(); 338 | 339 | curl_setopt($ch, CURLOPT_URL, $this->hostname . "detect" ); 340 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 341 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 342 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 343 | curl_setopt($ch, CURLOPT_HTTPHEADER, 344 | array( 345 | 'Content-Type: application/json', 346 | 'Content-Length: ' . strlen($request), 347 | 'app_id: ' . $this->app_id, 348 | 'app_key: '. $this->app_key) 349 | ); 350 | 351 | $response = curl_exec($ch); 352 | 353 | curl_close($ch); 354 | 355 | } 356 | catch(Exception $ex) 357 | { 358 | return 'there was a problem'; 359 | } 360 | 361 | return $response; 362 | 363 | } 364 | 365 | public function verify($args = array()) 366 | { 367 | 368 | if($this->authenticationProvided() == false) 369 | { 370 | return 'set your app_id and app_key before calling this method'; 371 | } 372 | 373 | $request_params = array( 374 | "image" => $args["image"], 375 | "subject_id" => $args["subject_id"], 376 | "gallery_name" => $args["gallery_name"] 377 | ); 378 | 379 | // build request string 380 | $request = json_encode($request_params); 381 | 382 | try 383 | { 384 | 385 | $ch = curl_init(); 386 | 387 | curl_setopt($ch, CURLOPT_URL, $this->hostname . "verify" ); 388 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); 389 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 390 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 391 | curl_setopt($ch, CURLOPT_HTTPHEADER, 392 | array( 393 | 'Content-Type: application/json', 394 | 'Content-Length: ' . strlen($request), 395 | 'app_id: ' . $this->app_id, 396 | 'app_key: '. $this->app_key) 397 | ); 398 | 399 | $response = curl_exec($ch); 400 | 401 | curl_close($ch); 402 | 403 | } 404 | catch(Exception $ex) 405 | { 406 | return 'there was a problem'; 407 | } 408 | 409 | return $response; 410 | 411 | } 412 | 413 | 414 | 415 | 416 | 417 | } 418 | 419 | ?> -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Kairos AR, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Kairos SDK (PHP) 2 | ============== 3 | 4 | Kairos is the easist way add **Face-Recognition** to your web applications. Our API provides a full-featured and robust Face-Recognition backend, right out of the box. This is the PHP wrapper for the [Kairos Face Recognition API](https://www.kairos.com). The package includes a **class** _(Kairos.php)_ you can use as an easy client to the API. Continue reading to learn how to integrate Kairos into your web application. 5 | 6 | _Thanks to contributions by some of our customers, we also have [Ruby](https://github.com/kany/kairos-api) and [.NET](https://github.com/humbywan/Kairos.Net) wrappers available. Also see our [Javascript SDK](https://github.com/kairosinc/Kairos-SDK-Javascript), our [Android SDK](https://github.com/kairosinc/Kairos-SDK-Android) and our [iOS SDK](https://github.com/kairosinc/Kairos-SDK-iOS)._ 7 | 8 | ## What You'll Need 9 | * An environment configured to run PHP scripts. 10 | 11 | --- 12 | 13 | 14 | ## How to Do a Quick Demo 15 | 16 | If you just want to do a quick test run, follow these steps: 17 | 18 | 1. [Create your free developer account](https://www.kairos.com/signup) 19 | 2. Log into the Kairos Developer Dashboard 20 | 3. Create an application and copy your **App Id** & **App Key** 21 | 3. Run `methods_test.php` in your browser. 22 | 4. Enter your app_id and app_key, and run the Kairos methods. 23 | 24 | 25 | --- 26 | 27 | 28 | ## How to Install Kairos in Your Own Web App 29 | 30 | 1. [Create your free Kairos developer account](https://www.kairos.com/signup) if you don't already have one. 31 | 2. Log into the [dashboard](https://www.kairos.com/login) and create a new app. 32 | 3. Copy your **App ID** & **App Key** (you'll need them later). 33 | 4. [Download](https://github.com/kairosinc/Kairos-SDK-PHP) the SDK and unzip the package. 34 | 5. Open the folder named **Kairos-SDK-PHP** containing the Kairos.php class. 35 | 6. Place the wrapper class _(Kairos.php)_ somewhere within your application. 36 | 7. Include Kairos.php where needed in your web application project. 37 | 38 | 39 | ``` 40 | include("Kairos.php"); 41 | ``` 42 | ## View Your Galleries 43 | 44 | This method returns a list of all galleries you've created: 45 | 46 | ``` 47 | $response = $Kairos->viewGalleries(); 48 | ``` 49 | ## View Your Subjects 50 | 51 | This method returns a list of all subjects for a given gallery: 52 | 53 | ``` 54 | $gallery_name = 'friends1'; 55 | $argumentArray = array( 56 | "gallery_name" => $gallery_name 57 | ); 58 | $response = $Kairos->viewSubjectsInGallery($argumentArray); 59 | ``` 60 | 61 | ## Remove a Subject 62 | 63 | This method removes a subject from given gallery: 64 | 65 | ``` 66 | $subject_id = 'dave'; 67 | $gallery_name = 'friends1'; 68 | $argumentArray = array( 69 | "subject_id" => $subject_id, 70 | "gallery_name" => $gallery_name 71 | ); 72 | $response = $Kairos->removeSubjectFromGallery($argumentArray); 73 | ``` 74 | 75 | ## Remove a Gallery 76 | 77 | This method removes a given gallery: 78 | 79 | ``` 80 | $gallery_name = 'friends1'; 81 | $argumentArray = array( 82 | "gallery_name" => $gallery_name 83 | ); 84 | $response = $Kairos->removeGallery($argumentArray); 85 | ``` 86 | ## Enroll an Image 87 | 88 | The **Enroll** method **registers a face for later recognitions**. Here's an example of enrolling a face (subject) using a method that accepts an absolute path to an image file in your file system **or** base64 image data, and enrolls it as a new subject into your specified gallery: 89 | 90 | ``` 91 | $image = '/images/myphotos/myphoto123.png'; 92 | (or) 93 | $image = 'iVBORw0KGgoAAA ... ABJRU5ErkJggg==\r\n'; 94 | $subject_id = 'elizabeth'; 95 | $gallery_name = 'friends1'; 96 | $argumentArray = array( 97 | "image" => $image, 98 | "subject_id" => $subject_id, 99 | "gallery_name" => $gallery_name 100 | ); 101 | $response = $Kairos->enroll($argumentArray); 102 | ``` 103 | `The SDK also includes a file upload field, which converts a local image file to base64 data.` 104 | 105 | ## Recognize an Image 106 | 107 | The **Recognize** method takes an image of a subject and **attempts to match it against a given gallery of previously-enrolled subjects**. Here's an example of recognizing a subject using a method that accepts an absolute path to an image file in your file system **or** base64 image data, sends it to the API, and returns a match and confidence value: 108 | 109 | ``` 110 | $image = '/images/myphotos/myphoto123.png'; 111 | (or) 112 | $image = 'iVBORw0KGgoAAA ... ABJRU5ErkJggg==\r\n'; 113 | $gallery_name = 'friends1'; 114 | $argumentArray = array( 115 | "image" => $image, 116 | "gallery_name" => $gallery_name 117 | ); 118 | $response = $Kairos->recognize($argumentArray); 119 | ``` 120 | 121 | `The SDK also includes a file upload field, which converts a local image file to base64 data.` 122 | 123 | ## Detect Image Attributes 124 | 125 | The **Detect** method takes an image of a subject and **returns various attributes pertaining to the face features**. Here's an example of the detect method which accepts a path to an image file on your system **or** base64 image data, sends it to the API, and returns face attributes: 126 | 127 | ``` 128 | $image = '/images/myphotos/myphoto123.png'; 129 | (or) 130 | $image = 'iVBORw0KGgoAAA ... ABJRU5ErkJggg==\r\n'; 131 | $argumentArray = array( 132 | "image" => $image 133 | ); 134 | $response = $Kairos->detect($argumentArray); 135 | ``` 136 | 137 | `The SDK also includes a file upload field, which converts a local image file to base64 data.` 138 | 139 | ## Verify image 140 | 141 | The **Verify** method takes an image and verifies that it matches an existing subject in a gallery. Here's an example of using verify via method that accepts a path to an image file, sends it to the API, and returns face attributes: 142 | 143 | ``` 144 | $image = '/images/myphotos/myphoto123.png'; 145 | (or) 146 | $image = 'iVBORw0KGgoAAA ... ABJRU5ErkJggg==\r\n'; 147 | $subject_id = 'elizabeth'; 148 | $gallery_name = 'friends1'; 149 | $argumentArray = array( 150 | "image" => $image, 151 | "subject_id" => $subject_id, 152 | "gallery_name" => $gallery_name 153 | ); 154 | $response = $Kairos->verify($argumentArray); 155 | ``` 156 | `The SDK also includes a file upload field, which converts a local image file to base64 data.` 157 | 158 | ##Support 159 | Have an issue? Visit our [Support page](http://www.kairos.com/support) or [create an issue on GitHub](https://github.com/kairosinc/Kairos-SDK-PHP) 160 | 161 | Test on [RapidAPI](https://rapidapi.com/package/KairosAPI/functions?utm_source=KairosGitHub&utm_medium=button) 162 | -------------------------------------------------------------------------------- /examples/assets/css/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | styles for methods_test.php 3 | created:; November 2016 4 | author: Steve Rucker 5 | */ 6 | 7 | #view_data { 8 | padding: 10px 0; 9 | color: #ff0000; 10 | word-wrap: break-word; 11 | } 12 | .method-test { 13 | margin-left: 30px; 14 | } 15 | .glyphicon { 16 | float: left; 17 | margin-top: 2px; 18 | margin-right: 10px; 19 | } 20 | form { 21 | margin-left: 30px; 22 | } 23 | #loader { 24 | display: none; 25 | width: 250px; 26 | float: left; 27 | } -------------------------------------------------------------------------------- /examples/assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kairosinc/Kairos-SDK-PHP/3c5baf3c825f6357549ace6f8cf754199c51f5c2/examples/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /examples/assets/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 | -------------------------------------------------------------------------------- /examples/assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kairosinc/Kairos-SDK-PHP/3c5baf3c825f6357549ace6f8cf754199c51f5c2/examples/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /examples/assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kairosinc/Kairos-SDK-PHP/3c5baf3c825f6357549ace6f8cf754199c51f5c2/examples/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /examples/assets/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kairosinc/Kairos-SDK-PHP/3c5baf3c825f6357549ace6f8cf754199c51f5c2/examples/assets/images/loading.gif -------------------------------------------------------------------------------- /examples/assets/images/sample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kairosinc/Kairos-SDK-PHP/3c5baf3c825f6357549ace6f8cf754199c51f5c2/examples/assets/images/sample.jpg -------------------------------------------------------------------------------- /examples/assets/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.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') { 8 | throw new Error('Bootstrap\'s JavaScript requires jQuery') 9 | } 10 | 11 | +function ($) { 12 | var version = $.fn.jquery.split(' ')[0].split('.') 13 | if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { 14 | throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') 15 | } 16 | }(jQuery); 17 | 18 | /* ======================================================================== 19 | * Bootstrap: transition.js v3.3.1 20 | * http://getbootstrap.com/javascript/#transitions 21 | * ======================================================================== 22 | * Copyright 2011-2014 Twitter, Inc. 23 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 24 | * ======================================================================== */ 25 | 26 | 27 | +function ($) { 28 | 'use strict'; 29 | 30 | // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) 31 | // ============================================================ 32 | 33 | function transitionEnd() { 34 | var el = document.createElement('bootstrap') 35 | 36 | var transEndEventNames = { 37 | WebkitTransition : 'webkitTransitionEnd', 38 | MozTransition : 'transitionend', 39 | OTransition : 'oTransitionEnd otransitionend', 40 | transition : 'transitionend' 41 | } 42 | 43 | for (var name in transEndEventNames) { 44 | if (el.style[name] !== undefined) { 45 | return { end: transEndEventNames[name] } 46 | } 47 | } 48 | 49 | return false // explicit for ie8 ( ._.) 50 | } 51 | 52 | // http://blog.alexmaccaw.com/css-transitions 53 | $.fn.emulateTransitionEnd = function (duration) { 54 | var called = false 55 | var $el = this 56 | $(this).one('bsTransitionEnd', function () { called = true }) 57 | var callback = function () { if (!called) $($el).trigger($.support.transition.end) } 58 | setTimeout(callback, duration) 59 | return this 60 | } 61 | 62 | $(function () { 63 | $.support.transition = transitionEnd() 64 | 65 | if (!$.support.transition) return 66 | 67 | $.event.special.bsTransitionEnd = { 68 | bindType: $.support.transition.end, 69 | delegateType: $.support.transition.end, 70 | handle: function (e) { 71 | if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) 72 | } 73 | } 74 | }) 75 | 76 | }(jQuery); 77 | 78 | /* ======================================================================== 79 | * Bootstrap: alert.js v3.3.1 80 | * http://getbootstrap.com/javascript/#alerts 81 | * ======================================================================== 82 | * Copyright 2011-2014 Twitter, Inc. 83 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 84 | * ======================================================================== */ 85 | 86 | 87 | +function ($) { 88 | 'use strict'; 89 | 90 | // ALERT CLASS DEFINITION 91 | // ====================== 92 | 93 | var dismiss = '[data-dismiss="alert"]' 94 | var Alert = function (el) { 95 | $(el).on('click', dismiss, this.close) 96 | } 97 | 98 | Alert.VERSION = '3.3.1' 99 | 100 | Alert.TRANSITION_DURATION = 150 101 | 102 | Alert.prototype.close = function (e) { 103 | var $this = $(this) 104 | var selector = $this.attr('data-target') 105 | 106 | if (!selector) { 107 | selector = $this.attr('href') 108 | selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 109 | } 110 | 111 | var $parent = $(selector) 112 | 113 | if (e) e.preventDefault() 114 | 115 | if (!$parent.length) { 116 | $parent = $this.closest('.alert') 117 | } 118 | 119 | $parent.trigger(e = $.Event('close.bs.alert')) 120 | 121 | if (e.isDefaultPrevented()) return 122 | 123 | $parent.removeClass('in') 124 | 125 | function removeElement() { 126 | // detach from parent, fire event then clean up data 127 | $parent.detach().trigger('closed.bs.alert').remove() 128 | } 129 | 130 | $.support.transition && $parent.hasClass('fade') ? 131 | $parent 132 | .one('bsTransitionEnd', removeElement) 133 | .emulateTransitionEnd(Alert.TRANSITION_DURATION) : 134 | removeElement() 135 | } 136 | 137 | 138 | // ALERT PLUGIN DEFINITION 139 | // ======================= 140 | 141 | function Plugin(option) { 142 | return this.each(function () { 143 | var $this = $(this) 144 | var data = $this.data('bs.alert') 145 | 146 | if (!data) $this.data('bs.alert', (data = new Alert(this))) 147 | if (typeof option == 'string') data[option].call($this) 148 | }) 149 | } 150 | 151 | var old = $.fn.alert 152 | 153 | $.fn.alert = Plugin 154 | $.fn.alert.Constructor = Alert 155 | 156 | 157 | // ALERT NO CONFLICT 158 | // ================= 159 | 160 | $.fn.alert.noConflict = function () { 161 | $.fn.alert = old 162 | return this 163 | } 164 | 165 | 166 | // ALERT DATA-API 167 | // ============== 168 | 169 | $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) 170 | 171 | }(jQuery); 172 | 173 | /* ======================================================================== 174 | * Bootstrap: button.js v3.3.1 175 | * http://getbootstrap.com/javascript/#buttons 176 | * ======================================================================== 177 | * Copyright 2011-2014 Twitter, Inc. 178 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 179 | * ======================================================================== */ 180 | 181 | 182 | +function ($) { 183 | 'use strict'; 184 | 185 | // BUTTON PUBLIC CLASS DEFINITION 186 | // ============================== 187 | 188 | var Button = function (element, options) { 189 | this.$element = $(element) 190 | this.options = $.extend({}, Button.DEFAULTS, options) 191 | this.isLoading = false 192 | } 193 | 194 | Button.VERSION = '3.3.1' 195 | 196 | Button.DEFAULTS = { 197 | loadingText: 'loading...' 198 | } 199 | 200 | Button.prototype.setState = function (state) { 201 | var d = 'disabled' 202 | var $el = this.$element 203 | var val = $el.is('input') ? 'val' : 'html' 204 | var data = $el.data() 205 | 206 | state = state + 'Text' 207 | 208 | if (data.resetText == null) $el.data('resetText', $el[val]()) 209 | 210 | // push to event loop to allow forms to submit 211 | setTimeout($.proxy(function () { 212 | $el[val](data[state] == null ? this.options[state] : data[state]) 213 | 214 | if (state == 'loadingText') { 215 | this.isLoading = true 216 | $el.addClass(d).attr(d, d) 217 | } else if (this.isLoading) { 218 | this.isLoading = false 219 | $el.removeClass(d).removeAttr(d) 220 | } 221 | }, this), 0) 222 | } 223 | 224 | Button.prototype.toggle = function () { 225 | var changed = true 226 | var $parent = this.$element.closest('[data-toggle="buttons"]') 227 | 228 | if ($parent.length) { 229 | var $input = this.$element.find('input') 230 | if ($input.prop('type') == 'radio') { 231 | if ($input.prop('checked') && this.$element.hasClass('active')) changed = false 232 | else $parent.find('.active').removeClass('active') 233 | } 234 | if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') 235 | } else { 236 | this.$element.attr('aria-pressed', !this.$element.hasClass('active')) 237 | } 238 | 239 | if (changed) this.$element.toggleClass('active') 240 | } 241 | 242 | 243 | // BUTTON PLUGIN DEFINITION 244 | // ======================== 245 | 246 | function Plugin(option) { 247 | return this.each(function () { 248 | var $this = $(this) 249 | var data = $this.data('bs.button') 250 | var options = typeof option == 'object' && option 251 | 252 | if (!data) $this.data('bs.button', (data = new Button(this, options))) 253 | 254 | if (option == 'toggle') data.toggle() 255 | else if (option) data.setState(option) 256 | }) 257 | } 258 | 259 | var old = $.fn.button 260 | 261 | $.fn.button = Plugin 262 | $.fn.button.Constructor = Button 263 | 264 | 265 | // BUTTON NO CONFLICT 266 | // ================== 267 | 268 | $.fn.button.noConflict = function () { 269 | $.fn.button = old 270 | return this 271 | } 272 | 273 | 274 | // BUTTON DATA-API 275 | // =============== 276 | 277 | $(document) 278 | .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { 279 | var $btn = $(e.target) 280 | if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') 281 | Plugin.call($btn, 'toggle') 282 | e.preventDefault() 283 | }) 284 | .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { 285 | $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) 286 | }) 287 | 288 | }(jQuery); 289 | 290 | /* ======================================================================== 291 | * Bootstrap: carousel.js v3.3.1 292 | * http://getbootstrap.com/javascript/#carousel 293 | * ======================================================================== 294 | * Copyright 2011-2014 Twitter, Inc. 295 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 296 | * ======================================================================== */ 297 | 298 | 299 | +function ($) { 300 | 'use strict'; 301 | 302 | // CAROUSEL CLASS DEFINITION 303 | // ========================= 304 | 305 | var Carousel = function (element, options) { 306 | this.$element = $(element) 307 | this.$indicators = this.$element.find('.carousel-indicators') 308 | this.options = options 309 | this.paused = 310 | this.sliding = 311 | this.interval = 312 | this.$active = 313 | this.$items = null 314 | 315 | this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) 316 | 317 | this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element 318 | .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) 319 | .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) 320 | } 321 | 322 | Carousel.VERSION = '3.3.1' 323 | 324 | Carousel.TRANSITION_DURATION = 600 325 | 326 | Carousel.DEFAULTS = { 327 | interval: 5000, 328 | pause: 'hover', 329 | wrap: true, 330 | keyboard: true 331 | } 332 | 333 | Carousel.prototype.keydown = function (e) { 334 | if (/input|textarea/i.test(e.target.tagName)) return 335 | switch (e.which) { 336 | case 37: this.prev(); break 337 | case 39: this.next(); break 338 | default: return 339 | } 340 | 341 | e.preventDefault() 342 | } 343 | 344 | Carousel.prototype.cycle = function (e) { 345 | e || (this.paused = false) 346 | 347 | this.interval && clearInterval(this.interval) 348 | 349 | this.options.interval 350 | && !this.paused 351 | && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) 352 | 353 | return this 354 | } 355 | 356 | Carousel.prototype.getItemIndex = function (item) { 357 | this.$items = item.parent().children('.item') 358 | return this.$items.index(item || this.$active) 359 | } 360 | 361 | Carousel.prototype.getItemForDirection = function (direction, active) { 362 | var delta = direction == 'prev' ? -1 : 1 363 | var activeIndex = this.getItemIndex(active) 364 | var itemIndex = (activeIndex + delta) % this.$items.length 365 | return this.$items.eq(itemIndex) 366 | } 367 | 368 | Carousel.prototype.to = function (pos) { 369 | var that = this 370 | var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) 371 | 372 | if (pos > (this.$items.length - 1) || pos < 0) return 373 | 374 | if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" 375 | if (activeIndex == pos) return this.pause().cycle() 376 | 377 | return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) 378 | } 379 | 380 | Carousel.prototype.pause = function (e) { 381 | e || (this.paused = true) 382 | 383 | if (this.$element.find('.next, .prev').length && $.support.transition) { 384 | this.$element.trigger($.support.transition.end) 385 | this.cycle(true) 386 | } 387 | 388 | this.interval = clearInterval(this.interval) 389 | 390 | return this 391 | } 392 | 393 | Carousel.prototype.next = function () { 394 | if (this.sliding) return 395 | return this.slide('next') 396 | } 397 | 398 | Carousel.prototype.prev = function () { 399 | if (this.sliding) return 400 | return this.slide('prev') 401 | } 402 | 403 | Carousel.prototype.slide = function (type, next) { 404 | var $active = this.$element.find('.item.active') 405 | var $next = next || this.getItemForDirection(type, $active) 406 | var isCycling = this.interval 407 | var direction = type == 'next' ? 'left' : 'right' 408 | var fallback = type == 'next' ? 'first' : 'last' 409 | var that = this 410 | 411 | if (!$next.length) { 412 | if (!this.options.wrap) return 413 | $next = this.$element.find('.item')[fallback]() 414 | } 415 | 416 | if ($next.hasClass('active')) return (this.sliding = false) 417 | 418 | var relatedTarget = $next[0] 419 | var slideEvent = $.Event('slide.bs.carousel', { 420 | relatedTarget: relatedTarget, 421 | direction: direction 422 | }) 423 | this.$element.trigger(slideEvent) 424 | if (slideEvent.isDefaultPrevented()) return 425 | 426 | this.sliding = true 427 | 428 | isCycling && this.pause() 429 | 430 | if (this.$indicators.length) { 431 | this.$indicators.find('.active').removeClass('active') 432 | var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) 433 | $nextIndicator && $nextIndicator.addClass('active') 434 | } 435 | 436 | var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" 437 | if ($.support.transition && this.$element.hasClass('slide')) { 438 | $next.addClass(type) 439 | $next[0].offsetWidth // force reflow 440 | $active.addClass(direction) 441 | $next.addClass(direction) 442 | $active 443 | .one('bsTransitionEnd', function () { 444 | $next.removeClass([type, direction].join(' ')).addClass('active') 445 | $active.removeClass(['active', direction].join(' ')) 446 | that.sliding = false 447 | setTimeout(function () { 448 | that.$element.trigger(slidEvent) 449 | }, 0) 450 | }) 451 | .emulateTransitionEnd(Carousel.TRANSITION_DURATION) 452 | } else { 453 | $active.removeClass('active') 454 | $next.addClass('active') 455 | this.sliding = false 456 | this.$element.trigger(slidEvent) 457 | } 458 | 459 | isCycling && this.cycle() 460 | 461 | return this 462 | } 463 | 464 | 465 | // CAROUSEL PLUGIN DEFINITION 466 | // ========================== 467 | 468 | function Plugin(option) { 469 | return this.each(function () { 470 | var $this = $(this) 471 | var data = $this.data('bs.carousel') 472 | var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) 473 | var action = typeof option == 'string' ? option : options.slide 474 | 475 | if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) 476 | if (typeof option == 'number') data.to(option) 477 | else if (action) data[action]() 478 | else if (options.interval) data.pause().cycle() 479 | }) 480 | } 481 | 482 | var old = $.fn.carousel 483 | 484 | $.fn.carousel = Plugin 485 | $.fn.carousel.Constructor = Carousel 486 | 487 | 488 | // CAROUSEL NO CONFLICT 489 | // ==================== 490 | 491 | $.fn.carousel.noConflict = function () { 492 | $.fn.carousel = old 493 | return this 494 | } 495 | 496 | 497 | // CAROUSEL DATA-API 498 | // ================= 499 | 500 | var clickHandler = function (e) { 501 | var href 502 | var $this = $(this) 503 | var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 504 | if (!$target.hasClass('carousel')) return 505 | var options = $.extend({}, $target.data(), $this.data()) 506 | var slideIndex = $this.attr('data-slide-to') 507 | if (slideIndex) options.interval = false 508 | 509 | Plugin.call($target, options) 510 | 511 | if (slideIndex) { 512 | $target.data('bs.carousel').to(slideIndex) 513 | } 514 | 515 | e.preventDefault() 516 | } 517 | 518 | $(document) 519 | .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) 520 | .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) 521 | 522 | $(window).on('load', function () { 523 | $('[data-ride="carousel"]').each(function () { 524 | var $carousel = $(this) 525 | Plugin.call($carousel, $carousel.data()) 526 | }) 527 | }) 528 | 529 | }(jQuery); 530 | 531 | /* ======================================================================== 532 | * Bootstrap: collapse.js v3.3.1 533 | * http://getbootstrap.com/javascript/#collapse 534 | * ======================================================================== 535 | * Copyright 2011-2014 Twitter, Inc. 536 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 537 | * ======================================================================== */ 538 | 539 | 540 | +function ($) { 541 | 'use strict'; 542 | 543 | // COLLAPSE PUBLIC CLASS DEFINITION 544 | // ================================ 545 | 546 | var Collapse = function (element, options) { 547 | this.$element = $(element) 548 | this.options = $.extend({}, Collapse.DEFAULTS, options) 549 | this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]') 550 | this.transitioning = null 551 | 552 | if (this.options.parent) { 553 | this.$parent = this.getParent() 554 | } else { 555 | this.addAriaAndCollapsedClass(this.$element, this.$trigger) 556 | } 557 | 558 | if (this.options.toggle) this.toggle() 559 | } 560 | 561 | Collapse.VERSION = '3.3.1' 562 | 563 | Collapse.TRANSITION_DURATION = 350 564 | 565 | Collapse.DEFAULTS = { 566 | toggle: true, 567 | trigger: '[data-toggle="collapse"]' 568 | } 569 | 570 | Collapse.prototype.dimension = function () { 571 | var hasWidth = this.$element.hasClass('width') 572 | return hasWidth ? 'width' : 'height' 573 | } 574 | 575 | Collapse.prototype.show = function () { 576 | if (this.transitioning || this.$element.hasClass('in')) return 577 | 578 | var activesData 579 | var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing') 580 | 581 | if (actives && actives.length) { 582 | activesData = actives.data('bs.collapse') 583 | if (activesData && activesData.transitioning) return 584 | } 585 | 586 | var startEvent = $.Event('show.bs.collapse') 587 | this.$element.trigger(startEvent) 588 | if (startEvent.isDefaultPrevented()) return 589 | 590 | if (actives && actives.length) { 591 | Plugin.call(actives, 'hide') 592 | activesData || actives.data('bs.collapse', null) 593 | } 594 | 595 | var dimension = this.dimension() 596 | 597 | this.$element 598 | .removeClass('collapse') 599 | .addClass('collapsing')[dimension](0) 600 | .attr('aria-expanded', true) 601 | 602 | this.$trigger 603 | .removeClass('collapsed') 604 | .attr('aria-expanded', true) 605 | 606 | this.transitioning = 1 607 | 608 | var complete = function () { 609 | this.$element 610 | .removeClass('collapsing') 611 | .addClass('collapse in')[dimension]('') 612 | this.transitioning = 0 613 | this.$element 614 | .trigger('shown.bs.collapse') 615 | } 616 | 617 | if (!$.support.transition) return complete.call(this) 618 | 619 | var scrollSize = $.camelCase(['scroll', dimension].join('-')) 620 | 621 | this.$element 622 | .one('bsTransitionEnd', $.proxy(complete, this)) 623 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) 624 | } 625 | 626 | Collapse.prototype.hide = function () { 627 | if (this.transitioning || !this.$element.hasClass('in')) return 628 | 629 | var startEvent = $.Event('hide.bs.collapse') 630 | this.$element.trigger(startEvent) 631 | if (startEvent.isDefaultPrevented()) return 632 | 633 | var dimension = this.dimension() 634 | 635 | this.$element[dimension](this.$element[dimension]())[0].offsetHeight 636 | 637 | this.$element 638 | .addClass('collapsing') 639 | .removeClass('collapse in') 640 | .attr('aria-expanded', false) 641 | 642 | this.$trigger 643 | .addClass('collapsed') 644 | .attr('aria-expanded', false) 645 | 646 | this.transitioning = 1 647 | 648 | var complete = function () { 649 | this.transitioning = 0 650 | this.$element 651 | .removeClass('collapsing') 652 | .addClass('collapse') 653 | .trigger('hidden.bs.collapse') 654 | } 655 | 656 | if (!$.support.transition) return complete.call(this) 657 | 658 | this.$element 659 | [dimension](0) 660 | .one('bsTransitionEnd', $.proxy(complete, this)) 661 | .emulateTransitionEnd(Collapse.TRANSITION_DURATION) 662 | } 663 | 664 | Collapse.prototype.toggle = function () { 665 | this[this.$element.hasClass('in') ? 'hide' : 'show']() 666 | } 667 | 668 | Collapse.prototype.getParent = function () { 669 | return $(this.options.parent) 670 | .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') 671 | .each($.proxy(function (i, element) { 672 | var $element = $(element) 673 | this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) 674 | }, this)) 675 | .end() 676 | } 677 | 678 | Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { 679 | var isOpen = $element.hasClass('in') 680 | 681 | $element.attr('aria-expanded', isOpen) 682 | $trigger 683 | .toggleClass('collapsed', !isOpen) 684 | .attr('aria-expanded', isOpen) 685 | } 686 | 687 | function getTargetFromTrigger($trigger) { 688 | var href 689 | var target = $trigger.attr('data-target') 690 | || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 691 | 692 | return $(target) 693 | } 694 | 695 | 696 | // COLLAPSE PLUGIN DEFINITION 697 | // ========================== 698 | 699 | function Plugin(option) { 700 | return this.each(function () { 701 | var $this = $(this) 702 | var data = $this.data('bs.collapse') 703 | var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) 704 | 705 | if (!data && options.toggle && option == 'show') options.toggle = false 706 | if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) 707 | if (typeof option == 'string') data[option]() 708 | }) 709 | } 710 | 711 | var old = $.fn.collapse 712 | 713 | $.fn.collapse = Plugin 714 | $.fn.collapse.Constructor = Collapse 715 | 716 | 717 | // COLLAPSE NO CONFLICT 718 | // ==================== 719 | 720 | $.fn.collapse.noConflict = function () { 721 | $.fn.collapse = old 722 | return this 723 | } 724 | 725 | 726 | // COLLAPSE DATA-API 727 | // ================= 728 | 729 | $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { 730 | var $this = $(this) 731 | 732 | if (!$this.attr('data-target')) e.preventDefault() 733 | 734 | var $target = getTargetFromTrigger($this) 735 | var data = $target.data('bs.collapse') 736 | var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this }) 737 | 738 | Plugin.call($target, option) 739 | }) 740 | 741 | }(jQuery); 742 | 743 | /* ======================================================================== 744 | * Bootstrap: dropdown.js v3.3.1 745 | * http://getbootstrap.com/javascript/#dropdowns 746 | * ======================================================================== 747 | * Copyright 2011-2014 Twitter, Inc. 748 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 749 | * ======================================================================== */ 750 | 751 | 752 | +function ($) { 753 | 'use strict'; 754 | 755 | // DROPDOWN CLASS DEFINITION 756 | // ========================= 757 | 758 | var backdrop = '.dropdown-backdrop' 759 | var toggle = '[data-toggle="dropdown"]' 760 | var Dropdown = function (element) { 761 | $(element).on('click.bs.dropdown', this.toggle) 762 | } 763 | 764 | Dropdown.VERSION = '3.3.1' 765 | 766 | Dropdown.prototype.toggle = function (e) { 767 | var $this = $(this) 768 | 769 | if ($this.is('.disabled, :disabled')) return 770 | 771 | var $parent = getParent($this) 772 | var isActive = $parent.hasClass('open') 773 | 774 | clearMenus() 775 | 776 | if (!isActive) { 777 | if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { 778 | // if mobile we use a backdrop because click events don't delegate 779 | $('