├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── app ├── Commands │ └── Command.php ├── Console │ ├── Commands │ │ └── Inspire.php │ └── Kernel.php ├── Events │ └── Event.php ├── Exceptions │ └── Handler.php ├── Handlers │ ├── Commands │ │ └── .gitkeep │ └── Events │ │ └── .gitkeep ├── Http │ ├── Controllers │ │ ├── Auth │ │ │ ├── AuthController.php │ │ │ └── PasswordController.php │ │ ├── Controller.php │ │ ├── HomeController.php │ │ ├── TodoController.php │ │ ├── UserController.php │ │ └── WelcomeController.php │ ├── Kernel.php │ ├── Middleware │ │ ├── Authenticate.php │ │ ├── RedirectIfAuthenticated.php │ │ └── VerifyCsrfToken.php │ ├── Requests │ │ └── Request.php │ └── routes.php ├── Providers │ ├── AppServiceProvider.php │ ├── BusServiceProvider.php │ ├── ConfigServiceProvider.php │ ├── EventServiceProvider.php │ └── RouteServiceProvider.php ├── Services │ └── Registrar.php ├── Todo.php └── User.php ├── artisan ├── bootstrap ├── app.php └── autoload.php ├── composer.json ├── config ├── app.php ├── auth.php ├── cache.php ├── compile.php ├── database.php ├── filesystems.php ├── jwt.php ├── mail.php ├── queue.php ├── services.php ├── session.php └── view.php ├── database ├── .gitignore ├── migrations │ ├── .gitkeep │ ├── 2014_10_12_000000_create_users_table.php │ ├── 2014_10_12_100000_create_password_resets_table.php │ └── 2015_02_26_065521_create_todos_table.php └── seeds │ ├── .gitkeep │ └── DatabaseSeeder.php ├── gulpfile.js ├── package.json ├── phpspec.yml ├── phpunit.xml ├── public ├── .htaccess ├── favicon.ico ├── index.php └── robots.txt ├── resources ├── css │ ├── foundation-icons.css │ ├── foundation.min.css │ ├── normalize.css │ └── style.css ├── fonts │ ├── foundation-icons.eot │ ├── foundation-icons.svg │ ├── foundation-icons.ttf │ └── foundation-icons.woff ├── js │ ├── app.js │ ├── appRoutes.js │ ├── controllers │ │ ├── MainController.js │ │ ├── TodoController.js │ │ └── UserController.js │ ├── directives │ │ └── enterStroke.js │ ├── libs │ │ ├── angular.js │ │ ├── angular_modules │ │ │ ├── angular-resource.js │ │ │ ├── angular-route.js │ │ │ └── ng-storage.js │ │ ├── fastclick.js │ │ ├── foundation │ │ │ └── foundation.min.js │ │ ├── jquery.js │ │ └── modernizr.js │ └── services │ │ ├── TodoService.js │ │ └── UserService.js ├── lang │ └── en │ │ ├── pagination.php │ │ ├── passwords.php │ │ └── validation.php └── views │ ├── errors │ └── 503.blade.php │ ├── layout.blade.php │ └── partials │ ├── auth │ ├── login.php │ └── signup.php │ ├── index.php │ ├── todos │ ├── create.php │ ├── index.php │ └── view.php │ └── users │ └── view.php ├── server.php ├── storage ├── .gitignore ├── app │ └── .gitignore ├── framework │ ├── .gitignore │ ├── cache │ │ └── .gitignore │ ├── sessions │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore └── tests ├── ExampleTest.php └── TestCase.php /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | .env 3 | /public/css 4 | /public/js 5 | /public/build 6 | 7 | # Created by https://www.gitignore.io 8 | 9 | ### Laravel ### 10 | /bootstrap/compiled.php 11 | .env.*.php 12 | .env.php 13 | 14 | 15 | ### Composer ### 16 | composer.phar 17 | vendor/ 18 | 19 | # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file 20 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 21 | # composer.lock 22 | 23 | 24 | ### Intellij ### 25 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm 26 | 27 | *.iml 28 | 29 | ## Directory-based project format: 30 | .idea/ 31 | # if you remove the above rule, at least ignore the following: 32 | 33 | # User-specific stuff: 34 | # .idea/workspace.xml 35 | # .idea/tasks.xml 36 | # .idea/dictionaries 37 | 38 | # Sensitive or high-churn files: 39 | # .idea/dataSources.ids 40 | # .idea/dataSources.xml 41 | # .idea/sqlDataSources.xml 42 | # .idea/dynamic.xml 43 | # .idea/uiDesigner.xml 44 | 45 | # Gradle: 46 | # .idea/gradle.xml 47 | # .idea/libraries 48 | 49 | # Mongo Explorer plugin: 50 | # .idea/mongoSettings.xml 51 | 52 | ## File-based project format: 53 | *.ipr 54 | *.iws 55 | 56 | ## Plugin-specific files: 57 | 58 | # IntelliJ 59 | out/ 60 | 61 | # mpeltonen/sbt-idea plugin 62 | .idea_modules/ 63 | 64 | # JIRA plugin 65 | atlassian-ide-plugin.xml 66 | 67 | # Crashlytics plugin (for Android Studio and IntelliJ) 68 | com_crashlytics_export_strings.xml 69 | crashlytics.properties 70 | crashlytics-build.properties 71 | composer.lock 72 | -------------------------------------------------------------------------------- /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 | # Laravel, AngularJS and Foundation starter kit 2 | 3 | This is a starter kit for a Single Page Application featuring the modern Laravel PHP framework and Google’s acclaimed front-end framework AngularJS, featured with Foundation 5.5 for the GUI. Just download and play with it to build something great! 4 | 5 | ## Features! 6 | The "engine" (Laravel and Angular) are powered from [the repository 'starter-laravel-angular' by Zemke](https://github.com/Zemke/starter-laravel-angular). 7 | 8 | - Single Page Application 9 | - HTML5 mode URLs 10 | - Optimized Laravel and AngularJS routes 11 | - You kind of don’t need to care about routes, they work automatically as you add new views. Still allows for flexibility if you plan any special routes. 12 | - Authentication! 13 | - Flexible, extensible, clean 14 | - Token-based (![tymondesigns/jwt-auth](https://github.com/tymondesigns/jwt-auth)) 15 | - Persistent local storage 16 | - Larevel Elixir readily configured 17 | - Versioning of CSS and JS files (cache busting) 18 | - CSS and JS files will be included automatically 19 | - A whole ready CRUD architecture 20 | - Comes with Bootstrap and AngularJS configured to work together at their best 21 | - And more... have a try! 22 | 23 | ## Installation 24 | Clone the repository 25 | ``` 26 | git clone https://github.com/JulienBernard/starter-laravel-angular-foundation 27 | ``` 28 | Install the requirements 29 | ``` 30 | composer install --prefer-dist 31 | ``` 32 | ``` 33 | npm install 34 | ``` 35 | Laravel stuff: use `artisan` to create the database (see database/migrations/) 36 | ``` 37 | php artisan migrate 38 | ``` 39 | Compile and watch any changes 40 | ``` 41 | gulp 42 | ``` 43 | ``` 44 | gulp watch 45 | ``` 46 | Create an access at localhost:8080 47 | ``` 48 | php -S localhost:8080 -t public 49 | ``` 50 | 51 | Edit `.env.example` according to your environment and save as `.env`. 52 | 53 | ## Requirements 54 | 55 | - PHP >= 5.4 56 | - Composer 57 | - Gulp 58 | - NPM 59 | - MySQL 60 | 61 | ## Notices 62 | For now, Foundation was added with it CSS files. Soon, I will pass on SASS files for more flexibility. 63 | 64 | Have fun! Any feedback is welcome: use Issues. 65 | 66 | ![Laravel](https://cloud.githubusercontent.com/assets/3391981/6683259/2e914726-cc84-11e4-856c-bb26bda733a0.png) 67 | ![AngularJS](https://cloud.githubusercontent.com/assets/3391981/6683229/9e0ea694-cc83-11e4-9b2e-59524dafd069.jpg)![Foundation](http://foundation.zurb.com/assets/img/support/goodies/why-the-yeti.svg) 68 | -------------------------------------------------------------------------------- /app/Commands/Command.php: -------------------------------------------------------------------------------- 1 | comment(PHP_EOL.Inspiring::quote().PHP_EOL); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire') 26 | ->hourly(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /app/Events/Event.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 33 | $this->registrar = $registrar; 34 | 35 | $this->middleware('guest', ['except' => 'getLogout']); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/Http/Controllers/Auth/PasswordController.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 33 | $this->passwords = $passwords; 34 | 35 | $this->middleware('guest'); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 24 | } 25 | 26 | /** 27 | * Show the application dashboard to the user. 28 | * 29 | * @return Response 30 | */ 31 | public function index() 32 | { 33 | return view('home'); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/Http/Controllers/TodoController.php: -------------------------------------------------------------------------------- 1 | request = $request; 15 | } 16 | 17 | 18 | /** 19 | * Display a listing of the resource. 20 | * 21 | * @return Response 22 | */ 23 | public function index() 24 | { 25 | return Todo::all(); 26 | } 27 | 28 | /** 29 | * Show the form for creating a new resource. 30 | * 31 | * @return Response 32 | */ 33 | public function create() 34 | { 35 | // 36 | } 37 | 38 | /** 39 | * Store a newly created resource in storage. 40 | * 41 | * @return Response 42 | */ 43 | public function store() 44 | { 45 | $input = $this->request->all(); 46 | $todo = new Todo($input); 47 | if (!$todo->save()) { 48 | abort(500, "Saving failed."); 49 | } 50 | return $todo; 51 | } 52 | 53 | /** 54 | * Display the specified resource. 55 | * 56 | * @param int $id 57 | * @return Response 58 | */ 59 | public function show($id) 60 | { 61 | return Todo::find($id); 62 | } 63 | 64 | /** 65 | * Show the form for editing the specified resource. 66 | * 67 | * @param int $id 68 | * @return Response 69 | */ 70 | public function edit($id) 71 | { 72 | // 73 | } 74 | 75 | /** 76 | * Update the specified resource in storage. 77 | * 78 | * @param int $id 79 | * @return Response 80 | */ 81 | public function update($id) 82 | { 83 | $todo = Todo::find($id); 84 | $todo->body = $this->request->input('body'); 85 | if (!$todo->save()) { 86 | abort(500, "Saving failed"); 87 | } 88 | return $todo; 89 | } 90 | 91 | /** 92 | * Remove the specified resource from storage. 93 | * 94 | * @param int $id 95 | * @return Response 96 | */ 97 | public function destroy($id) 98 | { 99 | return Todo::destroy($id); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /app/Http/Controllers/UserController.php: -------------------------------------------------------------------------------- 1 | req = $request; 19 | $this->user = $user; 20 | $this->res = $responseFactory; 21 | $this->jwtAuth = $jwtAuth; 22 | } 23 | 24 | /** 25 | * Log a user in. 26 | * 27 | * @return Response 28 | */ 29 | public function login() 30 | { 31 | $user = $this->user->authenticate( 32 | $this->req->input('username'), $this->req->input('password')); 33 | if (!$user) { 34 | return $this->res->json([ 35 | 'code' => null, 36 | 'message' => 'Login failed', 37 | 'description' => 'Wrong username/password.' 38 | 39 | ], Response::HTTP_UNPROCESSABLE_ENTITY); 40 | } 41 | $user['token'] = $this->jwtAuth->fromUser($user); 42 | return $this->res->json($user, Response::HTTP_OK); 43 | } 44 | 45 | /** 46 | * Get a user by the token from the header. 47 | * 48 | * @return Response 49 | */ 50 | public function getByToken() 51 | { 52 | return $this->jwtAuth->parseToken()->authenticate(); 53 | } 54 | 55 | /** 56 | * Display a listing of the resource. 57 | * 58 | * @return Response 59 | */ 60 | public function index() 61 | { 62 | // 63 | } 64 | 65 | /** 66 | * Show the form for creating a new resource. 67 | * 68 | * @return Response 69 | */ 70 | public function create() 71 | { 72 | // 73 | } 74 | 75 | /** 76 | * Store a newly created resource in storage. 77 | * 78 | * @return Response 79 | */ 80 | public function store() 81 | { 82 | $user = new User($this->req->all()); 83 | if (!$user->save()) { 84 | abort(500, 'Could not save user.'); 85 | } 86 | $user['token'] = $this->jwtAuth->fromUser($user); 87 | return $user; 88 | } 89 | 90 | /** 91 | * Display the specified resource. 92 | * 93 | * @param int $id 94 | * @return Response 95 | */ 96 | public function show($id) 97 | { 98 | return User::find($id); 99 | } 100 | 101 | /** 102 | * Show the form for editing the specified resource. 103 | * 104 | * @param int $id 105 | * @return Response 106 | */ 107 | public function edit($id) 108 | { 109 | // 110 | } 111 | 112 | /** 113 | * Update the specified resource in storage. 114 | * 115 | * @param int $id 116 | * @return Response 117 | */ 118 | public function update($id) 119 | { 120 | // 121 | } 122 | 123 | /** 124 | * Remove the specified resource from storage. 125 | * 126 | * @param int $id 127 | * @return Response 128 | */ 129 | public function destroy($id) 130 | { 131 | // 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /app/Http/Controllers/WelcomeController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 24 | } 25 | 26 | /** 27 | * Show the application welcome screen to the user. 28 | * 29 | * @return Response 30 | */ 31 | public function index() 32 | { 33 | return view('welcome'); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/Http/Kernel.php: -------------------------------------------------------------------------------- 1 | 'Todo\Http\Middleware\Authenticate', 28 | 'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth', 29 | 'guest' => 'Todo\Http\Middleware\RedirectIfAuthenticated', 30 | ]; 31 | 32 | } 33 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 24 | } 25 | 26 | /** 27 | * Handle an incoming request. 28 | * 29 | * @param \Illuminate\Http\Request $request 30 | * @param \Closure $next 31 | * @return mixed 32 | */ 33 | public function handle($request, Closure $next) 34 | { 35 | if ($this->auth->guest()) 36 | { 37 | if ($request->ajax()) 38 | { 39 | return response('Unauthorized.', 401); 40 | } 41 | else 42 | { 43 | return redirect()->guest('auth/login'); 44 | } 45 | } 46 | 47 | return $next($request); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/Http/Middleware/RedirectIfAuthenticated.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 25 | } 26 | 27 | /** 28 | * Handle an incoming request. 29 | * 30 | * @param \Illuminate\Http\Request $request 31 | * @param \Closure $next 32 | * @return mixed 33 | */ 34 | public function handle($request, Closure $next) 35 | { 36 | if ($this->auth->check()) 37 | { 38 | return new RedirectResponse(url('/')); 39 | } 40 | 41 | return $next($request); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/Http/Middleware/VerifyCsrfToken.php: -------------------------------------------------------------------------------- 1 | where('undefinedRoute', '([A-z\d-\/_.]+)?'); 42 | 43 | // Using different syntax for Blade to avoid conflicts with Jade. 44 | // You are well-advised to go without any Blade at all. 45 | Blade::setContentTags('<%', '%>'); // For variables and all things Blade. 46 | Blade::setEscapedContentTags('<%%', '%%>'); // For escaped data. 47 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->bind( 29 | 'Illuminate\Contracts\Auth\Registrar', 30 | 'Todo\Services\Registrar' 31 | ); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/Providers/BusServiceProvider.php: -------------------------------------------------------------------------------- 1 | mapUsing(function($command) 17 | { 18 | return Dispatcher::simpleMapping( 19 | $command, 'Todo\Commands', 'Todo\Handlers\Commands' 20 | ); 21 | }); 22 | } 23 | 24 | /** 25 | * Register any application services. 26 | * 27 | * @return void 28 | */ 29 | public function register() 30 | { 31 | // 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /app/Providers/ConfigServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'EventListener', 19 | ], 20 | ]; 21 | 22 | /** 23 | * Register any other events for your application. 24 | * 25 | * @param \Illuminate\Contracts\Events\Dispatcher $events 26 | * @return void 27 | */ 28 | public function boot(DispatcherContract $events) 29 | { 30 | parent::boot($events); 31 | 32 | User::creating(function ($user) { 33 | if (isset($user->password)) { 34 | $user->password = Hash::make($user->password); 35 | } 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/Providers/RouteServiceProvider.php: -------------------------------------------------------------------------------- 1 | group(['namespace' => $this->namespace], function($router) 39 | { 40 | require app_path('Http/routes.php'); 41 | }); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/Services/Registrar.php: -------------------------------------------------------------------------------- 1 | 'required|max:255', 19 | 'email' => 'required|email|max:255|unique:users', 20 | 'password' => 'required|confirmed|min:6', 21 | ]); 22 | } 23 | 24 | /** 25 | * Create a new user instance after a valid registration. 26 | * 27 | * @param array $data 28 | * @return User 29 | */ 30 | public function create(array $data) 31 | { 32 | return User::create([ 33 | 'name' => $data['name'], 34 | 'email' => $data['email'], 35 | 'password' => bcrypt($data['password']), 36 | ]); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/Todo.php: -------------------------------------------------------------------------------- 1 | first(); 46 | if (!Hash::check($password, $user->password)) { 47 | return false; 48 | } 49 | return $user; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make('Illuminate\Contracts\Console\Kernel'); 32 | 33 | $status = $kernel->handle( 34 | $input = new Symfony\Component\Console\Input\ArgvInput, 35 | new Symfony\Component\Console\Output\ConsoleOutput 36 | ); 37 | 38 | /* 39 | |-------------------------------------------------------------------------- 40 | | Shutdown The Application 41 | |-------------------------------------------------------------------------- 42 | | 43 | | Once Artisan has finished running. We will fire off the shutdown events 44 | | so that any final work may be done by the application before we shut 45 | | down the process. This is the last thing to happen to the request. 46 | | 47 | */ 48 | 49 | $kernel->terminate($input, $status); 50 | 51 | exit($status); 52 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | singleton( 30 | 'Illuminate\Contracts\Http\Kernel', 31 | 'Todo\Http\Kernel' 32 | ); 33 | 34 | $app->singleton( 35 | 'Illuminate\Contracts\Console\Kernel', 36 | 'Todo\Console\Kernel' 37 | ); 38 | 39 | $app->singleton( 40 | 'Illuminate\Contracts\Debug\ExceptionHandler', 41 | 'Todo\Exceptions\Handler' 42 | ); 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Return The Application 47 | |-------------------------------------------------------------------------- 48 | | 49 | | This script returns the application instance. The instance is given to 50 | | the calling script so we can separate the building of the instances 51 | | from the actual running of the application and sending responses. 52 | | 53 | */ 54 | 55 | return $app; 56 | -------------------------------------------------------------------------------- /bootstrap/autoload.php: -------------------------------------------------------------------------------- 1 | env('APP_DEBUG'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Application URL 21 | |-------------------------------------------------------------------------- 22 | | 23 | | This URL is used by the console to properly generate URLs when using 24 | | the Artisan command line tool. You should set this to the root of 25 | | your application so that it is used when running Artisan tasks. 26 | | 27 | */ 28 | 29 | 'url' => 'http://localhost', 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Application Timezone 34 | |-------------------------------------------------------------------------- 35 | | 36 | | Here you may specify the default timezone for your application, which 37 | | will be used by the PHP date and date-time functions. We have gone 38 | | ahead and set this to a sensible default for you out of the box. 39 | | 40 | */ 41 | 42 | 'timezone' => 'UTC', 43 | 44 | /* 45 | |-------------------------------------------------------------------------- 46 | | Application Locale Configuration 47 | |-------------------------------------------------------------------------- 48 | | 49 | | The application locale determines the default locale that will be used 50 | | by the translation service provider. You are free to set this value 51 | | to any of the locales which will be supported by the application. 52 | | 53 | */ 54 | 55 | 'locale' => 'en', 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | Application Fallback Locale 60 | |-------------------------------------------------------------------------- 61 | | 62 | | The fallback locale determines the locale to use when the current one 63 | | is not available. You may change the value to correspond to any of 64 | | the language folders that are provided through your application. 65 | | 66 | */ 67 | 68 | 'fallback_locale' => 'en', 69 | 70 | /* 71 | |-------------------------------------------------------------------------- 72 | | Encryption Key 73 | |-------------------------------------------------------------------------- 74 | | 75 | | This key is used by the Illuminate encrypter service and should be set 76 | | to a random, 32 character string, otherwise these encrypted strings 77 | | will not be safe. Please do this before deploying an application! 78 | | 79 | */ 80 | 81 | 'key' => env('APP_KEY', 'SomeRandomString'), 82 | 83 | 'cipher' => MCRYPT_RIJNDAEL_128, 84 | 85 | /* 86 | |-------------------------------------------------------------------------- 87 | | Logging Configuration 88 | |-------------------------------------------------------------------------- 89 | | 90 | | Here you may configure the log settings for your application. Out of 91 | | the box, Laravel uses the Monolog PHP logging library. This gives 92 | | you a variety of powerful log handlers / formatters to utilize. 93 | | 94 | | Available Settings: "single", "daily", "syslog", "errorlog" 95 | | 96 | */ 97 | 98 | 'log' => 'daily', 99 | 100 | /* 101 | |-------------------------------------------------------------------------- 102 | | Autoloaded Service Providers 103 | |-------------------------------------------------------------------------- 104 | | 105 | | The service providers listed here will be automatically loaded on the 106 | | request to your application. Feel free to add your own services to 107 | | this array to grant expanded functionality to your applications. 108 | | 109 | */ 110 | 111 | 'providers' => [ 112 | 113 | /* 114 | * Laravel Framework Service Providers... 115 | */ 116 | 'Illuminate\Foundation\Providers\ArtisanServiceProvider', 117 | 'Illuminate\Auth\AuthServiceProvider', 118 | 'Illuminate\Bus\BusServiceProvider', 119 | 'Illuminate\Cache\CacheServiceProvider', 120 | 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', 121 | 'Illuminate\Routing\ControllerServiceProvider', 122 | 'Illuminate\Cookie\CookieServiceProvider', 123 | 'Illuminate\Database\DatabaseServiceProvider', 124 | 'Illuminate\Encryption\EncryptionServiceProvider', 125 | 'Illuminate\Filesystem\FilesystemServiceProvider', 126 | 'Illuminate\Foundation\Providers\FoundationServiceProvider', 127 | 'Illuminate\Hashing\HashServiceProvider', 128 | 'Illuminate\Mail\MailServiceProvider', 129 | 'Illuminate\Pagination\PaginationServiceProvider', 130 | 'Illuminate\Pipeline\PipelineServiceProvider', 131 | 'Illuminate\Queue\QueueServiceProvider', 132 | 'Illuminate\Redis\RedisServiceProvider', 133 | 'Illuminate\Auth\Passwords\PasswordResetServiceProvider', 134 | 'Illuminate\Session\SessionServiceProvider', 135 | 'Illuminate\Translation\TranslationServiceProvider', 136 | 'Illuminate\Validation\ValidationServiceProvider', 137 | 'Illuminate\View\ViewServiceProvider', 138 | 139 | /* 140 | * Application Service Providers... 141 | */ 142 | 'Todo\Providers\AppServiceProvider', 143 | 'Todo\Providers\BusServiceProvider', 144 | 'Todo\Providers\ConfigServiceProvider', 145 | 'Todo\Providers\EventServiceProvider', 146 | 'Todo\Providers\RouteServiceProvider', 147 | 148 | /* 149 | * JSON Web Token (Authentication) 150 | */ 151 | 'Tymon\JWTAuth\Providers\JWTAuthServiceProvider', 152 | 153 | ], 154 | 155 | /* 156 | |-------------------------------------------------------------------------- 157 | | Class Aliases 158 | |-------------------------------------------------------------------------- 159 | | 160 | | This array of class aliases will be registered when this application 161 | | is started. However, feel free to register as many as you wish as 162 | | the aliases are "lazy" loaded so they don't hinder performance. 163 | | 164 | */ 165 | 166 | 'aliases' => [ 167 | 168 | 'App' => 'Illuminate\Support\Facades\App', 169 | 'Artisan' => 'Illuminate\Support\Facades\Artisan', 170 | 'Auth' => 'Illuminate\Support\Facades\Auth', 171 | 'Blade' => 'Illuminate\Support\Facades\Blade', 172 | 'Bus' => 'Illuminate\Support\Facades\Bus', 173 | 'Cache' => 'Illuminate\Support\Facades\Cache', 174 | 'Config' => 'Illuminate\Support\Facades\Config', 175 | 'Cookie' => 'Illuminate\Support\Facades\Cookie', 176 | 'Crypt' => 'Illuminate\Support\Facades\Crypt', 177 | 'DB' => 'Illuminate\Support\Facades\DB', 178 | 'Eloquent' => 'Illuminate\Database\Eloquent\Model', 179 | 'Event' => 'Illuminate\Support\Facades\Event', 180 | 'File' => 'Illuminate\Support\Facades\File', 181 | 'Hash' => 'Illuminate\Support\Facades\Hash', 182 | 'Input' => 'Illuminate\Support\Facades\Input', 183 | 'Inspiring' => 'Illuminate\Foundation\Inspiring', 184 | 'Lang' => 'Illuminate\Support\Facades\Lang', 185 | 'Log' => 'Illuminate\Support\Facades\Log', 186 | 'Mail' => 'Illuminate\Support\Facades\Mail', 187 | 'Password' => 'Illuminate\Support\Facades\Password', 188 | 'Queue' => 'Illuminate\Support\Facades\Queue', 189 | 'Redirect' => 'Illuminate\Support\Facades\Redirect', 190 | 'Redis' => 'Illuminate\Support\Facades\Redis', 191 | 'Request' => 'Illuminate\Support\Facades\Request', 192 | 'Response' => 'Illuminate\Support\Facades\Response', 193 | 'Route' => 'Illuminate\Support\Facades\Route', 194 | 'Schema' => 'Illuminate\Support\Facades\Schema', 195 | 'Session' => 'Illuminate\Support\Facades\Session', 196 | 'Storage' => 'Illuminate\Support\Facades\Storage', 197 | 'URL' => 'Illuminate\Support\Facades\URL', 198 | 'Validator' => 'Illuminate\Support\Facades\Validator', 199 | 'View' => 'Illuminate\Support\Facades\View', 200 | 201 | 'JWTAuth' => 'Tymon\JWTAuth\Facades\JWTAuth', 202 | 203 | ], 204 | 205 | ]; 206 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | 'eloquent', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Authentication Model 23 | |-------------------------------------------------------------------------- 24 | | 25 | | When using the "Eloquent" authentication driver, we need to know which 26 | | Eloquent model should be used to retrieve your users. Of course, it 27 | | is often just the "User" model but you may use whatever you like. 28 | | 29 | */ 30 | 31 | 'model' => 'Todo\User', 32 | 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | Authentication Table 36 | |-------------------------------------------------------------------------- 37 | | 38 | | When using the "Database" authentication driver, we need to know which 39 | | table should be used to retrieve your users. We have chosen a basic 40 | | default value but you may easily change it to any table you like. 41 | | 42 | */ 43 | 44 | 'table' => 'users', 45 | 46 | /* 47 | |-------------------------------------------------------------------------- 48 | | Password Reset Settings 49 | |-------------------------------------------------------------------------- 50 | | 51 | | Here you may set the options for resetting passwords including the view 52 | | that is your password reset e-mail. You can also set the name of the 53 | | table that maintains all of the reset tokens for your application. 54 | | 55 | | The expire time is the number of minutes that the reset token should be 56 | | considered valid. This security feature keeps tokens short-lived so 57 | | they have less time to be guessed. You may change this as needed. 58 | | 59 | */ 60 | 61 | 'password' => [ 62 | 'email' => 'emails.password', 63 | 'table' => 'password_resets', 64 | 'expire' => 60, 65 | ], 66 | 67 | ]; 68 | -------------------------------------------------------------------------------- /config/cache.php: -------------------------------------------------------------------------------- 1 | env('CACHE_DRIVER', 'file'), 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Cache Stores 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may define all of the cache "stores" for your application as 24 | | well as their drivers. You may even define multiple stores for the 25 | | same cache driver to group types of items stored in your caches. 26 | | 27 | */ 28 | 29 | 'stores' => [ 30 | 31 | 'apc' => [ 32 | 'driver' => 'apc' 33 | ], 34 | 35 | 'array' => [ 36 | 'driver' => 'array' 37 | ], 38 | 39 | 'database' => [ 40 | 'driver' => 'database', 41 | 'table' => 'cache', 42 | 'connection' => null, 43 | ], 44 | 45 | 'file' => [ 46 | 'driver' => 'file', 47 | 'path' => storage_path().'/framework/cache', 48 | ], 49 | 50 | 'memcached' => [ 51 | 'driver' => 'memcached', 52 | 'servers' => [ 53 | [ 54 | 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100 55 | ], 56 | ], 57 | ], 58 | 59 | 'redis' => [ 60 | 'driver' => 'redis', 61 | 'connection' => 'default', 62 | ], 63 | 64 | ], 65 | 66 | /* 67 | |-------------------------------------------------------------------------- 68 | | Cache Key Prefix 69 | |-------------------------------------------------------------------------- 70 | | 71 | | When utilizing a RAM based store such as APC or Memcached, there might 72 | | be other applications utilizing the same cache. So, we'll specify a 73 | | value to get prefixed to all our keys so we can avoid collisions. 74 | | 75 | */ 76 | 77 | 'prefix' => 'laravel', 78 | 79 | ]; 80 | -------------------------------------------------------------------------------- /config/compile.php: -------------------------------------------------------------------------------- 1 | [ 17 | 18 | realpath(__DIR__.'/../app/Providers/AppServiceProvider.php'), 19 | realpath(__DIR__.'/../app/Providers/BusServiceProvider.php'), 20 | realpath(__DIR__.'/../app/Providers/ConfigServiceProvider.php'), 21 | realpath(__DIR__.'/../app/Providers/EventServiceProvider.php'), 22 | realpath(__DIR__.'/../app/Providers/RouteServiceProvider.php'), 23 | 24 | ], 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Compiled File Providers 29 | |-------------------------------------------------------------------------- 30 | | 31 | | Here you may list service providers which define a "compiles" function 32 | | that returns additional files that should be compiled, providing an 33 | | easy way to get common files from any packages you are utilizing. 34 | | 35 | */ 36 | 37 | 'providers' => [ 38 | // 39 | ], 40 | 41 | ]; 42 | -------------------------------------------------------------------------------- /config/database.php: -------------------------------------------------------------------------------- 1 | PDO::FETCH_CLASS, 17 | 18 | /* 19 | |-------------------------------------------------------------------------- 20 | | Default Database Connection Name 21 | |-------------------------------------------------------------------------- 22 | | 23 | | Here you may specify which of the database connections below you wish 24 | | to use as your default connection for all database work. Of course 25 | | you may use many connections at once using the Database library. 26 | | 27 | */ 28 | 29 | 'default' => 'mysql', 30 | 31 | /* 32 | |-------------------------------------------------------------------------- 33 | | Database Connections 34 | |-------------------------------------------------------------------------- 35 | | 36 | | Here are each of the database connections setup for your application. 37 | | Of course, examples of configuring each database platform that is 38 | | supported by Laravel is shown below to make development simple. 39 | | 40 | | 41 | | All database work in Laravel is done through the PHP PDO facilities 42 | | so make sure you have the driver for your particular database of 43 | | choice installed on your machine before you begin development. 44 | | 45 | */ 46 | 47 | 'connections' => [ 48 | 49 | 'sqlite' => [ 50 | 'driver' => 'sqlite', 51 | 'database' => storage_path().'/database.sqlite', 52 | 'prefix' => '', 53 | ], 54 | 55 | 'mysql' => [ 56 | 'driver' => 'mysql', 57 | 'host' => env('DB_HOST', '127.0.0.1'), 58 | 'database' => env('DB_DATABASE', 'tel'), 59 | 'username' => env('DB_USERNAME', 'root'), 60 | 'unix_socket' => env('UNIX_SOCKET', '/Applications/XAMPP/xamppfiles/var/mysql/mysql.sock'), 61 | 'password' => env('DB_PASSWORD', ''), 62 | 'charset' => 'utf8', 63 | 'collation' => 'utf8_unicode_ci', 64 | 'prefix' => '', 65 | 'strict' => false, 66 | ], 67 | 68 | 'pgsql' => [ 69 | 'driver' => 'pgsql', 70 | 'host' => env('DB_HOST', 'localhost'), 71 | 'database' => env('DB_DATABASE', 'forge'), 72 | 'username' => env('DB_USERNAME', 'forge'), 73 | 'password' => env('DB_PASSWORD', ''), 74 | 'charset' => 'utf8', 75 | 'prefix' => '', 76 | 'schema' => 'public', 77 | ], 78 | 79 | 'sqlsrv' => [ 80 | 'driver' => 'sqlsrv', 81 | 'host' => env('DB_HOST', 'localhost'), 82 | 'database' => env('DB_DATABASE', 'forge'), 83 | 'username' => env('DB_USERNAME', 'forge'), 84 | 'password' => env('DB_PASSWORD', ''), 85 | 'prefix' => '', 86 | ], 87 | 88 | ], 89 | 90 | /* 91 | |-------------------------------------------------------------------------- 92 | | Migration Repository Table 93 | |-------------------------------------------------------------------------- 94 | | 95 | | This table keeps track of all the migrations that have already run for 96 | | your application. Using this information, we can determine which of 97 | | the migrations on disk haven't actually been run in the database. 98 | | 99 | */ 100 | 101 | 'migrations' => 'migrations', 102 | 103 | /* 104 | |-------------------------------------------------------------------------- 105 | | Redis Databases 106 | |-------------------------------------------------------------------------- 107 | | 108 | | Redis is an open source, fast, and advanced key-value store that also 109 | | provides a richer set of commands than a typical key-value systems 110 | | such as APC or Memcached. Laravel makes it easy to dig right in. 111 | | 112 | */ 113 | 114 | 'redis' => [ 115 | 116 | 'cluster' => false, 117 | 118 | 'default' => [ 119 | 'host' => '127.0.0.1', 120 | 'port' => 6379, 121 | 'database' => 0, 122 | ], 123 | 124 | ], 125 | 126 | ]; 127 | -------------------------------------------------------------------------------- /config/filesystems.php: -------------------------------------------------------------------------------- 1 | 'local', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Default Cloud Filesystem Disk 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Many applications store files both locally and in the cloud. For this 26 | | reason, you may specify a default "cloud" driver here. This driver 27 | | will be bound as the Cloud disk implementation in the container. 28 | | 29 | */ 30 | 31 | 'cloud' => 's3', 32 | 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | Filesystem Disks 36 | |-------------------------------------------------------------------------- 37 | | 38 | | Here you may configure as many filesystem "disks" as you wish, and you 39 | | may even configure multiple disks of the same driver. Defaults have 40 | | been setup for each driver as an example of the required options. 41 | | 42 | */ 43 | 44 | 'disks' => [ 45 | 46 | 'local' => [ 47 | 'driver' => 'local', 48 | 'root' => storage_path().'/app', 49 | ], 50 | 51 | 's3' => [ 52 | 'driver' => 's3', 53 | 'key' => 'your-key', 54 | 'secret' => 'your-secret', 55 | 'region' => 'your-region', 56 | 'bucket' => 'your-bucket', 57 | ], 58 | 59 | 'rackspace' => [ 60 | 'driver' => 'rackspace', 61 | 'username' => 'your-username', 62 | 'key' => 'your-key', 63 | 'container' => 'your-container', 64 | 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', 65 | 'region' => 'IAD', 66 | ], 67 | 68 | ], 69 | 70 | ]; 71 | -------------------------------------------------------------------------------- /config/jwt.php: -------------------------------------------------------------------------------- 1 | env('JWT_SECRET', 'zIJYhWbvHOefkTtRGC8pFVw6LF7v7KsT'), 16 | 17 | /* 18 | |-------------------------------------------------------------------------- 19 | | JWT time to live 20 | |-------------------------------------------------------------------------- 21 | | 22 | | Specify the length of time (in minutes) that the token will be valid for. 23 | | Defaults to 1 hour 24 | | 25 | */ 26 | 27 | 'ttl' => 60, 28 | 29 | /* 30 | |-------------------------------------------------------------------------- 31 | | Refresh time to live 32 | |-------------------------------------------------------------------------- 33 | | 34 | | Specify the length of time (in minutes) that the token can be refreshed 35 | | within. I.E. The user can refresh their token within a 2 week window of 36 | | the original token being created until they must re-authenticate. 37 | | Defaults to 2 weeks 38 | | 39 | */ 40 | 41 | 'refresh_ttl' => 20160, 42 | 43 | /* 44 | |-------------------------------------------------------------------------- 45 | | JWT hashing algorithm 46 | |-------------------------------------------------------------------------- 47 | | 48 | | Specify the hashing algorithm that will be used to sign the token. 49 | | 50 | | See here: https://github.com/namshi/jose/tree/2.2.0/src/Namshi/JOSE/Signer 51 | | for possible values 52 | | 53 | */ 54 | 55 | 'algo' => 'HS256', 56 | 57 | /* 58 | |-------------------------------------------------------------------------- 59 | | User Model namespace 60 | |-------------------------------------------------------------------------- 61 | | 62 | | Specify the full namespace to your User model. 63 | | e.g. 'Acme\Entities\User' 64 | | 65 | */ 66 | 67 | 'user' => 'Todo\User', 68 | 69 | /* 70 | |-------------------------------------------------------------------------- 71 | | User identifier 72 | |-------------------------------------------------------------------------- 73 | | 74 | | Specify a unique property of the user that will be added as the 'sub' 75 | | claim of the token payload. 76 | | 77 | */ 78 | 79 | 'identifier' => 'id', 80 | 81 | /* 82 | |-------------------------------------------------------------------------- 83 | | Required Claims 84 | |-------------------------------------------------------------------------- 85 | | 86 | | Specify the required claims that must exist in any token. 87 | | A TokenInvalidException will be thrown if any of these claims are not 88 | | present in the payload. 89 | | 90 | */ 91 | 92 | 'required_claims' => ['iss', 'iat', 'exp', 'nbf', 'sub', 'jti'], 93 | 94 | /* 95 | |-------------------------------------------------------------------------- 96 | | Blacklist Enabled 97 | |-------------------------------------------------------------------------- 98 | | 99 | | In order to invalidate tokens, you must have the the blacklist enabled. 100 | | If you do not want or need this functionality, then set this to false. 101 | | 102 | */ 103 | 104 | 'blacklist_enabled' => env('JWT_BLACKLIST_ENABLED', true), 105 | 106 | /* 107 | |-------------------------------------------------------------------------- 108 | | Providers 109 | |-------------------------------------------------------------------------- 110 | | 111 | | Specify the various providers used throughout the package. 112 | | 113 | */ 114 | 115 | 'providers' => [ 116 | 117 | /* 118 | |-------------------------------------------------------------------------- 119 | | User Provider 120 | |-------------------------------------------------------------------------- 121 | | 122 | | Specify the provider that is used to find the user based 123 | | on the subject claim 124 | | 125 | */ 126 | 127 | 'user' => 'Tymon\JWTAuth\Providers\User\EloquentUserAdapter', 128 | 129 | /* 130 | |-------------------------------------------------------------------------- 131 | | JWT Provider 132 | |-------------------------------------------------------------------------- 133 | | 134 | | Specify the provider that is used to create and decode the tokens. 135 | | 136 | */ 137 | 138 | 'jwt' => 'Tymon\JWTAuth\Providers\JWT\NamshiAdapter', 139 | 140 | /* 141 | |-------------------------------------------------------------------------- 142 | | Authentication Provider 143 | |-------------------------------------------------------------------------- 144 | | 145 | | Specify the provider that is used to authenticate users. 146 | | 147 | */ 148 | 149 | 'auth' => function ($app) { 150 | return new Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter($app['auth']); 151 | }, 152 | 153 | /* 154 | |-------------------------------------------------------------------------- 155 | | Storage Provider 156 | |-------------------------------------------------------------------------- 157 | | 158 | | Specify the provider that is used to store tokens in the blacklist 159 | | 160 | */ 161 | 162 | 'storage' => function ($app) { 163 | return new Tymon\JWTAuth\Providers\Storage\IlluminateCacheAdapter($app['cache']); 164 | } 165 | 166 | ] 167 | 168 | ]; 169 | -------------------------------------------------------------------------------- /config/mail.php: -------------------------------------------------------------------------------- 1 | 'smtp', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | SMTP Host Address 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may provide the host address of the SMTP server used by your 26 | | applications. A default option is provided that is compatible with 27 | | the Mailgun mail service which will provide reliable deliveries. 28 | | 29 | */ 30 | 31 | 'host' => 'smtp.mailgun.org', 32 | 33 | /* 34 | |-------------------------------------------------------------------------- 35 | | SMTP Host Port 36 | |-------------------------------------------------------------------------- 37 | | 38 | | This is the SMTP port used by your application to deliver e-mails to 39 | | users of the application. Like the host we have set this value to 40 | | stay compatible with the Mailgun e-mail application by default. 41 | | 42 | */ 43 | 44 | 'port' => 587, 45 | 46 | /* 47 | |-------------------------------------------------------------------------- 48 | | Global "From" Address 49 | |-------------------------------------------------------------------------- 50 | | 51 | | You may wish for all e-mails sent by your application to be sent from 52 | | the same address. Here, you may specify a name and address that is 53 | | used globally for all e-mails that are sent by your application. 54 | | 55 | */ 56 | 57 | 'from' => ['address' => null, 'name' => null], 58 | 59 | /* 60 | |-------------------------------------------------------------------------- 61 | | E-Mail Encryption Protocol 62 | |-------------------------------------------------------------------------- 63 | | 64 | | Here you may specify the encryption protocol that should be used when 65 | | the application send e-mail messages. A sensible default using the 66 | | transport layer security protocol should provide great security. 67 | | 68 | */ 69 | 70 | 'encryption' => 'tls', 71 | 72 | /* 73 | |-------------------------------------------------------------------------- 74 | | SMTP Server Username 75 | |-------------------------------------------------------------------------- 76 | | 77 | | If your SMTP server requires a username for authentication, you should 78 | | set it here. This will get used to authenticate with your server on 79 | | connection. You may also set the "password" value below this one. 80 | | 81 | */ 82 | 83 | 'username' => null, 84 | 85 | /* 86 | |-------------------------------------------------------------------------- 87 | | SMTP Server Password 88 | |-------------------------------------------------------------------------- 89 | | 90 | | Here you may set the password required by your SMTP server to send out 91 | | messages from your application. This will be given to the server on 92 | | connection so that the application will be able to send messages. 93 | | 94 | */ 95 | 96 | 'password' => null, 97 | 98 | /* 99 | |-------------------------------------------------------------------------- 100 | | Sendmail System Path 101 | |-------------------------------------------------------------------------- 102 | | 103 | | When using the "sendmail" driver to send e-mails, we will need to know 104 | | the path to where Sendmail lives on this server. A default path has 105 | | been provided here, which will work well on most of your systems. 106 | | 107 | */ 108 | 109 | 'sendmail' => '/usr/sbin/sendmail -bs', 110 | 111 | /* 112 | |-------------------------------------------------------------------------- 113 | | Mail "Pretend" 114 | |-------------------------------------------------------------------------- 115 | | 116 | | When this option is enabled, e-mail will not actually be sent over the 117 | | web and will instead be written to your application's logs files so 118 | | you may inspect the message. This is great for local development. 119 | | 120 | */ 121 | 122 | 'pretend' => false, 123 | 124 | ]; 125 | -------------------------------------------------------------------------------- /config/queue.php: -------------------------------------------------------------------------------- 1 | env('QUEUE_DRIVER', 'sync'), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Queue Connections 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Here you may configure the connection information for each server that 27 | | is used by your application. A default configuration has been added 28 | | for each back-end shipped with Laravel. You are free to add more. 29 | | 30 | */ 31 | 32 | 'connections' => [ 33 | 34 | 'sync' => [ 35 | 'driver' => 'sync', 36 | ], 37 | 38 | 'database' => [ 39 | 'driver' => 'database', 40 | 'table' => 'jobs', 41 | 'queue' => 'default', 42 | 'expire' => 60, 43 | ], 44 | 45 | 'beanstalkd' => [ 46 | 'driver' => 'beanstalkd', 47 | 'host' => 'localhost', 48 | 'queue' => 'default', 49 | 'ttr' => 60, 50 | ], 51 | 52 | 'sqs' => [ 53 | 'driver' => 'sqs', 54 | 'key' => 'your-public-key', 55 | 'secret' => 'your-secret-key', 56 | 'queue' => 'your-queue-url', 57 | 'region' => 'us-east-1', 58 | ], 59 | 60 | 'iron' => [ 61 | 'driver' => 'iron', 62 | 'host' => 'mq-aws-us-east-1.iron.io', 63 | 'token' => 'your-token', 64 | 'project' => 'your-project-id', 65 | 'queue' => 'your-queue-name', 66 | 'encrypt' => true, 67 | ], 68 | 69 | 'redis' => [ 70 | 'driver' => 'redis', 71 | 'queue' => 'default', 72 | 'expire' => 60, 73 | ], 74 | 75 | ], 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Failed Queue Jobs 80 | |-------------------------------------------------------------------------- 81 | | 82 | | These options configure the behavior of failed queue job logging so you 83 | | can control which database and table are used to store the jobs that 84 | | have failed. You may change them to any database / table you wish. 85 | | 86 | */ 87 | 88 | 'failed' => [ 89 | 'database' => 'mysql', 'table' => 'failed_jobs', 90 | ], 91 | 92 | ]; 93 | -------------------------------------------------------------------------------- /config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => '', 19 | 'secret' => '', 20 | ], 21 | 22 | 'mandrill' => [ 23 | 'secret' => '', 24 | ], 25 | 26 | 'ses' => [ 27 | 'key' => '', 28 | 'secret' => '', 29 | 'region' => 'us-east-1', 30 | ], 31 | 32 | 'stripe' => [ 33 | 'model' => 'User', 34 | 'secret' => '', 35 | ], 36 | 37 | ]; 38 | -------------------------------------------------------------------------------- /config/session.php: -------------------------------------------------------------------------------- 1 | env('SESSION_DRIVER', 'file'), 20 | 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Session Lifetime 24 | |-------------------------------------------------------------------------- 25 | | 26 | | Here you may specify the number of minutes that you wish the session 27 | | to be allowed to remain idle before it expires. If you want them 28 | | to immediately expire on the browser closing, set that option. 29 | | 30 | */ 31 | 32 | 'lifetime' => 120, 33 | 34 | 'expire_on_close' => false, 35 | 36 | /* 37 | |-------------------------------------------------------------------------- 38 | | Session Encryption 39 | |-------------------------------------------------------------------------- 40 | | 41 | | This option allows you to easily specify that all of your session data 42 | | should be encrypted before it is stored. All encryption will be run 43 | | automatically by Laravel and you can use the Session like normal. 44 | | 45 | */ 46 | 47 | 'encrypt' => false, 48 | 49 | /* 50 | |-------------------------------------------------------------------------- 51 | | Session File Location 52 | |-------------------------------------------------------------------------- 53 | | 54 | | When using the native session driver, we need a location where session 55 | | files may be stored. A default has been set for you but a different 56 | | location may be specified. This is only needed for file sessions. 57 | | 58 | */ 59 | 60 | 'files' => storage_path().'/framework/sessions', 61 | 62 | /* 63 | |-------------------------------------------------------------------------- 64 | | Session Database Connection 65 | |-------------------------------------------------------------------------- 66 | | 67 | | When using the "database" or "redis" session drivers, you may specify a 68 | | connection that should be used to manage these sessions. This should 69 | | correspond to a connection in your database configuration options. 70 | | 71 | */ 72 | 73 | 'connection' => null, 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Session Database Table 78 | |-------------------------------------------------------------------------- 79 | | 80 | | When using the "database" session driver, you may specify the table we 81 | | should use to manage the sessions. Of course, a sensible default is 82 | | provided for you; however, you are free to change this as needed. 83 | | 84 | */ 85 | 86 | 'table' => 'sessions', 87 | 88 | /* 89 | |-------------------------------------------------------------------------- 90 | | Session Sweeping Lottery 91 | |-------------------------------------------------------------------------- 92 | | 93 | | Some session drivers must manually sweep their storage location to get 94 | | rid of old sessions from storage. Here are the chances that it will 95 | | happen on a given request. By default, the odds are 2 out of 100. 96 | | 97 | */ 98 | 99 | 'lottery' => [2, 100], 100 | 101 | /* 102 | |-------------------------------------------------------------------------- 103 | | Session Cookie Name 104 | |-------------------------------------------------------------------------- 105 | | 106 | | Here you may change the name of the cookie used to identify a session 107 | | instance by ID. The name specified here will get used every time a 108 | | new session cookie is created by the framework for every driver. 109 | | 110 | */ 111 | 112 | 'cookie' => 'laravel_session', 113 | 114 | /* 115 | |-------------------------------------------------------------------------- 116 | | Session Cookie Path 117 | |-------------------------------------------------------------------------- 118 | | 119 | | The session cookie path determines the path for which the cookie will 120 | | be regarded as available. Typically, this will be the root path of 121 | | your application but you are free to change this when necessary. 122 | | 123 | */ 124 | 125 | 'path' => '/', 126 | 127 | /* 128 | |-------------------------------------------------------------------------- 129 | | Session Cookie Domain 130 | |-------------------------------------------------------------------------- 131 | | 132 | | Here you may change the domain of the cookie used to identify a session 133 | | in your application. This will determine which domains the cookie is 134 | | available to in your application. A sensible default has been set. 135 | | 136 | */ 137 | 138 | 'domain' => null, 139 | 140 | /* 141 | |-------------------------------------------------------------------------- 142 | | HTTPS Only Cookies 143 | |-------------------------------------------------------------------------- 144 | | 145 | | By setting this option to true, session cookies will only be sent back 146 | | to the server if the browser has a HTTPS connection. This will keep 147 | | the cookie from being sent to you if it can not be done securely. 148 | | 149 | */ 150 | 151 | 'secure' => false, 152 | 153 | ]; 154 | -------------------------------------------------------------------------------- /config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | realpath(base_path('resources/views')) 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => realpath(storage_path().'/framework/views'), 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /database/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulienBernard/starter-laravel-angular-foundation/4c7f6a0a9e76f239213a3ff64436ecbe7886eb8f/database/migrations/.gitkeep -------------------------------------------------------------------------------- /database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('username')->unique(); 19 | $table->string('email')->unique(); 20 | $table->string('password', 60); 21 | $table->rememberToken(); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::drop('users'); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token')->index(); 19 | $table->timestamp('created_at'); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::drop('password_resets'); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /database/migrations/2015_02_26_065521_create_todos_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('body'); 19 | $table->timestamps(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::drop('todos'); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /database/seeds/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulienBernard/starter-laravel-angular-foundation/4c7f6a0a9e76f239213a3ff64436ecbe7886eb8f/database/seeds/.gitkeep -------------------------------------------------------------------------------- /database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call('UserTableSeeder'); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var elixir = require('laravel-elixir'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Elixir Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Elixir provides a clean, fluent API for defining some basic Gulp tasks 9 | | for your Laravel application. By default, we are compiling the Less 10 | | file for our application, as well as publishing vendor resources. 11 | | 12 | */ 13 | 14 | elixir(function (mix) { 15 | mix 16 | .styles([ 17 | 'normalize.css', 18 | 'foundation.min.css', 19 | 'foundation-icons.css', 20 | 'style.css' 21 | ]) 22 | .scripts([ 23 | 'libs/**/*.js', 24 | 'app.js', 25 | 'appRoutes.js', 26 | 'controllers/**/*.js', 27 | 'services/**/*.js', 28 | 'directives/**/*.js' 29 | ]) 30 | .version([ 31 | 'css/all.css', 32 | 'js/all.js' 33 | ]) 34 | .copy( 35 | 'public/js/all.js.map', 'public/build/js/all.js.map' 36 | ) 37 | .copy( 38 | 'public/css/all.css.map', 'public/build/css/all.css.map' 39 | ) 40 | .copy( 41 | 'resources/fonts/**', 'public/build/css' 42 | ); 43 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "starter-laravel-angular-foundation", 3 | "version": "1.0.0", 4 | "description": "Laravel 5 and AngularJS 1.3 starter kit featuring Foundation 5.5!", 5 | "main": "gulpfile.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/JulienBernard/starter-laravel-angular-foundation/" 12 | }, 13 | "keywords": [ 14 | "laravel", 15 | "gulp", 16 | "foundation", 17 | "bower", 18 | "angular", 19 | "GNU", 20 | "starter", 21 | "kit" 22 | ], 23 | "author": "Julien Bernard ", 24 | "license": "GNU Version 2", 25 | "bugs": { 26 | "url": "https://github.com/JulienBernard/starter-laravel-angular-foundation/issues" 27 | }, 28 | "homepage": "https://github.com/JulienBernard/starter-laravel-angular-foundation", 29 | "devDependencies": { 30 | "gulp": "^3.8.8", 31 | "laravel-elixir": "*" 32 | } 33 | } -------------------------------------------------------------------------------- /phpspec.yml: -------------------------------------------------------------------------------- 1 | suites: 2 | main: 3 | namespace: Todo 4 | psr4_prefix: Todo 5 | src_path: app -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Redirect Trailing Slashes... 9 | RewriteRule ^(.*)/$ /$1 [L,R=301] 10 | 11 | # Handle Front Controller... 12 | RewriteCond %{REQUEST_FILENAME} !-d 13 | RewriteCond %{REQUEST_FILENAME} !-f 14 | RewriteRule ^ index.php [L] 15 | 16 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulienBernard/starter-laravel-angular-foundation/4c7f6a0a9e76f239213a3ff64436ecbe7886eb8f/public/favicon.ico -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | 9 | /* 10 | |-------------------------------------------------------------------------- 11 | | Register The Auto Loader 12 | |-------------------------------------------------------------------------- 13 | | 14 | | Composer provides a convenient, automatically generated class loader for 15 | | our application. We just need to utilize it! We'll simply require it 16 | | into the script here so that we don't have to worry about manual 17 | | loading any of our classes later on. It feels nice to relax. 18 | | 19 | */ 20 | 21 | require __DIR__.'/../bootstrap/autoload.php'; 22 | 23 | /* 24 | |-------------------------------------------------------------------------- 25 | | Turn On The Lights 26 | |-------------------------------------------------------------------------- 27 | | 28 | | We need to illuminate PHP development, so let us turn on the lights. 29 | | This bootstraps the framework and gets it ready for use, then it 30 | | will load up this application so that we can run it and send 31 | | the responses back to the browser and delight our users. 32 | | 33 | */ 34 | 35 | $app = require_once __DIR__.'/../bootstrap/app.php'; 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Run The Application 40 | |-------------------------------------------------------------------------- 41 | | 42 | | Once we have the application, we can simply call the run method, 43 | | which will execute the request and send the response back to 44 | | the client's browser allowing them to enjoy the creative 45 | | and wonderful application we have prepared for them. 46 | | 47 | */ 48 | 49 | $kernel = $app->make('Illuminate\Contracts\Http\Kernel'); 50 | 51 | $response = $kernel->handle( 52 | $request = Illuminate\Http\Request::capture() 53 | ); 54 | 55 | $response->send(); 56 | 57 | $kernel->terminate($request, $response); 58 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /resources/css/foundation-icons.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Foundation Icons v 3.0 3 | * Made by ZURB 2013 http://zurb.com/playground/foundation-icon-fonts-3 4 | * MIT License 5 | */ 6 | 7 | @font-face { 8 | font-family: "foundation-icons"; 9 | src: url("foundation-icons.eot"); 10 | src: url("foundation-icons.eot?#iefix") format("embedded-opentype"), 11 | url("foundation-icons.woff") format("woff"), 12 | url("foundation-icons.ttf") format("truetype"), 13 | url("foundation-icons.svg#fontcustom") format("svg"); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | 18 | .fi-address-book:before, 19 | .fi-alert:before, 20 | .fi-align-center:before, 21 | .fi-align-justify:before, 22 | .fi-align-left:before, 23 | .fi-align-right:before, 24 | .fi-anchor:before, 25 | .fi-annotate:before, 26 | .fi-archive:before, 27 | .fi-arrow-down:before, 28 | .fi-arrow-left:before, 29 | .fi-arrow-right:before, 30 | .fi-arrow-up:before, 31 | .fi-arrows-compress:before, 32 | .fi-arrows-expand:before, 33 | .fi-arrows-in:before, 34 | .fi-arrows-out:before, 35 | .fi-asl:before, 36 | .fi-asterisk:before, 37 | .fi-at-sign:before, 38 | .fi-background-color:before, 39 | .fi-battery-empty:before, 40 | .fi-battery-full:before, 41 | .fi-battery-half:before, 42 | .fi-bitcoin-circle:before, 43 | .fi-bitcoin:before, 44 | .fi-blind:before, 45 | .fi-bluetooth:before, 46 | .fi-bold:before, 47 | .fi-book-bookmark:before, 48 | .fi-book:before, 49 | .fi-bookmark:before, 50 | .fi-braille:before, 51 | .fi-burst-new:before, 52 | .fi-burst-sale:before, 53 | .fi-burst:before, 54 | .fi-calendar:before, 55 | .fi-camera:before, 56 | .fi-check:before, 57 | .fi-checkbox:before, 58 | .fi-clipboard-notes:before, 59 | .fi-clipboard-pencil:before, 60 | .fi-clipboard:before, 61 | .fi-clock:before, 62 | .fi-closed-caption:before, 63 | .fi-cloud:before, 64 | .fi-comment-minus:before, 65 | .fi-comment-quotes:before, 66 | .fi-comment-video:before, 67 | .fi-comment:before, 68 | .fi-comments:before, 69 | .fi-compass:before, 70 | .fi-contrast:before, 71 | .fi-credit-card:before, 72 | .fi-crop:before, 73 | .fi-crown:before, 74 | .fi-css3:before, 75 | .fi-database:before, 76 | .fi-die-five:before, 77 | .fi-die-four:before, 78 | .fi-die-one:before, 79 | .fi-die-six:before, 80 | .fi-die-three:before, 81 | .fi-die-two:before, 82 | .fi-dislike:before, 83 | .fi-dollar-bill:before, 84 | .fi-dollar:before, 85 | .fi-download:before, 86 | .fi-eject:before, 87 | .fi-elevator:before, 88 | .fi-euro:before, 89 | .fi-eye:before, 90 | .fi-fast-forward:before, 91 | .fi-female-symbol:before, 92 | .fi-female:before, 93 | .fi-filter:before, 94 | .fi-first-aid:before, 95 | .fi-flag:before, 96 | .fi-folder-add:before, 97 | .fi-folder-lock:before, 98 | .fi-folder:before, 99 | .fi-foot:before, 100 | .fi-foundation:before, 101 | .fi-graph-bar:before, 102 | .fi-graph-horizontal:before, 103 | .fi-graph-pie:before, 104 | .fi-graph-trend:before, 105 | .fi-guide-dog:before, 106 | .fi-hearing-aid:before, 107 | .fi-heart:before, 108 | .fi-home:before, 109 | .fi-html5:before, 110 | .fi-indent-less:before, 111 | .fi-indent-more:before, 112 | .fi-info:before, 113 | .fi-italic:before, 114 | .fi-key:before, 115 | .fi-laptop:before, 116 | .fi-layout:before, 117 | .fi-lightbulb:before, 118 | .fi-like:before, 119 | .fi-link:before, 120 | .fi-list-bullet:before, 121 | .fi-list-number:before, 122 | .fi-list-thumbnails:before, 123 | .fi-list:before, 124 | .fi-lock:before, 125 | .fi-loop:before, 126 | .fi-magnifying-glass:before, 127 | .fi-mail:before, 128 | .fi-male-female:before, 129 | .fi-male-symbol:before, 130 | .fi-male:before, 131 | .fi-map:before, 132 | .fi-marker:before, 133 | .fi-megaphone:before, 134 | .fi-microphone:before, 135 | .fi-minus-circle:before, 136 | .fi-minus:before, 137 | .fi-mobile-signal:before, 138 | .fi-mobile:before, 139 | .fi-monitor:before, 140 | .fi-mountains:before, 141 | .fi-music:before, 142 | .fi-next:before, 143 | .fi-no-dogs:before, 144 | .fi-no-smoking:before, 145 | .fi-page-add:before, 146 | .fi-page-copy:before, 147 | .fi-page-csv:before, 148 | .fi-page-delete:before, 149 | .fi-page-doc:before, 150 | .fi-page-edit:before, 151 | .fi-page-export-csv:before, 152 | .fi-page-export-doc:before, 153 | .fi-page-export-pdf:before, 154 | .fi-page-export:before, 155 | .fi-page-filled:before, 156 | .fi-page-multiple:before, 157 | .fi-page-pdf:before, 158 | .fi-page-remove:before, 159 | .fi-page-search:before, 160 | .fi-page:before, 161 | .fi-paint-bucket:before, 162 | .fi-paperclip:before, 163 | .fi-pause:before, 164 | .fi-paw:before, 165 | .fi-paypal:before, 166 | .fi-pencil:before, 167 | .fi-photo:before, 168 | .fi-play-circle:before, 169 | .fi-play-video:before, 170 | .fi-play:before, 171 | .fi-plus:before, 172 | .fi-pound:before, 173 | .fi-power:before, 174 | .fi-previous:before, 175 | .fi-price-tag:before, 176 | .fi-pricetag-multiple:before, 177 | .fi-print:before, 178 | .fi-prohibited:before, 179 | .fi-projection-screen:before, 180 | .fi-puzzle:before, 181 | .fi-quote:before, 182 | .fi-record:before, 183 | .fi-refresh:before, 184 | .fi-results-demographics:before, 185 | .fi-results:before, 186 | .fi-rewind-ten:before, 187 | .fi-rewind:before, 188 | .fi-rss:before, 189 | .fi-safety-cone:before, 190 | .fi-save:before, 191 | .fi-share:before, 192 | .fi-sheriff-badge:before, 193 | .fi-shield:before, 194 | .fi-shopping-bag:before, 195 | .fi-shopping-cart:before, 196 | .fi-shuffle:before, 197 | .fi-skull:before, 198 | .fi-social-500px:before, 199 | .fi-social-adobe:before, 200 | .fi-social-amazon:before, 201 | .fi-social-android:before, 202 | .fi-social-apple:before, 203 | .fi-social-behance:before, 204 | .fi-social-bing:before, 205 | .fi-social-blogger:before, 206 | .fi-social-delicious:before, 207 | .fi-social-designer-news:before, 208 | .fi-social-deviant-art:before, 209 | .fi-social-digg:before, 210 | .fi-social-dribbble:before, 211 | .fi-social-drive:before, 212 | .fi-social-dropbox:before, 213 | .fi-social-evernote:before, 214 | .fi-social-facebook:before, 215 | .fi-social-flickr:before, 216 | .fi-social-forrst:before, 217 | .fi-social-foursquare:before, 218 | .fi-social-game-center:before, 219 | .fi-social-github:before, 220 | .fi-social-google-plus:before, 221 | .fi-social-hacker-news:before, 222 | .fi-social-hi5:before, 223 | .fi-social-instagram:before, 224 | .fi-social-joomla:before, 225 | .fi-social-lastfm:before, 226 | .fi-social-linkedin:before, 227 | .fi-social-medium:before, 228 | .fi-social-myspace:before, 229 | .fi-social-orkut:before, 230 | .fi-social-path:before, 231 | .fi-social-picasa:before, 232 | .fi-social-pinterest:before, 233 | .fi-social-rdio:before, 234 | .fi-social-reddit:before, 235 | .fi-social-skillshare:before, 236 | .fi-social-skype:before, 237 | .fi-social-smashing-mag:before, 238 | .fi-social-snapchat:before, 239 | .fi-social-spotify:before, 240 | .fi-social-squidoo:before, 241 | .fi-social-stack-overflow:before, 242 | .fi-social-steam:before, 243 | .fi-social-stumbleupon:before, 244 | .fi-social-treehouse:before, 245 | .fi-social-tumblr:before, 246 | .fi-social-twitter:before, 247 | .fi-social-vimeo:before, 248 | .fi-social-windows:before, 249 | .fi-social-xbox:before, 250 | .fi-social-yahoo:before, 251 | .fi-social-yelp:before, 252 | .fi-social-youtube:before, 253 | .fi-social-zerply:before, 254 | .fi-social-zurb:before, 255 | .fi-sound:before, 256 | .fi-star:before, 257 | .fi-stop:before, 258 | .fi-strikethrough:before, 259 | .fi-subscript:before, 260 | .fi-superscript:before, 261 | .fi-tablet-landscape:before, 262 | .fi-tablet-portrait:before, 263 | .fi-target-two:before, 264 | .fi-target:before, 265 | .fi-telephone-accessible:before, 266 | .fi-telephone:before, 267 | .fi-text-color:before, 268 | .fi-thumbnails:before, 269 | .fi-ticket:before, 270 | .fi-torso-business:before, 271 | .fi-torso-female:before, 272 | .fi-torso:before, 273 | .fi-torsos-all-female:before, 274 | .fi-torsos-all:before, 275 | .fi-torsos-female-male:before, 276 | .fi-torsos-male-female:before, 277 | .fi-torsos:before, 278 | .fi-trash:before, 279 | .fi-trees:before, 280 | .fi-trophy:before, 281 | .fi-underline:before, 282 | .fi-universal-access:before, 283 | .fi-unlink:before, 284 | .fi-unlock:before, 285 | .fi-upload-cloud:before, 286 | .fi-upload:before, 287 | .fi-usb:before, 288 | .fi-video:before, 289 | .fi-volume-none:before, 290 | .fi-volume-strike:before, 291 | .fi-volume:before, 292 | .fi-web:before, 293 | .fi-wheelchair:before, 294 | .fi-widget:before, 295 | .fi-wrench:before, 296 | .fi-x-circle:before, 297 | .fi-x:before, 298 | .fi-yen:before, 299 | .fi-zoom-in:before, 300 | .fi-zoom-out:before { 301 | font-family: "foundation-icons"; 302 | font-style: normal; 303 | font-weight: normal; 304 | font-variant: normal; 305 | text-transform: none; 306 | line-height: 1; 307 | -webkit-font-smoothing: antialiased; 308 | display: inline-block; 309 | text-decoration: inherit; 310 | } 311 | 312 | .fi-address-book:before { content: "\f100"; } 313 | .fi-alert:before { content: "\f101"; } 314 | .fi-align-center:before { content: "\f102"; } 315 | .fi-align-justify:before { content: "\f103"; } 316 | .fi-align-left:before { content: "\f104"; } 317 | .fi-align-right:before { content: "\f105"; } 318 | .fi-anchor:before { content: "\f106"; } 319 | .fi-annotate:before { content: "\f107"; } 320 | .fi-archive:before { content: "\f108"; } 321 | .fi-arrow-down:before { content: "\f109"; } 322 | .fi-arrow-left:before { content: "\f10a"; } 323 | .fi-arrow-right:before { content: "\f10b"; } 324 | .fi-arrow-up:before { content: "\f10c"; } 325 | .fi-arrows-compress:before { content: "\f10d"; } 326 | .fi-arrows-expand:before { content: "\f10e"; } 327 | .fi-arrows-in:before { content: "\f10f"; } 328 | .fi-arrows-out:before { content: "\f110"; } 329 | .fi-asl:before { content: "\f111"; } 330 | .fi-asterisk:before { content: "\f112"; } 331 | .fi-at-sign:before { content: "\f113"; } 332 | .fi-background-color:before { content: "\f114"; } 333 | .fi-battery-empty:before { content: "\f115"; } 334 | .fi-battery-full:before { content: "\f116"; } 335 | .fi-battery-half:before { content: "\f117"; } 336 | .fi-bitcoin-circle:before { content: "\f118"; } 337 | .fi-bitcoin:before { content: "\f119"; } 338 | .fi-blind:before { content: "\f11a"; } 339 | .fi-bluetooth:before { content: "\f11b"; } 340 | .fi-bold:before { content: "\f11c"; } 341 | .fi-book-bookmark:before { content: "\f11d"; } 342 | .fi-book:before { content: "\f11e"; } 343 | .fi-bookmark:before { content: "\f11f"; } 344 | .fi-braille:before { content: "\f120"; } 345 | .fi-burst-new:before { content: "\f121"; } 346 | .fi-burst-sale:before { content: "\f122"; } 347 | .fi-burst:before { content: "\f123"; } 348 | .fi-calendar:before { content: "\f124"; } 349 | .fi-camera:before { content: "\f125"; } 350 | .fi-check:before { content: "\f126"; } 351 | .fi-checkbox:before { content: "\f127"; } 352 | .fi-clipboard-notes:before { content: "\f128"; } 353 | .fi-clipboard-pencil:before { content: "\f129"; } 354 | .fi-clipboard:before { content: "\f12a"; } 355 | .fi-clock:before { content: "\f12b"; } 356 | .fi-closed-caption:before { content: "\f12c"; } 357 | .fi-cloud:before { content: "\f12d"; } 358 | .fi-comment-minus:before { content: "\f12e"; } 359 | .fi-comment-quotes:before { content: "\f12f"; } 360 | .fi-comment-video:before { content: "\f130"; } 361 | .fi-comment:before { content: "\f131"; } 362 | .fi-comments:before { content: "\f132"; } 363 | .fi-compass:before { content: "\f133"; } 364 | .fi-contrast:before { content: "\f134"; } 365 | .fi-credit-card:before { content: "\f135"; } 366 | .fi-crop:before { content: "\f136"; } 367 | .fi-crown:before { content: "\f137"; } 368 | .fi-css3:before { content: "\f138"; } 369 | .fi-database:before { content: "\f139"; } 370 | .fi-die-five:before { content: "\f13a"; } 371 | .fi-die-four:before { content: "\f13b"; } 372 | .fi-die-one:before { content: "\f13c"; } 373 | .fi-die-six:before { content: "\f13d"; } 374 | .fi-die-three:before { content: "\f13e"; } 375 | .fi-die-two:before { content: "\f13f"; } 376 | .fi-dislike:before { content: "\f140"; } 377 | .fi-dollar-bill:before { content: "\f141"; } 378 | .fi-dollar:before { content: "\f142"; } 379 | .fi-download:before { content: "\f143"; } 380 | .fi-eject:before { content: "\f144"; } 381 | .fi-elevator:before { content: "\f145"; } 382 | .fi-euro:before { content: "\f146"; } 383 | .fi-eye:before { content: "\f147"; } 384 | .fi-fast-forward:before { content: "\f148"; } 385 | .fi-female-symbol:before { content: "\f149"; } 386 | .fi-female:before { content: "\f14a"; } 387 | .fi-filter:before { content: "\f14b"; } 388 | .fi-first-aid:before { content: "\f14c"; } 389 | .fi-flag:before { content: "\f14d"; } 390 | .fi-folder-add:before { content: "\f14e"; } 391 | .fi-folder-lock:before { content: "\f14f"; } 392 | .fi-folder:before { content: "\f150"; } 393 | .fi-foot:before { content: "\f151"; } 394 | .fi-foundation:before { content: "\f152"; } 395 | .fi-graph-bar:before { content: "\f153"; } 396 | .fi-graph-horizontal:before { content: "\f154"; } 397 | .fi-graph-pie:before { content: "\f155"; } 398 | .fi-graph-trend:before { content: "\f156"; } 399 | .fi-guide-dog:before { content: "\f157"; } 400 | .fi-hearing-aid:before { content: "\f158"; } 401 | .fi-heart:before { content: "\f159"; } 402 | .fi-home:before { content: "\f15a"; } 403 | .fi-html5:before { content: "\f15b"; } 404 | .fi-indent-less:before { content: "\f15c"; } 405 | .fi-indent-more:before { content: "\f15d"; } 406 | .fi-info:before { content: "\f15e"; } 407 | .fi-italic:before { content: "\f15f"; } 408 | .fi-key:before { content: "\f160"; } 409 | .fi-laptop:before { content: "\f161"; } 410 | .fi-layout:before { content: "\f162"; } 411 | .fi-lightbulb:before { content: "\f163"; } 412 | .fi-like:before { content: "\f164"; } 413 | .fi-link:before { content: "\f165"; } 414 | .fi-list-bullet:before { content: "\f166"; } 415 | .fi-list-number:before { content: "\f167"; } 416 | .fi-list-thumbnails:before { content: "\f168"; } 417 | .fi-list:before { content: "\f169"; } 418 | .fi-lock:before { content: "\f16a"; } 419 | .fi-loop:before { content: "\f16b"; } 420 | .fi-magnifying-glass:before { content: "\f16c"; } 421 | .fi-mail:before { content: "\f16d"; } 422 | .fi-male-female:before { content: "\f16e"; } 423 | .fi-male-symbol:before { content: "\f16f"; } 424 | .fi-male:before { content: "\f170"; } 425 | .fi-map:before { content: "\f171"; } 426 | .fi-marker:before { content: "\f172"; } 427 | .fi-megaphone:before { content: "\f173"; } 428 | .fi-microphone:before { content: "\f174"; } 429 | .fi-minus-circle:before { content: "\f175"; } 430 | .fi-minus:before { content: "\f176"; } 431 | .fi-mobile-signal:before { content: "\f177"; } 432 | .fi-mobile:before { content: "\f178"; } 433 | .fi-monitor:before { content: "\f179"; } 434 | .fi-mountains:before { content: "\f17a"; } 435 | .fi-music:before { content: "\f17b"; } 436 | .fi-next:before { content: "\f17c"; } 437 | .fi-no-dogs:before { content: "\f17d"; } 438 | .fi-no-smoking:before { content: "\f17e"; } 439 | .fi-page-add:before { content: "\f17f"; } 440 | .fi-page-copy:before { content: "\f180"; } 441 | .fi-page-csv:before { content: "\f181"; } 442 | .fi-page-delete:before { content: "\f182"; } 443 | .fi-page-doc:before { content: "\f183"; } 444 | .fi-page-edit:before { content: "\f184"; } 445 | .fi-page-export-csv:before { content: "\f185"; } 446 | .fi-page-export-doc:before { content: "\f186"; } 447 | .fi-page-export-pdf:before { content: "\f187"; } 448 | .fi-page-export:before { content: "\f188"; } 449 | .fi-page-filled:before { content: "\f189"; } 450 | .fi-page-multiple:before { content: "\f18a"; } 451 | .fi-page-pdf:before { content: "\f18b"; } 452 | .fi-page-remove:before { content: "\f18c"; } 453 | .fi-page-search:before { content: "\f18d"; } 454 | .fi-page:before { content: "\f18e"; } 455 | .fi-paint-bucket:before { content: "\f18f"; } 456 | .fi-paperclip:before { content: "\f190"; } 457 | .fi-pause:before { content: "\f191"; } 458 | .fi-paw:before { content: "\f192"; } 459 | .fi-paypal:before { content: "\f193"; } 460 | .fi-pencil:before { content: "\f194"; } 461 | .fi-photo:before { content: "\f195"; } 462 | .fi-play-circle:before { content: "\f196"; } 463 | .fi-play-video:before { content: "\f197"; } 464 | .fi-play:before { content: "\f198"; } 465 | .fi-plus:before { content: "\f199"; } 466 | .fi-pound:before { content: "\f19a"; } 467 | .fi-power:before { content: "\f19b"; } 468 | .fi-previous:before { content: "\f19c"; } 469 | .fi-price-tag:before { content: "\f19d"; } 470 | .fi-pricetag-multiple:before { content: "\f19e"; } 471 | .fi-print:before { content: "\f19f"; } 472 | .fi-prohibited:before { content: "\f1a0"; } 473 | .fi-projection-screen:before { content: "\f1a1"; } 474 | .fi-puzzle:before { content: "\f1a2"; } 475 | .fi-quote:before { content: "\f1a3"; } 476 | .fi-record:before { content: "\f1a4"; } 477 | .fi-refresh:before { content: "\f1a5"; } 478 | .fi-results-demographics:before { content: "\f1a6"; } 479 | .fi-results:before { content: "\f1a7"; } 480 | .fi-rewind-ten:before { content: "\f1a8"; } 481 | .fi-rewind:before { content: "\f1a9"; } 482 | .fi-rss:before { content: "\f1aa"; } 483 | .fi-safety-cone:before { content: "\f1ab"; } 484 | .fi-save:before { content: "\f1ac"; } 485 | .fi-share:before { content: "\f1ad"; } 486 | .fi-sheriff-badge:before { content: "\f1ae"; } 487 | .fi-shield:before { content: "\f1af"; } 488 | .fi-shopping-bag:before { content: "\f1b0"; } 489 | .fi-shopping-cart:before { content: "\f1b1"; } 490 | .fi-shuffle:before { content: "\f1b2"; } 491 | .fi-skull:before { content: "\f1b3"; } 492 | .fi-social-500px:before { content: "\f1b4"; } 493 | .fi-social-adobe:before { content: "\f1b5"; } 494 | .fi-social-amazon:before { content: "\f1b6"; } 495 | .fi-social-android:before { content: "\f1b7"; } 496 | .fi-social-apple:before { content: "\f1b8"; } 497 | .fi-social-behance:before { content: "\f1b9"; } 498 | .fi-social-bing:before { content: "\f1ba"; } 499 | .fi-social-blogger:before { content: "\f1bb"; } 500 | .fi-social-delicious:before { content: "\f1bc"; } 501 | .fi-social-designer-news:before { content: "\f1bd"; } 502 | .fi-social-deviant-art:before { content: "\f1be"; } 503 | .fi-social-digg:before { content: "\f1bf"; } 504 | .fi-social-dribbble:before { content: "\f1c0"; } 505 | .fi-social-drive:before { content: "\f1c1"; } 506 | .fi-social-dropbox:before { content: "\f1c2"; } 507 | .fi-social-evernote:before { content: "\f1c3"; } 508 | .fi-social-facebook:before { content: "\f1c4"; } 509 | .fi-social-flickr:before { content: "\f1c5"; } 510 | .fi-social-forrst:before { content: "\f1c6"; } 511 | .fi-social-foursquare:before { content: "\f1c7"; } 512 | .fi-social-game-center:before { content: "\f1c8"; } 513 | .fi-social-github:before { content: "\f1c9"; } 514 | .fi-social-google-plus:before { content: "\f1ca"; } 515 | .fi-social-hacker-news:before { content: "\f1cb"; } 516 | .fi-social-hi5:before { content: "\f1cc"; } 517 | .fi-social-instagram:before { content: "\f1cd"; } 518 | .fi-social-joomla:before { content: "\f1ce"; } 519 | .fi-social-lastfm:before { content: "\f1cf"; } 520 | .fi-social-linkedin:before { content: "\f1d0"; } 521 | .fi-social-medium:before { content: "\f1d1"; } 522 | .fi-social-myspace:before { content: "\f1d2"; } 523 | .fi-social-orkut:before { content: "\f1d3"; } 524 | .fi-social-path:before { content: "\f1d4"; } 525 | .fi-social-picasa:before { content: "\f1d5"; } 526 | .fi-social-pinterest:before { content: "\f1d6"; } 527 | .fi-social-rdio:before { content: "\f1d7"; } 528 | .fi-social-reddit:before { content: "\f1d8"; } 529 | .fi-social-skillshare:before { content: "\f1d9"; } 530 | .fi-social-skype:before { content: "\f1da"; } 531 | .fi-social-smashing-mag:before { content: "\f1db"; } 532 | .fi-social-snapchat:before { content: "\f1dc"; } 533 | .fi-social-spotify:before { content: "\f1dd"; } 534 | .fi-social-squidoo:before { content: "\f1de"; } 535 | .fi-social-stack-overflow:before { content: "\f1df"; } 536 | .fi-social-steam:before { content: "\f1e0"; } 537 | .fi-social-stumbleupon:before { content: "\f1e1"; } 538 | .fi-social-treehouse:before { content: "\f1e2"; } 539 | .fi-social-tumblr:before { content: "\f1e3"; } 540 | .fi-social-twitter:before { content: "\f1e4"; } 541 | .fi-social-vimeo:before { content: "\f1e5"; } 542 | .fi-social-windows:before { content: "\f1e6"; } 543 | .fi-social-xbox:before { content: "\f1e7"; } 544 | .fi-social-yahoo:before { content: "\f1e8"; } 545 | .fi-social-yelp:before { content: "\f1e9"; } 546 | .fi-social-youtube:before { content: "\f1ea"; } 547 | .fi-social-zerply:before { content: "\f1eb"; } 548 | .fi-social-zurb:before { content: "\f1ec"; } 549 | .fi-sound:before { content: "\f1ed"; } 550 | .fi-star:before { content: "\f1ee"; } 551 | .fi-stop:before { content: "\f1ef"; } 552 | .fi-strikethrough:before { content: "\f1f0"; } 553 | .fi-subscript:before { content: "\f1f1"; } 554 | .fi-superscript:before { content: "\f1f2"; } 555 | .fi-tablet-landscape:before { content: "\f1f3"; } 556 | .fi-tablet-portrait:before { content: "\f1f4"; } 557 | .fi-target-two:before { content: "\f1f5"; } 558 | .fi-target:before { content: "\f1f6"; } 559 | .fi-telephone-accessible:before { content: "\f1f7"; } 560 | .fi-telephone:before { content: "\f1f8"; } 561 | .fi-text-color:before { content: "\f1f9"; } 562 | .fi-thumbnails:before { content: "\f1fa"; } 563 | .fi-ticket:before { content: "\f1fb"; } 564 | .fi-torso-business:before { content: "\f1fc"; } 565 | .fi-torso-female:before { content: "\f1fd"; } 566 | .fi-torso:before { content: "\f1fe"; } 567 | .fi-torsos-all-female:before { content: "\f1ff"; } 568 | .fi-torsos-all:before { content: "\f200"; } 569 | .fi-torsos-female-male:before { content: "\f201"; } 570 | .fi-torsos-male-female:before { content: "\f202"; } 571 | .fi-torsos:before { content: "\f203"; } 572 | .fi-trash:before { content: "\f204"; } 573 | .fi-trees:before { content: "\f205"; } 574 | .fi-trophy:before { content: "\f206"; } 575 | .fi-underline:before { content: "\f207"; } 576 | .fi-universal-access:before { content: "\f208"; } 577 | .fi-unlink:before { content: "\f209"; } 578 | .fi-unlock:before { content: "\f20a"; } 579 | .fi-upload-cloud:before { content: "\f20b"; } 580 | .fi-upload:before { content: "\f20c"; } 581 | .fi-usb:before { content: "\f20d"; } 582 | .fi-video:before { content: "\f20e"; } 583 | .fi-volume-none:before { content: "\f20f"; } 584 | .fi-volume-strike:before { content: "\f210"; } 585 | .fi-volume:before { content: "\f211"; } 586 | .fi-web:before { content: "\f212"; } 587 | .fi-wheelchair:before { content: "\f213"; } 588 | .fi-widget:before { content: "\f214"; } 589 | .fi-wrench:before { content: "\f215"; } 590 | .fi-x-circle:before { content: "\f216"; } 591 | .fi-x:before { content: "\f217"; } 592 | .fi-yen:before { content: "\f218"; } 593 | .fi-zoom-in:before { content: "\f219"; } 594 | .fi-zoom-out:before { content: "\f21a"; } 595 | -------------------------------------------------------------------------------- /resources/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } 428 | -------------------------------------------------------------------------------- /resources/css/style.css: -------------------------------------------------------------------------------- 1 | #todoApp-main-container { 2 | padding-top: 40px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | .size-12 { font-size: 12px; } 7 | 8 | .size-14 { font-size: 14px; } 9 | 10 | .size-16 { font-size: 16px; } 11 | 12 | .size-18 { font-size: 18px; } 13 | 14 | .size-21 { font-size: 21px; } 15 | 16 | .size-24 { font-size: 24px; } 17 | 18 | .size-36 { font-size: 36px; } 19 | 20 | .size-48 { font-size: 48px; } 21 | 22 | .size-60 { font-size: 60px; } 23 | 24 | .size-72 { font-size: 72px; } 25 | -------------------------------------------------------------------------------- /resources/fonts/foundation-icons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulienBernard/starter-laravel-angular-foundation/4c7f6a0a9e76f239213a3ff64436ecbe7886eb8f/resources/fonts/foundation-icons.eot -------------------------------------------------------------------------------- /resources/fonts/foundation-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulienBernard/starter-laravel-angular-foundation/4c7f6a0a9e76f239213a3ff64436ecbe7886eb8f/resources/fonts/foundation-icons.ttf -------------------------------------------------------------------------------- /resources/fonts/foundation-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JulienBernard/starter-laravel-angular-foundation/4c7f6a0a9e76f239213a3ff64436ecbe7886eb8f/resources/fonts/foundation-icons.woff -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | angular.module('todoApp', [ 2 | 'ngRoute', 3 | 'ngResource', 4 | 'ngStorage', 5 | 'appRoutes', 6 | 'enterStroke', 7 | 'MainController', 8 | 'TodoController', 9 | 'UserController', 10 | 'UserService', 11 | 'TodoService', 12 | ]); 13 | 14 | -------------------------------------------------------------------------------- /resources/js/appRoutes.js: -------------------------------------------------------------------------------- 1 | angular.module('appRoutes', []).config(['$routeProvider', '$locationProvider', '$httpProvider', 2 | function ($routeProvider, $locationProvider, $httpProvider) { 3 | $routeProvider 4 | .when('/', { 5 | templateUrl: '/partials/index', 6 | controller: 'MainController' 7 | }) 8 | .when('/:category/:action?/:id?', { 9 | templateUrl: function (params) { 10 | var allowedParams = ['category', 'action', 'id']; 11 | var paramVals = []; 12 | for (var key in params) { 13 | if (allowedParams.indexOf(key) !== -1) { 14 | paramVals.push(params[key]); 15 | } 16 | } 17 | return '/partials/' + paramVals.join('/'); 18 | } 19 | }) 20 | .otherwise({ 21 | redirectTo: '/' 22 | }); 23 | 24 | $locationProvider.html5Mode(true); 25 | 26 | $httpProvider.interceptors.push(['$rootScope', '$q', '$localStorage', 27 | function ($rootScope, $q, $localStorage) { 28 | return { 29 | request: function (config) { 30 | config.headers = config.headers || {}; 31 | if ($localStorage.token) { 32 | config.headers.Authorization = 'Bearer ' + $localStorage.token; 33 | } 34 | return config; 35 | }, 36 | response: function (res) { 37 | if (res.status === 401) { 38 | // Handle unauthenticated user. 39 | } 40 | return res || $q.when(res); 41 | } 42 | }; 43 | } 44 | ]); 45 | } 46 | ]); 47 | -------------------------------------------------------------------------------- /resources/js/controllers/MainController.js: -------------------------------------------------------------------------------- 1 | angular.module('MainController', []).controller('MainController', ['$scope', '$location', '$localStorage', 'User', 2 | function ($scope, $location, $localStorage, User) { 3 | /** 4 | * Responsible for highlighting the currently active menu item in the navbar. 5 | * 6 | * @param route 7 | * @returns {boolean} 8 | */ 9 | $scope.isActive = function (route) { 10 | return route === $location.path(); 11 | }; 12 | 13 | /** 14 | * Query the authenticated user by the Authorization token from the header. 15 | * 16 | * @param user {object} If provided, it won't query from database, but take this one. 17 | * @returns {null} 18 | */ 19 | $scope.getAuthenticatedUser = function (user) { 20 | if (user) { 21 | $scope.authenticatedUser = user; 22 | return; 23 | } 24 | 25 | if (typeof $localStorage.token === 'undefined') { 26 | return null; 27 | } 28 | 29 | new User().$getByToken(function (user) { 30 | $scope.authenticatedUser = user; 31 | }, function (err) { 32 | console.log(err); 33 | }); 34 | }; 35 | 36 | $scope.logout = function () { 37 | delete $localStorage.token; 38 | $scope.authenticatedUser = null; 39 | }; 40 | } 41 | ]); 42 | -------------------------------------------------------------------------------- /resources/js/controllers/TodoController.js: -------------------------------------------------------------------------------- 1 | angular.module('TodoController', []).controller('TodoController', ['$scope', '$location', '$routeParams', 'Todo', 2 | function ($scope, $location, $routeParams, Todo) { 3 | $scope.create = function () { 4 | var todo = new Todo({ 5 | body: this.body 6 | }); 7 | todo.$save(function (res) { 8 | $location.path('todos/view/' + res.id); 9 | $scope.body = ''; 10 | }, function (err) { 11 | console.log(err); 12 | }); 13 | }; 14 | 15 | $scope.find = function () { 16 | $scope.todos = Todo.query(); 17 | }; 18 | 19 | $scope.remove = function (todo) { 20 | todo.$remove(function (res) { 21 | if (res) { 22 | for (var i in $scope.todos) { 23 | if ($scope.todos[i] === todo) { 24 | $scope.todos.splice(i, 1); 25 | } 26 | } 27 | } 28 | }, function (err) { 29 | console.log(err); 30 | }) 31 | }; 32 | 33 | $scope.update = function (todo) { 34 | todo.$update(function (res) { 35 | }, function (err) { 36 | console.log(err); 37 | }); 38 | }; 39 | 40 | $scope.findOne = function () { 41 | var splitPath = $location.path().split('/'); 42 | var todoId = splitPath[splitPath.length - 1]; 43 | $scope.todo = Todo.get({todoId: todoId}); 44 | }; 45 | } 46 | ]); 47 | -------------------------------------------------------------------------------- /resources/js/controllers/UserController.js: -------------------------------------------------------------------------------- 1 | angular.module('UserController', []).controller('UserController', ['$scope', 'User', '$localStorage', '$location', 2 | function ($scope, User, $localStorage, $location) { 3 | $scope.login = function () { 4 | var user = new User({ 5 | username: this.username, 6 | password: this.password 7 | }); 8 | user.$login(function (user) { 9 | $localStorage.token = user.token; 10 | $scope.getAuthenticatedUser(user); 11 | $location.path('users/view/' + user.id); 12 | }, function (err) { 13 | console.log(err); 14 | }); 15 | }; 16 | 17 | $scope.create = function () { 18 | if (this.password != this.passwordConfirmation) { 19 | return alert('The passwords do not match.'); 20 | } 21 | var user = new User({ 22 | username: this.username, 23 | password: this.password, 24 | email: this.email 25 | }); 26 | user.$save(function (user) { 27 | $localStorage.token = user.token; 28 | $scope.getAuthenticatedUser(user); 29 | $location.path('users/view/' + user.id); 30 | }, function (err) { 31 | console.log(err); 32 | }); 33 | }; 34 | 35 | $scope.findOne = function () { 36 | var splitPath = $location.path().split('/'); 37 | var userId = splitPath[splitPath.length - 1]; 38 | $scope.user = User.get({userId: userId}); 39 | }; 40 | } 41 | ]); 42 | -------------------------------------------------------------------------------- /resources/js/directives/enterStroke.js: -------------------------------------------------------------------------------- 1 | // Reacts upon enter key press. 2 | angular.module('enterStroke', []).directive('enterStroke', 3 | function () { 4 | return function (scope, element, attrs) { 5 | element.bind('keydown keypress', function (event) { 6 | if (event.which === 13) { 7 | scope.$apply(function () { 8 | scope.$eval(attrs.enterStroke); 9 | }); 10 | event.preventDefault(); 11 | } 12 | }); 13 | }; 14 | } 15 | ); -------------------------------------------------------------------------------- /resources/js/libs/angular_modules/angular-resource.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license AngularJS v1.3.13 3 | * (c) 2010-2014 Google, Inc. http://angularjs.org 4 | * License: MIT 5 | */ 6 | (function(window, angular, undefined) {'use strict'; 7 | 8 | var $resourceMinErr = angular.$$minErr('$resource'); 9 | 10 | // Helper functions and regex to lookup a dotted path on an object 11 | // stopping at undefined/null. The path must be composed of ASCII 12 | // identifiers (just like $parse) 13 | var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/; 14 | 15 | function isValidDottedPath(path) { 16 | return (path != null && path !== '' && path !== 'hasOwnProperty' && 17 | MEMBER_NAME_REGEX.test('.' + path)); 18 | } 19 | 20 | function lookupDottedPath(obj, path) { 21 | if (!isValidDottedPath(path)) { 22 | throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path); 23 | } 24 | var keys = path.split('.'); 25 | for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) { 26 | var key = keys[i]; 27 | obj = (obj !== null) ? obj[key] : undefined; 28 | } 29 | return obj; 30 | } 31 | 32 | /** 33 | * Create a shallow copy of an object and clear other fields from the destination 34 | */ 35 | function shallowClearAndCopy(src, dst) { 36 | dst = dst || {}; 37 | 38 | angular.forEach(dst, function(value, key) { 39 | delete dst[key]; 40 | }); 41 | 42 | for (var key in src) { 43 | if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) { 44 | dst[key] = src[key]; 45 | } 46 | } 47 | 48 | return dst; 49 | } 50 | 51 | /** 52 | * @ngdoc module 53 | * @name ngResource 54 | * @description 55 | * 56 | * # ngResource 57 | * 58 | * The `ngResource` module provides interaction support with RESTful services 59 | * via the $resource service. 60 | * 61 | * 62 | *
63 | * 64 | * See {@link ngResource.$resource `$resource`} for usage. 65 | */ 66 | 67 | /** 68 | * @ngdoc service 69 | * @name $resource 70 | * @requires $http 71 | * 72 | * @description 73 | * A factory which creates a resource object that lets you interact with 74 | * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources. 75 | * 76 | * The returned resource object has action methods which provide high-level behaviors without 77 | * the need to interact with the low level {@link ng.$http $http} service. 78 | * 79 | * Requires the {@link ngResource `ngResource`} module to be installed. 80 | * 81 | * By default, trailing slashes will be stripped from the calculated URLs, 82 | * which can pose problems with server backends that do not expect that 83 | * behavior. This can be disabled by configuring the `$resourceProvider` like 84 | * this: 85 | * 86 | * ```js 87 | app.config(['$resourceProvider', function($resourceProvider) { 88 | // Don't strip trailing slashes from calculated URLs 89 | $resourceProvider.defaults.stripTrailingSlashes = false; 90 | }]); 91 | * ``` 92 | * 93 | * @param {string} url A parametrized URL template with parameters prefixed by `:` as in 94 | * `/user/:username`. If you are using a URL with a port number (e.g. 95 | * `http://example.com:8080/api`), it will be respected. 96 | * 97 | * If you are using a url with a suffix, just add the suffix, like this: 98 | * `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')` 99 | * or even `$resource('http://example.com/resource/:resource_id.:format')` 100 | * If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be 101 | * collapsed down to a single `.`. If you need this sequence to appear and not collapse then you 102 | * can escape it with `/\.`. 103 | * 104 | * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in 105 | * `actions` methods. If any of the parameter value is a function, it will be executed every time 106 | * when a param value needs to be obtained for a request (unless the param was overridden). 107 | * 108 | * Each key value in the parameter object is first bound to url template if present and then any 109 | * excess keys are appended to the url search query after the `?`. 110 | * 111 | * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in 112 | * URL `/path/greet?salutation=Hello`. 113 | * 114 | * If the parameter value is prefixed with `@` then the value for that parameter will be extracted 115 | * from the corresponding property on the `data` object (provided when calling an action method). For 116 | * example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam` 117 | * will be `data.someProp`. 118 | * 119 | * @param {Object.=} actions Hash with declaration of custom actions that should extend 120 | * the default set of resource actions. The declaration should be created in the format of {@link 121 | * ng.$http#usage $http.config}: 122 | * 123 | * {action1: {method:?, params:?, isArray:?, headers:?, ...}, 124 | * action2: {method:?, params:?, isArray:?, headers:?, ...}, 125 | * ...} 126 | * 127 | * Where: 128 | * 129 | * - **`action`** – {string} – The name of action. This name becomes the name of the method on 130 | * your resource object. 131 | * - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`, 132 | * `DELETE`, `JSONP`, etc). 133 | * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of 134 | * the parameter value is a function, it will be executed every time when a param value needs to 135 | * be obtained for a request (unless the param was overridden). 136 | * - **`url`** – {string} – action specific `url` override. The url templating is supported just 137 | * like for the resource-level urls. 138 | * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array, 139 | * see `returns` section. 140 | * - **`transformRequest`** – 141 | * `{function(data, headersGetter)|Array.}` – 142 | * transform function or an array of such functions. The transform function takes the http 143 | * request body and headers and returns its transformed (typically serialized) version. 144 | * By default, transformRequest will contain one function that checks if the request data is 145 | * an object and serializes to using `angular.toJson`. To prevent this behavior, set 146 | * `transformRequest` to an empty array: `transformRequest: []` 147 | * - **`transformResponse`** – 148 | * `{function(data, headersGetter)|Array.}` – 149 | * transform function or an array of such functions. The transform function takes the http 150 | * response body and headers and returns its transformed (typically deserialized) version. 151 | * By default, transformResponse will contain one function that checks if the response looks like 152 | * a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set 153 | * `transformResponse` to an empty array: `transformResponse: []` 154 | * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the 155 | * GET request, otherwise if a cache instance built with 156 | * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for 157 | * caching. 158 | * - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that 159 | * should abort the request when resolved. 160 | * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the 161 | * XHR object. See 162 | * [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5) 163 | * for more information. 164 | * - **`responseType`** - `{string}` - see 165 | * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType). 166 | * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods - 167 | * `response` and `responseError`. Both `response` and `responseError` interceptors get called 168 | * with `http response` object. See {@link ng.$http $http interceptors}. 169 | * 170 | * @param {Object} options Hash with custom settings that should extend the 171 | * default `$resourceProvider` behavior. The only supported option is 172 | * 173 | * Where: 174 | * 175 | * - **`stripTrailingSlashes`** – {boolean} – If true then the trailing 176 | * slashes from any calculated URL will be stripped. (Defaults to true.) 177 | * 178 | * @returns {Object} A resource "class" object with methods for the default set of resource actions 179 | * optionally extended with custom `actions`. The default set contains these actions: 180 | * ```js 181 | * { 'get': {method:'GET'}, 182 | * 'save': {method:'POST'}, 183 | * 'query': {method:'GET', isArray:true}, 184 | * 'remove': {method:'DELETE'}, 185 | * 'delete': {method:'DELETE'} }; 186 | * ``` 187 | * 188 | * Calling these methods invoke an {@link ng.$http} with the specified http method, 189 | * destination and parameters. When the data is returned from the server then the object is an 190 | * instance of the resource class. The actions `save`, `remove` and `delete` are available on it 191 | * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create, 192 | * read, update, delete) on server-side data like this: 193 | * ```js 194 | * var User = $resource('/user/:userId', {userId:'@id'}); 195 | * var user = User.get({userId:123}, function() { 196 | * user.abc = true; 197 | * user.$save(); 198 | * }); 199 | * ``` 200 | * 201 | * It is important to realize that invoking a $resource object method immediately returns an 202 | * empty reference (object or array depending on `isArray`). Once the data is returned from the 203 | * server the existing reference is populated with the actual data. This is a useful trick since 204 | * usually the resource is assigned to a model which is then rendered by the view. Having an empty 205 | * object results in no rendering, once the data arrives from the server then the object is 206 | * populated with the data and the view automatically re-renders itself showing the new data. This 207 | * means that in most cases one never has to write a callback function for the action methods. 208 | * 209 | * The action methods on the class object or instance object can be invoked with the following 210 | * parameters: 211 | * 212 | * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])` 213 | * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])` 214 | * - non-GET instance actions: `instance.$action([parameters], [success], [error])` 215 | * 216 | * Success callback is called with (value, responseHeaders) arguments. Error callback is called 217 | * with (httpResponse) argument. 218 | * 219 | * Class actions return empty instance (with additional properties below). 220 | * Instance actions return promise of the action. 221 | * 222 | * The Resource instances and collection have these additional properties: 223 | * 224 | * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this 225 | * instance or collection. 226 | * 227 | * On success, the promise is resolved with the same resource instance or collection object, 228 | * updated with data from server. This makes it easy to use in 229 | * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view 230 | * rendering until the resource(s) are loaded. 231 | * 232 | * On failure, the promise is resolved with the {@link ng.$http http response} object, without 233 | * the `resource` property. 234 | * 235 | * If an interceptor object was provided, the promise will instead be resolved with the value 236 | * returned by the interceptor. 237 | * 238 | * - `$resolved`: `true` after first server interaction is completed (either with success or 239 | * rejection), `false` before that. Knowing if the Resource has been resolved is useful in 240 | * data-binding. 241 | * 242 | * @example 243 | * 244 | * # Credit card resource 245 | * 246 | * ```js 247 | // Define CreditCard class 248 | var CreditCard = $resource('/user/:userId/card/:cardId', 249 | {userId:123, cardId:'@id'}, { 250 | charge: {method:'POST', params:{charge:true}} 251 | }); 252 | 253 | // We can retrieve a collection from the server 254 | var cards = CreditCard.query(function() { 255 | // GET: /user/123/card 256 | // server returns: [ {id:456, number:'1234', name:'Smith'} ]; 257 | 258 | var card = cards[0]; 259 | // each item is an instance of CreditCard 260 | expect(card instanceof CreditCard).toEqual(true); 261 | card.name = "J. Smith"; 262 | // non GET methods are mapped onto the instances 263 | card.$save(); 264 | // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'} 265 | // server returns: {id:456, number:'1234', name: 'J. Smith'}; 266 | 267 | // our custom method is mapped as well. 268 | card.$charge({amount:9.99}); 269 | // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'} 270 | }); 271 | 272 | // we can create an instance as well 273 | var newCard = new CreditCard({number:'0123'}); 274 | newCard.name = "Mike Smith"; 275 | newCard.$save(); 276 | // POST: /user/123/card {number:'0123', name:'Mike Smith'} 277 | // server returns: {id:789, number:'0123', name: 'Mike Smith'}; 278 | expect(newCard.id).toEqual(789); 279 | * ``` 280 | * 281 | * The object returned from this function execution is a resource "class" which has "static" method 282 | * for each action in the definition. 283 | * 284 | * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and 285 | * `headers`. 286 | * When the data is returned from the server then the object is an instance of the resource type and 287 | * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD 288 | * operations (create, read, update, delete) on server-side data. 289 | 290 | ```js 291 | var User = $resource('/user/:userId', {userId:'@id'}); 292 | User.get({userId:123}, function(user) { 293 | user.abc = true; 294 | user.$save(); 295 | }); 296 | ``` 297 | * 298 | * It's worth noting that the success callback for `get`, `query` and other methods gets passed 299 | * in the response that came from the server as well as $http header getter function, so one 300 | * could rewrite the above example and get access to http headers as: 301 | * 302 | ```js 303 | var User = $resource('/user/:userId', {userId:'@id'}); 304 | User.get({userId:123}, function(u, getResponseHeaders){ 305 | u.abc = true; 306 | u.$save(function(u, putResponseHeaders) { 307 | //u => saved user object 308 | //putResponseHeaders => $http header getter 309 | }); 310 | }); 311 | ``` 312 | * 313 | * You can also access the raw `$http` promise via the `$promise` property on the object returned 314 | * 315 | ``` 316 | var User = $resource('/user/:userId', {userId:'@id'}); 317 | User.get({userId:123}) 318 | .$promise.then(function(user) { 319 | $scope.user = user; 320 | }); 321 | ``` 322 | 323 | * # Creating a custom 'PUT' request 324 | * In this example we create a custom method on our resource to make a PUT request 325 | * ```js 326 | * var app = angular.module('app', ['ngResource', 'ngRoute']); 327 | * 328 | * // Some APIs expect a PUT request in the format URL/object/ID 329 | * // Here we are creating an 'update' method 330 | * app.factory('Notes', ['$resource', function($resource) { 331 | * return $resource('/notes/:id', null, 332 | * { 333 | * 'update': { method:'PUT' } 334 | * }); 335 | * }]); 336 | * 337 | * // In our controller we get the ID from the URL using ngRoute and $routeParams 338 | * // We pass in $routeParams and our Notes factory along with $scope 339 | * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes', 340 | function($scope, $routeParams, Notes) { 341 | * // First get a note object from the factory 342 | * var note = Notes.get({ id:$routeParams.id }); 343 | * $id = note.id; 344 | * 345 | * // Now call update passing in the ID first then the object you are updating 346 | * Notes.update({ id:$id }, note); 347 | * 348 | * // This will PUT /notes/ID with the note object in the request payload 349 | * }]); 350 | * ``` 351 | */ 352 | angular.module('ngResource', ['ng']). 353 | provider('$resource', function() { 354 | var provider = this; 355 | 356 | this.defaults = { 357 | // Strip slashes by default 358 | stripTrailingSlashes: true, 359 | 360 | // Default actions configuration 361 | actions: { 362 | 'get': {method: 'GET'}, 363 | 'save': {method: 'POST'}, 364 | 'query': {method: 'GET', isArray: true}, 365 | 'remove': {method: 'DELETE'}, 366 | 'delete': {method: 'DELETE'} 367 | } 368 | }; 369 | 370 | this.$get = ['$http', '$q', function($http, $q) { 371 | 372 | var noop = angular.noop, 373 | forEach = angular.forEach, 374 | extend = angular.extend, 375 | copy = angular.copy, 376 | isFunction = angular.isFunction; 377 | 378 | /** 379 | * We need our custom method because encodeURIComponent is too aggressive and doesn't follow 380 | * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set 381 | * (pchar) allowed in path segments: 382 | * segment = *pchar 383 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 384 | * pct-encoded = "%" HEXDIG HEXDIG 385 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 386 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 387 | * / "*" / "+" / "," / ";" / "=" 388 | */ 389 | function encodeUriSegment(val) { 390 | return encodeUriQuery(val, true). 391 | replace(/%26/gi, '&'). 392 | replace(/%3D/gi, '='). 393 | replace(/%2B/gi, '+'); 394 | } 395 | 396 | 397 | /** 398 | * This method is intended for encoding *key* or *value* parts of query component. We need a 399 | * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't 400 | * have to be encoded per http://tools.ietf.org/html/rfc3986: 401 | * query = *( pchar / "/" / "?" ) 402 | * pchar = unreserved / pct-encoded / sub-delims / ":" / "@" 403 | * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 404 | * pct-encoded = "%" HEXDIG HEXDIG 405 | * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 406 | * / "*" / "+" / "," / ";" / "=" 407 | */ 408 | function encodeUriQuery(val, pctEncodeSpaces) { 409 | return encodeURIComponent(val). 410 | replace(/%40/gi, '@'). 411 | replace(/%3A/gi, ':'). 412 | replace(/%24/g, '$'). 413 | replace(/%2C/gi, ','). 414 | replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); 415 | } 416 | 417 | function Route(template, defaults) { 418 | this.template = template; 419 | this.defaults = extend({}, provider.defaults, defaults); 420 | this.urlParams = {}; 421 | } 422 | 423 | Route.prototype = { 424 | setUrlParams: function(config, params, actionUrl) { 425 | var self = this, 426 | url = actionUrl || self.template, 427 | val, 428 | encodedVal; 429 | 430 | var urlParams = self.urlParams = {}; 431 | forEach(url.split(/\W/), function(param) { 432 | if (param === 'hasOwnProperty') { 433 | throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name."); 434 | } 435 | if (!(new RegExp("^\\d+$").test(param)) && param && 436 | (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) { 437 | urlParams[param] = true; 438 | } 439 | }); 440 | url = url.replace(/\\:/g, ':'); 441 | 442 | params = params || {}; 443 | forEach(self.urlParams, function(_, urlParam) { 444 | val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam]; 445 | if (angular.isDefined(val) && val !== null) { 446 | encodedVal = encodeUriSegment(val); 447 | url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) { 448 | return encodedVal + p1; 449 | }); 450 | } else { 451 | url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match, 452 | leadingSlashes, tail) { 453 | if (tail.charAt(0) == '/') { 454 | return tail; 455 | } else { 456 | return leadingSlashes + tail; 457 | } 458 | }); 459 | } 460 | }); 461 | 462 | // strip trailing slashes and set the url (unless this behavior is specifically disabled) 463 | if (self.defaults.stripTrailingSlashes) { 464 | url = url.replace(/\/+$/, '') || '/'; 465 | } 466 | 467 | // then replace collapse `/.` if found in the last URL path segment before the query 468 | // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x` 469 | url = url.replace(/\/\.(?=\w+($|\?))/, '.'); 470 | // replace escaped `/\.` with `/.` 471 | config.url = url.replace(/\/\\\./, '/.'); 472 | 473 | 474 | // set params - delegate param encoding to $http 475 | forEach(params, function(value, key) { 476 | if (!self.urlParams[key]) { 477 | config.params = config.params || {}; 478 | config.params[key] = value; 479 | } 480 | }); 481 | } 482 | }; 483 | 484 | 485 | function resourceFactory(url, paramDefaults, actions, options) { 486 | var route = new Route(url, options); 487 | 488 | actions = extend({}, provider.defaults.actions, actions); 489 | 490 | function extractParams(data, actionParams) { 491 | var ids = {}; 492 | actionParams = extend({}, paramDefaults, actionParams); 493 | forEach(actionParams, function(value, key) { 494 | if (isFunction(value)) { value = value(); } 495 | ids[key] = value && value.charAt && value.charAt(0) == '@' ? 496 | lookupDottedPath(data, value.substr(1)) : value; 497 | }); 498 | return ids; 499 | } 500 | 501 | function defaultResponseInterceptor(response) { 502 | return response.resource; 503 | } 504 | 505 | function Resource(value) { 506 | shallowClearAndCopy(value || {}, this); 507 | } 508 | 509 | Resource.prototype.toJSON = function() { 510 | var data = extend({}, this); 511 | delete data.$promise; 512 | delete data.$resolved; 513 | return data; 514 | }; 515 | 516 | forEach(actions, function(action, name) { 517 | var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method); 518 | 519 | Resource[name] = function(a1, a2, a3, a4) { 520 | var params = {}, data, success, error; 521 | 522 | /* jshint -W086 */ /* (purposefully fall through case statements) */ 523 | switch (arguments.length) { 524 | case 4: 525 | error = a4; 526 | success = a3; 527 | //fallthrough 528 | case 3: 529 | case 2: 530 | if (isFunction(a2)) { 531 | if (isFunction(a1)) { 532 | success = a1; 533 | error = a2; 534 | break; 535 | } 536 | 537 | success = a2; 538 | error = a3; 539 | //fallthrough 540 | } else { 541 | params = a1; 542 | data = a2; 543 | success = a3; 544 | break; 545 | } 546 | case 1: 547 | if (isFunction(a1)) success = a1; 548 | else if (hasBody) data = a1; 549 | else params = a1; 550 | break; 551 | case 0: break; 552 | default: 553 | throw $resourceMinErr('badargs', 554 | "Expected up to 4 arguments [params, data, success, error], got {0} arguments", 555 | arguments.length); 556 | } 557 | /* jshint +W086 */ /* (purposefully fall through case statements) */ 558 | 559 | var isInstanceCall = this instanceof Resource; 560 | var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data)); 561 | var httpConfig = {}; 562 | var responseInterceptor = action.interceptor && action.interceptor.response || 563 | defaultResponseInterceptor; 564 | var responseErrorInterceptor = action.interceptor && action.interceptor.responseError || 565 | undefined; 566 | 567 | forEach(action, function(value, key) { 568 | if (key != 'params' && key != 'isArray' && key != 'interceptor') { 569 | httpConfig[key] = copy(value); 570 | } 571 | }); 572 | 573 | if (hasBody) httpConfig.data = data; 574 | route.setUrlParams(httpConfig, 575 | extend({}, extractParams(data, action.params || {}), params), 576 | action.url); 577 | 578 | var promise = $http(httpConfig).then(function(response) { 579 | var data = response.data, 580 | promise = value.$promise; 581 | 582 | if (data) { 583 | // Need to convert action.isArray to boolean in case it is undefined 584 | // jshint -W018 585 | if (angular.isArray(data) !== (!!action.isArray)) { 586 | throw $resourceMinErr('badcfg', 587 | 'Error in resource configuration for action `{0}`. Expected response to ' + 588 | 'contain an {1} but got an {2}', name, action.isArray ? 'array' : 'object', 589 | angular.isArray(data) ? 'array' : 'object'); 590 | } 591 | // jshint +W018 592 | if (action.isArray) { 593 | value.length = 0; 594 | forEach(data, function(item) { 595 | if (typeof item === "object") { 596 | value.push(new Resource(item)); 597 | } else { 598 | // Valid JSON values may be string literals, and these should not be converted 599 | // into objects. These items will not have access to the Resource prototype 600 | // methods, but unfortunately there 601 | value.push(item); 602 | } 603 | }); 604 | } else { 605 | shallowClearAndCopy(data, value); 606 | value.$promise = promise; 607 | } 608 | } 609 | 610 | value.$resolved = true; 611 | 612 | response.resource = value; 613 | 614 | return response; 615 | }, function(response) { 616 | value.$resolved = true; 617 | 618 | (error || noop)(response); 619 | 620 | return $q.reject(response); 621 | }); 622 | 623 | promise = promise.then( 624 | function(response) { 625 | var value = responseInterceptor(response); 626 | (success || noop)(value, response.headers); 627 | return value; 628 | }, 629 | responseErrorInterceptor); 630 | 631 | if (!isInstanceCall) { 632 | // we are creating instance / collection 633 | // - set the initial promise 634 | // - return the instance / collection 635 | value.$promise = promise; 636 | value.$resolved = false; 637 | 638 | return value; 639 | } 640 | 641 | // instance call 642 | return promise; 643 | }; 644 | 645 | 646 | Resource.prototype['$' + name] = function(params, success, error) { 647 | if (isFunction(params)) { 648 | error = success; success = params; params = {}; 649 | } 650 | var result = Resource[name].call(this, params, this, success, error); 651 | return result.$promise || result; 652 | }; 653 | }); 654 | 655 | Resource.bind = function(additionalParamDefaults) { 656 | return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions); 657 | }; 658 | 659 | return Resource; 660 | } 661 | 662 | return resourceFactory; 663 | }]; 664 | }); 665 | 666 | 667 | })(window, window.angular); -------------------------------------------------------------------------------- /resources/js/libs/angular_modules/ng-storage.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | (function() { 4 | 5 | /** 6 | * @ngdoc overview 7 | * @name ngStorage 8 | */ 9 | 10 | angular.module('ngStorage', []). 11 | 12 | /** 13 | * @ngdoc object 14 | * @name ngStorage.$localStorage 15 | * @requires $rootScope 16 | * @requires $window 17 | */ 18 | 19 | factory('$localStorage', _storageFactory('localStorage')). 20 | 21 | /** 22 | * @ngdoc object 23 | * @name ngStorage.$sessionStorage 24 | * @requires $rootScope 25 | * @requires $window 26 | */ 27 | 28 | factory('$sessionStorage', _storageFactory('sessionStorage')); 29 | 30 | function _storageFactory(storageType) { 31 | return [ 32 | '$rootScope', 33 | '$window', 34 | '$log', 35 | 36 | function( 37 | $rootScope, 38 | $window, 39 | $log 40 | ){ 41 | // #9: Assign a placeholder object if Web Storage is unavailable to prevent breaking the entire AngularJS app 42 | var webStorage = $window[storageType] || ($log.warn('This browser does not support Web Storage!'), {}), 43 | $storage = { 44 | $default: function(items) { 45 | for (var k in items) { 46 | angular.isDefined($storage[k]) || ($storage[k] = items[k]); 47 | } 48 | 49 | return $storage; 50 | }, 51 | $reset: function(items) { 52 | for (var k in $storage) { 53 | '$' === k[0] || delete $storage[k]; 54 | } 55 | 56 | return $storage.$default(items); 57 | } 58 | }, 59 | _last$storage, 60 | _debounce; 61 | 62 | for (var i = 0, k; i < webStorage.length; i++) { 63 | // #8, #10: `webStorage.key(i)` may be an empty string (or throw an exception in IE9 if `webStorage` is empty) 64 | (k = webStorage.key(i)) && 'ngStorage-' === k.slice(0, 10) && ($storage[k.slice(10)] = angular.fromJson(webStorage.getItem(k))); 65 | } 66 | 67 | _last$storage = angular.copy($storage); 68 | 69 | $rootScope.$watch(function() { 70 | _debounce || (_debounce = setTimeout(function() { 71 | _debounce = null; 72 | 73 | if (!angular.equals($storage, _last$storage)) { 74 | angular.forEach($storage, function(v, k) { 75 | angular.isDefined(v) && '$' !== k[0] && webStorage.setItem('ngStorage-' + k, angular.toJson(v)); 76 | 77 | delete _last$storage[k]; 78 | }); 79 | 80 | for (var k in _last$storage) { 81 | webStorage.removeItem('ngStorage-' + k); 82 | } 83 | 84 | _last$storage = angular.copy($storage); 85 | } 86 | }, 100)); 87 | }); 88 | 89 | // #6: Use `$window.addEventListener` instead of `angular.element` to avoid the jQuery-specific `event.originalEvent` 90 | 'localStorage' === storageType && $window.addEventListener && $window.addEventListener('storage', function(event) { 91 | if ('ngStorage-' === event.key.slice(0, 10)) { 92 | event.newValue ? $storage[event.key.slice(10)] = angular.fromJson(event.newValue) : delete $storage[event.key.slice(10)]; 93 | 94 | _last$storage = angular.copy($storage); 95 | 96 | $rootScope.$apply(); 97 | } 98 | }); 99 | 100 | return $storage; 101 | } 102 | ]; 103 | } 104 | 105 | })(); 106 | -------------------------------------------------------------------------------- /resources/js/libs/fastclick.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";/** 2 | * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs. 3 | * 4 | * @codingstandard ftlabs-jsv2 5 | * @copyright The Financial Times Limited [All Rights Reserved] 6 | * @license MIT License (see LICENSE.txt) 7 | */ 8 | function a(b,d){function e(a,b){return function(){return a.apply(b,arguments)}}var f;if(d=d||{},this.trackingClick=!1,this.trackingClickStart=0,this.targetElement=null,this.touchStartX=0,this.touchStartY=0,this.lastTouchIdentifier=0,this.touchBoundary=d.touchBoundary||10,this.layer=b,this.tapDelay=d.tapDelay||200,this.tapTimeout=d.tapTimeout||700,!a.notNeeded(b)){for(var g=["onMouse","onClick","onTouchStart","onTouchMove","onTouchEnd","onTouchCancel"],h=this,i=0,j=g.length;j>i;i++)h[g[i]]=e(h[g[i]],h);c&&(b.addEventListener("mouseover",this.onMouse,!0),b.addEventListener("mousedown",this.onMouse,!0),b.addEventListener("mouseup",this.onMouse,!0)),b.addEventListener("click",this.onClick,!0),b.addEventListener("touchstart",this.onTouchStart,!1),b.addEventListener("touchmove",this.onTouchMove,!1),b.addEventListener("touchend",this.onTouchEnd,!1),b.addEventListener("touchcancel",this.onTouchCancel,!1),Event.prototype.stopImmediatePropagation||(b.removeEventListener=function(a,c,d){var e=Node.prototype.removeEventListener;"click"===a?e.call(b,a,c.hijacked||c,d):e.call(b,a,c,d)},b.addEventListener=function(a,c,d){var e=Node.prototype.addEventListener;"click"===a?e.call(b,a,c.hijacked||(c.hijacked=function(a){a.propagationStopped||c(a)}),d):e.call(b,a,c,d)}),"function"==typeof b.onclick&&(f=b.onclick,b.addEventListener("click",function(a){f(a)},!1),b.onclick=null)}}var b=navigator.userAgent.indexOf("Windows Phone")>=0,c=navigator.userAgent.indexOf("Android")>0&&!b,d=/iP(ad|hone|od)/.test(navigator.userAgent)&&!b,e=d&&/OS 4_\d(_\d)?/.test(navigator.userAgent),f=d&&/OS [6-7]_\d/.test(navigator.userAgent),g=navigator.userAgent.indexOf("BB10")>0;a.prototype.needsClick=function(a){switch(a.nodeName.toLowerCase()){case"button":case"select":case"textarea":if(a.disabled)return!0;break;case"input":if(d&&"file"===a.type||a.disabled)return!0;break;case"label":case"iframe":case"video":return!0}return/\bneedsclick\b/.test(a.className)},a.prototype.needsFocus=function(a){switch(a.nodeName.toLowerCase()){case"textarea":return!0;case"select":return!c;case"input":switch(a.type){case"button":case"checkbox":case"file":case"image":case"radio":case"submit":return!1}return!a.disabled&&!a.readOnly;default:return/\bneedsfocus\b/.test(a.className)}},a.prototype.sendClick=function(a,b){var c,d;document.activeElement&&document.activeElement!==a&&document.activeElement.blur(),d=b.changedTouches[0],c=document.createEvent("MouseEvents"),c.initMouseEvent(this.determineEventType(a),!0,!0,window,1,d.screenX,d.screenY,d.clientX,d.clientY,!1,!1,!1,!1,0,null),c.forwardedTouchEvent=!0,a.dispatchEvent(c)},a.prototype.determineEventType=function(a){return c&&"select"===a.tagName.toLowerCase()?"mousedown":"click"},a.prototype.focus=function(a){var b;d&&a.setSelectionRange&&0!==a.type.indexOf("date")&&"time"!==a.type&&"month"!==a.type?(b=a.value.length,a.setSelectionRange(b,b)):a.focus()},a.prototype.updateScrollParent=function(a){var b,c;if(b=a.fastClickScrollParent,!b||!b.contains(a)){c=a;do{if(c.scrollHeight>c.offsetHeight){b=c,a.fastClickScrollParent=c;break}c=c.parentElement}while(c)}b&&(b.fastClickLastScrollTop=b.scrollTop)},a.prototype.getTargetElementFromEventTarget=function(a){return a.nodeType===Node.TEXT_NODE?a.parentNode:a},a.prototype.onTouchStart=function(a){var b,c,f;if(a.targetTouches.length>1)return!0;if(b=this.getTargetElementFromEventTarget(a.target),c=a.targetTouches[0],d){if(f=window.getSelection(),f.rangeCount&&!f.isCollapsed)return!0;if(!e){if(c.identifier&&c.identifier===this.lastTouchIdentifier)return a.preventDefault(),!1;this.lastTouchIdentifier=c.identifier,this.updateScrollParent(b)}}return this.trackingClick=!0,this.trackingClickStart=a.timeStamp,this.targetElement=b,this.touchStartX=c.pageX,this.touchStartY=c.pageY,a.timeStamp-this.lastClickTimec||Math.abs(b.pageY-this.touchStartY)>c?!0:!1},a.prototype.onTouchMove=function(a){return this.trackingClick?((this.targetElement!==this.getTargetElementFromEventTarget(a.target)||this.touchHasMoved(a))&&(this.trackingClick=!1,this.targetElement=null),!0):!0},a.prototype.findControl=function(a){return void 0!==a.control?a.control:a.htmlFor?document.getElementById(a.htmlFor):a.querySelector("button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea")},a.prototype.onTouchEnd=function(a){var b,g,h,i,j,k=this.targetElement;if(!this.trackingClick)return!0;if(a.timeStamp-this.lastClickTimethis.tapTimeout)return!0;if(this.cancelNextClick=!1,this.lastClickTime=a.timeStamp,g=this.trackingClickStart,this.trackingClick=!1,this.trackingClickStart=0,f&&(j=a.changedTouches[0],k=document.elementFromPoint(j.pageX-window.pageXOffset,j.pageY-window.pageYOffset)||k,k.fastClickScrollParent=this.targetElement.fastClickScrollParent),h=k.tagName.toLowerCase(),"label"===h){if(b=this.findControl(k)){if(this.focus(k),c)return!1;k=b}}else if(this.needsFocus(k))return a.timeStamp-g>100||d&&window.top!==window&&"input"===h?(this.targetElement=null,!1):(this.focus(k),this.sendClick(k,a),d&&"select"===h||(this.targetElement=null,a.preventDefault()),!1);return d&&!e&&(i=k.fastClickScrollParent,i&&i.fastClickLastScrollTop!==i.scrollTop)?!0:(this.needsClick(k)||(a.preventDefault(),this.sendClick(k,a)),!1)},a.prototype.onTouchCancel=function(){this.trackingClick=!1,this.targetElement=null},a.prototype.onMouse=function(a){return this.targetElement?a.forwardedTouchEvent?!0:a.cancelable&&(!this.needsClick(this.targetElement)||this.cancelNextClick)?(a.stopImmediatePropagation?a.stopImmediatePropagation():a.propagationStopped=!0,a.stopPropagation(),a.preventDefault(),!1):!0:!0},a.prototype.onClick=function(a){var b;return this.trackingClick?(this.targetElement=null,this.trackingClick=!1,!0):"submit"===a.target.type&&0===a.detail?!0:(b=this.onMouse(a),b||(this.targetElement=null),b)},a.prototype.destroy=function(){var a=this.layer;c&&(a.removeEventListener("mouseover",this.onMouse,!0),a.removeEventListener("mousedown",this.onMouse,!0),a.removeEventListener("mouseup",this.onMouse,!0)),a.removeEventListener("click",this.onClick,!0),a.removeEventListener("touchstart",this.onTouchStart,!1),a.removeEventListener("touchmove",this.onTouchMove,!1),a.removeEventListener("touchend",this.onTouchEnd,!1),a.removeEventListener("touchcancel",this.onTouchCancel,!1)},a.notNeeded=function(a){var b,d,e,f;if("undefined"==typeof window.ontouchstart)return!0;if(d=+(/Chrome\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1]){if(!c)return!0;if(b=document.querySelector("meta[name=viewport]")){if(-1!==b.content.indexOf("user-scalable=no"))return!0;if(d>31&&document.documentElement.scrollWidth<=window.outerWidth)return!0}}if(g&&(e=navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/),e[1]>=10&&e[2]>=3&&(b=document.querySelector("meta[name=viewport]")))){if(-1!==b.content.indexOf("user-scalable=no"))return!0;if(document.documentElement.scrollWidth<=window.outerWidth)return!0}return"none"===a.style.msTouchAction||"manipulation"===a.style.touchAction?!0:(f=+(/Firefox\/([0-9]+)/.exec(navigator.userAgent)||[,0])[1],f>=27&&(b=document.querySelector("meta[name=viewport]"),b&&(-1!==b.content.indexOf("user-scalable=no")||document.documentElement.scrollWidth<=window.outerWidth))?!0:"none"===a.style.touchAction||"manipulation"===a.style.touchAction?!0:!1)},a.attach=function(b,c){return new a(b,c)},"function"==typeof define&&"object"==typeof define.amd&&define.amd?define(function(){return a}):"undefined"!=typeof module&&module.exports?(module.exports=a.attach,module.exports.FastClick=a):window.FastClick=a}(); 9 | -------------------------------------------------------------------------------- /resources/js/libs/modernizr.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Modernizr v2.8.3 3 | * www.modernizr.com 4 | * 5 | * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton 6 | * Available under the BSD and MIT licenses: www.modernizr.com/license/ 7 | */ 8 | window.Modernizr=function(a,b,c){function d(a){t.cssText=a}function e(a,b){return d(x.join(a+";")+(b||""))}function f(a,b){return typeof a===b}function g(a,b){return!!~(""+a).indexOf(b)}function h(a,b){for(var d in a){var e=a[d];if(!g(e,"-")&&t[e]!==c)return"pfx"==b?e:!0}return!1}function i(a,b,d){for(var e in a){var g=b[a[e]];if(g!==c)return d===!1?a[e]:f(g,"function")?g.bind(d||b):g}return!1}function j(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+z.join(d+" ")+d).split(" ");return f(b,"string")||f(b,"undefined")?h(e,b):(e=(a+" "+A.join(d+" ")+d).split(" "),i(e,b,c))}function k(){o.input=function(c){for(var d=0,e=c.length;e>d;d++)E[c[d]]=!!(c[d]in u);return E.list&&(E.list=!(!b.createElement("datalist")||!a.HTMLDataListElement)),E}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),o.inputtypes=function(a){for(var d,e,f,g=0,h=a.length;h>g;g++)u.setAttribute("type",e=a[g]),d="text"!==u.type,d&&(u.value=v,u.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(e)&&u.style.WebkitAppearance!==c?(q.appendChild(u),f=b.defaultView,d=f.getComputedStyle&&"textfield"!==f.getComputedStyle(u,null).WebkitAppearance&&0!==u.offsetHeight,q.removeChild(u)):/^(search|tel)$/.test(e)||(d=/^(url|email)$/.test(e)?u.checkValidity&&u.checkValidity()===!1:u.value!=v)),D[a[g]]=!!d;return D}("search tel url email datetime date month week time datetime-local number range color".split(" "))}var l,m,n="2.8.3",o={},p=!0,q=b.documentElement,r="modernizr",s=b.createElement(r),t=s.style,u=b.createElement("input"),v=":)",w={}.toString,x=" -webkit- -moz- -o- -ms- ".split(" "),y="Webkit Moz O ms",z=y.split(" "),A=y.toLowerCase().split(" "),B={svg:"http://www.w3.org/2000/svg"},C={},D={},E={},F=[],G=F.slice,H=function(a,c,d,e){var f,g,h,i,j=b.createElement("div"),k=b.body,l=k||b.createElement("body");if(parseInt(d,10))for(;d--;)h=b.createElement("div"),h.id=e?e[d]:r+(d+1),j.appendChild(h);return f=["­",'"].join(""),j.id=r,(k?j:l).innerHTML+=f,l.appendChild(j),k||(l.style.background="",l.style.overflow="hidden",i=q.style.overflow,q.style.overflow="hidden",q.appendChild(l)),g=c(j,a),k?j.parentNode.removeChild(j):(l.parentNode.removeChild(l),q.style.overflow=i),!!g},I=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b)&&c(b).matches||!1;var d;return H("@media "+b+" { #"+r+" { position: absolute; } }",function(b){d="absolute"==(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle).position}),d},J=function(){function a(a,e){e=e||b.createElement(d[a]||"div"),a="on"+a;var g=a in e;return g||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(a,""),g=f(e[a],"function"),f(e[a],"undefined")||(e[a]=c),e.removeAttribute(a))),e=null,g}var d={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return a}(),K={}.hasOwnProperty;m=f(K,"undefined")||f(K.call,"undefined")?function(a,b){return b in a&&f(a.constructor.prototype[b],"undefined")}:function(a,b){return K.call(a,b)},Function.prototype.bind||(Function.prototype.bind=function(a){var b=this;if("function"!=typeof b)throw new TypeError;var c=G.call(arguments,1),d=function(){if(this instanceof d){var e=function(){};e.prototype=b.prototype;var f=new e,g=b.apply(f,c.concat(G.call(arguments)));return Object(g)===g?g:f}return b.apply(a,c.concat(G.call(arguments)))};return d}),C.flexbox=function(){return j("flexWrap")},C.flexboxlegacy=function(){return j("boxDirection")},C.canvas=function(){var a=b.createElement("canvas");return!(!a.getContext||!a.getContext("2d"))},C.canvastext=function(){return!(!o.canvas||!f(b.createElement("canvas").getContext("2d").fillText,"function"))},C.webgl=function(){return!!a.WebGLRenderingContext},C.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:H(["@media (",x.join("touch-enabled),("),r,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=9===a.offsetTop}),c},C.geolocation=function(){return"geolocation"in navigator},C.postmessage=function(){return!!a.postMessage},C.websqldatabase=function(){return!!a.openDatabase},C.indexedDB=function(){return!!j("indexedDB",a)},C.hashchange=function(){return J("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},C.history=function(){return!(!a.history||!history.pushState)},C.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},C.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},C.rgba=function(){return d("background-color:rgba(150,255,150,.5)"),g(t.backgroundColor,"rgba")},C.hsla=function(){return d("background-color:hsla(120,40%,100%,.5)"),g(t.backgroundColor,"rgba")||g(t.backgroundColor,"hsla")},C.multiplebgs=function(){return d("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(t.background)},C.backgroundsize=function(){return j("backgroundSize")},C.borderimage=function(){return j("borderImage")},C.borderradius=function(){return j("borderRadius")},C.boxshadow=function(){return j("boxShadow")},C.textshadow=function(){return""===b.createElement("div").style.textShadow},C.opacity=function(){return e("opacity:.55"),/^0.55$/.test(t.opacity)},C.cssanimations=function(){return j("animationName")},C.csscolumns=function(){return j("columnCount")},C.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return d((a+"-webkit- ".split(" ").join(b+a)+x.join(c+a)).slice(0,-a.length)),g(t.backgroundImage,"gradient")},C.cssreflections=function(){return j("boxReflect")},C.csstransforms=function(){return!!j("transform")},C.csstransforms3d=function(){var a=!!j("perspective");return a&&"webkitPerspective"in q.style&&H("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b){a=9===b.offsetLeft&&3===b.offsetHeight}),a},C.csstransitions=function(){return j("transition")},C.fontface=function(){var a;return H('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&0===g.indexOf(d.split(" ")[0])}),a},C.generatedcontent=function(){var a;return H(["#",r,"{font:0/0 a}#",r,':after{content:"',v,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},C.video=function(){var a=b.createElement("video"),c=!1;try{(c=!!a.canPlayType)&&(c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""))}catch(d){}return c},C.audio=function(){var a=b.createElement("audio"),c=!1;try{(c=!!a.canPlayType)&&(c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(d){}return c},C.localstorage=function(){try{return localStorage.setItem(r,r),localStorage.removeItem(r),!0}catch(a){return!1}},C.sessionstorage=function(){try{return sessionStorage.setItem(r,r),sessionStorage.removeItem(r),!0}catch(a){return!1}},C.webworkers=function(){return!!a.Worker},C.applicationcache=function(){return!!a.applicationCache},C.svg=function(){return!!b.createElementNS&&!!b.createElementNS(B.svg,"svg").createSVGRect},C.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==B.svg},C.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(w.call(b.createElementNS(B.svg,"animate")))},C.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(w.call(b.createElementNS(B.svg,"clipPath")))};for(var L in C)m(C,L)&&(l=L.toLowerCase(),o[l]=C[L](),F.push((o[l]?"":"no-")+l));return o.input||k(),o.addTest=function(a,b){if("object"==typeof a)for(var d in a)m(a,d)&&o.addTest(d,a[d]);else{if(a=a.toLowerCase(),o[a]!==c)return o;b="function"==typeof b?b():b,"undefined"!=typeof p&&p&&(q.className+=" "+(b?"":"no-")+a),o[a]=b}return o},d(""),s=u=null,function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=s.elements;return"string"==typeof a?a.split(" "):a}function e(a){var b=r[a[p]];return b||(b={},q++,a[p]=q,r[q]=b),b}function f(a,c,d){if(c||(c=b),k)return c.createElement(a);d||(d=e(c));var f;return f=d.cache[a]?d.cache[a].cloneNode():o.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!f.canHaveChildren||n.test(a)||f.tagUrn?f:d.frag.appendChild(f)}function g(a,c){if(a||(a=b),k)return a.createDocumentFragment();c=c||e(a);for(var f=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)f.createElement(h[g]);return f}function h(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return s.shivMethods?f(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(s,b.frag)}function i(a){a||(a=b);var d=e(a);return!s.shivCSS||j||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),k||h(a,d),a}var j,k,l="3.7.0",m=a.html5||{},n=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,o=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,p="_html5shiv",q=0,r={};!function(){try{var a=b.createElement("a");a.innerHTML="",j="hidden"in a,k=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){j=!0,k=!0}}();var s={elements:m.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:l,shivCSS:m.shivCSS!==!1,supportsUnknownElements:k,shivMethods:m.shivMethods!==!1,type:"default",shivDocument:i,createElement:f,createDocumentFragment:g};a.html5=s,i(b)}(this,b),o._version=n,o._prefixes=x,o._domPrefixes=A,o._cssomPrefixes=z,o.mq=I,o.hasEvent=J,o.testProp=function(a){return h([a])},o.testAllProps=j,o.testStyles=H,o.prefixed=function(a,b,c){return b?j(a,b,c):j(a,"pfx")},q.className=q.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(p?" js "+F.join(" "):""),o}(this,this.document); 9 | -------------------------------------------------------------------------------- /resources/js/services/TodoService.js: -------------------------------------------------------------------------------- 1 | angular.module('TodoService', []).factory('Todo', ['$resource', 2 | function ($resource) { 3 | return $resource('/api/todo/:todoId', { 4 | todoId: '@id' 5 | }, { 6 | update: { 7 | method: 'PUT' 8 | } 9 | }); 10 | } 11 | ]); -------------------------------------------------------------------------------- /resources/js/services/UserService.js: -------------------------------------------------------------------------------- 1 | angular.module('UserService', []).factory('User', ['$resource', 2 | function ($resource) { 3 | return $resource('/api/user/:userId', { 4 | userId: '@id' 5 | }, { 6 | update: { 7 | method: 'PUT' 8 | }, 9 | login: { 10 | method: 'POST', 11 | url: '/api/user/login' 12 | }, 13 | getByToken: { 14 | method: 'GET', 15 | url: '/api/user/getByToken' 16 | } 17 | }); 18 | } 19 | ]); 20 | -------------------------------------------------------------------------------- /resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | "Passwords must be at least six characters and match the confirmation.", 17 | "user" => "We can't find a user with that e-mail address.", 18 | "token" => "This password reset token is invalid.", 19 | "sent" => "We have e-mailed your password reset link!", 20 | "reset" => "Your password has been reset!", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /resources/lang/en/validation.php: -------------------------------------------------------------------------------- 1 | "The :attribute must be accepted.", 17 | "active_url" => "The :attribute is not a valid URL.", 18 | "after" => "The :attribute must be a date after :date.", 19 | "alpha" => "The :attribute may only contain letters.", 20 | "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.", 21 | "alpha_num" => "The :attribute may only contain letters and numbers.", 22 | "array" => "The :attribute must be an array.", 23 | "before" => "The :attribute must be a date before :date.", 24 | "between" => [ 25 | "numeric" => "The :attribute must be between :min and :max.", 26 | "file" => "The :attribute must be between :min and :max kilobytes.", 27 | "string" => "The :attribute must be between :min and :max characters.", 28 | "array" => "The :attribute must have between :min and :max items.", 29 | ], 30 | "boolean" => "The :attribute field must be true or false.", 31 | "confirmed" => "The :attribute confirmation does not match.", 32 | "date" => "The :attribute is not a valid date.", 33 | "date_format" => "The :attribute does not match the format :format.", 34 | "different" => "The :attribute and :other must be different.", 35 | "digits" => "The :attribute must be :digits digits.", 36 | "digits_between" => "The :attribute must be between :min and :max digits.", 37 | "email" => "The :attribute must be a valid email address.", 38 | "filled" => "The :attribute field is required.", 39 | "exists" => "The selected :attribute is invalid.", 40 | "image" => "The :attribute must be an image.", 41 | "in" => "The selected :attribute is invalid.", 42 | "integer" => "The :attribute must be an integer.", 43 | "ip" => "The :attribute must be a valid IP address.", 44 | "max" => [ 45 | "numeric" => "The :attribute may not be greater than :max.", 46 | "file" => "The :attribute may not be greater than :max kilobytes.", 47 | "string" => "The :attribute may not be greater than :max characters.", 48 | "array" => "The :attribute may not have more than :max items.", 49 | ], 50 | "mimes" => "The :attribute must be a file of type: :values.", 51 | "min" => [ 52 | "numeric" => "The :attribute must be at least :min.", 53 | "file" => "The :attribute must be at least :min kilobytes.", 54 | "string" => "The :attribute must be at least :min characters.", 55 | "array" => "The :attribute must have at least :min items.", 56 | ], 57 | "not_in" => "The selected :attribute is invalid.", 58 | "numeric" => "The :attribute must be a number.", 59 | "regex" => "The :attribute format is invalid.", 60 | "required" => "The :attribute field is required.", 61 | "required_if" => "The :attribute field is required when :other is :value.", 62 | "required_with" => "The :attribute field is required when :values is present.", 63 | "required_with_all" => "The :attribute field is required when :values is present.", 64 | "required_without" => "The :attribute field is required when :values is not present.", 65 | "required_without_all" => "The :attribute field is required when none of :values are present.", 66 | "same" => "The :attribute and :other must match.", 67 | "size" => [ 68 | "numeric" => "The :attribute must be :size.", 69 | "file" => "The :attribute must be :size kilobytes.", 70 | "string" => "The :attribute must be :size characters.", 71 | "array" => "The :attribute must contain :size items.", 72 | ], 73 | "unique" => "The :attribute has already been taken.", 74 | "url" => "The :attribute format is invalid.", 75 | "timezone" => "The :attribute must be a valid zone.", 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Custom Validation Language Lines 80 | |-------------------------------------------------------------------------- 81 | | 82 | | Here you may specify custom validation messages for attributes using the 83 | | convention "attribute.rule" to name the lines. This makes it quick to 84 | | specify a specific custom language line for a given attribute rule. 85 | | 86 | */ 87 | 88 | 'custom' => [ 89 | 'attribute-name' => [ 90 | 'rule-name' => 'custom-message', 91 | ], 92 | ], 93 | 94 | /* 95 | |-------------------------------------------------------------------------- 96 | | Custom Validation Attributes 97 | |-------------------------------------------------------------------------- 98 | | 99 | | The following language lines are used to swap attribute place-holders 100 | | with something more reader friendly such as E-Mail Address instead 101 | | of "email". This simply helps us make messages a little cleaner. 102 | | 103 | */ 104 | 105 | 'attributes' => [], 106 | 107 | ]; 108 | -------------------------------------------------------------------------------- /resources/views/errors/503.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 33 | 34 | 35 |
36 |
37 |
Be right back.
38 |
39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /resources/views/layout.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Todo 7 | 8 | 9 | 10 | 11 | 12 | 33 | 34 |
35 |
36 |
37 |
38 | 39 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /resources/views/partials/auth/login.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 7 |
8 |
9 | 10 | 12 |
13 |
14 |
15 |
16 | 17 |
18 |
19 |
20 | -------------------------------------------------------------------------------- /resources/views/partials/auth/signup.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 7 |
8 |
9 | 10 | 12 |
13 |
14 |
15 |
16 | 17 | 19 |
20 |
21 | 22 | 24 |
25 |
26 |
27 |
28 | 29 |
30 |
31 |
-------------------------------------------------------------------------------- /resources/views/partials/index.php: -------------------------------------------------------------------------------- 1 |

2 | Hello {{authenticatedUser.username}}, thank you for installing me. 3 |

4 |

5 | Hello guest, thank you for installing me. 6 |

7 | -------------------------------------------------------------------------------- /resources/views/partials/todos/create.php: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Create a new todo task

4 |
5 |
6 |
7 |
8 | 12 |
13 |
14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /resources/views/partials/todos/index.php: -------------------------------------------------------------------------------- 1 |
2 |

3 | There are no todos right now, create one! 4 |

5 | 6 |
7 |
8 |
9 |
10 | 12 |
13 |
14 | 15 | 16 |   17 | 18 | 19 |
20 |
21 |
22 |
23 | 24 |

25 | Create another task 26 |

27 |
-------------------------------------------------------------------------------- /resources/views/partials/todos/view.php: -------------------------------------------------------------------------------- 1 |
2 |

View Todo #{{todo.id}} Remove this task

3 |

4 | {{todo.body}} 5 |

6 |
7 | 8 | 9 | -------------------------------------------------------------------------------- /resources/views/partials/users/view.php: -------------------------------------------------------------------------------- 1 |
2 |

{{user.username}}

3 | Email: {{user.email}} 4 |
5 | -------------------------------------------------------------------------------- /server.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | 9 | $uri = urldecode( 10 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 11 | ); 12 | 13 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 14 | // built-in PHP web server. This provides a convenient way to test a Laravel 15 | // application without having installed a "real" web server software here. 16 | if ($uri !== '/' and file_exists(__DIR__.'/public'.$uri)) 17 | { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /storage/.gitignore: -------------------------------------------------------------------------------- 1 | laravel.log -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | routes.php 3 | compiled.php 4 | services.json 5 | events.scanned.php 6 | routes.scanned.php 7 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/ExampleTest.php: -------------------------------------------------------------------------------- 1 | call('GET', '/'); 13 | 14 | $this->assertEquals(200, $response->getStatusCode()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | make('Illuminate\Contracts\Console\Kernel')->bootstrap(); 15 | 16 | return $app; 17 | } 18 | 19 | } 20 | --------------------------------------------------------------------------------