├── .editorconfig ├── .gitignore ├── README.md ├── chapter10 ├── .babelrc ├── .eslintrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── __tests__ │ ├── app-test.js │ └── response.json ├── index.html ├── package.json ├── server.js ├── src │ ├── App.js │ ├── Cats.css │ ├── Home.js │ ├── Modal.js │ ├── Picture.js │ ├── index.js │ └── models.js └── webpack.config.js ├── chapter11 ├── .eslintrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── __tests__ │ └── .keep ├── index.html ├── package.json ├── server.js ├── src │ ├── App.js │ ├── Cats.css │ ├── Home.js │ ├── Modal.js │ ├── Picture.js │ ├── index.js │ └── models.js └── webpack.config.js ├── chapter12 ├── .gitignore ├── README.md ├── config.example.js ├── config.js ├── css │ └── app.css ├── index.html ├── js │ ├── actions │ │ └── SocialActions.js │ ├── app.js │ ├── components │ │ ├── Header.react.js │ │ ├── MainSection.react.js │ │ └── SocialTracker.react.js │ ├── constants │ │ └── SocialConstants.js │ ├── dispatcher │ │ └── AppDispatcher.js │ ├── stores │ │ └── SocialStore.js │ └── utils │ │ ├── array.js │ │ └── jsonutil.js ├── package.json ├── screenshot.png └── server.js ├── chapter13 ├── .babelrc ├── .gitignore ├── README.md ├── actions │ └── social.js ├── components │ └── SocialTracker.js ├── config.example.js ├── containers │ └── App.js ├── index.html ├── index.js ├── package.json ├── reducers │ ├── index.js │ └── social.js ├── server.js ├── store │ └── configureStore.js ├── styles │ └── App.css ├── test │ ├── .eslintrc │ ├── actions │ │ └── counter.spec.js │ ├── components │ │ └── Counter.spec.js │ ├── containers │ │ └── App.spec.js │ ├── reducers │ │ └── counter.spec.js │ └── setup.js ├── utils │ ├── array.js │ └── jsonutil.js └── webpack.config.js ├── chapter2 ├── index.html └── src │ ├── App.js │ └── index.js ├── chapter4 ├── .babelrc ├── .eslintrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── index.html ├── package.json ├── server.js ├── src │ ├── BookStore.js │ └── index.js └── webpack.config.js ├── chapter5 ├── .babelrc ├── .eslintrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── index.html ├── package.json ├── server.js ├── src │ ├── App.js │ ├── booklist.js │ ├── confirmation.js │ ├── delivery_details.js │ ├── index.js │ ├── mixins │ │ ├── cart_timeout_mixin.js │ │ └── set_interval_mixin.js │ ├── modals │ │ └── modal_alert_timeout.js │ ├── shipping_details.js │ └── success.js └── webpack.config.js ├── chapter6-iso ├── .babelrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── config │ └── app.js ├── package.json ├── src │ ├── app │ │ ├── __tests__ │ │ │ └── app.spec.js │ │ ├── app.js │ │ ├── components │ │ │ ├── AppRoot.js │ │ │ ├── SearchPage.js │ │ │ └── __tests__ │ │ │ │ ├── AppRoot.spec.js │ │ │ │ ├── Cart.spec.js │ │ │ │ └── Item.spec.js │ │ └── index.js │ ├── client │ │ ├── index.ejs │ │ ├── index.html │ │ ├── scripts │ │ │ └── client.js │ │ └── styles │ │ │ └── main.css │ └── server │ │ ├── index.js │ │ └── server.js ├── tools │ └── preprocessor.js └── webpack.js ├── chapter6-rails ├── .eslintrc ├── .gitignore ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── Procfile ├── README.md ├── Rakefile ├── app │ ├── admin │ │ ├── dashboard.rb │ │ └── user.rb │ ├── assets │ │ ├── javascripts │ │ │ ├── application_common.js │ │ │ ├── application_desktop.js │ │ │ ├── application_phone.js │ │ │ ├── common │ │ │ │ ├── active_admin.js │ │ │ │ ├── bootstrap.js │ │ │ │ ├── fetch.js │ │ │ │ └── modal_behavior.js │ │ │ ├── components.js │ │ │ ├── components │ │ │ │ ├── .gitkeep │ │ │ │ └── SearchPage.js.jsx │ │ │ ├── desktop │ │ │ │ └── .gitkeep │ │ │ └── phone │ │ │ │ └── .gitkeep │ │ └── stylesheets │ │ │ ├── application_common.scss │ │ │ ├── application_desktop.scss │ │ │ ├── application_phone.scss │ │ │ ├── bootstrap │ │ │ ├── custom.scss │ │ │ └── devise_forms.scss │ │ │ ├── common │ │ │ ├── active_admin.scss │ │ │ ├── alerts.scss │ │ │ └── base.scss │ │ │ ├── desktop │ │ │ └── .gitkeep │ │ │ ├── environment │ │ │ └── ribbon.scss │ │ │ └── phone │ │ │ └── .gitkeep │ ├── carriers │ │ └── layout_carrier.rb │ ├── controllers │ │ ├── api │ │ │ └── v1 │ │ │ │ ├── base_controller.rb │ │ │ │ ├── sessions_controller.rb │ │ │ │ └── users_controller.rb │ │ ├── application_controller.rb │ │ ├── contacts_controller.rb │ │ ├── home_controller.rb │ │ ├── pages_controller.rb │ │ ├── registrations_controller.rb │ │ ├── sessions_controller.rb │ │ └── superadmin │ │ │ ├── base_controller.rb │ │ │ └── users_controller.rb │ ├── helpers │ │ └── application_helper.rb │ ├── mailers │ │ └── mailer.rb │ ├── middleware │ │ └── catch_json_parse_errors.rb │ ├── models │ │ ├── contact.rb │ │ └── user.rb │ ├── services │ │ └── addition_service.rb │ ├── uploaders │ │ └── profile_image_uploader.rb │ ├── views │ │ ├── home │ │ │ └── index.html.haml │ │ ├── layouts │ │ │ ├── application.html+phone.haml │ │ │ ├── application.html.haml │ │ │ ├── mailer.haml │ │ │ └── superadmin.html.haml │ │ ├── mailer │ │ │ └── contact_us_notification.html.haml │ │ ├── pages │ │ │ ├── about.html+phone.haml │ │ │ ├── about.html.haml │ │ │ ├── contact_us.html.haml │ │ │ └── index.html.haml │ │ ├── shared │ │ │ ├── _bootstrap_flash.html.haml │ │ │ ├── _modal.html.haml │ │ │ ├── _nav.html.haml │ │ │ ├── _superadmin_nav.html.haml │ │ │ ├── _user_is_signed_in.html.haml │ │ │ └── _user_right_nav.html.haml │ │ ├── superadmin │ │ │ └── users │ │ │ │ ├── _edit_modal.html.haml │ │ │ │ └── index.html.haml │ │ └── users │ │ │ ├── confirmations │ │ │ └── new.html.haml │ │ │ ├── mailer │ │ │ ├── confirmation_instructions.html.haml │ │ │ ├── reset_password_instructions.html.haml │ │ │ └── unlock_instructions.html.haml │ │ │ ├── passwords │ │ │ ├── edit.html.haml │ │ │ └── new.html.haml │ │ │ ├── registrations │ │ │ ├── edit.html.haml │ │ │ ├── edit_password.html.haml │ │ │ └── new.html.haml │ │ │ ├── sessions │ │ │ └── new.html.haml │ │ │ ├── shared │ │ │ └── _links.haml │ │ │ └── unlocks │ │ │ └── new.html.haml │ └── workers │ │ ├── base_worker.rb │ │ └── event_notification_worker.rb ├── bin │ ├── bundle │ ├── delayed_job │ ├── honeybadger │ ├── rails │ ├── rake │ ├── setup │ └── spring ├── circle.yml ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── database.yml.ci │ ├── database.yml.postgresql │ ├── database.yml.postgresqlapp │ ├── database.yml.sqlite3 │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ ├── staging.rb │ │ └── test.rb │ ├── honeybadger.yml │ ├── initializers │ │ ├── active_admin.rb │ │ ├── asset_precompile.rb │ │ ├── assets.rb │ │ ├── backtrace_silencers.rb │ │ ├── catch_json_parser_errors.rb │ │ ├── cookies_serializer.rb │ │ ├── delayed_job_config.rb │ │ ├── delayed_job_invoke_worker_automatically.rb │ │ ├── devise.rb │ │ ├── devise_async.rb │ │ ├── email_interceptor.rb │ │ ├── email_prefixer.rb │ │ ├── filter_parameter_logging.rb │ │ ├── honeybadger.rb │ │ ├── inflections.rb │ │ ├── marginalia.rb │ │ ├── mime_types.rb │ │ ├── rack_deflater.rb │ │ ├── session_store.rb │ │ ├── setup_email.rb │ │ ├── simple_form.rb │ │ ├── simple_form_bootstrap.rb │ │ ├── tagged_logging.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ ├── devise.en.yml │ │ ├── en.bootstrap.yml │ │ ├── en.yml │ │ └── simple_form.en.yml │ ├── routes.rb │ ├── secrets.yml │ └── unicorn.rb ├── db │ ├── migrate │ │ ├── 20131112184628_add_devise_to_users.rb │ │ ├── 20131120170220_create_delayed_jobs.rb │ │ ├── 20131122045009_add_user_attributes.rb │ │ ├── 20131213184726_create_active_admin_comments.rb │ │ ├── 20140220111712_add_authentication_token_to_users.rb │ │ └── 20140225143027_add_profile_image_to_users.rb │ ├── schema.rb │ └── seeds.rb ├── doc │ ├── api.md │ └── why_database_name_only_63_characters_long.md ├── lib │ ├── tasks │ │ └── setup.rake │ └── templates │ │ └── erb │ │ └── scaffold │ │ └── _form.html.erb ├── public │ ├── 404.html │ ├── 422.html │ ├── 500.html │ ├── favicon.ico │ └── robots.txt └── test │ ├── controllers │ ├── active_admin │ │ └── dashboard_controller_test.rb │ ├── api │ │ └── v1 │ │ │ ├── sessions_controller_test.rb │ │ │ └── users_controller_test.rb │ ├── contacts_controller_test.rb │ ├── home_controller_test.rb │ ├── pages_controller_test.rb │ ├── registrations_controller_test.rb │ └── superadmin │ │ └── users_controller_test.rb │ ├── fixtures │ └── users.yml │ ├── integration │ ├── api_invalid_json_data_test.rb │ └── compression_test.rb │ ├── models │ ├── contact_test.rb │ └── user_test.rb │ ├── services │ └── addition_service_test.rb │ └── test_helper.rb ├── chapter6 ├── .babelrc ├── .eslintrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── index.html ├── package.json ├── server.js ├── src │ ├── App.js │ └── index.js └── webpack.config.js ├── chapter7 ├── .babelrc ├── .eslintrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── __tests__ │ ├── app-test.js │ └── response.json ├── bower_components │ ├── bootstrap │ │ ├── .bower.json │ │ ├── Gruntfile.js │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bower.json │ │ ├── dist │ │ │ ├── css │ │ │ │ ├── bootstrap-theme.css │ │ │ │ ├── bootstrap-theme.css.map │ │ │ │ ├── bootstrap-theme.min.css │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ └── bootstrap.min.css │ │ │ ├── fonts │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ │ └── glyphicons-halflings-regular.woff2 │ │ │ └── js │ │ │ │ ├── bootstrap.js │ │ │ │ ├── bootstrap.min.js │ │ │ │ └── npm.js │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ ├── grunt │ │ │ ├── .jshintrc │ │ │ ├── bs-commonjs-generator.js │ │ │ ├── bs-glyphicons-data-generator.js │ │ │ ├── bs-lessdoc-parser.js │ │ │ ├── bs-raw-files-generator.js │ │ │ ├── configBridge.json │ │ │ └── sauce_browsers.yml │ │ ├── js │ │ │ ├── .jscsrc │ │ │ ├── .jshintrc │ │ │ ├── affix.js │ │ │ ├── alert.js │ │ │ ├── button.js │ │ │ ├── carousel.js │ │ │ ├── collapse.js │ │ │ ├── dropdown.js │ │ │ ├── modal.js │ │ │ ├── popover.js │ │ │ ├── scrollspy.js │ │ │ ├── tab.js │ │ │ ├── tooltip.js │ │ │ └── transition.js │ │ ├── less │ │ │ ├── .csscomb.json │ │ │ ├── .csslintrc │ │ │ ├── alerts.less │ │ │ ├── badges.less │ │ │ ├── bootstrap.less │ │ │ ├── breadcrumbs.less │ │ │ ├── button-groups.less │ │ │ ├── buttons.less │ │ │ ├── carousel.less │ │ │ ├── close.less │ │ │ ├── code.less │ │ │ ├── component-animations.less │ │ │ ├── dropdowns.less │ │ │ ├── forms.less │ │ │ ├── glyphicons.less │ │ │ ├── grid.less │ │ │ ├── input-groups.less │ │ │ ├── jumbotron.less │ │ │ ├── labels.less │ │ │ ├── list-group.less │ │ │ ├── media.less │ │ │ ├── mixins.less │ │ │ ├── mixins │ │ │ │ ├── alerts.less │ │ │ │ ├── background-variant.less │ │ │ │ ├── border-radius.less │ │ │ │ ├── buttons.less │ │ │ │ ├── center-block.less │ │ │ │ ├── clearfix.less │ │ │ │ ├── forms.less │ │ │ │ ├── gradients.less │ │ │ │ ├── grid-framework.less │ │ │ │ ├── grid.less │ │ │ │ ├── hide-text.less │ │ │ │ ├── image.less │ │ │ │ ├── labels.less │ │ │ │ ├── list-group.less │ │ │ │ ├── nav-divider.less │ │ │ │ ├── nav-vertical-align.less │ │ │ │ ├── opacity.less │ │ │ │ ├── pagination.less │ │ │ │ ├── panels.less │ │ │ │ ├── progress-bar.less │ │ │ │ ├── reset-filter.less │ │ │ │ ├── reset-text.less │ │ │ │ ├── resize.less │ │ │ │ ├── responsive-visibility.less │ │ │ │ ├── size.less │ │ │ │ ├── tab-focus.less │ │ │ │ ├── table-row.less │ │ │ │ ├── text-emphasis.less │ │ │ │ ├── text-overflow.less │ │ │ │ └── vendor-prefixes.less │ │ │ ├── modals.less │ │ │ ├── navbar.less │ │ │ ├── navs.less │ │ │ ├── normalize.less │ │ │ ├── pager.less │ │ │ ├── pagination.less │ │ │ ├── panels.less │ │ │ ├── popovers.less │ │ │ ├── print.less │ │ │ ├── progress-bars.less │ │ │ ├── responsive-embed.less │ │ │ ├── responsive-utilities.less │ │ │ ├── scaffolding.less │ │ │ ├── tables.less │ │ │ ├── theme.less │ │ │ ├── thumbnails.less │ │ │ ├── tooltip.less │ │ │ ├── type.less │ │ │ ├── utilities.less │ │ │ ├── variables.less │ │ │ └── wells.less │ │ ├── package.js │ │ └── package.json │ └── jquery │ │ ├── .bower.json │ │ ├── MIT-LICENSE.txt │ │ ├── bower.json │ │ ├── dist │ │ ├── jquery.js │ │ ├── jquery.min.js │ │ └── jquery.min.map │ │ └── src │ │ ├── ajax.js │ │ ├── ajax │ │ ├── jsonp.js │ │ ├── load.js │ │ ├── parseJSON.js │ │ ├── parseXML.js │ │ ├── script.js │ │ ├── var │ │ │ ├── nonce.js │ │ │ └── rquery.js │ │ └── xhr.js │ │ ├── attributes.js │ │ ├── attributes │ │ ├── attr.js │ │ ├── classes.js │ │ ├── prop.js │ │ ├── support.js │ │ └── val.js │ │ ├── callbacks.js │ │ ├── core.js │ │ ├── core │ │ ├── access.js │ │ ├── init.js │ │ ├── parseHTML.js │ │ ├── ready.js │ │ └── var │ │ │ └── rsingleTag.js │ │ ├── css.js │ │ ├── css │ │ ├── addGetHookIf.js │ │ ├── curCSS.js │ │ ├── defaultDisplay.js │ │ ├── hiddenVisibleSelectors.js │ │ ├── support.js │ │ ├── swap.js │ │ └── var │ │ │ ├── cssExpand.js │ │ │ ├── getStyles.js │ │ │ ├── isHidden.js │ │ │ ├── rmargin.js │ │ │ └── rnumnonpx.js │ │ ├── data.js │ │ ├── data │ │ ├── Data.js │ │ ├── accepts.js │ │ └── var │ │ │ ├── data_priv.js │ │ │ └── data_user.js │ │ ├── deferred.js │ │ ├── deprecated.js │ │ ├── dimensions.js │ │ ├── effects.js │ │ ├── effects │ │ ├── Tween.js │ │ └── animatedSelector.js │ │ ├── event.js │ │ ├── event │ │ ├── ajax.js │ │ ├── alias.js │ │ └── support.js │ │ ├── exports │ │ ├── amd.js │ │ └── global.js │ │ ├── intro.js │ │ ├── jquery.js │ │ ├── manipulation.js │ │ ├── manipulation │ │ ├── _evalUrl.js │ │ ├── support.js │ │ └── var │ │ │ └── rcheckableType.js │ │ ├── offset.js │ │ ├── outro.js │ │ ├── queue.js │ │ ├── queue │ │ └── delay.js │ │ ├── selector-native.js │ │ ├── selector-sizzle.js │ │ ├── selector.js │ │ ├── serialize.js │ │ ├── sizzle │ │ └── dist │ │ │ ├── sizzle.js │ │ │ ├── sizzle.min.js │ │ │ └── sizzle.min.map │ │ ├── traversing.js │ │ ├── traversing │ │ ├── findFilter.js │ │ └── var │ │ │ └── rneedsContext.js │ │ ├── var │ │ ├── arr.js │ │ ├── class2type.js │ │ ├── concat.js │ │ ├── hasOwn.js │ │ ├── indexOf.js │ │ ├── pnum.js │ │ ├── push.js │ │ ├── rnotwhite.js │ │ ├── slice.js │ │ ├── strundefined.js │ │ ├── support.js │ │ └── toString.js │ │ └── wrap.js ├── index.html ├── package.json ├── server.js ├── src │ ├── App.js │ ├── RowAlternator.js │ ├── Spinner.js │ └── index.js └── webpack.config.js ├── chapter8 ├── .babelrc ├── .eslintrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── __tests__ │ ├── app-test.js │ └── response.json ├── index.html ├── package.json ├── server.js ├── src │ ├── App.js │ ├── BookList.js │ ├── BookListHeader.js │ ├── BookRow.js │ ├── BookTableHeader.js │ ├── Form.js │ ├── Header.js │ ├── RowAlternator.js │ ├── Spinner.js │ └── index.js └── webpack.config.js └── chapter9 ├── .babelrc ├── .eslintrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── __tests__ ├── app-test.js └── response.json ├── index.html ├── package.json ├── server.js ├── src ├── App.js ├── Home.js ├── Modal.js ├── Picture.js ├── Sample.js ├── index.js └── models.js └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | max_line_length = 80 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | max_line_length = 0 14 | trim_trailing_whitespace = false 15 | 16 | [COMMIT_EDITMSG] 17 | max_line_length = 0 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | reactjs-by-example 2 | =========== 3 | 4 | Examples for "ReactJS by Example" 5 | 6 | ### Usage 7 | 8 | See individual directories for usage 9 | -------------------------------------------------------------------------------- /chapter10/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /chapter10/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /chapter10/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "newcap": false 6 | } 7 | -------------------------------------------------------------------------------- /chapter10/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter10/README.md: -------------------------------------------------------------------------------- 1 | react-addons 2 | =========== 3 | 4 | Examples of React addons 5 | 6 | ### Usage 7 | 8 | ``` 9 | npm install 10 | npm start 11 | open http://localhost:9000 12 | npm test 13 | ``` 14 | -------------------------------------------------------------------------------- /chapter10/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React Router/ Data Models 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /chapter10/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | publicPath: config.output.publicPath, 7 | hot: true, 8 | historyApiFallback: true 9 | }).listen(9000, 'localhost', function (err, result) { 10 | if (err) { 11 | console.log(err); 12 | } 13 | 14 | console.log('Listening at localhost:9000'); 15 | }); 16 | -------------------------------------------------------------------------------- /chapter10/src/Modal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Router, Route, IndexRoute, Link } from 'react-router' 3 | 4 | const Modal = React.createClass({ 5 | styles: { 6 | position: 'fixed', 7 | top: '20%', 8 | right: '20%', 9 | bottom: '20%', 10 | left: '20%', 11 | padding: 20, 12 | boxShadow: '0px 0px 150px 130px rgba(0, 0, 0, 0.5)', 13 | overflow: 'auto', 14 | background: '#fff' 15 | }, 16 | 17 | render() { 18 | return ( 19 |
20 |

