Repository: scaffeinate/socify Branch: master Commit: 19d02bb72685 Files: 218 Total size: 294.4 KB Directory structure: gitextract_ctb4iudp/ ├── .gitignore ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── app/ │ ├── assets/ │ │ ├── images/ │ │ │ └── .keep │ │ ├── javascripts/ │ │ │ ├── application.js │ │ │ ├── comments.js │ │ │ ├── events.js │ │ │ ├── follows.js │ │ │ ├── home.js │ │ │ ├── likes.js │ │ │ ├── posts.js │ │ │ └── users.js │ │ └── stylesheets/ │ │ ├── application.css.scss │ │ ├── comments.css.scss │ │ ├── events.css.scss │ │ ├── follows.css.scss │ │ ├── home.css.scss │ │ ├── likes.css.scss │ │ ├── posts.css.scss │ │ ├── styles.css.scss │ │ ├── users.css.scss │ │ └── variables.css.scss │ ├── controllers/ │ │ ├── application_controller.rb │ │ ├── comments_controller.rb │ │ ├── concerns/ │ │ │ └── .keep │ │ ├── events_controller.rb │ │ ├── follows_controller.rb │ │ ├── home_controller.rb │ │ ├── likes_controller.rb │ │ ├── posts_controller.rb │ │ └── users_controller.rb │ ├── helpers/ │ │ ├── application_helper.rb │ │ ├── comments_helper.rb │ │ ├── events_helper.rb │ │ ├── follows_helper.rb │ │ ├── home_helper.rb │ │ ├── likes_helper.rb │ │ ├── posts_helper.rb │ │ └── users_helper.rb │ ├── mailers/ │ │ └── .keep │ ├── models/ │ │ ├── .keep │ │ ├── comment.rb │ │ ├── concerns/ │ │ │ ├── .keep │ │ │ └── shared/ │ │ │ └── callbacks.rb │ │ ├── event.rb │ │ ├── follow.rb │ │ ├── mention.rb │ │ ├── merit/ │ │ │ ├── badge_rules.rb │ │ │ ├── point_rules.rb │ │ │ └── rank_rules.rb │ │ ├── post.rb │ │ └── user.rb │ ├── serializers/ │ │ └── event_calendar_serializer.rb │ ├── uploaders/ │ │ └── avatar_uploader.rb │ └── views/ │ ├── comments/ │ │ ├── _comment.html.erb │ │ ├── _form.html.erb │ │ ├── create.js.erb │ │ └── destroy.js.erb │ ├── devise/ │ │ ├── confirmations/ │ │ │ └── new.html.erb │ │ ├── mailer/ │ │ │ ├── confirmation_instructions.html.erb │ │ │ ├── reset_password_instructions.html.erb │ │ │ └── unlock_instructions.html.erb │ │ ├── passwords/ │ │ │ ├── edit.html.erb │ │ │ └── new.html.erb │ │ ├── registrations/ │ │ │ ├── edit.html.erb │ │ │ └── new.html.erb │ │ ├── sessions/ │ │ │ └── new.html.erb │ │ ├── shared/ │ │ │ └── _links.html.erb │ │ └── unlocks/ │ │ └── new.html.erb │ ├── events/ │ │ ├── _event.html.erb │ │ ├── _form.html.erb │ │ ├── calendar.html.erb │ │ ├── destroy.js.erb │ │ ├── edit.html.erb │ │ ├── new.html.erb │ │ └── show.html.erb │ ├── follows/ │ │ ├── _form.html.erb │ │ ├── create.js.erb │ │ └── destroy.js.erb │ ├── home/ │ │ ├── about.html.erb │ │ ├── find_friends.html.erb │ │ ├── find_friends.js.erb │ │ ├── front.html.erb │ │ ├── front.js.erb │ │ ├── index.html.erb │ │ └── index.js.erb │ ├── layouts/ │ │ └── application.html.erb │ ├── likes/ │ │ ├── _form.html.erb │ │ ├── create.js.erb │ │ └── destroy.js.erb │ ├── posts/ │ │ ├── _form.html.erb │ │ ├── _post.html.erb │ │ ├── destroy.js.erb │ │ ├── edit.html.erb │ │ └── show.html.erb │ ├── public_activity/ │ │ ├── comment/ │ │ │ └── _create.html.erb │ │ ├── event/ │ │ │ ├── _create.html.erb │ │ │ └── _like.html.erb │ │ ├── follow/ │ │ │ └── _create.html.erb │ │ └── post/ │ │ ├── _create.html.erb │ │ └── _like.html.erb │ ├── shared/ │ │ ├── _actions.html.erb │ │ ├── _activity.html.erb │ │ ├── _avatar.html.erb │ │ ├── _cover.html.erb │ │ ├── _created_at.html.erb │ │ ├── _links.html.erb │ │ ├── _navbar.html.erb │ │ ├── _no_resource.html.erb │ │ ├── _paginate.html.erb │ │ ├── _paginate.js.erb │ │ └── _user_info.html.erb │ └── users/ │ ├── _user.html.erb │ ├── deactivate.html.erb │ ├── edit.html.erb │ ├── followers.html.erb │ ├── followers.js.erb │ ├── friends.html.erb │ ├── friends.js.erb │ ├── show.html.erb │ └── show.js.erb ├── bin/ │ ├── bundle │ ├── rails │ ├── rake │ ├── setup │ └── spring ├── config/ │ ├── application.rb │ ├── boot.rb │ ├── database.yml │ ├── environment.rb │ ├── environments/ │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers/ │ │ ├── assets.rb │ │ ├── backtrace_silencers.rb │ │ ├── carrierwave.rb │ │ ├── cookies_serializer.rb │ │ ├── devise.rb │ │ ├── filter_parameter_logging.rb │ │ ├── friendly_id.rb │ │ ├── inflections.rb │ │ ├── merit.rb │ │ ├── mime_types.rb │ │ ├── session_store.rb │ │ └── wrap_parameters.rb │ ├── locales/ │ │ ├── devise.en.yml │ │ └── en.yml │ ├── puma.rb │ ├── routes.rb │ └── secrets.yml ├── config.ru ├── db/ │ ├── migrate/ │ │ ├── 20150701024445_devise_create_users.rb │ │ ├── 20150702015915_create_posts.rb │ │ ├── 20150702020527_create_activities.rb │ │ ├── 20150703041854_acts_as_votable_migration.rb │ │ ├── 20150703053202_add_cached_votes_to_posts.rb │ │ ├── 20150703054721_create_comments.rb │ │ ├── 20150703161656_add_counter_cache_to_posts.rb │ │ ├── 20150703194107_acts_as_follower_migration.rb │ │ ├── 20150709034258_create_events.rb │ │ ├── 20150709050651_add_votes_comments_count_to_events.rb │ │ ├── 20150710004012_add_fields_to_user.rb │ │ ├── 20150710030803_add_posts_count_to_users.rb │ │ ├── 20150710044606_create_friendly_id_slugs.rb │ │ ├── 20150710044624_add_slug_to_users.rb │ │ ├── 20150723052523_add_content_html_to_posts.rb │ │ ├── 20150723052743_add_comment_html_to_comments.rb │ │ ├── 20170428044229_rename_events_when_column.rb │ │ ├── 20170613183107_add_merit_fields_to_users.rb │ │ ├── 20170613183243_create_merit_actions.rb │ │ ├── 20170613183244_create_merit_activity_logs.rb │ │ ├── 20170613183245_create_sashes.rb │ │ ├── 20170613183246_create_badges_sashes.rb │ │ └── 20170613183247_create_scores_and_points.rb │ ├── schema.rb │ └── seeds.rb ├── lib/ │ ├── assets/ │ │ └── .keep │ └── tasks/ │ ├── .keep │ └── populate.rake ├── public/ │ ├── 404.html │ ├── 422.html │ ├── 500.html │ └── robots.txt ├── test/ │ ├── controllers/ │ │ ├── .keep │ │ ├── comments_controller_test.rb │ │ ├── events_controller_test.rb │ │ ├── follows_controller_test.rb │ │ ├── home_controller_test.rb │ │ ├── likes_controller_test.rb │ │ ├── posts_controller_test.rb │ │ └── users_controller_test.rb │ ├── fixtures/ │ │ ├── .keep │ │ ├── events.yml │ │ ├── posts.yml │ │ └── users.yml │ ├── helpers/ │ │ ├── .keep │ │ ├── comments_helper_test.rb │ │ ├── events_helper_test.rb │ │ ├── follows_helper_test.rb │ │ ├── home_helper_test.rb │ │ ├── likes_helper_test.rb │ │ ├── posts_helper_test.rb │ │ └── users_helper_test.rb │ ├── integration/ │ │ └── .keep │ ├── mailers/ │ │ └── .keep │ ├── models/ │ │ ├── .keep │ │ ├── event_test.rb │ │ ├── post_test.rb │ │ └── user_test.rb │ └── test_helper.rb └── vendor/ └── assets/ ├── javascripts/ │ ├── .keep │ ├── bindWithDelay.js │ └── jquery.datetimepicker.js └── stylesheets/ ├── .keep ├── fontello-embedded.css └── jquery.datetimepicker.css ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # See https://help.github.com/articles/ignoring-files for more about ignoring files. # # If you find yourself ignoring temporary files generated by your text editor # or operating system, you probably want to add a global ignore instead: # git config --global core.excludesfile '~/.gitignore_global' *.rbc capybara-*.html .rspec /log /tmp /db/*.sqlite3 /public/system /public/uploads /db/*.sqlite3-journal /coverage/ /spec/tmp **.orig rerun.txt pickle-email-*.html # Ignore all .idea files generated by RubyMine *.idea/ # TODO Comment out these rules if you are OK with secrets being uploaded to the repo config/initializers/secret_token.rb ## Environment normalisation: /.bundle /vendor/bundle # these should all be checked in to normalise the environment: # Gemfile.lock, .ruby-version, .ruby-gemset # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc # if using bower-rails ignore default bower_components path bower.json files /vendor/assets/bower_components *.bowerrc bower.json # Ignore pow environment settings .powenv node_modules/ ================================================ FILE: Gemfile ================================================ source 'https://rubygems.org' ruby '~> 2.3.1' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '5.0.2' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0.0' # Use Uglifier as compressor for JavaScript assets gem 'uglifier', '>= 1.3.0' # Use jquery as the JavaScript library gem 'jquery-rails' gem 'merit' # Used to implement at.js for auto complete mentions/emojis gem 'jquery-atwho-rails' # Use twitter bootstrap sass gem 'bootstrap-sass', '~> 3.2.0' gem 'autoprefixer-rails' gem 'font-awesome-rails' group :development do gem 'spring' gem 'better_errors' gem 'binding_of_caller' gem 'letter_opener' gem 'guard' gem 'guard-rspec', '~> 4.2.8' end group :development, :test do gem 'puma' gem 'sqlite3' end group :production do gem 'pg' gem 'unicorn' gem 'rails_12factor' gem 'fog' gem 'fog-aws' end gem 'devise' gem 'carrierwave' gem 'friendly_id', '~> 5.0' gem 'will_paginate', '~> 3.1.0' gem 'public_activity' gem 'acts_as_votable', '~> 0.10.0' gem 'acts_as_commentable' gem 'acts_as_follower' gem 'counter_culture', '~> 0.1.33' gem 'faker' gem 'populator' gem 'auto_html', '~>1.6.4' gem 'sanitize' gem 'active_model_serializers' # Use ActiveModel has_secure_password # gem 'bcrypt', '~> 3.1.7' # Use unicorn as the app server # gem 'unicorn' # Use Capistrano for deployment # gem 'capistrano-rails', group: :development # Use debugger # gem 'debugger', group: [:development, :test] ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) {year} {fullname} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. {signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ================================================ FILE: README.md ================================================ ## Socify Socify is an open source social networking platform written in Ruby on Rails. Here is the blog post: [How to build a social network using Rails](https://medium.com/@sudharshanmuralidharaniyer/eb31da569233). [![Heroku](http://heroku-badge.herokuapp.com/?app=socifyapp&style=flat)](http://socifyapp.herokuapp.com) Do you want to see it in action? Here is a working version deployed to heroku [http://socifyapp.herokuapp.com](http://socifyapp.herokuapp.com) ### UPDATE Since my cloudinary free tier hit a bandwidth overload. So had to switch to AWS. If you plan on deploying to production please set the AWS key and secret as environment variables. Or you can checkout the older version which uses cloudinary https://github.com/sudharti/socify/tree/930b2f7c6a6eb6b442189dc6237765dbf16d461c ### UPDATE #2 Updated the Rails version to 5.0. Thanks to [@briankung](https://github.com/briankung) for the Pull Request. There are some more things to be upgraded which will be done shortly. Refer this for the list of changes to be done https://hashrocket.com/blog/posts/how-to-upgrade-to-rails-5. ### What it uses? * [Ruby on Rails](https://github.com/rails/rails) * [Bootstrap](https://github.com/twbs/bootstrap-sass) * [Devise](https://github.com/plataformatec/devise) * [Public Activity](https://github.com/chaps-io/public_activity) ### How do I get set up? To set it up on your local machine here is what you need to do. Install Ruby & Rails. Clone this repo using the following command: ``` git clone https://github.com/sudharti/socify cd socify ``` Then resolve dependencies using bundler: ``` bundle install ``` Run Migrations: ``` rake db:migrate ``` Run rails using ``` rails server ``` ### Populate Mock data To test the app with mock data by running the following rake task: ``` rake fill:data ``` This will create records with values from faker & populator gems. Also here are the test user credentials: * email: test@socify.com * password: password ### Screenshots ![index](https://cloud.githubusercontent.com/assets/1825853/8845551/daa4d51c-30e5-11e5-8d65-171a06fa31e2.png) ![home](https://cloud.githubusercontent.com/assets/1825853/8845431/b5a5de74-30e4-11e5-8a80-00ebc59c2804.png) ![profile](https://cloud.githubusercontent.com/assets/1825853/8845432/b5a61718-30e4-11e5-8b1f-ecd401404c31.png) ![post](https://cloud.githubusercontent.com/assets/1825853/8845433/b5a5fe86-30e4-11e5-9ebf-312e00153768.png) ![find_friends](https://cloud.githubusercontent.com/assets/1825853/8845434/b5a657d2-30e4-11e5-807d-1045e754b02d.png) ### Pull Requests * Fork this repo * Make changes to code * Send Pull Request ### Issues If you find any issue with the app please do raise an issue here https://github.com/sudharti/socify/issues ### License This project is Licensed under the [GNU GPL V2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html). See [LICENSE](https://github.com/sudharti/socify/blob/master/LICENSE) for more info. ================================================ FILE: Rakefile ================================================ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require File.expand_path('../config/application', __FILE__) Rails.application.load_tasks ================================================ FILE: app/assets/images/.keep ================================================ ================================================ FILE: app/assets/javascripts/application.js ================================================ // This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. // // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // //= require jquery //= require jquery.atwho //= require jquery_ujs //= require bootstrap //= require bindWithDelay //= require moment.min //= require fullcalendar.min //= require jquery.datetimepicker //= require_tree . $(document).ready(function () { $("#event_event_datetime").datetimepicker({format: 'Y/m/d H:i'}); $("#user_dob").datetimepicker({timepicker: false, format: 'Y/m/d', maxDate: '0'}); }); ================================================ FILE: app/assets/javascripts/comments.js ================================================ // Place all the behaviors and hooks related to the matching controller here. // All this logic will automatically be available in application.js. $(document).ready(function() { $('#new_comment').submit(function() { $('#comment_text').val($('#comment-text').html()); $('#comment-text').html(''); }); }); ================================================ FILE: app/assets/javascripts/events.js ================================================ // Place all the behaviors and hooks related to the matching controller here. // All this logic will automatically be available in application.js. $(document).ready(function () { var friends_calendar = $('#calendar').fullCalendar({ defaultView: 'month', events: { url: '/events/calendar', type: 'GET', error: function () { alert('There was an error while fetching events.'); } } }); }); ================================================ FILE: app/assets/javascripts/follows.js ================================================ // Place all the behaviors and hooks related to the matching controller here. // All this logic will automatically be available in application.js. ================================================ FILE: app/assets/javascripts/home.js ================================================ // Place all the behaviors and hooks related to the matching controller here. // All this logic will automatically be available in application.js. var readURL = function(input, preview) { if (input.files && input.files[0]) { var reader = new FileReader(); reader.onload = function (e) { $(preview).parent().removeClass('hidden'); $(preview).attr('src', e.target.result); } reader.readAsDataURL(input.files[0]); } }; $(document).ready(function(){ var preview = "#img-preview > img"; $("#post-attachment").click(function(){ $("#post_attachment").click(); }); $('#post_attachment').change(function(){ readURL(this, preview); }); }); ================================================ FILE: app/assets/javascripts/likes.js ================================================ // Place all the behaviors and hooks related to the matching controller here. // All this logic will automatically be available in application.js. ================================================ FILE: app/assets/javascripts/posts.js ================================================ // Place all the behaviors and hooks related to the matching controller here. // All this logic will automatically be available in application.js. $(document).ready(function () { if ($(".pagination").size() > 0) { $(".pagination").hide(); $("#endless-scroll").removeClass("hidden"); $(window).bindWithDelay("scroll", function () { var url = $("a.next_page").attr("href"); if (url && $(window).scrollTop() > $(document).height() - $(window).height() - 50) { $.getScript(url); } }, 150); } $('#post-content').html($('#post_content').val()); $('.input-mentionable').atwho({at: '@', data: $('#mentionable-data').data('content'), insertTpl: '${name}', displayTpl: '
  • ${name}
  • ', limit: 15}); $('.post_form').submit(function () { $('#post_content').val($('#post-content').html()); $('#post-content').html(''); }); }); ================================================ FILE: app/assets/javascripts/users.js ================================================ // Place all the behaviors and hooks related to the matching controller here. // All this logic will automatically be available in application.js. ================================================ FILE: app/assets/stylesheets/application.css.scss ================================================ /* * This is a manifest file that'll be compiled into application.css, which will include all the files * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. * * You're free to add application-wide styles to this file and they'll appear at the bottom of the * compiled file so the styles you add here take precedence over styles defined in any styles * defined in the other CSS/SCSS files in this directory. It is generally better to create a new * file per style scope. * */ @import "bootstrap-sprockets"; @import "bootstrap"; @import "font-awesome"; @import "variables"; @import "jquery.datetimepicker"; @import "jquery.atwho"; @import "fullcalendar.min"; @import "fontello-embedded"; @import "*"; ================================================ FILE: app/assets/stylesheets/comments.css.scss ================================================ // Place all the styles related to the comments controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ .activity-comment, .activity-like, .comment, .like { .content { border: 1px solid $border-color; margin-left: 75px; margin-right: 15px; padding: 5px 15px; .text { font-size: $default-font-size; } } .created-at { margin-left: 75px; } } ================================================ FILE: app/assets/stylesheets/events.css.scss ================================================ // Place all the styles related to the events controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ .activity-event, .event { .content { margin-left: 60px; padding: 0px 15px; } } ================================================ FILE: app/assets/stylesheets/follows.css.scss ================================================ // Place all the styles related to the follows controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ .activity-follow { .action { font-size: $default-font-size; margin-left: 2px; } .followee { margin-left: 75px; } .created-at { margin-left: 75px; } } ================================================ FILE: app/assets/stylesheets/home.css.scss ================================================ // Place all the styles related to the home controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ #newsfeed > h4 { text-align: center; padding: 10px; } #intro { margin-top: 125px; padding: 10px 50px; text-align: center; h1 { color: $navbar-color; font-weight: 300 !important; } p { font-size: 1.65rem; line-height: 3rem; } } #img-preview { padding: 5px; display: inline-block; border: 1px solid $border-color; img { width: 35px; height: 35px; } } ================================================ FILE: app/assets/stylesheets/likes.css.scss ================================================ // Place all the styles related to the likes controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ ================================================ FILE: app/assets/stylesheets/posts.css.scss ================================================ // Place all the styles related to the posts controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ .activity-post, .post { .content { margin-left: 60px; padding: 5px 15px; .text { font-size: $default-font-size; } img { width: 100%; } } } .attachment { border: 1px solid $border-color; padding: 5px; margin-top: 10px; img { width: 100%; } } ================================================ FILE: app/assets/stylesheets/styles.css.scss ================================================ @import url(https://fonts.googleapis.com/css?family=Noto+Sans); @import url(https://fonts.googleapis.com/css?family=Montserrat); body { padding-top: 100px; background: $bg-color; font-family: 'Noto Sans', sans-serif; } h1, h2, h3, h4, h5, h6 { font-family: 'Montserrat', sans-serif; } .navbar { border: none; background-color: $navbar-color; } .navbar-brand { font-weight: 600; } .navbar-brand, .navbar-default .navbar-nav > li > a { font-family: 'Montserrat'; color: white !important; &:hover { color: $bg-color !important; }; } .avatar { border: 1px solid $border-color; width: 50px; height: 50px; } .cover { width: 100%; height: 400px; background-repeat: no-repeat; background-attachment: fixed; background-position: center; } .activity { background: white; border: 1px solid $border-color; border-radius: 3px; padding: 10px; margin: 10px; } .name { display: inline-block; font-size: $default-font-size; margin-left: 10px; } .action { font-size: $default-font-size; margin-left: 2px; } .created-at { color: $light-text-color; font-size: $small-font-size; margin-top: 15px; } .btn { font-family: 'Montserrat', sans-serif; padding: 10px 20px; } .btn-primary { background-color: $navbar-color; } .btn-sm { padding: 7px 15px; border: none; } div.editable { height: 65px; max-height: 65px; overflow-y: scroll; } div.editable, input[type="email"], input[type="password"], input[type="text"], textarea { box-shadow: none !important; border: 2px solid #ccc !important; &:focus { border: 2px solid #888 !important; }; } [placeholder]:empty:before { content: attr(placeholder); color: $light-text-color; } [placeholder]:empty:focus:before { content: ""; } .alert-fixed { position: fixed; top: 0; left: 0; margin-left: 32%; margin-top: 30px; width: 450px; z-index: 10000; text-align: center; padding: 5px 25px; } .liked { color: $liked-color !important; } .points span { padding: 5px; background-color: $bg-color; color: $light-text-color; display: inline-block; font-size: $small-font-size; margin-top: 10px; margin-right: 10px; } .activity-event, .activity-post, .event, .post { .actions { margin-top: 10px; padding-top: 10px; border-top: 1px solid $border-color; a, button { font-family: 'Montserrat', sans-serif; background-color: $border-color; color: #555; i { margin-right: 5px; } } } } #links, #user-info { h5 { border-bottom: 1px solid $border-color; padding: 15px 10px; margin: 0; } i { font-size: 1.75rem; margin-right: 20px; } } p { font-size: 1.65rem; line-height: 3rem; } .atwho-view .cur { background: $navbar-color; } .navbar-default .navbar-nav > .open > a, .navbar-default .navbar-nav > .open > a:focus, .navbar-default .navbar-nav > .open > a:hover { background: darken($navbar-color, 10%); } .dropdown-menu > li > a { padding: 10px 30px; } ================================================ FILE: app/assets/stylesheets/users.css.scss ================================================ // Place all the styles related to the users controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ .well { background-color: white; } ================================================ FILE: app/assets/stylesheets/variables.css.scss ================================================ $navbar-color: #005686; $border-color: #e0e0e0; $liked-color: #2a6496; $bg-color: #f0f0f0; $light-text-color: #808080; $default-font-size: 1.5rem; $small-font-size: 1.25rem; ================================================ FILE: app/controllers/application_controller.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class ApplicationController < ActionController::Base # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :password_confirmation]) devise_parameter_sanitizer.permit(:sign_in, keys: [:email, :remember_me]) end def render_404 respond_to do |format| format.html { render :file => "#{Rails.root}/public/404", :layout => false, :status => :not_found } end end include PublicActivity::StoreController end ================================================ FILE: app/controllers/comments_controller.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class CommentsController < ApplicationController before_action :authenticate_user! before_action :find_commentable, only: :create respond_to :js def create @comment = @commentable.comments.new do |comment| comment.comment = params[:comment_text] comment.user = current_user end @comment.save end def destroy @comment = current_user.comments.find(params[:id]) @comment_id = params[:id] @comment.destroy end private def find_commentable @commentable_type = params[:commentable_type].classify @commentable = @commentable_type.constantize.find(params[:commentable_id]) end end ================================================ FILE: app/controllers/concerns/.keep ================================================ ================================================ FILE: app/controllers/events_controller.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class EventsController < ApplicationController before_action :set_user before_action :authenticate_user! before_action :set_event, only: [:edit, :update, :show, :destroy] def new @event = Event.new end def create @event = current_user.events.new(event_params) if @event.save redirect_to root_path else render 'new', notice: @event.errors.full_messages.first end end def edit @event.event_datetime = @event.event_datetime.strftime("%Y/%m/%d %H:%M") end def show @comments = @event.comments end def update @event.update(event_params) redirect_to @event end def destroy @event.destroy respond_to do |format| format.js format.html { redirect_to root_path } end end def calendar if request.xhr? friend_events = Event.select("events.*").joins("INNER JOIN follows ON events.user_id = follows.followable_id").where("follows.follower_id = #{current_user.id} AND follows.followable_type ='User'") current_user_events = current_user.events @events = Event.from("(#{friend_events.to_sql} UNION #{current_user_events.to_sql}) as events").where("events.event_datetime BETWEEN '#{params[:start]}' AND '#{params[:end]}'") end respond_to do |format| format.html format.json { render :json => @events, each_serializer: EventCalendarSerializer } end end private def event_params params.require(:event).permit(:name, :event_datetime) end def set_event @event = Event.find_by(id: params[:id]) render_404 and return unless @event && User.find_by(id: @event.user_id) end def set_user @user = current_user end end ================================================ FILE: app/controllers/follows_controller.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class FollowsController < ApplicationController before_action :authenticate_user! respond_to :js def create @user = User.find(params[:user_id]) current_user.follow(@user) end def destroy @user = User.find(params[:user_id]) current_user.stop_following(@user) end end ================================================ FILE: app/controllers/home_controller.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class HomeController < ApplicationController before_action :set_user, except: :front respond_to :html, :js def index @post = Post.new @friends = @user.all_following.unshift(@user) @activities = PublicActivity::Activity.where(owner_id: @friends).order(created_at: :desc).paginate(page: params[:page], per_page: 10) end def front @activities = PublicActivity::Activity.joins("INNER JOIN users ON activities.owner_id = users.id").order(created_at: :desc).paginate(page: params[:page], per_page: 10) end def find_friends @friends = @user.all_following @users = User.where.not(id: @friends.unshift(@user)).paginate(page: params[:page]) end private def set_user @user = current_user end end ================================================ FILE: app/controllers/likes_controller.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class LikesController < ApplicationController before_action :find_likeable before_action :authenticate_user! respond_to :js def create @likeable.liked_by current_user @likeable.create_activity(:like, owner: current_user) end def destroy @likeable.disliked_by current_user activity = PublicActivity::Activity.find_by_trackable_id_and_key(@likeable.id, "#{@likeable_type.downcase}.like") activity.destroy if activity.present? end private def find_likeable @likeable_type = params[:likeable_type].classify @likeable = @likeable_type.constantize.find(params[:likeable_id]) end end ================================================ FILE: app/controllers/posts_controller.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class PostsController < ApplicationController before_action :authenticate_user! before_action :set_post, only: [:show, :edit, :update, :destroy] def show @comments = @post.comments.all end def create @post = current_user.posts.new(post_params) if @post.save redirect_to root_path else redirect_to root_path, notice: @post.errors.full_messages.first end end def edit end def update @post.update(post_params) redirect_to @post end def destroy @post.destroy respond_to do |format| format.js format.html { redirect_to root_path } end end private def set_post @post = Post.find_by(id: params[:id]) render_404 and return unless @post && User.find_by(id: @post.user_id) end def post_params params.require(:post).permit(:content, :attachment) end end ================================================ FILE: app/controllers/users_controller.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class UsersController < ApplicationController before_action :authenticate_user! before_action :set_user before_action :check_ownership, only: [:edit, :update] respond_to :html, :js def show @activities = PublicActivity::Activity.where(owner: @user).order(created_at: :desc).paginate(page: params[:page], per_page: 10) end def edit end def update if @user.update(user_params) redirect_to user_path(@user) else render :edit end end def deactivate end def friends @friends = @user.following_users.paginate(page: params[:page]) end def followers @followers = @user.user_followers.paginate(page: params[:page]) end def mentionable render json: @user.following_users.as_json(only: [:id, :name]), root: false end private def user_params params.require(:user).permit(:name, :about, :avatar, :cover, :sex, :dob, :location, :phone_number) end def check_ownership redirect_to current_user, notice: 'Not Authorized' unless @user == current_user end def set_user @user = User.friendly.find_by(slug: params[:id]) || User.find_by(id: params[:id]) render_404 and return unless @user end end ================================================ FILE: app/helpers/application_helper.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. module ApplicationHelper def belongs_to_user?(resource) resource.user == current_user end def activity_resources_exist?(activity) activity && activity.trackable && activity.owner end end ================================================ FILE: app/helpers/comments_helper.rb ================================================ module CommentsHelper end ================================================ FILE: app/helpers/events_helper.rb ================================================ module EventsHelper end ================================================ FILE: app/helpers/follows_helper.rb ================================================ module FollowsHelper end ================================================ FILE: app/helpers/home_helper.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. module HomeHelper def relative_time(created_at) time_ago_in_words(created_at) end def formatted_time(time) time.to_formatted_s(:short) end end ================================================ FILE: app/helpers/likes_helper.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. module LikesHelper def find_like(likeable) likeable.get_likes.where(user: current_user) end end ================================================ FILE: app/helpers/posts_helper.rb ================================================ module PostsHelper end ================================================ FILE: app/helpers/users_helper.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. module UsersHelper def options_for_seasons [['Male', 'male'], ['Female', 'female']] end def age(dob) now = Time.now.utc.to_date now.year - dob.year - (dob.to_date.change(:year => now.year) > now ? 1 : 0) end def is_current_user?(user) user == current_user end end ================================================ FILE: app/mailers/.keep ================================================ ================================================ FILE: app/models/.keep ================================================ ================================================ FILE: app/models/comment.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class Comment < ActiveRecord::Base include Shared::Callbacks include ActsAsCommentable::Comment include Mention belongs_to :commentable, polymorphic: true, counter_cache: true default_scope -> { order('created_at DESC') } # NOTE: install the acts_as_votable plugin if you # want user to vote on the quality of comments. # acts_as_voteable # NOTE: Comments belong to a user belongs_to :user include PublicActivity::Model tracked only: [:create], owner: proc { |_controller, model| model.user } validates_presence_of :comment validates_presence_of :commentable validates_presence_of :user auto_html_for :comment do image youtube(width: 400, height: 250, autoplay: true) link target: '_blank', rel: 'nofollow' simple_format end end ================================================ FILE: app/models/concerns/.keep ================================================ ================================================ FILE: app/models/concerns/shared/callbacks.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. module Shared::Callbacks extend ActiveSupport::Concern included do before_destroy :remove_activity before_destroy :remove_likes end def remove_activity activity = PublicActivity::Activity.find_by(trackable_id: self.id, trackable_type: self.class.to_s, key: "#{self.class.to_s.downcase}.create") activity.destroy if activity.present? true end def remove_likes activity = PublicActivity::Activity.find_by(trackable_id: self.id, trackable_type: self.class.to_s, key: "#{self.class.to_s.downcase}.like") activity.destroy if activity.present? end end ================================================ FILE: app/models/event.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class Event < ActiveRecord::Base include Shared::Callbacks belongs_to :user acts_as_votable acts_as_commentable include PublicActivity::Model tracked only: [:create, :like], owner: Proc.new{ |controller, model| model.user } validates_presence_of :name validates_presence_of :event_datetime validates_presence_of :user end ================================================ FILE: app/models/follow.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class Follow < ActiveRecord::Base include Shared::Callbacks extend ActsAsFollower::FollowerLib extend ActsAsFollower::FollowScopes # NOTE: Follows belong to the "followable" interface, and also to followers belongs_to :followable, :polymorphic => true belongs_to :follower, :polymorphic => true def block! self.update_attribute(:blocked, true) end include PublicActivity::Model tracked only: [:create], owner: Proc.new{ |controller, model| model.follower } validates_presence_of :follower validates_presence_of :followable end ================================================ FILE: app/models/mention.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. module Mention private def friends_names names_array = [] user.following_users.each do |friend| names_array << friend.name end names_array end def html_type if is_a?(Post) content_html elsif is_a?(Comment) comment_html end end def mentioned_friends friends_names.select { |name| html_type.include? name } end def add_mention_links_to_content mentioned_friends.each do |friend_name| new_content = html_type.gsub!(friend_name, "#{friend_name}") self.content = new_content if is_a?(Post) self.comment = new_content if is_a?(Comment) end end end ================================================ FILE: app/models/merit/badge_rules.rb ================================================ # Be sure to restart your server when you modify this file. # # +grant_on+ accepts: # * Nothing (always grants) # * A block which evaluates to boolean (recieves the object as parameter) # * A block with a hash composed of methods to run on the target object with # expected values (+votes: 5+ for instance). # # +grant_on+ can have a +:to+ method name, which called over the target object # should retrieve the object to badge (could be +:user+, +:self+, +:follower+, # etc). If it's not defined merit will apply the badge to the user who # triggered the action (:action_user by default). If it's :itself, it badges # the created object (new user for instance). # # The :temporary option indicates that if the condition doesn't hold but the # badge is granted, then it's removed. It's false by default (badges are kept # forever). module Merit class BadgeRules include Merit::BadgeRulesMethods def initialize grant_on 'comments#create', badge: 'Jr.Critics', temporary: true, to: :user do |comment| comment.user.comments.count >= 2 end end # If it creates user, grant badge # Should be "current_user" after registration for badge to be granted. # Find badge by badge_id, badge_id takes presidence over badge # grant_on 'users#create', badge_id: 7, badge: 'just-registered', to: :itself # If it has 10 comments, grant commenter-10 badge # grant_on 'comments#create', badge: 'commenter', level: 10 do |comment| # comment.user.comments.count == 10 # end # If it has 5 votes, grant relevant-commenter badge # grant_on 'comments#vote', badge: 'relevant-commenter', # to: :user do |comment| # # comment.votes.count == 5 # end # Changes his name by one wider than 4 chars (arbitrary ruby code case) # grant_on 'registrations#update', badge: 'autobiographer', # temporary: true, model_name: 'User' do |user| # # user.name.length > 4 # end end end ================================================ FILE: app/models/merit/point_rules.rb ================================================ module Merit class PointRules include Merit::PointRulesMethods def initialize score 2, on: 'comments#create', to: [:user] score 1, on: 'posts#upvote', to: [:user] score 4, on: 'posts#create', to: [:user] score 3, on: 'events#create', to: [:user] score 1, on: 'events#upvote', to: [:user] # score 10, :on => 'users#create' do |user| # user.bio.present? # end # # score 15, :on => 'reviews#create', :to => [:reviewer, :reviewed] # # score 20, :on => [ # 'comments#create', # 'photos#create' # ] # # score -10, :on => 'comments#destroy' end end end ================================================ FILE: app/models/merit/rank_rules.rb ================================================ # Be sure to restart your server when you modify this file. # # 5 stars is a common ranking use case. They are not given at specified # actions like badges, you should define a cron job to test if ranks are to be # granted. # # +set_rank+ accepts: # * :+level+ ranking level (greater is better) # * :+to+ model or scope to check if new rankings apply # * :+level_name+ attribute name (default is empty and results in 'level' # attribute, if set it's appended like 'level_#{level_name}') module Merit class RankRules include Merit::RankRulesMethods def initialize # set_rank :level => 1, :to => Commiter.active do |commiter| # commiter.repositories.count > 1 && commiter.followers >= 10 # end # # set_rank :level => 2, :to => Commiter.active do |commiter| # commiter.branches.count > 1 && commiter.followers >= 10 # end # # set_rank :level => 3, :to => Commiter.active do |commiter| # commiter.branches.count > 2 && commiter.followers >= 20 # end end end end ================================================ FILE: app/models/post.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class Post < ActiveRecord::Base include Shared::Callbacks belongs_to :user counter_culture :user acts_as_votable acts_as_commentable include PublicActivity::Model tracked only: [:create, :like], owner: proc { |_controller, model| model.user } default_scope -> { order('created_at DESC') } mount_uploader :attachment, AvatarUploader validates_presence_of :content validates_presence_of :user auto_html_for :content do image youtube(width: 400, height: 250, autoplay: true) link target: '_blank', rel: 'nofollow' simple_format end end ================================================ FILE: app/models/user.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class User < ActiveRecord::Base # Include default devise modules. Others available are: has_merit # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable acts_as_voter acts_as_follower acts_as_followable has_many :posts has_many :comments has_many :events mount_uploader :avatar, AvatarUploader mount_uploader :cover, AvatarUploader validates_presence_of :name self.per_page = 10 extend FriendlyId friendly_id :name, use: [:slugged, :finders] end ================================================ FILE: app/serializers/event_calendar_serializer.rb ================================================ class EventCalendarSerializer < ActiveModel::Serializer attributes :id, :start, :end, :title, :allDay def title object.name end def start object.event_datetime end def end object.event_datetime end def allDay true end end ================================================ FILE: app/uploaders/avatar_uploader.rb ================================================ # Copyright (c) 2015, @sudharti(Sudharsanan Muralidharan) # Socify is an Open source Social network written in Ruby on Rails This file is licensed # under GNU GPL v2 or later. See the LICENSE. class AvatarUploader < CarrierWave::Uploader::Base # Include RMagick or MiniMagick support: # include CarrierWave::RMagick # include CarrierWave::MiniMagick storage :fog if Rails.env.production? # Choose what kind of storage to use for this uploader: storage :file if Rails.env.development? # storage :fog # Override the directory where uploaded files will be stored. # This is a sensible default for uploaders that are meant to be mounted: def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end # Provide a default URL as a default if there hasn't been a file uploaded: # def default_url # # For Rails 3.1+ asset pipeline compatibility: # # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_')) # # "/images/fallback/" + [version_name, "default.png"].compact.join('_') # end # Process files as they are uploaded: # process :scale => [200, 300] # # def scale(width, height) # # do something # end # Create different versions of your uploaded files: # version :thumb do # process :resize_to_fit => [50, 50] # end # Add a white list of extensions which are allowed to be uploaded. # For images you might use something like this: # def extension_white_list # %w(jpg jpeg gif png) # end # Override the filename of the uploaded files: # Avoid using model.id or version_name here, see uploader/store.rb for details. # def filename # "something.jpg" if original_filename # end end ================================================ FILE: app/views/comments/_comment.html.erb ================================================ <% if comment.user %>
    <%= render 'shared/avatar', user: comment.user %>

    <%= link_to comment.user.name, user_path(comment.user) %>

    <%= comment.comment_html %>
    <% if belongs_to_user?(comment) %> <%= link_to comment_path(comment), method: :delete, class: 'btn btn-danger btn-sm', remote: true do %> <% fa_icon 'trash' %> <% end %> <% end %>


    <% end %> ================================================ FILE: app/views/comments/_form.html.erb ================================================
    <%= form_tag comments_path(commentable_type: commentable.class.to_s, commentable_id: commentable.id), id: 'new_comment', method: :post, remote: true do %>
    <%= hidden_field_tag :comment_text, nil, placeholder: 'Enter Comment', class: 'form-control input-mentionable' %>
    <%= submit_tag :comment, class: 'btn btn-primary' %> <% end %> ================================================ FILE: app/views/comments/create.js.erb ================================================ $("#<%= @commentable_type.downcase %>-<%= @commentable.id %> .comments").prepend("<%=j render(@comment) %>"); $("#comment_text").val(""); ================================================ FILE: app/views/comments/destroy.js.erb ================================================ $("#comment-<%= @comment.id %>").remove(); ================================================ FILE: app/views/devise/confirmations/new.html.erb ================================================

    Resend Confirmation


    <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> <% if resource.errors.any? %>
    <%= resource.errors.full_messages.first %>
    <% end %>
    <%= f.label :email %> <%= f.email_field :email, value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email), class: 'form-control', autofocus: true, placeholder: 'email@example.com' %>
    <%= f.submit 'Resend confirmation', class: 'btn btn-primary' %>
    <% end %>
    <%= render "devise/shared/links" %>
    ================================================ FILE: app/views/devise/mailer/confirmation_instructions.html.erb ================================================

    Welcome <%= @email %>!

    You can confirm your account email through the link below:

    <%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

    ================================================ FILE: app/views/devise/mailer/reset_password_instructions.html.erb ================================================

    Hello <%= @resource.email %>!

    Someone has requested a link to change your password. You can do this through the link below.

    <%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

    If you didn't request this, please ignore this email.

    Your password won't change until you access the link above and create a new one.

    ================================================ FILE: app/views/devise/mailer/unlock_instructions.html.erb ================================================

    Hello <%= @resource.email %>!

    Your account has been locked due to an excessive number of unsuccessful sign in attempts.

    Click the link below to unlock your account:

    <%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

    ================================================ FILE: app/views/devise/passwords/edit.html.erb ================================================

    Change your password


    <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> <% if resource.errors.any? %>
    <%= resource.errors.full_messages.first %>
    <% end %> <%= f.hidden_field :reset_password_token %>
    <%= f.label :password, "New password" %>
    <% if @minimum_password_length %> (<%= @minimum_password_length %> characters minimum) <% end %>
    <%= f.password_field :password, autofocus: true, autocomplete: 'off', class: 'form-control', placeholder: 'Password' %>
    <%= f.label :password_confirmation, 'Confirm new password'%>
    <%= f.password_field :password_confirmation, autocomplete: 'off', class: 'form-control', placeholder: 'Repeat password' %>
    <%= f.submit 'Change Password', class: 'btn btn-primary' %>
    <% end %>
    <%= render "devise/shared/links" %>
    ================================================ FILE: app/views/devise/passwords/new.html.erb ================================================

    Forgot your password?


    <%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> <% if resource.errors.any? %>
    <%= resource.errors.full_messages.first %>
    <% end %>
    <%= f.label :email %> <%= f.email_field :email, class: 'form-control', autofocus: true, placeholder: 'email@example.com' %>
    <%= f.submit 'Reset Password', class: 'btn btn-primary' %>
    <% end %>
    <%= render "devise/shared/links" %>
    ================================================ FILE: app/views/devise/registrations/edit.html.erb ================================================

    Change Password

    <% if resource.errors.any? %>
    <%= resource.errors.full_messages.first %>
    <% end %> <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
    Currently waiting confirmation for: <%= resource.unconfirmed_email %>
    <% end %>
    <%= f.label :password %> (leave blank if you don't want to change it)
    <%= f.password_field :password, autocomplete: 'off', class: 'form-control' %>
    <%= f.label :password_confirmation %>
    <%= f.password_field :password_confirmation, autocomplete: 'off', class: 'form-control' %>
    <%= f.label :current_password %> (we need your current password to confirm your changes)
    <%= f.password_field :current_password, autocomplete: 'off', class: 'form-control' %>
    <%= f.submit 'Update', class: 'btn btn-primary' %>
    <% end %>
    ================================================ FILE: app/views/devise/registrations/new.html.erb ================================================

    Sign up


    <%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <% if resource.errors.any? %>
    <%= resource.errors.full_messages.first %>
    <% end %>
    <%= f.label :name %> <%= f.text_field :name, class: 'form-control', autofocus: true, placeholder: 'Full name' %>
    <%= f.label :email %> <%= f.email_field :email, class: 'form-control', placeholder: 'email@example.com' %>
    <%= f.label :password %> <% if @minimum_password_length %> (<%= @minimum_password_length %> characters minimum) <% end %>
    <%= f.password_field :password, class: 'form-control', autocomplete: 'off', placeholder: 'password' %>
    <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class: 'form-control', autocomplete: 'off', placeholder: 'password confirmation' %>
    <%= f.submit 'Sign up', class: 'btn btn-success' %>
    <% end %>
    <%= render 'devise/shared/links' %>
    ================================================ FILE: app/views/devise/sessions/new.html.erb ================================================

    Log in


    <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
    <%= f.label :email %> <%= f.email_field :email, class: 'form-control', autofocus: true, placeholder: 'email@example.com' %>
    <%= f.label :password %> <%= f.password_field :password, class: 'form-control', autocomplete: 'off', placeholder: 'password' %>
    <% if devise_mapping.rememberable? -%>
    <%= f.check_box :remember_me %> <%= f.label :remember_me %>
    <% end -%>
    <%= f.submit 'Log in', class: 'btn btn-success' %>
    <% end %>
    <%= render 'devise/shared/links' %>
    ================================================ FILE: app/views/devise/shared/_links.html.erb ================================================ <%- if controller_name != 'sessions' %> <%= link_to "Log in", new_session_path(resource_name) %>
    <% end -%> <%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%= link_to "Sign up", new_registration_path(resource_name) %>
    <% end -%> <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> <%= link_to "Forgot your password?", new_password_path(resource_name) %>
    <% end -%> <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
    <% end -%> <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
    <% end -%> <%- if devise_mapping.omniauthable? %> <%- resource_class.omniauth_providers.each do |provider| %> <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %>
    <% end -%> <% end -%> ================================================ FILE: app/views/devise/unlocks/new.html.erb ================================================

    Resend unlock instructions

    <%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> <%= devise_error_messages! %>
    <%= f.label :email %>
    <%= f.email_field :email, autofocus: true %>
    <%= f.submit "Resend unlock instructions" %>
    <% end %> <%= render "devise/shared/links" %> ================================================ FILE: app/views/events/_event.html.erb ================================================ <% if event.user %>
    <%= render 'shared/avatar', user: event.user %>

    <%= link_to event.user.name, user_path(event.user) %>

    created an <%= link_to 'event', event %>

    <%= event.name %>

    <%= fa_icon'calendar' %> <%= formatted_time(event.event_datetime) %> <%= render 'shared/created_at', activity: event %>
    <%= pluralize(event.comments_count, 'comment') %>
    <% if belongs_to_user?(event) %> <%= link_to edit_event_path(event), class: 'btn btn-primary btn-sm' do %> <% fa_icon 'pencil' %> <% end %> <%= link_to event_path(event), method: :delete, class:'btn btn-danger btn-sm', remote: remote do %> <% fa_icon 'trash' %> <% end %> <% end %>
    <%= render 'shared/actions', resource: event %> <% end %> ================================================ FILE: app/views/events/_form.html.erb ================================================ <%= form_for(@event) do |f| %>
    <%= f.label :event_name %> <%= f.text_field :name, autofocus: true, placeholder: 'Event Name', class: 'form-control' %>
    <%= f.label :when? %> <%= f.text_field :event_datetime, placeholder: 'When is it?', class: 'form-control' %>
    <%= f.submit (@event.persisted? ? :update : :create), class: 'btn btn-primary' %>
    <% end %> ================================================ FILE: app/views/events/calendar.html.erb ================================================
    <%= render 'shared/user_info' %>

    Events Calendar


    <%= render 'shared/links' %>
    ================================================ FILE: app/views/events/destroy.js.erb ================================================ $("#event-<%= @event.id %>").parent().remove(); ================================================ FILE: app/views/events/edit.html.erb ================================================
    <%= render 'shared/user_info' %>
    <%= render 'form' %>
    <%= render 'shared/links' %>
    ================================================ FILE: app/views/events/new.html.erb ================================================
    <%= render 'shared/user_info' %>
    <%= render 'form' %>
    <%= render 'shared/links' %>
    ================================================ FILE: app/views/events/show.html.erb ================================================ <% if @event.user %>
    <%= render @event, remote: false %>

    Comments


    <%= render 'comments/form', commentable: @event %>
    <%= render(@comments) || render('shared/no_resource', resources: 'Comments') %>
    <% end %> ================================================ FILE: app/views/follows/_form.html.erb ================================================
    <% if user.followed_by?(current_user) %> <%= form_tag unfollow_path(user_id: user.id), method: :post, remote: true do %> <%= button_tag 'unfollow', class: 'btn btn-primary' %> <% end %> <% else %> <%= form_tag follow_path(user_id: user.id), method: :post, remote: true do %> <%= button_tag 'follow', class: 'btn btn-success' %> <% end %> <% end %>
    ================================================ FILE: app/views/follows/create.js.erb ================================================ $("#user-<%= @user.id %> .follow").html("<%=j render('follows/form', user: @user) %>"); ================================================ FILE: app/views/follows/destroy.js.erb ================================================ $("#user-<%= @user.id %> .follow").html("<%=j render('follows/form', user: @user) %>"); ================================================ FILE: app/views/home/about.html.erb ================================================

    ABOUT


    What?

    Socify is a social networking app built using Ruby on Rails. It's free & completely open source. You can check the source on <%= fa_icon 'github' %> Github. Also take a look at the demo deployed to Heroku.


    Why?

    I am not building the next Facebook. Given that there are enough social networks already I don't want to end up launching one. Pointless! So why am I building? I want to try and learn how to develop a social network and in the process show you how easy it is done using Rails. Here is the <%= fa_icon 'medium' %> Blog post.


    How?

    As stated above it's a Ruby on Rails application. Frontend is developed using Twitter Bootstrap. Database is SQLite for development and Postgresql for production.


    <%= fa_icon 'star' %> Star it <%= fa_icon 'code-fork' %> Fork it
    ================================================ FILE: app/views/home/find_friends.html.erb ================================================
    <%= render 'shared/user_info' %>

    Find Friends


    <%= render(@users) || render('shared/no_resource', resources: 'Users') %>
    <%= render 'shared/paginate', resources: @users %>
    <%= render 'shared/links' %>
    ================================================ FILE: app/views/home/find_friends.js.erb ================================================ $('#users').append("<%= j render(@users) %>"); <%= render 'shared/paginate', resources: @users %> ================================================ FILE: app/views/home/front.html.erb ================================================

    <%= fa_icon "newspaper-o" %> NEWSFEED

    <% if @activities.empty? %>
    <%= render('shared/no_resource', resources: 'Activities') %>
    <% else %> <%= render_activities(@activities, layout: '/shared/activity') %> <% end %>
    <%= render 'shared/paginate', resources: @activities %>

    Socify

    Socify is an open source social networking app written using <%= fa_icon 'diamond' %> Ruby on Rails. You can checkout the blog post on how it was developed and also the source code on <%= fa_icon 'github' %> Github.


    <%= fa_icon 'star' %> Star it <%= fa_icon 'code-fork' %> Fork it
    ================================================ FILE: app/views/home/front.js.erb ================================================ $('#activities').append("<%= j render_activities(@activities, layout: '/shared/activity') %>"); <%= render 'shared/paginate', resources: @activities %> ================================================ FILE: app/views/home/index.html.erb ================================================
    <%= render 'shared/user_info' %>
    <%= render 'posts/form' %>
    <% if @activities.empty? %>
    <%= render('shared/no_resource', resources: 'Activities') %>
    <% else %> <%= render_activities(@activities, layout: '/shared/activity') %> <% end %>
    <%= render 'shared/paginate', resources: @activities %>
    <%= render 'shared/links' %>
    ================================================ FILE: app/views/home/index.js.erb ================================================ $('#activities').append("<%= j render_activities(@activities, layout: '/shared/activity') %>"); <%= render 'shared/paginate', resources: @activities %> ================================================ FILE: app/views/layouts/application.html.erb ================================================ Socify <%= stylesheet_link_tag 'application', media: 'all' %> <%= javascript_include_tag 'application' %> <%= csrf_meta_tags %> <%= render 'shared/navbar' %> <% unless notice.blank? %>
    <%= notice %>
    <% end %> <% unless alert.blank? %>
    <%= alert %>
    <% end %>
    <%= yield %>
    ================================================ FILE: app/views/likes/_form.html.erb ================================================ <% if current_user.liked? likeable %> <%= form_tag unlike_path(likeable_type: likeable.class.to_s, likeable_id: likeable.id), method: :post, remote: true do %> <% button_tag class: 'btn btn-block liked' do %> <%= fa_icon 'thumbs-up' %> unlike <% end %> <% end %> <% else %> <%= form_tag like_path(likeable_type: likeable.class.to_s, likeable_id: likeable.id), remote: true do %> <% button_tag class: 'btn btn-block' do %> <%= fa_icon 'thumbs-up' %> like <% end %> <% end %> <% end %> ================================================ FILE: app/views/likes/create.js.erb ================================================ $("#<%= @likeable_type.downcase %>-<%= @likeable.id %> .like").html("<%=j render('likes/form', likeable: @likeable) %>"); $("#<%= @likeable_type.downcase %>-<%= @likeable.id %> .like-count").html("<%= pluralize(@likeable.cached_votes_up, 'like') %>"); ================================================ FILE: app/views/likes/destroy.js.erb ================================================ $("#<%= @likeable_type.downcase %>-<%= @likeable.id %> .like").html("<%=j render('likes/form', likeable: @likeable) %>"); $("#<%= @likeable_type.downcase %>-<%= @likeable.id %> .like-count").html("<%= pluralize(@likeable.cached_votes_up, 'like') %>"); ================================================ FILE: app/views/posts/_form.html.erb ================================================
    <%= form_for @post, html: { class: 'post_form' } do |f| %>

    Update Status

    <%= f.hidden_field :content, value: @post.content, class: 'form-control input-mentionable', autofocus: true %>
    <%= fa_icon 'image' %> <%= f.submit 'Post', class: 'btn btn-primary'%>
    <% if @post.attachment.present? %>
    <%= image_tag @post.attachment %>
    <% end %> <% end %>
    ================================================ FILE: app/views/posts/_post.html.erb ================================================ <% if post.user %>
    <%= render 'shared/avatar', user: post.user %>

    <%= link_to post.user.name, user_path(post.user) %>

    created a <%= link_to 'post', post %>
    <%= post.content_html %> <% if post.attachment.present? %>
    <%= image_tag post.attachment %>
    <% end %> <%= render 'shared/created_at', activity: post %>
    <%= pluralize(post.comments_count, 'comment') %>
    <% if belongs_to_user?(post) %> <%= link_to edit_post_path(post), class: 'btn btn-primary btn-sm' do %> <% fa_icon 'pencil' %> <% end %> <%= link_to post_path(post), method: :delete, class:'btn btn-danger btn-sm', remote: remote do %> <% fa_icon 'trash' %> <% end %> <% end %>
    <%= render 'shared/actions', resource: post %> <% end %> ================================================ FILE: app/views/posts/destroy.js.erb ================================================ $("#post-<%= @post.id %>").parent().remove(); ================================================ FILE: app/views/posts/edit.html.erb ================================================
    <%= render 'form' %>
    ================================================ FILE: app/views/posts/show.html.erb ================================================ <% if @post.user %>
    <%= render @post, remote: false %>

    Comments


    <%= render 'comments/form', commentable: @post %>
    <%= render(@comments) || render('shared/no_resource', resources: 'Comments') %>
    <% end %> ================================================ FILE: app/views/public_activity/comment/_create.html.erb ================================================ <% if activity_resources_exist?(activity) %>
    <%= render 'shared/avatar', user: activity.owner %>

    <%= link_to activity.owner.name, user_path(activity.owner) %>

    commented on a <%= link_to activity.trackable.commentable.class.to_s, activity.trackable.commentable %>

    <%= activity.trackable.comment_html %>

    <%= render 'shared/created_at', activity: activity %>
    <% end %> ================================================ FILE: app/views/public_activity/event/_create.html.erb ================================================ <% if activity_resources_exist?(activity) %>
    <%= render activity.trackable, remote: true %>
    <% end %> ================================================ FILE: app/views/public_activity/event/_like.html.erb ================================================ <% if activity_resources_exist?(activity) %>
    <% if activity.trackable %>
    <%= render 'shared/avatar', user: activity.owner %>

    <%= link_to activity.owner.name, user_path(activity.owner) %>

    liked a <%= link_to 'event', activity.trackable %>

    <%= activity.trackable.name %>

    <%= fa_icon'calendar' %> <%= formatted_time(activity.trackable.event_datetime) %>

    <%= render 'shared/created_at', activity: activity %>
    <% end %>
    <% end %> ================================================ FILE: app/views/public_activity/follow/_create.html.erb ================================================ <% if activity_resources_exist?(activity) && activity.trackable.followable %>
    <%= render 'shared/avatar', user: activity.owner %>

    <%= link_to activity.owner.name, user_path(activity.owner) %>

    Followed
    <%= render 'shared/avatar', user: activity.trackable.followable %>

    <%= link_to activity.trackable.followable.name, user_path(activity.trackable.followable) %>

    <%= render 'shared/created_at', activity: activity %>
    <% end %> ================================================ FILE: app/views/public_activity/post/_create.html.erb ================================================ <% if activity_resources_exist?(activity) %>
    <%= render activity.trackable, remote: true %>
    <% end %> ================================================ FILE: app/views/public_activity/post/_like.html.erb ================================================ <% if activity_resources_exist?(activity) %>
    <%= render 'shared/avatar', user: activity.owner %>

    <%= link_to activity.owner.name, user_path(activity.owner) %>

    liked a <%= link_to 'post', activity.trackable %>

    <%= activity.trackable.content_html %>

    <%= render 'shared/created_at', activity: activity %>
    <% end %> ================================================ FILE: app/views/shared/_actions.html.erb ================================================ <% if user_signed_in? %>
    <%= link_to resource, class: 'btn btn-block' do %> <%= fa_icon 'comment' %> comment <% end %>
    <% end %> ================================================ FILE: app/views/shared/_activity.html.erb ================================================ <%= render_activity(activity) %> ================================================ FILE: app/views/shared/_avatar.html.erb ================================================ <% if user %> <%= link_to user_path(user) do %> <%= image_tag user.avatar.url || 'avatar.jpg', class: 'avatar' %> <% end %> <% end %> ================================================ FILE: app/views/shared/_cover.html.erb ================================================ <% if user.cover.url %>
    <% else %>
    <% end %> ================================================ FILE: app/views/shared/_created_at.html.erb ================================================
    <%= fa_icon 'clock-o' %> <%= relative_time(activity.created_at) %> ago
    ================================================ FILE: app/views/shared/_links.html.erb ================================================ ================================================ FILE: app/views/shared/_navbar.html.erb ================================================ ================================================ FILE: app/views/shared/_no_resource.html.erb ================================================
    No <%= resources %> found.
    ================================================ FILE: app/views/shared/_paginate.html.erb ================================================ ================================================ FILE: app/views/shared/_paginate.js.erb ================================================ <% if resources.next_page %> $(".pagination").replaceWith("<%= j will_paginate(resources) %>"); $(".pagination").hide(); <% else %> $(window).off('scroll'); $("#endless-scroll").remove(); <% end %> ================================================ FILE: app/views/shared/_user_info.html.erb ================================================
    <%= render 'shared/avatar', user: @user %>
    <%= link_to @user.name, @user %>
    <%= fa_icon 'shield' %> <%= pluralize(@user.posts_count, 'post') %>
    <% if @user.dob.present? %>
    <%= fa_icon @user.sex %> <%= "#{pluralize(age(@user.dob), 'year')} old" %>
    <% end %> <% if @user.location.present? %>
    <%= fa_icon 'map-marker' %> <%= @user.location %>
    <% end %>
    <%= pluralize(@user.points, 'point') %>
    <% if @user.badges.empty? %>
    No badge yet.
    <% else %>
    <% @user.badges.each do |badge| %> <%= badge.name %> <% end %>
    <% end %>
    <% unless is_current_user?(@user) %> <%= render 'follows/form', user: @user %>
    <%= 'Follows you' if current_user.followed_by?(@user) %>
    <% end %>
    ================================================ FILE: app/views/users/_user.html.erb ================================================
    <%= render 'shared/avatar', user: user %>
    <%= link_to user.name, user %>

    ================================================ FILE: app/views/users/deactivate.html.erb ================================================

    Deactivate


    Unhappy with Socify? Hit the Button below to cancel account.

    <%= button_to 'Cancel my account', registration_path(@user), data: { confirm: "Are you sure?" }, method: :delete, class: 'btn btn-danger' %>
    ================================================ FILE: app/views/users/edit.html.erb ================================================

    Edit Profile

    <%= form_for @user do |f| %>
    <%= f.label :avatar %>
    <%= render 'shared/avatar', user: @user %>

    <%= f.file_field :avatar %>
    <%= f.label :cover %>
    <%= render 'shared/cover', user: @user %>
    <%= f.file_field :cover %>
    <%= f.label :name %> <%= f.text_field :name, placeholder: 'Full Name', class: 'form-control' %>
    <%= f.label :about %> <%= f.text_area :about, placeholder: 'About', class: 'form-control' %>
    <%= f.label :location %> <%= f.text_field :location, placeholder: 'Location', class: 'form-control' %>
    <%= f.label :phone_number %> <%= f.text_field :phone_number, placeholder: 'Phone Number', class: 'form-control' %>
    <%= f.label :dob %> <%= f.text_field :dob, placeholder: 'Date of Birth', class: 'form-control' %>
    <%= f.label :sex %>
    <%= f.select :sex, options_for_seasons, class: 'form-control', prompt: 'Select One' %>
    <%= submit_tag 'Update', class: 'btn btn-primary' %>
    <% end %>
    ================================================ FILE: app/views/users/followers.html.erb ================================================
    <%= render 'shared/user_info' %>

    Followers


    <%= render(@followers) || render('shared/no_resource', resources: 'Followers') %>
    <%= render 'shared/paginate', resources: @followers %>
    <%= render 'shared/links' %>
    ================================================ FILE: app/views/users/followers.js.erb ================================================ $('#followers').append("<%= j render(@followers) %>"); <%= render 'shared/paginate', resources: @followers %> ================================================ FILE: app/views/users/friends.html.erb ================================================
    <%= render 'shared/user_info' %>

    Friends


    <%= render(@friends) || render('shared/no_resource', resources: 'Friends') %>
    <%= render 'shared/paginate', resources: @friends %>
    <%= render 'shared/links' %>
    ================================================ FILE: app/views/users/friends.js.erb ================================================ $('#friends').append("<%= j render(@friends) %>"); <%= render 'shared/paginate', resources: @friends %> ================================================ FILE: app/views/users/show.html.erb ================================================ <%= render 'shared/cover', user: @user %>
    <%= render 'shared/user_info' %>
    <% if @activities.empty? %>
    <%= render('shared/no_resource', resources: 'Activities') %>
    <% else %> <%= render_activities(@activities, layout: '/shared/activity') %> <% end %>
    <%= render 'shared/paginate', resources: @activities %>
    <% if is_current_user?(@user) %>
    <% end %>
    ================================================ FILE: app/views/users/show.js.erb ================================================ $('#activities').append("<%= j render_activities(@activities, layout: '/shared/activity') %>"); <%= render 'shared/paginate', resources: @activities %> ================================================ FILE: bin/bundle ================================================ #!/usr/bin/env ruby ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) load Gem.bin_path('bundler', 'bundle') ================================================ FILE: bin/rails ================================================ #!/usr/bin/env ruby begin load File.expand_path("../spring", __FILE__) rescue LoadError end APP_PATH = File.expand_path('../../config/application', __FILE__) require_relative '../config/boot' require 'rails/commands' ================================================ FILE: bin/rake ================================================ #!/usr/bin/env ruby begin load File.expand_path("../spring", __FILE__) rescue LoadError end require_relative '../config/boot' require 'rake' Rake.application.run ================================================ FILE: bin/setup ================================================ #!/usr/bin/env ruby require 'pathname' # path to your application root. APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) Dir.chdir APP_ROOT do # This script is a starting point to setup your application. # Add necessary setup steps to this file: puts "== Installing dependencies ==" system "gem install bundler --conservative" system "bundle check || bundle install" # puts "\n== Copying sample files ==" # unless File.exist?("config/database.yml") # system "cp config/database.yml.sample config/database.yml" # end puts "\n== Preparing database ==" system "bin/rake db:setup" puts "\n== Removing old logs and tempfiles ==" system "rm -f log/*" system "rm -rf tmp/cache" puts "\n== Restarting application server ==" system "touch tmp/restart.txt" end ================================================ FILE: bin/spring ================================================ #!/usr/bin/env ruby # This file loads spring without using Bundler, in order to be fast. # It gets overwritten when you run the `spring binstub` command. unless defined?(Spring) require "rubygems" require "bundler" if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m) Gem.paths = { "GEM_PATH" => [Bundler.bundle_path.to_s, *Gem.path].uniq } gem "spring", match[1] require "spring/binstub" end end ================================================ FILE: config/application.rb ================================================ require File.expand_path('../boot', __FILE__) require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module Socify class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de end end ================================================ FILE: config/boot.rb ================================================ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' # Set up gems listed in the Gemfile. ================================================ FILE: config/database.yml ================================================ # SQLite version 3.x # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' # default: &default adapter: sqlite3 pool: 5 timeout: 5000 development: <<: *default database: db/development.sqlite3 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default database: db/test.sqlite3 production: <<: *default database: db/production.sqlite3 ================================================ FILE: config/environment.rb ================================================ # Load the Rails application. require File.expand_path('../application', __FILE__) # Initialize the Rails application. Rails.application.initialize! ================================================ FILE: config/environments/development.rb ================================================ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false # Do not eager load code on boot. config.eager_load = false # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true # Asset digests allow you to set far-future HTTP expiration dates on all assets, # yet still be able to expire them through the digest params. config.assets.digest = true # Adds additional error checking when serving assets at runtime. # Checks for improperly declared sprockets dependencies. # Raises helpful error messages. config.assets.raise_runtime_errors = true # Raises error for missing translations # config.action_view.raise_on_missing_translations = true config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } config.action_mailer.delivery_method = :letter_opener end ================================================ FILE: config/environments/production.rb ================================================ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. config.cache_classes = true # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true # Full error reports are disabled and caching is turned on. config.consider_all_requests_local = false config.action_controller.perform_caching = true # Enable Rack::Cache to put a simple HTTP cache in front of your application # Add `rack-cache` to your Gemfile before enabling this. # For large-scale production use, consider using a caching reverse proxy like # NGINX, varnish or squid. # config.action_dispatch.rack_cache = true # Disable serving static files from the `/public` folder by default since # Apache or NGINX already handles this. config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = true # Asset digests allow you to set far-future HTTP expiration dates on all assets, # yet still be able to expire them through the digest params. config.assets.digest = true # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb # Specifies the header that your server uses for sending files. # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information # when problems arise. config.log_level = :debug # Prepend all log lines with the following tags. # config.log_tags = [ :subdomain, :uuid ] # Use a different logger for distributed setups. # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) # Use a different cache store in production. # config.cache_store = :mem_cache_store # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.action_controller.asset_host = 'http://assets.example.com' # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false config.action_mailer.default_url_options = { host: 'http://socifyapp.herokuapp.com' } ActionMailer::Base.delivery_method = :smtp ActionMailer::Base.perform_deliveries = true ActionMailer::Base.smtp_settings = { :address => 'smtp.sendgrid.net', :port => '587', :domain => 'heroku.com', :user_name => ENV['USERNAME'], :password => ENV['PASSWORD'], :authentication => "plain", :enable_starttls_auto => true } end ================================================ FILE: config/environments/test.rb ================================================ Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! config.cache_classes = true # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that # preloads Rails for running tests, you may have to set it to true. config.eager_load = false # Configure static file server for tests with Cache-Control for performance. config.serve_static_files = true config.static_cache_control = 'public, max-age=3600' # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test # Randomize the order test cases are executed. config.active_support.test_order = :random # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr # Raises error for missing translations # config.action_view.raise_on_missing_translations = true end ================================================ FILE: config/initializers/assets.rb ================================================ # Be sure to restart your server when you modify this file. # Version of your assets, change this if you want to expire all your assets. Rails.application.config.assets.version = '1.0' # Add additional assets to the asset load path # Rails.application.config.assets.paths << Emoji.images_path # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # Rails.application.config.assets.precompile += %w( search.js ) ================================================ FILE: config/initializers/backtrace_silencers.rb ================================================ # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! ================================================ FILE: config/initializers/carrierwave.rb ================================================ CarrierWave.configure do |config| if Rails.env.production? config.fog_credentials = { provider: 'AWS', # required aws_access_key_id: Rails.application.secrets.aws_access_key_id, # required aws_secret_access_key: Rails.application.secrets.aws_secret_access_key, # required region: 'us-east-1', # optional, defaults to 'us-east-1' } config.fog_directory = 'socify' # required config.fog_public = true # optional, defaults to true config.fog_attributes = { 'Cache-Control' => "max-age=#{365.day.to_i}" } # optional, defaults to {} end end ================================================ FILE: config/initializers/cookies_serializer.rb ================================================ # Be sure to restart your server when you modify this file. Rails.application.config.action_dispatch.cookies_serializer = :json ================================================ FILE: config/initializers/devise.rb ================================================ # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| # The secret key used by Devise. Devise uses this key to generate # random tokens. Changing this key will render invalid all existing # confirmation, reset password and unlock tokens in the database. # Devise will use the `secret_key_base` on Rails 4+ applications as its `secret_key` # by default. You can change it below and use your own secret key. # config.secret_key = '658880288113e5b68bd9d6a14833f20128a9ffc66a4b117fd4b6b1761766ba1acdf2c525405fb08ab4cf1c060a6d8cb9dd4115457c204cea735899d4c78b3b42' # ==> Mailer Configuration # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. config.mailer_sender = 'admin@socifyapp.herokuapp.com' # Configure the class responsible to send e-mails. # config.mailer = 'Devise::Mailer' # ==> ORM configuration # Load and configure the ORM. Supports :active_record (default) and # :mongoid (bson_ext recommended) by default. Other ORMs may be # available as additional gems. require 'devise/orm/active_record' # ==> Configuration for any authentication mechanism # Configure which keys are used when authenticating a user. The default is # just :email. You can configure it to use [:username, :subdomain], so for # authenticating a user, both parameters are required. Remember that those # parameters are used only when authenticating and not when retrieving from # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. # config.authentication_keys = [:email] # Configure parameters from the request object used for authentication. Each entry # given should be a request method and it will automatically be passed to the # find_for_authentication method and considered in your model lookup. For instance, # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. # The same considerations mentioned for authentication_keys also apply to request_keys. # config.request_keys = [] # Configure which authentication keys should be case-insensitive. # These keys will be downcased upon creating or modifying a user and when used # to authenticate or find a user. Default is :email. config.case_insensitive_keys = [:email] # Configure which authentication keys should have whitespace stripped. # These keys will have whitespace before and after removed upon creating or # modifying a user and when used to authenticate or find a user. Default is :email. config.strip_whitespace_keys = [:email] # Tell if authentication through request.params is enabled. True by default. # It can be set to an array that will enable params authentication only for the # given strategies, for example, `config.params_authenticatable = [:database]` will # enable it only for database (email + password) authentication. # config.params_authenticatable = true # Tell if authentication through HTTP Auth is enabled. False by default. # It can be set to an array that will enable http authentication only for the # given strategies, for example, `config.http_authenticatable = [:database]` will # enable it only for database authentication. The supported strategies are: # :database = Support basic authentication with authentication key + password # config.http_authenticatable = false # If 401 status code should be returned for AJAX requests. True by default. # config.http_authenticatable_on_xhr = true # The realm used in Http Basic Authentication. 'Application' by default. # config.http_authentication_realm = 'Application' # It will change confirmation, password recovery and other workflows # to behave the same regardless if the e-mail provided was right or wrong. # Does not affect registerable. # config.paranoid = true # By default Devise will store the user in session. You can skip storage for # particular strategies by setting this option. # Notice that if you are skipping storage for all authentication paths, you # may want to disable generating routes to Devise's sessions controller by # passing skip: :sessions to `devise_for` in your config/routes.rb config.skip_session_storage = [:http_auth] # By default, Devise cleans up the CSRF token on authentication to # avoid CSRF token fixation attacks. This means that, when using AJAX # requests for sign in and sign up, you need to get a new CSRF token # from the server. You can disable this option at your own risk. # config.clean_up_csrf_token_on_authentication = true # ==> Configuration for :database_authenticatable # For bcrypt, this is the cost for hashing the password and defaults to 10. If # using other encryptors, it sets how many times you want the password re-encrypted. # # Limiting the stretches to just one in testing will increase the performance of # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use # a value less than 10 in other environments. Note that, for bcrypt (the default # encryptor), the cost increases exponentially with the number of stretches (e.g. # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation). config.stretches = Rails.env.test? ? 1 : 10 # Setup a pepper to generate the encrypted password. # config.pepper = '3ef86ba979b6b2993e9ec0a4baed06cd5341625212d1a0a3dda3cd21db4f82b655b8089e9323e9f595f1b0f92e972c71cc5a3459d8139067e6891bf344f667e3' # ==> Configuration for :confirmable # A period that the user is allowed to access the website even without # confirming their account. For instance, if set to 2.days, the user will be # able to access the website for two days without confirming their account, # access will be blocked just in the third day. Default is 0.days, meaning # the user cannot access the website without confirming their account. # config.allow_unconfirmed_access_for = 2.days # A period that the user is allowed to confirm their account before their # token becomes invalid. For example, if set to 3.days, the user can confirm # their account within 3 days after the mail was sent, but on the fourth day # their account can't be confirmed with the token any more. # Default is nil, meaning there is no restriction on how long a user can take # before confirming their account. # config.confirm_within = 3.days # If true, requires any email changes to be confirmed (exactly the same way as # initial account confirmation) to be applied. Requires additional unconfirmed_email # db field (see migrations). Until confirmed, new email is stored in # unconfirmed_email column, and copied to email column on successful confirmation. config.reconfirmable = false # Defines which key will be used when confirming an account # config.confirmation_keys = [:email] # ==> Configuration for :rememberable # The time the user will be remembered without asking for credentials again. # config.remember_for = 2.weeks # Invalidates all the remember me tokens when the user signs out. config.expire_all_remember_me_on_sign_out = true # If true, extends the user's remember period when remembered via cookie. # config.extend_remember_period = false # Options to be passed to the created cookie. For instance, you can set # secure: true in order to force SSL only cookies. # config.rememberable_options = {} # ==> Configuration for :validatable # Range for password length. config.password_length = 8..72 # Email regex used to validate email formats. It simply asserts that # one (and only one) @ exists in the given string. This is mainly # to give user feedback and not to assert the e-mail validity. # config.email_regexp = /\A[^@]+@[^@]+\z/ # ==> Configuration for :timeoutable # The time you want to timeout the user session without activity. After this # time the user will be asked for credentials again. Default is 30 minutes. # config.timeout_in = 30.minutes # If true, expires auth token on session timeout. # config.expire_auth_token_on_timeout = false # ==> Configuration for :lockable # Defines which strategy will be used to lock an account. # :failed_attempts = Locks an account after a number of failed attempts to sign in. # :none = No lock strategy. You should handle locking by yourself. # config.lock_strategy = :failed_attempts # Defines which key will be used when locking and unlocking an account # config.unlock_keys = [:email] # Defines which strategy will be used to unlock an account. # :email = Sends an unlock link to the user email # :time = Re-enables login after a certain amount of time (see :unlock_in below) # :both = Enables both strategies # :none = No unlock strategy. You should handle unlocking by yourself. # config.unlock_strategy = :both # Number of authentication tries before locking an account if lock_strategy # is failed attempts. # config.maximum_attempts = 20 # Time interval to unlock the account if :time is enabled as unlock_strategy. # config.unlock_in = 1.hour # Warn on the last attempt before the account is locked. # config.last_attempt_warning = true # ==> Configuration for :recoverable # # Defines which key will be used when recovering the password for an account # config.reset_password_keys = [:email] # Time interval you can reset your password with a reset password key. # Don't put a too small interval or your users won't have the time to # change their passwords. config.reset_password_within = 6.hours # When set to false, does not sign a user in automatically after their password is # reset. Defaults to true, so a user is signed in automatically after a reset. # config.sign_in_after_reset_password = true # ==> Configuration for :encryptable # Allow you to use another encryption algorithm besides bcrypt (default). You can use # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) # and :restful_authentication_sha1 (then you should set stretches to 10, and copy # REST_AUTH_SITE_KEY to pepper). # # Require the `devise-encryptable` gem when using anything other than bcrypt # config.encryptor = :sha512 # ==> Scopes configuration # Turn scoped views on. Before rendering "sessions/new", it will first check for # "users/sessions/new". It's turned off by default because it's slower if you # are using only default views. # config.scoped_views = false # Configure the default scope given to Warden. By default it's the first # devise role declared in your routes (usually :user). # config.default_scope = :user # Set this configuration to false if you want /users/sign_out to sign out # only the current scope. By default, Devise signs out all scopes. # config.sign_out_all_scopes = true # ==> Navigation configuration # Lists the formats that should be treated as navigational. Formats like # :html, should redirect to the sign in page when the user does not have # access, but formats like :xml or :json, should return 401. # # If you have any extra navigational formats, like :iphone or :mobile, you # should add them to the navigational formats lists. # # The "*/*" below is required to match Internet Explorer requests. # config.navigational_formats = ['*/*', :html] # The default HTTP method used to sign out a resource. Default is :delete. config.sign_out_via = :delete # ==> OmniAuth # Add a new OmniAuth provider. Check the wiki for more information on setting # up on your models and hooks. # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' # ==> Warden configuration # If you want to use other strategies, that are not supported by Devise, or # change the failure app, you can configure them inside the config.warden block. # # config.warden do |manager| # manager.intercept_401 = false # manager.default_strategies(scope: :user).unshift :some_external_strategy # end # ==> Mountable engine configurations # When using Devise inside an engine, let's call it `MyEngine`, and this engine # is mountable, there are some extra configurations to be taken into account. # The following options are available, assuming the engine is mounted as: # # mount MyEngine, at: '/my_engine' # # The router that invoked `devise_for`, in the example above, would be: # config.router_name = :my_engine # # When using OmniAuth, Devise cannot automatically set OmniAuth path, # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' end ================================================ FILE: config/initializers/filter_parameter_logging.rb ================================================ # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. Rails.application.config.filter_parameters += [:password] ================================================ FILE: config/initializers/friendly_id.rb ================================================ # FriendlyId Global Configuration # # Use this to set up shared configuration options for your entire application. # Any of the configuration options shown here can also be applied to single # models by passing arguments to the `friendly_id` class method or defining # methods in your model. # # To learn more, check out the guide: # # http://norman.github.io/friendly_id/file.Guide.html FriendlyId.defaults do |config| # ## Reserved Words # # Some words could conflict with Rails's routes when used as slugs, or are # undesirable to allow as slugs. Edit this list as needed for your app. config.use :reserved config.reserved_words = %w(new edit index session login logout users admin stylesheets assets javascripts images) # ## Friendly Finders # # Uncomment this to use friendly finders in all models. By default, if # you wish to find a record by its friendly id, you must do: # # MyModel.friendly.find('foo') # # If you uncomment this, you can do: # # MyModel.find('foo') # # This is significantly more convenient but may not be appropriate for # all applications, so you must explicity opt-in to this behavior. You can # always also configure it on a per-model basis if you prefer. # # Something else to consider is that using the :finders addon boosts # performance because it will avoid Rails-internal code that makes runtime # calls to `Module.extend`. # # config.use :finders # # ## Slugs # # Most applications will use the :slugged module everywhere. If you wish # to do so, uncomment the following line. # # config.use :slugged # # By default, FriendlyId's :slugged addon expects the slug column to be named # 'slug', but you can change it if you wish. # # config.slug_column = 'slug' # # When FriendlyId can not generate a unique ID from your base method, it appends # a UUID, separated by a single dash. You can configure the character used as the # separator. If you're upgrading from FriendlyId 4, you may wish to replace this # with two dashes. # # config.sequence_separator = '-' # # ## Tips and Tricks # # ### Controlling when slugs are generated # # As of FriendlyId 5.0, new slugs are generated only when the slug field is # nil, but if you're using a column as your base method can change this # behavior by overriding the `should_generate_new_friendly_id` method that # FriendlyId adds to your model. The change below makes FriendlyId 5.0 behave # more like 4.0. # # config.use Module.new { # def should_generate_new_friendly_id? # slug.blank? || _changed? # end # } # # FriendlyId uses Rails's `parameterize` method to generate slugs, but for # languages that don't use the Roman alphabet, that's not usually sufficient. # Here we use the Babosa library to transliterate Russian Cyrillic slugs to # ASCII. If you use this, don't forget to add "babosa" to your Gemfile. # # config.use Module.new { # def normalize_friendly_id(text) # text.to_slug.normalize! :transliterations => [:russian, :latin] # end # } end ================================================ FILE: config/initializers/inflections.rb ================================================ # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections # are locale specific, and you may define rules for as many different # locales as you wish. All of these examples are active by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end # These inflection rules are supported but not enabled by default: # ActiveSupport::Inflector.inflections(:en) do |inflect| # inflect.acronym 'RESTful' # end ================================================ FILE: config/initializers/merit.rb ================================================ # Use this hook to configure merit parameters Merit.setup do |config| Merit::Badge.create!( id: 1, name: "Jr.Critics", description: "Over 5 comments", custom_fields: { color: '#C9AE5D', icon: 'icon-star-circled' } ) Merit::Badge.create!( id: 2, name: "Sr.Critic", description: "Over 50 comments", custom_fields: { color: '#FFD700', icon: 'icon-crown' } ) Merit::Badge.create!( id: 3, name: "Story Teller", description: "Over 5 posts!", custom_fields: { color: '#C0C0C0', icon: 'icon-certificate' } ) Merit::Badge.create!( id: 4, name: "First story ", description: "created first story", custom_fields: { color: '#C9AE5D', icon: 'icon-star-1' } ) Merit::Badge.create!( id: 5, name: "Scholar", description: "Recieved over 2 likes on your post!", custom_fields: { color: '#FFD700', icon: 'icon-certificate' } ) Merit::Badge.create!( id: 6, name: "Necromancer", description: "followed 7 people", custom_fields: { color: '#FFD700', icon: 'icon-minefield' } ) end # Check rules on each request or in background # config.checks_on_each_request = true # Define ORM. Could be :active_record (default) and :mongoid # config.orm = :active_record # Add application observers to get notifications when reputation changes. # config.add_observer 'MyObserverClassName' # Define :user_model_name. This model will be used to grand badge if no # `:to` option is given. Default is 'User'. # config.user_model_name = 'User' # Define :current_user_method. Similar to previous option. It will be used # to retrieve :user_model_name object if no `:to` option is given. Default # is "current_#{user_model_name.downcase}". # config.current_user_method = 'current_user' # Create application badges (uses https://github.com/norman/ambry) # badge_id = 0 # [{ # id: (badge_id = badge_id+1), # name: 'just-registered' # }, { # id: (badge_id = badge_id+1), # name: 'best-unicorn', # custom_fields: { category: 'fantasy' } # }].each do |attrs| # Merit::Badge.create! attrs # end ================================================ FILE: config/initializers/mime_types.rb ================================================ # Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf ================================================ FILE: config/initializers/session_store.rb ================================================ # Be sure to restart your server when you modify this file. Rails.application.config.session_store :cookie_store, key: '_socify_session' ================================================ FILE: config/initializers/wrap_parameters.rb ================================================ # Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which # is enabled by default. # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do wrap_parameters format: [:json] if respond_to?(:wrap_parameters) end # To enable root element in JSON for ActiveRecord objects. # ActiveSupport.on_load(:active_record) do # self.include_root_in_json = true # end ================================================ FILE: config/locales/devise.en.yml ================================================ # Additional translations at https://github.com/plataformatec/devise/wiki/I18n en: devise: confirmations: confirmed: "Your email address has been successfully confirmed." send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." failure: already_authenticated: "You are already signed in." inactive: "Your account is not activated yet." invalid: "Invalid %{authentication_keys} or password." locked: "Your account is locked." last_attempt: "You have one more attempt before your account is locked." not_found_in_database: "Invalid %{authentication_keys} or password." timeout: "Your session expired. Please sign in again to continue." unauthenticated: "You need to sign in or sign up before continuing." unconfirmed: "You have to confirm your email address before continuing." mailer: confirmation_instructions: subject: "Confirmation instructions" reset_password_instructions: subject: "Reset password instructions" unlock_instructions: subject: "Unlock instructions" omniauth_callbacks: failure: "Could not authenticate you from %{kind} because \"%{reason}\"." success: "Successfully authenticated from %{kind} account." passwords: no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." updated: "Your password has been changed successfully. You are now signed in." updated_not_active: "Your password has been changed successfully." registrations: destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon." signed_up: "Welcome! You have signed up successfully." signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address." updated: "Your account has been updated successfully." sessions: signed_in: "" signed_out: "Signed out. Bye!" already_signed_out: "Signed out. Bye!" unlocks: send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." unlocked: "Your account has been unlocked successfully. Please sign in to continue." errors: messages: already_confirmed: "was already confirmed, please try signing in" confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" expired: "has expired, please request a new one" not_found: "not found" not_locked: "was not locked" not_saved: one: "1 error prohibited this %{resource} from being saved:" other: "%{count} errors prohibited this %{resource} from being saved:" ================================================ FILE: config/locales/en.yml ================================================ # Files in the config/locales directory are used for internationalization # and are automatically loaded by Rails. If you want to use locales other # than English, add the necessary files in this directory. # # To use the locales, use `I18n.t`: # # I18n.t 'hello' # # In views, this is aliased to just `t`: # # <%= t('hello') %> # # To use a different locale, set it with `I18n.locale`: # # I18n.locale = :es # # This would use the information in config/locales/es.yml. # # To learn more, please read the Rails Internationalization guide # available at http://guides.rubyonrails.org/i18n.html. en: hello: "Hello world" ================================================ FILE: config/puma.rb ================================================ workers Integer(ENV['WEB_CONCURRENCY'] || 2) threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 1) threads threads_count, threads_count preload_app! rackup DefaultRackup port ENV['PORT'] || 3000 environment ENV['RACK_ENV'] || 'development' on_worker_boot do # Worker specific setup for Rails 4.1+ # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot ActiveRecord::Base.establish_connection end ================================================ FILE: config/routes.rb ================================================ Rails.application.routes.draw do resources :posts resources :comments, only: [:create, :destroy] devise_for :users resources :users do member do get :friends get :followers get :deactivate get :mentionable end end resources :events do collection do get :calendar end end authenticated :user do root to: 'home#index', as: 'home' end unauthenticated :user do root 'home#front' end match :follow, to: 'follows#create', as: :follow, via: :post match :unfollow, to: 'follows#destroy', as: :unfollow, via: :post match :like, to: 'likes#create', as: :like, via: :post match :unlike, to: 'likes#destroy', as: :unlike, via: :post match :find_friends, to: 'home#find_friends', as: :find_friends, via: :get match :about, to: 'home#about', as: :about, via: :get # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". # You can have the root of your site routed with "root" # root 'welcome#index' # Example of regular route: # get 'products/:id' => 'catalog#view' # Example of named route that can be invoked with purchase_url(id: product.id) # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase # Example resource route (maps HTTP verbs to controller actions automatically): # resources :products # Example resource route with options: # resources :products do # member do # get 'short' # post 'toggle' # end # # collection do # get 'sold' # end # end # Example resource route with sub-resources: # resources :products do # resources :comments, :sales # resource :seller # end # Example resource route with more complex sub-resources: # resources :products do # resources :comments # resources :sales do # get 'recent', on: :collection # end # end # Example resource route with concerns: # concern :toggleable do # post 'toggle' # end # resources :posts, concerns: :toggleable # resources :photos, concerns: :toggleable # Example resource route within a namespace: # namespace :admin do # # Directs /admin/products/* to Admin::ProductsController # # (app/controllers/admin/products_controller.rb) # resources :products # end end ================================================ FILE: config/secrets.yml ================================================ # Be sure to restart your server when you modify this file. # Your secret key is used for verifying the integrity of signed cookies. # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. # You can use `rake secret` to generate a secure secret key. # Make sure the secrets in this file are kept private # if you're sharing your code publicly. development: secret_key_base: 60d47b0c616136ad34cb09ad5c0b5fa3f4cf938128fad8b52664881886355a6525ba8384f2cd81f8c051abd9e276a88c6e0504685b2a6f4489d3d406d65bc3f6 test: secret_key_base: 962263610e563c52551c565eb7aafbe4c2c786f640fb8a540bf25d310cee799c7408692c4700e38eec3c3c153f0dee9cb91d0fd440f0b9c9b3706647afe4e74d # Do not keep production secrets in the repository, # instead read values from the environment. production: secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> aws_access_key_id: <%= ENV["AWS_ACCESS_KEY_ID"] %> aws_secret_access_key: <%= ENV["AWS_SECRET_ACCESS_KEY"] %> ================================================ FILE: config.ru ================================================ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) run Rails.application ================================================ FILE: db/migrate/20150701024445_devise_create_users.rb ================================================ class DeviseCreateUsers < ActiveRecord::Migration def change create_table(:users) do |t| ## Database authenticatable t.string :name, null: false, default: "" t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" t.string :about t.string :avatar t.string :cover ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable t.integer :sign_in_count, default: 0, null: false t.datetime :current_sign_in_at t.datetime :last_sign_in_at t.string :current_sign_in_ip t.string :last_sign_in_ip ## Confirmable t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end ================================================ FILE: db/migrate/20150702015915_create_posts.rb ================================================ class CreatePosts < ActiveRecord::Migration def change create_table :posts do |t| t.text :content, null: false t.references :user, index: true t.string :attachment t.timestamps end end end ================================================ FILE: db/migrate/20150702020527_create_activities.rb ================================================ # Migration responsible for creating a table with activities class CreateActivities < ActiveRecord::Migration # Create table def self.up create_table :activities do |t| t.belongs_to :trackable, :polymorphic => true t.belongs_to :owner, :polymorphic => true t.string :key t.text :parameters t.belongs_to :recipient, :polymorphic => true t.timestamps end add_index :activities, [:trackable_id, :trackable_type] add_index :activities, [:owner_id, :owner_type] add_index :activities, [:recipient_id, :recipient_type] end # Drop table def self.down drop_table :activities end end ================================================ FILE: db/migrate/20150703041854_acts_as_votable_migration.rb ================================================ class ActsAsVotableMigration < ActiveRecord::Migration def self.up create_table :votes do |t| t.references :votable, :polymorphic => true t.references :voter, :polymorphic => true t.boolean :vote_flag t.string :vote_scope t.integer :vote_weight t.timestamps end if ActiveRecord::VERSION::MAJOR < 4 add_index :votes, [:votable_id, :votable_type] add_index :votes, [:voter_id, :voter_type] end add_index :votes, [:voter_id, :voter_type, :vote_scope] add_index :votes, [:votable_id, :votable_type, :vote_scope] end def self.down drop_table :votes end end ================================================ FILE: db/migrate/20150703053202_add_cached_votes_to_posts.rb ================================================ class AddCachedVotesToPosts < ActiveRecord::Migration def change add_column :posts, :cached_votes_up, :integer, :default => 0 add_index :posts, :cached_votes_up end end ================================================ FILE: db/migrate/20150703054721_create_comments.rb ================================================ class CreateComments < ActiveRecord::Migration def self.up create_table :comments do |t| t.string :title, :limit => 50, :default => "" t.text :comment t.references :commentable, :polymorphic => true t.references :user t.string :role, :default => "comments" t.timestamps end add_index :comments, :commentable_type add_index :comments, :commentable_id add_index :comments, :user_id end def self.down drop_table :comments end end ================================================ FILE: db/migrate/20150703161656_add_counter_cache_to_posts.rb ================================================ class AddCounterCacheToPosts < ActiveRecord::Migration def change add_column :posts, :comments_count, :integer, :default => 0 add_index :posts, :comments_count end end ================================================ FILE: db/migrate/20150703194107_acts_as_follower_migration.rb ================================================ class ActsAsFollowerMigration < ActiveRecord::Migration def self.up create_table :follows, :force => true do |t| t.references :followable, :polymorphic => true, :null => false t.references :follower, :polymorphic => true, :null => false t.boolean :blocked, :default => false, :null => false t.timestamps end add_index :follows, ["follower_id", "follower_type"], :name => "fk_follows" add_index :follows, ["followable_id", "followable_type"], :name => "fk_followables" end def self.down drop_table :follows end end ================================================ FILE: db/migrate/20150709034258_create_events.rb ================================================ class CreateEvents < ActiveRecord::Migration def change create_table :events do |t| t.string :name t.datetime :when t.references :user, index: true t.timestamps end end end ================================================ FILE: db/migrate/20150709050651_add_votes_comments_count_to_events.rb ================================================ class AddVotesCommentsCountToEvents < ActiveRecord::Migration def change add_column :events, :cached_votes_up, :integer, :default => 0 add_index :events, :cached_votes_up add_column :events, :comments_count, :integer, :default => 0 add_index :events, :comments_count end end ================================================ FILE: db/migrate/20150710004012_add_fields_to_user.rb ================================================ class AddFieldsToUser < ActiveRecord::Migration def change add_column :users, :sex, :string, null: false, default: 'male' add_column :users, :location, :string add_column :users, :dob, :date add_column :users, :phone_number, :string end end ================================================ FILE: db/migrate/20150710030803_add_posts_count_to_users.rb ================================================ class AddPostsCountToUsers < ActiveRecord::Migration def self.up add_column :users, :posts_count, :integer, :null => false, :default => 0 end def self.down remove_column :users, :posts_count end end ================================================ FILE: db/migrate/20150710044606_create_friendly_id_slugs.rb ================================================ class CreateFriendlyIdSlugs < ActiveRecord::Migration def change create_table :friendly_id_slugs do |t| t.string :slug, :null => false t.integer :sluggable_id, :null => false t.string :sluggable_type, :limit => 50 t.string :scope t.datetime :created_at end add_index :friendly_id_slugs, :sluggable_id add_index :friendly_id_slugs, [:slug, :sluggable_type] add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], :unique => true add_index :friendly_id_slugs, :sluggable_type end end ================================================ FILE: db/migrate/20150710044624_add_slug_to_users.rb ================================================ class AddSlugToUsers < ActiveRecord::Migration def change add_column :users, :slug, :string add_index :users, :slug, unique: true end end ================================================ FILE: db/migrate/20150723052523_add_content_html_to_posts.rb ================================================ class AddContentHtmlToPosts < ActiveRecord::Migration def change add_column :posts, :content_html, :text end end ================================================ FILE: db/migrate/20150723052743_add_comment_html_to_comments.rb ================================================ class AddCommentHtmlToComments < ActiveRecord::Migration def change add_column :comments, :comment_html, :text end end ================================================ FILE: db/migrate/20170428044229_rename_events_when_column.rb ================================================ class RenameEventsWhenColumn < ActiveRecord::Migration[5.0] def change rename_column :events, :when, :event_datetime end end ================================================ FILE: db/migrate/20170613183107_add_merit_fields_to_users.rb ================================================ class AddMeritFieldsToUsers < ActiveRecord::Migration def change add_column :users, :sash_id, :integer add_column :users, :level, :integer, :default => 0 end end ================================================ FILE: db/migrate/20170613183243_create_merit_actions.rb ================================================ class CreateMeritActions < ActiveRecord::Migration def change create_table :merit_actions do |t| t.integer :user_id t.string :action_method t.integer :action_value t.boolean :had_errors, default: false t.string :target_model t.integer :target_id t.text :target_data t.boolean :processed, default: false t.timestamps end end end ================================================ FILE: db/migrate/20170613183244_create_merit_activity_logs.rb ================================================ class CreateMeritActivityLogs < ActiveRecord::Migration def change create_table :merit_activity_logs do |t| t.integer :action_id t.string :related_change_type t.integer :related_change_id t.string :description t.datetime :created_at end end end ================================================ FILE: db/migrate/20170613183245_create_sashes.rb ================================================ class CreateSashes < ActiveRecord::Migration def change create_table :sashes do |t| t.timestamps end end end ================================================ FILE: db/migrate/20170613183246_create_badges_sashes.rb ================================================ class CreateBadgesSashes < ActiveRecord::Migration def self.up create_table :badges_sashes do |t| t.integer :badge_id, :sash_id t.boolean :notified_user, default: false t.datetime :created_at end add_index :badges_sashes, [:badge_id, :sash_id] add_index :badges_sashes, :badge_id add_index :badges_sashes, :sash_id end def self.down drop_table :badges_sashes end end ================================================ FILE: db/migrate/20170613183247_create_scores_and_points.rb ================================================ class CreateScoresAndPoints < ActiveRecord::Migration def change create_table :merit_scores do |t| t.references :sash t.string :category, default: 'default' end create_table :merit_score_points do |t| t.references :score t.integer :num_points, default: 0 t.string :log t.datetime :created_at end end end ================================================ FILE: db/schema.rb ================================================ # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # # Note that this schema.rb definition is the authoritative source for your # database schema. If you need to create the application database on another # system, you should be using db:schema:load, not running all the migrations # from scratch. The latter is a flawed and unsustainable approach (the more migrations # you'll amass, the slower it'll run and the greater likelihood for issues). # # It's strongly recommended that you check this file into your version control system. ActiveRecord::Schema.define(version: 20170613183247) do create_table "activities", force: :cascade do |t| t.string "trackable_type" t.integer "trackable_id" t.string "owner_type" t.integer "owner_id" t.string "key" t.text "parameters" t.string "recipient_type" t.integer "recipient_id" t.datetime "created_at" t.datetime "updated_at" t.index ["owner_id", "owner_type"], name: "index_activities_on_owner_id_and_owner_type" t.index ["recipient_id", "recipient_type"], name: "index_activities_on_recipient_id_and_recipient_type" t.index ["trackable_id", "trackable_type"], name: "index_activities_on_trackable_id_and_trackable_type" end create_table "attachments", force: :cascade do |t| t.string "file_name" t.string "attachable_type", default: "" t.integer "attachable_id", default: 0 t.datetime "created_at" t.datetime "updated_at" t.index ["attachable_type", "attachable_id"], name: "index_attachments_on_attachable_type_and_attachable_id" end create_table "authentications", force: :cascade do |t| t.string "uid" t.string "provider" t.string "oauth_token" t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" t.index ["user_id"], name: "index_authentications_on_user_id" end create_table "badges_sashes", force: :cascade do |t| t.integer "badge_id" t.integer "sash_id" t.boolean "notified_user", default: false t.datetime "created_at" t.index ["badge_id", "sash_id"], name: "index_badges_sashes_on_badge_id_and_sash_id" t.index ["badge_id"], name: "index_badges_sashes_on_badge_id" t.index ["sash_id"], name: "index_badges_sashes_on_sash_id" end create_table "comments", force: :cascade do |t| t.string "title", limit: 50, default: "" t.text "comment" t.string "commentable_type" t.integer "commentable_id" t.integer "user_id" t.string "role", default: "comments" t.datetime "created_at" t.datetime "updated_at" t.text "comment_html" t.index ["commentable_id"], name: "index_comments_on_commentable_id" t.index ["commentable_type"], name: "index_comments_on_commentable_type" t.index ["user_id"], name: "index_comments_on_user_id" end create_table "event_attendees", force: :cascade do |t| t.integer "event_id", null: false t.integer "user_id", null: false t.datetime "created_at" t.datetime "updated_at" t. "status", default: "0", null: false t.index ["event_id"], name: "index_event_attendees_on_event_id" t.index ["user_id"], name: "index_event_attendees_on_user_id" end create_table "events", force: :cascade do |t| t.string "name" t.datetime "event_datetime" t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" t.integer "cached_votes_up", default: 0 t.integer "comments_count", default: 0 t.string "location" t.string "latlng", default: "" t.index ["cached_votes_up"], name: "index_events_on_cached_votes_up" t.index ["comments_count"], name: "index_events_on_comments_count" t.index ["user_id"], name: "index_events_on_user_id" end create_table "follows", force: :cascade do |t| t.string "followable_type", null: false t.integer "followable_id", null: false t.string "follower_type", null: false t.integer "follower_id", null: false t.boolean "blocked", default: false, null: false t.datetime "created_at" t.datetime "updated_at" t.index ["followable_id", "followable_type"], name: "fk_followables" t.index ["follower_id", "follower_type"], name: "fk_follows" end create_table "friendly_id_slugs", force: :cascade do |t| t.string "slug", null: false t.integer "sluggable_id", null: false t.string "sluggable_type", limit: 50 t.string "scope" t.datetime "created_at" t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type" t.index ["sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_id" t.index ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type" end create_table "merit_actions", force: :cascade do |t| t.integer "user_id" t.string "action_method" t.integer "action_value" t.boolean "had_errors", default: false t.string "target_model" t.integer "target_id" t.text "target_data" t.boolean "processed", default: false t.datetime "created_at" t.datetime "updated_at" end create_table "merit_activity_logs", force: :cascade do |t| t.integer "action_id" t.string "related_change_type" t.integer "related_change_id" t.string "description" t.datetime "created_at" end create_table "merit_score_points", force: :cascade do |t| t.integer "score_id" t.integer "num_points", default: 0 t.string "log" t.datetime "created_at" end create_table "merit_scores", force: :cascade do |t| t.integer "sash_id" t.string "category", default: "default" end create_table "photo_albums", force: :cascade do |t| t.string "title", default: "Album" t.string "front_image_url" t.integer "photos_count", default: 0, null: false t.integer "user_id" t.datetime "created_at" t.datetime "updated_at" t.string "slug" t.integer "cached_votes_up", default: 0 t.integer "comments_count", default: 0 t.index ["slug"], name: "index_photo_albums_on_slug", unique: true t.index ["user_id"], name: "index_photo_albums_on_user_id" end create_table "photos", force: :cascade do |t| t.string "title", default: "", null: false t.string "file", null: false t.integer "photo_album_id" t.datetime "created_at" t.datetime "updated_at" t.index ["photo_album_id"], name: "index_photos_on_photo_album_id" end create_table "posts", force: :cascade do |t| t.text "content", null: false t.integer "user_id" t.string "attachment" t.datetime "created_at" t.datetime "updated_at" t.integer "cached_votes_up", default: 0 t.integer "comments_count", default: 0 t.text "preview_html", default: "", null: false t.index ["cached_votes_up"], name: "index_posts_on_cached_votes_up" t.index ["comments_count"], name: "index_posts_on_comments_count" t.index ["user_id"], name: "index_posts_on_user_id" end create_table "sashes", force: :cascade do |t| t.datetime "created_at" t.datetime "updated_at" end create_table "users", force: :cascade do |t| t.string "name", default: "", null: false t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false t.string "bio" t.string "avatar" t.string "cover" t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" t.string "confirmation_token" t.datetime "confirmed_at" t.datetime "confirmation_sent_at" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "sex", default: "male", null: false t.string "location" t.date "dob" t.string "phone_number" t.integer "posts_count", default: 0, null: false t.string "slug" t.boolean "profile_complete", default: false, null: false t.string "first_name", default: "", null: false t.string "last_name", default: "", null: false t.string "hometown" t.string "works_at" t.integer "photo_albums_count", default: 0, null: false t.integer "sash_id" t.integer "level", default: 0 t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["slug"], name: "index_users_on_slug", unique: true end create_table "votes", force: :cascade do |t| t.string "votable_type" t.integer "votable_id" t.string "voter_type" t.integer "voter_id" t.boolean "vote_flag" t.string "vote_scope" t.integer "vote_weight" t.datetime "created_at" t.datetime "updated_at" t.index ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope" t.index ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope" end end ================================================ FILE: db/seeds.rb ================================================ # This file should contain all the record creation needed to seed the database with its default values. # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). # # Examples: # # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) # Mayor.create(name: 'Emanuel', city: cities.first) ================================================ FILE: lib/assets/.keep ================================================ ================================================ FILE: lib/tasks/.keep ================================================ ================================================ FILE: lib/tasks/populate.rake ================================================ namespace :fill do desc 'Fill data' task data: :environment do require 'faker' require 'populator' puts 'Erasing existing data' puts '=====================' [User, Post, Event, Comment].each(&:delete_all) ActsAsVotable::Vote.delete_all PublicActivity::Activity.delete_all puts 'Creating users' puts '==============' genders = ['male', 'female'] password = 'socify' User.populate 20 do |user| user.name = Faker::Name.name user.email = Faker::Internet.email user.sex = genders user.dob = Faker::Date.between(45.years.ago, 15.years.ago) user.phone_number = Faker::PhoneNumber.cell_phone user.encrypted_password = User.new(password: password).encrypted_password user.confirmed_at = DateTime.now user.sign_in_count = 0 user.posts_count = 0 puts "created user #{user.name}" end user = User.new(name: 'Rails', email: 'test@socify.com', sex: 'female', password: 'password') user.skip_confirmation! user.save! puts 'Created test user with email=test@socify.com and password=password' puts 'Generate Friendly id slug for users' puts '===================================' User.find_each(&:save) puts 'Creating Posts' puts '==============' users = User.all 15.times do post = Post.new post.content = Populator.sentences(2..4) post.user = users.sample post.save! puts "created post #{post.id}" end puts 'Creating Comments For Posts' puts '===========================' posts = Post.all 15.times do post = posts.sample user = users.sample comment = post.comments.new comment.comment = Populator.sentences(1) comment.user = user comment.save puts "user #{user.name} commented on post #{post.id}" end puts 'Creating Events' puts '===============' 15.times do event = Event.new event.name = Populator.words(1..3).titleize event.event_datetime = Faker::Date.between(2.years.ago, 1.day.from_now) event.user = users.sample event.save puts "created event #{event.name}" end puts 'Creating Likes For Posts' puts '========================' 15.times do post = posts.sample user = users.sample post.liked_by user puts "post #{post.id} liked by user #{user.name}" end puts 'Creating Likes For Events' puts '=========================' events = Event.all 15.times do event = events.sample user = users.sample event.liked_by user puts "event #{event.id} liked by user #{user.name}" end puts 'Creating Comments For Events' puts '=============================' 15.times do event = events.sample user = users.sample comment = event.comments.new comment.commentable_type = 'Event' comment.comment = Populator.sentences(1) comment.user = user comment.save puts "user #{user.name} commented on event #{event.id}" end end end ================================================ FILE: public/404.html ================================================ The page you were looking for doesn't exist (404)

    The page you were looking for doesn't exist.

    You may have mistyped the address or the page may have moved.

    If you are the application owner check the logs for more information.

    ================================================ FILE: public/422.html ================================================ The change you wanted was rejected (422)

    The change you wanted was rejected.

    Maybe you tried to change something you didn't have access to.

    If you are the application owner check the logs for more information.

    ================================================ FILE: public/500.html ================================================ We're sorry, but something went wrong (500)

    We're sorry, but something went wrong.

    If you are the application owner check the logs for more information.

    ================================================ FILE: public/robots.txt ================================================ # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file # # To ban all spiders from the entire site uncomment the next two lines: # User-agent: * # Disallow: / ================================================ FILE: test/controllers/.keep ================================================ ================================================ FILE: test/controllers/comments_controller_test.rb ================================================ require 'test_helper' class CommentsControllerTest < ActionController::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/controllers/events_controller_test.rb ================================================ require 'test_helper' class EventsControllerTest < ActionController::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/controllers/follows_controller_test.rb ================================================ require 'test_helper' class FollowsControllerTest < ActionController::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/controllers/home_controller_test.rb ================================================ require 'test_helper' class HomeControllerTest < ActionController::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/controllers/likes_controller_test.rb ================================================ require 'test_helper' class LikesControllerTest < ActionController::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/controllers/posts_controller_test.rb ================================================ require 'test_helper' class PostsControllerTest < ActionController::TestCase setup do @post = posts(:one) end test "should get index" do get :index assert_response :success assert_not_nil assigns(:posts) end test "should get new" do get :new assert_response :success end test "should create post" do assert_difference('Post.count') do post :create, post: { attachment: @post.attachment, content: @post.content, user_id: @post.user_id } end assert_redirected_to post_path(assigns(:post)) end test "should show post" do get :show, id: @post assert_response :success end test "should get edit" do get :edit, id: @post assert_response :success end test "should update post" do patch :update, id: @post, post: { attachment: @post.attachment, content: @post.content, user_id: @post.user_id } assert_redirected_to post_path(assigns(:post)) end test "should destroy post" do assert_difference('Post.count', -1) do delete :destroy, id: @post end assert_redirected_to posts_path end end ================================================ FILE: test/controllers/users_controller_test.rb ================================================ require 'test_helper' class UsersControllerTest < ActionController::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/fixtures/.keep ================================================ ================================================ FILE: test/fixtures/events.yml ================================================ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html one: name: MyString date: 2015-07-08 time: 2015-07-08 22:42:59 user_id: two: name: MyString date: 2015-07-08 time: 2015-07-08 22:42:59 user_id: ================================================ FILE: test/fixtures/posts.yml ================================================ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html one: content: MyText user_id: attachment: MyString two: content: MyText user_id: attachment: MyString ================================================ FILE: test/fixtures/users.yml ================================================ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html # This model initially had no columns defined. If you add columns to the # model remove the '{}' from the fixture names and add the columns immediately # below each fixture, per the syntax in the comments below # one: {} # column: value # two: {} # column: value ================================================ FILE: test/helpers/.keep ================================================ ================================================ FILE: test/helpers/comments_helper_test.rb ================================================ require 'test_helper' class CommentsHelperTest < ActionView::TestCase end ================================================ FILE: test/helpers/events_helper_test.rb ================================================ require 'test_helper' class EventsHelperTest < ActionView::TestCase end ================================================ FILE: test/helpers/follows_helper_test.rb ================================================ require 'test_helper' class FollowsHelperTest < ActionView::TestCase end ================================================ FILE: test/helpers/home_helper_test.rb ================================================ require 'test_helper' class HomeHelperTest < ActionView::TestCase end ================================================ FILE: test/helpers/likes_helper_test.rb ================================================ require 'test_helper' class LikesHelperTest < ActionView::TestCase end ================================================ FILE: test/helpers/posts_helper_test.rb ================================================ require 'test_helper' class PostsHelperTest < ActionView::TestCase end ================================================ FILE: test/helpers/users_helper_test.rb ================================================ require 'test_helper' class UsersHelperTest < ActionView::TestCase end ================================================ FILE: test/integration/.keep ================================================ ================================================ FILE: test/mailers/.keep ================================================ ================================================ FILE: test/models/.keep ================================================ ================================================ FILE: test/models/event_test.rb ================================================ require 'test_helper' class EventTest < ActiveSupport::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/models/post_test.rb ================================================ require 'test_helper' class PostTest < ActiveSupport::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/models/user_test.rb ================================================ require 'test_helper' class UserTest < ActiveSupport::TestCase # test "the truth" do # assert true # end end ================================================ FILE: test/test_helper.rb ================================================ ENV['RAILS_ENV'] ||= 'test' require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all # Add more helper methods to be used by all tests here... end ================================================ FILE: vendor/assets/javascripts/.keep ================================================ ================================================ FILE: vendor/assets/javascripts/bindWithDelay.js ================================================ /* bindWithDelay jQuery plugin Author: Brian Grinstead MIT license: http://www.opensource.org/licenses/mit-license.php http://github.com/bgrins/bindWithDelay http://briangrinstead.com/files/bindWithDelay Usage: See http://api.jquery.com/bind/ .bindWithDelay( eventType, [ eventData ], handler(eventObject), timeout, throttle ) Examples: $("#foo").bindWithDelay("click", function(e) { }, 100); $(window).bindWithDelay("resize", { optional: "eventData" }, callback, 1000); $(window).bindWithDelay("resize", callback, 1000, true); */ (function($) { $.fn.bindWithDelay = function( type, data, fn, timeout, throttle ) { if ( $.isFunction( data ) ) { throttle = timeout; timeout = fn; fn = data; data = undefined; } // Allow delayed function to be removed with fn in unbind function fn.guid = fn.guid || ($.guid && $.guid++); // Bind each separately so that each element has its own delay return this.each(function() { var wait = null; function cb() { var e = $.extend(true, { }, arguments[0]); var ctx = this; var throttler = function() { wait = null; fn.apply(ctx, [e]); }; if (!throttle) { clearTimeout(wait); wait = null; } if (!wait) { wait = setTimeout(throttler, timeout); } } cb.guid = fn.guid; $(this).bind(type, data, cb); }); }; })(jQuery); ================================================ FILE: vendor/assets/javascripts/jquery.datetimepicker.js ================================================ /** * @preserve jQuery DateTimePicker plugin v2.4.5 * @homepage http://xdsoft.net/jqplugins/datetimepicker/ * (c) 2014, Chupurnov Valeriy. */ /*global document,window,jQuery,setTimeout,clearTimeout,HighlightedDate,getCurrentValue*/ (function ($) { 'use strict'; var default_options = { i18n: { ar: { // Arabic months: [ "كانون الثاني", "شباط", "آذار", "نيسان", "مايو", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول" ], dayOfWeek: [ "ن", "ث", "ع", "خ", "ج", "س", "ح" ] }, ro: { // Romanian months: [ "ianuarie", "februarie", "martie", "aprilie", "mai", "iunie", "iulie", "august", "septembrie", "octombrie", "noiembrie", "decembrie" ], dayOfWeek: [ "l", "ma", "mi", "j", "v", "s", "d" ] }, id: { // Indonesian months: [ "Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember" ], dayOfWeek: [ "Min", "Sen", "Sel", "Rab", "Kam", "Jum", "Sab" ] }, is: { // Icelandic months: [ "Janúar", "Febrúar", "Mars", "Apríl", "Maí", "Júní", "Júlí", "Ágúst", "September", "Október", "Nóvember", "Desember" ], dayOfWeek: [ "Sun", "Mán", "Þrið", "Mið", "Fim", "Fös", "Lau" ] }, bg: { // Bulgarian months: [ "Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември" ], dayOfWeek: [ "Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб" ] }, fa: { // Persian/Farsi months: [ 'فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند' ], dayOfWeek: [ 'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه' ] }, ru: { // Russian months: [ 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' ], dayOfWeek: [ "Вск", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб" ] }, uk: { // Ukrainian months: [ 'Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень' ], dayOfWeek: [ "Ндл", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Сбт" ] }, en: { // English months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], dayOfWeek: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ] }, el: { // Ελληνικά months: [ "Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος" ], dayOfWeek: [ "Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ" ] }, de: { // German months: [ 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ], dayOfWeek: [ "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" ] }, nl: { // Dutch months: [ "januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december" ], dayOfWeek: [ "zo", "ma", "di", "wo", "do", "vr", "za" ] }, tr: { // Turkish months: [ "Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık" ], dayOfWeek: [ "Paz", "Pts", "Sal", "Çar", "Per", "Cum", "Cts" ] }, fr: { //French months: [ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre" ], dayOfWeek: [ "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam" ] }, es: { // Spanish months: [ "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre" ], dayOfWeek: [ "Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb" ] }, th: { // Thai months: [ 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม' ], dayOfWeek: [ 'อา.', 'จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.' ] }, pl: { // Polish months: [ "styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień" ], dayOfWeek: [ "nd", "pn", "wt", "śr", "cz", "pt", "sb" ] }, pt: { // Portuguese months: [ "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" ], dayOfWeek: [ "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab" ] }, ch: { // Simplified Chinese months: [ "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月" ], dayOfWeek: [ "日", "一", "二", "三", "四", "五", "六" ] }, se: { // Swedish months: [ "Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December" ], dayOfWeek: [ "Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör" ] }, kr: { // Korean months: [ "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" ], dayOfWeek: [ "일", "월", "화", "수", "목", "금", "토" ] }, it: { // Italian months: [ "Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre" ], dayOfWeek: [ "Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab" ] }, da: { // Dansk months: [ "January", "Februar", "Marts", "April", "Maj", "Juni", "July", "August", "September", "Oktober", "November", "December" ], dayOfWeek: [ "Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør" ] }, no: { // Norwegian months: [ "Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember" ], dayOfWeek: [ "Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør" ] }, ja: { // Japanese months: [ "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月" ], dayOfWeek: [ "日", "月", "火", "水", "木", "金", "土" ] }, vi: { // Vietnamese months: [ "Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12" ], dayOfWeek: [ "CN", "T2", "T3", "T4", "T5", "T6", "T7" ] }, sl: { // Slovenščina months: [ "Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December" ], dayOfWeek: [ "Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob" ] }, cs: { // Čeština months: [ "Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec" ], dayOfWeek: [ "Ne", "Po", "Út", "St", "Čt", "Pá", "So" ] }, hu: { // Hungarian months: [ "Január", "Február", "Március", "Április", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December" ], dayOfWeek: [ "Va", "Hé", "Ke", "Sze", "Cs", "Pé", "Szo" ] }, az: { //Azerbaijanian (Azeri) months: [ "Yanvar", "Fevral", "Mart", "Aprel", "May", "Iyun", "Iyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr" ], dayOfWeek: [ "B", "Be", "Ça", "Ç", "Ca", "C", "Ş" ] }, bs: { //Bosanski months: [ "Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar" ], dayOfWeek: [ "Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub" ] }, ca: { //Català months: [ "Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre" ], dayOfWeek: [ "Dg", "Dl", "Dt", "Dc", "Dj", "Dv", "Ds" ] }, 'en-GB': { //English (British) months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], dayOfWeek: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ] }, et: { //"Eesti" months: [ "Jaanuar", "Veebruar", "Märts", "Aprill", "Mai", "Juuni", "Juuli", "August", "September", "Oktoober", "November", "Detsember" ], dayOfWeek: [ "P", "E", "T", "K", "N", "R", "L" ] }, eu: { //Euskara months: [ "Urtarrila", "Otsaila", "Martxoa", "Apirila", "Maiatza", "Ekaina", "Uztaila", "Abuztua", "Iraila", "Urria", "Azaroa", "Abendua" ], dayOfWeek: [ "Ig.", "Al.", "Ar.", "Az.", "Og.", "Or.", "La." ] }, fi: { //Finnish (Suomi) months: [ "Tammikuu", "Helmikuu", "Maaliskuu", "Huhtikuu", "Toukokuu", "Kesäkuu", "Heinäkuu", "Elokuu", "Syyskuu", "Lokakuu", "Marraskuu", "Joulukuu" ], dayOfWeek: [ "Su", "Ma", "Ti", "Ke", "To", "Pe", "La" ] }, gl: { //Galego months: [ "Xan", "Feb", "Maz", "Abr", "Mai", "Xun", "Xul", "Ago", "Set", "Out", "Nov", "Dec" ], dayOfWeek: [ "Dom", "Lun", "Mar", "Mer", "Xov", "Ven", "Sab" ] }, hr: { //Hrvatski months: [ "Siječanj", "Veljača", "Ožujak", "Travanj", "Svibanj", "Lipanj", "Srpanj", "Kolovoz", "Rujan", "Listopad", "Studeni", "Prosinac" ], dayOfWeek: [ "Ned", "Pon", "Uto", "Sri", "Čet", "Pet", "Sub" ] }, ko: { //Korean (한국어) months: [ "1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월" ], dayOfWeek: [ "일", "월", "화", "수", "목", "금", "토" ] }, lt: { //Lithuanian (lietuvių) months: [ "Sausio", "Vasario", "Kovo", "Balandžio", "Gegužės", "Birželio", "Liepos", "Rugpjūčio", "Rugsėjo", "Spalio", "Lapkričio", "Gruodžio" ], dayOfWeek: [ "Sek", "Pir", "Ant", "Tre", "Ket", "Pen", "Šeš" ] }, lv: { //Latvian (Latviešu) months: [ "Janvāris", "Februāris", "Marts", "Aprīlis ", "Maijs", "Jūnijs", "Jūlijs", "Augusts", "Septembris", "Oktobris", "Novembris", "Decembris" ], dayOfWeek: [ "Sv", "Pr", "Ot", "Tr", "Ct", "Pk", "St" ] }, mk: { //Macedonian (Македонски) months: [ "јануари", "февруари", "март", "април", "мај", "јуни", "јули", "август", "септември", "октомври", "ноември", "декември" ], dayOfWeek: [ "нед", "пон", "вто", "сре", "чет", "пет", "саб" ] }, mn: { //Mongolian (Монгол) months: [ "1-р сар", "2-р сар", "3-р сар", "4-р сар", "5-р сар", "6-р сар", "7-р сар", "8-р сар", "9-р сар", "10-р сар", "11-р сар", "12-р сар" ], dayOfWeek: [ "Дав", "Мяг", "Лха", "Пүр", "Бсн", "Бям", "Ням" ] }, 'pt-BR': { //Português(Brasil) months: [ "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro" ], dayOfWeek: [ "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb" ] }, sk: { //Slovenčina months: [ "Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December" ], dayOfWeek: [ "Ne", "Po", "Ut", "St", "Št", "Pi", "So" ] }, sq: { //Albanian (Shqip) months: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ], dayOfWeek: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ] }, 'sr-YU': { //Serbian (Srpski) months: [ "Januar", "Februar", "Mart", "April", "Maj", "Jun", "Jul", "Avgust", "Septembar", "Oktobar", "Novembar", "Decembar" ], dayOfWeek: [ "Ned", "Pon", "Uto", "Sre", "čet", "Pet", "Sub" ] }, sr: { //Serbian Cyrillic (Српски) months: [ "јануар", "фебруар", "март", "април", "мај", "јун", "јул", "август", "септембар", "октобар", "новембар", "децембар" ], dayOfWeek: [ "нед", "пон", "уто", "сре", "чет", "пет", "суб" ] }, sv: { //Svenska months: [ "Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December" ], dayOfWeek: [ "Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör" ] }, 'zh-TW': { //Traditional Chinese (繁體中文) months: [ "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月" ], dayOfWeek: [ "日", "一", "二", "三", "四", "五", "六" ] }, zh: { //Simplified Chinese (简体中文) months: [ "一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月" ], dayOfWeek: [ "日", "一", "二", "三", "四", "五", "六" ] }, he: { //Hebrew (עברית) months: [ 'ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר' ], dayOfWeek: [ 'א\'', 'ב\'', 'ג\'', 'ד\'', 'ה\'', 'ו\'', 'שבת' ] }, hy: { // Armenian months: [ "Հունվար", "Փետրվար", "Մարտ", "Ապրիլ", "Մայիս", "Հունիս", "Հուլիս", "Օգոստոս", "Սեպտեմբեր", "Հոկտեմբեր", "Նոյեմբեր", "Դեկտեմբեր" ], dayOfWeek: [ "Կի", "Երկ", "Երք", "Չոր", "Հնգ", "Ուրբ", "Շբթ" ] }, kg: { // Kyrgyz months: [ 'Үчтүн айы', 'Бирдин айы', 'Жалган Куран', 'Чын Куран', 'Бугу', 'Кулжа', 'Теке', 'Баш Оона', 'Аяк Оона', 'Тогуздун айы', 'Жетинин айы', 'Бештин айы' ], dayOfWeek: [ "Жек", "Дүй", "Шей", "Шар", "Бей", "Жум", "Ише" ] } }, value: '', lang: 'en', format: 'Y/m/d H:i', formatTime: 'H:i', formatDate: 'Y/m/d', startDate: false, // new Date(), '1986/12/08', '-1970/01/05','-1970/01/05', step: 60, monthChangeSpinner: true, closeOnDateSelect: false, closeOnTimeSelect: true, closeOnWithoutClick: true, closeOnInputClick: true, timepicker: true, datepicker: true, weeks: false, defaultTime: false, // use formatTime format (ex. '10:00' for formatTime: 'H:i') defaultDate: false, // use formatDate format (ex new Date() or '1986/12/08' or '-1970/01/05' or '-1970/01/05') minDate: false, maxDate: false, minTime: false, maxTime: false, disabledMinTime: false, disabledMaxTime: false, allowTimes: [], opened: false, initTime: true, inline: false, theme: '', onSelectDate: function () {}, onSelectTime: function () {}, onChangeMonth: function () {}, onChangeYear: function () {}, onChangeDateTime: function () {}, onShow: function () {}, onClose: function () {}, onGenerate: function () {}, withoutCopyright: true, inverseButton: false, hours12: false, next: 'xdsoft_next', prev : 'xdsoft_prev', dayOfWeekStart: 0, parentID: 'body', timeHeightInTimePicker: 25, timepickerScrollbar: true, todayButton: true, prevButton: true, nextButton: true, defaultSelect: true, scrollMonth: true, scrollTime: true, scrollInput: true, lazyInit: false, mask: false, validateOnBlur: true, allowBlank: true, yearStart: 1950, yearEnd: 2050, monthStart: 0, monthEnd: 11, style: '', id: '', fixed: false, roundTime: 'round', // ceil, floor className: '', weekends: [], highlightedDates: [], highlightedPeriods: [], disabledDates : [], disabledWeekDays: [], yearOffset: 0, beforeShowDay: null, enterLikeTab: true, showApplyButton: false }; // fix for ie8 if (!window.getComputedStyle) { window.getComputedStyle = function (el, pseudo) { this.el = el; this.getPropertyValue = function (prop) { var re = /(\-([a-z]){1})/g; if (prop === 'float') { prop = 'styleFloat'; } if (re.test(prop)) { prop = prop.replace(re, function (a, b, c) { return c.toUpperCase(); }); } return el.currentStyle[prop] || null; }; return this; }; } if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (obj, start) { var i, j; for (i = (start || 0), j = this.length; i < j; i += 1) { if (this[i] === obj) { return i; } } return -1; }; } Date.prototype.countDaysInMonth = function () { return new Date(this.getFullYear(), this.getMonth() + 1, 0).getDate(); }; $.fn.xdsoftScroller = function (percent) { return this.each(function () { var timeboxparent = $(this), pointerEventToXY = function (e) { var out = {x: 0, y: 0}, touch; if (e.type === 'touchstart' || e.type === 'touchmove' || e.type === 'touchend' || e.type === 'touchcancel') { touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0]; out.x = touch.clientX; out.y = touch.clientY; } else if (e.type === 'mousedown' || e.type === 'mouseup' || e.type === 'mousemove' || e.type === 'mouseover' || e.type === 'mouseout' || e.type === 'mouseenter' || e.type === 'mouseleave') { out.x = e.clientX; out.y = e.clientY; } return out; }, move = 0, timebox, parentHeight, height, scrollbar, scroller, maximumOffset = 100, start = false, startY = 0, startTop = 0, h1 = 0, touchStart = false, startTopScroll = 0, calcOffset = function () {}; if (percent === 'hide') { timeboxparent.find('.xdsoft_scrollbar').hide(); return; } if (!$(this).hasClass('xdsoft_scroller_box')) { timebox = timeboxparent.children().eq(0); parentHeight = timeboxparent[0].clientHeight; height = timebox[0].offsetHeight; scrollbar = $('
    '); scroller = $('
    '); scrollbar.append(scroller); timeboxparent.addClass('xdsoft_scroller_box').append(scrollbar); calcOffset = function calcOffset(event) { var offset = pointerEventToXY(event).y - startY + startTopScroll; if (offset < 0) { offset = 0; } if (offset + scroller[0].offsetHeight > h1) { offset = h1 - scroller[0].offsetHeight; } timeboxparent.trigger('scroll_element.xdsoft_scroller', [maximumOffset ? offset / maximumOffset : 0]); }; scroller .on('touchstart.xdsoft_scroller mousedown.xdsoft_scroller', function (event) { if (!parentHeight) { timeboxparent.trigger('resize_scroll.xdsoft_scroller', [percent]); } startY = pointerEventToXY(event).y; startTopScroll = parseInt(scroller.css('margin-top'), 10); h1 = scrollbar[0].offsetHeight; if (event.type === 'mousedown') { if (document) { $(document.body).addClass('xdsoft_noselect'); } $([document.body, window]).on('mouseup.xdsoft_scroller', function arguments_callee() { $([document.body, window]).off('mouseup.xdsoft_scroller', arguments_callee) .off('mousemove.xdsoft_scroller', calcOffset) .removeClass('xdsoft_noselect'); }); $(document.body).on('mousemove.xdsoft_scroller', calcOffset); } else { touchStart = true; event.stopPropagation(); event.preventDefault(); } }) .on('touchmove', function (event) { if (touchStart) { event.preventDefault(); calcOffset(event); } }) .on('touchend touchcancel', function (event) { touchStart = false; startTopScroll = 0; }); timeboxparent .on('scroll_element.xdsoft_scroller', function (event, percentage) { if (!parentHeight) { timeboxparent.trigger('resize_scroll.xdsoft_scroller', [percentage, true]); } percentage = percentage > 1 ? 1 : (percentage < 0 || isNaN(percentage)) ? 0 : percentage; scroller.css('margin-top', maximumOffset * percentage); setTimeout(function () { timebox.css('marginTop', -parseInt((timebox[0].offsetHeight - parentHeight) * percentage, 10)); }, 10); }) .on('resize_scroll.xdsoft_scroller', function (event, percentage, noTriggerScroll) { var percent, sh; parentHeight = timeboxparent[0].clientHeight; height = timebox[0].offsetHeight; percent = parentHeight / height; sh = percent * scrollbar[0].offsetHeight; if (percent > 1) { scroller.hide(); } else { scroller.show(); scroller.css('height', parseInt(sh > 10 ? sh : 10, 10)); maximumOffset = scrollbar[0].offsetHeight - scroller[0].offsetHeight; if (noTriggerScroll !== true) { timeboxparent.trigger('scroll_element.xdsoft_scroller', [percentage || Math.abs(parseInt(timebox.css('marginTop'), 10)) / (height - parentHeight)]); } } }); timeboxparent.on('mousewheel', function (event) { var top = Math.abs(parseInt(timebox.css('marginTop'), 10)); top = top - (event.deltaY * 20); if (top < 0) { top = 0; } timeboxparent.trigger('scroll_element.xdsoft_scroller', [top / (height - parentHeight)]); event.stopPropagation(); return false; }); timeboxparent.on('touchstart', function (event) { start = pointerEventToXY(event); startTop = Math.abs(parseInt(timebox.css('marginTop'), 10)); }); timeboxparent.on('touchmove', function (event) { if (start) { event.preventDefault(); var coord = pointerEventToXY(event); timeboxparent.trigger('scroll_element.xdsoft_scroller', [(startTop - (coord.y - start.y)) / (height - parentHeight)]); } }); timeboxparent.on('touchend touchcancel', function (event) { start = false; startTop = 0; }); } timeboxparent.trigger('resize_scroll.xdsoft_scroller', [percent]); }); }; $.fn.datetimepicker = function (opt) { var KEY0 = 48, KEY9 = 57, _KEY0 = 96, _KEY9 = 105, CTRLKEY = 17, DEL = 46, ENTER = 13, ESC = 27, BACKSPACE = 8, ARROWLEFT = 37, ARROWUP = 38, ARROWRIGHT = 39, ARROWDOWN = 40, TAB = 9, F5 = 116, AKEY = 65, CKEY = 67, VKEY = 86, ZKEY = 90, YKEY = 89, ctrlDown = false, options = ($.isPlainObject(opt) || !opt) ? $.extend(true, {}, default_options, opt) : $.extend(true, {}, default_options), lazyInitTimer = 0, createDateTimePicker, destroyDateTimePicker, lazyInit = function (input) { input .on('open.xdsoft focusin.xdsoft mousedown.xdsoft', function initOnActionCallback(event) { if (input.is(':disabled') || input.data('xdsoft_datetimepicker')) { return; } clearTimeout(lazyInitTimer); lazyInitTimer = setTimeout(function () { if (!input.data('xdsoft_datetimepicker')) { createDateTimePicker(input); } input .off('open.xdsoft focusin.xdsoft mousedown.xdsoft', initOnActionCallback) .trigger('open.xdsoft'); }, 100); }); }; createDateTimePicker = function (input) { var datetimepicker = $('
    '), xdsoft_copyright = $(''), datepicker = $('
    '), mounth_picker = $('
    ' + '
    ' + '
    ' + '
    '), calendar = $('
    '), timepicker = $('
    '), timeboxparent = timepicker.find('.xdsoft_time_box').eq(0), timebox = $('
    '), applyButton = $(''), /*scrollbar = $('
    '), scroller = $('
    '),*/ monthselect = $('
    '), yearselect = $('
    '), triggerAfterOpen = false, XDSoft_datetime, //scroll_element, xchangeTimer, timerclick, current_time_index, setPos, timer = 0, timer1 = 0, _xdsoft_datetime; if (options.id) { datetimepicker.attr('id', options.id); } if (options.style) { datetimepicker.attr('style', options.style); } if (options.weeks) { datetimepicker.addClass('xdsoft_showweeks'); } datetimepicker.addClass('xdsoft_' + options.theme); datetimepicker.addClass(options.className); mounth_picker .find('.xdsoft_month span') .after(monthselect); mounth_picker .find('.xdsoft_year span') .after(yearselect); mounth_picker .find('.xdsoft_month,.xdsoft_year') .on('mousedown.xdsoft', function (event) { var select = $(this).find('.xdsoft_select').eq(0), val = 0, top = 0, visible = select.is(':visible'), items, i; mounth_picker .find('.xdsoft_select') .hide(); if (_xdsoft_datetime.currentTime) { val = _xdsoft_datetime.currentTime[$(this).hasClass('xdsoft_month') ? 'getMonth' : 'getFullYear'](); } select[visible ? 'hide' : 'show'](); for (items = select.find('div.xdsoft_option'), i = 0; i < items.length; i += 1) { if (items.eq(i).data('value') === val) { break; } else { top += items[0].offsetHeight; } } select.xdsoftScroller(top / (select.children()[0].offsetHeight - (select[0].clientHeight))); event.stopPropagation(); return false; }); mounth_picker .find('.xdsoft_select') .xdsoftScroller() .on('mousedown.xdsoft', function (event) { event.stopPropagation(); event.preventDefault(); }) .on('mousedown.xdsoft', '.xdsoft_option', function (event) { if (_xdsoft_datetime.currentTime === undefined || _xdsoft_datetime.currentTime === null) { _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); } var year = _xdsoft_datetime.currentTime.getFullYear(); if (_xdsoft_datetime && _xdsoft_datetime.currentTime) { _xdsoft_datetime.currentTime[$(this).parent().parent().hasClass('xdsoft_monthselect') ? 'setMonth' : 'setFullYear']($(this).data('value')); } $(this).parent().parent().hide(); datetimepicker.trigger('xchange.xdsoft'); if (options.onChangeMonth && $.isFunction(options.onChangeMonth)) { options.onChangeMonth.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); } if (year !== _xdsoft_datetime.currentTime.getFullYear() && $.isFunction(options.onChangeYear)) { options.onChangeYear.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); } }); datetimepicker.setOptions = function (_options) { var highlightedDates = {}, getCaretPos = function (input) { try { if (document.selection && document.selection.createRange) { var range = document.selection.createRange(); return range.getBookmark().charCodeAt(2) - 2; } if (input.setSelectionRange) { return input.selectionStart; } } catch (e) { return 0; } }, setCaretPos = function (node, pos) { node = (typeof node === "string" || node instanceof String) ? document.getElementById(node) : node; if (!node) { return false; } if (node.createTextRange) { var textRange = node.createTextRange(); textRange.collapse(true); textRange.moveEnd('character', pos); textRange.moveStart('character', pos); textRange.select(); return true; } if (node.setSelectionRange) { node.setSelectionRange(pos, pos); return true; } return false; }, isValidValue = function (mask, value) { var reg = mask .replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g, '\\$1') .replace(/_/g, '{digit+}') .replace(/([0-9]{1})/g, '{digit$1}') .replace(/\{digit([0-9]{1})\}/g, '[0-$1_]{1}') .replace(/\{digit[\+]\}/g, '[0-9_]{1}'); return (new RegExp(reg)).test(value); }; options = $.extend(true, {}, options, _options); if (_options.allowTimes && $.isArray(_options.allowTimes) && _options.allowTimes.length) { options.allowTimes = $.extend(true, [], _options.allowTimes); } if (_options.weekends && $.isArray(_options.weekends) && _options.weekends.length) { options.weekends = $.extend(true, [], _options.weekends); } if (_options.highlightedDates && $.isArray(_options.highlightedDates) && _options.highlightedDates.length) { $.each(_options.highlightedDates, function (index, value) { var splitData = $.map(value.split(','), $.trim), exDesc, hDate = new HighlightedDate(Date.parseDate(splitData[0], options.formatDate), splitData[1], splitData[2]), // date, desc, style keyDate = hDate.date.dateFormat(options.formatDate); if (highlightedDates[keyDate] !== undefined) { exDesc = highlightedDates[keyDate].desc; if (exDesc && exDesc.length && hDate.desc && hDate.desc.length) { highlightedDates[keyDate].desc = exDesc + "\n" + hDate.desc; } } else { highlightedDates[keyDate] = hDate; } }); options.highlightedDates = $.extend(true, [], highlightedDates); } if (_options.highlightedPeriods && $.isArray(_options.highlightedPeriods) && _options.highlightedPeriods.length) { highlightedDates = $.extend(true, [], options.highlightedDates); $.each(_options.highlightedPeriods, function (index, value) { var splitData = $.map(value.split(','), $.trim), dateTest = Date.parseDate(splitData[0], options.formatDate), // start date dateEnd = Date.parseDate(splitData[1], options.formatDate), desc = splitData[2], hDate, keyDate, exDesc, style = splitData[3]; while (dateTest <= dateEnd) { hDate = new HighlightedDate(dateTest, desc, style); keyDate = dateTest.dateFormat(options.formatDate); dateTest.setDate(dateTest.getDate() + 1); if (highlightedDates[keyDate] !== undefined) { exDesc = highlightedDates[keyDate].desc; if (exDesc && exDesc.length && hDate.desc && hDate.desc.length) { highlightedDates[keyDate].desc = exDesc + "\n" + hDate.desc; } } else { highlightedDates[keyDate] = hDate; } } }); options.highlightedDates = $.extend(true, [], highlightedDates); } if (_options.disabledDates && $.isArray(_options.disabledDates) && _options.disabledDates.length) { options.disabledDates = $.extend(true, [], _options.disabledDates); } if (_options.disabledWeekDays && $.isArray(_options.disabledWeekDays) && _options.disabledWeekDays.length) { options.disabledWeekDays = $.extend(true, [], _options.disabledWeekDays); } if ((options.open || options.opened) && (!options.inline)) { input.trigger('open.xdsoft'); } if (options.inline) { triggerAfterOpen = true; datetimepicker.addClass('xdsoft_inline'); input.after(datetimepicker).hide(); } if (options.inverseButton) { options.next = 'xdsoft_prev'; options.prev = 'xdsoft_next'; } if (options.datepicker) { datepicker.addClass('active'); } else { datepicker.removeClass('active'); } if (options.timepicker) { timepicker.addClass('active'); } else { timepicker.removeClass('active'); } if (options.value) { _xdsoft_datetime.setCurrentTime(options.value); if (input && input.val) { input.val(_xdsoft_datetime.str); } } if (isNaN(options.dayOfWeekStart)) { options.dayOfWeekStart = 0; } else { options.dayOfWeekStart = parseInt(options.dayOfWeekStart, 10) % 7; } if (!options.timepickerScrollbar) { timeboxparent.xdsoftScroller('hide'); } if (options.minDate && /^-(.*)$/.test(options.minDate)) { options.minDate = _xdsoft_datetime.strToDateTime(options.minDate).dateFormat(options.formatDate); } if (options.maxDate && /^\+(.*)$/.test(options.maxDate)) { options.maxDate = _xdsoft_datetime.strToDateTime(options.maxDate).dateFormat(options.formatDate); } applyButton.toggle(options.showApplyButton); mounth_picker .find('.xdsoft_today_button') .css('visibility', !options.todayButton ? 'hidden' : 'visible'); mounth_picker .find('.' + options.prev) .css('visibility', !options.prevButton ? 'hidden' : 'visible'); mounth_picker .find('.' + options.next) .css('visibility', !options.nextButton ? 'hidden' : 'visible'); if (options.mask) { input.off('keydown.xdsoft'); if (options.mask === true) { options.mask = options.format .replace(/Y/g, '9999') .replace(/F/g, '9999') .replace(/m/g, '19') .replace(/d/g, '39') .replace(/H/g, '29') .replace(/i/g, '59') .replace(/s/g, '59'); } if ($.type(options.mask) === 'string') { if (!isValidValue(options.mask, input.val())) { input.val(options.mask.replace(/[0-9]/g, '_')); } input.on('keydown.xdsoft', function (event) { var val = this.value, key = event.which, pos, digit; if (((key >= KEY0 && key <= KEY9) || (key >= _KEY0 && key <= _KEY9)) || (key === BACKSPACE || key === DEL)) { pos = getCaretPos(this); digit = (key !== BACKSPACE && key !== DEL) ? String.fromCharCode((_KEY0 <= key && key <= _KEY9) ? key - KEY0 : key) : '_'; if ((key === BACKSPACE || key === DEL) && pos) { pos -= 1; digit = '_'; } while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) { pos += (key === BACKSPACE || key === DEL) ? -1 : 1; } val = val.substr(0, pos) + digit + val.substr(pos + 1); if ($.trim(val) === '') { val = options.mask.replace(/[0-9]/g, '_'); } else { if (pos === options.mask.length) { event.preventDefault(); return false; } } pos += (key === BACKSPACE || key === DEL) ? 0 : 1; while (/[^0-9_]/.test(options.mask.substr(pos, 1)) && pos < options.mask.length && pos > 0) { pos += (key === BACKSPACE || key === DEL) ? -1 : 1; } if (isValidValue(options.mask, val)) { this.value = val; setCaretPos(this, pos); } else if ($.trim(val) === '') { this.value = options.mask.replace(/[0-9]/g, '_'); } else { input.trigger('error_input.xdsoft'); } } else { if (([AKEY, CKEY, VKEY, ZKEY, YKEY].indexOf(key) !== -1 && ctrlDown) || [ESC, ARROWUP, ARROWDOWN, ARROWLEFT, ARROWRIGHT, F5, CTRLKEY, TAB, ENTER].indexOf(key) !== -1) { return true; } } event.preventDefault(); return false; }); } } if (options.validateOnBlur) { input .off('blur.xdsoft') .on('blur.xdsoft', function () { if (options.allowBlank && !$.trim($(this).val()).length) { $(this).val(null); datetimepicker.data('xdsoft_datetime').empty(); } else if (!Date.parseDate($(this).val(), options.format)) { var splittedHours = +([$(this).val()[0], $(this).val()[1]].join('')), splittedMinutes = +([$(this).val()[2], $(this).val()[3]].join('')); // parse the numbers as 0312 => 03:12 if (!options.datepicker && options.timepicker && splittedHours >= 0 && splittedHours < 24 && splittedMinutes >= 0 && splittedMinutes < 60) { $(this).val([splittedHours, splittedMinutes].map(function (item) { return item > 9 ? item : '0' + item; }).join(':')); } else { $(this).val((_xdsoft_datetime.now()).dateFormat(options.format)); } datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val()); } else { datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val()); } datetimepicker.trigger('changedatetime.xdsoft'); }); } options.dayOfWeekStartPrev = (options.dayOfWeekStart === 0) ? 6 : options.dayOfWeekStart - 1; datetimepicker .trigger('xchange.xdsoft') .trigger('afterOpen.xdsoft'); }; datetimepicker .data('options', options) .on('mousedown.xdsoft', function (event) { event.stopPropagation(); event.preventDefault(); yearselect.hide(); monthselect.hide(); return false; }); //scroll_element = timepicker.find('.xdsoft_time_box'); timeboxparent.append(timebox); timeboxparent.xdsoftScroller(); datetimepicker.on('afterOpen.xdsoft', function () { timeboxparent.xdsoftScroller(); }); datetimepicker .append(datepicker) .append(timepicker); if (options.withoutCopyright !== true) { datetimepicker .append(xdsoft_copyright); } datepicker .append(mounth_picker) .append(calendar) .append(applyButton); $(options.parentID) .append(datetimepicker); XDSoft_datetime = function () { var _this = this; _this.now = function (norecursion) { var d = new Date(), date, time; if (!norecursion && options.defaultDate) { date = _this.strToDateTime(options.defaultDate); d.setFullYear(date.getFullYear()); d.setMonth(date.getMonth()); d.setDate(date.getDate()); } if (options.yearOffset) { d.setFullYear(d.getFullYear() + options.yearOffset); } if (!norecursion && options.defaultTime) { time = _this.strtotime(options.defaultTime); d.setHours(time.getHours()); d.setMinutes(time.getMinutes()); } return d; }; _this.isValidDate = function (d) { if (Object.prototype.toString.call(d) !== "[object Date]") { return false; } return !isNaN(d.getTime()); }; _this.setCurrentTime = function (dTime) { _this.currentTime = (typeof dTime === 'string') ? _this.strToDateTime(dTime) : _this.isValidDate(dTime) ? dTime : _this.now(); datetimepicker.trigger('xchange.xdsoft'); }; _this.empty = function () { _this.currentTime = null; }; _this.getCurrentTime = function (dTime) { return _this.currentTime; }; _this.nextMonth = function () { if (_this.currentTime === undefined || _this.currentTime === null) { _this.currentTime = _this.now(); } var month = _this.currentTime.getMonth() + 1, year; if (month === 12) { _this.currentTime.setFullYear(_this.currentTime.getFullYear() + 1); month = 0; } year = _this.currentTime.getFullYear(); _this.currentTime.setDate( Math.min( new Date(_this.currentTime.getFullYear(), month + 1, 0).getDate(), _this.currentTime.getDate() ) ); _this.currentTime.setMonth(month); if (options.onChangeMonth && $.isFunction(options.onChangeMonth)) { options.onChangeMonth.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); } if (year !== _this.currentTime.getFullYear() && $.isFunction(options.onChangeYear)) { options.onChangeYear.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); } datetimepicker.trigger('xchange.xdsoft'); return month; }; _this.prevMonth = function () { if (_this.currentTime === undefined || _this.currentTime === null) { _this.currentTime = _this.now(); } var month = _this.currentTime.getMonth() - 1; if (month === -1) { _this.currentTime.setFullYear(_this.currentTime.getFullYear() - 1); month = 11; } _this.currentTime.setDate( Math.min( new Date(_this.currentTime.getFullYear(), month + 1, 0).getDate(), _this.currentTime.getDate() ) ); _this.currentTime.setMonth(month); if (options.onChangeMonth && $.isFunction(options.onChangeMonth)) { options.onChangeMonth.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); } datetimepicker.trigger('xchange.xdsoft'); return month; }; _this.getWeekOfYear = function (datetime) { var onejan = new Date(datetime.getFullYear(), 0, 1); return Math.ceil((((datetime - onejan) / 86400000) + onejan.getDay() + 1) / 7); }; _this.strToDateTime = function (sDateTime) { var tmpDate = [], timeOffset, currentTime; if (sDateTime && sDateTime instanceof Date && _this.isValidDate(sDateTime)) { return sDateTime; } tmpDate = /^(\+|\-)(.*)$/.exec(sDateTime); if (tmpDate) { tmpDate[2] = Date.parseDate(tmpDate[2], options.formatDate); } if (tmpDate && tmpDate[2]) { timeOffset = tmpDate[2].getTime() - (tmpDate[2].getTimezoneOffset()) * 60000; currentTime = new Date((_this.now(true)).getTime() + parseInt(tmpDate[1] + '1', 10) * timeOffset); } else { currentTime = sDateTime ? Date.parseDate(sDateTime, options.format) : _this.now(); } if (!_this.isValidDate(currentTime)) { currentTime = _this.now(); } return currentTime; }; _this.strToDate = function (sDate) { if (sDate && sDate instanceof Date && _this.isValidDate(sDate)) { return sDate; } var currentTime = sDate ? Date.parseDate(sDate, options.formatDate) : _this.now(true); if (!_this.isValidDate(currentTime)) { currentTime = _this.now(true); } return currentTime; }; _this.strtotime = function (sTime) { if (sTime && sTime instanceof Date && _this.isValidDate(sTime)) { return sTime; } var currentTime = sTime ? Date.parseDate(sTime, options.formatTime) : _this.now(true); if (!_this.isValidDate(currentTime)) { currentTime = _this.now(true); } return currentTime; }; _this.str = function () { return _this.currentTime.dateFormat(options.format); }; _this.currentTime = this.now(); }; _xdsoft_datetime = new XDSoft_datetime(); applyButton.on('click', function (e) {//pathbrite e.preventDefault(); datetimepicker.data('changed', true); _xdsoft_datetime.setCurrentTime(getCurrentValue()); input.val(_xdsoft_datetime.str()); datetimepicker.trigger('close.xdsoft'); }); mounth_picker .find('.xdsoft_today_button') .on('mousedown.xdsoft', function () { datetimepicker.data('changed', true); _xdsoft_datetime.setCurrentTime(0); datetimepicker.trigger('afterOpen.xdsoft'); }).on('dblclick.xdsoft', function () { var currentDate = _xdsoft_datetime.getCurrentTime(), minDate, maxDate; currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()); minDate = _xdsoft_datetime.strToDate(options.minDate); minDate = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()); if (currentDate < minDate) { return; } maxDate = _xdsoft_datetime.strToDate(options.maxDate); maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()); if (currentDate > maxDate) { return; } input.val(_xdsoft_datetime.str()); datetimepicker.trigger('close.xdsoft'); }); mounth_picker .find('.xdsoft_prev,.xdsoft_next') .on('mousedown.xdsoft', function () { var $this = $(this), timer = 0, stop = false; (function arguments_callee1(v) { if ($this.hasClass(options.next)) { _xdsoft_datetime.nextMonth(); } else if ($this.hasClass(options.prev)) { _xdsoft_datetime.prevMonth(); } if (options.monthChangeSpinner) { if (!stop) { timer = setTimeout(arguments_callee1, v || 100); } } }(500)); $([document.body, window]).on('mouseup.xdsoft', function arguments_callee2() { clearTimeout(timer); stop = true; $([document.body, window]).off('mouseup.xdsoft', arguments_callee2); }); }); timepicker .find('.xdsoft_prev,.xdsoft_next') .on('mousedown.xdsoft', function () { var $this = $(this), timer = 0, stop = false, period = 110; (function arguments_callee4(v) { var pheight = timeboxparent[0].clientHeight, height = timebox[0].offsetHeight, top = Math.abs(parseInt(timebox.css('marginTop'), 10)); if ($this.hasClass(options.next) && (height - pheight) - options.timeHeightInTimePicker >= top) { timebox.css('marginTop', '-' + (top + options.timeHeightInTimePicker) + 'px'); } else if ($this.hasClass(options.prev) && top - options.timeHeightInTimePicker >= 0) { timebox.css('marginTop', '-' + (top - options.timeHeightInTimePicker) + 'px'); } timeboxparent.trigger('scroll_element.xdsoft_scroller', [Math.abs(parseInt(timebox.css('marginTop'), 10) / (height - pheight))]); period = (period > 10) ? 10 : period - 10; if (!stop) { timer = setTimeout(arguments_callee4, v || period); } }(500)); $([document.body, window]).on('mouseup.xdsoft', function arguments_callee5() { clearTimeout(timer); stop = true; $([document.body, window]) .off('mouseup.xdsoft', arguments_callee5); }); }); xchangeTimer = 0; // base handler - generating a calendar and timepicker datetimepicker .on('xchange.xdsoft', function (event) { clearTimeout(xchangeTimer); xchangeTimer = setTimeout(function () { if (_xdsoft_datetime.currentTime === undefined || _xdsoft_datetime.currentTime === null) { _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); } var table = '', start = new Date(_xdsoft_datetime.currentTime.getFullYear(), _xdsoft_datetime.currentTime.getMonth(), 1, 12, 0, 0), i = 0, j, today = _xdsoft_datetime.now(), maxDate = false, minDate = false, hDate, day, d, y, m, w, classes = [], customDateSettings, newRow = true, time = '', h = '', line_time, description; while (start.getDay() !== options.dayOfWeekStart) { start.setDate(start.getDate() - 1); } table += ''; if (options.weeks) { table += ''; } for (j = 0; j < 7; j += 1) { table += ''; } table += ''; table += ''; if (options.maxDate !== false) { maxDate = _xdsoft_datetime.strToDate(options.maxDate); maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate(), 23, 59, 59, 999); } if (options.minDate !== false) { minDate = _xdsoft_datetime.strToDate(options.minDate); minDate = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()); } while (i < _xdsoft_datetime.currentTime.countDaysInMonth() || start.getDay() !== options.dayOfWeekStart || _xdsoft_datetime.currentTime.getMonth() === start.getMonth()) { classes = []; i += 1; day = start.getDay(); d = start.getDate(); y = start.getFullYear(); m = start.getMonth(); w = _xdsoft_datetime.getWeekOfYear(start); description = ''; classes.push('xdsoft_date'); if (options.beforeShowDay && $.isFunction(options.beforeShowDay.call)) { customDateSettings = options.beforeShowDay.call(datetimepicker, start); } else { customDateSettings = null; } if ((maxDate !== false && start > maxDate) || (minDate !== false && start < minDate) || (customDateSettings && customDateSettings[0] === false)) { classes.push('xdsoft_disabled'); } else if (options.disabledDates.indexOf(start.dateFormat(options.formatDate)) !== -1) { classes.push('xdsoft_disabled'); } else if (options.disabledWeekDays.indexOf(day) !== -1) { classes.push('xdsoft_disabled'); } if (customDateSettings && customDateSettings[1] !== "") { classes.push(customDateSettings[1]); } if (_xdsoft_datetime.currentTime.getMonth() !== m) { classes.push('xdsoft_other_month'); } if ((options.defaultSelect || datetimepicker.data('changed')) && _xdsoft_datetime.currentTime.dateFormat(options.formatDate) === start.dateFormat(options.formatDate)) { classes.push('xdsoft_current'); } if (today.dateFormat(options.formatDate) === start.dateFormat(options.formatDate)) { classes.push('xdsoft_today'); } if (start.getDay() === 0 || start.getDay() === 6 || options.weekends.indexOf(start.dateFormat(options.formatDate)) !== -1) { classes.push('xdsoft_weekend'); } if (options.highlightedDates[start.dateFormat(options.formatDate)] !== undefined) { hDate = options.highlightedDates[start.dateFormat(options.formatDate)]; classes.push(hDate.style === undefined ? 'xdsoft_highlighted_default' : hDate.style); description = hDate.desc === undefined ? '' : hDate.desc; } if (options.beforeShowDay && $.isFunction(options.beforeShowDay)) { classes.push(options.beforeShowDay(start)); } if (newRow) { table += ''; newRow = false; if (options.weeks) { table += ''; } } table += ''; if (start.getDay() === options.dayOfWeekStartPrev) { table += ''; newRow = true; } start.setDate(d + 1); } table += '
    ' + options.i18n[options.lang].dayOfWeek[(j + options.dayOfWeekStart) % 7] + '
    ' + w + '' + '
    ' + d + '
    ' + '
    '; calendar.html(table); mounth_picker.find('.xdsoft_label span').eq(0).text(options.i18n[options.lang].months[_xdsoft_datetime.currentTime.getMonth()]); mounth_picker.find('.xdsoft_label span').eq(1).text(_xdsoft_datetime.currentTime.getFullYear()); // generate timebox time = ''; h = ''; m = ''; line_time = function line_time(h, m) { var now = _xdsoft_datetime.now(), optionDateTime, current_time; now.setHours(h); h = parseInt(now.getHours(), 10); now.setMinutes(m); m = parseInt(now.getMinutes(), 10); optionDateTime = new Date(_xdsoft_datetime.currentTime); optionDateTime.setHours(h); optionDateTime.setMinutes(m); classes = []; if ((options.minDateTime !== false && options.minDateTime > optionDateTime) || (options.maxTime !== false && _xdsoft_datetime.strtotime(options.maxTime).getTime() < now.getTime()) || (options.minTime !== false && _xdsoft_datetime.strtotime(options.minTime).getTime() > now.getTime())) { classes.push('xdsoft_disabled'); } if ((options.minDateTime !== false && options.minDateTime > optionDateTime) || ((options.disabledMinTime !== false && now.getTime() > _xdsoft_datetime.strtotime(options.disabledMinTime).getTime()) && (options.disabledMaxTime !== false && now.getTime() < _xdsoft_datetime.strtotime(options.disabledMaxTime).getTime()))) { classes.push('xdsoft_disabled'); } current_time = new Date(_xdsoft_datetime.currentTime); current_time.setHours(parseInt(_xdsoft_datetime.currentTime.getHours(), 10)); current_time.setMinutes(Math[options.roundTime](_xdsoft_datetime.currentTime.getMinutes() / options.step) * options.step); if ((options.initTime || options.defaultSelect || datetimepicker.data('changed')) && current_time.getHours() === parseInt(h, 10) && (options.step > 59 || current_time.getMinutes() === parseInt(m, 10))) { if (options.defaultSelect || datetimepicker.data('changed')) { classes.push('xdsoft_current'); } else if (options.initTime) { classes.push('xdsoft_init_time'); } } if (parseInt(today.getHours(), 10) === parseInt(h, 10) && parseInt(today.getMinutes(), 10) === parseInt(m, 10)) { classes.push('xdsoft_today'); } time += '
    ' + now.dateFormat(options.formatTime) + '
    '; }; if (!options.allowTimes || !$.isArray(options.allowTimes) || !options.allowTimes.length) { for (i = 0, j = 0; i < (options.hours12 ? 12 : 24); i += 1) { for (j = 0; j < 60; j += options.step) { h = (i < 10 ? '0' : '') + i; m = (j < 10 ? '0' : '') + j; line_time(h, m); } } } else { for (i = 0; i < options.allowTimes.length; i += 1) { h = _xdsoft_datetime.strtotime(options.allowTimes[i]).getHours(); m = _xdsoft_datetime.strtotime(options.allowTimes[i]).getMinutes(); line_time(h, m); } } timebox.html(time); opt = ''; i = 0; for (i = parseInt(options.yearStart, 10) + options.yearOffset; i <= parseInt(options.yearEnd, 10) + options.yearOffset; i += 1) { opt += '
    ' + i + '
    '; } yearselect.children().eq(0) .html(opt); for (i = parseInt(options.monthStart, 10), opt = ''; i <= parseInt(options.monthEnd, 10); i += 1) { opt += '
    ' + options.i18n[options.lang].months[i] + '
    '; } monthselect.children().eq(0).html(opt); $(datetimepicker) .trigger('generate.xdsoft'); }, 10); event.stopPropagation(); }) .on('afterOpen.xdsoft', function () { if (options.timepicker) { var classType, pheight, height, top; if (timebox.find('.xdsoft_current').length) { classType = '.xdsoft_current'; } else if (timebox.find('.xdsoft_init_time').length) { classType = '.xdsoft_init_time'; } if (classType) { pheight = timeboxparent[0].clientHeight; height = timebox[0].offsetHeight; top = timebox.find(classType).index() * options.timeHeightInTimePicker + 1; if ((height - pheight) < top) { top = height - pheight; } timeboxparent.trigger('scroll_element.xdsoft_scroller', [parseInt(top, 10) / (height - pheight)]); } else { timeboxparent.trigger('scroll_element.xdsoft_scroller', [0]); } } }); timerclick = 0; calendar .on('click.xdsoft', 'td', function (xdevent) { xdevent.stopPropagation(); // Prevents closing of Pop-ups, Modals and Flyouts in Bootstrap timerclick += 1; var $this = $(this), currentTime = _xdsoft_datetime.currentTime; if (currentTime === undefined || currentTime === null) { _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); currentTime = _xdsoft_datetime.currentTime; } if ($this.hasClass('xdsoft_disabled')) { return false; } currentTime.setDate(1); currentTime.setFullYear($this.data('year')); currentTime.setMonth($this.data('month')); currentTime.setDate($this.data('date')); datetimepicker.trigger('select.xdsoft', [currentTime]); input.val(_xdsoft_datetime.str()); if ((timerclick > 1 || (options.closeOnDateSelect === true || (options.closeOnDateSelect === false && !options.timepicker))) && !options.inline) { datetimepicker.trigger('close.xdsoft'); } if (options.onSelectDate && $.isFunction(options.onSelectDate)) { options.onSelectDate.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), xdevent); } datetimepicker.data('changed', true); datetimepicker.trigger('xchange.xdsoft'); datetimepicker.trigger('changedatetime.xdsoft'); setTimeout(function () { timerclick = 0; }, 200); }); timebox .on('click.xdsoft', 'div', function (xdevent) { xdevent.stopPropagation(); var $this = $(this), currentTime = _xdsoft_datetime.currentTime; if (currentTime === undefined || currentTime === null) { _xdsoft_datetime.currentTime = _xdsoft_datetime.now(); currentTime = _xdsoft_datetime.currentTime; } if ($this.hasClass('xdsoft_disabled')) { return false; } currentTime.setHours($this.data('hour')); currentTime.setMinutes($this.data('minute')); datetimepicker.trigger('select.xdsoft', [currentTime]); datetimepicker.data('input').val(_xdsoft_datetime.str()); if (options.inline !== true && options.closeOnTimeSelect === true) { datetimepicker.trigger('close.xdsoft'); } if (options.onSelectTime && $.isFunction(options.onSelectTime)) { options.onSelectTime.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), xdevent); } datetimepicker.data('changed', true); datetimepicker.trigger('xchange.xdsoft'); datetimepicker.trigger('changedatetime.xdsoft'); }); datepicker .on('mousewheel.xdsoft', function (event) { if (!options.scrollMonth) { return true; } if (event.deltaY < 0) { _xdsoft_datetime.nextMonth(); } else { _xdsoft_datetime.prevMonth(); } return false; }); input .on('mousewheel.xdsoft', function (event) { if (!options.scrollInput) { return true; } if (!options.datepicker && options.timepicker) { current_time_index = timebox.find('.xdsoft_current').length ? timebox.find('.xdsoft_current').eq(0).index() : 0; if (current_time_index + event.deltaY >= 0 && current_time_index + event.deltaY < timebox.children().length) { current_time_index += event.deltaY; } if (timebox.children().eq(current_time_index).length) { timebox.children().eq(current_time_index).trigger('mousedown'); } return false; } if (options.datepicker && !options.timepicker) { datepicker.trigger(event, [event.deltaY, event.deltaX, event.deltaY]); if (input.val) { input.val(_xdsoft_datetime.str()); } datetimepicker.trigger('changedatetime.xdsoft'); return false; } }); datetimepicker .on('changedatetime.xdsoft', function (event) { if (options.onChangeDateTime && $.isFunction(options.onChangeDateTime)) { var $input = datetimepicker.data('input'); options.onChangeDateTime.call(datetimepicker, _xdsoft_datetime.currentTime, $input, event); delete options.value; $input.trigger('change'); } }) .on('generate.xdsoft', function () { if (options.onGenerate && $.isFunction(options.onGenerate)) { options.onGenerate.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input')); } if (triggerAfterOpen) { datetimepicker.trigger('afterOpen.xdsoft'); triggerAfterOpen = false; } }) .on('click.xdsoft', function (xdevent) { xdevent.stopPropagation(); }); current_time_index = 0; setPos = function () { var offset = datetimepicker.data('input').offset(), top = offset.top + datetimepicker.data('input')[0].offsetHeight - 1, left = offset.left, position = "absolute", node; if (options.fixed) { top -= $(window).scrollTop(); left -= $(window).scrollLeft(); position = "fixed"; } else { if (top + datetimepicker[0].offsetHeight > $(window).height() + $(window).scrollTop()) { top = offset.top - datetimepicker[0].offsetHeight + 1; } if (top < 0) { top = 0; } if (left + datetimepicker[0].offsetWidth > $(window).width()) { left = $(window).width() - datetimepicker[0].offsetWidth; } } node = datetimepicker[0]; do { node = node.parentNode; if (window.getComputedStyle(node).getPropertyValue('position') === 'relative' && $(window).width() >= node.offsetWidth) { left = left - (($(window).width() - node.offsetWidth) / 2); break; } } while (node.nodeName !== 'HTML'); datetimepicker.css({ left: left, top: top, position: position }); }; datetimepicker .on('open.xdsoft', function (event) { var onShow = true; if (options.onShow && $.isFunction(options.onShow)) { onShow = options.onShow.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), event); } if (onShow !== false) { datetimepicker.show(); setPos(); $(window) .off('resize.xdsoft', setPos) .on('resize.xdsoft', setPos); if (options.closeOnWithoutClick) { $([document.body, window]).on('mousedown.xdsoft', function arguments_callee6() { datetimepicker.trigger('close.xdsoft'); $([document.body, window]).off('mousedown.xdsoft', arguments_callee6); }); } } }) .on('close.xdsoft', function (event) { var onClose = true; mounth_picker .find('.xdsoft_month,.xdsoft_year') .find('.xdsoft_select') .hide(); if (options.onClose && $.isFunction(options.onClose)) { onClose = options.onClose.call(datetimepicker, _xdsoft_datetime.currentTime, datetimepicker.data('input'), event); } if (onClose !== false && !options.opened && !options.inline) { datetimepicker.hide(); } event.stopPropagation(); }) .on('toggle.xdsoft', function (event) { if (datetimepicker.is(':visible')) { datetimepicker.trigger('close.xdsoft'); } else { datetimepicker.trigger('open.xdsoft'); } }) .data('input', input); timer = 0; timer1 = 0; datetimepicker.data('xdsoft_datetime', _xdsoft_datetime); datetimepicker.setOptions(options); function getCurrentValue() { var ct = false, time; if (options.startDate) { ct = _xdsoft_datetime.strToDate(options.startDate); } else { ct = options.value || ((input && input.val && input.val()) ? input.val() : ''); if (ct) { ct = _xdsoft_datetime.strToDateTime(ct); } else if (options.defaultDate) { ct = _xdsoft_datetime.strToDateTime(options.defaultDate); if (options.defaultTime) { time = _xdsoft_datetime.strtotime(options.defaultTime); ct.setHours(time.getHours()); ct.setMinutes(time.getMinutes()); } } } if (ct && _xdsoft_datetime.isValidDate(ct)) { datetimepicker.data('changed', true); } else { ct = ''; } return ct || 0; } _xdsoft_datetime.setCurrentTime(getCurrentValue()); input .data('xdsoft_datetimepicker', datetimepicker) .on('open.xdsoft focusin.xdsoft mousedown.xdsoft', function (event) { if (input.is(':disabled') || (input.data('xdsoft_datetimepicker').is(':visible') && options.closeOnInputClick)) { return; } clearTimeout(timer); timer = setTimeout(function () { if (input.is(':disabled')) { return; } triggerAfterOpen = true; _xdsoft_datetime.setCurrentTime(getCurrentValue()); datetimepicker.trigger('open.xdsoft'); }, 100); }) .on('keydown.xdsoft', function (event) { var val = this.value, elementSelector, key = event.which; if ([ENTER].indexOf(key) !== -1 && options.enterLikeTab) { elementSelector = $("input:visible,textarea:visible"); datetimepicker.trigger('close.xdsoft'); elementSelector.eq(elementSelector.index(this) + 1).focus(); return false; } if ([TAB].indexOf(key) !== -1) { datetimepicker.trigger('close.xdsoft'); return true; } }); }; destroyDateTimePicker = function (input) { var datetimepicker = input.data('xdsoft_datetimepicker'); if (datetimepicker) { datetimepicker.data('xdsoft_datetime', null); datetimepicker.remove(); input .data('xdsoft_datetimepicker', null) .off('.xdsoft'); $(window).off('resize.xdsoft'); $([window, document.body]).off('mousedown.xdsoft'); if (input.unmousewheel) { input.unmousewheel(); } } }; $(document) .off('keydown.xdsoftctrl keyup.xdsoftctrl') .on('keydown.xdsoftctrl', function (e) { if (e.keyCode === CTRLKEY) { ctrlDown = true; } }) .on('keyup.xdsoftctrl', function (e) { if (e.keyCode === CTRLKEY) { ctrlDown = false; } }); return this.each(function () { var datetimepicker = $(this).data('xdsoft_datetimepicker'), $input; if (datetimepicker) { if ($.type(opt) === 'string') { switch (opt) { case 'show': $(this).select().focus(); datetimepicker.trigger('open.xdsoft'); break; case 'hide': datetimepicker.trigger('close.xdsoft'); break; case 'toggle': datetimepicker.trigger('toggle.xdsoft'); break; case 'destroy': destroyDateTimePicker($(this)); break; case 'reset': this.value = this.defaultValue; if (!this.value || !datetimepicker.data('xdsoft_datetime').isValidDate(Date.parseDate(this.value, options.format))) { datetimepicker.data('changed', false); } datetimepicker.data('xdsoft_datetime').setCurrentTime(this.value); break; case 'validate': $input = datetimepicker.data('input'); $input.trigger('blur.xdsoft'); break; } } else { datetimepicker .setOptions(opt); } return 0; } if ($.type(opt) !== 'string') { if (!options.lazyInit || options.open || options.inline) { createDateTimePicker($(this)); } else { lazyInit($(this)); } } }); }; $.fn.datetimepicker.defaults = default_options; }(jQuery)); function HighlightedDate(date, desc, style) { "use strict"; this.date = date; this.desc = desc; this.style = style; } (function () { /*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh) * Licensed under the MIT License (LICENSE.txt). * * Version: 3.1.12 * * Requires: jQuery 1.2.2+ */ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})}); // Parse and Format Library //http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/ /* * Copyright (C) 2004 Baron Schwartz * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, version 2.1. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ Date.parseFunctions={count:0};Date.parseRegexes=[];Date.formatFunctions={count:0};Date.prototype.dateFormat=function(b){if(b=="unixtime"){return parseInt(this.getTime()/1000);}if(Date.formatFunctions[b]==null){Date.createNewFormat(b);}var a=Date.formatFunctions[b];return this[a]();};Date.createNewFormat=function(format){var funcName="format"+Date.formatFunctions.count++;Date.formatFunctions[format]=funcName;var codePrefix="Date.prototype."+funcName+" = function() {return ";var code="";var special=false;var ch="";for(var i=0;i 0) {";var regex="";var special=false;var ch="";for(var i=0;i 0 && z > 0){\nvar doyDate = new Date(y,0);\ndoyDate.setDate(z);\nm = doyDate.getMonth();\nd = doyDate.getDate();\n}";code+="if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n{return new Date(y, m, d, h, i, s);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n{return new Date(y, m, d, h, i);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0)\n{return new Date(y, m, d, h);}\nelse if (y > 0 && m >= 0 && d > 0)\n{return new Date(y, m, d);}\nelse if (y > 0 && m >= 0)\n{return new Date(y, m);}\nelse if (y > 0)\n{return new Date(y);}\n}return null;}";Date.parseRegexes[regexNum]=new RegExp("^"+regex+"$",'i');eval(code);};Date.formatCodeToRegex=function(b,a){switch(b){case"D":return{g:0,c:null,s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};case"j":case"d":return{g:1,c:"d = parseInt(results["+a+"], 10);\n",s:"(\\d{1,2})"};case"l":return{g:0,c:null,s:"(?:"+Date.dayNames.join("|")+")"};case"S":return{g:0,c:null,s:"(?:st|nd|rd|th)"};case"w":return{g:0,c:null,s:"\\d"};case"z":return{g:1,c:"z = parseInt(results["+a+"], 10);\n",s:"(\\d{1,3})"};case"W":return{g:0,c:null,s:"(?:\\d{2})"};case"F":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+a+"].substring(0, 3)], 10);\n",s:"("+Date.monthNames.join("|")+")"};case"M":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+a+"]], 10);\n",s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};case"n":case"m":return{g:1,c:"m = parseInt(results["+a+"], 10) - 1;\n",s:"(\\d{1,2})"};case"t":return{g:0,c:null,s:"\\d{1,2}"};case"L":return{g:0,c:null,s:"(?:1|0)"};case"Y":return{g:1,c:"y = parseInt(results["+a+"], 10);\n",s:"(\\d{4})"};case"y":return{g:1,c:"var ty = parseInt(results["+a+"], 10);\ny = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",s:"(\\d{1,2})"};case"a":return{g:1,c:"if (results["+a+"] == 'am') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(am|pm)"};case"A":return{g:1,c:"if (results["+a+"] == 'AM') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(AM|PM)"};case"g":case"G":case"h":case"H":return{g:1,c:"h = parseInt(results["+a+"], 10);\n",s:"(\\d{1,2})"};case"i":return{g:1,c:"i = parseInt(results["+a+"], 10);\n",s:"(\\d{2})"};case"s":return{g:1,c:"s = parseInt(results["+a+"], 10);\n",s:"(\\d{2})"};case"O":return{g:0,c:null,s:"[+-]\\d{4}"};case"T":return{g:0,c:null,s:"[A-Z]{3}"};case"Z":return{g:0,c:null,s:"[+-]\\d{1,5}"};default:return{g:0,c:null,s:String.escape(b)};}};Date.prototype.getTimezone=function(){return this.toString().replace(/^.*? ([A-Z]{3}) [0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3");};Date.prototype.getGMTOffset=function(){return(this.getTimezoneOffset()>0?"-":"+")+String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset())/60),2,"0")+String.leftPad(Math.abs(this.getTimezoneOffset())%60,2,"0");};Date.prototype.getDayOfYear=function(){var a=0;Date.daysInMonth[1]=this.isLeapYear()?29:28;for(var b=0;bdiv >div { background: #f5f5f5; border-top: 1px solid #ddd; color: #666; font-size: 12px; text-align: center; border-collapse: collapse; cursor: pointer; border-bottom-width: 0; height: 25px; line-height: 25px; } .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div > div:first-child { border-top-width: 0; } .xdsoft_datetimepicker .xdsoft_today_button:hover, .xdsoft_datetimepicker .xdsoft_next:hover, .xdsoft_datetimepicker .xdsoft_prev:hover { opacity: 1; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; } .xdsoft_datetimepicker .xdsoft_label { display: inline; position: relative; z-index: 9999; margin: 0; padding: 5px 3px; font-size: 14px; line-height: 20px; font-weight: bold; background-color: #fff; float: left; width: 182px; text-align: center; cursor: pointer; } .xdsoft_datetimepicker .xdsoft_label:hover>span { text-decoration: underline; } .xdsoft_datetimepicker .xdsoft_label:hover i { opacity: 1.0; } .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select { border: 1px solid #ccc; position: absolute; right: 0; top: 30px; z-index: 101; display: none; background: #fff; max-height: 160px; overflow-y: hidden; } .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_monthselect{ right: -7px } .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_yearselect{ right: 2px } .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option:hover { color: #fff; background: #ff8000; } .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option { padding: 2px 10px 2px 5px; text-decoration: none !important; } .xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option.xdsoft_current { background: #33aaff; box-shadow: #178fe5 0 1px 3px 0 inset; color: #fff; font-weight: 700; } .xdsoft_datetimepicker .xdsoft_month { width: 100px; text-align: right; } .xdsoft_datetimepicker .xdsoft_calendar { clear: both; } .xdsoft_datetimepicker .xdsoft_year{ width: 48px; margin-left: 5px; } .xdsoft_datetimepicker .xdsoft_calendar table { border-collapse: collapse; width: 100%; } .xdsoft_datetimepicker .xdsoft_calendar td > div { padding-right: 5px; } .xdsoft_datetimepicker .xdsoft_calendar th { height: 25px; } .xdsoft_datetimepicker .xdsoft_calendar td,.xdsoft_datetimepicker .xdsoft_calendar th { width: 14.2857142%; background: #f5f5f5; border: 1px solid #ddd; color: #666; font-size: 12px; text-align: right; vertical-align: middle; padding: 0; border-collapse: collapse; cursor: pointer; height: 25px; } .xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar td,.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar th { width: 12.5%; } .xdsoft_datetimepicker .xdsoft_calendar th { background: #f1f1f1; } .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_today { color: #33aaff; } .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_default { background: #ffe9d2; box-shadow: #ffb871 0 1px 4px 0 inset; color: #000; } .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_mint { background: #c1ffc9; box-shadow: #00dd1c 0 1px 4px 0 inset; color: #000; } .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_default, .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current, .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_current { background: #33aaff; box-shadow: #178fe5 0 1px 3px 0 inset; color: #fff; font-weight: 700; } .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month, .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled, .xdsoft_datetimepicker .xdsoft_time_box >div >div.xdsoft_disabled { opacity: 0.5; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; cursor: default; } .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month.xdsoft_disabled { opacity: 0.2; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)"; } .xdsoft_datetimepicker .xdsoft_calendar td:hover, .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div:hover { color: #fff !important; background: #ff8000 !important; box-shadow: none !important; } .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current.xdsoft_disabled:hover, .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current.xdsoft_disabled:hover { background: #33aaff !important; box-shadow: #178fe5 0 1px 3px 0 inset !important; color: #fff !important; } .xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled:hover, .xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_disabled:hover { color: inherit !important; background: inherit !important; box-shadow: inherit !important; } .xdsoft_datetimepicker .xdsoft_calendar th { font-weight: 700; text-align: center; color: #999; cursor: default; } .xdsoft_datetimepicker .xdsoft_copyright { color: #ccc !important; font-size: 10px; clear: both; float: none; margin-left: 8px; } .xdsoft_datetimepicker .xdsoft_copyright a { color: #eee !important } .xdsoft_datetimepicker .xdsoft_copyright a:hover { color: #aaa !important } .xdsoft_time_box { position: relative; border: 1px solid #ccc; } .xdsoft_scrollbar >.xdsoft_scroller { background: #ccc !important; height: 20px; border-radius: 3px; } .xdsoft_scrollbar { position: absolute; width: 7px; right: 0; top: 0; bottom: 0; cursor: pointer; } .xdsoft_scroller_box { position: relative; } .xdsoft_datetimepicker.xdsoft_dark { box-shadow: 0 5px 15px -5px rgba(255, 255, 255, 0.506); background: #000; border-bottom: 1px solid #444; border-left: 1px solid #333; border-right: 1px solid #333; border-top: 1px solid #333; color: #ccc; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box { border-bottom: 1px solid #222; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div { background: #0a0a0a; border-top: 1px solid #222; color: #999; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label { background-color: #000; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select { border: 1px solid #333; background: #000; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select > div > .xdsoft_option:hover { color: #000; background: #007fff; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select > div > .xdsoft_option.xdsoft_current { background: #cc5500; box-shadow: #b03e00 0 1px 3px 0 inset; color: #000; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_label i, .xdsoft_datetimepicker.xdsoft_dark .xdsoft_prev, .xdsoft_datetimepicker.xdsoft_dark .xdsoft_next, .xdsoft_datetimepicker.xdsoft_dark .xdsoft_today_button { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUExQUUzOTA0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUExQUUzOTE0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQTFBRTM4RTQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQTFBRTM4RjQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pp0VxGEAAAIASURBVHja7JrNSgMxEMebtgh+3MSLr1T1Xn2CHoSKB08+QmR8Bx9A8e7RixdB9CKCoNdexIugxFlJa7rNZneTbLIpM/CnNLsdMvNjM8l0mRCiQ9Ye61IKCAgZAUnH+mU3MMZaHYChBnJUDzWOFZdVfc5+ZFLbrWDeXPwbxIqrLLfaeS0hEBVGIRQCEiZoHQwtlGSByCCdYBl8g8egTTAWoKQMRBRBcZxYlhzhKegqMOageErsCHVkk3hXIFooDgHB1KkHIHVgzKB4ADJQ/A1jAFmAYhkQqA5TOBtocrKrgXwQA8gcFIuAIO8sQSA7hidvPwaQGZSaAYHOUWJABhWWw2EMIH9QagQERU4SArJXo0ZZL18uvaxejXt/Em8xjVBXmvFr1KVm/AJ10tRe2XnraNqaJvKE3KHuUbfK1E+VHB0q40/y3sdQSxY4FHWeKJCunP8UyDdqJZenT3ntVV5jIYCAh20vT7ioP8tpf6E2lfEMwERe+whV1MHjwZB7PBiCxcGQWwKZKD62lfGNnP/1poFAA60T7rF1UgcKd2id3KDeUS+oLWV8DfWAepOfq00CgQabi9zjcgJVYVD7PVzQUAUGAQkbNJTBICDhgwYTjDYD6XeW08ZKh+A4pYkzenOxXUbvZcWz7E8ykRMnIHGX1XPl+1m2vPYpL+2qdb8CDAARlKFEz/ZVkAAAAABJRU5ErkJggg==); } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td, .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th { background: #0a0a0a; border: 1px solid #222; color: #999; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th { background: #0e0e0e; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_today { color: #cc5500; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_default { background: #ffe9d2; box-shadow: #ffb871 0 1px 4px 0 inset; color:#000; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_mint { background: #c1ffc9; box-shadow: #00dd1c 0 1px 4px 0 inset; color:#000; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_default, .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_current, .xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_current { background: #cc5500; box-shadow: #b03e00 0 1px 3px 0 inset; color: #000; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td:hover, .xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div:hover { color: #000 !important; background: #007fff !important; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th { color: #666; } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright { color: #333 !important } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a { color: #111 !important } .xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a:hover { color: #555 !important } .xdsoft_dark .xdsoft_time_box { border: 1px solid #333; } .xdsoft_dark .xdsoft_scrollbar >.xdsoft_scroller { background: #333 !important; } .xdsoft_datetimepicker .xdsoft_save_selected { display: block; border: 1px solid #dddddd !important; margin-top: 5px; width: 100%; color: #454551; font-size: 13px; } .xdsoft_datetimepicker .blue-gradient-button { font-family: "museo-sans", "Book Antiqua", sans-serif; font-size: 12px; font-weight: 300; color: #82878c; height: 28px; position: relative; padding: 4px 17px 4px 33px; border: 1px solid #d7d8da; background: -moz-linear-gradient(top, #fff 0%, #f4f8fa 73%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(73%, #f4f8fa)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #fff 0%, #f4f8fa 73%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #fff 0%, #f4f8fa 73%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #fff 0%, #f4f8fa 73%); /* IE10+ */ background: linear-gradient(to bottom, #fff 0%, #f4f8fa 73%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fff', endColorstr='#f4f8fa',GradientType=0 ); /* IE6-9 */ } .xdsoft_datetimepicker .blue-gradient-button:hover, .xdsoft_datetimepicker .blue-gradient-button:focus, .xdsoft_datetimepicker .blue-gradient-button:hover span, .xdsoft_datetimepicker .blue-gradient-button:focus span { color: #454551; background: -moz-linear-gradient(top, #f4f8fa 0%, #FFF 73%); /* FF3.6+ */ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f4f8fa), color-stop(73%, #FFF)); /* Chrome,Safari4+ */ background: -webkit-linear-gradient(top, #f4f8fa 0%, #FFF 73%); /* Chrome10+,Safari5.1+ */ background: -o-linear-gradient(top, #f4f8fa 0%, #FFF 73%); /* Opera 11.10+ */ background: -ms-linear-gradient(top, #f4f8fa 0%, #FFF 73%); /* IE10+ */ background: linear-gradient(to bottom, #f4f8fa 0%, #FFF 73%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f8fa', endColorstr='#FFF',GradientType=0 ); /* IE6-9 */ }