Back

21 | {this.props.children} 22 |
23 | ) 24 | } 25 | }) 26 | 27 | export {Modal as default} 28 | -------------------------------------------------------------------------------- /chapter10/src/Picture.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { PictureModel } from './models'; 3 | 4 | const Picture = React.createClass({ 5 | render() { 6 | let { location } = this.props; 7 | let cat = location.state.cat; 8 | console.log(this.props); 9 | return ( 10 |
11 |
12 | 13 |
14 |
15 |

Name: {cat.get('name')}.

16 |

Details: {cat.get('details')}

17 |
18 |
19 | ) 20 | } 21 | }); 22 | 23 | export {Picture as default} 24 | -------------------------------------------------------------------------------- /chapter10/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createHistory, useBasename } from 'history' 4 | import { Router, Route, IndexRoute, Link } from 'react-router' 5 | import Backbone from 'backbone'; 6 | import Modal from './Modal' 7 | import App from './App' 8 | import Picture from './Picture' 9 | import Home from './Home' 10 | 11 | const history = useBasename(createHistory)({ 12 | basename: '/pinterest' 13 | }); 14 | 15 | 16 | render(( 17 | 18 | 19 | 20 | 21 | 22 | 23 | ), document.getElementById('rootElement')); 24 | -------------------------------------------------------------------------------- /chapter10/src/models.js: -------------------------------------------------------------------------------- 1 | import Backbone from 'backbone'; 2 | import Faker from 'faker'; 3 | import _ from 'underscore'; 4 | 5 | const PictureModel = Backbone.Model.extend({ 6 | defaults: { 7 | src: 'http://lorempixel.com/601/600/cats/', 8 | name: 'Pusheen', 9 | details: 'Pusheen is a Cat', 10 | faved: false 11 | } 12 | }); 13 | 14 | class CatGenerator { 15 | constructor() { 16 | this.Cats = new Backbone.Collection; 17 | [600, 601, 602, 603, 604, 605].map( (height)=>{ 18 | this.createCat(height, 600); 19 | }) 20 | } 21 | 22 | createCat(height = _.random(600, 650), width = 600) { 23 | console.log('Adding new cat'); 24 | this.Cats.add(new PictureModel({ 25 | src: `http://lorempixel.com/${height}/${width}/cats/`, 26 | name: Faker.Name.findName(), 27 | details: Faker.Lorem.paragraph() 28 | })); 29 | } 30 | 31 | randRange() { 32 | return _.random(5000, 10000); 33 | } 34 | 35 | } 36 | 37 | module.exports = {PictureModel, CatGenerator}; 38 | -------------------------------------------------------------------------------- /chapter11/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /chapter11/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "newcap": false 6 | } 7 | -------------------------------------------------------------------------------- /chapter11/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter11/README.md: -------------------------------------------------------------------------------- 1 | react-tools 2 | =========== 3 | 4 | Examples of React Tools 5 | 6 | ### Usage 7 | 8 | ``` 9 | npm install 10 | npm start 11 | open http://localhost:9000 12 | npm test 13 | ``` 14 | -------------------------------------------------------------------------------- /chapter11/__tests__/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter11/__tests__/.keep -------------------------------------------------------------------------------- /chapter11/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React Router/ Data Models 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /chapter11/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | publicPath: config.output.publicPath, 7 | hot: true, 8 | historyApiFallback: true 9 | }).listen(9000, 'localhost', function (err, result) { 10 | if (err) { 11 | console.log(err); 12 | } 13 | 14 | console.log('Listening at localhost:9000'); 15 | }); 16 | -------------------------------------------------------------------------------- /chapter11/src/Modal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Router, Route, IndexRoute, Link } from 'react-router' 3 | 4 | const Modal = React.createClass({ 5 | styles: { 6 | position: 'fixed', 7 | top: '20%', 8 | right: '20%', 9 | bottom: '20%', 10 | left: '20%', 11 | padding: 20, 12 | boxShadow: '0px 0px 150px 130px rgba(0, 0, 0, 0.5)', 13 | overflow: 'auto', 14 | background: '#fff' 15 | }, 16 | 17 | render() { 18 | return ( 19 |
20 |

Back

21 | {this.props.children} 22 |
23 | ) 24 | } 25 | }) 26 | 27 | export {Modal as default} 28 | -------------------------------------------------------------------------------- /chapter11/src/Picture.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { PictureModel } from './models'; 3 | 4 | const Picture = React.createClass({ 5 | render() { 6 | let { location } = this.props; 7 | let cat = location.state.cat; 8 | console.log(this.props); 9 | return ( 10 |
11 |
12 | 13 |
14 |
15 |

Name: {cat.get('name')}.

16 |

Details: {cat.get('details')}

17 |
18 |
19 | ) 20 | } 21 | }); 22 | 23 | export {Picture as default} 24 | -------------------------------------------------------------------------------- /chapter11/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createHistory, useBasename } from 'history' 4 | import { Router, Route, IndexRoute, Link } from 'react-router' 5 | import Backbone from 'backbone'; 6 | import Modal from './Modal' 7 | import App from './App' 8 | import Picture from './Picture' 9 | import Home from './Home' 10 | 11 | const history = useBasename(createHistory)({ 12 | basename: '/pinterest' 13 | }); 14 | 15 | 16 | render(( 17 | 18 | 19 | 20 | 21 | 22 | 23 | ), document.getElementById('rootElement')); 24 | -------------------------------------------------------------------------------- /chapter11/src/models.js: -------------------------------------------------------------------------------- 1 | import Backbone from 'backbone'; 2 | import Faker from 'faker'; 3 | import _ from 'underscore'; 4 | 5 | const PictureModel = Backbone.Model.extend({ 6 | defaults: { 7 | src: 'http://lorempixel.com/601/600/cats/', 8 | name: 'Pusheen', 9 | details: 'Pusheen is a Cat', 10 | faved: false 11 | } 12 | }); 13 | 14 | class CatGenerator { 15 | constructor() { 16 | this.Cats = new Backbone.Collection; 17 | [600, 601, 602, 603, 604, 605].map( (height)=>{ 18 | this.createCat(height, 600); 19 | }) 20 | } 21 | 22 | createCat(height = _.random(600, 650), width = 600) { 23 | console.log('Adding new cat'); 24 | this.Cats.add(new PictureModel({ 25 | src: `http://lorempixel.com/${height}/${width}/cats/`, 26 | name: Faker.Name.findName(), 27 | details: Faker.Lorem.paragraph() 28 | })); 29 | } 30 | 31 | randRange() { 32 | return _.random(5000, 10000); 33 | } 34 | 35 | } 36 | 37 | module.exports = {PictureModel, CatGenerator}; 38 | -------------------------------------------------------------------------------- /chapter12/.gitignore: -------------------------------------------------------------------------------- 1 | /js/bundle.js 2 | /js/bundle.min.js 3 | .bundle.js 4 | ./config.js 5 | -------------------------------------------------------------------------------- /chapter12/config.example.js: -------------------------------------------------------------------------------- 1 | module.exports ={ 2 | twitter_consumer_key: '', 3 | twitter_consumer_secret: '', 4 | twitter_access_token_key: '', 5 | twitter_access_token_secret: '' 6 | } 7 | -------------------------------------------------------------------------------- /chapter12/config.js: -------------------------------------------------------------------------------- 1 | module.exports ={ 2 | twitter_consumer_key: 'hRz8HdxVaGtwBhCjzt7pTRZho', 3 | twitter_consumer_secret: 'CtPCwGuSpunUKoJO5PV80H4PBNTKBzyX1DirjgqL5MHmVXjJUw', 4 | twitter_access_token_key: '52653289-DBbudBLcfJFfBRkUnZbuGkYuLLmRqUanfdvIszrKn', 5 | twitter_access_token_secret: 'FUYuoxsM2Et8tCSJzSYQsGiH3xeWbIzgfUQ5zwQLmkOVb' 6 | } 7 | -------------------------------------------------------------------------------- /chapter12/css/app.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | * base.css overrides 10 | */ 11 | 12 | .center-text { 13 | text-align: center; 14 | } 15 | 16 | .grid { 17 | word-wrap: break-word; 18 | } 19 | 20 | .twitter { 21 | border-left: 2px solid #55ACEE; 22 | position: relative; 23 | } 24 | .twitter:before { 25 | content: "\f099"; 26 | font: normal normal normal 20px/1 FontAwesome; 27 | position: absolute; 28 | bottom: 10px; 29 | right: 10px; 30 | color: #55ACEE; 31 | opacity: .5; 32 | } 33 | 34 | 35 | .reddit { 36 | border-left: 2px solid #FF4500; 37 | position: relative; 38 | } 39 | .reddit:before { 40 | content: "\f1a1"; 41 | font: normal normal normal 20px/1 FontAwesome; 42 | position: absolute; 43 | bottom: 10px; 44 | right: 10px; 45 | color: #FF4500; 46 | opacity: .5; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /chapter12/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Flux/Social Media Tracker 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /chapter12/js/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | var React = require('react'); 11 | var ReactDOM = require('react-dom'); 12 | var SocialTracker = require('./components/SocialTracker.react'); 13 | 14 | ReactDOM.render( 15 | , 16 | document.getElementById('container') 17 | ); 18 | -------------------------------------------------------------------------------- /chapter12/js/components/Header.react.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2014-2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | var React = require('react'); 11 | var ReactBootstrap = require('react-bootstrap'); 12 | var Row = ReactBootstrap.Row, Jumbotron = ReactBootstrap.Jumbotron; 13 | 14 | var Header = React.createClass({ 15 | 16 | render: function () { 17 | return ( 18 | 19 | 20 |

Social Media Tracker

21 |
22 |
23 | ); 24 | } 25 | 26 | }); 27 | 28 | module.exports = Header; 29 | -------------------------------------------------------------------------------- /chapter12/js/constants/SocialConstants.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | * SocialConstants 10 | */ 11 | 12 | var keyMirror = require('keymirror'); 13 | 14 | module.exports = keyMirror({ 15 | FILTER_BY_TWEETS: null, 16 | FILTER_BY_REDDITS: null, 17 | SYNC_TWEETS: null, 18 | SYNC_REDDITS: null 19 | 20 | }); 21 | 22 | 23 | -------------------------------------------------------------------------------- /chapter12/js/dispatcher/AppDispatcher.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2015, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | * 9 | * AppDispatcher 10 | * 11 | * A singleton that operates as the central hub for application updates. 12 | */ 13 | 14 | var Dispatcher = require('flux').Dispatcher; 15 | 16 | module.exports = new Dispatcher(); 17 | -------------------------------------------------------------------------------- /chapter12/js/utils/array.js: -------------------------------------------------------------------------------- 1 | var ArrayUtil = (function () { 2 | function in_groups_of(arr, n) { 3 | var ret = []; 4 | var group = []; 5 | var len = arr.length; 6 | 7 | for (var i = 0; i < len; ++i) { 8 | group.push(arr[i]); 9 | if ((i + 1) % n == 0) { 10 | ret.push(group); 11 | group = []; 12 | } 13 | } 14 | 15 | if (group.length) ret.push(group); 16 | 17 | return ret; 18 | }; 19 | 20 | 21 | return {'in_groups_of': in_groups_of} 22 | }()); 23 | 24 | module.exports = ArrayUtil; 25 | -------------------------------------------------------------------------------- /chapter12/js/utils/jsonutil.js: -------------------------------------------------------------------------------- 1 | var JSONUtil = (function () { 2 | function parseJSON(response){ 3 | return response.json() 4 | } 5 | 6 | function handleParseException(ex) { 7 | console.log('parsing failed', ex) 8 | } 9 | 10 | 11 | return {'parseJSON': parseJSON, 'handleParseException': handleParseException} 12 | }()); 13 | 14 | module.exports = JSONUtil; 15 | -------------------------------------------------------------------------------- /chapter12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactjs-by-example-flux", 3 | "version": "0.0.1", 4 | "description": "ReactJS with Flux.", 5 | "repository": "https://github.com/bigbinary/reactjs-by-example", 6 | "main": "server.js", 7 | "dependencies": { 8 | "classnames": "^2.1.3", 9 | "express": "^4.13.3", 10 | "flux": "^2.0.1", 11 | "keymirror": "~0.1.0", 12 | "object-assign": "^1.0.0", 13 | "react": "^0.14.6", 14 | "react-bootstrap": "^0.28.2", 15 | "twitter": "^1.2.5", 16 | "underscore": "^1.8.3", 17 | "whatwg-fetch": "^0.10.1" 18 | }, 19 | "devDependencies": { 20 | "browserify": "^6.2.0", 21 | "envify": "^3.0.0", 22 | "jest-cli": "^0.4.3", 23 | "reactify": "^0.15.2", 24 | "uglify-js": "~2.4.15", 25 | "watchify": "^2.1.1" 26 | }, 27 | "scripts": { 28 | "start": "npm run watch & node server.js", 29 | "watch": "watchify -o js/bundle.js -v -d js/app.js", 30 | "build": "browserify . -t [envify --NODE_ENV production] | uglifyjs -cm > js/bundle.min.js", 31 | "test": "jest" 32 | }, 33 | "author": ["Bill Fisher", "Vipul A M"], 34 | "browserify": { 35 | "transform": [ 36 | "reactify", 37 | "envify" 38 | ] 39 | }, 40 | "jest": { 41 | "rootDir": "./js" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /chapter12/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter12/screenshot.png -------------------------------------------------------------------------------- /chapter12/server.js: -------------------------------------------------------------------------------- 1 | var Twitter = require('twitter'); 2 | var config = require('./config'); 3 | 4 | var client = new Twitter({ 5 | consumer_key: config.twitter_consumer_key, 6 | consumer_secret: config.twitter_consumer_secret, 7 | access_token_key: config.twitter_access_token_key, 8 | access_token_secret: config.twitter_access_token_secret 9 | }); 10 | 11 | var express= require('express'); 12 | var app = new (require('express'))(); 13 | var port = 3000 14 | 15 | app.get('/tweets.json', function (req, res) { 16 | console.log(req.query.username); 17 | var params = {screen_name: req.query.username}; 18 | client.get('statuses/user_timeline', params, function (error, tweets, response) { 19 | console.log(error); 20 | if (!error) { 21 | res.json(tweets); 22 | } else { 23 | res.json({error: error}); 24 | } 25 | }); 26 | }); 27 | 28 | app.use(express.static(__dirname)); 29 | 30 | app.get("/", function (req, res) { 31 | res.sendFile(__dirname + '/index.html') 32 | }); 33 | 34 | app.listen(port, function (error) { 35 | if (error) { 36 | console.error(error) 37 | } else { 38 | console.info("==> 🌎 Listening on port %s. Open up http://localhost:%s/ in your browser.", port, port) 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /chapter13/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0, 3 | "env": { 4 | "development": { 5 | "plugins": [ 6 | "react-transform" 7 | ], 8 | "extra": { 9 | "react-transform": { 10 | "transforms": [{ 11 | "transform": "react-transform-hmr", 12 | "imports": ["react"], 13 | "locals": ["module"] 14 | }] 15 | } 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /chapter13/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | config.js 5 | -------------------------------------------------------------------------------- /chapter13/README.md: -------------------------------------------------------------------------------- 1 | react-flux 2 | =========== 3 | 4 | Example of Flux, using redux 5 | 6 | ### Usage 7 | 8 | ``` 9 | cp config.example.js config.js # Add App credentials 10 | npm install 11 | npm start 12 | open http://localhost:3000 13 | `` 14 | -------------------------------------------------------------------------------- /chapter13/config.example.js: -------------------------------------------------------------------------------- 1 | module.exports ={ 2 | twitter_consumer_key: '', 3 | twitter_consumer_secret: '', 4 | twitter_access_token_key: '', 5 | twitter_access_token_secret: '' 6 | } 7 | -------------------------------------------------------------------------------- /chapter13/containers/App.js: -------------------------------------------------------------------------------- 1 | import { bindActionCreators } from 'redux' 2 | import { connect } from 'react-redux' 3 | import SocialTracker from '../components/SocialTracker' 4 | import * as SocialActions from '../actions/social' 5 | 6 | function mapStateToProps(state) { 7 | return { 8 | social: state.social 9 | } 10 | } 11 | 12 | function mapDispatchToProps(dispatch) { 13 | return bindActionCreators(SocialActions, dispatch) 14 | } 15 | 16 | export default connect(mapStateToProps, mapDispatchToProps)(SocialTracker) 17 | -------------------------------------------------------------------------------- /chapter13/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Redux 5 | 6 | 7 | 8 | 9 | 10 |
11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /chapter13/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { Provider } from 'react-redux' 4 | import App from './containers/App' 5 | import configureStore from './store/configureStore' 6 | 7 | const store = configureStore() 8 | 9 | render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ) 15 | -------------------------------------------------------------------------------- /chapter13/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import social from './social' 3 | 4 | const rootReducer = combineReducers({ 5 | social 6 | }) 7 | 8 | export default rootReducer 9 | -------------------------------------------------------------------------------- /chapter13/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux' 2 | import thunk from 'redux-thunk' 3 | import reducer from '../reducers' 4 | 5 | const createStoreWithMiddleware = applyMiddleware( 6 | thunk 7 | )(createStore) 8 | 9 | export default function configureStore(initialState) { 10 | const store = createStoreWithMiddleware(reducer, initialState) 11 | 12 | if (module.hot) { 13 | // Enable Webpack hot module replacement for reducers 14 | module.hot.accept('../reducers', () => { 15 | const nextReducer = require('../reducers') 16 | store.replaceReducer(nextReducer) 17 | }) 18 | } 19 | 20 | return store 21 | } 22 | -------------------------------------------------------------------------------- /chapter13/styles/App.css: -------------------------------------------------------------------------------- 1 | .center-text { 2 | text-align: center; 3 | } 4 | 5 | .grid { 6 | word-wrap: break-word; 7 | } 8 | 9 | .twitter { 10 | border-left: 2px solid #55ACEE; 11 | position: relative; 12 | } 13 | .twitter:before { 14 | content: "\f099"; 15 | font: normal normal normal 20px/1 FontAwesome; 16 | position: absolute; 17 | bottom: 10px; 18 | right: 10px; 19 | color: #55ACEE; 20 | opacity: .5; 21 | } 22 | 23 | 24 | .reddit { 25 | border-left: 2px solid #FF4500; 26 | position: relative; 27 | } 28 | .reddit:before { 29 | content: "\f1a1"; 30 | font: normal normal normal 20px/1 FontAwesome; 31 | position: absolute; 32 | bottom: 10px; 33 | right: 10px; 34 | color: #FF4500; 35 | opacity: .5; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /chapter13/test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /chapter13/test/reducers/counter.spec.js: -------------------------------------------------------------------------------- 1 | import expect from 'expect' 2 | import counter from '../../reducers/counter' 3 | import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../../actions/counter' 4 | 5 | describe('reducers', () => { 6 | describe('counter', () => { 7 | it('should handle initial state', () => { 8 | expect(counter(undefined, {})).toBe(0) 9 | }) 10 | 11 | it('should handle INCREMENT_COUNTER', () => { 12 | expect(counter(1, { type: INCREMENT_COUNTER })).toBe(2) 13 | }) 14 | 15 | it('should handle DECREMENT_COUNTER', () => { 16 | expect(counter(1, { type: DECREMENT_COUNTER })).toBe(0) 17 | }) 18 | 19 | it('should handle unknown action type', () => { 20 | expect(counter(1, { type: 'unknown' })).toBe(1) 21 | }) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /chapter13/test/setup.js: -------------------------------------------------------------------------------- 1 | import { jsdom } from 'jsdom' 2 | 3 | global.document = jsdom('') 4 | global.window = document.defaultView 5 | global.navigator = global.window.navigator 6 | -------------------------------------------------------------------------------- /chapter13/utils/array.js: -------------------------------------------------------------------------------- 1 | class ArrayUtil { 2 | static in_groups_of(arr, n) { 3 | var ret = []; 4 | var group = []; 5 | var len = arr.length; 6 | 7 | for (var i = 0; i < len; ++i) { 8 | group.push(arr[i]); 9 | if ((i + 1) % n == 0) { 10 | ret.push(group); 11 | group = []; 12 | } 13 | } 14 | 15 | if (group.length) ret.push(group); 16 | 17 | return ret; 18 | }; 19 | 20 | } 21 | 22 | export {ArrayUtil as default}; 23 | -------------------------------------------------------------------------------- /chapter13/utils/jsonutil.js: -------------------------------------------------------------------------------- 1 | class JSONUtil{ 2 | static parseJSON(response){ 3 | return response.json() 4 | } 5 | 6 | static handleParseException(ex) { 7 | console.log('parsing failed', ex) 8 | } 9 | } 10 | 11 | export { JSONUtil as default } 12 | -------------------------------------------------------------------------------- /chapter2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | JSX in Detail 12 | 13 | 14 |
15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /chapter2/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | var App = React.createClass({ 4 | render: function(){ 5 | return( 6 | 7 | 8 | ); 9 | } 10 | }); 11 | 12 | var RecentChangesTable = React.createClass({ 13 | render: function() { 14 | return 15 | {this.props.children} 16 |
; 17 | } 18 | }); 19 | 20 | RecentChangesTable.Headings = React.createClass({ 21 | render: function() { 22 | var headings = this.props.headings.map(function(name, index) { 23 | return(); 24 | }); 25 | 26 | return ( 27 | 28 | {headings} 29 | 30 | ); 31 | } 32 | }); 33 | 34 | module.exports = App; 35 | -------------------------------------------------------------------------------- /chapter2/src/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom'; 2 | import React from 'react'; 3 | import App from './App'; 4 | 5 | var data = [{ "when": "2 minutes ago", 6 | "who": "Jilaal Dupre", 7 | "description": "Created new account" 8 | }, 9 | { 10 | "when": "1 hour ago", 11 | "who": "Losaae White", 12 | "description": "Added fist chapter" 13 | }]; 14 | var headings = ['When', 'Who', 'Description']; 15 | 16 | 17 | 18 | ReactDOM.render(, 20 | document.getElementById('container')); 21 | -------------------------------------------------------------------------------- /chapter4/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /chapter4/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "jsx": true, 4 | "modules": true 5 | }, 6 | "env": { 7 | "browser": true, 8 | "node": true 9 | }, 10 | "parser": "babel-eslint", 11 | "rules": { 12 | "quotes": [2, "single"], 13 | "strict": [2, "never"], 14 | "react/jsx-uses-react": 2, 15 | "react/jsx-uses-vars": 2, 16 | "react/react-in-jsx-scope": 2 17 | }, 18 | "plugins": [ 19 | "react" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /chapter4/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /chapter4/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "newcap": false 6 | } 7 | -------------------------------------------------------------------------------- /chapter4/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter4/README.md: -------------------------------------------------------------------------------- 1 | react-forms 2 | =========== 3 | 4 | Examples of Forms in ReactJS 5 | 6 | ### Usage 7 | 8 | ``` 9 | npm install 10 | npm start 11 | open http://localhost:9000 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /chapter4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Forms in React 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /chapter4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactjs-by-example-react-forms", 3 | "version": "0.0.1", 4 | "description": "ReactJS forms example", 5 | "scripts": { 6 | "start": "node server.js", 7 | "lint": "eslint src" 8 | }, 9 | "author": "Vipul A M (http://github.com/vipulnsward)", 10 | "license": "MIT", 11 | "homepage": "https://github.com/bigbinary/reactjs-by-example", 12 | "devDependencies": { 13 | "babel-core": "^5.4.7", 14 | "babel-eslint": "^3.1.9", 15 | "babel-loader": "^5.1.2", 16 | "eslint-plugin-react": "^2.3.0", 17 | "react-hot-loader": "^1.2.7", 18 | "webpack": "^1.9.6", 19 | "webpack-dev-server": "^1.8.2" 20 | }, 21 | "dependencies": { 22 | "react": "^0.13.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter4/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | publicPath: config.output.publicPath, 7 | hot: true, 8 | historyApiFallback: true 9 | }).listen(9000, 'localhost', function (err, result) { 10 | if (err) { 11 | console.log(err); 12 | } 13 | 14 | console.log('Listening at localhost:9000'); 15 | }); 16 | -------------------------------------------------------------------------------- /chapter4/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import BookStore from './BookStore'; 3 | 4 | React.render(, document.getElementById('root')); 5 | -------------------------------------------------------------------------------- /chapter4/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | devtool: 'eval', 6 | entry: [ 7 | 'webpack-dev-server/client?http://localhost:9000', 8 | 'webpack/hot/only-dev-server', 9 | './src/index' 10 | ], 11 | output: { 12 | path: path.join(__dirname, 'dist'), 13 | filename: 'bundle.js', 14 | publicPath: '/static/' 15 | }, 16 | plugins: [ 17 | new webpack.HotModuleReplacementPlugin(), 18 | new webpack.NoErrorsPlugin() 19 | ], 20 | resolve: { 21 | extensions: ['', '.js', '.jsx'] 22 | }, 23 | module: { 24 | loaders: [{ 25 | test: /\.jsx?$/, 26 | loaders: ['react-hot', 'babel'], 27 | include: path.join(__dirname, 'src') 28 | }] 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /chapter5/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /chapter5/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "jsx": true, 4 | "modules": true 5 | }, 6 | "env": { 7 | "browser": true, 8 | "node": true 9 | }, 10 | "parser": "babel-eslint", 11 | "rules": { 12 | "quotes": [2, "single"], 13 | "strict": [2, "never"], 14 | "react/jsx-uses-react": 2, 15 | "react/jsx-uses-vars": 2, 16 | "react/react-in-jsx-scope": 2 17 | }, 18 | "plugins": [ 19 | "react" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /chapter5/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /chapter5/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "newcap": false 6 | } 7 | -------------------------------------------------------------------------------- /chapter5/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter5/README.md: -------------------------------------------------------------------------------- 1 | react-forms 2 | =========== 3 | 4 | Examples of Forms in ReactJS 5 | 6 | ### Usage 7 | 8 | ``` 9 | npm install 10 | npm start 11 | open http://localhost:9000 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /chapter5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React Forms 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /chapter5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactjs-by-example-react-forms", 3 | "version": "0.0.1", 4 | "description": "ReactJS forms example", 5 | "scripts": { 6 | "start": "node server.js", 7 | "lint": "eslint src" 8 | }, 9 | "author": "Vipul A M (http://github.com/vipulnsward)", 10 | "license": "MIT", 11 | "homepage": "https://github.com/bigbinary/reactjs-by-example", 12 | "devDependencies": { 13 | "babel-core": "^5.4.7", 14 | "babel-eslint": "^3.1.9", 15 | "babel-loader": "^5.1.2", 16 | "css-loader": "^0.15.5", 17 | "eslint-plugin-react": "^2.3.0", 18 | "file-loader": "^0.8.4", 19 | "react-hot-loader": "^1.2.7", 20 | "style-loader": "^0.12.3", 21 | "webpack": "^1.10.1", 22 | "webpack-dev-server": "^1.8.2" 23 | }, 24 | "dependencies": { 25 | "bootstrap": "^3.3.5", 26 | "bootstrap-webpack": "0.0.3", 27 | "file-loader": "^0.8.4", 28 | "object-assign": "^4.0.1", 29 | "react": "^0.13.3", 30 | "url-loader": "^0.5.6" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter5/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | publicPath: config.output.publicPath, 7 | hot: true, 8 | historyApiFallback: true 9 | }).listen(9000, 'localhost', function (err, result) { 10 | if (err) { 11 | console.log(err); 12 | } 13 | 14 | console.log('Listening at localhost:9000'); 15 | }); 16 | -------------------------------------------------------------------------------- /chapter5/src/confirmation.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | var Confirmation = React.createClass({ 4 | handleSubmit(event) { 5 | event.preventDefault(); 6 | console.log("handleSubmit"); 7 | this.props.updateFormData(this.props.data); 8 | }, 9 | 10 | render() { 11 | return ( 12 |
13 |

Are you sure you want to submit the data?

14 |
15 |
16 | Full Name : { this.props.data.fullName } 17 |

18 |
19 | Contact Number : { this.props.data.contactNumber } 20 |

21 |
22 | Shipping Address : { this.props.data.shippingAddress } 23 |

24 |
25 | Selected books : { this.props.data.selectedBooks.join(", ") } 26 |

27 | 30 |
31 |
32 | ); 33 | } 34 | }); 35 | 36 | module.exports = Confirmation; 37 | -------------------------------------------------------------------------------- /chapter5/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import App from './App'; 3 | 4 | React.render(, document.getElementById('rootElement')); 5 | -------------------------------------------------------------------------------- /chapter5/src/mixins/cart_timeout_mixin.js: -------------------------------------------------------------------------------- 1 | var CartTimeoutMixin = { 2 | componentWillMount: function () { 3 | this.setInterval(this.decrementCartTimer, 1000); 4 | }, 5 | 6 | decrementCartTimer(){ 7 | if (this.state.cartTimeout == 0) { 8 | this.props.alertCartTimeout(); 9 | return; 10 | } 11 | this.setState({cartTimeout: this.state.cartTimeout - 1}); 12 | }, 13 | 14 | componentWillUnmount(){ 15 | this.props.updateCartTimeout(this.state.cartTimeout); 16 | } 17 | 18 | }; 19 | 20 | 21 | module.exports = CartTimeoutMixin; 22 | -------------------------------------------------------------------------------- /chapter5/src/mixins/set_interval_mixin.js: -------------------------------------------------------------------------------- 1 | var SetIntervalMixin = { 2 | componentWillMount: function() { 3 | this.intervals = []; 4 | }, 5 | setInterval: function() { 6 | this.intervals.push(setInterval.apply(null, arguments)); 7 | }, 8 | componentWillUnmount: function() { 9 | this.intervals.map(clearInterval); 10 | } 11 | }; 12 | 13 | 14 | module.exports = SetIntervalMixin; 15 | -------------------------------------------------------------------------------- /chapter5/src/modals/modal_alert_timeout.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | 4 | var ModalAlertTimeout = React.createClass({ 5 | componentDidMount(){ 6 | setTimeout(()=> { 7 | let timeoutModal = this.refs.timeoutModal.getDOMNode(); 8 | $(timeoutModal).modal('show'); 9 | $(timeoutModal).on('hidden.bs.modal', this.unMountComponent); 10 | }, 100); 11 | }, 12 | 13 | 14 | unMountComponent () { 15 | React.unmountComponentAtNode(this.getDOMNode().parentNode); 16 | }, 17 | 18 | render() { 19 | return ( 20 | 21 |
22 |
23 |
24 |
25 | 27 |

Timeout

28 |
29 |
30 |

The cart has timed-out. Please try again!

31 |
32 |
33 |
34 |
35 | ); 36 | } 37 | }); 38 | module.exports = ModalAlertTimeout; 39 | -------------------------------------------------------------------------------- /chapter5/src/success.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | var Success = React.createClass({ 4 | render() { 5 | var numberOfDays = "1 to 2 "; 6 | 7 | if (this.props.data.deliveryOption === 'Normal') { 8 | numberOfDays = "3 to 4 "; 9 | } 10 | return ( 11 |
12 |

13 | Thank you for shopping with us {this.props.data.fullName}. 14 |

15 |

16 | You will soon get {this.props.data.selectedBooks.join(", ")} at {this.props.data.shippingAddress} in approrximately {numberOfDays} days. 17 |

18 |
19 | ); 20 | } 21 | }); 22 | 23 | module.exports = Success; 24 | -------------------------------------------------------------------------------- /chapter6-iso/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /chapter6-iso/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | dist 29 | -------------------------------------------------------------------------------- /chapter6-iso/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "node": true, 4 | "browser": true, 5 | "bitwise": true, 6 | "camelcase": false, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "undef": true, 16 | "unused": true, 17 | "trailing": true, 18 | "smarttabs": true, 19 | "newcap": false, 20 | "globals": { 21 | "jest": false, 22 | "describe": false, 23 | "it": false, 24 | "expect": false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter6-iso/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M, RisingStack 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /chapter6-iso/README.md: -------------------------------------------------------------------------------- 1 | react-isomorphic 2 | =========== 3 | 4 | ## How to start 5 | 6 | Run: 7 | ``` 8 | npm install 9 | npm start 10 | ``` 11 | 12 | Check your http://localhost:3000/ or `open http://localhost:3000/` 13 | 14 | ## How to start code 15 | 16 | Run: 17 | `npm run webpack-watch` 18 | -------------------------------------------------------------------------------- /chapter6-iso/config/app.js: -------------------------------------------------------------------------------- 1 | var config = {}; 2 | 3 | config.title = 'Isomorphic App'; 4 | 5 | module.exports = config; 6 | -------------------------------------------------------------------------------- /chapter6-iso/src/app/__tests__/app.spec.js: -------------------------------------------------------------------------------- 1 | jest.dontMock('../app'); 2 | 3 | var App = require('../app'); 4 | var state = { 5 | cart: { 6 | title: 'title', 7 | items: [] 8 | } 9 | }; 10 | 11 | describe('App', function () { 12 | it('renders to string', function () { 13 | var app = new App({ state: state }); 14 | 15 | expect(typeof app.renderToString()).toBe('string'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /chapter6-iso/src/app/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react/addons'; 2 | 3 | import AppRoot from './components/AppRoot'; 4 | 5 | 6 | class App { 7 | 8 | constructor(options) { 9 | 10 | this.state = options.state; 11 | } 12 | 13 | render(element) { 14 | 15 | 16 | // would be in JSX: 17 | var appRootElement = ; 18 | 19 | // render to DOM 20 | if (element) { 21 | React.render(appRootElement, element); 22 | return; 23 | } 24 | 25 | // render to string 26 | return React.renderToString(appRootElement); 27 | } 28 | 29 | renderToDOM(element) { 30 | if (!element) { 31 | new Error('App.renderToDOM: element is required'); 32 | } 33 | 34 | this.render(element); 35 | } 36 | 37 | renderToString() { 38 | return this.render(); 39 | } 40 | } 41 | 42 | export default App; 43 | -------------------------------------------------------------------------------- /chapter6-iso/src/app/components/AppRoot.js: -------------------------------------------------------------------------------- 1 | require("jquery"); 2 | import React from 'react/addons'; 3 | import SearchPage from './SearchPage' 4 | import config from '../../../config/app'; 5 | 6 | var AppRoot = React.createClass({ 7 | propTypes: { 8 | state: React.PropTypes.object.isRequired // We can use state as needed ahead to initialize the App. 9 | }, 10 | render() 11 | { 12 | return ; 13 | } 14 | }) 15 | ; 16 | 17 | export default AppRoot; 18 | -------------------------------------------------------------------------------- /chapter6-iso/src/app/components/__tests__/AppRoot.spec.js: -------------------------------------------------------------------------------- 1 | jest.dontMock('../AppRoot'); 2 | 3 | import React from 'react/addons'; 4 | import AppRoot from '../AppRoot'; 5 | import Cart from '../Cart'; 6 | 7 | var TestUtils = React.addons.TestUtils; 8 | var state = { 9 | cart: { 10 | title: 'My Cart', 11 | items: [ 12 | { 13 | title: 'Item 1', 14 | price: 12 15 | }, 16 | { 17 | title: 'Item 2', 18 | price: 21 19 | }, 20 | { 21 | title: 'Item 3', 22 | price: 33 23 | } 24 | ] 25 | } 26 | }; 27 | 28 | describe('AppRoot', () => { 29 | 30 | it('renders properly', () => { 31 | var appRoot = TestUtils.renderIntoDocument( 32 | 33 | ); 34 | 35 | var title = TestUtils.findRenderedDOMComponentWithTag(appRoot, 'h1'); 36 | var carts = TestUtils.scryRenderedComponentsWithType(appRoot, Cart); 37 | 38 | expect(title.getDOMNode().textContent).toEqual('My React App'); 39 | expect(carts.length).toBe(1); 40 | expect(carts[0].props).toEqual({ 41 | cart: state.cart 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /chapter6-iso/src/app/components/__tests__/Cart.spec.js: -------------------------------------------------------------------------------- 1 | jest.dontMock('../Cart'); 2 | 3 | import React from 'react/addons'; 4 | import Cart from '../Cart'; 5 | import Item from '../Item'; 6 | 7 | var TestUtils = React.addons.TestUtils; 8 | var cartProp = { 9 | title: 'My Cart', 10 | items: [ 11 | { 12 | title: 'Item 1', 13 | price: 12 14 | }, 15 | { 16 | title: 'Item 2', 17 | price: 21 18 | }, 19 | { 20 | title: 'Item 3', 21 | price: 33 22 | } 23 | ] 24 | }; 25 | 26 | describe('Cart', () => { 27 | 28 | it('renders properly', () => { 29 | var cart = TestUtils.renderIntoDocument( 30 | 31 | ); 32 | 33 | var title = TestUtils.findRenderedDOMComponentWithTag(cart, 'h2'); 34 | var items = TestUtils.scryRenderedComponentsWithType(cart, Item); 35 | 36 | expect(title.getDOMNode().textContent).toEqual('My Cart'); 37 | expect(items.length).toBe(3); 38 | expect(items[0].props).toEqual({ 39 | item: cartProp.items[0] 40 | }); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /chapter6-iso/src/app/components/__tests__/Item.spec.js: -------------------------------------------------------------------------------- 1 | jest.dontMock('../Item'); 2 | 3 | import React from 'react/addons'; 4 | import Item from '../Item'; 5 | 6 | var TestUtils = React.addons.TestUtils; 7 | var itemProp = { 8 | title: 'Item 1', 9 | price: 12 10 | }; 11 | 12 | describe('Item', () => { 13 | 14 | it('renders properly', () => { 15 | var item = TestUtils.renderIntoDocument( 16 | 17 | ); 18 | 19 | var li = TestUtils.findRenderedDOMComponentWithTag(item, 'li'); 20 | 21 | expect(li.getDOMNode().textContent).toEqual('Item 1 - $12'); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /chapter6-iso/src/app/index.js: -------------------------------------------------------------------------------- 1 | import App from './app'; 2 | export default App; 3 | -------------------------------------------------------------------------------- /chapter6-iso/src/client/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Search 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | <%- reactOutput %> 15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /chapter6-iso/src/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Search 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /chapter6-iso/src/client/scripts/client.js: -------------------------------------------------------------------------------- 1 | import App from '../../app'; 2 | 3 | var attachElement = document.getElementById('app'); 4 | 5 | var state = {}; 6 | 7 | var app; 8 | 9 | 10 | // Create new app and attach to element 11 | app = new App({ 12 | state: state 13 | }); 14 | 15 | app.renderToDOM(attachElement); 16 | -------------------------------------------------------------------------------- /chapter6-iso/src/client/styles/main.css: -------------------------------------------------------------------------------- 1 | 2 | .appRoot { 3 | border: 2px solid blue; 4 | padding: 10px; 5 | } 6 | 7 | .cart { 8 | border: 2px solid red; 9 | padding: 10px; 10 | } 11 | .item { 12 | border: 2px solid green; 13 | padding: 10px; 14 | } 15 | 16 | ul { 17 | list-style: none; 18 | padding: 0; 19 | } 20 | 21 | li { 22 | margin: 5px 0 5px 0; 23 | } 24 | -------------------------------------------------------------------------------- /chapter6-iso/src/server/index.js: -------------------------------------------------------------------------------- 1 | require('babel/register'); 2 | 3 | module.exports = require('./server'); 4 | -------------------------------------------------------------------------------- /chapter6-iso/src/server/server.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import Express from 'express'; 3 | 4 | import AppRoot from '../app/components/AppRoot' 5 | import React from 'react/addons'; 6 | 7 | var app = Express(); 8 | var server; 9 | 10 | const PATH_STYLES = path.resolve(__dirname, '../client/styles'); 11 | const PATH_DIST = path.resolve(__dirname, '../../dist'); 12 | 13 | app.use('/styles', Express.static(PATH_STYLES)); 14 | app.use(Express.static(PATH_DIST)); 15 | 16 | app.get('/', (req, res) => { 17 | var reactAppContent = React.renderToString(); 18 | console.log(reactAppContent); 19 | res.render(path.resolve(__dirname, '../client/index.ejs'), {reactOutput: reactAppContent}); 20 | }); 21 | 22 | server = app.listen(process.env.PORT || 3000, () => { 23 | var port = server.address().port; 24 | 25 | console.log('Server is listening at %s', port); 26 | }); 27 | -------------------------------------------------------------------------------- /chapter6-iso/tools/preprocessor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var babel = require('babel-core'); 4 | 5 | module.exports = { 6 | process: function(src, filename) { 7 | // Ignore files other than .js, .es, .jsx or .es6 8 | if (!babel.canCompile(filename)) { 9 | return ''; 10 | } 11 | // Ignore all files within node_modules 12 | if (filename.indexOf('node_modules') === -1) { 13 | return babel.transform(src, {filename: filename}).code; 14 | } 15 | return src; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /chapter6-iso/webpack.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | 5 | 6 | module.exports = { 7 | entry: [path.resolve(__dirname, './src/client/scripts/client.js')], 8 | output: { 9 | path: path.resolve(__dirname, './dist'), 10 | filename: 'bundle.js' 11 | }, 12 | resolve: { 13 | extensions: ['', '.js', '.jsx'] 14 | }, 15 | plugins: [ 16 | new webpack.ProvidePlugin({ 17 | $: "jquery", 18 | jQuery: "jquery" 19 | }), 20 | new webpack.NoErrorsPlugin() 21 | ], 22 | module: { 23 | loaders: [ 24 | {test: /src\/.+.js$/, exclude: /node_modules/, loader: 'babel', include: path.join(__dirname, 'src')}, 25 | {test: /\.css$/, loader: "style-loader!css-loader"}, 26 | {test: /\.woff(\d+)?$/, loader: 'url?prefix=font/&limit=5000&mimetype=application/font-woff'}, 27 | {test: /\.ttf$/, loader: 'file?prefix=font/'}, 28 | {test: /\.eot$/, loader: 'file?prefix=font/'}, 29 | {test: /\.svg$/, loader: 'file?prefix=font/'}, 30 | {test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&minetype=application/font-woff"}, 31 | {test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader"} 32 | ] 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /chapter6-rails/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore database.yml file 15 | /config/database.yml 16 | 17 | # Ignore all logfiles and tempfiles. 18 | /log/*.log 19 | /tmp 20 | /db/backups 21 | public/uploads 22 | .idea 23 | *.DS_Store 24 | coverage 25 | .*swp 26 | /uploads/* 27 | -------------------------------------------------------------------------------- /chapter6-rails/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.2.2 2 | -------------------------------------------------------------------------------- /chapter6-rails/Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec unicorn -p $PORT -c ./config/unicorn.rb 2 | worker: bundle exec rake jobs:work 3 | -------------------------------------------------------------------------------- /chapter6-rails/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Search::Application.load_tasks 7 | -------------------------------------------------------------------------------- /chapter6-rails/app/admin/dashboard.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register_page "Dashboard" do 2 | 3 | menu priority: 1, label: proc { I18n.t("active_admin.dashboard") } 4 | 5 | content :title => proc { I18n.t("active_admin.dashboard") } do 6 | div :class => "blank_slate_container", :id => "dashboard_default_message" do 7 | span :class => "blank_slate" do 8 | span I18n.t("active_admin.dashboard_welcome.welcome") 9 | small I18n.t("active_admin.dashboard_welcome.call_to_action") 10 | end 11 | end 12 | 13 | # Here is an example of a simple dashboard with columns and panels. 14 | # 15 | # columns do 16 | # column do 17 | # panel "Recent Posts" do 18 | # ul do 19 | # Post.recent(5).map do |post| 20 | # li link_to(post.title, admin_post_path(post)) 21 | # end 22 | # end 23 | # end 24 | # end 25 | 26 | # column do 27 | # panel "Info" do 28 | # para "Welcome to ActiveAdmin." 29 | # end 30 | # end 31 | # end 32 | end # content 33 | end 34 | -------------------------------------------------------------------------------- /chapter6-rails/app/admin/user.rb: -------------------------------------------------------------------------------- 1 | ActiveAdmin.register User do 2 | 3 | permit_params :email, :password, :password_confirmation 4 | 5 | index do 6 | column :email 7 | column :current_sign_in_at 8 | column :last_sign_in_at 9 | column :sign_in_count 10 | end 11 | 12 | filter :email 13 | 14 | form do |f| 15 | f.inputs "Admin Details" do 16 | f.input :email 17 | f.input :password 18 | f.input :password_confirmation 19 | end 20 | f.actions 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/application_common.js: -------------------------------------------------------------------------------- 1 | //= require jquery 2 | //= require jquery_ujs 3 | //= require bootstrap-sprockets 4 | // 5 | //= require_tree ./common 6 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/application_desktop.js: -------------------------------------------------------------------------------- 1 | //= require react 2 | //= require react_ujs 3 | //= require components 4 | 5 | //= require ./application_common 6 | //= require_tree ./desktop 7 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/application_phone.js: -------------------------------------------------------------------------------- 1 | //= require ./application_common 2 | //= require_tree ./phone 3 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/common/active_admin.js: -------------------------------------------------------------------------------- 1 | #= require active_admin/base 2 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/common/bootstrap.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | $("a[rel~=popover], .has-popover").popover(); 4 | 5 | return $("a[rel~=tooltip], .has-tooltip").tooltip(); 6 | 7 | }); 8 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/components.js: -------------------------------------------------------------------------------- 1 | //= require_tree ./components 2 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter6-rails/app/assets/javascripts/components/.gitkeep -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/desktop/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter6-rails/app/assets/javascripts/desktop/.gitkeep -------------------------------------------------------------------------------- /chapter6-rails/app/assets/javascripts/phone/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter6-rails/app/assets/javascripts/phone/.gitkeep -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/application_common.scss: -------------------------------------------------------------------------------- 1 | @import "bootstrap-sprockets"; 2 | @import "bootstrap/custom"; 3 | 4 | @import "common/base"; 5 | @import "common/alerts"; 6 | 7 | @import "font-awesome-sprockets"; 8 | @import "font-awesome"; 9 | 10 | @import "bootstrap/devise_forms"; 11 | @import "environment/ribbon"; 12 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/application_desktop.scss: -------------------------------------------------------------------------------- 1 | /* 2 | *= require ./application_common 3 | *= require_tree ./desktop 4 | */ 5 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/application_phone.scss: -------------------------------------------------------------------------------- 1 | /* 2 | *= require ./application_common 3 | *= require_tree ./phone 4 | */ 5 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/common/active_admin.scss: -------------------------------------------------------------------------------- 1 | // SASS variable overrides must be declared before loading up Active Admin's styles. 2 | // 3 | // To view the variables that Active Admin provides, take a look at 4 | // `app/assets/stylesheets/active_admin/mixins/_variables.css.scss` in the 5 | // Active Admin source. 6 | // 7 | // For example, to change the sidebar width: 8 | // $sidebar-width: 242px; 9 | 10 | // Active Admin's got SASS! 11 | @import "active_admin/mixins"; 12 | @import "active_admin/base"; 13 | 14 | 15 | // Overriding any non-variable SASS must be done after the fact. 16 | // For example, to change the default status-tag color: 17 | // 18 | // .status_tag { background: #6090DB; } 19 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/common/alerts.scss: -------------------------------------------------------------------------------- 1 | .alert { 2 | margin: 10px 0; 3 | font-weight: bold; 4 | position: relative; 5 | padding-left: 40px; 6 | &:after { 7 | position: absolute; 8 | font: normal normal normal 18px/1 FontAwesome; 9 | left: 16px; 10 | top: 16px; 11 | width: 16px; 12 | height: 16px; 13 | } 14 | } 15 | 16 | .alert-success { 17 | border-color: #98CF6A; 18 | &:after { 19 | color: #48cf36; 20 | content: "\f00c"; 21 | text-shadow: 1px 1px 0px #6D924E; 22 | } 23 | } 24 | 25 | .alert-danger { 26 | border-color: #ebb6bf; 27 | color: #CA3532; 28 | &:after { 29 | content: "\f057"; 30 | } 31 | } 32 | 33 | .alert-warning { 34 | background-color: #F9F3DD; 35 | border-color: #E9D5AC; 36 | color: #b97a38; 37 | &:after { 38 | content: "\f071"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/common/base.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | min-height: 100%; 3 | height:100% 4 | } 5 | 6 | .navbar { 7 | margin-bottom: 0; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/desktop/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter6-rails/app/assets/stylesheets/desktop/.gitkeep -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/environment/ribbon.scss: -------------------------------------------------------------------------------- 1 | body.orange_ribbon { 2 | &:before { 3 | content: ''; 4 | display: block; 5 | width: 100%; 6 | height: 4px; 7 | background: orangered; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter6-rails/app/assets/stylesheets/phone/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter6-rails/app/assets/stylesheets/phone/.gitkeep -------------------------------------------------------------------------------- /chapter6-rails/app/carriers/layout_carrier.rb: -------------------------------------------------------------------------------- 1 | class LayoutCarrier 2 | 3 | def class_for_body 4 | if Rails.env.production? 5 | #noop 6 | else 7 | 'orange_ribbon' 8 | end 9 | end 10 | 11 | end 12 | -------------------------------------------------------------------------------- /chapter6-rails/app/controllers/api/v1/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class Api::V1::SessionsController < Api::V1::BaseController 2 | 3 | skip_before_action :authenticate_user! 4 | skip_before_action :authenticate_user_using_x_auth_token 5 | 6 | def create 7 | user = User.find_for_database_authentication(email: params[:user] && params[:user][:email]) 8 | if invalid_password?(user) 9 | respond_with_error "Incorrect email or password", 401 10 | else 11 | render json: { auth_token: user.authentication_token }, location: root_path, status: :created 12 | end 13 | end 14 | 15 | private 16 | 17 | def invalid_password? user 18 | user.blank? || !user.valid_password?(params[:user][:password]) 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /chapter6-rails/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | 3 | # Prevent CSRF attacks by raising an exception. 4 | # For APIs, you may want to use :null_session instead. 5 | protect_from_forgery with: :exception 6 | 7 | before_action :set_honeybadger_context 8 | before_action :set_device_type 9 | before_action :set_layout_carrier 10 | 11 | private 12 | 13 | def ensure_current_user_is_superadmin! 14 | authenticate_user! 15 | 16 | unless current_user.super_admin? 17 | redirect_to root_path, status: :forbidden, alert: "Unauthorized Access!" 18 | end 19 | end 20 | 21 | def set_device_type 22 | request.variant = :phone if browser.mobile? 23 | end 24 | 25 | def set_honeybadger_context 26 | hash = { uuid: request.uuid } 27 | hash.merge!(user_id: current_user.id, user_email: current_user.email) if current_user 28 | Honeybadger.context hash 29 | end 30 | 31 | def set_layout_carrier 32 | @layout_carrier = LayoutCarrier.new 33 | end 34 | 35 | end 36 | -------------------------------------------------------------------------------- /chapter6-rails/app/controllers/contacts_controller.rb: -------------------------------------------------------------------------------- 1 | class ContactsController < ApplicationController 2 | 3 | def create 4 | @contact = Contact.new(params[:contact]) 5 | 6 | if @contact.valid? 7 | Mailer.delay.contact_us_notification(@contact) 8 | flash[:notice] = 'Thank you for your message. We will contact you soon!' 9 | redirect_to pages_contact_us_path 10 | else 11 | render template: 'pages/contact_us' 12 | end 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /chapter6-rails/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | class HomeController < ApplicationController 2 | 3 | def index 4 | render 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /chapter6-rails/app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | class PagesController < ApplicationController 2 | 3 | def index 4 | render 5 | end 6 | 7 | def contact_us 8 | @contact = Contact.new 9 | end 10 | 11 | def about 12 | render 13 | end 14 | 15 | end 16 | -------------------------------------------------------------------------------- /chapter6-rails/app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < Devise::SessionsController 2 | 3 | def destroy 4 | super 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /chapter6-rails/app/controllers/superadmin/base_controller.rb: -------------------------------------------------------------------------------- 1 | class Superadmin::BaseController < ApplicationController 2 | 3 | before_action :ensure_current_user_is_superadmin! 4 | 5 | layout 'superadmin' 6 | 7 | end 8 | -------------------------------------------------------------------------------- /chapter6-rails/app/controllers/superadmin/users_controller.rb: -------------------------------------------------------------------------------- 1 | class Superadmin::UsersController < Superadmin::BaseController 2 | 3 | before_action :load_user, only: [:edit, :update] 4 | 5 | def index 6 | @users = User.order('id desc') 7 | end 8 | 9 | def edit 10 | @user_name = @user.name 11 | 12 | render partial: 'edit_modal' 13 | end 14 | 15 | def update 16 | @user_name = @user.name 17 | @user.update(user_params) 18 | if @user.valid? 19 | flash[:notice] = "Information for user #{@user.name} successfully updated!" 20 | render json: { redirect_to: superadmin_users_path } 21 | else 22 | render json: { modal_content: render_to_string(partial: 'edit_modal') } 23 | end 24 | end 25 | 26 | private 27 | 28 | def load_user 29 | @user ||= User.find(params[:id]) 30 | end 31 | 32 | def user_params 33 | params.require(:user).permit(:first_name, :last_name, :profile_image, :email) 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /chapter6-rails/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | 3 | def super_admin_signed_in? 4 | user_signed_in? && current_user.super_admin? 5 | end 6 | 7 | def nav_link text, path, condition = false, options = {} 8 | class_name = (current_page?(path) || condition) ? 'active' : '' 9 | 10 | content_tag(:li, class: class_name) do 11 | options[:title] = text unless options.has_key?(:title) 12 | link_to text, path, options 13 | end 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /chapter6-rails/app/mailers/mailer.rb: -------------------------------------------------------------------------------- 1 | class Mailer < ActionMailer::Base 2 | 3 | layout 'mailer' 4 | 5 | default from: Rails.application.secrets.mailer_default_from_email 6 | 7 | default_url_options[:host] = Rails.application.secrets.host 8 | 9 | def contact_us_notification(contact) 10 | @email = contact.email 11 | @title = contact.title 12 | @body = contact.body 13 | subject = "Contact us message from #{@email}" 14 | 15 | mail(to: Rails.application.secrets.support_email, from: @email, subject: subject) do |format| 16 | format.html 17 | end 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /chapter6-rails/app/middleware/catch_json_parse_errors.rb: -------------------------------------------------------------------------------- 1 | class CatchJsonParseErrors 2 | 3 | def initialize app 4 | @app = app 5 | end 6 | 7 | def call env 8 | begin 9 | @app.call(env) 10 | rescue ActionDispatch::ParamsParser::ParseError => exception 11 | is_content_type_json?(env) ? build_response(exception) : raise(exception) 12 | end 13 | end 14 | 15 | private 16 | 17 | def is_content_type_json? env 18 | env['CONTENT_TYPE'] =~ /application\/json/ 19 | end 20 | 21 | def error_message exception 22 | "Payload data is not valid JSON. Error message: #{exception}" 23 | end 24 | 25 | def build_response exception 26 | [ 400, { "Content-Type" => "application/json" }, [ { error: error_message(exception) }.to_json ] ] 27 | end 28 | 29 | end 30 | -------------------------------------------------------------------------------- /chapter6-rails/app/models/contact.rb: -------------------------------------------------------------------------------- 1 | class Contact 2 | include ActiveModel::Model 3 | 4 | attr_accessor :email, :title, :body 5 | 6 | validates :email, :title, presence: true 7 | validates :email, email: true 8 | end 9 | -------------------------------------------------------------------------------- /chapter6-rails/app/services/addition_service.rb: -------------------------------------------------------------------------------- 1 | class AdditionService 2 | 3 | attr_reader :number1, :number2 4 | 5 | def initialize number1, number2 6 | @number1 = number1 7 | @number2 = number2 8 | end 9 | 10 | def process 11 | number1 + number2 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /chapter6-rails/app/uploaders/profile_image_uploader.rb: -------------------------------------------------------------------------------- 1 | class ProfileImageUploader < CarrierWave::Uploader::Base 2 | 3 | storage :file 4 | 5 | def store_dir 6 | "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" 7 | end 8 | 9 | def extension_white_list 10 | %w(jpg jpeg png) 11 | end 12 | 13 | def filename 14 | if original_filename.present? 15 | if model && model.read_attribute(mounted_as).present? 16 | model.read_attribute(mounted_as) 17 | else 18 | "#{secure_token}.#{file.extension}" 19 | end 20 | end 21 | end 22 | 23 | protected 24 | 25 | def secure_token 26 | var = :"@#{mounted_as}_secure_token" 27 | model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid) 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/home/index.html.haml: -------------------------------------------------------------------------------- 1 | %span.home-message 2 | = react_component 'SearchPage', {}, {prerender: true} 3 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/mailer/contact_us_notification.html.haml: -------------------------------------------------------------------------------- 1 | %h3 New contact 2 | %p 3 | %b Email: 4 | = @email 5 | %p 6 | %b Title: 7 | = @title 8 | %p 9 | %b Message: 10 | = @body 11 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/pages/about.html+phone.haml: -------------------------------------------------------------------------------- 1 | You are seeing the phone version of the about page. 2 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/pages/about.html.haml: -------------------------------------------------------------------------------- 1 | You are seeing the desktop version of the about page. 2 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/pages/contact_us.html.haml: -------------------------------------------------------------------------------- 1 | .row{style: "padding-top: 10px;"} 2 | = simple_form_for @contact, html: { class: 'bootstrap-center-form-medium' } do |f| 3 | %h2 Contact us 4 | .form-controls 5 | = f.input :title, required: true, input_html: { class: 'form-control' } 6 | .form-controls 7 | = f.input :email, required: true, input_html: { class: 'form-control' } 8 | .form-controls 9 | = f.input :body, as: :text, input_html: { class: 'form-control', rows: '3' } 10 | .form-buttons 11 | = f.button :submit, 'Send message', class: "btn btn-primary" 12 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/pages/index.html.haml: -------------------------------------------------------------------------------- 1 | Listing of All Pages 2 | %br/ 3 | = link_to "Contact US", pages_contact_us_path 4 | %br/ 5 | = link_to "About", pages_about_path 6 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/shared/_bootstrap_flash.html.haml: -------------------------------------------------------------------------------- 1 | - flash.each do |name, message| 2 | - if message.present? 3 | %div{class: "alert alert-#{name.to_s == 'alert' ? "danger" : "success"}"} 4 | %a.close{"data-dismiss" => "alert"} × 5 | = content_tag :div, message, id: "flash_#{name}" if message.is_a?(String) 6 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/shared/_modal.html.haml: -------------------------------------------------------------------------------- 1 | %div{class: "modal", "data-behavior" => "modal-content"} 2 | .modal-dialog 3 | .modal-content 4 | .modal-header 5 | = button_tag '×', :class => "close btn-close-dialog", "data-behavior" => "modal-close", "aria-hidden" => "true" 6 | %h4.modal-title= yield(:modal_title) 7 | .modal-body 8 | = yield(:modal_body) 9 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/shared/_nav.html.haml: -------------------------------------------------------------------------------- 1 | %ul.nav.navbar-nav 2 | = nav_link 'Home', root_path 3 | = nav_link 'About', pages_about_path 4 | = nav_link 'Contact us', pages_contact_us_path 5 | = render('shared/user_right_nav') 6 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/shared/_superadmin_nav.html.haml: -------------------------------------------------------------------------------- 1 | %ul.nav.navbar-nav 2 | = nav_link('Users', superadmin_users_path) 3 | = nav_link("Active Admin", active_admin_root_path) 4 | = nav_link('DJ', '/delayed_job', false, "target" => '_blank') 5 | = render('shared/user_right_nav') 6 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/shared/_user_is_signed_in.html.haml: -------------------------------------------------------------------------------- 1 | %li.dropdown 2 | %a.dropdown-toggle{"data-toggle" => "dropdown", :href => "#"} 3 | = current_user.name 4 | %b.caret 5 | %ul.dropdown-menu 6 | - if super_admin_signed_in? 7 | = nav_link 'Superadmin', superadmin_root_path 8 | %li.divider 9 | = nav_link 'My account', profile_path 10 | = nav_link 'Change password', password_edit_path 11 | = nav_link 'Logout', destroy_user_session_path, false, method: :delete 12 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/shared/_user_right_nav.html.haml: -------------------------------------------------------------------------------- 1 | %ul.nav.navbar-nav.navbar-right 2 | - if user_signed_in? 3 | = render 'shared/user_is_signed_in' 4 | - else 5 | = nav_link 'Sign in', new_session_path(:user) 6 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/superadmin/users/_edit_modal.html.haml: -------------------------------------------------------------------------------- 1 | = content_for(:modal_title) do 2 | Edit #{@user_name.to_s.humanize} 3 | 4 | = content_for(:modal_body) do 5 | .row{style: "padding-top: 10px;"} 6 | = simple_form_for(@user, url: superadmin_user_path(@user), | 7 | method: :patch, | 8 | wrapper: :bootstrap3, | 9 | html: { method: :put, class: 'bootstrap-center-form-medium' }) do |f| | 10 | .form-controls 11 | = f.input :email, required: true, | 12 | autofocus: true, | 13 | input_html: { class: 'form-control' } | 14 | = f.input :first_name, required: true, input_html: { class: 'form-control' } 15 | = f.input :last_name, required: true, input_html: { class: 'form-control' } 16 | = f.input :profile_image, as: :file 17 | .form-buttons 18 | = f.button :submit, "Update", class: 'btn btn-primary' 19 | 20 | 21 | = render "shared/modal" 22 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/superadmin/users/index.html.haml: -------------------------------------------------------------------------------- 1 | %table.table.table-striped 2 | %thead 3 | %tr 4 | %th Name 5 | %th Email 6 | %th Last signed in 7 | %th 8 | - @users.each do |user| 9 | %tr 10 | %td 11 | = user.name 12 | %td 13 | = user.email 14 | %td 15 | = user.last_sign_in_at 16 | %td 17 | = link_to 'Edit', "#", data: { url: edit_superadmin_user_path(user), behavior: 'display-in-modal' } 18 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/confirmations/new.html.haml: -------------------------------------------------------------------------------- 1 | %h2 Resend confirmation instructions 2 | = simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| 3 | = f.error_notification 4 | = f.full_error :confirmation_token 5 | .form-inputs 6 | = f.input :email, required: true, autofocus: true 7 | .form-actions 8 | = f.button :submit, "Resend confirmation instructions" 9 | = render "users/shared/links" 10 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/mailer/confirmation_instructions.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Welcome #{@email}! 3 | %p You can confirm your account email through the link below: 4 | %p= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) 5 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/mailer/reset_password_instructions.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Hello #{@resource.email}! 3 | %p Someone has requested a link to change your password. You can do this through the link below. 4 | %p= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) 5 | 6 | %p If you didn't request this, please ignore this email. 7 | %p Your password won't change until you access the link above and create a new one. 8 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/mailer/unlock_instructions.html.haml: -------------------------------------------------------------------------------- 1 | %p 2 | Hello #{@resource.email}! 3 | %p Your account has been locked due to an excessive number of unsuccessful sign in attempts. 4 | %p Click the link below to unlock your account: 5 | %p= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) 6 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/passwords/new.html.haml: -------------------------------------------------------------------------------- 1 | .row{style: "padding-top: 10px;"} 2 | = simple_form_for(resource, as: resource_name, | 3 | url: password_path(resource_name), | 4 | wrapper: :bootstrap3, | 5 | html: { method: :post, class: 'bootstrap-center-form-medium' }) do |f| | 6 | %h2 Forgot your password? 7 | .form-controls 8 | = f.input :email, required: true, autofocus: true, input_html: { class: 'form-control' } 9 | .form-buttons 10 | = f.button :submit, "Send me reset password instructions", class: 'btn btn-primary' 11 | .devise-links 12 | = render "users/shared/links" 13 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/registrations/new.html.haml: -------------------------------------------------------------------------------- 1 | .row{style: "padding-top: 10px;"} 2 | = simple_form_for(resource, as: resource_name, | 3 | url: registration_path(resource_name), | 4 | wrapper: :bootstrap3, | 5 | html: { class: 'bootstrap-center-form-medium' }) do |f| | 6 | %h2 Sign up 7 | .form-controls 8 | = f.input :email, required: true, autofocus: true, input_html: { class: 'form-control' } 9 | = f.input :first_name, required: true, input_html: { class: 'form-control' } 10 | = f.input :last_name, required: true, input_html: { class: 'form-control' } 11 | = f.input :password, required: true, input_html: { class: 'form-control' } 12 | = f.input :password_confirmation, required: true, input_html: { class: 'form-control' } 13 | .form-buttons 14 | = f.button :submit, "Sign up", class: 'btn btn-primary' 15 | .devise-links 16 | = render "users/shared/links" 17 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/sessions/new.html.haml: -------------------------------------------------------------------------------- 1 | .row{style: "padding-top: 10px;"} 2 | = simple_form_for(resource, as: resource_name, | 3 | url: session_path(resource_name), | 4 | wrapper: :bootstrap3, | 5 | html: { class: 'bootstrap-center-form-medium' }) do |f| | 6 | %h2 Please Sign in 7 | .form-controls 8 | = f.input :email, placeholder: 'Email address', label: false, autofocus: true, input_html: { class: 'form-control' } 9 | = f.input :password, placeholder: 'Password', label: false, input_html: { class: 'form-control' } 10 | - if devise_mapping.rememberable? 11 | = f.input :remember_me, as: :boolean, wrapper: :default 12 | .form-buttons 13 | = f.button :submit, "Sign in", class: 'btn btn-primary' 14 | .devise-links 15 | = render "users/shared/links" 16 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/shared/_links.haml: -------------------------------------------------------------------------------- 1 | - if controller_name != 'sessions' 2 | = link_to "Sign in", new_session_path(resource_name) 3 | %br/ 4 | - if devise_mapping.registerable? && controller_name != 'registrations' 5 | = link_to "Sign up", new_registration_path(resource_name) 6 | %br/ 7 | - if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' 8 | = link_to "Forgot your password?", new_password_path(resource_name) 9 | %br/ 10 | - if devise_mapping.confirmable? && controller_name != 'confirmations' 11 | = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) 12 | %br/ 13 | - if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' 14 | = link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) 15 | %br/ 16 | - if devise_mapping.omniauthable? 17 | - resource_class.omniauth_providers.each do |provider| 18 | = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) 19 | %br/ 20 | -------------------------------------------------------------------------------- /chapter6-rails/app/views/users/unlocks/new.html.haml: -------------------------------------------------------------------------------- 1 | %h2 Resend unlock instructions 2 | = form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| 3 | = devise_error_messages! 4 | %div 5 | = f.label :email 6 | %br/ 7 | = f.email_field :email, autofocus: true 8 | %div 9 | = f.submit "Resend unlock instructions" 10 | = render "users/shared/links" 11 | -------------------------------------------------------------------------------- /chapter6-rails/app/workers/base_worker.rb: -------------------------------------------------------------------------------- 1 | class BaseWorker 2 | 3 | def perform 4 | Honeybadger.context(job_name: self.class.name, app_name: Rails.application.engine_name) 5 | end 6 | 7 | end 8 | -------------------------------------------------------------------------------- /chapter6-rails/app/workers/event_notification_worker.rb: -------------------------------------------------------------------------------- 1 | class EventNotificationWorker < BaseWorker 2 | 3 | def perform 4 | super 5 | 6 | # do the business stuff 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /chapter6-rails/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /chapter6-rails/bin/delayed_job: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) 4 | require 'delayed/command' 5 | Delayed::Command.new(ARGV).daemonize 6 | -------------------------------------------------------------------------------- /chapter6-rails/bin/honeybadger: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) 4 | require 'honeybadger/cli' 5 | Honeybadger::CLI.start(ARGV) 6 | -------------------------------------------------------------------------------- /chapter6-rails/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../../config/application', __FILE__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /chapter6-rails/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /chapter6-rails/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /chapter6-rails/bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast 4 | # It gets overwritten when you run the `spring binstub` command 5 | 6 | unless defined?(Spring) 7 | require "rubygems" 8 | require "bundler" 9 | 10 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ spring \((.*?)\)$.*?^$/m) 11 | ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR) 12 | ENV["GEM_HOME"] = "" 13 | Gem.paths = ENV 14 | 15 | gem "spring", match[1] 16 | require "spring/binstub" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /chapter6-rails/circle.yml: -------------------------------------------------------------------------------- 1 | ## Customize the test machine 2 | machine: 3 | 4 | timezone: 5 | America/New_York # List of timezones http://en.wikipedia.org/wiki/List_of_tz_database_time_zones 6 | 7 | # Version of ruby to use 8 | ruby: 9 | version: 10 | 2.2.2 11 | 12 | ## Customize database setup 13 | database: 14 | override: 15 | # replace Circle's generated database.yml 16 | - cp config/database.yml.ci config/database.yml 17 | - bundle exec rake db:create db:schema:load --trace 18 | 19 | test: 20 | minitest_globs: 21 | - test/**/*_test.rb 22 | -------------------------------------------------------------------------------- /chapter6-rails/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /chapter6-rails/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /chapter6-rails/config/database.yml.ci: -------------------------------------------------------------------------------- 1 | test: 2 | host: localhost 3 | username: ubuntu 4 | database: circle_ruby_test 5 | adapter: postgresql 6 | -------------------------------------------------------------------------------- /chapter6-rails/config/database.yml.postgresql: -------------------------------------------------------------------------------- 1 | <% branch_name = `git symbolic-ref HEAD 2>/dev/null`.chomp.sub('refs/heads/', '') %> 2 | <% repository_name = `git rev-parse --show-toplevel`.split('/').last.strip %> 3 | 4 | development: 5 | adapter: postgresql 6 | encoding: unicode 7 | database: <%= repository_name %>_development 8 | pool: 5 9 | username: postgres 10 | password: 11 | 12 | test: 13 | adapter: postgresql 14 | encoding: unicode 15 | database: <%= repository_name %>_test 16 | pool: 5 17 | username: postgres 18 | password: 19 | -------------------------------------------------------------------------------- /chapter6-rails/config/database.yml.postgresqlapp: -------------------------------------------------------------------------------- 1 | <% branch_name = `git symbolic-ref HEAD 2>/dev/null`.chomp.sub('refs/heads/', '') %> 2 | <% repository_name = `git rev-parse --show-toplevel`.split('/').last.strip %> 3 | 4 | # Check doc/why_database_name_only_63_characters_long.md to see 5 | # details about the restriction on database name 6 | 7 | # If you prefer to have branch name in the database name then use following 8 | # database: <%= "#{repository_name}_development_#{branch_name}"[0...63] %> 9 | 10 | development: 11 | adapter: postgresql 12 | database: <%= "#{repository_name}_development"[0...63] %> 13 | host: localhost 14 | 15 | test: 16 | adapter: postgresql 17 | database: <%= "#{repository_name}_test"[0...63] %> 18 | host: localhost 19 | -------------------------------------------------------------------------------- /chapter6-rails/config/database.yml.sqlite3: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /chapter6-rails/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /chapter6-rails/config/honeybadger.yml: -------------------------------------------------------------------------------- 1 | --- 2 | api_key: <%= Rails.application.secrets.honeybadger_api_key %> 3 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/asset_precompile.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.assets.precompile += [ 'application_desktop.css', 2 | 'application_phone.css', 3 | 'application_desktop.js', 4 | 'application_phone.js'] 5 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Precompile additional assets. 7 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 8 | Rails.application.config.assets.precompile += %w( common/active_admin.css ) 9 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/catch_json_parser_errors.rb: -------------------------------------------------------------------------------- 1 | unless Rails.env.development? 2 | Rails.application.config.middleware.insert_before ActionDispatch::ParamsParser, "CatchJsonParseErrors" 3 | end 4 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/delayed_job_config.rb: -------------------------------------------------------------------------------- 1 | Delayed::Worker.destroy_failed_jobs = false 2 | 3 | # Amount of time to sleep when no jobs are found. You can easily set it to 5 seconds or less. 4 | Delayed::Worker.sleep_delay = 5 5 | 6 | # If the work takes more than x minutes then DJ will abort 7 | Delayed::Worker.max_run_time = 5.minutes 8 | 9 | Delayed::Worker.read_ahead = 10 10 | 11 | Delayed::Worker.delay_jobs = !Rails.env.test? 12 | 13 | # In production have default number of attempts ( which I think is 30 ) 14 | if !Rails.env.production? 15 | Delayed::Worker.max_attempts = 3 16 | end 17 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/devise_async.rb: -------------------------------------------------------------------------------- 1 | Devise::Async.setup do |config| 2 | config.backend = :delayed_job 3 | config.priority = -1 4 | end -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/email_interceptor.rb: -------------------------------------------------------------------------------- 1 | if Rails.application.secrets.intercept_and_forward_emails_to.present? 2 | options = { forward_emails_to: Rails.application.secrets.intercept_and_forward_emails_to, 3 | deliver_emails_to: ['@example.com'] } 4 | 5 | interceptor = MailInterceptor::Interceptor.new(options) 6 | ActionMailer::Base.register_interceptor(interceptor) 7 | end 8 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/email_prefixer.rb: -------------------------------------------------------------------------------- 1 | EmailPrefixer.configure do |config| 2 | config.stage_name = 'Search' 3 | end 4 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/honeybadger.rb: -------------------------------------------------------------------------------- 1 | # When a DelayedJob operation fails then honeybadger should collect 2 | # contextual information like job name and the host. 3 | class HoneybadgerDelayedJobPlugin < Delayed::Plugin 4 | callbacks do |lifecycle| 5 | lifecycle.before(:invoke_job) do |job, *args, &block| 6 | Honeybadger.context(job_name: job.name, host: Rails.application.secrets.host) 7 | end 8 | end 9 | end 10 | 11 | Delayed::Worker.plugins << HoneybadgerDelayedJobPlugin 12 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/marginalia.rb: -------------------------------------------------------------------------------- 1 | Marginalia.application_name = 'Search' 2 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/rack_deflater.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.middleware.use Rack::Deflater 2 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_Search_session' 4 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/setup_email.rb: -------------------------------------------------------------------------------- 1 | ActionMailer::Base.default_url_options[:host] = Rails.application.secrets.host 2 | 3 | ActionMailer::Base.delivery_method = Rails.application.secrets.mailer_delivery_method 4 | 5 | if ActionMailer::Base.delivery_method == :smtp 6 | ActionMailer::Base.smtp_settings = Rails.application.secrets.mailer['smtp_settings'].symbolize_keys 7 | end 8 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/tagged_logging.rb: -------------------------------------------------------------------------------- 1 | Rails.application.config.log_tags = [ :subdomain, :uuid ] 2 | -------------------------------------------------------------------------------- /chapter6-rails/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /chapter6-rails/config/locales/en.bootstrap.yml: -------------------------------------------------------------------------------- 1 | # Sample localization file for English. Add more files in this directory for other locales. 2 | # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. 3 | 4 | en: 5 | helpers: 6 | actions: "Actions" 7 | links: 8 | back: "Back" 9 | cancel: "Cancel" 10 | confirm: "Are you sure?" 11 | destroy: "Delete" 12 | new: "New" 13 | edit: "Edit" 14 | titles: 15 | edit: "Edit %{model}" 16 | save: "Save %{model}" 17 | new: "New %{model}" 18 | delete: "Delete %{model}" 19 | -------------------------------------------------------------------------------- /chapter6-rails/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /chapter6-rails/config/locales/simple_form.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | simple_form: 3 | "yes": 'Yes' 4 | "no": 'No' 5 | required: 6 | text: 'required' 7 | mark: '*' 8 | # You can uncomment the line below if you need to overwrite the whole required html. 9 | # When using html, text and mark won't be used. 10 | # html: '*' 11 | error_notification: 12 | default_message: "Please review the problems below:" 13 | # Labels and hints examples 14 | # labels: 15 | # defaults: 16 | # password: 'Password' 17 | # user: 18 | # new: 19 | # email: 'E-mail to sign in.' 20 | # edit: 21 | # email: 'E-mail.' 22 | # hints: 23 | # defaults: 24 | # username: 'User name to sign in.' 25 | # password: 'No special characters, please.' 26 | 27 | -------------------------------------------------------------------------------- /chapter6-rails/config/unicorn.rb: -------------------------------------------------------------------------------- 1 | # this template has been picked up from 2 | # https://devcenter.heroku.com/articles/rails-unicorn 3 | 4 | worker_processes Integer(ENV["WEB_CONCURRENCY"] || 2) 5 | 6 | # 30 seconds is the timeout for heroku. If it is not 7 | # deployed on heroku then it can be bumped up. 8 | timeout 30 9 | 10 | preload_app true 11 | 12 | before_fork do |server, worker| 13 | Signal.trap 'TERM' do 14 | puts 'Unicorn master intercepting TERM and sending myself QUIT instead' 15 | Process.kill 'QUIT', Process.pid 16 | end 17 | 18 | defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! 19 | end 20 | 21 | after_fork do |server, worker| 22 | Signal.trap 'TERM' do 23 | puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT' 24 | end 25 | 26 | defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection 27 | end 28 | -------------------------------------------------------------------------------- /chapter6-rails/db/migrate/20131112184628_add_devise_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddDeviseToUsers < ActiveRecord::Migration 2 | def self.up 3 | create_table(:users) do |t| 4 | ## Database authenticatable 5 | t.string :email, :null => false, :default => "" 6 | t.string :encrypted_password, :null => false, :default => "" 7 | 8 | ## Recoverable 9 | t.string :reset_password_token 10 | t.datetime :reset_password_sent_at 11 | 12 | ## Rememberable 13 | t.datetime :remember_created_at 14 | 15 | ## Trackable 16 | t.integer :sign_in_count, :default => 0, :null => false 17 | t.datetime :current_sign_in_at 18 | t.datetime :last_sign_in_at 19 | t.string :current_sign_in_ip 20 | t.string :last_sign_in_ip 21 | 22 | t.timestamps 23 | end 24 | 25 | add_index :users, :email, :unique => true 26 | add_index :users, :reset_password_token, :unique => true 27 | # add_index :users, :confirmation_token, :unique => true 28 | # add_index :users, :unlock_token, :unique => true 29 | end 30 | 31 | def self.down 32 | drop_table :users 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /chapter6-rails/db/migrate/20131122045009_add_user_attributes.rb: -------------------------------------------------------------------------------- 1 | class AddUserAttributes < ActiveRecord::Migration 2 | def change 3 | add_column :users, :last_name, :string 4 | add_column :users, :first_name, :string 5 | add_column :users, :role, :string, default: 'standard' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /chapter6-rails/db/migrate/20131213184726_create_active_admin_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateActiveAdminComments < ActiveRecord::Migration 2 | def self.up 3 | create_table :active_admin_comments do |t| 4 | t.string :namespace 5 | t.text :body 6 | t.string :resource_id, :null => false 7 | t.string :resource_type, :null => false 8 | t.references :author, :polymorphic => true 9 | t.timestamps 10 | end 11 | add_index :active_admin_comments, [:namespace] 12 | add_index :active_admin_comments, [:author_type, :author_id] 13 | add_index :active_admin_comments, [:resource_type, :resource_id] 14 | end 15 | 16 | def self.down 17 | drop_table :active_admin_comments 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /chapter6-rails/db/migrate/20140220111712_add_authentication_token_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAuthenticationTokenToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :authentication_token, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /chapter6-rails/db/migrate/20140225143027_add_profile_image_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddProfileImageToUsers < ActiveRecord::Migration 2 | def change 3 | add_column :users, :profile_image, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /chapter6-rails/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /chapter6-rails/doc/why_database_name_only_63_characters_long.md: -------------------------------------------------------------------------------- 1 | ### Why length of table name is limited to 63 characters long? 2 | 3 | The default limit on length of identifiers in PostGreSQL is 63 because 4 | value of `NAMEDATALEN` constant is 64 by default. The length of identifiers 5 | is `NAMEDATALEN - 1` which becomes `64 - 1` equal to 63. 6 | 7 | This configuration can't be changed without compiling PostGreSQL again. 8 | We use name of the repository and name of branch to dynamically 9 | calculate database name for every branch. But if the length of this 10 | combination becomes greater than 63 then it gives error: 11 | 12 | ``` 13 | Input string is longer than NAMEDATALEN-1 (63) 14 | ``` 15 | 16 | To avoid this, we have restricted the length of the database name to 17 | maximum 63 characters. This has a possible side-effect that 2 branches with long names and 18 | similar characters upto length 63 will have same database name. But 19 | it is very unlikely. 20 | -------------------------------------------------------------------------------- /chapter6-rails/lib/templates/erb/scaffold/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %> 2 | <%%= f.error_notification %> 3 | 4 |
5 | <%- attributes.each do |attribute| -%> 6 | <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> 7 | <%- end -%> 8 |
9 | 10 |
11 | <%%= f.button :submit %> 12 |
13 | <%% end %> 14 | -------------------------------------------------------------------------------- /chapter6-rails/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter6-rails/public/favicon.ico -------------------------------------------------------------------------------- /chapter6-rails/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /chapter6-rails/test/controllers/active_admin/dashboard_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ActiveAdmin::DashboardControllerTest < ActionController::TestCase 4 | fixtures :all 5 | 6 | def setup 7 | sign_in users(:admin) 8 | end 9 | 10 | def test_index_success_for_super_admin 11 | get :index 12 | assert_response :success 13 | end 14 | 15 | def test_index_redirects_for_non_super_admin 16 | sign_in users(:nancy) 17 | get :index 18 | assert_response :forbidden 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /chapter6-rails/test/controllers/api/v1/sessions_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class Api::V1::SessionsControllerTest < ActionController::TestCase 4 | 5 | def test_valid_email_and_password_should_be_able_to_log_in 6 | admin = users :admin 7 | post :create, user: { email: admin.email, password: 'welcome' } 8 | assert_response :success 9 | end 10 | 11 | def test_wrong_combination_of_email_and_password_should_not_be_able_to_log_in 12 | non_existent_email = 'this_email_does_not_exist_in_db@example.email' 13 | post :create, user: { email: non_existent_email, password: 'welcome' } 14 | assert_response 401 15 | assert_equal 'Incorrect email or password', JSON.parse(response.body)['error'] 16 | end 17 | 18 | def test_should_return_auth_token 19 | admin = users :admin 20 | 21 | post :create, user: { email: admin.email, password: 'welcome' } 22 | 23 | assert_response :success 24 | assert JSON.parse(response.body)['auth_token'] 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /chapter6-rails/test/controllers/home_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class HomeControllerTest < ActionController::TestCase 4 | 5 | def test_index_renders_message 6 | admin = users :admin 7 | sign_in admin 8 | 9 | get :index 10 | 11 | assert_response :success 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /chapter6-rails/test/controllers/pages_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class PagesControllerTest < ActionController::TestCase 4 | 5 | def test_index_success 6 | get :index 7 | 8 | assert_response :success 9 | end 10 | 11 | def test_contact_us_success 12 | get :contact_us 13 | 14 | assert_response :success 15 | end 16 | 17 | def test_about_success 18 | get :about 19 | 20 | assert_response :success 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /chapter6-rails/test/controllers/superadmin/users_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class Superadmin::UsersControllerTest < ActionController::TestCase 4 | 5 | def test_index_when_user_is_superadmin 6 | user = users :admin 7 | sign_in user 8 | get :index 9 | assert_response :success 10 | end 11 | 12 | def test_index_when_user_is_not_superadmin 13 | user = users :nancy 14 | sign_in user 15 | get :index 16 | assert_response :forbidden 17 | end 18 | 19 | def test_edit_user_modal_success_response 20 | user = users :admin 21 | sign_in user 22 | get :edit, id: users(:nancy) 23 | assert_response :success 24 | end 25 | 26 | def test_user_update_success 27 | admin = users :admin 28 | sign_in admin 29 | nancy = users :nancy 30 | 31 | post :update, id: nancy, user: {first_name: 'Jane'} 32 | nancy.reload 33 | 34 | assert 'Jane', nancy.first_name 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /chapter6-rails/test/fixtures/users.yml: -------------------------------------------------------------------------------- 1 | admin: 2 | email: 'admin@example.com' 3 | first_name: 'Adam' 4 | last_name: 'Smith' 5 | encrypted_password: '$2a$10$3OF9YyLG6D8P8EqFFdudmeIUtIlnX2usIFYhAJ77pep5y93BLuSuu' #welcome 6 | reset_password_token: 5h632xrnASqFanDhKQsB8 7 | role: 'super_admin' 8 | authentication_token: 5h632xrnASqFanDhKQsB8 9 | 10 | nancy: 11 | email: nancy.smith@example.com 12 | first_name: 'Nancy' 13 | last_name: 'Smith' 14 | encrypted_password: '$2a$10$3OF9YyLG6D8P8EqFFdudmeIUtIlnX2usIFYhAJ77pep5y93BLuSuu' #welcome 15 | reset_password_token: 5h632xrnASsFanDhKQsB7 16 | authentication_token: 5h632xrnASqFanDhKQsB8 17 | -------------------------------------------------------------------------------- /chapter6-rails/test/integration/api_invalid_json_data_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ApiInvalidJsonDataTest < ActionDispatch::IntegrationTest 4 | 5 | def test_invalid_payload_responds_with_message 6 | invalid_json = %Q{ { "foo":'bar' } } 7 | 8 | post "/v1/users", invalid_json , "CONTENT_TYPE" => 'application/json' 9 | 10 | assert_response 400 11 | assert response.body.include?("Payload data is not valid JSON"), response.body 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /chapter6-rails/test/integration/compression_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class CompressionTest < ActionDispatch::IntegrationTest 4 | def test_a_visitor_browser_that_supports_compression 5 | ['deflate','gzip', 'deflate,gzip','gzip,deflate'].each do|compression_method| 6 | get root_path, {}, {'HTTP_ACCEPT_ENCODING' => compression_method } 7 | assert response.headers['Content-Encoding'] 8 | end 9 | end 10 | 11 | def test_a_visitor_browser_does_not_support_compression 12 | get root_path 13 | assert_not response.headers['Content-Encoding'] 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /chapter6-rails/test/models/contact_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ContactTest < ActiveSupport::TestCase 4 | 5 | def test_valid_contact 6 | valid_contact = { email: 'bob@exmaple.com', 7 | title: 'need help', 8 | body: 'some message' } 9 | 10 | contact = Contact.new(valid_contact) 11 | 12 | assert contact.valid? 13 | end 14 | 15 | def test_invalid_contact 16 | invalid_contact = { email: 'bob', 17 | title: '', 18 | body: 'some message' } 19 | 20 | contact = Contact.new(invalid_contact) 21 | 22 | assert_not contact.valid? 23 | assert_includes contact.errors.full_messages, "Title can't be blank" 24 | assert_includes contact.errors.full_messages, "Email is invalid" 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /chapter6-rails/test/models/user_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class UserTest < ActiveSupport::TestCase 4 | 5 | def test_admin_is_indeed_super_admin 6 | user = users :admin 7 | assert user.super_admin? 8 | end 9 | 10 | def test_first_name_is_blank 11 | user = users :admin 12 | user.first_name = nil 13 | assert_equal 'Smith', user.name 14 | end 15 | 16 | def test_last_name_is_blank 17 | user = users :admin 18 | user.last_name = nil 19 | assert_equal 'Adam', user.name 20 | end 21 | 22 | def test_as_json 23 | user = users :admin 24 | 25 | expected = {"email"=>"admin@example.com", "current_sign_in_at"=>nil, "last_name"=>"Smith", "first_name"=>"Adam"} 26 | assert_equal expected, user.as_json 27 | end 28 | 29 | end 30 | -------------------------------------------------------------------------------- /chapter6-rails/test/services/addition_service_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class AdditonServiceTest < ActiveSupport::TestCase 4 | 5 | def test_addition 6 | service = AdditionService.new 5, 10 7 | assert_equal 15, service.process 8 | end 9 | 10 | end 11 | -------------------------------------------------------------------------------- /chapter6/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /chapter6/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "jsx": true, 4 | "modules": true 5 | }, 6 | "env": { 7 | "browser": true, 8 | "node": true 9 | }, 10 | "parser": "babel-eslint", 11 | "rules": { 12 | "quotes": [2, "single"], 13 | "strict": [2, "never"], 14 | "react/jsx-uses-react": 2, 15 | "react/jsx-uses-vars": 2, 16 | "react/react-in-jsx-scope": 2 17 | }, 18 | "plugins": [ 19 | "react" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /chapter6/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /chapter6/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "newcap": false 6 | } 7 | -------------------------------------------------------------------------------- /chapter6/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter6/README.md: -------------------------------------------------------------------------------- 1 | react-forms 2 | =========== 3 | 4 | Examples of Forms in ReactJS 5 | 6 | ### Usage 7 | 8 | ``` 9 | npm install 10 | npm start 11 | open http://localhost:9000 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /chapter6/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React Forms 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /chapter6/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-forms", 3 | "version": "0.0.1", 4 | "description": "ReactJS forms example", 5 | "scripts": { 6 | "start": "node server.js", 7 | "lint": "eslint src" 8 | }, 9 | "author": "Vipul A M (http://github.com/vipulnsward)", 10 | "license": "MIT", 11 | "homepage": "https://github.com/bigbinary/reactjs-by-example", 12 | "devDependencies": { 13 | "babel-core": "^5.4.7", 14 | "babel-eslint": "^3.1.9", 15 | "babel-loader": "^5.1.2", 16 | "css-loader": "^0.15.5", 17 | "eslint-plugin-react": "^2.3.0", 18 | "file-loader": "^0.8.4", 19 | "react-hot-loader": "^1.2.7", 20 | "style-loader": "^0.12.3", 21 | "webpack": "^1.10.1", 22 | "webpack-dev-server": "^1.8.2" 23 | }, 24 | "dependencies": { 25 | "bootstrap-webpack": "0.0.3", 26 | "font-awesome-webpack": "0.0.3", 27 | "react": "^0.13.3", 28 | "url-loader": "^0.5.6", 29 | "whatwg-fetch": "^0.9.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /chapter6/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | publicPath: config.output.publicPath, 7 | hot: true, 8 | historyApiFallback: true 9 | }).listen(9000, 'localhost', function (err, result) { 10 | if (err) { 11 | console.log(err); 12 | } 13 | 14 | console.log('Listening at localhost:9000'); 15 | }); 16 | -------------------------------------------------------------------------------- /chapter6/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import App from './App'; 3 | 4 | React.render(, document.getElementById('rootElement')); 5 | -------------------------------------------------------------------------------- /chapter7/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /chapter7/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /chapter7/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "newcap": false 6 | } 7 | -------------------------------------------------------------------------------- /chapter7/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter7/README.md: -------------------------------------------------------------------------------- 1 | react-addons 2 | =========== 3 | 4 | Examples of React addons 5 | 6 | ### Usage 7 | 8 | ``` 9 | npm install 10 | npm start 11 | open http://localhost:9000 12 | npm test 13 | ``` 14 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": ">= 1.9.1" 33 | }, 34 | "version": "3.3.5", 35 | "_release": "3.3.5", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.3.5", 39 | "commit": "16b48259a62f576e52c903c476bd42b90ab22482" 40 | }, 41 | "_source": "git://github.com/twbs/bootstrap.git", 42 | "_target": "~3.3.5", 43 | "_originalSource": "bootstrap", 44 | "_direct": true 45 | } -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2015 Twitter, Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": ">= 1.9.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter7/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter7/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter7/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter7/bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter7/bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter7/bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter7/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neerajsingh0101/reactjs-by-example/0fb831f9add41f51480f468cdd7fcf9318161b65/chapter7/bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/grunt/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends" : "../js/.jshintrc", 3 | "asi" : false, 4 | "browser" : false, 5 | "es3" : false, 6 | "node" : true 7 | } 8 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/grunt/bs-commonjs-generator.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Grunt task for the CommonJS module generation 3 | * http://getbootstrap.com 4 | * Copyright 2014-2015 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | */ 7 | 8 | 'use strict'; 9 | 10 | var fs = require('fs'); 11 | var path = require('path'); 12 | 13 | var COMMONJS_BANNER = '// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.\n'; 14 | 15 | module.exports = function generateCommonJSModule(grunt, srcFiles, destFilepath) { 16 | var destDir = path.dirname(destFilepath); 17 | 18 | function srcPathToDestRequire(srcFilepath) { 19 | var requirePath = path.relative(destDir, srcFilepath).replace(/\\/g, '/'); 20 | return 'require(\'' + requirePath + '\')'; 21 | } 22 | 23 | var moduleOutputJs = COMMONJS_BANNER + srcFiles.map(srcPathToDestRequire).join('\n'); 24 | try { 25 | fs.writeFileSync(destFilepath, moduleOutputJs); 26 | } catch (err) { 27 | grunt.fail.warn(err); 28 | } 29 | grunt.log.writeln('File ' + destFilepath.cyan + ' created.'); 30 | }; 31 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/js/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi" : true, 3 | "browser" : true, 4 | "eqeqeq" : false, 5 | "eqnull" : true, 6 | "es3" : true, 7 | "expr" : true, 8 | "jquery" : true, 9 | "latedef" : true, 10 | "laxbreak" : true, 11 | "nonbsp" : true, 12 | "strict" : true, 13 | "undef" : true, 14 | "unused" : true 15 | } 16 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "adjoining-classes": false, 3 | "box-sizing": false, 4 | "box-model": false, 5 | "compatible-vendor-prefixes": false, 6 | "floats": false, 7 | "font-sizes": false, 8 | "gradients": false, 9 | "important": false, 10 | "known-properties": false, 11 | "outline-none": false, 12 | "qualified-headings": false, 13 | "regex-selectors": false, 14 | "shorthand": false, 15 | "text-indent": false, 16 | "unique-headings": false, 17 | "universal-selector": false, 18 | "unqualified-attributes": false 19 | } 20 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal; 8 | margin-bottom: @line-height-computed; 9 | list-style: none; 10 | background-color: @breadcrumb-bg; 11 | border-radius: @border-radius-base; 12 | 13 | > li { 14 | display: inline-block; 15 | 16 | + li:before { 17 | content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space 18 | padding: 0 5px; 19 | color: @breadcrumb-color; 20 | } 21 | } 22 | 23 | > .active { 24 | color: @breadcrumb-active-color; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/close.less: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | 6 | .close { 7 | float: right; 8 | font-size: (@font-size-base * 1.5); 9 | font-weight: @close-font-weight; 10 | line-height: 1; 11 | color: @close-color; 12 | text-shadow: @close-text-shadow; 13 | .opacity(.2); 14 | 15 | &:hover, 16 | &:focus { 17 | color: @close-color; 18 | text-decoration: none; 19 | cursor: pointer; 20 | .opacity(.5); 21 | } 22 | 23 | // Additional properties for button version 24 | // iOS requires the button element instead of an anchor tag. 25 | // If you want the anchor version, it requires `href="#"`. 26 | // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile 27 | button& { 28 | padding: 0; 29 | cursor: pointer; 30 | background: transparent; 31 | border: 0; 32 | -webkit-appearance: none; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/component-animations.less: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | // Heads up! 6 | // 7 | // We don't use the `.opacity()` mixin here since it causes a bug with text 8 | // fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552. 9 | 10 | .fade { 11 | opacity: 0; 12 | .transition(opacity .15s linear); 13 | &.in { 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .collapse { 19 | display: none; 20 | 21 | &.in { display: block; } 22 | tr&.in { display: table-row; } 23 | tbody&.in { display: table-row-group; } 24 | } 25 | 26 | .collapsing { 27 | position: relative; 28 | height: 0; 29 | overflow: hidden; 30 | .transition-property(~"height, visibility"); 31 | .transition-duration(.35s); 32 | .transition-timing-function(ease); 33 | } 34 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/media.less: -------------------------------------------------------------------------------- 1 | .media { 2 | // Proper spacing between instances of .media 3 | margin-top: 15px; 4 | 5 | &:first-child { 6 | margin-top: 0; 7 | } 8 | } 9 | 10 | .media, 11 | .media-body { 12 | zoom: 1; 13 | overflow: hidden; 14 | } 15 | 16 | .media-body { 17 | width: 10000px; 18 | } 19 | 20 | .media-object { 21 | display: block; 22 | 23 | // Fix collapse in webkit from max-width: 100% and display: table-cell. 24 | &.img-thumbnail { 25 | max-width: none; 26 | } 27 | } 28 | 29 | .media-right, 30 | .media > .pull-right { 31 | padding-left: 10px; 32 | } 33 | 34 | .media-left, 35 | .media > .pull-left { 36 | padding-right: 10px; 37 | } 38 | 39 | .media-left, 40 | .media-right, 41 | .media-body { 42 | display: table-cell; 43 | vertical-align: top; 44 | } 45 | 46 | .media-middle { 47 | vertical-align: middle; 48 | } 49 | 50 | .media-bottom { 51 | vertical-align: bottom; 52 | } 53 | 54 | // Reset margins on headings for tighter default spacing 55 | .media-heading { 56 | margin-top: 0; 57 | margin-bottom: 5px; 58 | } 59 | 60 | // Media list variation 61 | // 62 | // Undo default ul/ol styles 63 | .media-list { 64 | padding-left: 0; 65 | list-style: none; 66 | } 67 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/alerts.less: -------------------------------------------------------------------------------- 1 | // Alerts 2 | 3 | .alert-variant(@background; @border; @text-color) { 4 | background-color: @background; 5 | border-color: @border; 6 | color: @text-color; 7 | 8 | hr { 9 | border-top-color: darken(@border, 5%); 10 | } 11 | .alert-link { 12 | color: darken(@text-color, 10%); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/background-variant.less: -------------------------------------------------------------------------------- 1 | // Contextual backgrounds 2 | 3 | .bg-variant(@color) { 4 | background-color: @color; 5 | a&:hover, 6 | a&:focus { 7 | background-color: darken(@color, 10%); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/border-radius.less: -------------------------------------------------------------------------------- 1 | // Single side border-radius 2 | 3 | .border-top-radius(@radius) { 4 | border-top-right-radius: @radius; 5 | border-top-left-radius: @radius; 6 | } 7 | .border-right-radius(@radius) { 8 | border-bottom-right-radius: @radius; 9 | border-top-right-radius: @radius; 10 | } 11 | .border-bottom-radius(@radius) { 12 | border-bottom-right-radius: @radius; 13 | border-bottom-left-radius: @radius; 14 | } 15 | .border-left-radius(@radius) { 16 | border-bottom-left-radius: @radius; 17 | border-top-left-radius: @radius; 18 | } 19 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/center-block.less: -------------------------------------------------------------------------------- 1 | // Center-align a block level element 2 | 3 | .center-block() { 4 | display: block; 5 | margin-left: auto; 6 | margin-right: auto; 7 | } 8 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/clearfix.less: -------------------------------------------------------------------------------- 1 | // Clearfix 2 | // 3 | // For modern browsers 4 | // 1. The space content is one way to avoid an Opera bug when the 5 | // contenteditable attribute is included anywhere else in the document. 6 | // Otherwise it causes space to appear at the top and bottom of elements 7 | // that are clearfixed. 8 | // 2. The use of `table` rather than `block` is only necessary if using 9 | // `:before` to contain the top-margins of child elements. 10 | // 11 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/ 12 | 13 | .clearfix() { 14 | &:before, 15 | &:after { 16 | content: " "; // 1 17 | display: table; // 2 18 | } 19 | &:after { 20 | clear: both; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/hide-text.less: -------------------------------------------------------------------------------- 1 | // CSS image replacement 2 | // 3 | // Heads up! v3 launched with only `.hide-text()`, but per our pattern for 4 | // mixins being reused as classes with the same name, this doesn't hold up. As 5 | // of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. 6 | // 7 | // Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757 8 | 9 | // Deprecated as of v3.0.1 (will be removed in v4) 10 | .hide-text() { 11 | font: ~"0/0" a; 12 | color: transparent; 13 | text-shadow: none; 14 | background-color: transparent; 15 | border: 0; 16 | } 17 | 18 | // New mixin to use as of v3.0.1 19 | .text-hide() { 20 | .hide-text(); 21 | } 22 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/image.less: -------------------------------------------------------------------------------- 1 | // Image Mixins 2 | // - Responsive image 3 | // - Retina image 4 | 5 | 6 | // Responsive image 7 | // 8 | // Keep images from scaling beyond the width of their parents. 9 | .img-responsive(@display: block) { 10 | display: @display; 11 | max-width: 100%; // Part 1: Set a maximum relative to the parent 12 | height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching 13 | } 14 | 15 | 16 | // Retina image 17 | // 18 | // Short retina mixin for setting background-image and -size. Note that the 19 | // spelling of `min--moz-device-pixel-ratio` is intentional. 20 | .img-retina(@file-1x; @file-2x; @width-1x; @height-1x) { 21 | background-image: url("@{file-1x}"); 22 | 23 | @media 24 | only screen and (-webkit-min-device-pixel-ratio: 2), 25 | only screen and ( min--moz-device-pixel-ratio: 2), 26 | only screen and ( -o-min-device-pixel-ratio: 2/1), 27 | only screen and ( min-device-pixel-ratio: 2), 28 | only screen and ( min-resolution: 192dpi), 29 | only screen and ( min-resolution: 2dppx) { 30 | background-image: url("@{file-2x}"); 31 | background-size: @width-1x @height-1x; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/labels.less: -------------------------------------------------------------------------------- 1 | // Labels 2 | 3 | .label-variant(@color) { 4 | background-color: @color; 5 | 6 | &[href] { 7 | &:hover, 8 | &:focus { 9 | background-color: darken(@color, 10%); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/list-group.less: -------------------------------------------------------------------------------- 1 | // List Groups 2 | 3 | .list-group-item-variant(@state; @background; @color) { 4 | .list-group-item-@{state} { 5 | color: @color; 6 | background-color: @background; 7 | 8 | a&, 9 | button& { 10 | color: @color; 11 | 12 | .list-group-item-heading { 13 | color: inherit; 14 | } 15 | 16 | &:hover, 17 | &:focus { 18 | color: @color; 19 | background-color: darken(@background, 5%); 20 | } 21 | &.active, 22 | &.active:hover, 23 | &.active:focus { 24 | color: #fff; 25 | background-color: @color; 26 | border-color: @color; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/nav-divider.less: -------------------------------------------------------------------------------- 1 | // Horizontal dividers 2 | // 3 | // Dividers (basically an hr) within dropdowns and nav lists 4 | 5 | .nav-divider(@color: #e5e5e5) { 6 | height: 1px; 7 | margin: ((@line-height-computed / 2) - 1) 0; 8 | overflow: hidden; 9 | background-color: @color; 10 | } 11 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/nav-vertical-align.less: -------------------------------------------------------------------------------- 1 | // Navbar vertical align 2 | // 3 | // Vertically center elements in the navbar. 4 | // Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin. 5 | 6 | .navbar-vertical-align(@element-height) { 7 | margin-top: ((@navbar-height - @element-height) / 2); 8 | margin-bottom: ((@navbar-height - @element-height) / 2); 9 | } 10 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/opacity.less: -------------------------------------------------------------------------------- 1 | // Opacity 2 | 3 | .opacity(@opacity) { 4 | opacity: @opacity; 5 | // IE8 filter 6 | @opacity-ie: (@opacity * 100); 7 | filter: ~"alpha(opacity=@{opacity-ie})"; 8 | } 9 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/pagination.less: -------------------------------------------------------------------------------- 1 | // Pagination 2 | 3 | .pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { 4 | > li { 5 | > a, 6 | > span { 7 | padding: @padding-vertical @padding-horizontal; 8 | font-size: @font-size; 9 | line-height: @line-height; 10 | } 11 | &:first-child { 12 | > a, 13 | > span { 14 | .border-left-radius(@border-radius); 15 | } 16 | } 17 | &:last-child { 18 | > a, 19 | > span { 20 | .border-right-radius(@border-radius); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/panels.less: -------------------------------------------------------------------------------- 1 | // Panels 2 | 3 | .panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) { 4 | border-color: @border; 5 | 6 | & > .panel-heading { 7 | color: @heading-text-color; 8 | background-color: @heading-bg-color; 9 | border-color: @heading-border; 10 | 11 | + .panel-collapse > .panel-body { 12 | border-top-color: @border; 13 | } 14 | .badge { 15 | color: @heading-bg-color; 16 | background-color: @heading-text-color; 17 | } 18 | } 19 | & > .panel-footer { 20 | + .panel-collapse > .panel-body { 21 | border-bottom-color: @border; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/progress-bar.less: -------------------------------------------------------------------------------- 1 | // Progress bars 2 | 3 | .progress-bar-variant(@color) { 4 | background-color: @color; 5 | 6 | // Deprecated parent class requirement as of v3.2.0 7 | .progress-striped & { 8 | #gradient > .striped(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/reset-filter.less: -------------------------------------------------------------------------------- 1 | // Reset filters for IE 2 | // 3 | // When you need to remove a gradient background, do not forget to use this to reset 4 | // the IE filter for IE9 and below. 5 | 6 | .reset-filter() { 7 | filter: e(%("progid:DXImageTransform.Microsoft.gradient(enabled = false)")); 8 | } 9 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/reset-text.less: -------------------------------------------------------------------------------- 1 | .reset-text() { 2 | font-family: @font-family-base; 3 | // We deliberately do NOT reset font-size. 4 | font-style: normal; 5 | font-weight: normal; 6 | letter-spacing: normal; 7 | line-break: auto; 8 | line-height: @line-height-base; 9 | text-align: left; // Fallback for where `start` is not supported 10 | text-align: start; 11 | text-decoration: none; 12 | text-shadow: none; 13 | text-transform: none; 14 | white-space: normal; 15 | word-break: normal; 16 | word-spacing: normal; 17 | word-wrap: normal; 18 | } 19 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/resize.less: -------------------------------------------------------------------------------- 1 | // Resize anything 2 | 3 | .resizable(@direction) { 4 | resize: @direction; // Options: horizontal, vertical, both 5 | overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` 6 | } 7 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/responsive-visibility.less: -------------------------------------------------------------------------------- 1 | // Responsive utilities 2 | 3 | // 4 | // More easily include all the states for responsive-utilities.less. 5 | .responsive-visibility() { 6 | display: block !important; 7 | table& { display: table !important; } 8 | tr& { display: table-row !important; } 9 | th&, 10 | td& { display: table-cell !important; } 11 | } 12 | 13 | .responsive-invisibility() { 14 | display: none !important; 15 | } 16 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/size.less: -------------------------------------------------------------------------------- 1 | // Sizing shortcuts 2 | 3 | .size(@width; @height) { 4 | width: @width; 5 | height: @height; 6 | } 7 | 8 | .square(@size) { 9 | .size(@size; @size); 10 | } 11 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/tab-focus.less: -------------------------------------------------------------------------------- 1 | // WebKit-style focus 2 | 3 | .tab-focus() { 4 | // Default 5 | outline: thin dotted; 6 | // WebKit 7 | outline: 5px auto -webkit-focus-ring-color; 8 | outline-offset: -2px; 9 | } 10 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/table-row.less: -------------------------------------------------------------------------------- 1 | // Tables 2 | 3 | .table-row-variant(@state; @background) { 4 | // Exact selectors below required to override `.table-striped` and prevent 5 | // inheritance to nested tables. 6 | .table > thead > tr, 7 | .table > tbody > tr, 8 | .table > tfoot > tr { 9 | > td.@{state}, 10 | > th.@{state}, 11 | &.@{state} > td, 12 | &.@{state} > th { 13 | background-color: @background; 14 | } 15 | } 16 | 17 | // Hover states for `.table-hover` 18 | // Note: this is not available for cells or rows within `thead` or `tfoot`. 19 | .table-hover > tbody > tr { 20 | > td.@{state}:hover, 21 | > th.@{state}:hover, 22 | &.@{state}:hover > td, 23 | &:hover > .@{state}, 24 | &.@{state}:hover > th { 25 | background-color: darken(@background, 5%); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/text-emphasis.less: -------------------------------------------------------------------------------- 1 | // Typography 2 | 3 | .text-emphasis-variant(@color) { 4 | color: @color; 5 | a&:hover, 6 | a&:focus { 7 | color: darken(@color, 10%); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/mixins/text-overflow.less: -------------------------------------------------------------------------------- 1 | // Text overflow 2 | // Requires inline-block or block for proper styling 3 | 4 | .text-overflow() { 5 | overflow: hidden; 6 | text-overflow: ellipsis; 7 | white-space: nowrap; 8 | } 9 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/pager.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pager pagination 3 | // -------------------------------------------------- 4 | 5 | 6 | .pager { 7 | padding-left: 0; 8 | margin: @line-height-computed 0; 9 | list-style: none; 10 | text-align: center; 11 | &:extend(.clearfix all); 12 | li { 13 | display: inline; 14 | > a, 15 | > span { 16 | display: inline-block; 17 | padding: 5px 14px; 18 | background-color: @pager-bg; 19 | border: 1px solid @pager-border; 20 | border-radius: @pager-border-radius; 21 | } 22 | 23 | > a:hover, 24 | > a:focus { 25 | text-decoration: none; 26 | background-color: @pager-hover-bg; 27 | } 28 | } 29 | 30 | .next { 31 | > a, 32 | > span { 33 | float: right; 34 | } 35 | } 36 | 37 | .previous { 38 | > a, 39 | > span { 40 | float: left; 41 | } 42 | } 43 | 44 | .disabled { 45 | > a, 46 | > a:hover, 47 | > a:focus, 48 | > span { 49 | color: @pager-disabled-color; 50 | background-color: @pager-bg; 51 | cursor: @cursor-disabled; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/responsive-embed.less: -------------------------------------------------------------------------------- 1 | // Embeds responsive 2 | // 3 | // Credit: Nicolas Gallagher and SUIT CSS. 4 | 5 | .embed-responsive { 6 | position: relative; 7 | display: block; 8 | height: 0; 9 | padding: 0; 10 | overflow: hidden; 11 | 12 | .embed-responsive-item, 13 | iframe, 14 | embed, 15 | object, 16 | video { 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | bottom: 0; 21 | height: 100%; 22 | width: 100%; 23 | border: 0; 24 | } 25 | } 26 | 27 | // Modifier class for 16:9 aspect ratio 28 | .embed-responsive-16by9 { 29 | padding-bottom: 56.25%; 30 | } 31 | 32 | // Modifier class for 4:3 aspect ratio 33 | .embed-responsive-4by3 { 34 | padding-bottom: 75%; 35 | } 36 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/thumbnails.less: -------------------------------------------------------------------------------- 1 | // 2 | // Thumbnails 3 | // -------------------------------------------------- 4 | 5 | 6 | // Mixin and adjust the regular image class 7 | .thumbnail { 8 | display: block; 9 | padding: @thumbnail-padding; 10 | margin-bottom: @line-height-computed; 11 | line-height: @line-height-base; 12 | background-color: @thumbnail-bg; 13 | border: 1px solid @thumbnail-border; 14 | border-radius: @thumbnail-border-radius; 15 | .transition(border .2s ease-in-out); 16 | 17 | > img, 18 | a > img { 19 | &:extend(.img-responsive); 20 | margin-left: auto; 21 | margin-right: auto; 22 | } 23 | 24 | // Add a hover state for linked versions only 25 | a&:hover, 26 | a&:focus, 27 | a&.active { 28 | border-color: @link-color; 29 | } 30 | 31 | // Image captions 32 | .caption { 33 | padding: @thumbnail-caption-padding; 34 | color: @thumbnail-caption-color; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // Floats 7 | // ------------------------- 8 | 9 | .clearfix { 10 | .clearfix(); 11 | } 12 | .center-block { 13 | .center-block(); 14 | } 15 | .pull-right { 16 | float: right !important; 17 | } 18 | .pull-left { 19 | float: left !important; 20 | } 21 | 22 | 23 | // Toggling content 24 | // ------------------------- 25 | 26 | // Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1 27 | .hide { 28 | display: none !important; 29 | } 30 | .show { 31 | display: block !important; 32 | } 33 | .invisible { 34 | visibility: hidden; 35 | } 36 | .text-hide { 37 | .text-hide(); 38 | } 39 | 40 | 41 | // Hide from screenreaders and browsers 42 | // 43 | // Credit: HTML5 Boilerplate 44 | 45 | .hidden { 46 | display: none !important; 47 | } 48 | 49 | 50 | // For Affix plugin 51 | // ------------------------- 52 | 53 | .affix { 54 | position: fixed; 55 | } 56 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/less/wells.less: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .well { 8 | min-height: 20px; 9 | padding: 19px; 10 | margin-bottom: 20px; 11 | background-color: @well-bg; 12 | border: 1px solid @well-border; 13 | border-radius: @border-radius-base; 14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); 15 | blockquote { 16 | border-color: #ddd; 17 | border-color: rgba(0,0,0,.15); 18 | } 19 | } 20 | 21 | // Sizes 22 | .well-lg { 23 | padding: 24px; 24 | border-radius: @border-radius-large; 25 | } 26 | .well-sm { 27 | padding: 9px; 28 | border-radius: @border-radius-small; 29 | } 30 | -------------------------------------------------------------------------------- /chapter7/bower_components/bootstrap/package.js: -------------------------------------------------------------------------------- 1 | // package metadata file for Meteor.js 2 | 3 | /* jshint strict:false */ 4 | /* global Package:true */ 5 | 6 | Package.describe({ 7 | name: 'twbs:bootstrap', // http://atmospherejs.com/twbs/bootstrap 8 | summary: 'The most popular front-end framework for developing responsive, mobile first projects on the web.', 9 | version: '3.3.5', 10 | git: 'https://github.com/twbs/bootstrap.git' 11 | }); 12 | 13 | Package.onUse(function (api) { 14 | api.versionsFrom('METEOR@1.0'); 15 | api.use('jquery', 'client'); 16 | api.addFiles([ 17 | 'dist/fonts/glyphicons-halflings-regular.eot', 18 | 'dist/fonts/glyphicons-halflings-regular.svg', 19 | 'dist/fonts/glyphicons-halflings-regular.ttf', 20 | 'dist/fonts/glyphicons-halflings-regular.woff', 21 | 'dist/fonts/glyphicons-halflings-regular.woff2', 22 | 'dist/css/bootstrap.css', 23 | 'dist/js/bootstrap.js' 24 | ], 'client'); 25 | }); 26 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "2.1.4", 4 | "main": "dist/jquery.js", 5 | "license": "MIT", 6 | "ignore": [ 7 | "**/.*", 8 | "build", 9 | "dist/cdn", 10 | "speed", 11 | "test", 12 | "*.md", 13 | "AUTHORS.txt", 14 | "Gruntfile.js", 15 | "package.json" 16 | ], 17 | "devDependencies": { 18 | "sizzle": "2.1.1-jquery.2.1.2", 19 | "requirejs": "2.1.10", 20 | "qunit": "1.14.0", 21 | "sinon": "1.8.1" 22 | }, 23 | "keywords": [ 24 | "jquery", 25 | "javascript", 26 | "library" 27 | ], 28 | "homepage": "https://github.com/jquery/jquery", 29 | "_release": "2.1.4", 30 | "_resolution": { 31 | "type": "version", 32 | "tag": "2.1.4", 33 | "commit": "7751e69b615c6eca6f783a81e292a55725af6b85" 34 | }, 35 | "_source": "git://github.com/jquery/jquery.git", 36 | "_target": ">= 1.9.1", 37 | "_originalSource": "jquery" 38 | } -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 jQuery Foundation and other contributors 2 | http://jquery.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "version": "2.1.4", 4 | "main": "dist/jquery.js", 5 | "license": "MIT", 6 | "ignore": [ 7 | "**/.*", 8 | "build", 9 | "dist/cdn", 10 | "speed", 11 | "test", 12 | "*.md", 13 | "AUTHORS.txt", 14 | "Gruntfile.js", 15 | "package.json" 16 | ], 17 | "devDependencies": { 18 | "sizzle": "2.1.1-jquery.2.1.2", 19 | "requirejs": "2.1.10", 20 | "qunit": "1.14.0", 21 | "sinon": "1.8.1" 22 | }, 23 | "keywords": [ 24 | "jquery", 25 | "javascript", 26 | "library" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/ajax/parseJSON.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | // Support: Android 2.3 6 | // Workaround failure to string-cast null input 7 | jQuery.parseJSON = function( data ) { 8 | return JSON.parse( data + "" ); 9 | }; 10 | 11 | return jQuery.parseJSON; 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/ajax/parseXML.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | // Cross-browser xml parsing 6 | jQuery.parseXML = function( data ) { 7 | var xml, tmp; 8 | if ( !data || typeof data !== "string" ) { 9 | return null; 10 | } 11 | 12 | // Support: IE9 13 | try { 14 | tmp = new DOMParser(); 15 | xml = tmp.parseFromString( data, "text/xml" ); 16 | } catch ( e ) { 17 | xml = undefined; 18 | } 19 | 20 | if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { 21 | jQuery.error( "Invalid XML: " + data ); 22 | } 23 | return xml; 24 | }; 25 | 26 | return jQuery.parseXML; 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/ajax/var/nonce.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../../core" 3 | ], function( jQuery ) { 4 | return jQuery.now(); 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/ajax/var/rquery.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return (/\?/); 3 | }); 4 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/attributes.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./core", 3 | "./attributes/attr", 4 | "./attributes/prop", 5 | "./attributes/classes", 6 | "./attributes/val" 7 | ], function( jQuery ) { 8 | 9 | // Return jQuery for attributes-only inclusion 10 | return jQuery; 11 | }); 12 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/attributes/support.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../var/support" 3 | ], function( support ) { 4 | 5 | (function() { 6 | var input = document.createElement( "input" ), 7 | select = document.createElement( "select" ), 8 | opt = select.appendChild( document.createElement( "option" ) ); 9 | 10 | input.type = "checkbox"; 11 | 12 | // Support: iOS<=5.1, Android<=4.2+ 13 | // Default value for a checkbox should be "on" 14 | support.checkOn = input.value !== ""; 15 | 16 | // Support: IE<=11+ 17 | // Must access selectedIndex to make default options select 18 | support.optSelected = opt.selected; 19 | 20 | // Support: Android<=2.3 21 | // Options inside disabled selects are incorrectly marked as disabled 22 | select.disabled = true; 23 | support.optDisabled = !opt.disabled; 24 | 25 | // Support: IE<=11+ 26 | // An input loses its value after becoming a radio 27 | input = document.createElement( "input" ); 28 | input.value = "t"; 29 | input.type = "radio"; 30 | support.radioValue = input.value === "t"; 31 | })(); 32 | 33 | return support; 34 | 35 | }); 36 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/core/parseHTML.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "./var/rsingleTag", 4 | "../manipulation" // buildFragment 5 | ], function( jQuery, rsingleTag ) { 6 | 7 | // data: string of html 8 | // context (optional): If specified, the fragment will be created in this context, defaults to document 9 | // keepScripts (optional): If true, will include scripts passed in the html string 10 | jQuery.parseHTML = function( data, context, keepScripts ) { 11 | if ( !data || typeof data !== "string" ) { 12 | return null; 13 | } 14 | if ( typeof context === "boolean" ) { 15 | keepScripts = context; 16 | context = false; 17 | } 18 | context = context || document; 19 | 20 | var parsed = rsingleTag.exec( data ), 21 | scripts = !keepScripts && []; 22 | 23 | // Single tag 24 | if ( parsed ) { 25 | return [ context.createElement( parsed[1] ) ]; 26 | } 27 | 28 | parsed = jQuery.buildFragment( [ data ], context, scripts ); 29 | 30 | if ( scripts && scripts.length ) { 31 | jQuery( scripts ).remove(); 32 | } 33 | 34 | return jQuery.merge( [], parsed.childNodes ); 35 | }; 36 | 37 | return jQuery.parseHTML; 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/core/var/rsingleTag.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | // Match a standalone tag 3 | return (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); 4 | }); 5 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/css/addGetHookIf.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | 3 | function addGetHookIf( conditionFn, hookFn ) { 4 | // Define the hook, we'll check on the first run if it's really needed. 5 | return { 6 | get: function() { 7 | if ( conditionFn() ) { 8 | // Hook not needed (or it's not possible to use it due 9 | // to missing dependency), remove it. 10 | delete this.get; 11 | return; 12 | } 13 | 14 | // Hook needed; redefine it so that the support test is not executed again. 15 | return (this.get = hookFn).apply( this, arguments ); 16 | } 17 | }; 18 | } 19 | 20 | return addGetHookIf; 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/css/hiddenVisibleSelectors.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "../selector" 4 | ], function( jQuery ) { 5 | 6 | jQuery.expr.filters.hidden = function( elem ) { 7 | // Support: Opera <= 12.12 8 | // Opera reports offsetWidths and offsetHeights less than zero on some elements 9 | return elem.offsetWidth <= 0 && elem.offsetHeight <= 0; 10 | }; 11 | jQuery.expr.filters.visible = function( elem ) { 12 | return !jQuery.expr.filters.hidden( elem ); 13 | }; 14 | 15 | }); 16 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/css/swap.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | // A method for quickly swapping in/out CSS properties to get correct calculations. 6 | jQuery.swap = function( elem, options, callback, args ) { 7 | var ret, name, 8 | old = {}; 9 | 10 | // Remember the old values, and insert the new ones 11 | for ( name in options ) { 12 | old[ name ] = elem.style[ name ]; 13 | elem.style[ name ] = options[ name ]; 14 | } 15 | 16 | ret = callback.apply( elem, args || [] ); 17 | 18 | // Revert the old values 19 | for ( name in options ) { 20 | elem.style[ name ] = old[ name ]; 21 | } 22 | 23 | return ret; 24 | }; 25 | 26 | return jQuery.swap; 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/css/var/cssExpand.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return [ "Top", "Right", "Bottom", "Left" ]; 3 | }); 4 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/css/var/getStyles.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return function( elem ) { 3 | // Support: IE<=11+, Firefox<=30+ (#15098, #14150) 4 | // IE throws on elements created in popups 5 | // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" 6 | if ( elem.ownerDocument.defaultView.opener ) { 7 | return elem.ownerDocument.defaultView.getComputedStyle( elem, null ); 8 | } 9 | 10 | return window.getComputedStyle( elem, null ); 11 | }; 12 | }); 13 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/css/var/isHidden.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../../core", 3 | "../../selector" 4 | // css is assumed 5 | ], function( jQuery ) { 6 | 7 | return function( elem, el ) { 8 | // isHidden might be called from jQuery#filter function; 9 | // in that case, element will be second argument 10 | elem = el || elem; 11 | return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); 12 | }; 13 | }); 14 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/css/var/rmargin.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return (/^margin/); 3 | }); 4 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/css/var/rnumnonpx.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../../var/pnum" 3 | ], function( pnum ) { 4 | return new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/data/accepts.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | /** 6 | * Determines whether an object can have data 7 | */ 8 | jQuery.acceptData = function( owner ) { 9 | // Accepts only: 10 | // - Node 11 | // - Node.ELEMENT_NODE 12 | // - Node.DOCUMENT_NODE 13 | // - Object 14 | // - Any 15 | /* jshint -W018 */ 16 | return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); 17 | }; 18 | 19 | return jQuery.acceptData; 20 | }); 21 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/data/var/data_priv.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../Data" 3 | ], function( Data ) { 4 | return new Data(); 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/data/var/data_user.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../Data" 3 | ], function( Data ) { 4 | return new Data(); 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/deprecated.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./core", 3 | "./traversing" 4 | ], function( jQuery ) { 5 | 6 | // The number of elements contained in the matched element set 7 | jQuery.fn.size = function() { 8 | return this.length; 9 | }; 10 | 11 | jQuery.fn.andSelf = jQuery.fn.addBack; 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/effects/animatedSelector.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "../selector", 4 | "../effects" 5 | ], function( jQuery ) { 6 | 7 | jQuery.expr.filters.animated = function( elem ) { 8 | return jQuery.grep(jQuery.timers, function( fn ) { 9 | return elem === fn.elem; 10 | }).length; 11 | }; 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/event/ajax.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "../event" 4 | ], function( jQuery ) { 5 | 6 | // Attach a bunch of functions for handling common AJAX events 7 | jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) { 8 | jQuery.fn[ type ] = function( fn ) { 9 | return this.on( type, fn ); 10 | }; 11 | }); 12 | 13 | }); 14 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/event/support.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../var/support" 3 | ], function( support ) { 4 | 5 | support.focusinBubbles = "onfocusin" in window; 6 | 7 | return support; 8 | 9 | }); 10 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/exports/amd.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core" 3 | ], function( jQuery ) { 4 | 5 | // Register as a named AMD module, since jQuery can be concatenated with other 6 | // files that may use define, but not via a proper concatenation script that 7 | // understands anonymous AMD modules. A named AMD is safest and most robust 8 | // way to register. Lowercase jquery is used because AMD module names are 9 | // derived from file names, and jQuery is normally delivered in a lowercase 10 | // file name. Do this after creating the global so that if an AMD module wants 11 | // to call noConflict to hide this version of jQuery, it will work. 12 | 13 | // Note that for maximum portability, libraries that are not jQuery should 14 | // declare themselves as anonymous modules, and avoid setting a global if an 15 | // AMD loader is present. jQuery is a special case. For more information, see 16 | // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon 17 | 18 | if ( typeof define === "function" && define.amd ) { 19 | define( "jquery", [], function() { 20 | return jQuery; 21 | }); 22 | } 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/exports/global.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "../var/strundefined" 4 | ], function( jQuery, strundefined ) { 5 | 6 | var 7 | // Map over jQuery in case of overwrite 8 | _jQuery = window.jQuery, 9 | 10 | // Map over the $ in case of overwrite 11 | _$ = window.$; 12 | 13 | jQuery.noConflict = function( deep ) { 14 | if ( window.$ === jQuery ) { 15 | window.$ = _$; 16 | } 17 | 18 | if ( deep && window.jQuery === jQuery ) { 19 | window.jQuery = _jQuery; 20 | } 21 | 22 | return jQuery; 23 | }; 24 | 25 | // Expose jQuery and $ identifiers, even in AMD 26 | // (#7102#comment:10, https://github.com/jquery/jquery/pull/557) 27 | // and CommonJS for browser emulators (#13566) 28 | if ( typeof noGlobal === strundefined ) { 29 | window.jQuery = window.$ = jQuery; 30 | } 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/jquery.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./core", 3 | "./selector", 4 | "./traversing", 5 | "./callbacks", 6 | "./deferred", 7 | "./core/ready", 8 | "./data", 9 | "./queue", 10 | "./queue/delay", 11 | "./attributes", 12 | "./event", 13 | "./event/alias", 14 | "./manipulation", 15 | "./manipulation/_evalUrl", 16 | "./wrap", 17 | "./css", 18 | "./css/hiddenVisibleSelectors", 19 | "./serialize", 20 | "./ajax", 21 | "./ajax/xhr", 22 | "./ajax/script", 23 | "./ajax/jsonp", 24 | "./ajax/load", 25 | "./event/ajax", 26 | "./effects", 27 | "./effects/animatedSelector", 28 | "./offset", 29 | "./dimensions", 30 | "./deprecated", 31 | "./exports/amd", 32 | "./exports/global" 33 | ], function( jQuery ) { 34 | 35 | return jQuery; 36 | 37 | }); 38 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/manipulation/_evalUrl.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../ajax" 3 | ], function( jQuery ) { 4 | 5 | jQuery._evalUrl = function( url ) { 6 | return jQuery.ajax({ 7 | url: url, 8 | type: "GET", 9 | dataType: "script", 10 | async: false, 11 | global: false, 12 | "throws": true 13 | }); 14 | }; 15 | 16 | return jQuery._evalUrl; 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/manipulation/support.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../var/support" 3 | ], function( support ) { 4 | 5 | (function() { 6 | var fragment = document.createDocumentFragment(), 7 | div = fragment.appendChild( document.createElement( "div" ) ), 8 | input = document.createElement( "input" ); 9 | 10 | // Support: Safari<=5.1 11 | // Check state lost if the name is set (#11217) 12 | // Support: Windows Web Apps (WWA) 13 | // `name` and `type` must use .setAttribute for WWA (#14901) 14 | input.setAttribute( "type", "radio" ); 15 | input.setAttribute( "checked", "checked" ); 16 | input.setAttribute( "name", "t" ); 17 | 18 | div.appendChild( input ); 19 | 20 | // Support: Safari<=5.1, Android<4.2 21 | // Older WebKit doesn't clone checked state correctly in fragments 22 | support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; 23 | 24 | // Support: IE<=11+ 25 | // Make sure textarea (and checkbox) defaultValue is properly cloned 26 | div.innerHTML = ""; 27 | support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; 28 | })(); 29 | 30 | return support; 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/manipulation/var/rcheckableType.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return (/^(?:checkbox|radio)$/i); 3 | }); 4 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/outro.js: -------------------------------------------------------------------------------- 1 | })); 2 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/queue/delay.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../core", 3 | "../queue", 4 | "../effects" // Delay is optional because of this dependency 5 | ], function( jQuery ) { 6 | 7 | // Based off of the plugin by Clint Helfers, with permission. 8 | // http://blindsignals.com/index.php/2009/07/jquery-delay/ 9 | jQuery.fn.delay = function( time, type ) { 10 | time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; 11 | type = type || "fx"; 12 | 13 | return this.queue( type, function( next, hooks ) { 14 | var timeout = setTimeout( next, time ); 15 | hooks.stop = function() { 16 | clearTimeout( timeout ); 17 | }; 18 | }); 19 | }; 20 | 21 | return jQuery.fn.delay; 22 | }); 23 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/selector-sizzle.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./core", 3 | "sizzle" 4 | ], function( jQuery, Sizzle ) { 5 | 6 | jQuery.find = Sizzle; 7 | jQuery.expr = Sizzle.selectors; 8 | jQuery.expr[":"] = jQuery.expr.pseudos; 9 | jQuery.unique = Sizzle.uniqueSort; 10 | jQuery.text = Sizzle.getText; 11 | jQuery.isXMLDoc = Sizzle.isXML; 12 | jQuery.contains = Sizzle.contains; 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/selector.js: -------------------------------------------------------------------------------- 1 | define([ "./selector-sizzle" ]); 2 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/traversing/var/rneedsContext.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "../../core", 3 | "../../selector" 4 | ], function( jQuery ) { 5 | return jQuery.expr.match.needsContext; 6 | }); 7 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/arr.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return []; 3 | }); 4 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/class2type.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | // [[Class]] -> type pairs 3 | return {}; 4 | }); 5 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/concat.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./arr" 3 | ], function( arr ) { 4 | return arr.concat; 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/hasOwn.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./class2type" 3 | ], function( class2type ) { 4 | return class2type.hasOwnProperty; 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/indexOf.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./arr" 3 | ], function( arr ) { 4 | return arr.indexOf; 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/pnum.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; 3 | }); 4 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/push.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./arr" 3 | ], function( arr ) { 4 | return arr.push; 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/rnotwhite.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return (/\S+/g); 3 | }); 4 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/slice.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./arr" 3 | ], function( arr ) { 4 | return arr.slice; 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/strundefined.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | return typeof undefined; 3 | }); 4 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/support.js: -------------------------------------------------------------------------------- 1 | define(function() { 2 | // All support tests are defined in their respective modules. 3 | return {}; 4 | }); 5 | -------------------------------------------------------------------------------- /chapter7/bower_components/jquery/src/var/toString.js: -------------------------------------------------------------------------------- 1 | define([ 2 | "./class2type" 3 | ], function( class2type ) { 4 | return class2type.toString; 5 | }); 6 | -------------------------------------------------------------------------------- /chapter7/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React Addons 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /chapter7/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | publicPath: config.output.publicPath, 7 | hot: true, 8 | historyApiFallback: true 9 | }).listen(9000, 'localhost', function (err, result) { 10 | if (err) { 11 | console.log(err); 12 | } 13 | 14 | console.log('Listening at localhost:9000'); 15 | }); 16 | -------------------------------------------------------------------------------- /chapter7/src/RowAlternator.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | var RowAlternator = React.createClass({ 4 | propTypes: { 5 | firstColor: React.PropTypes.string, 6 | secondColor: React.PropTypes.string 7 | }, 8 | 9 | render() { 10 | return ( 11 | 12 | { this.props.children.map((row, idx) => { 13 | if (idx %2 == 0) { 14 | return React.cloneElement(row, { style: { background: this.props.firstColor }}); 15 | } else { 16 | return React.cloneElement(row, { style: { background: this.props.secondColor }}); 17 | } 18 | }) 19 | } 20 | 21 | ) 22 | } 23 | }); 24 | 25 | module.exports = RowAlternator; 26 | -------------------------------------------------------------------------------- /chapter7/src/Spinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | var Spinner = React.createClass({ 4 | render() { 5 | return( 6 |
7 |
8 |
9 |
10 |
11 | ); 12 | } 13 | }); 14 | 15 | module.exports = Spinner; 16 | -------------------------------------------------------------------------------- /chapter7/src/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom'; 2 | import React from 'react'; 3 | import App from './App'; 4 | 5 | ReactDOM.render(, document.getElementById('rootElement')); 6 | -------------------------------------------------------------------------------- /chapter7/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | devtool: 'eval', 6 | entry: [ 7 | 'webpack-dev-server/client?http://localhost:9000', 8 | 'webpack/hot/only-dev-server', 9 | './src/index' 10 | ], 11 | output: { 12 | path: path.join(__dirname, 'dist'), 13 | filename: 'bundle.js', 14 | publicPath: '/static/' 15 | }, 16 | plugins: [ 17 | new webpack.HotModuleReplacementPlugin(), 18 | new webpack.NoErrorsPlugin() 19 | ], 20 | resolve: { 21 | extensions: ['', '.js', '.jsx'] 22 | }, 23 | module: { 24 | loaders: [{ 25 | test: /\.jsx?$/, 26 | loaders: ['react-hot', 'babel'], 27 | include: path.join(__dirname, 'src') 28 | }, 29 | {test: /\.woff(\d+)?$/, loader: 'url?prefix=font/&limit=5000&mimetype=application/font-woff'}, 30 | {test: /\.ttf$/, loader: 'file?prefix=font/'}, 31 | {test: /\.eot$/, loader: 'file?prefix=font/'}, 32 | {test: /\.svg$/, loader: 'file?prefix=font/'}, 33 | {test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url-loader?limit=10000&minetype=application/font-woff"}, 34 | {test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader"} 35 | ] 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /chapter8/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /chapter8/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /chapter8/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "newcap": false 6 | } 7 | -------------------------------------------------------------------------------- /chapter8/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter8/README.md: -------------------------------------------------------------------------------- 1 | react-perf-tools 2 | =========== 3 | 4 | Examples of React Perf tools 5 | 6 | ### Usage 7 | 8 | ``` 9 | npm install 10 | npm start 11 | open http://localhost:9000 12 | npm test 13 | ``` 14 | -------------------------------------------------------------------------------- /chapter8/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React PERF tools 4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /chapter8/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | publicPath: config.output.publicPath, 7 | hot: true, 8 | historyApiFallback: true 9 | }).listen(9000, 'localhost', function (err, result) { 10 | if (err) { 11 | console.log(err); 12 | } 13 | 14 | console.log('Listening at localhost:9000'); 15 | }); 16 | -------------------------------------------------------------------------------- /chapter8/src/BookListHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default React.createClass({ 4 | shouldComponentUpdate(nextProps, nextState) { 5 | return nextProps.searchCount !== this.props.searchCount; 6 | }, 7 | 8 | render() { 9 | return ( 10 | 11 |

Total Results: {this.props.searchCount}

12 |
13 | ); 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /chapter8/src/BookRow.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PureRenderMixin from 'react-addons-pure-render-mixin'; 3 | 4 | export default React.createClass({ 5 | shouldComponentUpdate(nextProps, nextState) { 6 | return nextProps.title !== this.props.title || 7 | nextProps.author_name !== this.props.author_name || 8 | nextProps.edition_count !== this.props.edition_count; 9 | }, 10 | 11 | render() { 12 | return( 13 | 14 |

#{this.props.index}

15 |

{this.props.title}

16 |

{(this.props.author_name || []).join(', ')}

17 |

{this.props.edition_count}

18 | 19 | ); 20 | } 21 | }); 22 | -------------------------------------------------------------------------------- /chapter8/src/BookTableHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default React.createClass({ 4 | shouldComponentUpdate() { 5 | return false; 6 | }, 7 | 8 | render() { 9 | return ( 10 | 11 | 12 | 13 |

Title

14 |

Author

15 |

No. of Editions

16 | 17 | 18 | ); 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /chapter8/src/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PureRenderMixin from 'react-addons-pure-render-mixin'; 3 | 4 | export default React.createClass({ 5 | mixins: [PureRenderMixin], 6 | 7 | // shouldComponentUpdate(nextProps, nextState) { 8 | // return false; 9 | // }, 10 | 11 | render() { 12 | return ( 13 |
14 |
15 |

Open Library | Search any book you want!

16 |
17 |
18 | ) 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /chapter8/src/RowAlternator.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | var RowAlternator = React.createClass({ 4 | propTypes: { 5 | firstColor: React.PropTypes.string, 6 | secondColor: React.PropTypes.string 7 | }, 8 | 9 | render() { 10 | return ( 11 | 12 | { this.props.children.map((row, idx) => { 13 | if (idx %2 == 0) { 14 | return React.cloneElement(row, { style: { background: this.props.firstColor }}); 15 | } else { 16 | return React.cloneElement(row, { style: { background: this.props.secondColor }}); 17 | } 18 | }) 19 | } 20 | 21 | ) 22 | } 23 | }); 24 | 25 | module.exports = RowAlternator; 26 | -------------------------------------------------------------------------------- /chapter8/src/Spinner.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default React.createClass({ 4 | shouldComponentUpdate() { 5 | return false; 6 | }, 7 | 8 | render() { 9 | return( 10 |
11 |
12 | 13 | 14 |
15 |
16 | ); 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /chapter8/src/index.js: -------------------------------------------------------------------------------- 1 | import ReactDOM from 'react-dom'; 2 | import React from 'react'; 3 | import App from './App'; 4 | import Perf from 'react-addons-perf'; 5 | 6 | window.Perf = Perf; 7 | window.Perf.start(); 8 | 9 | ReactDOM.render(, document.getElementById('rootElement')); 10 | -------------------------------------------------------------------------------- /chapter9/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "stage": 0 3 | } 4 | -------------------------------------------------------------------------------- /chapter9/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /chapter9/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "newcap": false 6 | } 7 | -------------------------------------------------------------------------------- /chapter9/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vipul A M 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /chapter9/README.md: -------------------------------------------------------------------------------- 1 | react-addons 2 | =========== 3 | 4 | Examples of React addons 5 | 6 | ### Usage 7 | 8 | ``` 9 | npm install 10 | npm start 11 | open http://localhost:9000 12 | npm test 13 | ``` 14 | -------------------------------------------------------------------------------- /chapter9/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | React Router/ Data Models 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /chapter9/server.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var WebpackDevServer = require('webpack-dev-server'); 3 | var config = require('./webpack.config'); 4 | 5 | new WebpackDevServer(webpack(config), { 6 | publicPath: config.output.publicPath, 7 | hot: true, 8 | historyApiFallback: true 9 | }).listen(9000, 'localhost', function (err, result) { 10 | if (err) { 11 | console.log(err); 12 | } 13 | 14 | console.log('Listening at localhost:9000'); 15 | }); 16 | -------------------------------------------------------------------------------- /chapter9/src/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Cats, PictureModel } from './models'; 3 | import { createHistory, useBasename } from 'history' 4 | import { Router, Route, IndexRoute, Link } from 'react-router' 5 | 6 | 7 | const Home = React.createClass({ 8 | render() { 9 | let sampleCat = Cats.sample(); 10 | return ( 11 |
12 |
13 | {Cats.map(cat => ( 14 | 15 | 16 | 17 | ))} 18 |
19 |

{`Interesting Details about ${sampleCat.get('name')}`}

20 |
21 | ) 22 | } 23 | }); 24 | 25 | 26 | export {Home as default} 27 | -------------------------------------------------------------------------------- /chapter9/src/Modal.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Router, Route, IndexRoute, Link } from 'react-router' 3 | 4 | const Modal = React.createClass({ 5 | styles: { 6 | position: 'fixed', 7 | top: '20%', 8 | right: '20%', 9 | bottom: '20%', 10 | left: '20%', 11 | padding: 20, 12 | boxShadow: '0px 0px 150px 130px rgba(0, 0, 0, 0.5)', 13 | overflow: 'auto', 14 | background: '#fff' 15 | }, 16 | 17 | render() { 18 | return ( 19 |
20 |

Back

21 | {this.props.children} 22 |
23 | ) 24 | } 25 | }) 26 | 27 | export {Modal as default} 28 | -------------------------------------------------------------------------------- /chapter9/src/Picture.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Cats, PictureModel } from './models'; 3 | 4 | const Picture = React.createClass({ 5 | render() { 6 | return ( 7 |
8 | 9 |
10 | ) 11 | } 12 | }); 13 | 14 | export {Picture as default} 15 | -------------------------------------------------------------------------------- /chapter9/src/Sample.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Cats, PictureModel } from './models'; 3 | import { createHistory, useBasename } from 'history' 4 | import { Router, Route, IndexRoute, Link } from 'react-router' 5 | 6 | const Sample = React.createClass({ 7 | render() { 8 | let cat = Cats.get(this.props.params.cid); 9 | return ( 10 |
11 |

CID for the Cat: {this.props.params.cid}, and Random ID: {this.props.params.randomId}

12 |

Name of this Cat is: {cat.get('name')}

13 |

Some interesting details about this Cat:

14 |

{cat.get('details')}

15 |

16 | 17 | Link to picture with Modal 18 |
19 | 20 | Without modal 21 | 22 |

23 |
24 | ) 25 | } 26 | }); 27 | 28 | 29 | export {Sample as default}; 30 | -------------------------------------------------------------------------------- /chapter9/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createHistory, useBasename } from 'history' 4 | import { Router, Route, IndexRoute, Link } from 'react-router' 5 | import Backbone from 'backbone'; 6 | import Modal from './Modal' 7 | import App from './App' 8 | import { Cats, PictureModel } from './models'; 9 | import Picture from './Picture' 10 | import Sample from './Sample' 11 | import Home from './Home' 12 | 13 | const history = useBasename(createHistory)({ 14 | basename: '/pinterest' 15 | }); 16 | 17 | 18 | render(( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ), document.getElementById('rootElement')); 27 | --------------------------------------------------------------------------------