From 46511e1253a9a99aa17c9d4f6b8184012f54375a Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Tue, 30 Jan 2018 09:54:45 -0500 Subject: [PATCH 1/4] Revert "[Develop] Upgrade to ES6" --- .babelrc | 3 - .eslintrc | 29 + .eslintrc.js | 3 - .tx/config | 6 - Makefile | 2 +- bin/configure-fastly.js | 47 +- bin/lib/fastly-config-methods.js | 10 +- bin/lib/fastly-extended.js | 52 +- dev-server/handler.js | 12 +- package.json | 45 +- src/.eslintrc.js | 10 - src/components/accordion/accordion.jsx | 56 +- src/components/adminpanel/adminpanel.jsx | 98 +- src/components/avatar/avatar.jsx | 39 +- src/components/box/box.jsx | 66 +- src/components/card/card.jsx | 25 +- src/components/carousel/carousel.jsx | 174 +- src/components/carousel/legacy-carousel.jsx | 175 +- src/components/comment/comment.jsx | 55 +- src/components/deck/deck.jsx | 41 +- src/components/dropdown-banner/banner.jsx | 52 +- src/components/dropdown/dropdown.jsx | 62 +- src/components/dropdown/dropdown.scss | 8 +- src/components/emoji-text/emoji-text.jsx | 48 +- src/components/flex-row/flex-row.jsx | 38 +- .../footer/conference/2016/footer.jsx | 247 +- .../footer/conference/2017/footer.jsx | 170 +- .../footer/conference/2018/footer.jsx | 216 +- src/components/footer/container/footer.jsx | 22 +- src/components/footer/www/footer.jsx | 429 +-- src/components/forms/button.jsx | 38 +- src/components/forms/charcount.jsx | 46 +- src/components/forms/checkbox-group.jsx | 38 +- src/components/forms/checkbox.jsx | 34 +- src/components/forms/form.jsx | 72 +- src/components/forms/general-error.jsx | 30 +- src/components/forms/input-hoc.jsx | 44 +- src/components/forms/input.jsx | 69 +- src/components/forms/phone-input.jsx | 71 +- src/components/forms/radio-group.jsx | 34 +- src/components/forms/select.jsx | 50 +- src/components/forms/textarea.jsx | 38 +- src/components/forms/validations.jsx | 62 +- src/components/grid/grid.jsx | 133 +- .../informationpage/informationpage.jsx | 55 +- src/components/intro/intro.jsx | 198 +- .../languagechooser/languagechooser.jsx | 73 +- src/components/login/login.jsx | 110 +- src/components/masonrygrid/masonrygrid.jsx | 82 +- src/components/microworld/microworld.jsx | 253 +- src/components/modal/base/modal.jsx | 74 +- src/components/modal/base/modal.scss | 2 +- src/components/modal/iframe/modal.jsx | 50 +- src/components/modal/ttt/modal.jsx | 241 +- src/components/navigation/base/navigation.jsx | 29 +- .../navigation/conference/2016/navigation.jsx | 77 +- .../navigation/conference/2017/navigation.jsx | 44 +- .../navigation/conference/2018/navigation.jsx | 44 +- src/components/navigation/www/navigation.jsx | 468 ++- .../nestedcarousel/nestedcarousel.jsx | 123 +- src/components/news/news.jsx | 91 +- src/components/page/conference/2016/page.jsx | 42 +- src/components/page/conference/2017/page.jsx | 42 +- src/components/page/conference/2018/page.jsx | 42 +- src/components/page/www/page.jsx | 52 +- src/components/progression/progression.jsx | 75 +- src/components/registration/registration.jsx | 81 +- src/components/registration/steps.jsx | 2590 +++++++---------- src/components/slide/slide.jsx | 25 +- .../social-message/social-message.jsx | 92 +- src/components/spinner/spinner.jsx | 28 +- .../stepnavigation/stepnavigation.jsx | 47 +- .../subnavigation/subnavigation.jsx | 48 +- src/components/tabs/tabs.jsx | 38 +- .../teacher-banner/teacher-banner.jsx | 166 +- src/components/thumbnail/thumbnail.jsx | 338 ++- src/components/title-banner/title-banner.jsx | 29 +- src/components/tooltip/tooltip.jsx | 60 +- src/components/ttt-tile/ttt-tile.jsx | 104 +- src/components/welcome/welcome.jsx | 134 +- src/init.js | 18 +- src/l10n.json | 3 - src/lib/api.js | 53 +- src/lib/country-data.js | 40 +- src/lib/format.js | 34 + src/lib/frameless.js | 5 +- src/lib/intl.jsx | 12 +- src/lib/jar.js | 65 +- src/lib/log.js | 2 +- src/lib/render.jsx | 39 +- src/lib/require-all.js | 6 +- src/lib/shuffle.js | 28 +- src/lib/url-params.js | 33 +- src/redux/conference-details.js | 101 +- src/redux/conference-schedule.js | 164 +- src/redux/message-count.js | 78 +- src/redux/messages.js | 252 +- src/redux/navigation.js | 18 +- src/redux/permissions.js | 64 +- src/redux/reducer.js | 16 +- src/redux/session.js | 132 +- src/redux/splash.js | 304 +- src/views/about/about.jsx | 346 ++- src/views/camp/camp.jsx | 290 +- src/views/cards/cards.jsx | 533 ++-- .../communityblocks-interviews.jsx | 120 +- src/views/components/components.jsx | 119 +- src/views/conference/2016/details/details.jsx | 121 +- src/views/conference/2016/expect/expect.jsx | 572 ++-- src/views/conference/2016/index/index.jsx | 146 +- src/views/conference/2016/plan/plan.jsx | 59 +- .../conference/2016/schedule/schedule.jsx | 201 +- src/views/conference/2017/index/index.jsx | 1026 ++++--- src/views/conference/2018/index/index.jsx | 289 +- src/views/credits/credits.jsx | 664 ++--- src/views/developers/developers.jsx | 685 +++-- src/views/dmca/dmca.jsx | 54 +- src/views/download/download.jsx | 218 +- src/views/explore/explore.jsx | 249 +- src/views/faq/faq.jsx | 424 +-- src/views/guidelines/guidelines.jsx | 77 +- src/views/jobs/jobs.jsx | 123 +- src/views/jobs/moderator/moderator.jsx | 175 +- src/views/messages/container.jsx | 191 +- .../messages/message-rows/admin-message.jsx | 70 +- .../messages/message-rows/become-manager.jsx | 84 +- .../messages/message-rows/comment-message.jsx | 287 +- .../messages/message-rows/curator-invite.jsx | 98 +- .../message-rows/favorite-project.jsx | 84 +- .../messages/message-rows/follow-user.jsx | 73 +- .../message-rows/forum-topic-post.jsx | 68 +- .../messages/message-rows/love-project.jsx | 84 +- .../messages/message-rows/remix-project.jsx | 95 +- .../message-rows/scratcher-invite.jsx | 94 +- .../messages/message-rows/studio-activity.jsx | 67 +- src/views/messages/message-rows/user-join.jsx | 72 +- src/views/messages/presentation.jsx | 617 ++-- src/views/microworld/art/art.jsx | 12 +- src/views/microworld/fashion/fashion.jsx | 12 +- src/views/microworld/hiphop/hiphop.jsx | 12 +- src/views/microworld/soccer/soccer.jsx | 12 +- .../microworldshomepage.jsx | 86 +- src/views/preview-faq/preview-faq.jsx | 50 +- src/views/privacypolicy/privacypolicy.jsx | 432 +-- src/views/search/search.jsx | 244 +- .../splash/activity-rows/become-curator.jsx | 82 +- .../splash/activity-rows/become-manager.jsx | 82 +- .../splash/activity-rows/favorite-project.jsx | 82 +- src/views/splash/activity-rows/follow.jsx | 107 +- .../splash/activity-rows/love-project.jsx | 82 +- .../splash/activity-rows/remix-project.jsx | 95 +- .../splash/activity-rows/share-project.jsx | 82 +- src/views/splash/l10n.json | 2 +- src/views/splash/presentation.jsx | 513 ++-- src/views/splash/splash.jsx | 311 +- .../studentcompleteregistration.jsx | 210 +- .../studentregistration.jsx | 199 +- .../teacherregistration.jsx | 171 +- src/views/teachers/faq/faq.jsx | 211 +- src/views/teachers/landing/landing.jsx | 271 +- .../teacherwaitingroom/teacherwaitingroom.jsx | 40 +- src/views/terms/terms.jsx | 1134 ++++---- src/views/tips/tips.jsx | 237 +- src/views/wedo2/wedo2.jsx | 277 +- test/helpers/selenium-helpers.js | 1 - .../smoke-testing/test_footer_links.js | 238 +- .../smoke-testing/test_navbar_links.js | 67 +- .../smoke-testing/test_project_rows.js | 71 +- .../test_signing_in_and_my_stuff.js | 288 +- .../test_signing_in_and_out_discuss.js | 32 +- .../test_signing_in_and_out_homepage.js | 31 +- .../smoke-testing/test_statistics_page.js | 36 +- .../teacher_registration_utils.js | 48 +- .../test_teacher_registration_address_step.js | 26 +- ..._teacher_registration_demographics_step.js | 42 +- .../test_teacher_registration_name_step.js | 26 +- ..._teacher_registration_organization_step.js | 31 +- .../test_teacher_registration_phone_step.js | 18 +- ...test_teacher_registration_username_step.js | 66 +- ...st_teacher_registration_usescratch_step.js | 25 +- test/localization/check_duplicate_strings.js | 20 +- test/localization/check_string_ids.js | 19 +- test/localization/check_valid_json.js | 4 +- test/unit/test_fastly_config_methods.js | 6 +- webpack.config.js | 113 +- 185 files changed, 11594 insertions(+), 13650 deletions(-) delete mode 100644 .babelrc create mode 100644 .eslintrc delete mode 100644 .eslintrc.js delete mode 100644 src/.eslintrc.js create mode 100644 src/lib/format.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 43777946d..000000000 --- a/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["es2015", "react"], -} diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 000000000..9cadb556a --- /dev/null +++ b/.eslintrc @@ -0,0 +1,29 @@ +{ + "parser": "babel-eslint", + "rules": { + "curly": [2, "multi-line"], + "eol-last": [2], + "indent": [2, 4], + "linebreak-style": [2, "unix"], + "max-len": [2, 120, 4, {"ignoreUrls": true}], + "no-trailing-spaces": [2, { "skipBlankLines": true }], + "no-unused-vars": [2, {"args": "after-used", "varsIgnorePattern": "^_"}], + "quotes": [2, "single"], + "semi": [2, "always"], + "space-before-function-paren": [2, "always"], + "strict": [2, "never"] + }, + "env": { + "browser": true, + "es6": true, + "node": true + }, + "globals": { + "formatMessage": true + }, + "plugins": [ + "react", + "json" + ], + "extends": "eslint:recommended" +} diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 36ff570d9..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ['scratch', 'scratch/node'] -}; diff --git a/.tx/config b/.tx/config index d36892ba7..2e63e88f3 100644 --- a/.tx/config +++ b/.tx/config @@ -133,9 +133,3 @@ file_filter = localizations/conference-index/.json source_file = src/views/conference/2018/index/l10n.json source_lang = en type = KEYVALUEJSON - -[scratch-website.preview-faq-l10njson] -file_filter = localizations/preview-faq/.json -source_file = src/views/preview-faq/l10n.json -source_lang = en -type = KEYVALUEJSON \ No newline at end of file diff --git a/Makefile b/Makefile index abe7f3a72..65a57a3ac 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ test: @make tap lint: - $(ESLINT) . --ext .js,.jsx + $(ESLINT) . --ext .js,.jsx,.json $(SASSLINT) ./src/*.scss $(SASSLINT) ./src/**/*.scss diff --git a/bin/configure-fastly.js b/bin/configure-fastly.js index a935b906e..edb7196ad 100644 --- a/bin/configure-fastly.js +++ b/bin/configure-fastly.js @@ -3,7 +3,7 @@ var defaults = require('lodash.defaults'); var fastlyConfig = require('./lib/fastly-config-methods'); const languages = require('../languages.json'); -var routeJson = require('../src/routes.json'); +var route_json = require('../src/routes.json'); const FASTLY_SERVICE_ID = process.env.FASTLY_SERVICE_ID || ''; const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME || ''; @@ -15,10 +15,10 @@ var extraAppRoutes = [ // TODO: Should this be added for every route? '/\\?', // View html - '/[^/]*.html$' + '/[^\/]*\.html$' ]; -var routes = routeJson.map(function (route) { +var routes = route_json.map(function (route) { return defaults({}, {pattern: fastlyConfig.expressPatternToRegex(route.pattern)}, route); }); @@ -28,9 +28,9 @@ async.auto({ if (err) return cb(err); // Validate latest version before continuing if (response.active || response.locked) { - fastly.cloneVersion(response.number, function (e, resp) { - if (e) return cb('Failed to clone latest version: ' + e); - cb(null, resp.number); + fastly.cloneVersion(response.number, function (err, response) { + if (err) return cb('Failed to clone latest version: ' + err); + cb(null, response.number); }); } else { cb(null, response.number); @@ -46,11 +46,11 @@ async.auto({ var recvCondition = '' + 'if (' + notPassStatement + ') {\n' + ' set req.backend = F_s3;\n' + - ' set req.http.host = "' + S3_BUCKET_NAME + '";\n' + + ' set req.http.host = \"' + S3_BUCKET_NAME + '\";\n' + '} else {\n' + ' if (!req.http.Fastly-FF) {\n' + ' if (req.http.X-Forwarded-For) {\n' + - ' set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For ", " client.ip;\n' + + ' set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For \", \" client.ip;\n' + ' } else {\n' + ' set req.http.Fastly-Temp-XFF = client.ip;\n' + ' }\n' + @@ -171,19 +171,20 @@ async.auto({ if (err) return cb(err); cb(null, headers); }); - }] -}, function (err, results) { - if (err) throw new Error(err); - if (process.env.FASTLY_ACTIVATE_CHANGES) { - fastly.activateVersion(results.version, function (e, resp) { - if (err) throw new Error(e); - process.stdout.write('Successfully configured and activated version ' + resp.number + '\n'); - if (process.env.FASTLY_PURGE_ALL) { - fastly.purgeAll(FASTLY_SERVICE_ID, function (error) { - if (error) throw new Error(error); - process.stdout.write('Purged all.\n'); - }); - } - }); + }]}, + function (err, results) { + if (err) throw new Error(err); + if (process.env.FASTLY_ACTIVATE_CHANGES) { + fastly.activateVersion(results.version, function (err, response) { + if (err) throw new Error(err); + process.stdout.write('Successfully configured and activated version ' + response.number + '\n'); + if (process.env.FASTLY_PURGE_ALL) { + fastly.purgeAll(FASTLY_SERVICE_ID, function (err) { + if (err) throw new Error(err); + process.stdout.write('Purged all.\n'); + }); + } + }); + } } -}); +); diff --git a/bin/lib/fastly-config-methods.js b/bin/lib/fastly-config-methods.js index d6a8c973d..750b1893b 100644 --- a/bin/lib/fastly-config-methods.js +++ b/bin/lib/fastly-config-methods.js @@ -24,9 +24,9 @@ var FastlyConfigMethods = { */ getViewPaths: function (routes) { return routes.reduce(function (paths, route) { - var p = route.routeAlias || route.pattern; - if (paths.indexOf(p) === -1) { - paths.push(p); + var path = route.routeAlias || route.pattern; + if (paths.indexOf(path) === -1) { + paths.push(path); } return paths; }, []); @@ -39,7 +39,7 @@ var FastlyConfigMethods = { * 2. /path/:arg([regex]) – :arg is removed, leaving just /path/([regex]) */ expressPatternToRegex: function (pattern) { - pattern = pattern.replace(/(:\w+)(\([^)]+\))/gi, '$2'); + pattern = pattern.replace(/(:\w+)(\([^\)]+\))/gi, '$2'); return pattern.replace(/(:\w+)/gi, '.+?'); }, @@ -84,7 +84,7 @@ var FastlyConfigMethods = { return 'redirects/' + route.pattern; }, - /* + /** * Returns custom vcl configuration as a string that sets the varnish * Time to Live (TTL) for responses that come from s3. * diff --git a/bin/lib/fastly-extended.js b/bin/lib/fastly-extended.js index 0e4467221..3ec9fd7e3 100644 --- a/bin/lib/fastly-extended.js +++ b/bin/lib/fastly-extended.js @@ -19,8 +19,8 @@ module.exports = function (apiKey, serviceId) { * * @return {string} */ - fastly.getFastlyAPIPrefix = function (servId, version) { - return '/service/' + encodeURIComponent(servId) + '/version/' + version; + fastly.getFastlyAPIPrefix = function (serviceId, version) { + return '/service/' + encodeURIComponent(serviceId) + '/version/' + version; }; /* @@ -32,15 +32,15 @@ module.exports = function (apiKey, serviceId) { if (!this.serviceId) { return cb('Failed to get latest version. No serviceId configured'); } - var url = '/service/' + encodeURIComponent(this.serviceId) + '/version'; + var url = '/service/'+ encodeURIComponent(this.serviceId) +'/version'; this.request('GET', url, function (err, versions) { if (err) { return cb('Failed to fetch versions: ' + err); } - var latestVersion = versions.reduce(function (lateVersion, version) { - if (!lateVersion) return version; - if (version.number > lateVersion.number) return version; - return lateVersion; + var latestVersion = versions.reduce(function (latestVersion, version) { + if (!latestVersion) return version; + if (version.number > latestVersion.number) return version; + return latestVersion; }); return cb(null, latestVersion); }); @@ -63,16 +63,16 @@ module.exports = function (apiKey, serviceId) { var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/condition'; return this.request('PUT', putUrl, condition, function (err, response) { if (err && err.statusCode === 404) { - this.request('POST', postUrl, condition, function (e, resp) { - if (e) { - return cb('Failed while inserting condition "' + condition.statement + '": ' + e); + this.request('POST', postUrl, condition, function (err, response) { + if (err) { + return cb('Failed while inserting condition \"' + condition.statement + '\": ' + err); } - return cb(null, resp); + return cb(null, response); }); return; } if (err) { - return cb('Failed to update condition "' + condition.statement + '": ' + err); + return cb('Failed to update condition \"' + condition.statement + '\": ' + err); } return cb(null, response); }.bind(this)); @@ -95,11 +95,11 @@ module.exports = function (apiKey, serviceId) { var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/header'; return this.request('PUT', putUrl, header, function (err, response) { if (err && err.statusCode === 404) { - this.request('POST', postUrl, header, function (e, resp) { - if (e) { - return cb('Failed to insert header: ' + e); + this.request('POST', postUrl, header, function (err, response) { + if (err) { + return cb('Failed to insert header: ' + err); } - return cb(null, resp); + return cb(null, response); }); return; } @@ -127,11 +127,11 @@ module.exports = function (apiKey, serviceId) { var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/response_object'; return this.request('PUT', putUrl, responseObj, function (err, response) { if (err && err.statusCode === 404) { - this.request('POST', postUrl, responseObj, function (e, resp) { - if (e) { - return cb('Failed to insert response object: ' + e); + this.request('POST', postUrl, responseObj, function (err, response) { + if (err) { + return cb('Failed to insert response object: ' + err); } - return cb(null, resp); + return cb(null, response); }); return; } @@ -166,7 +166,7 @@ module.exports = function (apiKey, serviceId) { this.request('PUT', url, cb); }; - /* + /** * Upsert a custom vcl file. Attempts a PUT, and falls back * to POST if not there already. * @@ -186,16 +186,16 @@ module.exports = function (apiKey, serviceId) { return this.request('PUT', url, content, function (err, response) { if (err && err.statusCode === 404) { content.name = name; - this.request('POST', postUrl, content, function (e, resp) { - if (e) { - return cb('Failed while adding custom vcl "' + name + '": ' + e); + this.request('POST', postUrl, content, function (err, response) { + if (err) { + return cb('Failed while adding custom vcl \"' + name + '\": ' + err); } - return cb(null, resp); + return cb(null, response); }); return; } if (err) { - return cb('Failed to update custom vcl "' + name + '": ' + err); + return cb('Failed to update custom vcl \"' + name + '\": ' + err); } return cb(null, response); }.bind(this)); diff --git a/dev-server/handler.js b/dev-server/handler.js index 339ceff5c..43c12857d 100644 --- a/dev-server/handler.js +++ b/dev-server/handler.js @@ -1,12 +1,10 @@ -/* +/** * Constructor */ -const Handler = function (route) { +function Handler (route) { // Handle redirects if (route.redirect) { - return (req, res) => { - res.redirect(route.redirect); - }; + return (req, res) => { res.redirect(route.redirect); }; } var url = '/' + route.name + '.html'; @@ -14,9 +12,9 @@ const Handler = function (route) { req.url = url; next(); }; -}; +} -/* +/** * Export a new instance */ module.exports = function (route) { diff --git a/package.json b/package.json index 9e9ec7fa4..68fec9862 100644 --- a/package.json +++ b/package.json @@ -33,27 +33,24 @@ "devDependencies": { "async": "1.5.2", "autoprefixer": "6.3.6", - "babel-cli": "6.26.0", - "babel-core": "6.23.1", - "babel-eslint": "8.0.2", - "babel-loader": "7.1.0", - "babel-preset-es2015": "6.22.0", - "babel-preset-react": "6.22.0", + "babel-core": "6.10.4", + "babel-eslint": "5.0.4", + "babel-loader": "6.2.4", + "babel-preset-es2015": "6.9.0", + "babel-preset-react": "6.11.1", "cheerio": "1.0.0-rc.2", - "classnames": "2.2.5", + "classnames": "2.1.3", "cookie": "0.2.2", "copy-webpack-plugin": "0.2.0", - "create-react-class": "15.6.2", "css-loader": "0.23.1", - "eslint": "4.7.1", - "eslint-config-scratch": "5.0.0", + "eslint": "1.3.1", "eslint-plugin-json": "1.2.0", - "eslint-plugin-react": "7.4.0", + "eslint-plugin-react": "3.3.1", "exenv": "1.2.0", "fastly": "1.2.1", "file-loader": "0.8.4", - "formsy-react": "0.19.5", - "formsy-react-components": "0.11.1", + "formsy-react": "0.18.0", + "formsy-react-components": "0.7.1", "git-bundle-sha": "0.0.2", "glob": "5.0.15", "google-libphonenumber": "1.0.21", @@ -62,7 +59,6 @@ "json-loader": "0.5.2", "json2po-stream": "1.0.3", "keymirror": "0.1.1", - "lodash.bindall": "4.4.0", "lodash.clone": "3.0.3", "lodash.defaultsdeep": "3.10.0", "lodash.isarray": "3.0.4", @@ -74,22 +70,21 @@ "node-sass": "4.6.1", "pako": "0.2.8", "po2icu": "0.0.2", - "postcss-loader": "2.0.10", - "prop-types": "15.6.0", + "postcss-loader": "0.8.2", "raven-js": "3.0.4", - "react": "15.5.4", - "react-dom": "15.5.4", + "react": "15.1.0", + "react-dom": "15.0.1", "react-intl": "2.1.2", - "react-modal": "3.1.11", - "react-onclickoutside": "6.7.1", + "react-modal": "1.5.2", + "react-onclickoutside": "4.1.1", "react-redux": "4.4.5", - "react-responsive": "3.0.0", + "react-responsive": "1.1.4", "react-slick": "0.12.2", - "react-telephone-input": "3.8.6", + "react-telephone-input": "3.4.5", "redux": "3.5.2", "redux-thunk": "2.0.1", "sass-lint": "1.5.1", - "sass-loader": "6.0.6", + "sass-loader": "2.0.1", "scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master", "slick-carousel": "1.5.8", "source-map-support": "0.3.2", @@ -97,8 +92,8 @@ "tap": "7.1.2", "url-loader": "0.5.6", "watch": "0.16.0", - "webpack": "2.7.0", - "webpack-dev-middleware": "2.0.4", + "webpack": "1.12.14", + "webpack-dev-middleware": "1.2.0", "xhr": "2.2.0" }, "nyc": { diff --git a/src/.eslintrc.js b/src/.eslintrc.js deleted file mode 100644 index 0abd74d67..000000000 --- a/src/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - root: true, - extends: ['scratch', 'scratch/es6', 'scratch/react'], - env: { - browser: true - }, - globals: { - process: true - } -}; diff --git a/src/components/accordion/accordion.jsx b/src/components/accordion/accordion.jsx index 431705395..e6e921a7b 100644 --- a/src/components/accordion/accordion.jsx +++ b/src/components/accordion/accordion.jsx @@ -1,35 +1,33 @@ -const bindAll = require('lodash.bindall'); -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); require('./accordion.scss'); -class Accordion extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleClick' - ]); - this.state = { +var Accordion = React.createClass({ + type: 'Accordion', + getDefaultProps: function () { + return { + titleAs: 'div', + contentAs: 'div' + }; + }, + getInitialState: function () { + return { isOpen: false }; - } - handleClick (e) { - e.preventDefault(); + }, + toggleContent: function () { this.setState({isOpen: !this.state.isOpen}); - } - render () { - const classes = classNames({ - content: true, - open: this.state.isOpen + }, + render: function () { + var classes = classNames({ + 'content': true, + 'open': this.state.isOpen }); return (
- + {this.props.title} @@ -38,16 +36,6 @@ class Accordion extends React.Component {
); } -} - -Accordion.propTypes = { - content: PropTypes.node, - title: PropTypes.string -}; - -Accordion.defaultProps = { - contentAs: 'div', - titleAs: 'div' -}; +}); module.exports = Accordion; diff --git a/src/components/adminpanel/adminpanel.jsx b/src/components/adminpanel/adminpanel.jsx index 4d9ac9e79..222258176 100644 --- a/src/components/adminpanel/adminpanel.jsx +++ b/src/components/adminpanel/adminpanel.jsx @@ -1,39 +1,37 @@ -const bindAll = require('lodash.bindall'); -const connect = require('react-redux').connect; -const PropTypes = require('prop-types'); -const React = require('react'); +var React = require('react'); +var connect = require('react-redux').connect; -const Button = require('../forms/button.jsx'); +var Button = require('../forms/button.jsx'); require('./adminpanel.scss'); -class AdminPanel extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleToggleVisibility' - ]); - this.state = { +var AdminPanel = React.createClass({ + type: 'AdminPanel', + getInitialState: function () { + return { showPanel: false }; - } - handleToggleVisibility (e) { + }, + handleToggleVisibility: function (e) { e.preventDefault(); this.setState({showPanel: !this.state.showPanel}); - } - render () { - if (!this.props.isAdmin) return false; + }, + render: function () { + // make sure user is present before checking if they're an admin. Don't show anything if user not an admin. + var showAdmin = false; + if (this.props.session.session.user) { + showAdmin = this.props.session.session.permissions.admin; + } + + if (!showAdmin) return false; if (this.state.showPanel) { return ( -
+
+ onClick={this.handleToggleVisibility}> + x
@@ -46,15 +44,8 @@ class AdminPanel extends React.Component {
  • -
    - + +
    For anonymous users:
    -
  • +
); + } else { + return ( +
+ + + > + +
+ ); } - return ( -
- - > - -
- ); } -} - -AdminPanel.propTypes = { - children: PropTypes.node, - isAdmin: PropTypes.bool -}; - -const mapStateToProps = state => ({ - isAdmin: state.permissions.admin }); -const ConnectedAdminPanel = connect(mapStateToProps)(AdminPanel); +var mapStateToProps = function (state) { + return { + session: state.session + }; +}; + +var ConnectedAdminPanel = connect(mapStateToProps)(AdminPanel); module.exports = ConnectedAdminPanel; diff --git a/src/components/avatar/avatar.jsx b/src/components/avatar/avatar.jsx index 566b97199..5830e5ffb 100644 --- a/src/components/avatar/avatar.jsx +++ b/src/components/avatar/avatar.jsx @@ -1,22 +1,23 @@ -const classNames = require('classnames'); -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); +var React = require('react'); +var classNames = require('classnames'); -const Avatar = props => ( - -); - -Avatar.propTypes = { - className: PropTypes.string, - src: PropTypes.string -}; - -Avatar.defaultProps = { - src: '//cdn2.scratch.mit.edu/get_image/user/2584924_24x24.png?v=1438702210.96' -}; +var Avatar = React.createClass({ + type: 'Avatar', + propTypes: { + src: React.PropTypes.string + }, + getDefaultProps: function () { + return { + src: '//cdn2.scratch.mit.edu/get_image/user/2584924_24x24.png?v=1438702210.96' + }; + }, + render: function () { + var classes = classNames( + 'avatar', + this.props.className + ); + return ; + } +}); module.exports = Avatar; diff --git a/src/components/box/box.jsx b/src/components/box/box.jsx index 832e27ea4..543bc15a2 100644 --- a/src/components/box/box.jsx +++ b/src/components/box/box.jsx @@ -1,38 +1,40 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); require('./box.scss'); -const Box = props => ( -
-
-

{props.title}

-
{props.subtitle}
-

- - {props.moreTitle} - -

-
+var Box = React.createClass({ + type: 'Box', + propTypes: { + title: React.PropTypes.string.isRequired, + subtitle: React.PropTypes.string, + moreTitle: React.PropTypes.string, + moreHref: React.PropTypes.string, + moreProps: React.PropTypes.object + }, + render: function () { + var classes = classNames( + 'box', + this.props.className + ); + return ( +
+
+

{this.props.title}

+
{this.props.subtitle}
+

+ + {this.props.moreTitle} + +

+
-
- {props.children} -
-
-); - -Box.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - moreHref: PropTypes.string, - moreProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types - moreTitle: PropTypes.string, - subtitle: PropTypes.string, - title: PropTypes.string.isRequired -}; +
+ {this.props.children} +
+
+ ); + } +}); module.exports = Box; diff --git a/src/components/card/card.jsx b/src/components/card/card.jsx index 37f6dc13c..5ac22fae1 100644 --- a/src/components/card/card.jsx +++ b/src/components/card/card.jsx @@ -1,18 +1,17 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); require('./card.scss'); -const Card = props => ( -
- {props.children} -
-); - -Card.propTypes = { - children: PropTypes.node, - className: PropTypes.string -}; +var Card = React.createClass({ + displayName: 'Card', + render: function () { + return ( +
+ {this.props.children} +
+ ); + } +}); module.exports = Card; diff --git a/src/components/carousel/carousel.jsx b/src/components/carousel/carousel.jsx index 5438d414f..46e01fa1a 100644 --- a/src/components/carousel/carousel.jsx +++ b/src/components/carousel/carousel.jsx @@ -1,115 +1,95 @@ -const classNames = require('classnames'); -const defaults = require('lodash.defaults'); -const PropTypes = require('prop-types'); -const React = require('react'); -const Slider = require('react-slick'); +var classNames = require('classnames'); +var defaults = require('lodash.defaults'); +var React = require('react'); +var Slider = require('react-slick'); -const Thumbnail = require('../thumbnail/thumbnail.jsx'); +var Thumbnail = require('../thumbnail/thumbnail.jsx'); -const frameless = require('../../lib/frameless.js'); +var frameless = require('../../lib/frameless.js'); require('slick-carousel/slick/slick.scss'); require('slick-carousel/slick/slick-theme.scss'); require('./carousel.scss'); -const Carousel = props => { - defaults(props.settings, { - centerMode: false, - dots: false, - infinite: false, - lazyLoad: true, - slidesToShow: 5, - slidesToScroll: 5, - variableWidth: true, - responsive: [ - { - breakpoint: frameless.mobile, - settings: { +/** + * Displays content in horizontal scrolling box. Example usage: splash page rows. + */ +var Carousel = React.createClass({ + type: 'Carousel', + propTypes: { + items: React.PropTypes.array + }, + getDefaultProps: function () { + return { + items: require('./carousel.json'), + showRemixes: false, + showLoves: false, + type: 'project' + }; + }, + render: function () { + var settings = this.props.settings || {}; + defaults(settings, { + centerMode: false, + dots: false, + infinite: false, + lazyLoad: true, + slidesToShow: 5, + slidesToScroll: 5, + variableWidth: true, + responsive: [ + {breakpoint: frameless.mobile, settings: { arrows: true, slidesToScroll: 1, slidesToShow: 1, centerMode: true - } - }, - { - breakpoint: frameless.tablet, - settings: { + }}, + {breakpoint: frameless.tablet, settings: { slidesToScroll: 2, slidesToShow: 2 - } - }, - { - breakpoint: frameless.desktop, - settings: { + }}, + {breakpoint: frameless.desktop, settings: { slidesToScroll: 4, slidesToShow: 4 - } - } - ] - }); - const arrows = props.items.length > props.settings.slidesToShow; - return ( - - {props.items.map(item => { - let href = ''; - switch (props.type) { - case 'gallery': - href = `/studios/${item.id}/`; - break; - case 'project': - href = `/projects/${item.id}/`; - break; - default: - href = `/${item.type}/${item.id}/`; - } + }} + ] + }); + var arrows = this.props.items.length > settings.slidesToShow; + var classes = classNames( + 'carousel', + this.props.className + ); + return ( + + {this.props.items.map(function (item) { + var href = ''; + switch (this.props.type) { + case 'gallery': + href = '/studios/' + item.id + '/'; + break; + case 'project': + href = '/projects/' + item.id + '/'; + break; + default: + href = '/' + item.type + '/' + item.id + '/'; + } - return ( - - ); - })} - - ); -}; - -Carousel.propTypes = { - className: PropTypes.string, - items: PropTypes.arrayOf(PropTypes.any), - settings: PropTypes.shape({ - centerMode: PropTypes.bool, - dots: PropTypes.bool, - infinite: PropTypes.bool, - lazyLoad: PropTypes.bool, - slidesToShow: PropTypes.number, - slidesToScroll: PropTypes.number, - variableWidth: PropTypes.bool, - responsive: PropTypes.array - }), - showLoves: PropTypes.bool, - showRemixes: PropTypes.bool, - type: PropTypes.string -}; - -Carousel.defaultProps = { - items: require('./carousel.json'), - settings: {}, - showRemixes: false, - showLoves: false, - type: 'project' -}; + return ( + + ); + }.bind(this))} + + ); + } +}); module.exports = Carousel; diff --git a/src/components/carousel/legacy-carousel.jsx b/src/components/carousel/legacy-carousel.jsx index d5ab1dbf8..36efb5cbf 100644 --- a/src/components/carousel/legacy-carousel.jsx +++ b/src/components/carousel/legacy-carousel.jsx @@ -1,118 +1,97 @@ // This component handles json returned via proxy from a django server, // or directly from a django server, and the model structure that system // has. -const classNames = require('classnames'); -const defaults = require('lodash.defaults'); -const PropTypes = require('prop-types'); -const React = require('react'); -const Slider = require('react-slick'); +var classNames = require('classnames'); +var defaults = require('lodash.defaults'); +var React = require('react'); +var Slider = require('react-slick'); -const Thumbnail = require('../thumbnail/thumbnail.jsx'); +var Thumbnail = require('../thumbnail/thumbnail.jsx'); -const frameless = require('../../lib/frameless.js'); +var frameless = require('../../lib/frameless.js'); require('slick-carousel/slick/slick.scss'); require('slick-carousel/slick/slick-theme.scss'); require('./carousel.scss'); -const Carousel = props => { - defaults(props.settings, { - centerMode: false, - dots: false, - infinite: false, - lazyLoad: true, - slidesToShow: 5, - slidesToScroll: 5, - variableWidth: true, - responsive: [ - { - breakpoint: frameless.mobile, - settings: { +/** + * Displays content in horizontal scrolling box. Example usage: splash page rows. + */ +var LegacyCarousel = React.createClass({ + type: 'LegacyCarousel', + propTypes: { + items: React.PropTypes.array + }, + getDefaultProps: function () { + return { + items: require('./carousel.json'), + showRemixes: false, + showLoves: false + }; + }, + render: function () { + var settings = this.props.settings || {}; + defaults(settings, { + centerMode: false, + dots: false, + infinite: false, + lazyLoad: true, + slidesToShow: 5, + slidesToScroll: 5, + variableWidth: true, + responsive: [ + {breakpoint: frameless.mobile, settings: { arrows: true, slidesToScroll: 1, slidesToShow: 1, centerMode: true - } - }, - { - breakpoint: frameless.tablet, - settings: { + }}, + {breakpoint: frameless.tablet, settings: { slidesToScroll: 2, slidesToShow: 2 - } - }, - { - breakpoint: frameless.desktop, - settings: { + }}, + {breakpoint: frameless.desktop, settings: { slidesToScroll: 4, slidesToShow: 4 - } - } - ] - }); - const arrows = props.items.length > props.settings.slidesToShow; - return ( - - {props.items.map(item => { - let href = ''; - switch (item.type) { - case 'gallery': - href = `/studios/${item.id}/`; - break; - case 'project': - href = `/projects/${item.id}/`; - break; - default: - href = `/${item.type}/${item.id}/`; - } + }} + ] + }); + var arrows = this.props.items.length > settings.slidesToShow; + var classes = classNames( + 'carousel', + this.props.className + ); + return ( + + {this.props.items.map(function (item) { + var href = ''; + switch (item.type) { + case 'gallery': + href = '/studios/' + item.id + '/'; + break; + case 'project': + href = '/projects/' + item.id + '/'; + break; + default: + href = '/' + item.type + '/' + item.id + '/'; + } - return ( - - ); - })} - - ); -}; + return ( + + ); + }.bind(this))} + + ); + } +}); -Carousel.propTypes = { - className: PropTypes.string, - items: PropTypes.arrayOf(PropTypes.any), - settings: PropTypes.shape({ - centerMode: PropTypes.bool, - dots: PropTypes.bool, - infinite: PropTypes.bool, - lazyLoad: PropTypes.bool, - slidesToShow: PropTypes.number, - slidesToScroll: PropTypes.number, - variableWidth: PropTypes.bool, - responsive: PropTypes.array - }), - showLoves: PropTypes.bool, - showRemixes: PropTypes.bool, - type: PropTypes.string -}; - -Carousel.defaultProps = { - items: require('./carousel.json'), - settings: {}, - showRemixes: false, - showLoves: false, - type: 'project' -}; - -module.exports = Carousel; +module.exports = LegacyCarousel; diff --git a/src/components/comment/comment.jsx b/src/components/comment/comment.jsx index 5edaeb51d..4a324799a 100644 --- a/src/components/comment/comment.jsx +++ b/src/components/comment/comment.jsx @@ -1,33 +1,34 @@ -const classNames = require('classnames'); -const FormattedRelative = require('react-intl').FormattedRelative; -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var FormattedRelative = require('react-intl').FormattedRelative; +var React = require('react'); -const EmojiText = require('../emoji-text/emoji-text.jsx'); +var EmojiText = require('../emoji-text/emoji-text.jsx'); require('./comment.scss'); -const CommentText = props => ( -
- - {typeof props.datetimeCreated === 'undefined' ? [] : [ -

- -

- ]} -
-); - -CommentText.propTypes = { - className: PropTypes.string, - comment: PropTypes.string.isRequired, - datetimeCreated: PropTypes.string -}; +var CommentText = React.createClass({ + type: 'CommentText', + propTypes: { + comment: React.PropTypes.string.isRequired, + datetimeCreated: React.PropTypes.string, + className: React.PropTypes.string + }, + render: function () { + var classes = classNames( + 'comment-text', + this.props.class + ); + return ( +
+ + {typeof this.props.datetimeCreated !== 'undefined' ? [ +

+ +

+ ] : []} +
+ ); + } +}); module.exports = CommentText; diff --git a/src/components/deck/deck.jsx b/src/components/deck/deck.jsx index 7d150a7e8..5d929c68a 100644 --- a/src/components/deck/deck.jsx +++ b/src/components/deck/deck.jsx @@ -1,29 +1,22 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); require('./deck.scss'); -const Deck = props => ( -
-
- - - - {props.children} -
-
-); - -Deck.propTypes = { - children: PropTypes.node, - className: PropTypes.string -}; +var Deck = React.createClass({ + displayName: 'Deck', + render: function () { + return ( +
+
+ + + + {this.props.children} +
+
+ ); + } +}); module.exports = Deck; diff --git a/src/components/dropdown-banner/banner.jsx b/src/components/dropdown-banner/banner.jsx index fa912f49e..e9808228e 100644 --- a/src/components/dropdown-banner/banner.jsx +++ b/src/components/dropdown-banner/banner.jsx @@ -1,29 +1,33 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); require('./banner.scss'); -const Banner = props => ( -
-
- {props.children} - {props.onRequestDismiss ? [ - x - ] : []} -
-
-); - -Banner.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - onRequestDismiss: PropTypes.func -}; +/** + * Container for messages displayed below the nav bar that can be dismissed + * (See: email not confirmed banner) + */ +var Banner = React.createClass({ + type: 'Banner', + propTypes: { + onRequestDismiss: React.PropTypes.func + }, + render: function () { + var classes = classNames( + 'banner', + this.props.className + ); + return ( +
+
+ {this.props.children} + {this.props.onRequestDismiss ? [ + x + ] : []} +
+
+ ); + } +}); module.exports = Banner; diff --git a/src/components/dropdown/dropdown.jsx b/src/components/dropdown/dropdown.jsx index 095194856..83990264b 100644 --- a/src/components/dropdown/dropdown.jsx +++ b/src/components/dropdown/dropdown.jsx @@ -1,46 +1,40 @@ -const bindAll = require('lodash.bindall'); -const classNames = require('classnames'); -const onClickOutside = require('react-onclickoutside').default; -const PropTypes = require('prop-types'); -const React = require('react'); +var React = require('react'); +var classNames = require('classnames'); require('./dropdown.scss'); -class Dropdown extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleClickOutside' - ]); - } - handleClickOutside () { +var Dropdown = React.createClass({ + type: 'Dropdown', + mixins: [ + require('react-onclickoutside') + ], + propTypes: { + onRequestClose: React.PropTypes.func, + isOpen: React.PropTypes.bool + }, + getDefaultProps: function () { + return { + as: 'div', + isOpen: false + }; + }, + handleClickOutside: function () { if (this.props.isOpen) { this.props.onRequestClose(); } - } - render () { + }, + render: function () { + var classes = classNames( + 'dropdown', + this.props.className, + {open: this.props.isOpen} + ); return ( - + {this.props.children} ); } -} +}); -Dropdown.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - isOpen: PropTypes.bool, - onRequestClose: PropTypes.func.isRequired -}; - -Dropdown.defaultProps = { - as: 'div', - isOpen: false -}; - -module.exports = onClickOutside(Dropdown); +module.exports = Dropdown; diff --git a/src/components/dropdown/dropdown.scss b/src/components/dropdown/dropdown.scss index 6aea2f067..66af291ef 100644 --- a/src/components/dropdown/dropdown.scss +++ b/src/components/dropdown/dropdown.scss @@ -24,12 +24,8 @@ } a { - &:link, - &:visited, - &:active { - background-color: transparent; - color: $type-white; - } + background-color: transparent; + color: $type-white; } input { diff --git a/src/components/emoji-text/emoji-text.jsx b/src/components/emoji-text/emoji-text.jsx index ee4c00a52..c6f382260 100644 --- a/src/components/emoji-text/emoji-text.jsx +++ b/src/components/emoji-text/emoji-text.jsx @@ -1,25 +1,33 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); require('./emoji-text.scss'); -const EmojiText = props => ( - -); - -EmojiText.propTypes = { - className: PropTypes.string, - text: PropTypes.string.isRequired -}; - -EmojiText.defaultProps = { - as: 'p' -}; +var EmojiText = React.createClass({ + type: 'EmojiText', + propTyes: { + text: React.PropTypes.string.isRequired, + className: React.PropTypes.string + }, + getDefaultProps: function () { + return { + as: 'p' + }; + }, + render: function () { + var classes = classNames( + 'emoji-text', + this.props.className + ); + return ( + + ); + } +}); module.exports = EmojiText; diff --git a/src/components/flex-row/flex-row.jsx b/src/components/flex-row/flex-row.jsx index 4dc8582c6..4a2deb36e 100644 --- a/src/components/flex-row/flex-row.jsx +++ b/src/components/flex-row/flex-row.jsx @@ -1,22 +1,26 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); require('./flex-row.scss'); -const FlexRow = props => ( - - {props.children} - -); - -FlexRow.propTypes = { - children: PropTypes.node, - className: PropTypes.string -}; - -FlexRow.defaultProps = { - as: 'div' -}; +var FlexRow = React.createClass({ + type: 'FlexRow', + getDefaultProps: function () { + return { + as: 'div' + }; + }, + render: function () { + var classes = classNames( + 'flex-row', + this.props.className + ); + return ( + + {this.props.children} + + ); + } +}); module.exports = FlexRow; diff --git a/src/components/footer/conference/2016/footer.jsx b/src/components/footer/conference/2016/footer.jsx index 76207f6af..b342e59fd 100644 --- a/src/components/footer/conference/2016/footer.jsx +++ b/src/components/footer/conference/2016/footer.jsx @@ -1,152 +1,125 @@ -const React = require('react'); +var React = require('react'); -const FlexRow = require('../../../flex-row/flex-row.jsx'); -const FooterBox = require('../../container/footer.jsx'); +var FlexRow = require('../../../flex-row/flex-row.jsx'); +var FooterBox = require('../../container/footer.jsx'); require('../footer.scss'); -const ConferenceFooter = () => ( - -
-

Sponsors

- -
  • - - MIT Office of Digital Learning - -
  • -
  • - - Intel - -
  • -
  • - - LEGO Foundation - -
  • -
  • - - Google - -
  • -
  • - - Siegel Family Endowment - -
  • -
  • - - No Starch Press - -
  • -
  • - - Scratch Foundation - -
  • -
    -
    - -
    -

    Scratch Family

    - - -
  • - Scratch -
  • -
  • - ScratchJr -
  • -
    - -
  • - Scratch Foundation -
  • -
  • - ScratchEd -
  • -
    - -
  • - Scratch Day -
  • -
    -
    -

    - Scratch is a project of the Lifelong Kindergarten Group at the MIT Media Lab. -

    -
    -
    -
    -

    Contact

    -

    - - Email Us - -

    -
    -
    +var ConferenceFooter = React.createClass({ + type: 'ConferenceFooter', + render: function () { + return ( + + -
    - - -); + +
    +

    Scratch Family

    + + +
  • + Scratch +
  • +
  • + ScratchJr +
  • +
    + +
  • + Scratch Foundation +
  • +
  • + ScratchEd +
  • +
    + +
  • + Scratch Day +
  • +
    +
    +

    + Scratch is a project of the Lifelong Kindergarten Group at the MIT Media Lab. +

    +
    +
    +
    +

    Contact

    +

    + + Email Us + +

    +
    +
    + +
  • + + scratch twitter + +
  • +
  • + + scratch facebook + +
  • +
  • + + scratch foundation blog + +
  • +
    +
    +
    +
    + + ); + } +}); module.exports = ConferenceFooter; diff --git a/src/components/footer/conference/2017/footer.jsx b/src/components/footer/conference/2017/footer.jsx index d026ce7ee..ebd11f36d 100644 --- a/src/components/footer/conference/2017/footer.jsx +++ b/src/components/footer/conference/2017/footer.jsx @@ -1,100 +1,84 @@ -const injectIntl = require('react-intl').injectIntl; -const intlShape = require('react-intl').intlShape; -const FormattedMessage = require('react-intl').FormattedMessage; -const React = require('react'); +var React = require('react'); +var ReactIntl = require('react-intl'); -const FlexRow = require('../../../flex-row/flex-row.jsx'); -const FooterBox = require('../../container/footer.jsx'); -const LanguageChooser = require('../../../languagechooser/languagechooser.jsx'); +var injectIntl = ReactIntl.injectIntl; +var FormattedMessage = ReactIntl.FormattedMessage; + +var FlexRow = require('../../../flex-row/flex-row.jsx'); +var FooterBox = require('../../container/footer.jsx'); +var LanguageChooser = require('../../../languagechooser/languagechooser.jsx'); require('../footer.scss'); -const ConferenceFooter = props => ( - - -
    -

    - - -
  • - Scratch -
  • -
  • - ScratchJr -
  • -
    - -
  • - Scratch Foundation -
  • -
  • - ScratchEd -
  • -
    - -
  • - Scratch Day -
  • -
    +var ConferenceFooter = React.createClass({ + type: 'ConferenceFooter', + render: function () { + return ( + + +
    +

    + + +
  • + Scratch +
  • +
  • + ScratchJr +
  • +
    + +
  • + Scratch Foundation +
  • +
  • + ScratchEd +
  • +
    + +
  • + Scratch Day +
  • +
    +
    +

    + +

    +
    +
    +
    +

    Contact

    +

    + + Email Us + +

    +
    +
    + +
  • + + scratch twitter + +
  • +
  • + + scratch facebook + +
  • +
  • + + scratch foundation blog + +
  • +
    +
    +
    -

    - -

    -
    -
    -
    -

    Contact

    -

    - - Email Us - -

    -
    -
    - -
  • - - scratch twitter - -
  • -
  • - - scratch facebook - -
  • -
  • - - scratch foundation blog - -
  • -
    -
    -
    -
    - -
    -); - -ConferenceFooter.propTypes = { - intl: intlShape -}; + + + ); + } +}); module.exports = injectIntl(ConferenceFooter); diff --git a/src/components/footer/conference/2018/footer.jsx b/src/components/footer/conference/2018/footer.jsx index 1a08cc823..06daa2e92 100644 --- a/src/components/footer/conference/2018/footer.jsx +++ b/src/components/footer/conference/2018/footer.jsx @@ -1,146 +1,84 @@ -const FormattedMessage = require('react-intl').FormattedMessage; -const injectIntl = require('react-intl').injectIntl; -const intlShape = require('react-intl').intlShape; -const React = require('react'); +var React = require('react'); +var ReactIntl = require('react-intl'); -const FlexRow = require('../../../flex-row/flex-row.jsx'); -const FooterBox = require('../../container/footer.jsx'); -const LanguageChooser = require('../../../languagechooser/languagechooser.jsx'); +var injectIntl = ReactIntl.injectIntl; +var FormattedMessage = ReactIntl.FormattedMessage; + +var FlexRow = require('../../../flex-row/flex-row.jsx'); +var FooterBox = require('../../container/footer.jsx'); +var LanguageChooser = require('../../../languagechooser/languagechooser.jsx'); require('../footer.scss'); -const ConferenceFooter = props => ( - - -
    -

    - - -
  • - - Scratch - -
  • -
  • - - ScratchJr - -
  • -
    - -
  • - - Scratch Foundation - -
  • -
  • - - ScratchEd - -
  • -
    - -
  • - - Scratch Day - -
  • -
    +var ConferenceFooter = React.createClass({ + type: 'ConferenceFooter', + render: function () { + return ( + + +
    +

    + + +
  • + Scratch +
  • +
  • + ScratchJr +
  • +
    + +
  • + Scratch Foundation +
  • +
  • + ScratchEd +
  • +
    + +
  • + Scratch Day +
  • +
    +
    +

    + +

    +
    +
    +
    +

    Contact

    +

    + + Email Us + +

    +
    +
    + +
  • + + scratch twitter + +
  • +
  • + + scratch facebook + +
  • +
  • + + scratch foundation blog + +
  • +
    +
    +
    -

    - -

    -
    -
    -
    -

    Contact

    -

    - - Email Us - -

    -
    -
    - -
  • - - scratch twitter - -
  • -
  • - - scratch facebook - -
  • -
  • - - scratch foundation blog - -
  • -
    -
    -
    -
    - -
    -); - -ConferenceFooter.propTypes = { - intl: intlShape -}; + + + ); + } +}); module.exports = injectIntl(ConferenceFooter); diff --git a/src/components/footer/container/footer.jsx b/src/components/footer/container/footer.jsx index f629e9f39..53f7eba59 100644 --- a/src/components/footer/container/footer.jsx +++ b/src/components/footer/container/footer.jsx @@ -1,16 +1,16 @@ -const PropTypes = require('prop-types'); -const React = require('react'); +var React = require('react'); require('./footer.scss'); -const FooterBox = props => ( -
    - {props.children} -
    -); - -FooterBox.propTypes = { - children: PropTypes.node -}; +var FooterBox = React.createClass({ + type: 'FooterBox', + render: function () { + return ( +
    + {this.props.children} +
    + ); + } +}); module.exports = FooterBox; diff --git a/src/components/footer/www/footer.jsx b/src/components/footer/www/footer.jsx index e983b4f8b..0cfaa46cd 100644 --- a/src/components/footer/www/footer.jsx +++ b/src/components/footer/www/footer.jsx @@ -1,225 +1,226 @@ -const FormattedMessage = require('react-intl').FormattedMessage; -const injectIntl = require('react-intl').injectIntl; -const intlShape = require('react-intl').intlShape; -const MediaQuery = require('react-responsive').default; -const React = require('react'); +var React = require('react'); +var ReactIntl = require('react-intl'); +var FormattedMessage = ReactIntl.FormattedMessage; +var injectIntl = ReactIntl.injectIntl; -const FooterBox = require('../container/footer.jsx'); -const LanguageChooser = require('../../languagechooser/languagechooser.jsx'); +var FooterBox = require('../container/footer.jsx'); +var LanguageChooser = require('../../languagechooser/languagechooser.jsx'); -const frameless = require('../../../lib/frameless'); +var MediaQuery = require('react-responsive'); +var frameless = require('../../../lib/frameless'); require('./footer.scss'); -const Footer = props => ( - - -
    -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    -
    -
    - -
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    +var Footer = React.createClass({ + type: 'Footer', + render: function () { + return ( + + +
    +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +
    +
    + +
    +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - Scratch Day - -
    -
    - - - -
    -
    - - - -
    -
    -
    -
    - +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + Scratch Day + +
    +
    + + + +
    +
    + + + +
    +
    +
    +
    + -
    -

    - -

    -
    -
    -); - -Footer.propTypes = { - intl: intlShape.isRequired -}; +
    +

    + +

    +
    + + ); + } +}); module.exports = injectIntl(Footer); diff --git a/src/components/forms/button.jsx b/src/components/forms/button.jsx index b5b97e39a..2c12d7db7 100644 --- a/src/components/forms/button.jsx +++ b/src/components/forms/button.jsx @@ -1,26 +1,22 @@ -const classNames = require('classnames'); -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); +var React = require('react'); +var classNames = require('classnames'); require('./button.scss'); -const Button = props => { - const classes = classNames('button', props.className); - - return ( - - ); -}; - -Button.propTypes = { - children: PropTypes.node, - className: PropTypes.string -}; +var Button = React.createClass({ + type: 'Button', + propTypes: { + + }, + render: function () { + var classes = classNames( + 'button', + this.props.className + ); + return ( + + ); + } +}); module.exports = Button; diff --git a/src/components/forms/charcount.jsx b/src/components/forms/charcount.jsx index bf46c95f4..af6192ebe 100644 --- a/src/components/forms/charcount.jsx +++ b/src/components/forms/charcount.jsx @@ -1,28 +1,28 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); require('./charcount.scss'); -const CharCount = props => ( -

    props.maxCharacters) - })} - > - {props.currentCharacters}/{props.maxCharacters} -

    -); - -CharCount.propTypes = { - className: PropTypes.string, - currentCharacters: PropTypes.number, - maxCharacters: PropTypes.number -}; - -CharCount.defaultProps = { - currentCharacters: 0, - maxCharacters: 0 -}; +var CharCount = React.createClass({ + type: 'CharCount', + getDefaultProps: function () { + return { + maxCharacters: 0, + currentCharacters: 0 + }; + }, + render: function () { + var classes = classNames( + 'char-count', + this.props.className, + {overmax: (this.props.currentCharacters > this.props.maxCharacters)} + ); + return ( +

    + {this.props.currentCharacters}/{this.props.maxCharacters} +

    + ); + } +}); module.exports = CharCount; diff --git a/src/components/forms/checkbox-group.jsx b/src/components/forms/checkbox-group.jsx index c98a0e5dd..29321d268 100644 --- a/src/components/forms/checkbox-group.jsx +++ b/src/components/forms/checkbox-group.jsx @@ -1,25 +1,25 @@ -const classNames = require('classnames'); -const FRCCheckboxGroup = require('formsy-react-components').CheckboxGroup; -const PropTypes = require('prop-types'); -const React = require('react'); - -const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -const inputHOC = require('./input-hoc.jsx'); +var classNames = require('classnames'); +var FRCCheckboxGroup = require('formsy-react-components').CheckboxGroup; +var React = require('react'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +var inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./checkbox-group.scss'); -const CheckboxGroup = props => ( -
    - -
    -); - -CheckboxGroup.propTypes = { - className: PropTypes.string -}; +var CheckboxGroup = React.createClass({ + type: 'CheckboxGroup', + render: function () { + var classes = classNames( + 'checkbox-group', + this.props.className + ); + return ( +
    + +
    + ); + } +}); module.exports = inputHOC(defaultValidationHOC(CheckboxGroup)); diff --git a/src/components/forms/checkbox.jsx b/src/components/forms/checkbox.jsx index fcaac2293..f0aa295b8 100644 --- a/src/components/forms/checkbox.jsx +++ b/src/components/forms/checkbox.jsx @@ -1,23 +1,23 @@ -const classNames = require('classnames'); -const FRCCheckbox = require('formsy-react-components').Checkbox; -const PropTypes = require('prop-types'); -const React = require('react'); - -const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -const inputHOC = require('./input-hoc.jsx'); +var classNames = require('classnames'); +var FRCCheckbox = require('formsy-react-components').Checkbox; +var React = require('react'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +var inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./checkbox.scss'); -const Checkbox = props => ( - -); - -Checkbox.propTypes = { - className: PropTypes.string -}; +var Checkbox = React.createClass({ + type: 'Checkbox', + render: function () { + var classes = classNames( + 'checkbox-row', + this.props.className + ); + return ( + + ); + } +}); module.exports = inputHOC(defaultValidationHOC(Checkbox)); diff --git a/src/components/forms/form.jsx b/src/components/forms/form.jsx index 1514787b7..17ada223a 100644 --- a/src/components/forms/form.jsx +++ b/src/components/forms/form.jsx @@ -1,61 +1,47 @@ -const bindAll = require('lodash.bindall'); -const classNames = require('classnames'); -const Formsy = require('formsy-react'); -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var Formsy = require('formsy-react'); +var omit = require('lodash.omit'); +var React = require('react'); +var validations = require('./validations.jsx').validations; -const validations = require('./validations.jsx').validations; - -for (const validation in validations) { +for (var validation in validations) { Formsy.addValidationRule(validation, validations[validation]); } -class Form extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleChange' - ]); - this.state = { +var Form = React.createClass({ + getDefaultProps: function () { + return { + noValidate: true, + onChange: function () {} + }; + }, + getInitialState: function () { + return { allValues: {} }; - } - handleChange (currentValues, isChanged) { + }, + onChange: function (currentValues, isChanged) { this.setState({allValues: omit(currentValues, 'all')}); this.props.onChange(currentValues, isChanged); - } - render () { + }, + render: function () { + var classes = classNames( + 'form', + this.props.className + ); return ( - { - this.formsy = form; - }} - onChange={this.handleChange} - {...this.props} - > - {React.Children.map(this.props.children, child => { + + {React.Children.map(this.props.children, function (child) { if (!child) return child; if (child.props.name === 'all') { return React.cloneElement(child, {value: this.state.allValues}); + } else { + return child; } - return child; - })} + }.bind(this))} ); } -} - -Form.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - onChange: PropTypes.func -}; - -Form.defaultProps = { - noValidate: true, - onChange: function () {} -}; +}); module.exports = Form; diff --git a/src/components/forms/general-error.jsx b/src/components/forms/general-error.jsx index 270e3ca39..d9e20463b 100644 --- a/src/components/forms/general-error.jsx +++ b/src/components/forms/general-error.jsx @@ -1,6 +1,5 @@ -const Formsy = require('formsy-react'); -const PropTypes = require('prop-types'); -const React = require('react'); +var Formsy = require('formsy-react'); +var React = require('react'); require('./general-error.scss'); @@ -11,18 +10,13 @@ require('./general-error.scss'); * give it a name, and apply your validation error to * the name of the GeneralError component. */ -const GeneralError = props => { - if (!props.showError()) return null; - return ( -

    - {props.getErrorMessage()} -

    - ); -}; - -GeneralError.propTypes = { - getErrorMessage: PropTypes.func, - showError: PropTypes.func -}; - -module.exports = Formsy.HOC(GeneralError); +module.exports = Formsy.HOC(React.createClass({ + render: function () { + if (!this.props.showError()) return null; + return ( +

    + {this.props.getErrorMessage()} +

    + ); + } +})); diff --git a/src/components/forms/input-hoc.jsx b/src/components/forms/input-hoc.jsx index 1ce3c1c0b..1532eaefd 100644 --- a/src/components/forms/input-hoc.jsx +++ b/src/components/forms/input-hoc.jsx @@ -1,32 +1,20 @@ -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); +var React = require('react'); -/** - * Higher-order component for building an input field - * @param {React.Component} Component an input component - * @return {React.Component} a wrapped input component - */ -module.exports = Component => { - const InputComponent = props => ( - - ); - - InputComponent.propTypes = { - messages: PropTypes.shape({ - 'general.notRequired': PropTypes.string - }), - required: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]) - }; - - InputComponent.defaultProps = { - messages: { - 'general.notRequired': 'Not Required' +module.exports = function InputComponentMixin (Component) { + var InputComponent = React.createClass({ + getDefaultProps: function () { + return { + messages: { + 'general.notRequired': 'Not Required' + } + }; + }, + render: function () { + return ( + + ); } - }; - + }); return InputComponent; }; diff --git a/src/components/forms/input.jsx b/src/components/forms/input.jsx index a9992a40c..3244ade3c 100644 --- a/src/components/forms/input.jsx +++ b/src/components/forms/input.jsx @@ -1,57 +1,46 @@ -const bindAll = require('lodash.bindall'); -const classNames = require('classnames'); -const FRCInput = require('formsy-react-components').Input; -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); - -const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -const inputHOC = require('./input-hoc.jsx'); +var classNames = require('classnames'); +var FRCInput = require('formsy-react-components').Input; +var React = require('react'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +var inputHOC = require('./input-hoc.jsx'); require('./input.scss'); require('./row.scss'); -class Input extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleInvalid', - 'handleValid' - ]); - this.state = { +var Input = React.createClass({ + type: 'Input', + getDefaultProps: function () { + return {}; + }, + getInitialState: function () { + return { status: '' }; - } - handleValid () { + }, + onValid: function () { this.setState({ status: 'pass' }); - } - handleInvalid () { + }, + onInvalid: function () { this.setState({ status: 'fail' }); - } - render () { + }, + render: function () { + var classes = classNames( + this.state.status, + this.props.className, + {'no-label': (typeof this.props.label === 'undefined')} + ); return ( - + ); } -} - -Input.propTypes = { - className: PropTypes.string, - label: PropTypes.string -}; +}); module.exports = inputHOC(defaultValidationHOC(Input)); diff --git a/src/components/forms/phone-input.jsx b/src/components/forms/phone-input.jsx index 69d8ab23f..260c5a2ef 100644 --- a/src/components/forms/phone-input.jsx +++ b/src/components/forms/phone-input.jsx @@ -1,33 +1,23 @@ -const allCountries = require('react-telephone-input/lib/country_data').allCountries; -const classNames = require('classnames'); -const ComponentMixin = require('formsy-react-components').ComponentMixin; -const createReactClass = require('create-react-class'); -const FormsyMixin = require('formsy-react').Mixin; -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); -const ReactPhoneInput = require('react-telephone-input/lib/withStyles').default; -const Row = require('formsy-react-components').Row; +var allCountries = require('react-telephone-input/lib/country_data').allCountries; +var classNames = require('classnames'); +var ComponentMixin = require('formsy-react-components').ComponentMixin; +var FormsyMixin = require('formsy-react').Mixin; +var React = require('react'); +var ReactPhoneInput = require('react-telephone-input/lib/withStyles'); +var Row = require('formsy-react-components').Row; -const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -const inputHOC = require('./input-hoc.jsx'); -const intl = require('../../lib/intl.jsx'); -const validationHOCFactory = require('./validations.jsx').validationHOCFactory; +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +var inputHOC = require('./input-hoc.jsx'); +var intl = require('../../lib/intl.jsx'); +var validationHOCFactory = require('./validations.jsx').validationHOCFactory; -const allIso2 = allCountries.map(country => (country.iso2)); +var allIso2 = allCountries.map(function (country) {return country.iso2;}); require('./row.scss'); require('./phone-input.scss'); -const PhoneInput = createReactClass({ // eslint-disable-line react/prefer-es6-class +var PhoneInput = React.createClass({ displayName: 'PhoneInput', - propTypes: { - className: PropTypes.string, - defaultCountry: PropTypes.string, - disabled: PropTypes.bool, - name: PropTypes.string, - onChange: PropTypes.func - }, mixins: [ FormsyMixin, ComponentMixin @@ -41,34 +31,29 @@ const PhoneInput = createReactClass({ // eslint-disable-line react/prefer-es6-cl defaultCountry: 'us' }; }, - handleChangeInput: function (number, country) { - const value = { - national_number: number, - country_code: country - }; + onChangeInput: function (number, country) { + var value = {national_number: number, country_code: country}; this.setValue(value); this.props.onChange(this.props.name, value); }, render: function () { - let defaultCountry = PhoneInput.getDefaultProps().defaultCountry; + var defaultCountry = PhoneInput.getDefaultProps().defaultCountry; if (allIso2.indexOf(this.props.defaultCountry.toLowerCase()) !== -1) { - defaultCountry = this.props.defaultCountry.toLowerCase(); + defaultCountry = this.props.defaultCountry.toLowerCase(); } return ( -
    - {this.renderHelp()} {this.renderErrorMessage()} @@ -78,7 +63,7 @@ const PhoneInput = createReactClass({ // eslint-disable-line react/prefer-es6-cl } }); -const phoneValidationHOC = validationHOCFactory({ +var phoneValidationHOC = validationHOCFactory({ isPhone: }); diff --git a/src/components/forms/radio-group.jsx b/src/components/forms/radio-group.jsx index 168f0a926..fcdf928a6 100644 --- a/src/components/forms/radio-group.jsx +++ b/src/components/forms/radio-group.jsx @@ -1,23 +1,23 @@ -const classNames = require('classnames'); -const FRCRadioGroup = require('formsy-react-components').RadioGroup; -const PropTypes = require('prop-types'); -const React = require('react'); - -const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -const inputHOC = require('./input-hoc.jsx'); +var classNames = require('classnames'); +var FRCRadioGroup = require('formsy-react-components').RadioGroup; +var React = require('react'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +var inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./radio-group.scss'); -const RadioGroup = props => ( - -); - -RadioGroup.propTypes = { - className: PropTypes.string -}; +var RadioGroup = React.createClass({ + type: 'RadioGroup', + render: function () { + var classes = classNames( + 'radio-group', + this.props.className + ); + return ( + + ); + } +}); module.exports = inputHOC(defaultValidationHOC(RadioGroup)); diff --git a/src/components/forms/select.jsx b/src/components/forms/select.jsx index 16a7e1ee2..a17053942 100644 --- a/src/components/forms/select.jsx +++ b/src/components/forms/select.jsx @@ -1,31 +1,33 @@ -const classNames = require('classnames'); -const defaults = require('lodash.defaultsdeep'); -const FRCSelect = require('formsy-react-components').Select; -const PropTypes = require('prop-types'); -const React = require('react'); - -const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -const inputHOC = require('./input-hoc.jsx'); +var classNames = require('classnames'); +var defaults = require('lodash.defaultsdeep'); +var FRCSelect = require('formsy-react-components').Select; +var React = require('react'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +var inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./select.scss'); -const Select = props => { - if (props.required && !props.value) { - props = defaults({}, props, {value: props.options[0].value}); +var Select = React.createClass({ + type: 'Select', + propTypes: { + + }, + render: function () { + var classes = classNames( + 'select', + this.props.className + ); + var props = this.props; + if (this.props.required && !this.props.value) { + props = defaults({}, this.props, {value: this.props.options[0].value}); + } + return ( +
    + +
    + ); } - return ( -
    - -
    - ); -}; - -Select.propTypes = { - className: PropTypes.string, - options: PropTypes.arrayOf(PropTypes.any), - required: PropTypes.bool, - value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) -}; +}); module.exports = inputHOC(defaultValidationHOC(Select)); diff --git a/src/components/forms/textarea.jsx b/src/components/forms/textarea.jsx index 0c488f995..ec90f8b59 100644 --- a/src/components/forms/textarea.jsx +++ b/src/components/forms/textarea.jsx @@ -1,25 +1,25 @@ -const classNames = require('classnames'); -const FRCTextarea = require('formsy-react-components').Textarea; -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); - -const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -const inputHOC = require('./input-hoc.jsx'); +var classNames = require('classnames'); +var FRCTextarea = require('formsy-react-components').Textarea; +var React = require('react'); +var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +var inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./textarea.scss'); -const TextArea = props => ( - -); - -TextArea.propTypes = { - className: PropTypes.string -}; +var TextArea = React.createClass({ + type: 'TextArea', + render: function () { + var classes = classNames( + 'textarea-row', + this.props.className + ); + return ( + + ); + } +}); module.exports = inputHOC(defaultValidationHOC(TextArea)); diff --git a/src/components/forms/validations.jsx b/src/components/forms/validations.jsx index c83ce63cb..113cd6fb4 100644 --- a/src/components/forms/validations.jsx +++ b/src/components/forms/validations.jsx @@ -1,46 +1,48 @@ -const defaults = require('lodash.defaultsdeep'); -const intl = require('../../lib/intl.jsx'); -const libphonenumber = require('google-libphonenumber'); -const omit = require('lodash.omit'); -const phoneNumberUtil = libphonenumber.PhoneNumberUtil.getInstance(); -const PropTypes = require('prop-types'); -const React = require('react'); +var defaults = require('lodash.defaultsdeep'); +var intl = require('../../lib/intl.jsx'); +var libphonenumber = require('google-libphonenumber'); +var phoneNumberUtil = libphonenumber.PhoneNumberUtil.getInstance(); +var React = require('react'); + +module.exports = {}; module.exports.validations = { - notEquals: (values, value, neq) => (value !== neq), - notEqualsField: (values, value, field) => (value !== values[field]), - isPhone: (values, value) => { + notEquals: function (values, value, neq) { + return value !== neq; + }, + notEqualsField: function (values, value, field) { + return value !== values[field]; + }, + isPhone: function (values, value) { if (typeof value === 'undefined') return true; if (value && value.national_number === '+') return true; try { - const parsed = phoneNumberUtil.parse(value.national_number, value.country_code.iso2); - return phoneNumberUtil.isValidNumber(parsed); + var parsed = phoneNumberUtil.parse(value.national_number, value.country_code.iso2); } catch (err) { return false; } + return phoneNumberUtil.isValidNumber(parsed); } }; - module.exports.validations.notEqualsUsername = module.exports.validations.notEquals; -module.exports.validationHOCFactory = defaultValidationErrors => (Component => { - const ValidatedComponent = props => ( - - ); - - ValidatedComponent.propTypes = { - validationErrors: PropTypes.object // eslint-disable-line react/forbid-prop-types +module.exports.validationHOCFactory = function (defaultValidationErrors) { + return function (Component) { + var ValidatedComponent = React.createClass({ + render: function () { + var validationErrors = defaults( + {}, + defaultValidationErrors, + this.props.validationErrors + ); + return ( + + ); + } + }); + return ValidatedComponent; }; - - return ValidatedComponent; -}); +}; module.exports.defaultValidationHOC = module.exports.validationHOCFactory({ isDefaultRequiredValue: diff --git a/src/components/grid/grid.jsx b/src/components/grid/grid.jsx index 0bc8c9286..f130e5bbd 100644 --- a/src/components/grid/grid.jsx +++ b/src/components/grid/grid.jsx @@ -1,68 +1,79 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); -const Thumbnail = require('../thumbnail/thumbnail.jsx'); -const FlexRow = require('../flex-row/flex-row.jsx'); +var Thumbnail = require('../thumbnail/thumbnail.jsx'); +var FlexRow = require('../flex-row/flex-row.jsx'); require('./grid.scss'); -const Grid = props => ( -
    - - {props.items.map((item, key) => { - const href = `/${props.itemType}/${item.id}/`; - if (props.itemType === 'projects') { - return ( - - ); - } - return ( - - ); - })} - -
    -); +var Grid = React.createClass({ + type: 'Grid', + getDefaultProps: function () { + return { + items: require('./grid.json'), + itemType: 'projects', + showLoves: false, + showFavorites: false, + showRemixes: false, + showViews: false, + showAvatar: false + }; + }, + render: function () { + var classes = classNames( + 'grid', + this.props.className + ); + return ( +
    + + {this.props.items.map(function (item, key) { + var href = '/' + this.props.itemType + '/' + item.id + '/'; -Grid.propTypes = { - className: PropTypes.string, - itemType: PropTypes.string, - items: PropTypes.arrayOf(PropTypes.object) -}; - -Grid.defaultProps = { - items: require('./grid.json'), - itemType: 'projects', - showLoves: false, - showFavorites: false, - showRemixes: false, - showViews: false, - showAvatar: false -}; + if (this.props.itemType == 'projects') { + return ( + + ); + } + else { + return ( + + ); + } + }.bind(this))} + +
    + ); + } +}); module.exports = Grid; diff --git a/src/components/informationpage/informationpage.jsx b/src/components/informationpage/informationpage.jsx index 94a8bd740..acc68da77 100644 --- a/src/components/informationpage/informationpage.jsx +++ b/src/components/informationpage/informationpage.jsx @@ -1,34 +1,39 @@ -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); - -const TitleBanner = require('../../components/title-banner/title-banner.jsx'); +var classNames = require('classnames'); +var React = require('react'); +var TitleBanner = require('../../components/title-banner/title-banner.jsx'); require('./informationpage.scss'); -/* +/** * Container for a table of contents * alongside a long body of text */ -const InformationPage = props => ( -
    - -
    -

    - {props.title} -

    +var InformationPage = React.createClass({ + type: 'InformationPage', + propTypes: { + title: React.PropTypes.string.isRequired + }, + render: function () { + var classes = classNames( + 'info-outer', + 'inner', + this.props.className + ); + return ( +
    + +
    +

    + {this.props.title} +

    +
    +
    +
    + {this.props.children} +
    - -
    - {props.children} -
    -
    -); - -InformationPage.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - title: PropTypes.string.isRequired -}; + ); + } +}); module.exports = InformationPage; diff --git a/src/components/intro/intro.jsx b/src/components/intro/intro.jsx index efe0473a7..d1f7c4275 100644 --- a/src/components/intro/intro.jsx +++ b/src/components/intro/intro.jsx @@ -1,128 +1,111 @@ -const bindAll = require('lodash.bindall'); -const connect = require('react-redux').connect; -const PropTypes = require('prop-types'); -const React = require('react'); +var connect = require('react-redux').connect; +var React = require('react'); -const sessionActions = require('../../redux/session.js'); +var sessionActions = require('../../redux/session.js'); -const IframeModal = require('../modal/iframe/modal.jsx'); -const Registration = require('../registration/registration.jsx'); +var IframeModal = require('../modal/iframe/modal.jsx'); +var Registration = require('../registration/registration.jsx'); require('./intro.scss'); -class Intro extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleShowVideo', - 'handleCloseVideo', - 'handleJoinClick', - 'handleCloseRegistration', - 'handleCompleteRegistration' - ]); - this.state = { +var Intro = React.createClass({ + type: 'Intro', + getDefaultProps: function () { + return { + messages: { + 'intro.aboutScratch': 'ABOUT SCRATCH', + 'intro.forEducators': 'FOR EDUCATORS', + 'intro.forParents': 'FOR PARENTS', + 'intro.itsFree': 'it\'s free!', + 'intro.joinScratch': 'JOIN SCRATCH', + 'intro.seeExamples': 'SEE EXAMPLES', + 'intro.tagLine': 'Create stories, games, and animations
    Share with others around the world', + 'intro.tryItOut': 'TRY IT OUT', + 'intro.description': 'A creative learning community with ' + + 'over 14 million projects shared' + }, + session: {} + }; + }, + getInitialState: function () { + return { videoOpen: false }; - } - handleShowVideo () { + }, + showVideo: function () { this.setState({videoOpen: true}); - } - handleCloseVideo () { + }, + closeVideo: function () { this.setState({videoOpen: false}); - } - handleJoinClick (e) { + }, + handleJoinClick: function (e) { e.preventDefault(); - this.setState({registrationOpen: true}); - } - handleCloseRegistration () { - this.setState({registrationOpen: false}); - } - handleCompleteRegistration () { + this.setState({'registrationOpen': true}); + }, + closeRegistration: function () { + this.setState({'registrationOpen': false}); + }, + completeRegistration: function () { this.props.dispatch(sessionActions.refreshSession()); this.closeRegistration(); - } - render () { + }, + render: function () { return (
    -

    +

    +

    - + Scratch Cat + alt="Scratch Cat" /> Scratch Cat -
    + alt="Scratch Cat" /> +
    {this.props.messages['intro.tryItOut']}
    - + Tera + alt="Tera" /> Tera -
    + alt="Tera" /> +
    {this.props.messages['intro.seeExamples']}
    - + Gobo + alt="Gobo" /> Gobo - -
    -
    - Intro Video +
    + Intro Video
    ); } -} - -Intro.propTypes = { - dispatch: PropTypes.func.isRequired, - messages: PropTypes.shape({ - 'intro.aboutScratch': PropTypes.string, - 'intro.forEducators': PropTypes.string, - 'intro.forParents': PropTypes.string, - 'intro.itsFree': PropTypes.string, - 'intro.joinScratch': PropTypes.string, - 'intro.seeExamples': PropTypes.string, - 'intro.tagLine': PropTypes.string, - 'intro.tryItOut': PropTypes.string, - 'intro.description': PropTypes.string - }) -}; - -Intro.defaultProps = { - messages: { - 'intro.aboutScratch': 'ABOUT SCRATCH', - 'intro.forEducators': 'FOR EDUCATORS', - 'intro.forParents': 'FOR PARENTS', - 'intro.itsFree': 'it\'s free!', - 'intro.joinScratch': 'JOIN SCRATCH', - 'intro.seeExamples': 'SEE EXAMPLES', - 'intro.tagLine': 'Create stories, games, and animations
    Share with others around the world', - 'intro.tryItOut': 'TRY IT OUT', - 'intro.description': 'A creative learning community with ' + - 'over 14 million projects shared' - }, - session: {} -}; - -const mapStateToProps = state => ({ - session: state.session }); -const ConnectedIntro = connect(mapStateToProps)(Intro); +var mapStateToProps = function (state) { + return { + session: state.session + }; +}; + +var ConnectedIntro = connect(mapStateToProps)(Intro); module.exports = ConnectedIntro; diff --git a/src/components/languagechooser/languagechooser.jsx b/src/components/languagechooser/languagechooser.jsx index 1e9258853..c538fb923 100644 --- a/src/components/languagechooser/languagechooser.jsx +++ b/src/components/languagechooser/languagechooser.jsx @@ -1,57 +1,46 @@ -const bindAll = require('lodash.bindall'); -const classNames = require('classnames'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var React = require('react'); -const jar = require('../../lib/jar.js'); -const languages = require('../../../languages.json'); -const Form = require('../forms/form.jsx'); -const Select = require('../forms/select.jsx'); +var jar = require('../../lib/jar.js'); +var languages = require('../../../languages.json'); +var Form = require('../forms/form.jsx'); +var Select = require('../forms/select.jsx'); require('./languagechooser.scss'); /** * Footer dropdown menu that allows one to change their language. */ -class LanguageChooser extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleSetLanguage' - ]); - } - handleSetLanguage (name, value) { +var LanguageChooser = React.createClass({ + type: 'LanguageChooser', + getDefaultProps: function () { + return { + languages: languages, + locale: 'en' + }; + }, + onSetLanguage: function (name, value) { jar.set('scratchlanguage', value); window.location.reload(); - } - render () { - const languageOptions = Object.keys(this.props.languages).map(value => ({ - value: value, - label: this.props.languages[value] - })); + }, + render: function () { + var classes = classNames( + 'language-chooser', + this.props.className + ); + var languageOptions = Object.keys(this.props.languages).map(function (value) { + return {value: value, label: this.props.languages[value]}; + }.bind(this)); return ( -
    -
    ); } -} - -LanguageChooser.propTypes = { - className: PropTypes.string, - languages: PropTypes.object, // eslint-disable-line react/forbid-prop-types - locale: PropTypes.string -}; - -LanguageChooser.defaultProps = { - languages: languages, - locale: 'en' -}; +}); module.exports = LanguageChooser; diff --git a/src/components/login/login.jsx b/src/components/login/login.jsx index 58586e5e5..c7243d7a6 100644 --- a/src/components/login/login.jsx +++ b/src/components/login/login.jsx @@ -1,108 +1,66 @@ -const bindAll = require('lodash.bindall'); -const FormattedMessage = require('react-intl').FormattedMessage; -const PropTypes = require('prop-types'); -const React = require('react'); +var React = require('react'); +var FormattedMessage = require('react-intl').FormattedMessage; -const log = require('../../lib/log.js'); +var log = require('../../lib/log.js'); -const Form = require('../forms/form.jsx'); -const Input = require('../forms/input.jsx'); -const Button = require('../forms/button.jsx'); -const Spinner = require('../spinner/spinner.jsx'); +var Form = require('../forms/form.jsx'); +var Input = require('../forms/input.jsx'); +var Button = require('../forms/button.jsx'); +var Spinner = require('../spinner/spinner.jsx'); require('./login.scss'); -class Login extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleSubmit' - ]); - this.state = { +var Login = React.createClass({ + type: 'Login', + propTypes: { + onLogIn: React.PropTypes.func, + error: React.PropTypes.string + }, + getInitialState: function () { + return { waiting: false }; - } - handleSubmit (formData) { + }, + handleSubmit: function (formData) { this.setState({waiting: true}); - this.props.onLogIn(formData, err => { + this.props.onLogIn(formData, function (err) { if (err) log.error(err); this.setState({waiting: false}); - }); - } - render () { - let error; + }.bind(this)); + }, + render: function () { + var error; if (this.props.error) { error =
    {this.props.error}
    ; } return (
    -
    ); } -} - -Login.propTypes = { - error: PropTypes.string, - onLogIn: PropTypes.func -}; +}); module.exports = Login; diff --git a/src/components/masonrygrid/masonrygrid.jsx b/src/components/masonrygrid/masonrygrid.jsx index 5f654488d..ef32172e5 100644 --- a/src/components/masonrygrid/masonrygrid.jsx +++ b/src/components/masonrygrid/masonrygrid.jsx @@ -1,68 +1,60 @@ -const bindAll = require('lodash.bindall'); -const classNames = require('classnames'); -const MediaQuery = require('react-responsive').default; -const PropTypes = require('prop-types'); -const React = require('react'); - -const frameless = require('../../lib/frameless'); +var classNames = require('classnames'); +var React = require('react'); +var MediaQuery = require('react-responsive'); +var frameless = require('../../lib/frameless'); require('./masonrygrid.scss'); -class MasonryGrid extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'reorderColumns' - ]); - } - reorderColumns (items, cols) { - const a1 = []; - const a2 = []; - const a3 = []; - let i = 0; - // only implemented for 2 and 3 columns so far - easy to extend if needed +var MasonryGrid = React.createClass({ + type: 'MasonryGrid', + getDefaultProps: function () { + return { + as: 'div' + }; + }, + reorderColumns: function (items, cols) { + var a1 = []; + var a2 = []; + var a3 = []; + var i = 0; + //only implemented for 2 and 3 columns so far - easy to extend if needed if (cols > 1 && cols < 4) { - for (i = 0; i < items.length; i++){ - const col = (i + cols) % cols; + for (i=0;i - + + {this.props.children} - + {this.reorderColumns(this.props.children, 2)} - + {this.reorderColumns(this.props.children, 3)} ); } -} - -MasonryGrid.propTypes = { - children: PropTypes.node, - className: PropTypes.string -}; - -MasonryGrid.defaultProps = { - as: 'div' -}; +}); module.exports = MasonryGrid; diff --git a/src/components/microworld/microworld.jsx b/src/components/microworld/microworld.jsx index 5923f7ac4..ec21d5a87 100644 --- a/src/components/microworld/microworld.jsx +++ b/src/components/microworld/microworld.jsx @@ -1,53 +1,39 @@ -const bindAll = require('lodash.bindall'); -const PropTypes = require('prop-types'); -const React = require('react'); - -const Box = require('../box/box.jsx'); -const LegacyCarousel = require('../carousel/legacy-carousel.jsx'); -const IframeModal = require('../modal/iframe/modal.jsx'); -const NestedCarousel = require('../nestedcarousel/nestedcarousel.jsx'); +var React = require('react'); require('./microworld.scss'); -class Microworld extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'markVideoOpen', - 'markVideoClosed', - 'renderVideos', - 'renderVideo', - 'renderEditorWindow', - 'renderTips', - 'renderStarterProject', - 'renderProjectIdeasBox', - 'renderForum', - 'renderDesignStudio' - ]); - this.state = { - videoOpen: {} - }; - } - markVideoOpen (key) { - /* - When a video is clicked, mark it as an open video, so the video Modal will open. - Key is the number of the video, so distinguish between different videos on the page - */ - const videoOpenArr = this.state.videoOpen; +var Box = require('../box/box.jsx'); +var LegacyCarousel = require('../carousel/legacy-carousel.jsx'); +var IframeModal = require('../modal/iframe/modal.jsx'); +var NestedCarousel = require('../nestedcarousel/nestedcarousel.jsx'); + +var Microworld = React.createClass({ + type: 'Microworld', + propTypes: { + microworldData: React.PropTypes.node.isRequired + }, + markVideoOpen: function (key) { + {/* When a video is clicked, mark it as an open video, so the video Modal will open. + Key is the number of the video, so distinguish between different videos on the page */} + + var videoOpenArr = this.state.videoOpen; videoOpenArr[key] = true; this.setState({videoOpen: videoOpenArr}); - } - markVideoClosed (key) { - /* - When a video's x is clicked, mark it as closed, so the video Modal will disappear. - Key is the number of the video, so distinguish between different videos on the page - */ - const videoOpenArr = this.state.videoOpen; + }, + markVideoClosed: function (key) { + {/* When a video's x is clicked, mark it as closed, so the video Modal will disappear. + Key is the number of the video, so distinguish between different videos on the page */} + var videoOpenArr = this.state.videoOpen; videoOpenArr[key] = false; this.setState({videoOpen: videoOpenArr}); - } - renderVideos () { - const videos = this.props.microworldData.videos; + }, + getInitialState: function () { + return { + videoOpen: {} + }; + }, + renderVideos: function () { + var videos = this.props.microworldData.videos; if (!videos || videos.length <= 0) { return null; } @@ -62,32 +48,26 @@ class Microworld extends React.Component {
    ); - } - renderVideo (video, key) { + }, + renderVideo: function (video, key) { return (
    -
    { // eslint-disable-line react/jsx-no-bind - this.markVideoOpen(key); - }} - /> +
    +
    { // eslint-disable-line react/jsx-no-bind - this.markVideoClosed(key); - }} />
    ); - } - renderEditorWindow () { - const projectId = this.props.microworldData.microworld_project_id; + }, + renderEditorWindow: function () { + var projectId = this.props.microworldData.microworld_project_id; if (!projectId) { return null; @@ -95,37 +75,30 @@ class Microworld extends React.Component { return (

    Start Creating!

    - {this.renderTips()}
    ); - } - renderTips () { - const tips = this.props.microworldData.tips; + }, + renderTips: function () { + var tips = this.props.microworldData.tips; if (!tips || tips.length <= 0) { return null; } return (
    -
    +
    +
    - +
    - ); - } - renderStarterProject () { - const starterProjects = this.props.microworldData.starter_projects; + ); + }, + renderStarterProject: function () { + var starterProjects = this.props.microworldData.starter_projects; if (!starterProjects || starterProjects.length <= 0){ return null; } @@ -134,42 +107,39 @@ class Microworld extends React.Component {

    Check out ideas for more projects

    + key="starter_projects">
    ); - } - renderProjectIdeasBox () { - const communityProjects = this.props.microworldData.community_projects; + }, + renderProjectIdeasBox: function () { + var communityProjects = this.props.microworldData.community_projects; if (!communityProjects || communityProjects.size <= 0) { return null; } - const featured = communityProjects.featured_projects; - const all = communityProjects.newest_projects; + var featured = communityProjects.featured_projects; + var all = communityProjects.newest_projects; - const rows = []; + var rows = []; if (featured && featured.length > 0){ rows.push( + key="community_featured_projects"> - + ); } if (all && all.length > 0) { rows.push( - - + title="All Community Projects" + key="community_all_projects"> + + ); } if (rows.length <= 0) { @@ -181,88 +151,67 @@ class Microworld extends React.Component { {rows}
    ); - } - renderForum () { + }, + renderForum: function () { if (!this.props.microworldData.show_forum) { return null; } return ( -
    -

    Chat with others!

    - -
    +
    +

    Chat with others!

    + +
    ); - } - renderDesignStudio () { - const designChallenge = this.props.microworldData.design_challenge; + }, + renderDesignStudio: function () { + var designChallenge = this.props.microworldData.design_challenge; if (!designChallenge) { return null; } - - let studioHref = ''; if (designChallenge.studio_id) { - studioHref = `https://scratch.mit.edu//studios/${designChallenge.studio_id}/`; + var studioHref = 'https://scratch.mit.edu//studios/' + designChallenge.studio_id + '/'; } if (designChallenge.project_id) { return (

    Join our Design Challenge!

    -
    - + {/* The two carousels are used to show two rows of projects, one above the other. This should be probably be changed, to allow better scrolling. */} - - + +
    ); + } else { + return ( +
    +

    Join our Design Challenge!

    + + + +
    + ); } - return ( -
    -

    Join our Design Challenge!

    - - - ` -
    - ); - } - render () { + }, + render: function () { return (
    @@ -282,10 +231,6 @@ class Microworld extends React.Component { ); } -} - -Microworld.propTypes = { - microworldData: PropTypes.node.isRequired -}; +}); module.exports = Microworld; diff --git a/src/components/modal/base/modal.jsx b/src/components/modal/base/modal.jsx index 613233a15..0c0647144 100644 --- a/src/components/modal/base/modal.jsx +++ b/src/components/modal/base/modal.jsx @@ -1,9 +1,7 @@ -const bindAll = require('lodash.bindall'); -const classNames = require('classnames'); -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); -const ReactModal = require('react-modal'); +var classNames = require('classnames'); +var omit = require('lodash.omit'); +var React = require('react'); +var ReactModal = require('react-modal'); require('./modal.scss'); @@ -12,55 +10,47 @@ ReactModal.setAppElement(document.getElementById('view')); /** * Container for pop up windows (See: registration window) */ -class Modal extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleRequestClose' - ]); - } - handleRequestClose () { +var Modal = React.createClass({ + type: 'Modal', + propTypes: { + className: React.PropTypes.string, + overlayClassName: React.PropTypes.string + }, + requestClose: function () { return this.modal.portal.requestClose(); - } - render () { + }, + render: function () { + var modalClasses = classNames( + 'modal-content', + this.props.className + ); + var overlayClasses = classNames( + 'modal-overlay', + this.props.overlayClassName + ); + return ( { - this.modal = component; - }} + ref={ + function (component) { + this.modal = component; + }.bind(this) + } + className={modalClasses} + overlayClassName={overlayClasses} {...omit(this.props, ['className', 'overlayClassName'])} > -
    +
    close-icon
    {this.props.children} ); } -} - -Modal.propTypes = { - children: PropTypes.node, - className: PropTypes.string, - overlayClassName: PropTypes.string -}; +}); module.exports = Modal; diff --git a/src/components/modal/base/modal.scss b/src/components/modal/base/modal.scss index 9fec2deef..3d01d683f 100644 --- a/src/components/modal/base/modal.scss +++ b/src/components/modal/base/modal.scss @@ -21,7 +21,7 @@ background-color: transparentize($ui-blue, .3); } -.modal-content:focus { +.ReactModal__Content:focus { outline: none; } diff --git a/src/components/modal/iframe/modal.jsx b/src/components/modal/iframe/modal.jsx index 620e761f8..6bff74ee5 100644 --- a/src/components/modal/iframe/modal.jsx +++ b/src/components/modal/iframe/modal.jsx @@ -1,28 +1,34 @@ -const classNames = require('classnames'); -const omit = require('lodash.omit'); -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var omit = require('lodash.omit'); +var React = require('react'); -const Modal = require('../base/modal.jsx'); +var Modal = require('../base/modal.jsx'); require('./modal.scss'); -const IframeModal = props => ( - - +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +
    + +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +

    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + ); + } +})); -const TeacherFaq = props => ( - -
    -
    - -

    -
    -
    -
    - +
    +
    - -
    - - + + -
    -
    - -

    - -

    -

    - -

    - -

    -

    -

    -
    -
    -
    - -

    - -
    -

    - -

    -

    - -

    -
    -
    -

    - -

    -

    - -

    -
    -
    -

    - -

    - -
    - - cards icon - -

    - -

    -
    -
    - - tips window icon - -

    - -

    -
    -
    - - creative computing icon - -

    - -

    -
    -
    -
    -
    -
    -
    -
    -

    - -

    -

    - -

    - - -
  • -
    -
    +
    +
    + +

    +

    + +

    +

    +

    +
    +
    +
    + +

    + +
    +

    +

    + +

    +
    +
    +

    +

    + +

    +
    +
    +

    + +
    + + cards icon + +

    + +

    +
    +
    + + tips window icon + +

    + +

    +
    +
    + + creative computing icon + +

    + +

    +
    +
    +
    +
    +
    +
    +
    +

    +

    + +

    + + +
  • +
    +
    +
    + teacher account +
    - teacher account
    -
    -
    -); + ); + } +})); render(, document.getElementById('app')); diff --git a/src/views/teacherwaitingroom/teacherwaitingroom.jsx b/src/views/teacherwaitingroom/teacherwaitingroom.jsx index 0c50dea8e..94c0660b3 100644 --- a/src/views/teacherwaitingroom/teacherwaitingroom.jsx +++ b/src/views/teacherwaitingroom/teacherwaitingroom.jsx @@ -1,38 +1,32 @@ -const classNames = require('classnames'); -const connect = require('react-redux').connect; -const PropTypes = require('prop-types'); -const React = require('react'); +var classNames = require('classnames'); +var connect = require('react-redux').connect; +var React = require('react'); +var render = require('../../lib/render.jsx'); -const Deck = require('../../components/deck/deck.jsx'); -const TeacherApprovalStep = require('../../components/registration/steps.jsx').TeacherApprovalStep; - -const render = require('../../lib/render.jsx'); +var Deck = require ('../../components/deck/deck.jsx'); +var TeacherApprovalStep = require('../../components/registration/steps.jsx').TeacherApprovalStep; require('./teacherwaitingroom.scss'); -class TeacherWaitingRoom extends React.Component { - componentWillReceiveProps (nextProps) { +var TeacherWaitingRoom = React.createClass({ + displayName: 'TeacherWaitingRoom', + componentWillReceiveProps: function (nextProps) { if (nextProps.approved) { window.location.href = '/educators/classes/'; } - } - render () { + }, + render: function () { return ( - + ); } -} +}); -TeacherWaitingRoom.propTypes = { - approved: PropTypes.bool, - className: PropTypes.string -}; - -const mapStateToProps = state => { - const permissions = state.session.session.permissions || {}; - const user = state.session.session.user || {}; +var mapStateToProps = function (state) { + var permissions = state.session.session.permissions || {}; + var user = state.session.session.user || {}; return { approved: permissions && permissions.educator && !permissions.educator_invitee && permissions.social, confirmed: permissions && permissions.social, @@ -42,6 +36,6 @@ const mapStateToProps = state => { }; }; -const ConnectedTeacherWaitingRoom = connect(mapStateToProps)(TeacherWaitingRoom); +var ConnectedTeacherWaitingRoom = connect(mapStateToProps)(TeacherWaitingRoom); render(, document.getElementById('app')); diff --git a/src/views/terms/terms.jsx b/src/views/terms/terms.jsx index 63e223e1d..9bc31ccfa 100644 --- a/src/views/terms/terms.jsx +++ b/src/views/terms/terms.jsx @@ -1,571 +1,575 @@ -const React = require('react'); +var React = require('react'); +var render = require('../../lib/render.jsx'); -const Page = require('../../components/page/www/page.jsx'); -const render = require('../../lib/render.jsx'); +var Page = require('../../components/page/www/page.jsx'); +var InformationPage = require('../../components/informationpage/informationpage.jsx'); -const InformationPage = require('../../components/informationpage/informationpage.jsx'); - -const Terms = () => ( - -
    -
    - -

    1. User Agreement

    -

    - 1.1 These Terms of Use constitute an agreement between - you and the Scratch Team that governs your use of{' '} - scratch.mit.edu{' '} - and all associated services, including but not limited - to the Scratch Day{' '} - and ScratchX websites - (collectively "Scratch"). The Scratch Team is part of the - Lifelong Kindergarten Group in the Media Laboratory at the - Massachusetts Institute of Technology ("MIT"). Please - read the Terms of Use carefully. By using Scratch you - affirm that you have read, understood, and accepted - the terms and conditions in the Terms of Use. If you - do not agree with any of these conditions, please do not - use Scratch. -

    -

    - 1.2 Your privacy is important to us. Please read our{' '} - Privacy Policy, which identifies - how the Scratch Team uses, collects, and stores information - it collects through the Services. By using Scratch, you - additionally agree that you are comfortable with Scratch's - Privacy Policy. -

    -

    - 1.3 Scratch is open to children and adults of all ages, and - we ask that you keep this in mind when using the Scratch - services. When you use Scratch, you agree to abide by the{' '} - Scratch Community Guidelines. -

    -

    - 1.4 The Scratch Team may change the Terms of Use from time to - time. You can always find the latest version of the Terms of Use - at http://scratch.mit.edu/terms_of_use. - The date of the most recent revisions will appear on this page. - Your continued use of the Services constitutes your acceptance - of any changes to or revisions of the Terms of Use. -

    -
    -
    - -

    2. Account Creation and Maintenance

    -

    - 2.1 In order to use some features of the Services, you will need to - register with Scratch and create an account. Creating an account is - optional, but without an account you will not be able to save or - publish projects or comments on Scratch. When registering for a - personal account, you will be asked to provide certain personal - information, such as your email address, gender, birth month and - year, and country. Please see Scratch's{' '} - Privacy Policy for Scratch's data - retention and usage policies. -

    -

    - 2.2 You are responsible for keeping your password secret and your - account secure. You are solely responsible for any use of your - account, even if your account is used by another person. If any use - of your account violates the Terms of Service, your account may be - suspended or deleted. -

    -

    - 2.3 You may not use another person's Scratch account without permission. -

    -

    - 2.4 Account names cannot be changed. If you want a different account name, - create a new account and copy your existing projects over by hand. -

    -

    - 2.5 If you have reason to believe that your account is no longer secure - (for example, in the event of a loss, theft, or unauthorized disclosure - of your password), promptly change your password. If you cannot access - your account to change your password, notify us at{' '} - help@scratch.mit.edu. -

    -
    -
    - -

    3. Rules of Usage

    -

    - 3.1 The Scratch Team supports freedom of expression. However, Scratch is - intended for a wide audience, and some content is inappropriate for the - Scratch community. You may not use the Scratch service in any way, that: +var Terms = React.createClass({ + type: 'Terms', + render: function () { + return ( + +

    +
    + +

    1. User Agreement

    +

    + 1.1 These Terms of Use constitute an agreement between + you and the Scratch Team that governs your use of{' '} + scratch.mit.edu{' '} + and all associated services, including but not limited + to the Scratch Day{' '} + and ScratchX websites + (collectively "Scratch"). The Scratch Team is part of the + Lifelong Kindergarten Group in the Media Laboratory at the + Massachusetts Institute of Technology ("MIT"). Please + read the Terms of Use carefully. By using Scratch you + affirm that you have read, understood, and accepted + the terms and conditions in the Terms of Use. If you + do not agree with any of these conditions, please do not + use Scratch. +

    +

    + 1.2 Your privacy is important to us. Please read our{' '} + Privacy Policy, which identifies + how the Scratch Team uses, collects, and stores information + it collects through the Services. By using Scratch, you + additionally agree that you are comfortable with Scratch's + Privacy Policy. +

    +

    + 1.3 Scratch is open to children and adults of all ages, and + we ask that you keep this in mind when using the Scratch + services. When you use Scratch, you agree to abide by the{' '} + Scratch Community Guidelines. +

    +

    + 1.4 The Scratch Team may change the Terms of Use from time to + time. You can always find the latest version of the Terms of Use + at http://scratch.mit.edu/terms_of_use. + The date of the most recent revisions will appear on this page. + Your continued use of the Services constitutes your acceptance + of any changes to or revisions of the Terms of Use. +

    +
    +
    + +

    2. Account Creation and Maintenance

    +

    + 2.1 In order to use some features of the Services, you will need to + register with Scratch and create an account. Creating an account is + optional, but without an account you will not be able to save or + publish projects or comments on Scratch. When registering for a + personal account, you will be asked to provide certain personal + information, such as your email address, gender, birth month and + year, and country. Please see Scratch's{' '} + Privacy Policy for Scratch's data + retention and usage policies. +

    +

    + 2.2 You are responsible for keeping your password secret and your + account secure. You are solely responsible for any use of your + account, even if your account is used by another person. If any use + of your account violates the Terms of Service, your account may be + suspended or deleted. +

    +

    + 2.3 You may not use another person's Scratch account without permission. +

    +

    + 2.4 Account names cannot be changed. If you want a different account name, + create a new account and copy your existing projects over by hand. +

    +

    + 2.5 If you have reason to believe that your account is no longer secure + (for example, in the event of a loss, theft, or unauthorized disclosure + of your password), promptly change your password. If you cannot access + your account to change your password, notify us at{' '} + help@scratch.mit.edu. +

    +
    +
    + +

    3. Rules of Usage

    +

    + 3.1 The Scratch Team supports freedom of expression. However, Scratch is + intended for a wide audience, and some content is inappropriate for the + Scratch community. You may not use the Scratch service in any way, that: +

      +
    1. + Promotes bigotry, discrimination, hatred, or violence against any + individual or group; +
    2. +
    3. + Threatens, harasses, or intimidates any other person, whether that + person is a Scratch user or not; +
    4. +
    5. Contains foul language or personal attacks;
    6. +
    7. Contains sexually explicit or graphically violent material;
    8. +
    9. + Provides instructions on how to commit illegal activities or obtain + illegal products; +
    10. +
    11. + Except in connection with organizing Scratch day events, asks any + other user for personally identifying information, contact + information, or passwords; or +
    12. +
    13. + Exposes any others person's personally identifying information, + contact information, or passwords without that person's permission. +
    14. +
    +

    +

    + 3.3 You agree to comply with all applicable laws and regulations when you use + Scratch. You may not use Scratch in any unlawful way, including to harass, + stalk, or defame any other person. +

    +

    + 3.4 You may not impersonate, imitate or pretend to be somebody else when using + the Services. +

    +

    + 3.5 You agree not to use Scratch in any way intended to disrupt the service, + gain unauthorized access to the service, or interfere with any other user's + ability to use the service. Prohibited activities include, but are not limited + to: +

      +
    1. + Posting content deliberately designed to crash the Scratch + website or editor; +
    2. +
    3. + Linking to pages containing viruses or malware; +
    4. +
    5. + Using administrator passwords or pretending to be an administrator; +
    6. +
    7. + Repeatedly posting the same material, or "spamming"; +
    8. +
    9. + Using alternate accounts or organizing voting groups to manipulate + site statistics, such as purposely trying to get on the "What the + Community is Loving/Remixing" rows of the front page. +
    10. +
    +

    +

    + 3.6 Commercial use of Scratch, user-generated content, and support + materials is permitted under the{' '} + + Creative Commons Attribution-ShareAlike 2.0 license. However, + the Scratch Team reserves the right to block any commercial use + of Scratch that, in the Scratch Team's sole discretion, is harmful + to the community. Harmful commercial use includes spamming or + repeated advertisement through projects, comments, or forum posts. +

    +

    + 3.7 You agree not to post links to any content outside of the + Scratch website, if to do so would violate any part of the Terms of Use. +

    +
    +
    + +

    4. User-Generated Content and Licensing

    +

    + 4.1 For the purposes of the Terms of Use, "user-generated content" + includes any projects, comments, forum posts, or links to third + party websites that a user submits to Scratch. +

    +

    + 4.2 The Scratch Team encourages everyone to foster creativity by + freely sharing code, art, music, and other works. However, we + also understand the need for individuals and companies to protect + their intellectual property rights. You are responsible for making + sure you have the necessary rights, licenses, or permission for + any user-generated content you submit to Scratch. +

    +

    + 4.3 All user-generated content you submit to Scratch is licensed + to and through Scratch under the{' '} + + Creative Commons Attribution-ShareAlike 2.0 license. This + allows others to view and remix your content. This license also + allows the Scratch Team to display, distribute, and reproduce + your content on the Scratch website, through social media + channels, and elsewhere. If you do not want to license your + content under this license, then do not share it on Scratch. +

    +

    + 4.4 You may only submit user-generated projects that were created + with (1) the Scratch website editor or (2) an unmodified copy of + the Scratch editor compiled from the source code described in + Section 5.3. You may not upload any projects that were created, by + you or by anyone else, with a modified version of the Scratch editor. +

    +

    + 4.5 Although the Scratch Team requires all users to comply with + these Terms of Use, some inappropriate user-generated content + may be submitted and displayed on the Scratch website. You + understand that when you use Scratch you may be exposed to + user-generated content that you find objectionable or offensive. + If you see any content that violates the Community Guidelines + or Terms of Use, please let us know by using the "Report this" + button. You only need to report an item once. The Scratch Team + reviews reported content every day. +

    +

    + 4.6 In addition to reviewing reported user-generated content, the + Scratch Team reserves the right, but is not obligated, to monitor + all uses of the Scratch service. The Scratch Team may edit, move, + or delete any content that violates the Terms of Use or Community + Guidelines, without notice. +

    +

    + 4.7 All user-generated content is provided as-is. The Scratch Team + makes no warranties about the accuracy or reliability of any + user-generated content available through Scratch and does not + endorse Scratch Day events or vet or verify information posted in + connection with said events. The Scratch Team does not endorse any + views, opinions, or advice expressed in user-generated content. You + agree to relieve the Scratch Team of any and all liability arising + from your user-generated content and from Scratch Day events you + may organize or host. +

    +
    +
    + +

    5. Scratch Content and Licensing

    +

    + 5.1 Except for any user-generated content, the Scratch Team owns and + retains all rights in and to the Scratch code, the design, + functionality, and architecture of Scratch, and any software or + content provided through Scratch (collectively "the Scratch IP"). + If you want to use Scratch in a way that is not allowed by these + Terms of Use, you must first contact the Scratch Team. Except for + any rights explicitly granted under these Terms of Use, you are not + granted any rights in and to any Scratch IP. +

    +

    + 5.2 Scratch provides support materials, including images, sounds, + video, and sample code, to help users build projects. Support materials + are licensed under the{' '} + + Creative Commons Attribution-ShareAlike 2.0 license. You may also + use screenshots of Scratch under the same license. Please note that + this does not apply to materials that are also trademarked by the + Scratch Team or other parties as described in parts 5.4 and 5.5, below. +
    + The Creative Commons Attribution-ShareAlike 2.0 license requires you to + attribute any material you use to the original author. When you use + Scratch support materials, or screenshots of the Scratch website, + please use the following attribution: "Scratch is developed by the + Lifelong Kindergarten Group at the MIT Media Lab. See + http://scratch.mit.edu." +

    +

    + 5.3 The source code for Scratch 1.4 is available for download and subject + to the copyright notice as indicated on the Scratch FAQ + {' '}page. +

    +

    + 5.4 The Scratch name, Scratch logo, Scratch Day logo, Scratch Cat, and Gobo + are Trademarks owned by the Scratch Team. The MIT name and logo are Trademarks + owned by the Massachusetts Institute of Technology. Unless you are licensed by + Scratch under a specific licensing program or agreement, you may not use + these logos to label, promote, or endorse any product or service. You may use + the Scratch Logo to refer to the Scratch website and programming language. +

    +

    + 5.5 The Scratch support materials library may contain images and sounds that + are trademarked by third parties. The fact that materials are included in + the Scratch support materials library does not in any way limit or reduce + intellectual property rights, including trademark rights, otherwise + available to the materials' owners. Nothing in these Terms of Use or the + Creative Commons 2.0 license will be construed to limit or reduce any + party's rights in that party's valid trademarks. You may not use these + materials to label, promote, or endorse any product or service. You are + solely responsible for any violation of a third party's intellectual + property rights caused by your misuse of these materials. +

    +
    +
    + +

    6. Digital Millennium Copyright Act (DMCA)

    +

    + 6.1 If you are a copyright holder and believe that content on Scratch + violates your rights, you may send a DMCA notification to{' '} + copyright@scratch.mit.edu. + For more information, including the information that must be included + in a DMCA notification, see our full DMCA Policy and + the text of the DMCA,{' '} + 17 U.S.C. § 512. +

    +

    + 6.2 If you are a Scratch user and you believe that your content did not + constitute a copyright violation and was taken down in error, you may + send a notification to{' '} + copyright@scratch.mit.edu. + Please include: +

      +
    • Your Scratch username and email address;
    • +
    • The specific content you believe was taken down in error; and
    • +
    • + A brief statement of why you believe there was no copyright violation + (e.g., the content was not copyrighted, you had permission to use the + content, or your use of the content was a "fair use"). +
    • +
    +

    +
    +
    + +

    7. Suspension and Termination of Accounts

    +

    + 7.1 Scratch has the right to suspend your account for violations of the + Terms of Use or Community Guidelines. Repeat violators may have their + account deleted. The Scratch Team reserves the sole right to determine + what constitutes a violation of the Terms of Use or Community Guidelines. + The Scratch Team also reserves the right to terminate any account used + to circumvent prior enforcement of the Terms of Use. +

    +

    + 7.2 If you want to delete or temporarily disable your account, please + email help@scratch.mit.edu. +

    +
    +
    + +

    8. Third Party Websites

    +

    + 8.1 Content on Scratch, including user-generated content, may include + links to third party websites. The Scratch Team is not capable of + reviewing or managing third party websites, and assumes no + responsibility for the privacy practices, content, or functionality + of third party websites. You agree to relieve the Scratch Team of + any and all liability arising from third party websites. +

    +
    +
    + +

    9. Indemnification

    +

    + You agree to indemnify MIT, the Scratch Team, the Scratch Foundation, + and all their affiliates, employees, faculty members, fellows, + students, agents, representatives, third party service providers, + and members of their governing boards (all of which are "Scratch + Entities"), and to defend and hold each of them harmless, from any + and all claims and liabilities (including attorneys{'\''} fees) arising + out of or related to your breach of the Terms of Service or your + use of Scratch. +

    +

    + For federal government agencies, provisions in the Terms of Use + relating to Indemnification shall not apply to your Official Use, + except to the extent expressly authorized by federal law. For + state and local government agencies in the United States, Terms + of Use relating to Indemnification shall apply to your Official + Use only to the extent authorized by the laws of your jurisdiction. +

    +
    +
    + +

    10. Disclaimer of Warranty

    +

    + You acknowledge that you are using Scratch at your own risk. Scratch + is provided "as is," and the Scratch Entities hereby expressly + disclaim any and all warranties, express and implied, including but + not limited to any warranties of accuracy, reliability, title, + merchantability, non-infringement, fitness for a particular purpose + or any other warranty, condition, guarantee or representation, + whether oral, in writing or in electronic form, including but not + limited to the accuracy or completeness of any information contained + therein or provided by Scratch. Without limiting the foregoing, the + Scratch Entities disclaim any and all warranties, express and implied, + regarding user-generated content and Scratch Day events. The Scratch + Entities and their third party service providers do not represent or + warrant that access to Scratch will be uninterrupted or that there + will be no failures, errors or omissions or loss of transmitted + information, or that no viruses will be transmitted through Scratch + services. +

    +
    +
    + +

    11. Limitation of Liability

    +

    + The Scratch Entities shall not be liable to you or any third parties + for any direct, indirect, special, consequential or punitive damages + of any kind, regardless of the type of claim or the nature of the + cause of action, even if the Scratch Team has been advised of the + possibility of such damages. Without limiting the foregoing, the + Scratch Entites shall have no liability to you or any third parties + for damages or harms arising out of user-generated content or + Scratch Day events. +

    +
    +
    + +

    12. Jurisdiction

    +

    + Scratch is offered by the Scratch Team from its facilities in the United + States. The Scratch Team makes no representations that Scratch is + appropriate or available for use in other locations. Those who access + or use Scratch are responsible for compliance with local law. +

    +
    +
    + +

    13. Choice of Law and Venue

    +

    + You agree that these Terms of Use, for all purposes, shall be governed + and construed in accordance with the laws of the Commonwealth of + Massachusetts applicable to contracts to be wholly performed therein, + and any action based on, relating to, or alleging a breach of the + Terms of Use must be brought in a state or federal court in Suffolk + County, Massachusetts. In addition, both parties agree to submit to + the exclusive personal jurisdiction and venue of such courts. +

    +

    + If you are a federal, state, or local government entity in the United + States using Scratch in your official capacity and legally unable to + accept the controlling law, jurisdiction or venue clauses above, then + those clauses do not apply to you. For such U.S. federal government + entities, these Terms and any action related thereto will be governed + by the laws of the United States of America (without reference to + conflict of laws) and, in the absence of federal law and to the extent + permitted under federal law, the laws of the Commonwealth of + Massachusetts (excluding choice of law). +

    +
    +
    + +

    14. Choice of Language

    +

    + If the Scratch Team provides you with a translation of the English language + version of these Terms of Use, the Privacy Policy, or any other policy, + then you agree that the translation is provided for informational purposes + only and does not modify the English language version. In the event of a + conflict between a translation and the English version, the English version + will govern. +

    +
    +
    + +

    15. No Waiver

    +

    + No waiver of any term of these Terms of Use shall be deemed a further or + continuing waiver of such term or any other term, and the Scratch Team's + failure to assert any right or provision under these Terms of Use shall + not constitute a waiver of such right or provision. +

    +
    +
    + +

    16. Entire Agreement

    +

    + This document, together with all appendices, constitutes the entire Terms + of Use and supersedes all previous agreements with the Scratch Team relating + to the use of Scratch. Revision date: 4 March 2015. +

    +
    +
    + +

    Appendix A: Additional Terms for Scratch Day Website

    +

    + The following additional terms also govern your access to and use of web + pages hosted within day.scratch.mit.edu/ (collectively, the “Scratch Day + Site”). All of the terms set forth in the general Terms of Use above also + apply to the Scratch Day Site, unless we clearly state otherwise. +

    +

    1. Privacy Policy

    +

    + The Scratch Day Site Privacy Policy, not the Scratch Privacy Policy, + describes how the Scratch Team uses, collects, and stores information + it collects through the Scratch Day Site. By using the Scratch Day + Site, you agree that you are comfortable with the Privacy Policy. +

    +

    2. Account Creation and Maintenance

    +

    + 2.1 In order to post an event to the Scratch Day Site, you will need + to register and create an account. This account is a separate account + from your Scratch account. All registrants must be over 18 years of + age. When registering for a personal account, you will be asked to + provide certain personal information, such as your email address, + first and last name, and Scratch username (optional). Please see the + Scratch Day Site Privacy Policy for Scratch’s data retention and usage + policies. +

    +

    + 2.2 You are responsible for keeping your password secret and your account + secure. You are solely responsible for any use of your account, even if + your account is used by another person. If any use of your account + violates the Terms of Use, your account may be suspended or deleted. +

    +

    + 2.3 If you have reason to believe that your account is no longer secure + (for example, in the event of a loss, theft, or unauthorized disclosure + of your password), promptly change your password. If you cannot access + your account to change your password, notify us at{' '} + scratchday@media.mit.edu +

    +

    + 2.4 The terms set forth in this section apply to the Scratch Day Site. + The Account Creation and Maintenance terms in the general Terms of Use + do not apply to the Scratch Day Site. +

    +

    3. No Endorsement

    +

    + You understand that neither MIT, nor the Scratch Team, nor the Code to + Learn Foundation endorses any Scratch Day event. If you are hosting a + Scratch Day event, you may not state or imply that MIT, the Scratch + Team, or the Code to Learn Foundation has endorsed your event. +

    +
    +
    + +

    Appendix B: Additional Terms for ScratchX Website

    +

    + The following additional terms also govern your access to and use of web + pages hosted within scratchx.org (collectively, the “ScratchX Site”). + All of the terms set forth in the general Terms of Use above also apply + to the ScratchX Site, unless we clearly state otherwise. +

    +

    1. ScratchX and GitHub

    +

    + The ScratchX Site provides a platform for developers to link their + experimental extensions to Scratch. However, we do not host those + extensions or save them on the ScratchX site. All the extensions loaded + on to ScratchX are hosted publicly on independent developers’ accounts + on GitHub. Your use of GitHub is subject to GitHub’s Terms of Service + and Privacy. +

    +

    2. Privacy Policy

    +

    + The ScratchX Site Privacy Policy, not the Scratch Privacy Policy, + describes how the Scratch Team uses, collects, and stores information + it collects through the ScratchX Site. By using the ScratchX Site, you + agree to the terms of the Privacy Policy. +

    +

    3. No Endorsement

    +

    + By using ScratchX, you understand that neither MIT, nor the Scratch Team, + nor the Code to Learn Foundation endorses any ScratchX experimental + extension. If you are a developer linking to your own experimental + extension via the ScratchX site, you may not state or imply that MIT, + the Scratch Team, or the Code to Learn Foundation has endorsed your + extension. +

    +
    +

    The Scratch Terms of Use was last updated: April 2016

    +
    +
    -
    - -

    4. User-Generated Content and Licensing

    -

    - 4.1 For the purposes of the Terms of Use, "user-generated content" - includes any projects, comments, forum posts, or links to third - party websites that a user submits to Scratch. -

    -

    - 4.2 The Scratch Team encourages everyone to foster creativity by - freely sharing code, art, music, and other works. However, we - also understand the need for individuals and companies to protect - their intellectual property rights. You are responsible for making - sure you have the necessary rights, licenses, or permission for - any user-generated content you submit to Scratch. -

    -

    - 4.3 All user-generated content you submit to Scratch is licensed - to and through Scratch under the{' '} - - Creative Commons Attribution-ShareAlike 2.0 license. This - allows others to view and remix your content. This license also - allows the Scratch Team to display, distribute, and reproduce - your content on the Scratch website, through social media - channels, and elsewhere. If you do not want to license your - content under this license, then do not share it on Scratch. -

    -

    - 4.4 You may only submit user-generated projects that were created - with (1) the Scratch website editor or (2) an unmodified copy of - the Scratch editor compiled from the source code described in - Section 5.3. You may not upload any projects that were created, by - you or by anyone else, with a modified version of the Scratch editor. -

    -

    - 4.5 Although the Scratch Team requires all users to comply with - these Terms of Use, some inappropriate user-generated content - may be submitted and displayed on the Scratch website. You - understand that when you use Scratch you may be exposed to - user-generated content that you find objectionable or offensive. - If you see any content that violates the Community Guidelines - or Terms of Use, please let us know by using the "Report this" - button. You only need to report an item once. The Scratch Team - reviews reported content every day. -

    -

    - 4.6 In addition to reviewing reported user-generated content, the - Scratch Team reserves the right, but is not obligated, to monitor - all uses of the Scratch service. The Scratch Team may edit, move, - or delete any content that violates the Terms of Use or Community - Guidelines, without notice. -

    -

    - 4.7 All user-generated content is provided as-is. The Scratch Team - makes no warranties about the accuracy or reliability of any - user-generated content available through Scratch and does not - endorse Scratch Day events or vet or verify information posted in - connection with said events. The Scratch Team does not endorse any - views, opinions, or advice expressed in user-generated content. You - agree to relieve the Scratch Team of any and all liability arising - from your user-generated content and from Scratch Day events you - may organize or host. -

    -
    -
    - -

    5. Scratch Content and Licensing

    -

    - 5.1 Except for any user-generated content, the Scratch Team owns and - retains all rights in and to the Scratch code, the design, - functionality, and architecture of Scratch, and any software or - content provided through Scratch (collectively "the Scratch IP"). - If you want to use Scratch in a way that is not allowed by these - Terms of Use, you must first contact the Scratch Team. Except for - any rights explicitly granted under these Terms of Use, you are not - granted any rights in and to any Scratch IP. -

    -

    - 5.2 Scratch provides support materials, including images, sounds, - video, and sample code, to help users build projects. Support materials - are licensed under the{' '} - - Creative Commons Attribution-ShareAlike 2.0 license. You may also - use screenshots of Scratch under the same license. Please note that - this does not apply to materials that are also trademarked by the - Scratch Team or other parties as described in parts 5.4 and 5.5, below. -
    - The Creative Commons Attribution-ShareAlike 2.0 license requires you to - attribute any material you use to the original author. When you use - Scratch support materials, or screenshots of the Scratch website, - please use the following attribution: "Scratch is developed by the - Lifelong Kindergarten Group at the MIT Media Lab. See - http://scratch.mit.edu." -

    -

    - 5.3 The source code for Scratch 1.4 is available for download and subject - to the copyright notice as indicated on the Scratch FAQ - {' '}page. -

    -

    - 5.4 The Scratch name, Scratch logo, Scratch Day logo, Scratch Cat, and Gobo - are Trademarks owned by the Scratch Team. The MIT name and logo are Trademarks - owned by the Massachusetts Institute of Technology. Unless you are licensed by - Scratch under a specific licensing program or agreement, you may not use - these logos to label, promote, or endorse any product or service. You may use - the Scratch Logo to refer to the Scratch website and programming language. -

    -

    - 5.5 The Scratch support materials library may contain images and sounds that - are trademarked by third parties. The fact that materials are included in - the Scratch support materials library does not in any way limit or reduce - intellectual property rights, including trademark rights, otherwise - available to the materials' owners. Nothing in these Terms of Use or the - Creative Commons 2.0 license will be construed to limit or reduce any - party's rights in that party's valid trademarks. You may not use these - materials to label, promote, or endorse any product or service. You are - solely responsible for any violation of a third party's intellectual - property rights caused by your misuse of these materials. -

    -
    -
    - -

    6. Digital Millennium Copyright Act (DMCA)

    -

    - 6.1 If you are a copyright holder and believe that content on Scratch - violates your rights, you may send a DMCA notification to{' '} - copyright@scratch.mit.edu. - For more information, including the information that must be included - in a DMCA notification, see our full DMCA Policy and - the text of the DMCA,{' '} - 17 U.S.C. § 512. -

    -

    - 6.2 If you are a Scratch user and you believe that your content did not - constitute a copyright violation and was taken down in error, you may - send a notification to{' '} - copyright@scratch.mit.edu. - Please include: -

      -
    • Your Scratch username and email address;
    • -
    • The specific content you believe was taken down in error; and
    • -
    • - A brief statement of why you believe there was no copyright violation - (e.g., the content was not copyrighted, you had permission to use the - content, or your use of the content was a "fair use"). -
    • -
    -

    -
    -
    - -

    7. Suspension and Termination of Accounts

    -

    - 7.1 Scratch has the right to suspend your account for violations of the - Terms of Use or Community Guidelines. Repeat violators may have their - account deleted. The Scratch Team reserves the sole right to determine - what constitutes a violation of the Terms of Use or Community Guidelines. - The Scratch Team also reserves the right to terminate any account used - to circumvent prior enforcement of the Terms of Use. -

    -

    - 7.2 If you want to delete or temporarily disable your account, please - email help@scratch.mit.edu. -

    -
    -
    - -

    8. Third Party Websites

    -

    - 8.1 Content on Scratch, including user-generated content, may include - links to third party websites. The Scratch Team is not capable of - reviewing or managing third party websites, and assumes no - responsibility for the privacy practices, content, or functionality - of third party websites. You agree to relieve the Scratch Team of - any and all liability arising from third party websites. -

    -
    -
    - -

    9. Indemnification

    -

    - You agree to indemnify MIT, the Scratch Team, the Scratch Foundation, - and all their affiliates, employees, faculty members, fellows, - students, agents, representatives, third party service providers, - and members of their governing boards (all of which are "Scratch - Entities"), and to defend and hold each of them harmless, from any - and all claims and liabilities (including attorneys{'\''} fees) arising - out of or related to your breach of the Terms of Service or your - use of Scratch. -

    -

    - For federal government agencies, provisions in the Terms of Use - relating to Indemnification shall not apply to your Official Use, - except to the extent expressly authorized by federal law. For - state and local government agencies in the United States, Terms - of Use relating to Indemnification shall apply to your Official - Use only to the extent authorized by the laws of your jurisdiction. -

    -
    -
    - -

    10. Disclaimer of Warranty

    -

    - You acknowledge that you are using Scratch at your own risk. Scratch - is provided "as is," and the Scratch Entities hereby expressly - disclaim any and all warranties, express and implied, including but - not limited to any warranties of accuracy, reliability, title, - merchantability, non-infringement, fitness for a particular purpose - or any other warranty, condition, guarantee or representation, - whether oral, in writing or in electronic form, including but not - limited to the accuracy or completeness of any information contained - therein or provided by Scratch. Without limiting the foregoing, the - Scratch Entities disclaim any and all warranties, express and implied, - regarding user-generated content and Scratch Day events. The Scratch - Entities and their third party service providers do not represent or - warrant that access to Scratch will be uninterrupted or that there - will be no failures, errors or omissions or loss of transmitted - information, or that no viruses will be transmitted through Scratch - services. -

    -
    -
    - -

    11. Limitation of Liability

    -

    - The Scratch Entities shall not be liable to you or any third parties - for any direct, indirect, special, consequential or punitive damages - of any kind, regardless of the type of claim or the nature of the - cause of action, even if the Scratch Team has been advised of the - possibility of such damages. Without limiting the foregoing, the - Scratch Entites shall have no liability to you or any third parties - for damages or harms arising out of user-generated content or - Scratch Day events. -

    -
    -
    - -

    12. Jurisdiction

    -

    - Scratch is offered by the Scratch Team from its facilities in the United - States. The Scratch Team makes no representations that Scratch is - appropriate or available for use in other locations. Those who access - or use Scratch are responsible for compliance with local law. -

    -
    -
    - -

    13. Choice of Law and Venue

    -

    - You agree that these Terms of Use, for all purposes, shall be governed - and construed in accordance with the laws of the Commonwealth of - Massachusetts applicable to contracts to be wholly performed therein, - and any action based on, relating to, or alleging a breach of the - Terms of Use must be brought in a state or federal court in Suffolk - County, Massachusetts. In addition, both parties agree to submit to - the exclusive personal jurisdiction and venue of such courts. -

    -

    - If you are a federal, state, or local government entity in the United - States using Scratch in your official capacity and legally unable to - accept the controlling law, jurisdiction or venue clauses above, then - those clauses do not apply to you. For such U.S. federal government - entities, these Terms and any action related thereto will be governed - by the laws of the United States of America (without reference to - conflict of laws) and, in the absence of federal law and to the extent - permitted under federal law, the laws of the Commonwealth of - Massachusetts (excluding choice of law). -

    -
    -
    - -

    14. Choice of Language

    -

    - If the Scratch Team provides you with a translation of the English language - version of these Terms of Use, the Privacy Policy, or any other policy, - then you agree that the translation is provided for informational purposes - only and does not modify the English language version. In the event of a - conflict between a translation and the English version, the English version - will govern. -

    -
    -
    - -

    15. No Waiver

    -

    - No waiver of any term of these Terms of Use shall be deemed a further or - continuing waiver of such term or any other term, and the Scratch Team's - failure to assert any right or provision under these Terms of Use shall - not constitute a waiver of such right or provision. -

    -
    -
    - -

    16. Entire Agreement

    -

    - This document, together with all appendices, constitutes the entire Terms - of Use and supersedes all previous agreements with the Scratch Team relating - to the use of Scratch. Revision date: 4 March 2015. -

    -
    -
    - -

    Appendix A: Additional Terms for Scratch Day Website

    -

    - The following additional terms also govern your access to and use of web - pages hosted within day.scratch.mit.edu/ (collectively, the “Scratch Day - Site”). All of the terms set forth in the general Terms of Use above also - apply to the Scratch Day Site, unless we clearly state otherwise. -

    -

    1. Privacy Policy

    -

    - The Scratch Day Site Privacy Policy, not the Scratch Privacy Policy, - describes how the Scratch Team uses, collects, and stores information - it collects through the Scratch Day Site. By using the Scratch Day - Site, you agree that you are comfortable with the Privacy Policy. -

    -

    2. Account Creation and Maintenance

    -

    - 2.1 In order to post an event to the Scratch Day Site, you will need - to register and create an account. This account is a separate account - from your Scratch account. All registrants must be over 18 years of - age. When registering for a personal account, you will be asked to - provide certain personal information, such as your email address, - first and last name, and Scratch username (optional). Please see the - Scratch Day Site Privacy Policy for Scratch’s data retention and usage - policies. -

    -

    - 2.2 You are responsible for keeping your password secret and your account - secure. You are solely responsible for any use of your account, even if - your account is used by another person. If any use of your account - violates the Terms of Use, your account may be suspended or deleted. -

    -

    - 2.3 If you have reason to believe that your account is no longer secure - (for example, in the event of a loss, theft, or unauthorized disclosure - of your password), promptly change your password. If you cannot access - your account to change your password, notify us at{' '} - scratchday@media.mit.edu -

    -

    - 2.4 The terms set forth in this section apply to the Scratch Day Site. - The Account Creation and Maintenance terms in the general Terms of Use - do not apply to the Scratch Day Site. -

    -

    3. No Endorsement

    -

    - You understand that neither MIT, nor the Scratch Team, nor the Code to - Learn Foundation endorses any Scratch Day event. If you are hosting a - Scratch Day event, you may not state or imply that MIT, the Scratch - Team, or the Code to Learn Foundation has endorsed your event. -

    -
    -
    - -

    Appendix B: Additional Terms for ScratchX Website

    -

    - The following additional terms also govern your access to and use of web - pages hosted within scratchx.org (collectively, the “ScratchX Site”). - All of the terms set forth in the general Terms of Use above also apply - to the ScratchX Site, unless we clearly state otherwise. -

    -

    1. ScratchX and GitHub

    -

    - The ScratchX Site provides a platform for developers to link their - experimental extensions to Scratch. However, we do not host those - extensions or save them on the ScratchX site. All the extensions loaded - on to ScratchX are hosted publicly on independent developers’ accounts - on GitHub. Your use of GitHub is subject to GitHub’s Terms of Service - and Privacy. -

    -

    2. Privacy Policy

    -

    - The ScratchX Site Privacy Policy, not the Scratch Privacy Policy, - describes how the Scratch Team uses, collects, and stores information - it collects through the ScratchX Site. By using the ScratchX Site, you - agree to the terms of the Privacy Policy. -

    -

    3. No Endorsement

    -

    - By using ScratchX, you understand that neither MIT, nor the Scratch Team, - nor the Code to Learn Foundation endorses any ScratchX experimental - extension. If you are a developer linking to your own experimental - extension via the ScratchX site, you may not state or imply that MIT, - the Scratch Team, or the Code to Learn Foundation has endorsed your - extension. -

    -
    -

    The Scratch Terms of Use was last updated: April 2016

    -
    - -
    -); + + + ); + } +}); render(, document.getElementById('app')); diff --git a/src/views/tips/tips.jsx b/src/views/tips/tips.jsx index b23a0d979..12012f531 100644 --- a/src/views/tips/tips.jsx +++ b/src/views/tips/tips.jsx @@ -1,94 +1,73 @@ -const bindAll = require('lodash.bindall'); -const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage; -const FormattedMessage = require('react-intl').FormattedMessage; -const injectIntl = require('react-intl').injectIntl; -const intlShape = require('react-intl').intlShape; -const React = require('react'); +var React = require('react'); +var injectIntl = require('react-intl').injectIntl; +var FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage; +var FormattedMessage = require('react-intl').FormattedMessage; +var render = require('../../lib/render.jsx'); -const Button = require('../../components/forms/button.jsx'); -const FlexRow = require('../../components/flex-row/flex-row.jsx'); -const MasonryGrid = require('../../components/masonrygrid/masonrygrid.jsx'); -const TitleBanner = require('../../components/title-banner/title-banner.jsx'); -const TTTModal = require('../../components/modal/ttt/modal.jsx'); -const TTTTile = require('../../components/ttt-tile/ttt-tile.jsx'); - -const Page = require('../../components/page/www/page.jsx'); -const render = require('../../lib/render.jsx'); - -const Tiles = require('./ttt.json'); +var MasonryGrid = require('../../components/masonrygrid/masonrygrid.jsx'); +var Page = require('../../components/page/www/page.jsx'); +var Button = require('../../components/forms/button.jsx'); +var TitleBanner = require('../../components/title-banner/title-banner.jsx'); +var FlexRow = require('../../components/flex-row/flex-row.jsx'); +var TTTTile = require('../../components/ttt-tile/ttt-tile.jsx'); +var TTTModal = require('../../components/modal/ttt/modal.jsx'); +var Tiles = require('./ttt.json'); require('./tips.scss'); -class Tips extends React.Component { - constructor (props) { - super(props); - bindAll(this, [ - 'handleShowTTTModal', - 'handleHideTTTModal', - 'renderTTTTiles' - ]); - this.state = { - currentTile: Tiles[0], - TTTModalOpen: false - }; - } - handleShowTTTModal (tile) { +var Tips = injectIntl(React.createClass({ + type: 'Tips', + getInitialState: function () { + return {currentTile: Tiles[0], TTTModalOpen: false}; + }, + showTTTModal: function (tile) { // expects translated tile - this.setState({ - currentTile: tile, - TTTModalOpen: true - }); - } - handleHideTTTModal () { - this.setState({ - TTTModalOpen: false - }); - } - renderTTTTiles () { + this.setState({currentTile: tile, TTTModalOpen: true}); + }, + hideTTTModal: function () { + this.setState({TTTModalOpen: false}); + }, + renderTTTTiles: function () { + var formatMessage = this.props.intl.formatMessage; + var translatedTile = {}; - return Tiles.map((tile, key) => { - const translatedTile = { - activityLoc: this.props.intl.formatMessage({id: tile.activityLoc}), - bannerUrl: tile.bannerUrl, - description: this.props.intl.formatMessage({id: tile.description}), - guideLoc: this.props.intl.formatMessage({id: tile.guideLoc}), + return Tiles.map(function (tile, key) { + translatedTile = { + title: formatMessage({id: tile.title}), + description: formatMessage({id: tile.description}), + tutorialLoc: tile.tutorialLoc, + activityLoc: formatMessage({id: tile.activityLoc}), + guideLoc: formatMessage({id: tile.guideLoc}), thumbUrl: tile.thumbUrl, - title: this.props.intl.formatMessage({id: tile.title}), - tutorialLoc: tile.tutorialLoc + bannerUrl: tile.bannerUrl }; - return ( - { // eslint-disable-line react/jsx-no-bind - this.handleShowTTTModal(translatedTile); - }} - {...translatedTile} - /> - ); - }); - } - render () { + return (); + }, this); // don't forget to pass 'this' into map function + }, + render: function () { + var formatMessage = this.props.intl.formatMessage; return (

    - +

    @@ -98,10 +77,10 @@ class Tips extends React.Component {

    - +

    - +

    @@ -109,78 +88,62 @@ class Tips extends React.Component { + onRequestClose={this.hideTTTModal} + {...this.state.currentTile}/>
    -
    +
    - +
    - +

    - +

    - +

    @@ -189,46 +152,40 @@ class Tips extends React.Component {
    - -
    - -

    - -

    -

    - -

    -
    -
    - -

    - -

    -

    - -

    -
    -
    + +
    + +

    + +

    +

    + +

    +
    +
    + +

    + +

    +

    + +

    +
    +
    ); } -} - -Tips.propTypes = { - intl: intlShape -}; - -const WrappedTips = injectIntl(Tips); +})); render( - , document.getElementById('app')); + , document.getElementById('app')); diff --git a/src/views/wedo2/wedo2.jsx b/src/views/wedo2/wedo2.jsx index e455f0732..7457f40eb 100644 --- a/src/views/wedo2/wedo2.jsx +++ b/src/views/wedo2/wedo2.jsx @@ -1,155 +1,142 @@ -const FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage; -const FormattedMessage = require('react-intl').FormattedMessage; -const React = require('react'); +var FormattedHTMLMessage = require('react-intl').FormattedHTMLMessage; +var FormattedMessage = require('react-intl').FormattedMessage; +var React = require('react'); -const Page = require('../../components/page/www/page.jsx'); -const render = require('../../lib/render.jsx'); +var Page = require('../../components/page/www/page.jsx'); +var render = require('../../lib/render.jsx'); require('./wedo2.scss'); -const Wedo2 = () => ( -
    -
    -
    -
    -
    -

    LEGO WeDo 2.0 & Scratch

    -

    - +var Wedo2 = React.createClass({ + type: 'wedo2', + render: function () { + return ( +

    +
    +
    +
    +
    +

    LEGO WeDo 2.0 & Scratch

    +

    + +

    +
    +
    + +
    +
    +
    +
    + +
    +
    +

    + +

    +

    +

    +
    +
    + +

    + +

    +

    + +
    + + + +
    + + + +

    +
    +
    + +

    + +

    +

    + +

    +
    +
    + +

    + +

    +

    + +

    +
    +
    +
    +
    + + + +
    +
    +

    + +

    +

    + +

    +
    +

    LEGO WeDo 1.0 Hub

    + LEGO WeDo 1.0 Hub + + + +
    +
    +

    LEGO WeDo 2.0 Hub

    + LEGO WeDo 2.0 Hub + + + +
    +
    -
    - -
    -
    -

    - -

    -

    - -

    -
    -
    - -

    - -

    -

    - -
    - - - -
    - - - -

    -
    -
    - -

    - -

    -

    - -

    -
    -
    - -

    - -

    -

    - -

    -
    -
    -
    -
    - - - -
    -
    -

    - -

    -

    - -

    -
    -

    LEGO WeDo 1.0 Hub

    - LEGO WeDo 1.0 Hub - - - -
    -
    -

    LEGO WeDo 2.0 Hub

    - LEGO WeDo 2.0 Hub - - - -
    -
    -
    -
    -); + ); + } +}); render(, document.getElementById('app')); diff --git a/test/helpers/selenium-helpers.js b/test/helpers/selenium-helpers.js index 2b55e2a4d..a850a6aac 100644 --- a/test/helpers/selenium-helpers.js +++ b/test/helpers/selenium-helpers.js @@ -49,7 +49,6 @@ const getLogs = (whitelist) => { } return true; } - return true; }); }); }; diff --git a/test/integration/smoke-testing/test_footer_links.js b/test/integration/smoke-testing/test_footer_links.js index cd5651d70..330b2d548 100644 --- a/test/integration/smoke-testing/test_footer_links.js +++ b/test/integration/smoke-testing/test_footer_links.js @@ -4,7 +4,7 @@ * Test cases: https://github.com/LLK/scratch-www/wiki/Most-Important-Workflows */ -const tap = require('tap'); +var tap = require('tap'); const { driver, @@ -12,109 +12,107 @@ const { } = require('../../helpers/selenium-helpers.js'); // Selenium's promise driver will be deprecated, so we should not rely on it -webdriver.SELENIUM_PROMISE_MANAGER = 0; +webdriver.SELENIUM_PROMISE_MANAGER=0; -const rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; +var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; -// timeout for each test; timeout for suite set at command line level -const options = {timeout: 30000}; +//timeout for each test; timeout for suite set at command line level +var options = { timeout: 30000 }; -// number of tests in the plan +//number of tests in the plan tap.plan(25); tap.tearDown(function () { - // quit the instance of the browser + //quit the instance of the browser driver.quit(); }); tap.beforeEach(function () { - // load the page with the driver + //load the page with the driver return driver.get(rootUrl); }); // Function clicks the link and returns the url of the resulting page -const clickFooterLinks = function (linkText) { +function clickFooterLinks (linkText) { return driver.wait(webdriver.until.elementLocated(webdriver.By.id('footer'))) - .then(function (element) { - return element.findElement(webdriver.By.linkText(linkText)); - }) - .then(function (element) { - return element.click(); - }) - .then(function () { - return driver.getCurrentUrl(); - }); -}; + .then( function (element) { + return element.findElement(webdriver.By.linkText(linkText)); }) + .then( function (element) { + return element.click(); }) + .then(function () { + return driver.getCurrentUrl(); + }); +} // ==== ABOUT SCRATCH column ==== // ABOUT SCRATCH -tap.test('clickAboutScratchLink', options, t => { - const linkText = 'About Scratch'; - const expectedHref = '/about'; - clickFooterLinks(linkText).then(url => { - // the href should be at the end of the URL +tap.test('clickAboutScratchLink', options, function (t) { + var linkText = 'About Scratch'; + var expectedHref = '/about'; + clickFooterLinks(linkText).then( function (url) { + //the href should be at the end of the URL t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // FOR PARENTS -tap.test('clickForParentsLink', options, t => { - const linkText = 'For Parents'; - const expectedHref = '/parents/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickForParentsLink', options, function (t) { + var linkText = 'For Parents'; + var expectedHref = '/parents/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // FOR EDUCATORS -tap.test('clickForEducatorsLink', options, t => { - const linkText = 'For Educators'; - const expectedHref = '/educators'; - clickFooterLinks(linkText).then(url => { +tap.test('clickForEducatorsLink', options, function (t) { + var linkText = 'For Educators'; + var expectedHref = '/educators'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // FOR DEVELOPERS -tap.test('clickForDevelopersScratchLink', options, t => { - const linkText = 'For Developers'; - const expectedHref = '/developers'; - clickFooterLinks(linkText).then(url => { +tap.test('clickForDevelopersScratchLink', options, function (t) { + var linkText = 'For Developers'; + var expectedHref = '/developers'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // CREDITS -tap.test('clickCreditsLink', options, t => { - const linkText = 'Credits'; - const expectedHref = '/info/credits'; - clickFooterLinks(linkText).then(url => { +tap.test('clickCreditsLink', options, function (t) { + var linkText = 'Credits'; + var expectedHref = '/info/credits'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // JOBS -tap.test('clickJobsLink', options, t => { - const linkText = 'Jobs'; - const expectedHref = '/jobs'; - clickFooterLinks(linkText).then(url => { +tap.test('clickJobsLink', options, function (t) { + var linkText = 'Jobs'; + var expectedHref = '/jobs'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // PRESS -tap.test('clickPressLink', options, t => { - const linkText = 'Press'; - const expectedUrl = 'https://wiki.scratch.mit.edu/wiki/Scratch_Press'; - clickFooterLinks(linkText).then(url => { +tap.test('clickPressLink', options, function (t) { + var linkText = 'Press'; + var expectedUrl = 'https://wiki.scratch.mit.edu/wiki/Scratch_Press'; + clickFooterLinks(linkText).then( function (url) { t.equal(url, expectedUrl); t.end(); }); @@ -123,40 +121,40 @@ tap.test('clickPressLink', options, t => { // ==== COMMUNITY column ==== // COMMUNITY GUIDELINES -tap.test('clickCommunityGuidelinesLink', options, t => { - const linkText = 'Community Guidelines'; - const expectedHref = '/community_guidelines'; - clickFooterLinks(linkText).then(url => { +tap.test('clickCommunityGuidelinesLink', options, function (t) { + var linkText = 'Community Guidelines'; + var expectedHref = '/community_guidelines'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // DISCUSSION FORUMS -tap.test('clickDiscussionForumsLink', options, t => { - const linkText = 'Discussion Forums'; - const expectedHref = '/discuss/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickDiscussionForumsLink', options, function (t) { + var linkText = 'Discussion Forums'; + var expectedHref = '/discuss/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // SCRATCH WIKI -tap.test('clickScratchWikiLink', options, t => { - const linkText = 'Scratch Wiki'; - const expectedUrl = 'https://wiki.scratch.mit.edu/wiki/Scratch_Wiki_Home'; - clickFooterLinks(linkText).then(url => { +tap.test('clickScratchWikiLink', options, function (t) { + var linkText = 'Scratch Wiki'; + var expectedUrl = 'https://wiki.scratch.mit.edu/wiki/Scratch_Wiki_Home'; + clickFooterLinks(linkText).then( function (url) { t.equal(url, expectedUrl); t.end(); }); }); // STATISTICS -tap.test('clickStatisticsLink', options, t => { - const linkText = 'Statistics'; - const expectedHref = '/statistics/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickStatisticsLink', options, function (t) { + var linkText = 'Statistics'; + var expectedHref = '/statistics/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); @@ -165,60 +163,60 @@ tap.test('clickStatisticsLink', options, t => { // ==== SUPPORT column ==== // TIPS PAGE -tap.test('clickTipsPageLink', options, t => { - const linkText = 'Tips'; - const expectedHref = '/tips'; - clickFooterLinks(linkText).then(url => { +tap.test('clickTipsPageLink', options, function (t) { + var linkText = 'Tips'; + var expectedHref = '/tips'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // FAQ -tap.test('clickFAQLink', options, t => { - const linkText = 'FAQ'; - const expectedHref = '/info/faq'; - clickFooterLinks(linkText).then(url => { +tap.test('clickFAQLink', options, function (t) { + var linkText = 'FAQ'; + var expectedHref = '/info/faq'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // OFFLINE EDITOR -tap.test('clickOfflineEditorLink', options, t => { - const linkText = 'Offline Editor'; - const expectedHref = '/download'; - clickFooterLinks(linkText).then(url => { +tap.test('clickOfflineEditorLink', options, function (t) { + var linkText = 'Offline Editor'; + var expectedHref = '/download'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // CONTACT US -tap.test('clickContactUsLink', options, t => { - const linkText = 'Contact Us'; - const expectedHref = '/contact-us/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickContactUsLink', options, function (t) { + var linkText = 'Contact Us'; + var expectedHref = '/contact-us/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // SCRATCH STORE -tap.test('clickScratchStoreLink', options, t => { - const linkText = 'Scratch Store'; - const expectedUrl = 'https://scratch-foundation.myshopify.com/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickScratchStoreLink', options, function (t) { + var linkText = 'Scratch Store'; + var expectedUrl = 'https://scratch-foundation.myshopify.com/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url, expectedUrl); t.end(); }); }); // DONATE -tap.test('clickDonateLink', options, t => { - const linkText = 'Donate'; - const expectedUrl = 'https://secure.donationpay.org/scratchfoundation/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickDonateLink', options, function (t) { + var linkText = 'Donate'; + var expectedUrl = 'https://secure.donationpay.org/scratchfoundation/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url, expectedUrl); t.end(); }); @@ -227,30 +225,30 @@ tap.test('clickDonateLink', options, t => { // ==== LEGAL column ==== // TERMS OF USE -tap.test('clickTermsOfUseLink', options, t => { - const linkText = 'Terms of Use'; - const expectedHref = '/terms_of_use'; - clickFooterLinks(linkText).then(url => { +tap.test('clickTermsOfUseLink', options, function (t) { + var linkText = 'Terms of Use'; + var expectedHref = '/terms_of_use'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // PRIVACY POLICY -tap.test('clickPrivacyPolicyLink', options, t => { - const linkText = 'Privacy Policy'; - const expectedHref = '/privacy_policy'; - clickFooterLinks(linkText).then(url => { +tap.test('clickPrivacyPolicyLink', options, function (t) { + var linkText = 'Privacy Policy'; + var expectedHref = '/privacy_policy'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // DMCA -tap.test('clickDMCALink', options, t => { - const linkText = 'DMCA'; - const expectedHref = '/DMCA'; - clickFooterLinks(linkText).then(url => { +tap.test('clickDMCALink', options, function (t) { + var linkText = 'DMCA'; + var expectedHref = '/DMCA'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); @@ -259,50 +257,50 @@ tap.test('clickDMCALink', options, t => { // ==== SCRATCH FAMILY column ==== // SCRATCH ED (SCRATCHED) -tap.test('clickScratchEdLink', options, t => { - const linkText = 'ScratchEd'; - const expectedUrl = 'http://scratched.gse.harvard.edu/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickScratchEdLink', options, function (t) { + var linkText = 'ScratchEd'; + var expectedUrl = 'http://scratched.gse.harvard.edu/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url, expectedUrl); t.end(); }); }); // SCRATCH JR (SCRATCHJR) -tap.test('clickScratchJrLink', options, t => { - const linkText = 'ScratchJr'; - const expectedUrl = 'http://www.scratchjr.org/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickScratchJrLink', options, function (t) { + var linkText = 'ScratchJr'; + var expectedUrl = 'http://www.scratchjr.org/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url, expectedUrl); t.end(); }); }); // SCRATCH DAY -tap.test('clickScratchDayLink', options, t => { - const linkText = 'Scratch Day'; - const expectedUrl = 'https://day.scratch.mit.edu/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickScratchDayLink', options, function (t) { + var linkText = 'Scratch Day'; + var expectedUrl = 'https://day.scratch.mit.edu/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url, expectedUrl); t.end(); }); }); // SCRATCH CONFERENCE -tap.test('clickScratchConferenceLink', options, t => { - const linkText = 'Scratch Conference'; - const expectedHref = '/conference'; - clickFooterLinks(linkText).then(url => { +tap.test('clickScratchConferenceLink', options, function (t) { + var linkText = 'Scratch Conference'; + var expectedHref = '/conference'; + clickFooterLinks(linkText).then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); }); // SCRATCH FOUNDATION -tap.test('clickScratchFoundationLink', options, t => { - const linkText = 'Scratch Foundation'; - const expectedUrl = 'https://www.scratchfoundation.org/'; - clickFooterLinks(linkText).then(url => { +tap.test('clickScratchFoundationLink', options, function (t) { + var linkText = 'Scratch Foundation'; + var expectedUrl = 'https://www.scratchfoundation.org/'; + clickFooterLinks(linkText).then( function (url) { t.equal(url, expectedUrl); t.end(); }); diff --git a/test/integration/smoke-testing/test_navbar_links.js b/test/integration/smoke-testing/test_navbar_links.js index efe5cf2ba..20e94ace5 100644 --- a/test/integration/smoke-testing/test_navbar_links.js +++ b/test/integration/smoke-testing/test_navbar_links.js @@ -9,39 +9,37 @@ var seleniumWebdriver = require('selenium-webdriver'); var tap = require('tap'); // Selenium's promise driver will be deprecated, so we should not rely on it -seleniumWebdriver.SELENIUM_PROMISE_MANAGER = 0; +seleniumWebdriver.SELENIUM_PROMISE_MANAGER=0; -// Set test url through environment variable +//Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); -// number of tests in the plan +//number of tests in the plan tap.plan(7); tap.tearDown(function () { - // quit the instance of the browser + //quit the instance of the browser driver.quit(); }); tap.beforeEach(function () { - // load the page with the driver + //load the page with the driver return driver.get(rootUrl); }); // ==== Links in navbar ==== -// the create link changes depending on whether the user is signed in or not (tips window opens) +//the create link changes depending on whether the user is signed in or not (tips window opens) tap.test('checkCreateLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "create")]/a'; var expectedHref = '/projects/editor/?tip_bar=home'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) - .then(function (element) { - return element.getAttribute('href'); - }) - .then(function (url) { + .then( function (element) { + return element.getAttribute('href');}) + .then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); @@ -51,10 +49,9 @@ tap.test('checkExploreLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "explore")]/a'; var expectedHref = '/explore/projects/all'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) - .then(function (element) { - return element.getAttribute('href'); - }) - .then(function (url) { + .then( function (element) { + return element.getAttribute('href');}) + .then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); @@ -64,10 +61,9 @@ tap.test('checkTipsLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "tips")]/a'; var expectedHref = '/tips'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) - .then(function (element) { - return element.getAttribute('href'); - }) - .then(function (url) { + .then( function (element) { + return element.getAttribute('href');}) + .then( function (url) { t.equal(url.substr(-expectedHref.length), expectedHref); t.end(); }); @@ -77,13 +73,12 @@ tap.test('checkAboutLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "about")]/a'; var expectedHref = '/about'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) - .then(function (element) { - return element.getAttribute('href'); - }) - .then(function (url) { - t.equal(url.substr(-expectedHref.length), expectedHref); - t.end(); - }); + .then( function (element) { + return element.getAttribute('href');}) + .then( function (url) { + t.equal(url.substr(-expectedHref.length), expectedHref); + t.end(); + }); }); // ==== Search bar ==== @@ -91,7 +86,7 @@ tap.test('checkAboutLinkWhenSignedOut', function (t) { tap.test('checkSearchBar', function (t) { var xPathLink = '//input[@id="frc-q-1088"]'; // search bar should exist - driver.findElement(seleniumWebdriver.By.xpath(xPathLink)).then(function (element) { + driver.findElement(seleniumWebdriver.By.xpath(xPathLink)).then( function (element) { t.ok(element); t.end(); }); @@ -103,10 +98,9 @@ tap.test('checkJoinScratchLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "right") and contains(@class, "join")]/a'; var expectedText = 'Join Scratch'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) - .then(function (element) { - return element.getText('a'); - }) - .then(function (text) { + .then( function (element) { + return element.getText('a');}) + .then( function (text) { t.equal(text, expectedText); t.end(); }); @@ -116,10 +110,9 @@ tap.test('checkSignInLinkWhenSignedOut', function (t) { var xPathLink = '//li[contains(@class, "link") and contains(@class, "right") and contains(@class, "login-item")]/a'; var expectedText = 'Sign in'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) - .then(function (element) { - return element.getText('a'); - }) - .then(function (text) { + .then( function (element) { + return element.getText('a');}) + .then( function (text) { t.equal(text, expectedText); t.end(); }); diff --git a/test/integration/smoke-testing/test_project_rows.js b/test/integration/smoke-testing/test_project_rows.js index 28e61bf93..9a2633d70 100644 --- a/test/integration/smoke-testing/test_project_rows.js +++ b/test/integration/smoke-testing/test_project_rows.js @@ -10,86 +10,85 @@ var tap = require('tap'); var seleniumWebdriver = require('selenium-webdriver'); // Selenium's promise driver will be deprecated, so we should not rely on it -seleniumWebdriver.SELENIUM_PROMISE_MANAGER = 0; +seleniumWebdriver.SELENIUM_PROMISE_MANAGER=0; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); var rootUrl = process.env.ROOT_URL || 'https://scratch.ly'; -// number of tests in the plan +//number of tests in the plan tap.plan(4); tap.tearDown(function () { - // quit the instance of the browser + //quit the instance of the browser driver.quit(); }); tap.beforeEach(function () { - // load the page with the driver + //load the page with the driver return driver.get(rootUrl); }); -// checks that the title of the first row is Featured Projects +//checks that the title of the first row is Featured Projects tap.test('checkFeaturedProjectsRowTitleWhenSignedOut', function (t) { var xPathLink = '//div[@class="box"]/div[@class="box-header"]/h4'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) - .then(function (element) { + .then( function (element) { element.getText('h4') - .then(function (text) { - // expected value of the title text - var expectedText = 'Featured Projects'; - t.equal(text, expectedText); - t.end(); - }); + .then( function (text) { + //expected value of the title text + var expectedText = 'Featured Projects'; + t.equal(text, expectedText); + t.end(); + }); }); }); -// checks that the link for a project makes sense +//checks that the link for a project makes sense tap.test('checkFeaturedProjectsRowLinkWhenSignedOut', function (t) { var xPathLink = '//div[contains(@class, "thumbnail") ' + 'and contains(@class, "project") and contains(@class, "slick-slide") ' + 'and contains(@class, "slick-active")]/a[@class="thumbnail-image"]'; driver.wait(seleniumWebdriver.until .elementLocated(seleniumWebdriver.By.xpath(xPathLink))) - .then(function (element) { + .then( function (element) { element.getAttribute('href') - .then(function (url) { - // expected pattern for the project URL - // since I don't know the length of the project ID number - var expectedUrlRegExp = new RegExp('/projects/.*[0-9].*/?'); - t.match(url, expectedUrlRegExp); - t.end(); - }); + .then( function (url) { + //expected pattern for the project URL + //since I don't know the length of the project ID number + var expectedUrlRegExp = new RegExp('/projects/.*[0-9].*/?'); + t.match(url, expectedUrlRegExp); + t.end(); + }); }); }); -// checks that the title of the 2nd row is Featured Studios +//checks that the title of the 2nd row is Featured Studios tap.test('checkFeaturedStudiosRowWhenSignedOut', function (t) { var xPathLink = '//div[@class="box"][2]/div[@class="box-header"]/h4'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) .then(function (element) { element.getText('h4') - .then(function (text) { - var expectedText = 'Featured Studios'; - t.equal(text, expectedText); - t.end(); - }); + .then( function (text) { + var expectedText = 'Featured Studios'; + t.equal(text, expectedText); + t.end(); + }); }); }); -// checks that the link for a studio makes sense +//checks that the link for a studio makes sense tap.test('checkFeaturedStudiosRowLinkWhenSignedOut', function (t) { var xPathLink = '//div[contains(@class, "thumbnail") and contains(@class, "gallery") ' + 'and contains(@class, "slick-slide") and contains(@class, "slick-active")]/a[@class="thumbnail-image"]'; driver.findElement(seleniumWebdriver.By.xpath(xPathLink)) .then(function (element) { element.getAttribute('href') - .then(function (url) { - var expectedUrlRegExp = new RegExp('/studios/.*[0-9].*/?'); - t.match(url, expectedUrlRegExp); - t.end(); - }); + .then( function (url) { + var expectedUrlRegExp = new RegExp('/studios/.*[0-9].*/?'); + t.match(url, expectedUrlRegExp); + t.end(); + }); }); }); diff --git a/test/integration/smoke-testing/test_signing_in_and_my_stuff.js b/test/integration/smoke-testing/test_signing_in_and_my_stuff.js index 68bed40b5..f2efdd455 100644 --- a/test/integration/smoke-testing/test_signing_in_and_my_stuff.js +++ b/test/integration/smoke-testing/test_signing_in_and_my_stuff.js @@ -42,18 +42,16 @@ tap.beforeEach(function () { */ test('Trying to sign in with no username and no password using scratchr2 navbar', t => { clickText('Sign in') - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]'))) - ) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]'))) - ) - .then(() => findByXpath('//form/div[@class="error"]')) - .then(element => element.getText()) - .then(text => t.match(text, 'This field is required.', - '"This field is required" error should be displayed')) - .then(() => t.end()); + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'This field is required.', + '"This field is required" error should be displayed')) + .then(() => t.end()); }); /* @@ -63,181 +61,175 @@ test('Trying to sign in with no username and no password using scratchr2 navbar' */ test('Trying to sign in with no username using scratchr2 navbar', t => { clickText('Sign in') - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys(password)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]'))) - ) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]'))) - ) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'This field is required.', - '"This field is required" error should be displayed')) - .then(() => t.end()); + .then(() => findByXpath('//input[@name="password"]')) + .then((element) => element.sendKeys(password)) + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'This field is required.', + '"This field is required" error should be displayed')) + .then(() => t.end()); }); test('Trying to sign in with no password using scratchr2 navbar', t => { - var nonsenseusername = Math.random().toString(36) - .replace(/[^a-z]+/g, '') - .substr(0, 5); + var nonsenseusername = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) - .then((element) => element.sendKeys(nonsenseusername)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'This field is required.', - '"This field is required" error should be displayed')) - .then(() => t.end()); + .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + .then((element) => element.sendKeys(nonsenseusername)) + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'This field is required.', + '"This field is required" error should be displayed')) + .then(() => t.end()); }); test('Trying to sign in with the wrong username using scratchr2 navbar', t => { - var nonsenseusername = Math.random().toString(36) - .replace(/[^a-z]+/g, '') - .substr(0, 5); + var nonsenseusername = Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5); clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) - .then((element) => element.sendKeys(nonsenseusername)) - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys(password)) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'Incorrect username or password.', - '"Incorrect username or password" error should be displayed')) - .then(() => t.end()); + .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + .then((element) => element.sendKeys(nonsenseusername)) + .then(() => findByXpath('//input[@name="password"]')) + .then((element) => element.sendKeys(password)) + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'Incorrect username or password.', + '"Incorrect username or password" error should be displayed')) + .then(() => t.end()); }); test('Trying to sign in with the wrong password using scratchr2 navbar', t => { clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) - .then((element) => element.sendKeys(username)) - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys('nonsensepassword')) - .then(() => clickButton('Sign in')) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) - .then(() => driver.wait(until - .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) - .then(() => findByXpath('//form/div[@class="error"]')) - .then((element) => element.getText()) - .then((text) => t.match(text, 'Incorrect username or password.', - '"Incorrect username or password" error should be displayed')) - .then(() => t.end()); + .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + .then((element) => element.sendKeys(username)) + .then(() => findByXpath('//input[@name="password"]')) + .then((element) => element.sendKeys('nonsensepassword')) + .then(() => clickButton('Sign in')) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/button[@type="submit"]')))) + .then(() => driver.wait(until + .elementLocated(By.xpath('//form[@id="login"]/div[@class="error"]')))) + .then(() => findByXpath('//form/div[@class="error"]')) + .then((element) => element.getText()) + .then((text) => t.match(text, 'Incorrect username or password.', + '"Incorrect username or password" error should be displayed')) + .then(() => t.end()); }); test('Sign in to Scratch using scratchr2 navbar', t => { clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) - .then((element) => element.sendKeys(username)) - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys(password)) - .then(() => clickButton('Sign in')) - .then(() => findByXpath('//li[contains(@class, "logged-in-user")' + - 'and contains(@class, "dropdown")]/span')) - .then((element) => element.getText('span')) - .then((text) => t.match(text.toLowerCase(), username.substring(0, 10).toLowerCase(), + .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + .then((element) => element.sendKeys(username)) + .then(() => findByXpath('//input[@name="password"]')) + .then((element) => element.sendKeys(password)) + .then(() => clickButton('Sign in')) + .then(() => findByXpath('//li[contains(@class, "logged-in-user")' + + 'and contains(@class, "dropdown")]/span')) + .then((element) => element.getText('span')) + .then((text) => t.match(text.toLowerCase(), username.substring(0,10).toLowerCase(), 'first part of username should be displayed in navbar')) - .then(() => t.end()); + .then(() => t.end()); }); test('Sign in to Scratch & verify My Stuff structure (tabs, title)', t => { clickXpath('//a[@class="mystuff-icon"]') - .then(() => findByXpath('//div[@class="box-head"]/h2')) - .then((element) => element.getText('h2')) - .then((text) => t.equal('My Stuff', text, 'title should be My Stuff')) - .then(() => findByXpath('//li[@data-tab="projects"]/a')) - .then((element) => element.getText('a')) - .then((text) => t.match(text, 'All Projects', 'All Projects tab should be present')) - .then(() => findByXpath('//li[@data-tab="shared"]/a')) - .then((element) => element.getText('a')) - .then((text) => t.match(text, 'Shared Projects', 'Shared Projects tab should be present')) - .then(() => findByXpath('//li[@data-tab="unshared"]/a')) - .then((element) => element.getText('a')) - .then((text) => t.match(text, 'Unshared Projects', 'Unshared Projects tab should be present')) - .then(() => findByXpath('//li[@data-tab="galleries"]/a')) - .then((element) => element.getText('a')) - .then((text) => t.match(text, 'My Studios', 'My Studios tab should be present')) - .then(() => findByXpath('//li[@data-tab="trash"]/a')) - .then((element) => element.getText('a')) - .then((text) => t.match(text, 'Trash', 'Trash tab should be present')) - .then(() => t.end()); + .then(() => findByXpath('//div[@class="box-head"]/h2')) + .then((element) => element.getText('h2')) + .then((text) => t.equal('My Stuff', text, 'title should be My Stuff')) + .then(() => findByXpath('//li[@data-tab="projects"]/a')) + .then((element) => element.getText('a')) + .then((text) => t.match(text, 'All Projects', 'All Projects tab should be present')) + .then(() => findByXpath('//li[@data-tab="shared"]/a')) + .then((element) => element.getText('a')) + .then((text) => t.match(text, 'Shared Projects', 'Shared Projects tab should be present')) + .then(() => findByXpath('//li[@data-tab="unshared"]/a')) + .then((element) => element.getText('a')) + .then((text) => t.match(text, 'Unshared Projects', 'Unshared Projects tab should be present')) + .then(() => findByXpath('//li[@data-tab="galleries"]/a')) + .then((element) => element.getText('a')) + .then((text) => t.match(text, 'My Studios', 'My Studios tab should be present')) + .then(() => findByXpath('//li[@data-tab="trash"]/a')) + .then((element) => element.getText('a')) + .then((text) => t.match(text, 'Trash', 'Trash tab should be present')) + .then(() => t.end()); }); test('clicking See Inside should take you to the editor', t => { clickXpath('//a[@class="mystuff-icon"]') - .then(() => findByXpath('//a[@data-control="edit"]')) - .then((element) => element.getText('span')) - .then((text) => t.equal(text, 'See inside', 'there should be a "See inside" button')) - .then(() => clickXpath('//a[@data-control="edit"]')) - .then(() => driver.getCurrentUrl()) - .then(function (u) { - var expectedUrl = '/#editor'; - t.equal(u.substr(-expectedUrl.length), expectedUrl, 'after clicking, the URL should end in #editor'); - }) - .then(() => t.end()); + .then(() => findByXpath('//a[@data-control="edit"]')) + .then((element) => element.getText('span')) + .then((text) => t.equal(text, 'See inside', 'there should be a "See inside" button')) + .then(() => clickXpath('//a[@data-control="edit"]')) + .then(() => driver.getCurrentUrl()) + .then( function (url) { + var expectedUrl = '/#editor'; + t.equal(url.substr(-expectedUrl.length), expectedUrl, 'after clicking, the URL should end in #editor'); + }) + .then(() => t.end()); }); test('clicking a project title should take you to the project page', t => { clickXpath('//a[@class="mystuff-icon"]') - .then(() => clickXpath('//a[@data-control="edit"]')) - .then(() => driver.getCurrentUrl()) - .then(function (u) { - var expectedUrlRegExp = new RegExp('/projects/.*[0-9].*/?'); - t.match(u, expectedUrlRegExp, 'after clicking, the URL should end in projects/PROJECT_ID/'); - }) - .then(() => t.end()); + .then(() => clickXpath('//a[@data-control="edit"]')) + .then(() => driver.getCurrentUrl()) + .then( function (url) { + var expectedUrlRegExp = new RegExp('/projects/.*[0-9].*/?'); + t.match(url, expectedUrlRegExp, 'after clicking, the URL should end in projects/PROJECT_ID/'); + }) + .then(() => t.end()); }); test('Add To button should bring up a list of studios', t => { clickXpath('//a[@class="mystuff-icon"]') - .then(() => findByXpath('//div[@data-control="add-to"]')) - .then((element) => element.getText('span')) - .then((text) => t.equal(text, 'Add to', 'there should be an "Add to" button')) - .then(() => clickXpath('//div[@data-control="add-to"]')) - .then(() => findByXpath('//div[@class="dropdown-menu"]/ul/li')) - .then((element) => element.getText('span')) - .then(function (text) { - var expectedRegExp = new RegExp('.+'); - t.match(text, expectedRegExp, 'the dropdown menu should have at least 1 text item in it'); - }) - .then(() => t.end()); + .then(() => findByXpath('//div[@data-control="add-to"]')) + .then((element) => element.getText('span')) + .then((text) => t.equal(text, 'Add to', 'there should be an "Add to" button')) + .then(() => clickXpath('//div[@data-control="add-to"]')) + .then(() => findByXpath('//div[@class="dropdown-menu"]/ul/li')) + .then((element) => element.getText('span')) + .then( function (text) { + var expectedRegExp = new RegExp('.+'); + t.match(text, expectedRegExp, 'the dropdown menu should have at least 1 text item in it'); + }) + .then(() => t.end()); }); test('+ New Studio button should take you to the studio page', t => { clickXpath('//a[@class="mystuff-icon"]') - .then(() => clickXpath('//form[@id="new_studio"]/button[@type="submit"]')) - .then(() => findByXpath('//div[@id="show-add-project"]')) - .then((element) => element.getText('span')) - .then((text) => t.equal(text, 'Add projects', 'there should be an "Add projects" button')) - .then(() => driver.getCurrentUrl()) - .then(function (u) { - var expectedUrlRegExp = new RegExp('/studios/.*[0-9].*/?'); - t.match(u, expectedUrlRegExp, - 'after clicking the + New Studio, the URL should end in studios/STUDIO_ID'); - }) - .then(() => t.end()); + .then(() => clickXpath('//form[@id="new_studio"]/button[@type="submit"]')) + .then(() => findByXpath('//div[@id="show-add-project"]')) + .then((element) => element.getText('span')) + .then((text) => t.equal(text, 'Add projects', 'there should be an "Add projects" button')) + .then(() => driver.getCurrentUrl()) + .then( function (url) { + var expectedUrlRegExp = new RegExp('/studios/.*[0-9].*/?'); + t.match(url, expectedUrlRegExp, + 'after clicking the + New Studio, the URL should end in studios/STUDIO_ID'); + }) + .then(() => t.end()); }); test('+ New Project button should open the editor', t => { clickXpath('//a[@class="mystuff-icon"]') - .then(() => clickText('+ New Project')) - .then(() => driver.getCurrentUrl()) - .then(function (u) { - var expectedUrlRegExp = new RegExp('/projects/editor'); - t.match(u, expectedUrlRegExp, - 'after clicking, the URL should end in projects/editor'); - }) - .then(() => t.end()); + .then(() => clickText('+ New Project')) + .then(() => driver.getCurrentUrl()) + .then( function (url) { + var expectedUrlRegExp = new RegExp('/projects/editor'); + t.match(url, expectedUrlRegExp, + 'after clicking, the URL should end in projects/editor'); + }) + .then(() => t.end()); }); diff --git a/test/integration/smoke-testing/test_signing_in_and_out_discuss.js b/test/integration/smoke-testing/test_signing_in_and_out_discuss.js index 030c12040..65d48c64b 100644 --- a/test/integration/smoke-testing/test_signing_in_and_out_discuss.js +++ b/test/integration/smoke-testing/test_signing_in_and_out_discuss.js @@ -36,24 +36,24 @@ tap.beforeEach(function () { test('Sign in to Scratch using scratchr2 navbar', t => { clickText('Sign in') - .then(() => findByXpath('//input[@id="login_dropdown_username"]')) - .then((element) => element.sendKeys(username)) - .then(() => findByXpath('//input[@name="password"]')) - .then((element) => element.sendKeys(password)) - .then(() => clickButton('Sign in')) - .then(() => findByXpath('//li[contains(@class, "logged-in-user")' + - 'and contains(@class, "dropdown")]/span')) - .then((element) => element.getText('span')) - .then((text) => t.match(text.toLowerCase(), username.substring(0, 10).toLowerCase(), + .then(() => findByXpath('//input[@id="login_dropdown_username"]')) + .then((element) => element.sendKeys(username)) + .then(() => findByXpath('//input[@name="password"]')) + .then((element) => element.sendKeys(password)) + .then(() => clickButton('Sign in')) + .then(() => findByXpath('//li[contains(@class, "logged-in-user")' + + 'and contains(@class, "dropdown")]/span')) + .then((element) => element.getText('span')) + .then((text) => t.match(text.toLowerCase(), username.substring(0,10).toLowerCase(), 'first part of username should be displayed in navbar')) - .then(() => t.end()); + .then(() => t.end()); }); test('Sign out of Scratch using scratchr2 navbar', t => { - clickXpath('//span[contains(@class, "user-name")' + - ' and contains(@class, "dropdown-toggle")]/img[@class="user-icon"]') - .then(() => clickXpath('//input[@value="Sign out"]')) - .then(() => findText('Sign in')) - .then((element) => t.ok(element, 'Sign in reappeared on the page after signing out')) - .then(() => t.end()); + clickXpath('//span[contains(@class, "user-name")' + + ' and contains(@class, "dropdown-toggle")]/img[@class="user-icon"]') + .then(() => clickXpath('//input[@value="Sign out"]')) + .then(() => findText('Sign in')) + .then((element) => t.ok(element, 'Sign in reappeared on the page after signing out')) + .then(() => t.end()); }); diff --git a/test/integration/smoke-testing/test_signing_in_and_out_homepage.js b/test/integration/smoke-testing/test_signing_in_and_out_homepage.js index 29bdf5dae..43775dee2 100644 --- a/test/integration/smoke-testing/test_signing_in_and_out_homepage.js +++ b/test/integration/smoke-testing/test_signing_in_and_out_homepage.js @@ -33,23 +33,26 @@ tap.beforeEach(function () { test('Sign in to Scratch using scratch-www navbar', t => { clickText('Sign in') - .then(() => findByXpath('//input[@id="frc-username-1088"]')) - .then((element) => element.sendKeys(username)) - .then(() => findByXpath('//input[@id="frc-password-1088"]')) - .then((element) => element.sendKeys(password)) - .then(() => clickXpath('//button[contains(@class, "button") and ' + - 'contains(@class, "submit-button") and contains(@class, "white")]')) - .then(() => findByXpath('//span[@class="profile-name"]')) - .then((element) => element.getText()) - .then((text) => t.match(text.toLowerCase(), username.substring(0, 10).toLowerCase(), + .then(() => findByXpath('//input[@id="frc-username-1088"]')) + .then((element) => element.sendKeys(username)) + .then(() => findByXpath('//input[@id="frc-password-1088"]')) + .then((element) => element.sendKeys(password)) + .then(() => clickXpath('//button[contains(@class, "button") and ' + + 'contains(@class, "submit-button") and contains(@class, "white")]')) + .then(() => findByXpath('//span[@class="profile-name"]')) + .then((element) => element.getText()) + .then((text) => t.match(text.toLowerCase(), username.substring(0,10).toLowerCase(), 'first part of username should be displayed in navbar')) - .then(() => t.end()); + .then(() => t.end()); }); test('Sign out of Scratch using scratch-www navbar', t => { clickXpath('//a[@class="user-info"]') - .then(() => clickText('Sign out')) - .then(() => findText('Sign in')) - .then((element) => t.ok(element, 'Sign in reappeared on the page after signing out')) - .then(() => t.end()); + .then(() => clickText('Sign out')) + .then(() => findText('Sign in')) + .then((element) => t.ok(element, 'Sign in reappeared on the page after signing out')) + .then(() => t.end()); }); + + + diff --git a/test/integration/smoke-testing/test_statistics_page.js b/test/integration/smoke-testing/test_statistics_page.js index 15c044e27..1d636e352 100644 --- a/test/integration/smoke-testing/test_statistics_page.js +++ b/test/integration/smoke-testing/test_statistics_page.js @@ -37,28 +37,24 @@ tap.beforeEach(function () { test('check that Monthly Activity Trends title is present & correct', t => { var chartTitle = 'Monthly Activity Trends'; findByCss('div.box-head h3') - .then((element) => element.getText('h3')) - .then((text) => t.equal(text, chartTitle, 'chart title should be Monthly Activity Trends')) - .then(() => t.end()); + .then((element) => element.getText('h3')) + .then((text) => t.equal(text, chartTitle, 'chart title should be Monthly Activity Trends')) + .then(() => t.end()); }); test('check that Monthly Activity Trends chart > New Projects label is toggleable', t => { - var classXpath = `(//div[@id="activity_chart"]/*[name()='svg']/*[name()='g']/*[name()='g']/*` + - `[name()='g'])[4]/*[name()='g']/*[name()='g']/*[name()='g']`; + var classXpath = `(//div[@id="activity_chart"]/*[name()='svg']/*[name()='g']/*[name()='g']/*` + + `[name()='g'])[4]/*[name()='g']/*[name()='g']/*[name()='g']`; findByXpath(classXpath) - .then((element) => element.getAttribute('class')) - .then((classtext) => t.equal(classtext, 'nv-series', 'by default, New Projects should be enabled')) - .then(() => clickText('New Projects')) - .then(() => findByXpath(classXpath)) - .then((element) => element.getAttribute('class')) - .then((classtext) => t.equal( - classtext, - 'nv-series nv-disabled', - 'when clicked, New Projects should be disabled' - )) - .then(() => clickText('New Projects')) - .then(() => findByXpath(classXpath)) - .then((element) => element.getAttribute('class')) - .then((classtext) => t.equal(classtext, 'nv-series', 'when clicked again, New Projects should be enabled')) - .then(() => t.end()); + .then((element) => element.getAttribute('class')) + .then((classtext) => t.equal(classtext, 'nv-series', 'by default, New Projects should be enabled')) + .then(() => clickText('New Projects')) + .then(() => findByXpath(classXpath)) + .then((element) => element.getAttribute('class')) + .then((classtext) => t.equal(classtext, 'nv-series nv-disabled', 'when clicked, New Projects should be disabled')) + .then(() => clickText('New Projects')) + .then(() => findByXpath(classXpath)) + .then((element) => element.getAttribute('class')) + .then((classtext) => t.equal(classtext, 'nv-series', 'when clicked again, New Projects should be enabled')) + .then(() => t.end()); }); diff --git a/test/integration/teacher-registration/teacher_registration_utils.js b/test/integration/teacher-registration/teacher_registration_utils.js index dfc828f68..424ca4319 100644 --- a/test/integration/teacher-registration/teacher_registration_utils.js +++ b/test/integration/teacher-registration/teacher_registration_utils.js @@ -1,11 +1,11 @@ module.exports.constants = { - nextStepXpath: '//button[span[contains(text(), "Next Step")]]', - generalErrorMessageXpath: '//span[@class="help-block validation-message"]/span[contains(text(),' + - '"This field is required")]', - loremIpsumTextLong: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur viverra' + - 'nec mauris efficitur tincidunt. Vestibulum ut diam odio. Cum sociis natoque penatibus et magnis dis' + - 'parturient montes, nascetur ridiculus mus. Morbi non enim dolor. Vestibulum at enim vestibulum, ullamcorper' + - 'Duis eget quam pharetra, ultricies est eu, pharetra nisi. In tempor cursus nisi, non sagittis quam gravida.' + 'nextStepXpath': '//button[span[contains(text(), "Next Step")]]', + 'generalErrorMessageXpath': '//span[@class="help-block validation-message"]/span[contains(text(),' + + '"This field is required")]', + 'loremIpsumTextLong': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur viverra' + + 'nec mauris efficitur tincidunt. Vestibulum ut diam odio. Cum sociis natoque penatibus et magnis dis' + + 'parturient montes, nascetur ridiculus mus. Morbi non enim dolor. Vestibulum at enim vestibulum, ullamcorper' + + 'Duis eget quam pharetra, ultricies est eu, pharetra nisi. In tempor cursus nisi, non sagittis quam gravida.' }; module.exports.fillUsernameSlide = function (driver, seleniumWebdriver) { @@ -14,7 +14,7 @@ module.exports.fillUsernameSlide = function (driver, seleniumWebdriver) { var usernamePromise = usernameInput.sendKeys('clipspringer'); var passwordPromise = passwordInput.sendKeys('educators'); var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(module.exports.constants.nextStepXpath)); - return Promise.all([usernamePromise, passwordPromise]).then(function () { // eslint-disable-line no-undef + return Promise.all([usernamePromise, passwordPromise]).then(function () { nextStepButton.click().then(function () { driver.wait(seleniumWebdriver.until .elementLocated(seleniumWebdriver.By.className('demographics-step'))); @@ -28,7 +28,7 @@ module.exports.fillDemographicsSlide = function (driver, seleniumWebdriver) { var selectCountry = driver.findElement(seleniumWebdriver.By.xpath('//select[@name="user.country"]' + '/option[@value="us"]')).click(); var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(module.exports.constants.nextStepXpath)); - return Promise.all([clickMaleInput, selectCountry]).then(function () { // eslint-disable-line no-undef + return Promise.all([clickMaleInput, selectCountry]).then(function () { nextStepButton.click().then(function () { driver.wait(seleniumWebdriver.until .elementLocated(seleniumWebdriver.By.className('name-step'))); @@ -40,7 +40,7 @@ module.exports.fillNameSlide = function (driver, seleniumWebdriver) { var firstNamePromise = driver.findElement(seleniumWebdriver.By.name('user.name.first')).sendKeys('first'); var lastNamePromise = driver.findElement(seleniumWebdriver.By.name('user.name.last')).sendKeys('surname'); var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(module.exports.constants.nextStepXpath)); - return Promise.all([firstNamePromise, lastNamePromise]).then(function () { // eslint-disable-line no-undef + return Promise.all([firstNamePromise, lastNamePromise]).then(function () { nextStepButton.click().then(function () { driver.wait(seleniumWebdriver.until .elementLocated(seleniumWebdriver.By.className('phone-step'))); @@ -53,8 +53,8 @@ module.exports.fillPhoneSlide = function (driver, seleniumWebdriver) { var consentCheckbox = driver.findElement(seleniumWebdriver.By.name('phoneConsent')); var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(module.exports.constants.nextStepXpath)); var phoneNumberPromise = phoneInput.sendKeys('6172535960'); - var consentPromise = consentCheckbox.click(); - return Promise.all([phoneNumberPromise, consentPromise]).then(function () { // eslint-disable-line no-undef + var consentPromise = consentCheckbox.click(); + return Promise.all([phoneNumberPromise, consentPromise]).then(function () { nextStepButton.click().then(function () { driver.wait(seleniumWebdriver.until .elementLocated(seleniumWebdriver.By.className('organization-step'))); @@ -68,15 +68,14 @@ module.exports.fillOrganizationSlide = function (driver, seleniumWebdriver) { var typeCheckbox = driver.findElement(seleniumWebdriver.By.xpath('//input[@type="checkbox" and @value="3"]')); var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(module.exports.constants.nextStepXpath)); var organizationPromise = organizationInput.sendKeys('MIT Media Lab'); - var titlePromise = titleInput.sendKeys('Software Developer'); + var titlePromise = titleInput.sendKeys('Software Developer'); var typePromise = typeCheckbox.click(); - return Promise.all([organizationPromise, titlePromise, typePromise]) // eslint-disable-line no-undef - .then(function () { - nextStepButton.click().then(function () { - driver.wait(seleniumWebdriver.until - .elementLocated(seleniumWebdriver.By.className('address-step'))); - }); + return Promise.all([organizationPromise, titlePromise, typePromise]).then(function () { + nextStepButton.click().then(function () { + driver.wait(seleniumWebdriver.until + .elementLocated(seleniumWebdriver.By.className('address-step'))); }); + }); }; module.exports.fillAddressSlide = function (driver, seleniumWebdriver) { @@ -89,11 +88,10 @@ module.exports.fillAddressSlide = function (driver, seleniumWebdriver) { var statePromise = driver.findElement(seleniumWebdriver.By.xpath('//select[@name="address.state"]' + '/option[@value="us-ma"]')).click(); var zipPromise = zipCodeInput.sendKeys('02139'); - return Promise.all([addressPromise, cityPromise, statePromise, zipPromise]) // eslint-disable-line no-undef - .then(function () { - nextStepButton.click().then(function () { - driver.wait(seleniumWebdriver.until - .elementLocated(seleniumWebdriver.By.className('usescratch-step'))); - }); + return Promise.all([addressPromise, cityPromise, statePromise, zipPromise]).then(function () { + nextStepButton.click().then(function () { + driver.wait(seleniumWebdriver.until + .elementLocated(seleniumWebdriver.By.className('usescratch-step'))); }); + }); }; diff --git a/test/integration/teacher-registration/test_teacher_registration_address_step.js b/test/integration/teacher-registration/test_teacher_registration_address_step.js index 557f5155f..2a0188422 100644 --- a/test/integration/teacher-registration/test_teacher_registration_address_step.js +++ b/test/integration/teacher-registration/test_teacher_registration_address_step.js @@ -10,12 +10,11 @@ var tap = require('tap'); var utils = require('./teacher_registration_utils.js'); var constants = utils.constants; -// Set test url through environment variable +//Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'http://localhost:8333'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); tap.plan(2); @@ -26,16 +25,16 @@ tap.tearDown(function () { tap.beforeEach(function () { driver.get(rootUrl + '/educators/register'); return utils.fillUsernameSlide(driver, seleniumWebdriver) - .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillNameSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillPhoneSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillOrganizationSlide.bind(this, driver, seleniumWebdriver)); // eslint-disable-line no-invalid-this + .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillNameSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillPhoneSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillOrganizationSlide.bind(this, driver, seleniumWebdriver)); }); -// Selects Vatican City as the country, and checks that the state dropdown disappears +//Selects Vatican City as the country, and checks that the state dropdown disappears tap.test('checkStateDropdownOnlyPresentWhenNeeded', function (t) { driver.findElement(seleniumWebdriver.By.xpath('//select[@name="address.country"]' + - '/option[@value="va"]')).click() // select Vatican City as the country + '/option[@value="va"]')).click() //select Vatican City as the country .then(function () { driver.findElements(seleniumWebdriver.By.name('address.state')) .then(function (stateDropdown) { @@ -47,9 +46,9 @@ tap.test('checkStateDropdownOnlyPresentWhenNeeded', function (t) { tap.test('checkZipCodeRequired', function (t) { var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(constants.nextStepXpath)); - var errorMessageXPath = '//input[@name="address.zip"]/following-sibling::' + - 'span[@class="help-block validation-message"]/span[contains(text(),' + - '"This field is required")]'; + var errorMessageXPath = '//input[@name="address.zip"]/following-sibling::' + + 'span[@class="help-block validation-message"]/span[contains(text(),' + + '"This field is required")]'; nextStepButton.click().then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)) .then(function (validationMessages) { @@ -58,3 +57,4 @@ tap.test('checkZipCodeRequired', function (t) { }); }); }); + diff --git a/test/integration/teacher-registration/test_teacher_registration_demographics_step.js b/test/integration/teacher-registration/test_teacher_registration_demographics_step.js index cb589d137..ee176a9fb 100644 --- a/test/integration/teacher-registration/test_teacher_registration_demographics_step.js +++ b/test/integration/teacher-registration/test_teacher_registration_demographics_step.js @@ -10,12 +10,11 @@ var tap = require('tap'); var utils = require('./teacher_registration_utils.js'); var constants = utils.constants; -// Set test url through environment variable +//Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'http://localhost:8333'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); tap.plan(2); @@ -28,8 +27,8 @@ tap.beforeEach(function () { return utils.fillUsernameSlide(driver, seleniumWebdriver); }); -// if the user selects the other gender option, they must input a gender -// selects the other gender option and attempt to advance the slide +//if the user selects the other gender option, they must input a gender +//selects the other gender option and attempt to advance the slide tap.test('checkOtherGenderInput', function (t) { var otherGenderRadio = driver.findElement(seleniumWebdriver.By.xpath('//input[@value="other"' + 'and @type="radio"]')); @@ -38,24 +37,25 @@ tap.test('checkOtherGenderInput', function (t) { otherGenderRadio.click().then(function () { nextStepButton.click().then(function () { driver.findElements(seleniumWebdriver.By.xpath(constants.generalErrorMessageXpath)) - .then(function (validationMessages) { - t.equal(validationMessages.length, 1); - t.end(); - }); - }); - }); -}); - -// the user must select a gender -// tries to advance the slide without selecting a gender -tap.test('checkNoGenderInput', function (t) { - var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(constants.nextStepXpath)); - driver.findElement(seleniumWebdriver.By.xpath('//select[@name="user.country"]/option[2]')).click(); - nextStepButton.click().then(function () { - driver.findElements(seleniumWebdriver.By.xpath(constants.generalErrorMessageXpath)) .then(function (validationMessages) { t.equal(validationMessages.length, 1); t.end(); }); + }); }); }); + +//the user must select a gender +//tries to advance the slide without selecting a gender +tap.test('checkNoGenderInput', function (t) { + var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(constants.nextStepXpath)); + driver.findElement(seleniumWebdriver.By.xpath('//select[@name="user.country"]/option[2]')).click(); + nextStepButton.click().then(function () { + driver.findElements(seleniumWebdriver.By.xpath(constants.generalErrorMessageXpath)) + .then(function (validationMessages) { + t.equal(validationMessages.length, 1); + t.end(); + }); + }); +}); + diff --git a/test/integration/teacher-registration/test_teacher_registration_name_step.js b/test/integration/teacher-registration/test_teacher_registration_name_step.js index dee76448d..b30bc5ffe 100644 --- a/test/integration/teacher-registration/test_teacher_registration_name_step.js +++ b/test/integration/teacher-registration/test_teacher_registration_name_step.js @@ -10,12 +10,11 @@ var tap = require('tap'); var utils = require('./teacher_registration_utils.js'); var constants = utils.constants; -// Set test url through environment variable +//Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'http://localhost:8333'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); tap.plan(2); @@ -26,15 +25,15 @@ tap.tearDown(function () { tap.beforeEach(function () { driver.get(rootUrl + '/educators/register'); return utils.fillUsernameSlide(driver, seleniumWebdriver) - .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)); // eslint-disable-line no-invalid-this + .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)); }); -// attempts to advance the slide without inputting either name, checks that both give the correct error +//attempts to advance the slide without inputting either name, checks that both give the correct error tap.test('checkFirstNameRequired', function (t) { var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(constants.nextStepXpath)); - var errorMessageXPath = '//input[@name="user.name.first"]/following-sibling::' + - 'span[@class="help-block validation-message"]/span[contains(text(),' + - '"This field is required")]'; + var errorMessageXPath = '//input[@name="user.name.first"]/following-sibling::' + + 'span[@class="help-block validation-message"]/span[contains(text(),' + + '"This field is required")]'; nextStepButton.click().then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)) .then(function (validationMessages) { @@ -44,12 +43,12 @@ tap.test('checkFirstNameRequired', function (t) { }); }); -// attempts to advance the slide without inputting either name, checks that both give the correct error +//attempts to advance the slide without inputting either name, checks that both give the correct error tap.test('checkLastNameRequired', function (t) { var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(constants.nextStepXpath)); - var errorMessageXPath = '//input[@name="user.name.last"]/following-sibling::' + - 'span[@class="help-block validation-message"]/span[contains(text(),' + - '"This field is required")]'; + var errorMessageXPath = '//input[@name="user.name.last"]/following-sibling::' + + 'span[@class="help-block validation-message"]/span[contains(text(),' + + '"This field is required")]'; nextStepButton.click().then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)) .then(function (validationMessages) { @@ -58,3 +57,4 @@ tap.test('checkLastNameRequired', function (t) { }); }); }); + diff --git a/test/integration/teacher-registration/test_teacher_registration_organization_step.js b/test/integration/teacher-registration/test_teacher_registration_organization_step.js index 6a136ecea..ba98e5baa 100644 --- a/test/integration/teacher-registration/test_teacher_registration_organization_step.js +++ b/test/integration/teacher-registration/test_teacher_registration_organization_step.js @@ -10,12 +10,11 @@ var tap = require('tap'); var utils = require('./teacher_registration_utils.js'); var constants = utils.constants; -// Set test url through environment variable +//Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'http://localhost:8333'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); tap.plan(4); @@ -26,9 +25,9 @@ tap.tearDown(function () { tap.beforeEach(function () { driver.get(rootUrl + '/educators/register'); return utils.fillUsernameSlide(driver, seleniumWebdriver) - .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillNameSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillPhoneSlide.bind(this, driver, seleniumWebdriver)); // eslint-disable-line no-invalid-this + .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillNameSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillPhoneSlide.bind(this, driver, seleniumWebdriver)); }); tap.test('otherFieldRequiredIfChecked', function (t) { @@ -48,9 +47,9 @@ tap.test('otherFieldRequiredIfChecked', function (t) { tap.test('checkOrganizationFieldRequired', function (t) { var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(constants.nextStepXpath)); - var errorMessageXPath = '//input[@name="organization.name"]/following-sibling::' + - 'span[@class="help-block validation-message"]/span[contains(text(),' + - '"This field is required")]'; + var errorMessageXPath = '//input[@name="organization.name"]/following-sibling::' + + 'span[@class="help-block validation-message"]/span[contains(text(),' + + '"This field is required")]'; nextStepButton.click().then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)) .then(function (validationMessages) { @@ -62,9 +61,9 @@ tap.test('checkOrganizationFieldRequired', function (t) { tap.test('checkRoleFieldRequired', function (t) { var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(constants.nextStepXpath)); - var errorMessageXPath = '//input[@name="organization.title"]/following-sibling::' + - 'span[@class="help-block validation-message"]/span[contains(text(),' + - '"This field is required")]'; + var errorMessageXPath = '//input[@name="organization.title"]/following-sibling::' + + 'span[@class="help-block validation-message"]/span[contains(text(),' + + '"This field is required")]'; nextStepButton.click().then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)) .then(function (validationMessages) { @@ -76,9 +75,9 @@ tap.test('checkRoleFieldRequired', function (t) { tap.test('checkOrganizationTypeRequired', function (t) { var nextStepButton = driver.findElement(seleniumWebdriver.By.xpath(constants.nextStepXpath)); - var errorMessageXPath = '//div[@class="checkbox"]/following-sibling::' + - 'span[@class="help-block validation-message" and contains(text(),' + - '"This field is required")]'; + var errorMessageXPath = '//div[@class="checkbox"]/following-sibling::' + + 'span[@class="help-block validation-message" and contains(text(),' + + '"This field is required")]'; nextStepButton.click().then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)) .then(function (validationMessages) { diff --git a/test/integration/teacher-registration/test_teacher_registration_phone_step.js b/test/integration/teacher-registration/test_teacher_registration_phone_step.js index ec3feaac9..2456567ac 100644 --- a/test/integration/teacher-registration/test_teacher_registration_phone_step.js +++ b/test/integration/teacher-registration/test_teacher_registration_phone_step.js @@ -9,12 +9,11 @@ var tap = require('tap'); var utils = require('./teacher_registration_utils.js'); -// Set test url through environment variable +//Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'http://localhost:8333'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); tap.plan(1); @@ -25,16 +24,16 @@ tap.tearDown(function () { tap.beforeEach(function () { driver.get(rootUrl + '/educators/register'); return utils.fillUsernameSlide(driver, seleniumWebdriver) - .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillNameSlide.bind(this, driver, seleniumWebdriver)); // eslint-disable-line no-invalid-this + .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillNameSlide.bind(this, driver, seleniumWebdriver)); }); -// inputs an invalid phone number and checks that the correct error message appears +//inputs an invalid phone number and checks that the correct error message appears tap.test('validatePhoneNumber', function (t) { var phoneInput = driver.findElement(seleniumWebdriver.By.xpath('//input[@type="tel"]')); var errorMessage = 'Please enter a valid phone number'; - var errorMessageXPath = '//span[@class="help-block validation-message"]/span[contains(text(),"' + - errorMessage + '")]'; + var errorMessageXPath = '//span[@class="help-block validation-message"]/span[contains(text(),"' + + errorMessage + '")]'; phoneInput.sendKeys(1234567890).then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)) .then(function (validationMessages) { @@ -43,3 +42,4 @@ tap.test('validatePhoneNumber', function (t) { }); }); }); + diff --git a/test/integration/teacher-registration/test_teacher_registration_username_step.js b/test/integration/teacher-registration/test_teacher_registration_username_step.js index 96c8d46ea..f8fb7e9a8 100644 --- a/test/integration/teacher-registration/test_teacher_registration_username_step.js +++ b/test/integration/teacher-registration/test_teacher_registration_username_step.js @@ -8,12 +8,11 @@ require('chromedriver'); var seleniumWebdriver = require('selenium-webdriver'); var tap = require('tap'); -// Set test url through environment variable +//Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'http://localhost:8333'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); tap.plan(5); @@ -25,15 +24,15 @@ tap.beforeEach(function () { return driver.get(rootUrl + '/educators/register'); }); -// an error message should appear for a username less than 3 characters long -// input a username less than 3 characters and look for the validation message +//an error message should appear for a username less than 3 characters long +//input a username less than 3 characters and look for the validation message tap.test('checkAtLeastThreeCharacters', function (t) { - // open scratch in a new instance of the browser + //open scratch in a new instance of the browser driver.get('https://scratch.mit.edu/educators/register'); var usernameInput = driver.findElement(seleniumWebdriver.By.name('user.username')); var errorMessage = 'Usernames must be at least 3 characters'; - var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + - errorMessage + '")]'; + var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + + errorMessage + '")]'; usernameInput.sendKeys('hi').then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)).then(function (validationMessages) { t.equal(validationMessages.length, 1); @@ -42,31 +41,31 @@ tap.test('checkAtLeastThreeCharacters', function (t) { }); }); -// usernames have to be unique -// input a username that exists and check that an error message appears +//usernames have to be unique +//input a username that exists and check that an error message appears tap.test('checkUsernameExistsError', function (t) { var usernameInput = driver.findElement(seleniumWebdriver.By.name('user.username')); var passwordInput = driver.findElement(seleniumWebdriver.By.name('user.password')); var inputUsername = usernameInput.sendKeys('mres'); var passwordClick = passwordInput.click(); var errorMessage = 'Sorry, that username already exists'; - var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + - errorMessage + '")]'; - Promise.all([inputUsername, passwordClick]).then(function () { // eslint-disable-line no-undef - var errorBubble = driver.wait(seleniumWebdriver.until - .elementLocated(seleniumWebdriver.By.xpath(errorMessageXPath)), 10000); - t.notEqual(errorBubble, undefined); // eslint-disable-line no-undefined + var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + + errorMessage + '")]'; + Promise.all([inputUsername, passwordClick]).then(function () { + var errorBubble = driver.wait(seleniumWebdriver.until. + elementLocated(seleniumWebdriver.By.xpath(errorMessageXPath)), 10000); + t.notEqual(errorBubble, undefined); t.end(); }); }); -// passwords must be at least 6 characters -// find the validation message if the input password is less than 6 characters +//passwords must be at least 6 characters +//find the validation message if the input password is less than 6 characters tap.test('checkPasswordAtLeastSixCharacters', function (t) { var passwordInput = driver.findElement(seleniumWebdriver.By.name('user.password')); var errorMessage = 'Passwords must be at least six characters'; - var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + - errorMessage + '")]'; + var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + + errorMessage + '")]'; passwordInput.sendKeys('hello').then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)).then(function (validationMessages) { t.equal(validationMessages.length, 1); @@ -75,15 +74,15 @@ tap.test('checkPasswordAtLeastSixCharacters', function (t) { }); }); -// password cannot be "password" -// find the validation message if the user inputs "password" +//password cannot be "password" +//find the validation message if the user inputs "password" tap.test('checkPasswordNotPassword', function (t) { driver.get('https://scratch.mit.edu/educators/register'); var passwordInput = driver.findElement(seleniumWebdriver.By.name('user.password')); - // keeping "password" in messed with the xPath, may need to find a better way + //keeping "password" in messed with the xPath, may need to find a better way var errorMessage = 'Your password may not be'; - var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + - errorMessage + '")]'; + var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + + errorMessage + '")]'; passwordInput.sendKeys('password').then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)).then(function (validationMessages) { t.equal(validationMessages.length, 1); @@ -92,23 +91,24 @@ tap.test('checkPasswordNotPassword', function (t) { }); }); -// the username and password cannot be the same -// find the validation message if the username and password match +//the username and password cannot be the same +//find the validation message if the username and password match tap.test('checkPasswordNotUsername', function (t) { driver.get('https://scratch.mit.edu/educators/register'); var passwordInput = driver.findElement(seleniumWebdriver.By.name('user.password')); var usernameInput = driver.findElement(seleniumWebdriver.By.name('user.username')); var errorMessage = 'Your password may not be your username'; - var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + - errorMessage + '")]'; + var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + + errorMessage + '")]'; var usernamePromise = usernameInput.sendKeys('educator'); var passwordPromise = passwordInput.sendKeys('educator'); - // wait for both inputs to have the same text, and check for validation message - Promise.all([usernamePromise, passwordPromise]).then(function () { // eslint-disable-line no-undef + //wait for both inputs to have the same text, and check for validation message + Promise.all([usernamePromise, passwordPromise]).then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)).then(function (validationMessages) { - // there should be only one validation message + //there should be only one validation message t.equal(validationMessages.length, 1); t.end(); }); }); }); + diff --git a/test/integration/teacher-registration/test_teacher_registration_usescratch_step.js b/test/integration/teacher-registration/test_teacher_registration_usescratch_step.js index f91baf590..97235697c 100644 --- a/test/integration/teacher-registration/test_teacher_registration_usescratch_step.js +++ b/test/integration/teacher-registration/test_teacher_registration_usescratch_step.js @@ -10,12 +10,11 @@ var tap = require('tap'); var utils = require('./teacher_registration_utils.js'); var constants = utils.constants; -// Set test url through environment variable +//Set test url through environment variable var rootUrl = process.env.ROOT_URL || 'http://localhost:8333'; -// chrome driver -var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()) - .build(); +//chrome driver +var driver = new seleniumWebdriver.Builder().withCapabilities(seleniumWebdriver.Capabilities.chrome()).build(); tap.plan(3); @@ -26,11 +25,11 @@ tap.tearDown(function () { tap.beforeEach(function () { driver.get(rootUrl + '/educators/register'); return utils.fillUsernameSlide(driver, seleniumWebdriver) - .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillNameSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillPhoneSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillOrganizationSlide.bind(this, driver, seleniumWebdriver)) // eslint-disable-line no-invalid-this - .then(utils.fillAddressSlide.bind(this, driver, seleniumWebdriver)); // eslint-disable-line no-invalid-this + .then(utils.fillDemographicsSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillNameSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillPhoneSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillOrganizationSlide.bind(this, driver, seleniumWebdriver)) + .then(utils.fillAddressSlide.bind(this, driver, seleniumWebdriver)); }); tap.test('checkCharacterCountIsCorrect', function (t) { @@ -44,8 +43,8 @@ tap.test('checkCharacterCountIsCorrect', function (t) { }); }); -// Inputs more than 300 characters and checks that the char count gets the class 'overmax' -// which turns the text orange +//Inputs more than 300 characters and checks that the char count gets the class 'overmax' +//which turns the text orange tap.test('checkCharacterCountTurnsOrangeWhenTooLong', function (t) { var textarea = driver.findElement(seleniumWebdriver.By.name('useScratch')); var charCount = driver.findElement(seleniumWebdriver.By.xpath('//p[@class="char-count"]')); @@ -60,8 +59,8 @@ tap.test('checkCharacterCountTurnsOrangeWhenTooLong', function (t) { tap.test('checkCharacterCountErrorAppersWhenTooLong', function (t) { var textarea = driver.findElement(seleniumWebdriver.By.name('useScratch')); var errorMessage = 'Description must be at most 300 characters'; - var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + - errorMessage + '")]'; + var errorMessageXPath = '//span[@class="help-block validation-message" and contains(text(),"' + + errorMessage + '")]'; textarea.sendKeys(constants.loremIpsumTextLong).then(function () { driver.findElements(seleniumWebdriver.By.xpath(errorMessageXPath)).then(function (validationMessages) { t.equal(validationMessages.length, 1); diff --git a/test/localization/check_duplicate_strings.js b/test/localization/check_duplicate_strings.js index 16f7ab71c..8b46cbe27 100644 --- a/test/localization/check_duplicate_strings.js +++ b/test/localization/check_duplicate_strings.js @@ -7,23 +7,23 @@ var tap = require('tap'); var routes = require('../../src/routes.json'); -const noDuplicateValues = (idsToCheck, name) => { - let values = {}; - for (const key in idsToCheck) { +function noDuplicateValues (idsToCheck, name) { + var values = {}; + for (var key in idsToCheck) { if (values.hasOwnProperty(idsToCheck[key])) { // duplicate values - // return false; - tap.fail(`${name}.${idsToCheck[key]} has duplicates`); + //return false; + tap.fail(name + '.' + idsToCheck[key] + ' has duplicates'); } else { values[idsToCheck[key]] = key; } } tap.pass(); - // return true; -}; + //return true; +} tap.test('generalCheckForDuplicates', function (t) { - const ids = require(path.resolve(__dirname, '../../src/l10n.json')); // eslint-disable-line global-require + var ids = require(path.resolve(__dirname, '../../src/l10n.json')); noDuplicateValues(ids, 'general'); t.end(); }); @@ -35,11 +35,11 @@ for (var v in routes) { var subdir = routes[v].view.split('/'); subdir.pop(); var name = routes[v].name; - var uri = path.resolve(__dirname, '../../src/views/' + subdir.join('/') + '/l10n.json'); + var uri = path.resolve(__dirname, '../../src/views/' + subdir.join('/') +'/l10n.json'); try { var file = fs.readFileSync(uri, 'utf8'); var ids = JSON.parse(file); - tap.test(name + 'CheckForDuplicates', function (t) { // eslint-disable-line no-loop-func + tap.test(name + 'CheckForDuplicates', function (t) { noDuplicateValues(ids, name); t.end(); }); diff --git a/test/localization/check_string_ids.js b/test/localization/check_string_ids.js index 8fc019228..de4491d21 100644 --- a/test/localization/check_string_ids.js +++ b/test/localization/check_string_ids.js @@ -20,34 +20,35 @@ var tap = require('tap'); var intlDirPath = path.resolve(__dirname, '../../intl/'); var intlFiles = fs.readdirSync(intlDirPath); -/* +/** * Tells tap whether the test should pass or fail for a given file. * @param {string} fileName * @param {Object} missingMessageId * @param {Object} pagesMissingIds */ -const noMissingStrings = (fileName, missingMessageId, pagesMissingIds) => { - if (Object.keys(missingMessageId).length === 0) { +function noMissingStrings (fileName, missingMessageId, pagesMissingIds) { + if (Object.keys(missingMessageId).length == 0) { tap.pass(); - } else { + } + else { tap.fail(fileName + ' is missing string IDs'); pagesMissingIds[fileName] = []; pagesMissingIds[fileName].push(missingMessageId); } -}; +} var pagesWithLanguagesMissingIds = {}; for (var i in intlFiles) { var file = intlFiles[i]; var filePath = path.resolve(__dirname, '../../intl/' + file); - var pageMessagesString = fs.readFileSync(filePath, 'utf8'); + var pageMessagesString = fs.readFileSync(filePath,'utf8'); /** * To make the string of the file of the page.intl.js back into useable objects */ var window = {}; - var pageMessages = eval(pageMessagesString); // eslint-disable-line no-eval + var pageMessages = eval(pageMessagesString); /** * The goal is to compare the IDs for each language to the IDs for English, @@ -60,8 +61,8 @@ for (var i in intlFiles) { for (var languageKey in pageMessages) { var currentLanguageObject = pageMessages[languageKey]; for (var messageId in englishIdList) { - if (!(messageId in currentLanguageObject)) { - if (typeof messageIdNotInLanguage[languageKey] === 'undefined') { + if (! (messageId in currentLanguageObject)) { + if (typeof messageIdNotInLanguage[languageKey] == 'undefined') { messageIdNotInLanguage[languageKey] = []; } messageIdNotInLanguage[languageKey].push(messageId); diff --git a/test/localization/check_valid_json.js b/test/localization/check_valid_json.js index efe6808ac..c9cf26a46 100644 --- a/test/localization/check_valid_json.js +++ b/test/localization/check_valid_json.js @@ -5,14 +5,14 @@ var tap = require('tap'); var TRANSLATIONS_PATTERN = './node_modules/scratchr2_translations/www/**/*.json'; var files = glob.sync(TRANSLATIONS_PATTERN); -const checkJson = (data, name) => { +function checkJson (data, name) { try { JSON.parse(data); } catch (e) { tap.fail(name + ' has invalid Json.\n'); } tap.pass(); -}; +} files.forEach(function (f) { tap.test('check valid json', function (t) { diff --git a/test/unit/test_fastly_config_methods.js b/test/unit/test_fastly_config_methods.js index 81d96d11a..a75e0afd6 100644 --- a/test/unit/test_fastly_config_methods.js +++ b/test/unit/test_fastly_config_methods.js @@ -1,6 +1,6 @@ var defaults = require('lodash.defaults'); var fastlyConfig = require('../../bin/lib/fastly-config-methods'); -var routeJson = require('../../src/routes.json'); +var route_json = require('../../src/routes.json'); var tap = require('tap'); var testRoutes = [ @@ -20,7 +20,7 @@ var testRoutes = [ } ]; -var routes = routeJson.map(function (route) { +var routes = route_json.map(function (route) { return defaults({}, {pattern: fastlyConfig.expressPatternToRegex(route.pattern)}, route); }); var extraAppRoutes = [ @@ -28,7 +28,7 @@ var extraAppRoutes = [ // TODO: Should this be added for every route? '/\\?', // View html - '/[^/]*.html$' + '/[^\/]*\.html$' ]; diff --git a/webpack.config.js b/webpack.config.js index b9976df34..484be5c20 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,43 +1,36 @@ -const autoprefixer = require('autoprefixer'); -const CopyWebpackPlugin = require('copy-webpack-plugin'); -const defaults = require('lodash.defaults'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const gitsha = require('git-bundle-sha'); -const path = require('path'); -const webpack = require('webpack'); +var autoprefixer = require('autoprefixer'); +var CopyWebpackPlugin = require('copy-webpack-plugin'); +var defaults = require('lodash.defaults'); +var HtmlWebpackPlugin = require('html-webpack-plugin'); +var gitsha = require('git-bundle-sha'); +var path = require('path'); +var webpack = require('webpack'); -let routes = require('./src/routes.json'); -const templateConfig = require('./src/template-config.js'); // eslint-disable-line global-require +var routes = require('./src/routes.json'); if (process.env.NODE_ENV !== 'production') { - routes = routes.concat(require('./src/routes-dev.json')); // eslint-disable-line global-require + routes = routes.concat(require('./src/routes-dev.json')); } -let VersionPlugin = function (options) { +var VersionPlugin = function (options) { this.options = options || {}; return this; }; - VersionPlugin.prototype.apply = function (compiler) { - const addVersion = function (compilation, versionId, callback) { + var addVersion = function (compilation, versionId, callback) { compilation.assets['version.txt'] = { - source: function () { - return versionId; - }, - size: function () { - return versionId.length; - } + source: function () {return versionId;}, + size: function () {return versionId.length;} }; callback(); }; - const options = this.options; - + var plugin = this; compiler.plugin('emit', function (compilation, callback) { - const sha = process.env.WWW_VERSION; - if (!sha) { // eslint-disable-line no-negated-condition - gitsha(options, function (err, _sha) { + var sha = process.env.WWW_VERSION; + if (!sha) { + gitsha(plugin.options, function (err, sha) { if (err) return callback(err); - return addVersion(compilation, _sha, callback); + return addVersion(compilation, sha, callback); }); } else { return addVersion(compilation, sha, callback); @@ -46,7 +39,7 @@ VersionPlugin.prototype.apply = function (compiler) { }; // Prepare all entry points -let entry = { +var entry = { common: [ // Vendor 'raven-js', @@ -60,7 +53,7 @@ let entry = { }; routes.forEach(function (route) { if (!route.redirect) { - entry[route.name] = `./src/views/${route.view}.jsx`; + entry[route.name] = './src/views/' + route.view + '.jsx'; } }); @@ -73,45 +66,26 @@ module.exports = { filename: 'js/[name].bundle.js' }, module: { - rules: [ + loaders: [ { - test: /\.jsx?$/, - loader: 'babel-loader', - include: path.resolve(__dirname, 'src'), - options: { - presets: ['es2015', 'react'] - } + test: /\.jsx$/, + loader: 'babel', + query: { + presets: ['es2015','react'] + }, + include: path.resolve(__dirname, 'src') + }, + { + test: /\.json$/, + loader: 'json-loader' }, { test: /\.scss$/, - use: [ - 'style-loader', - 'css-loader', - { - loader: 'postcss-loader', - options: { - plugins: function () { - return [autoprefixer({browsers: ['last 3 versions', 'Safari >= 8', 'iOS >= 8']})]; - } - } - }, - 'sass-loader' - ] + loader: 'style!css!postcss-loader!sass' }, { test: /\.css$/, - use: [ - 'style-loader', - 'css-loader', - { - loader: 'postcss-loader', - options: { - plugins: function () { - return [autoprefixer({browsers: ['last 3 versions', 'Safari >= 8', 'iOS >= 8']})]; - } - } - } - ] + loader: 'style!css!postcss-loader' }, { test: /\.(png|jpg|gif|eot|svg|ttf|woff)$/, @@ -120,21 +94,22 @@ module.exports = { ], noParse: /node_modules\/google-libphonenumber\/dist/ }, + postcss: function () { + return [autoprefixer({browsers: ['last 3 versions', 'Safari >= 8', 'iOS >= 8']})]; + }, node: { fs: 'empty' }, plugins: [ new VersionPlugin({length: 5}) ].concat(routes - .filter(function (route) { - return !route.redirect; - }) + .filter(function (route) {return !route.redirect;}) .map(function (route) { return new HtmlWebpackPlugin(defaults({}, { title: route.title, filename: route.name + '.html', route: route - }, templateConfig)); + }, require('./src/template-config.js'))); }) ).concat([ new CopyWebpackPlugin([ @@ -142,17 +117,17 @@ module.exports = { {from: 'intl', to: 'js'} ]), new webpack.optimize.UglifyJsPlugin({ - sourceMap: true + compress: { + warnings: false + } }), new webpack.DefinePlugin({ 'process.env.NODE_ENV': '"' + (process.env.NODE_ENV || 'development') + '"', 'process.env.SENTRY_DSN': '"' + (process.env.SENTRY_DSN || '') + '"', 'process.env.API_HOST': '"' + (process.env.API_HOST || 'https://api.scratch.mit.edu') + '"', - 'process.env.SCRATCH_ENV': '"' + (process.env.SCRATCH_ENV || 'development') + '"' + 'process.env.SCRATCH_ENV': '"'+ (process.env.SCRATCH_ENV || 'development') + '"' }), - new webpack.optimize.CommonsChunkPlugin({ - name: 'common', - filename: 'js/common.bundle.js' - }) + new webpack.optimize.CommonsChunkPlugin('common', 'js/common.bundle.js'), + new webpack.optimize.OccurenceOrderPlugin() ]) }; From 590f505a6178a19a0d40b839ec7a0b0c3ff321e1 Mon Sep 17 00:00:00 2001 From: Ray Schamp Date: Tue, 30 Jan 2018 11:53:12 -0500 Subject: [PATCH 2/4] Revert "Merge pull request #1788 from LLK/revert-1775-hotfix/es6-upgrade" This reverts commit 1b1b396e929c3684af5a17687280109843dfdae5, reversing changes made to a144bab0e60f4ab50a911a295313a284417b155d. --- .babelrc | 3 + .eslintrc | 29 - .eslintrc.js | 3 + .tx/config | 6 + Makefile | 2 +- bin/configure-fastly.js | 47 +- bin/lib/fastly-config-methods.js | 10 +- bin/lib/fastly-extended.js | 52 +- dev-server/handler.js | 12 +- package.json | 45 +- src/.eslintrc.js | 10 + src/components/accordion/accordion.jsx | 56 +- src/components/adminpanel/adminpanel.jsx | 96 +- src/components/avatar/avatar.jsx | 39 +- src/components/box/box.jsx | 66 +- src/components/card/card.jsx | 25 +- src/components/carousel/carousel.jsx | 174 +- src/components/carousel/legacy-carousel.jsx | 175 +- src/components/comment/comment.jsx | 55 +- src/components/deck/deck.jsx | 41 +- src/components/dropdown-banner/banner.jsx | 52 +- src/components/dropdown/dropdown.jsx | 62 +- src/components/dropdown/dropdown.scss | 8 +- src/components/emoji-text/emoji-text.jsx | 48 +- src/components/flex-row/flex-row.jsx | 38 +- .../footer/conference/2016/footer.jsx | 247 +- .../footer/conference/2017/footer.jsx | 170 +- .../footer/conference/2018/footer.jsx | 216 +- src/components/footer/container/footer.jsx | 22 +- src/components/footer/www/footer.jsx | 429 ++- src/components/forms/button.jsx | 38 +- src/components/forms/charcount.jsx | 46 +- src/components/forms/checkbox-group.jsx | 38 +- src/components/forms/checkbox.jsx | 34 +- src/components/forms/form.jsx | 72 +- src/components/forms/general-error.jsx | 30 +- src/components/forms/input-hoc.jsx | 44 +- src/components/forms/input.jsx | 69 +- src/components/forms/phone-input.jsx | 71 +- src/components/forms/radio-group.jsx | 34 +- src/components/forms/select.jsx | 50 +- src/components/forms/textarea.jsx | 38 +- src/components/forms/validations.jsx | 62 +- src/components/grid/grid.jsx | 133 +- .../informationpage/informationpage.jsx | 55 +- src/components/intro/intro.jsx | 196 +- .../languagechooser/languagechooser.jsx | 73 +- src/components/login/login.jsx | 110 +- src/components/masonrygrid/masonrygrid.jsx | 82 +- src/components/microworld/microworld.jsx | 257 +- src/components/modal/base/modal.jsx | 74 +- src/components/modal/base/modal.scss | 2 +- src/components/modal/iframe/modal.jsx | 50 +- src/components/modal/ttt/modal.jsx | 241 +- src/components/navigation/base/navigation.jsx | 29 +- .../navigation/conference/2016/navigation.jsx | 77 +- .../navigation/conference/2017/navigation.jsx | 44 +- .../navigation/conference/2018/navigation.jsx | 44 +- src/components/navigation/www/navigation.jsx | 468 +-- .../nestedcarousel/nestedcarousel.jsx | 123 +- src/components/news/news.jsx | 91 +- src/components/page/conference/2016/page.jsx | 42 +- src/components/page/conference/2017/page.jsx | 42 +- src/components/page/conference/2018/page.jsx | 42 +- src/components/page/www/page.jsx | 52 +- src/components/progression/progression.jsx | 75 +- src/components/registration/registration.jsx | 81 +- src/components/registration/steps.jsx | 2604 ++++++++++------- src/components/slide/slide.jsx | 25 +- .../social-message/social-message.jsx | 92 +- src/components/spinner/spinner.jsx | 28 +- .../stepnavigation/stepnavigation.jsx | 47 +- .../subnavigation/subnavigation.jsx | 48 +- src/components/tabs/tabs.jsx | 38 +- .../teacher-banner/teacher-banner.jsx | 166 +- src/components/thumbnail/thumbnail.jsx | 336 +-- src/components/title-banner/title-banner.jsx | 29 +- src/components/tooltip/tooltip.jsx | 60 +- src/components/ttt-tile/ttt-tile.jsx | 104 +- src/components/welcome/welcome.jsx | 134 +- src/init.js | 18 +- src/l10n.json | 3 + src/lib/api.js | 53 +- src/lib/country-data.js | 40 +- src/lib/format.js | 34 - src/lib/frameless.js | 5 +- src/lib/intl.jsx | 12 +- src/lib/jar.js | 65 +- src/lib/log.js | 2 +- src/lib/render.jsx | 39 +- src/lib/require-all.js | 6 +- src/lib/shuffle.js | 28 +- src/lib/url-params.js | 33 +- src/redux/conference-details.js | 101 +- src/redux/conference-schedule.js | 164 +- src/redux/message-count.js | 78 +- src/redux/messages.js | 252 +- src/redux/navigation.js | 18 +- src/redux/permissions.js | 64 +- src/redux/reducer.js | 16 +- src/redux/session.js | 132 +- src/redux/splash.js | 304 +- src/views/about/about.jsx | 348 +-- src/views/camp/camp.jsx | 290 +- src/views/cards/cards.jsx | 533 ++-- .../communityblocks-interviews.jsx | 120 +- src/views/components/components.jsx | 119 +- src/views/conference/2016/details/details.jsx | 119 +- src/views/conference/2016/expect/expect.jsx | 572 ++-- src/views/conference/2016/index/index.jsx | 146 +- src/views/conference/2016/plan/plan.jsx | 59 +- .../conference/2016/schedule/schedule.jsx | 199 +- src/views/conference/2017/index/index.jsx | 1026 +++---- src/views/conference/2018/index/index.jsx | 289 +- src/views/credits/credits.jsx | 664 +++-- src/views/developers/developers.jsx | 729 ++--- src/views/dmca/dmca.jsx | 54 +- src/views/download/download.jsx | 218 +- src/views/explore/explore.jsx | 249 +- src/views/faq/faq.jsx | 424 +-- src/views/guidelines/guidelines.jsx | 77 +- src/views/jobs/jobs.jsx | 127 +- src/views/jobs/moderator/moderator.jsx | 175 +- src/views/messages/container.jsx | 191 +- .../messages/message-rows/admin-message.jsx | 70 +- .../messages/message-rows/become-manager.jsx | 84 +- .../messages/message-rows/comment-message.jsx | 297 +- .../messages/message-rows/curator-invite.jsx | 98 +- .../message-rows/favorite-project.jsx | 84 +- .../messages/message-rows/follow-user.jsx | 73 +- .../message-rows/forum-topic-post.jsx | 68 +- .../messages/message-rows/love-project.jsx | 84 +- .../messages/message-rows/remix-project.jsx | 95 +- .../message-rows/scratcher-invite.jsx | 94 +- .../messages/message-rows/studio-activity.jsx | 67 +- src/views/messages/message-rows/user-join.jsx | 72 +- src/views/messages/presentation.jsx | 619 ++-- src/views/microworld/art/art.jsx | 12 +- src/views/microworld/fashion/fashion.jsx | 12 +- src/views/microworld/hiphop/hiphop.jsx | 12 +- src/views/microworld/soccer/soccer.jsx | 12 +- .../microworldshomepage.jsx | 86 +- src/views/preview-faq/preview-faq.jsx | 50 +- src/views/privacypolicy/privacypolicy.jsx | 432 ++- src/views/search/search.jsx | 246 +- .../splash/activity-rows/become-curator.jsx | 82 +- .../splash/activity-rows/become-manager.jsx | 82 +- .../splash/activity-rows/favorite-project.jsx | 82 +- src/views/splash/activity-rows/follow.jsx | 107 +- .../splash/activity-rows/love-project.jsx | 82 +- .../splash/activity-rows/remix-project.jsx | 95 +- .../splash/activity-rows/share-project.jsx | 82 +- src/views/splash/l10n.json | 2 +- src/views/splash/presentation.jsx | 513 ++-- src/views/splash/splash.jsx | 309 +- .../studentcompleteregistration.jsx | 210 +- .../studentregistration.jsx | 199 +- .../teacherregistration.jsx | 171 +- src/views/teachers/faq/faq.jsx | 211 +- src/views/teachers/landing/landing.jsx | 275 +- .../teacherwaitingroom/teacherwaitingroom.jsx | 40 +- src/views/terms/terms.jsx | 1134 ++++--- src/views/tips/tips.jsx | 237 +- src/views/wedo2/wedo2.jsx | 265 +- test/helpers/selenium-helpers.js | 1 + .../smoke-testing/test_footer_links.js | 238 +- .../smoke-testing/test_navbar_links.js | 67 +- .../smoke-testing/test_project_rows.js | 71 +- .../test_signing_in_and_my_stuff.js | 288 +- .../test_signing_in_and_out_discuss.js | 32 +- .../test_signing_in_and_out_homepage.js | 31 +- .../smoke-testing/test_statistics_page.js | 36 +- .../teacher_registration_utils.js | 48 +- .../test_teacher_registration_address_step.js | 26 +- ..._teacher_registration_demographics_step.js | 28 +- .../test_teacher_registration_name_step.js | 26 +- ..._teacher_registration_organization_step.js | 31 +- .../test_teacher_registration_phone_step.js | 18 +- ...test_teacher_registration_username_step.js | 66 +- ...st_teacher_registration_usescratch_step.js | 25 +- test/localization/check_duplicate_strings.js | 20 +- test/localization/check_string_ids.js | 19 +- test/localization/check_valid_json.js | 4 +- test/unit/test_fastly_config_methods.js | 6 +- webpack.config.js | 113 +- 185 files changed, 13674 insertions(+), 11618 deletions(-) create mode 100644 .babelrc delete mode 100644 .eslintrc create mode 100644 .eslintrc.js create mode 100644 src/.eslintrc.js delete mode 100644 src/lib/format.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 000000000..43777946d --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["es2015", "react"], +} diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 9cadb556a..000000000 --- a/.eslintrc +++ /dev/null @@ -1,29 +0,0 @@ -{ - "parser": "babel-eslint", - "rules": { - "curly": [2, "multi-line"], - "eol-last": [2], - "indent": [2, 4], - "linebreak-style": [2, "unix"], - "max-len": [2, 120, 4, {"ignoreUrls": true}], - "no-trailing-spaces": [2, { "skipBlankLines": true }], - "no-unused-vars": [2, {"args": "after-used", "varsIgnorePattern": "^_"}], - "quotes": [2, "single"], - "semi": [2, "always"], - "space-before-function-paren": [2, "always"], - "strict": [2, "never"] - }, - "env": { - "browser": true, - "es6": true, - "node": true - }, - "globals": { - "formatMessage": true - }, - "plugins": [ - "react", - "json" - ], - "extends": "eslint:recommended" -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..36ff570d9 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['scratch', 'scratch/node'] +}; diff --git a/.tx/config b/.tx/config index 2e63e88f3..d36892ba7 100644 --- a/.tx/config +++ b/.tx/config @@ -133,3 +133,9 @@ file_filter = localizations/conference-index/.json source_file = src/views/conference/2018/index/l10n.json source_lang = en type = KEYVALUEJSON + +[scratch-website.preview-faq-l10njson] +file_filter = localizations/preview-faq/.json +source_file = src/views/preview-faq/l10n.json +source_lang = en +type = KEYVALUEJSON \ No newline at end of file diff --git a/Makefile b/Makefile index 65a57a3ac..abe7f3a72 100644 --- a/Makefile +++ b/Makefile @@ -55,7 +55,7 @@ test: @make tap lint: - $(ESLINT) . --ext .js,.jsx,.json + $(ESLINT) . --ext .js,.jsx $(SASSLINT) ./src/*.scss $(SASSLINT) ./src/**/*.scss diff --git a/bin/configure-fastly.js b/bin/configure-fastly.js index edb7196ad..a935b906e 100644 --- a/bin/configure-fastly.js +++ b/bin/configure-fastly.js @@ -3,7 +3,7 @@ var defaults = require('lodash.defaults'); var fastlyConfig = require('./lib/fastly-config-methods'); const languages = require('../languages.json'); -var route_json = require('../src/routes.json'); +var routeJson = require('../src/routes.json'); const FASTLY_SERVICE_ID = process.env.FASTLY_SERVICE_ID || ''; const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME || ''; @@ -15,10 +15,10 @@ var extraAppRoutes = [ // TODO: Should this be added for every route? '/\\?', // View html - '/[^\/]*\.html$' + '/[^/]*.html$' ]; -var routes = route_json.map(function (route) { +var routes = routeJson.map(function (route) { return defaults({}, {pattern: fastlyConfig.expressPatternToRegex(route.pattern)}, route); }); @@ -28,9 +28,9 @@ async.auto({ if (err) return cb(err); // Validate latest version before continuing if (response.active || response.locked) { - fastly.cloneVersion(response.number, function (err, response) { - if (err) return cb('Failed to clone latest version: ' + err); - cb(null, response.number); + fastly.cloneVersion(response.number, function (e, resp) { + if (e) return cb('Failed to clone latest version: ' + e); + cb(null, resp.number); }); } else { cb(null, response.number); @@ -46,11 +46,11 @@ async.auto({ var recvCondition = '' + 'if (' + notPassStatement + ') {\n' + ' set req.backend = F_s3;\n' + - ' set req.http.host = \"' + S3_BUCKET_NAME + '\";\n' + + ' set req.http.host = "' + S3_BUCKET_NAME + '";\n' + '} else {\n' + ' if (!req.http.Fastly-FF) {\n' + ' if (req.http.X-Forwarded-For) {\n' + - ' set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For \", \" client.ip;\n' + + ' set req.http.Fastly-Temp-XFF = req.http.X-Forwarded-For ", " client.ip;\n' + ' } else {\n' + ' set req.http.Fastly-Temp-XFF = client.ip;\n' + ' }\n' + @@ -171,20 +171,19 @@ async.auto({ if (err) return cb(err); cb(null, headers); }); - }]}, - function (err, results) { - if (err) throw new Error(err); - if (process.env.FASTLY_ACTIVATE_CHANGES) { - fastly.activateVersion(results.version, function (err, response) { - if (err) throw new Error(err); - process.stdout.write('Successfully configured and activated version ' + response.number + '\n'); - if (process.env.FASTLY_PURGE_ALL) { - fastly.purgeAll(FASTLY_SERVICE_ID, function (err) { - if (err) throw new Error(err); - process.stdout.write('Purged all.\n'); - }); - } - }); - } + }] +}, function (err, results) { + if (err) throw new Error(err); + if (process.env.FASTLY_ACTIVATE_CHANGES) { + fastly.activateVersion(results.version, function (e, resp) { + if (err) throw new Error(e); + process.stdout.write('Successfully configured and activated version ' + resp.number + '\n'); + if (process.env.FASTLY_PURGE_ALL) { + fastly.purgeAll(FASTLY_SERVICE_ID, function (error) { + if (error) throw new Error(error); + process.stdout.write('Purged all.\n'); + }); + } + }); } -); +}); diff --git a/bin/lib/fastly-config-methods.js b/bin/lib/fastly-config-methods.js index 750b1893b..d6a8c973d 100644 --- a/bin/lib/fastly-config-methods.js +++ b/bin/lib/fastly-config-methods.js @@ -24,9 +24,9 @@ var FastlyConfigMethods = { */ getViewPaths: function (routes) { return routes.reduce(function (paths, route) { - var path = route.routeAlias || route.pattern; - if (paths.indexOf(path) === -1) { - paths.push(path); + var p = route.routeAlias || route.pattern; + if (paths.indexOf(p) === -1) { + paths.push(p); } return paths; }, []); @@ -39,7 +39,7 @@ var FastlyConfigMethods = { * 2. /path/:arg([regex]) – :arg is removed, leaving just /path/([regex]) */ expressPatternToRegex: function (pattern) { - pattern = pattern.replace(/(:\w+)(\([^\)]+\))/gi, '$2'); + pattern = pattern.replace(/(:\w+)(\([^)]+\))/gi, '$2'); return pattern.replace(/(:\w+)/gi, '.+?'); }, @@ -84,7 +84,7 @@ var FastlyConfigMethods = { return 'redirects/' + route.pattern; }, - /** + /* * Returns custom vcl configuration as a string that sets the varnish * Time to Live (TTL) for responses that come from s3. * diff --git a/bin/lib/fastly-extended.js b/bin/lib/fastly-extended.js index 3ec9fd7e3..0e4467221 100644 --- a/bin/lib/fastly-extended.js +++ b/bin/lib/fastly-extended.js @@ -19,8 +19,8 @@ module.exports = function (apiKey, serviceId) { * * @return {string} */ - fastly.getFastlyAPIPrefix = function (serviceId, version) { - return '/service/' + encodeURIComponent(serviceId) + '/version/' + version; + fastly.getFastlyAPIPrefix = function (servId, version) { + return '/service/' + encodeURIComponent(servId) + '/version/' + version; }; /* @@ -32,15 +32,15 @@ module.exports = function (apiKey, serviceId) { if (!this.serviceId) { return cb('Failed to get latest version. No serviceId configured'); } - var url = '/service/'+ encodeURIComponent(this.serviceId) +'/version'; + var url = '/service/' + encodeURIComponent(this.serviceId) + '/version'; this.request('GET', url, function (err, versions) { if (err) { return cb('Failed to fetch versions: ' + err); } - var latestVersion = versions.reduce(function (latestVersion, version) { - if (!latestVersion) return version; - if (version.number > latestVersion.number) return version; - return latestVersion; + var latestVersion = versions.reduce(function (lateVersion, version) { + if (!lateVersion) return version; + if (version.number > lateVersion.number) return version; + return lateVersion; }); return cb(null, latestVersion); }); @@ -63,16 +63,16 @@ module.exports = function (apiKey, serviceId) { var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/condition'; return this.request('PUT', putUrl, condition, function (err, response) { if (err && err.statusCode === 404) { - this.request('POST', postUrl, condition, function (err, response) { - if (err) { - return cb('Failed while inserting condition \"' + condition.statement + '\": ' + err); + this.request('POST', postUrl, condition, function (e, resp) { + if (e) { + return cb('Failed while inserting condition "' + condition.statement + '": ' + e); } - return cb(null, response); + return cb(null, resp); }); return; } if (err) { - return cb('Failed to update condition \"' + condition.statement + '\": ' + err); + return cb('Failed to update condition "' + condition.statement + '": ' + err); } return cb(null, response); }.bind(this)); @@ -95,11 +95,11 @@ module.exports = function (apiKey, serviceId) { var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/header'; return this.request('PUT', putUrl, header, function (err, response) { if (err && err.statusCode === 404) { - this.request('POST', postUrl, header, function (err, response) { - if (err) { - return cb('Failed to insert header: ' + err); + this.request('POST', postUrl, header, function (e, resp) { + if (e) { + return cb('Failed to insert header: ' + e); } - return cb(null, response); + return cb(null, resp); }); return; } @@ -127,11 +127,11 @@ module.exports = function (apiKey, serviceId) { var postUrl = this.getFastlyAPIPrefix(this.serviceId, version) + '/response_object'; return this.request('PUT', putUrl, responseObj, function (err, response) { if (err && err.statusCode === 404) { - this.request('POST', postUrl, responseObj, function (err, response) { - if (err) { - return cb('Failed to insert response object: ' + err); + this.request('POST', postUrl, responseObj, function (e, resp) { + if (e) { + return cb('Failed to insert response object: ' + e); } - return cb(null, response); + return cb(null, resp); }); return; } @@ -166,7 +166,7 @@ module.exports = function (apiKey, serviceId) { this.request('PUT', url, cb); }; - /** + /* * Upsert a custom vcl file. Attempts a PUT, and falls back * to POST if not there already. * @@ -186,16 +186,16 @@ module.exports = function (apiKey, serviceId) { return this.request('PUT', url, content, function (err, response) { if (err && err.statusCode === 404) { content.name = name; - this.request('POST', postUrl, content, function (err, response) { - if (err) { - return cb('Failed while adding custom vcl \"' + name + '\": ' + err); + this.request('POST', postUrl, content, function (e, resp) { + if (e) { + return cb('Failed while adding custom vcl "' + name + '": ' + e); } - return cb(null, response); + return cb(null, resp); }); return; } if (err) { - return cb('Failed to update custom vcl \"' + name + '\": ' + err); + return cb('Failed to update custom vcl "' + name + '": ' + err); } return cb(null, response); }.bind(this)); diff --git a/dev-server/handler.js b/dev-server/handler.js index 43c12857d..339ceff5c 100644 --- a/dev-server/handler.js +++ b/dev-server/handler.js @@ -1,10 +1,12 @@ -/** +/* * Constructor */ -function Handler (route) { +const Handler = function (route) { // Handle redirects if (route.redirect) { - return (req, res) => { res.redirect(route.redirect); }; + return (req, res) => { + res.redirect(route.redirect); + }; } var url = '/' + route.name + '.html'; @@ -12,9 +14,9 @@ function Handler (route) { req.url = url; next(); }; -} +}; -/** +/* * Export a new instance */ module.exports = function (route) { diff --git a/package.json b/package.json index 68fec9862..9e9ec7fa4 100644 --- a/package.json +++ b/package.json @@ -33,24 +33,27 @@ "devDependencies": { "async": "1.5.2", "autoprefixer": "6.3.6", - "babel-core": "6.10.4", - "babel-eslint": "5.0.4", - "babel-loader": "6.2.4", - "babel-preset-es2015": "6.9.0", - "babel-preset-react": "6.11.1", + "babel-cli": "6.26.0", + "babel-core": "6.23.1", + "babel-eslint": "8.0.2", + "babel-loader": "7.1.0", + "babel-preset-es2015": "6.22.0", + "babel-preset-react": "6.22.0", "cheerio": "1.0.0-rc.2", - "classnames": "2.1.3", + "classnames": "2.2.5", "cookie": "0.2.2", "copy-webpack-plugin": "0.2.0", + "create-react-class": "15.6.2", "css-loader": "0.23.1", - "eslint": "1.3.1", + "eslint": "4.7.1", + "eslint-config-scratch": "5.0.0", "eslint-plugin-json": "1.2.0", - "eslint-plugin-react": "3.3.1", + "eslint-plugin-react": "7.4.0", "exenv": "1.2.0", "fastly": "1.2.1", "file-loader": "0.8.4", - "formsy-react": "0.18.0", - "formsy-react-components": "0.7.1", + "formsy-react": "0.19.5", + "formsy-react-components": "0.11.1", "git-bundle-sha": "0.0.2", "glob": "5.0.15", "google-libphonenumber": "1.0.21", @@ -59,6 +62,7 @@ "json-loader": "0.5.2", "json2po-stream": "1.0.3", "keymirror": "0.1.1", + "lodash.bindall": "4.4.0", "lodash.clone": "3.0.3", "lodash.defaultsdeep": "3.10.0", "lodash.isarray": "3.0.4", @@ -70,21 +74,22 @@ "node-sass": "4.6.1", "pako": "0.2.8", "po2icu": "0.0.2", - "postcss-loader": "0.8.2", + "postcss-loader": "2.0.10", + "prop-types": "15.6.0", "raven-js": "3.0.4", - "react": "15.1.0", - "react-dom": "15.0.1", + "react": "15.5.4", + "react-dom": "15.5.4", "react-intl": "2.1.2", - "react-modal": "1.5.2", - "react-onclickoutside": "4.1.1", + "react-modal": "3.1.11", + "react-onclickoutside": "6.7.1", "react-redux": "4.4.5", - "react-responsive": "1.1.4", + "react-responsive": "3.0.0", "react-slick": "0.12.2", - "react-telephone-input": "3.4.5", + "react-telephone-input": "3.8.6", "redux": "3.5.2", "redux-thunk": "2.0.1", "sass-lint": "1.5.1", - "sass-loader": "2.0.1", + "sass-loader": "6.0.6", "scratchr2_translations": "git://github.com/LLK/scratchr2_translations.git#master", "slick-carousel": "1.5.8", "source-map-support": "0.3.2", @@ -92,8 +97,8 @@ "tap": "7.1.2", "url-loader": "0.5.6", "watch": "0.16.0", - "webpack": "1.12.14", - "webpack-dev-middleware": "1.2.0", + "webpack": "2.7.0", + "webpack-dev-middleware": "2.0.4", "xhr": "2.2.0" }, "nyc": { diff --git a/src/.eslintrc.js b/src/.eslintrc.js new file mode 100644 index 000000000..0abd74d67 --- /dev/null +++ b/src/.eslintrc.js @@ -0,0 +1,10 @@ +module.exports = { + root: true, + extends: ['scratch', 'scratch/es6', 'scratch/react'], + env: { + browser: true + }, + globals: { + process: true + } +}; diff --git a/src/components/accordion/accordion.jsx b/src/components/accordion/accordion.jsx index e6e921a7b..431705395 100644 --- a/src/components/accordion/accordion.jsx +++ b/src/components/accordion/accordion.jsx @@ -1,33 +1,35 @@ -var classNames = require('classnames'); -var React = require('react'); +const bindAll = require('lodash.bindall'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./accordion.scss'); -var Accordion = React.createClass({ - type: 'Accordion', - getDefaultProps: function () { - return { - titleAs: 'div', - contentAs: 'div' - }; - }, - getInitialState: function () { - return { +class Accordion extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleClick' + ]); + this.state = { isOpen: false }; - }, - toggleContent: function () { + } + handleClick (e) { + e.preventDefault(); this.setState({isOpen: !this.state.isOpen}); - }, - render: function () { - var classes = classNames({ - 'content': true, - 'open': this.state.isOpen + } + render () { + const classes = classNames({ + content: true, + open: this.state.isOpen }); return (
    - + {this.props.title} @@ -36,6 +38,16 @@ var Accordion = React.createClass({
    ); } -}); +} + +Accordion.propTypes = { + content: PropTypes.node, + title: PropTypes.string +}; + +Accordion.defaultProps = { + contentAs: 'div', + titleAs: 'div' +}; module.exports = Accordion; diff --git a/src/components/adminpanel/adminpanel.jsx b/src/components/adminpanel/adminpanel.jsx index 222258176..4d9ac9e79 100644 --- a/src/components/adminpanel/adminpanel.jsx +++ b/src/components/adminpanel/adminpanel.jsx @@ -1,37 +1,39 @@ -var React = require('react'); -var connect = require('react-redux').connect; +const bindAll = require('lodash.bindall'); +const connect = require('react-redux').connect; +const PropTypes = require('prop-types'); +const React = require('react'); -var Button = require('../forms/button.jsx'); +const Button = require('../forms/button.jsx'); require('./adminpanel.scss'); -var AdminPanel = React.createClass({ - type: 'AdminPanel', - getInitialState: function () { - return { +class AdminPanel extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleToggleVisibility' + ]); + this.state = { showPanel: false }; - }, - handleToggleVisibility: function (e) { + } + handleToggleVisibility (e) { e.preventDefault(); this.setState({showPanel: !this.state.showPanel}); - }, - render: function () { - // make sure user is present before checking if they're an admin. Don't show anything if user not an admin. - var showAdmin = false; - if (this.props.session.session.user) { - showAdmin = this.props.session.session.permissions.admin; - } - - if (!showAdmin) return false; + } + render () { + if (!this.props.isAdmin) return false; if (this.state.showPanel) { return ( -
    +
    - + onClick={this.handleToggleVisibility} + > x
    @@ -44,8 +46,15 @@ var AdminPanel = React.createClass({
    • -
      - + +
      For anonymous users:
      -
    • +
    ); - } else { - return ( -
    - - - > - -
    - ); } + return ( +
    + + > + +
    + ); } -}); +} -var mapStateToProps = function (state) { - return { - session: state.session - }; +AdminPanel.propTypes = { + children: PropTypes.node, + isAdmin: PropTypes.bool }; -var ConnectedAdminPanel = connect(mapStateToProps)(AdminPanel); +const mapStateToProps = state => ({ + isAdmin: state.permissions.admin +}); + +const ConnectedAdminPanel = connect(mapStateToProps)(AdminPanel); module.exports = ConnectedAdminPanel; diff --git a/src/components/avatar/avatar.jsx b/src/components/avatar/avatar.jsx index 5830e5ffb..566b97199 100644 --- a/src/components/avatar/avatar.jsx +++ b/src/components/avatar/avatar.jsx @@ -1,23 +1,22 @@ -var React = require('react'); -var classNames = require('classnames'); +const classNames = require('classnames'); +const omit = require('lodash.omit'); +const PropTypes = require('prop-types'); +const React = require('react'); -var Avatar = React.createClass({ - type: 'Avatar', - propTypes: { - src: React.PropTypes.string - }, - getDefaultProps: function () { - return { - src: '//cdn2.scratch.mit.edu/get_image/user/2584924_24x24.png?v=1438702210.96' - }; - }, - render: function () { - var classes = classNames( - 'avatar', - this.props.className - ); - return ; - } -}); +const Avatar = props => ( + +); + +Avatar.propTypes = { + className: PropTypes.string, + src: PropTypes.string +}; + +Avatar.defaultProps = { + src: '//cdn2.scratch.mit.edu/get_image/user/2584924_24x24.png?v=1438702210.96' +}; module.exports = Avatar; diff --git a/src/components/box/box.jsx b/src/components/box/box.jsx index 543bc15a2..832e27ea4 100644 --- a/src/components/box/box.jsx +++ b/src/components/box/box.jsx @@ -1,40 +1,38 @@ -var classNames = require('classnames'); -var React = require('react'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./box.scss'); -var Box = React.createClass({ - type: 'Box', - propTypes: { - title: React.PropTypes.string.isRequired, - subtitle: React.PropTypes.string, - moreTitle: React.PropTypes.string, - moreHref: React.PropTypes.string, - moreProps: React.PropTypes.object - }, - render: function () { - var classes = classNames( - 'box', - this.props.className - ); - return ( -
    -
    -

    {this.props.title}

    -
    {this.props.subtitle}
    -

    - - {this.props.moreTitle} - -

    -
    +const Box = props => ( +
    +
    +

    {props.title}

    +
    {props.subtitle}
    +

    + + {props.moreTitle} + +

    +
    -
    - {this.props.children} -
    -
    - ); - } -}); +
    + {props.children} +
    +
    +); + +Box.propTypes = { + children: PropTypes.node, + className: PropTypes.string, + moreHref: PropTypes.string, + moreProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types + moreTitle: PropTypes.string, + subtitle: PropTypes.string, + title: PropTypes.string.isRequired +}; module.exports = Box; diff --git a/src/components/card/card.jsx b/src/components/card/card.jsx index 5ac22fae1..37f6dc13c 100644 --- a/src/components/card/card.jsx +++ b/src/components/card/card.jsx @@ -1,17 +1,18 @@ -var classNames = require('classnames'); -var React = require('react'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./card.scss'); -var Card = React.createClass({ - displayName: 'Card', - render: function () { - return ( -
    - {this.props.children} -
    - ); - } -}); +const Card = props => ( +
    + {props.children} +
    +); + +Card.propTypes = { + children: PropTypes.node, + className: PropTypes.string +}; module.exports = Card; diff --git a/src/components/carousel/carousel.jsx b/src/components/carousel/carousel.jsx index 46e01fa1a..5438d414f 100644 --- a/src/components/carousel/carousel.jsx +++ b/src/components/carousel/carousel.jsx @@ -1,95 +1,115 @@ -var classNames = require('classnames'); -var defaults = require('lodash.defaults'); -var React = require('react'); -var Slider = require('react-slick'); +const classNames = require('classnames'); +const defaults = require('lodash.defaults'); +const PropTypes = require('prop-types'); +const React = require('react'); +const Slider = require('react-slick'); -var Thumbnail = require('../thumbnail/thumbnail.jsx'); +const Thumbnail = require('../thumbnail/thumbnail.jsx'); -var frameless = require('../../lib/frameless.js'); +const frameless = require('../../lib/frameless.js'); require('slick-carousel/slick/slick.scss'); require('slick-carousel/slick/slick-theme.scss'); require('./carousel.scss'); -/** - * Displays content in horizontal scrolling box. Example usage: splash page rows. - */ -var Carousel = React.createClass({ - type: 'Carousel', - propTypes: { - items: React.PropTypes.array - }, - getDefaultProps: function () { - return { - items: require('./carousel.json'), - showRemixes: false, - showLoves: false, - type: 'project' - }; - }, - render: function () { - var settings = this.props.settings || {}; - defaults(settings, { - centerMode: false, - dots: false, - infinite: false, - lazyLoad: true, - slidesToShow: 5, - slidesToScroll: 5, - variableWidth: true, - responsive: [ - {breakpoint: frameless.mobile, settings: { +const Carousel = props => { + defaults(props.settings, { + centerMode: false, + dots: false, + infinite: false, + lazyLoad: true, + slidesToShow: 5, + slidesToScroll: 5, + variableWidth: true, + responsive: [ + { + breakpoint: frameless.mobile, + settings: { arrows: true, slidesToScroll: 1, slidesToShow: 1, centerMode: true - }}, - {breakpoint: frameless.tablet, settings: { + } + }, + { + breakpoint: frameless.tablet, + settings: { slidesToScroll: 2, slidesToShow: 2 - }}, - {breakpoint: frameless.desktop, settings: { + } + }, + { + breakpoint: frameless.desktop, + settings: { slidesToScroll: 4, slidesToShow: 4 - }} - ] - }); - var arrows = this.props.items.length > settings.slidesToShow; - var classes = classNames( - 'carousel', - this.props.className - ); - return ( - - {this.props.items.map(function (item) { - var href = ''; - switch (this.props.type) { - case 'gallery': - href = '/studios/' + item.id + '/'; - break; - case 'project': - href = '/projects/' + item.id + '/'; - break; - default: - href = '/' + item.type + '/' + item.id + '/'; - } + } + } + ] + }); + const arrows = props.items.length > props.settings.slidesToShow; + return ( + + {props.items.map(item => { + let href = ''; + switch (props.type) { + case 'gallery': + href = `/studios/${item.id}/`; + break; + case 'project': + href = `/projects/${item.id}/`; + break; + default: + href = `/${item.type}/${item.id}/`; + } - return ( - - ); - }.bind(this))} - - ); - } -}); + return ( + + ); + })} + + ); +}; + +Carousel.propTypes = { + className: PropTypes.string, + items: PropTypes.arrayOf(PropTypes.any), + settings: PropTypes.shape({ + centerMode: PropTypes.bool, + dots: PropTypes.bool, + infinite: PropTypes.bool, + lazyLoad: PropTypes.bool, + slidesToShow: PropTypes.number, + slidesToScroll: PropTypes.number, + variableWidth: PropTypes.bool, + responsive: PropTypes.array + }), + showLoves: PropTypes.bool, + showRemixes: PropTypes.bool, + type: PropTypes.string +}; + +Carousel.defaultProps = { + items: require('./carousel.json'), + settings: {}, + showRemixes: false, + showLoves: false, + type: 'project' +}; module.exports = Carousel; diff --git a/src/components/carousel/legacy-carousel.jsx b/src/components/carousel/legacy-carousel.jsx index 36efb5cbf..d5ab1dbf8 100644 --- a/src/components/carousel/legacy-carousel.jsx +++ b/src/components/carousel/legacy-carousel.jsx @@ -1,97 +1,118 @@ // This component handles json returned via proxy from a django server, // or directly from a django server, and the model structure that system // has. -var classNames = require('classnames'); -var defaults = require('lodash.defaults'); -var React = require('react'); -var Slider = require('react-slick'); +const classNames = require('classnames'); +const defaults = require('lodash.defaults'); +const PropTypes = require('prop-types'); +const React = require('react'); +const Slider = require('react-slick'); -var Thumbnail = require('../thumbnail/thumbnail.jsx'); +const Thumbnail = require('../thumbnail/thumbnail.jsx'); -var frameless = require('../../lib/frameless.js'); +const frameless = require('../../lib/frameless.js'); require('slick-carousel/slick/slick.scss'); require('slick-carousel/slick/slick-theme.scss'); require('./carousel.scss'); -/** - * Displays content in horizontal scrolling box. Example usage: splash page rows. - */ -var LegacyCarousel = React.createClass({ - type: 'LegacyCarousel', - propTypes: { - items: React.PropTypes.array - }, - getDefaultProps: function () { - return { - items: require('./carousel.json'), - showRemixes: false, - showLoves: false - }; - }, - render: function () { - var settings = this.props.settings || {}; - defaults(settings, { - centerMode: false, - dots: false, - infinite: false, - lazyLoad: true, - slidesToShow: 5, - slidesToScroll: 5, - variableWidth: true, - responsive: [ - {breakpoint: frameless.mobile, settings: { +const Carousel = props => { + defaults(props.settings, { + centerMode: false, + dots: false, + infinite: false, + lazyLoad: true, + slidesToShow: 5, + slidesToScroll: 5, + variableWidth: true, + responsive: [ + { + breakpoint: frameless.mobile, + settings: { arrows: true, slidesToScroll: 1, slidesToShow: 1, centerMode: true - }}, - {breakpoint: frameless.tablet, settings: { + } + }, + { + breakpoint: frameless.tablet, + settings: { slidesToScroll: 2, slidesToShow: 2 - }}, - {breakpoint: frameless.desktop, settings: { + } + }, + { + breakpoint: frameless.desktop, + settings: { slidesToScroll: 4, slidesToShow: 4 - }} - ] - }); - var arrows = this.props.items.length > settings.slidesToShow; - var classes = classNames( - 'carousel', - this.props.className - ); - return ( - - {this.props.items.map(function (item) { - var href = ''; - switch (item.type) { - case 'gallery': - href = '/studios/' + item.id + '/'; - break; - case 'project': - href = '/projects/' + item.id + '/'; - break; - default: - href = '/' + item.type + '/' + item.id + '/'; - } + } + } + ] + }); + const arrows = props.items.length > props.settings.slidesToShow; + return ( + + {props.items.map(item => { + let href = ''; + switch (item.type) { + case 'gallery': + href = `/studios/${item.id}/`; + break; + case 'project': + href = `/projects/${item.id}/`; + break; + default: + href = `/${item.type}/${item.id}/`; + } - return ( - - ); - }.bind(this))} - - ); - } -}); + return ( + + ); + })} + + ); +}; -module.exports = LegacyCarousel; +Carousel.propTypes = { + className: PropTypes.string, + items: PropTypes.arrayOf(PropTypes.any), + settings: PropTypes.shape({ + centerMode: PropTypes.bool, + dots: PropTypes.bool, + infinite: PropTypes.bool, + lazyLoad: PropTypes.bool, + slidesToShow: PropTypes.number, + slidesToScroll: PropTypes.number, + variableWidth: PropTypes.bool, + responsive: PropTypes.array + }), + showLoves: PropTypes.bool, + showRemixes: PropTypes.bool, + type: PropTypes.string +}; + +Carousel.defaultProps = { + items: require('./carousel.json'), + settings: {}, + showRemixes: false, + showLoves: false, + type: 'project' +}; + +module.exports = Carousel; diff --git a/src/components/comment/comment.jsx b/src/components/comment/comment.jsx index 4a324799a..5edaeb51d 100644 --- a/src/components/comment/comment.jsx +++ b/src/components/comment/comment.jsx @@ -1,34 +1,33 @@ -var classNames = require('classnames'); -var FormattedRelative = require('react-intl').FormattedRelative; -var React = require('react'); +const classNames = require('classnames'); +const FormattedRelative = require('react-intl').FormattedRelative; +const PropTypes = require('prop-types'); +const React = require('react'); -var EmojiText = require('../emoji-text/emoji-text.jsx'); +const EmojiText = require('../emoji-text/emoji-text.jsx'); require('./comment.scss'); -var CommentText = React.createClass({ - type: 'CommentText', - propTypes: { - comment: React.PropTypes.string.isRequired, - datetimeCreated: React.PropTypes.string, - className: React.PropTypes.string - }, - render: function () { - var classes = classNames( - 'comment-text', - this.props.class - ); - return ( -
    - - {typeof this.props.datetimeCreated !== 'undefined' ? [ -

    - -

    - ] : []} -
    - ); - } -}); +const CommentText = props => ( +
    + + {typeof props.datetimeCreated === 'undefined' ? [] : [ +

    + +

    + ]} +
    +); + +CommentText.propTypes = { + className: PropTypes.string, + comment: PropTypes.string.isRequired, + datetimeCreated: PropTypes.string +}; module.exports = CommentText; diff --git a/src/components/deck/deck.jsx b/src/components/deck/deck.jsx index 5d929c68a..7d150a7e8 100644 --- a/src/components/deck/deck.jsx +++ b/src/components/deck/deck.jsx @@ -1,22 +1,29 @@ -var classNames = require('classnames'); -var React = require('react'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./deck.scss'); -var Deck = React.createClass({ - displayName: 'Deck', - render: function () { - return ( -
    -
    - - - - {this.props.children} -
    -
    - ); - } -}); +const Deck = props => ( +
    +
    + + + + {props.children} +
    +
    +); + +Deck.propTypes = { + children: PropTypes.node, + className: PropTypes.string +}; module.exports = Deck; diff --git a/src/components/dropdown-banner/banner.jsx b/src/components/dropdown-banner/banner.jsx index e9808228e..fa912f49e 100644 --- a/src/components/dropdown-banner/banner.jsx +++ b/src/components/dropdown-banner/banner.jsx @@ -1,33 +1,29 @@ -var classNames = require('classnames'); -var React = require('react'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./banner.scss'); -/** - * Container for messages displayed below the nav bar that can be dismissed - * (See: email not confirmed banner) - */ -var Banner = React.createClass({ - type: 'Banner', - propTypes: { - onRequestDismiss: React.PropTypes.func - }, - render: function () { - var classes = classNames( - 'banner', - this.props.className - ); - return ( -
    -
    - {this.props.children} - {this.props.onRequestDismiss ? [ - x - ] : []} -
    -
    - ); - } -}); +const Banner = props => ( +
    +
    + {props.children} + {props.onRequestDismiss ? [ + x + ] : []} +
    +
    +); + +Banner.propTypes = { + children: PropTypes.node, + className: PropTypes.string, + onRequestDismiss: PropTypes.func +}; module.exports = Banner; diff --git a/src/components/dropdown/dropdown.jsx b/src/components/dropdown/dropdown.jsx index 83990264b..095194856 100644 --- a/src/components/dropdown/dropdown.jsx +++ b/src/components/dropdown/dropdown.jsx @@ -1,40 +1,46 @@ -var React = require('react'); -var classNames = require('classnames'); +const bindAll = require('lodash.bindall'); +const classNames = require('classnames'); +const onClickOutside = require('react-onclickoutside').default; +const PropTypes = require('prop-types'); +const React = require('react'); require('./dropdown.scss'); -var Dropdown = React.createClass({ - type: 'Dropdown', - mixins: [ - require('react-onclickoutside') - ], - propTypes: { - onRequestClose: React.PropTypes.func, - isOpen: React.PropTypes.bool - }, - getDefaultProps: function () { - return { - as: 'div', - isOpen: false - }; - }, - handleClickOutside: function () { +class Dropdown extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleClickOutside' + ]); + } + handleClickOutside () { if (this.props.isOpen) { this.props.onRequestClose(); } - }, - render: function () { - var classes = classNames( - 'dropdown', - this.props.className, - {open: this.props.isOpen} - ); + } + render () { return ( - + {this.props.children} ); } -}); +} -module.exports = Dropdown; +Dropdown.propTypes = { + children: PropTypes.node, + className: PropTypes.string, + isOpen: PropTypes.bool, + onRequestClose: PropTypes.func.isRequired +}; + +Dropdown.defaultProps = { + as: 'div', + isOpen: false +}; + +module.exports = onClickOutside(Dropdown); diff --git a/src/components/dropdown/dropdown.scss b/src/components/dropdown/dropdown.scss index 66af291ef..6aea2f067 100644 --- a/src/components/dropdown/dropdown.scss +++ b/src/components/dropdown/dropdown.scss @@ -24,8 +24,12 @@ } a { - background-color: transparent; - color: $type-white; + &:link, + &:visited, + &:active { + background-color: transparent; + color: $type-white; + } } input { diff --git a/src/components/emoji-text/emoji-text.jsx b/src/components/emoji-text/emoji-text.jsx index c6f382260..ee4c00a52 100644 --- a/src/components/emoji-text/emoji-text.jsx +++ b/src/components/emoji-text/emoji-text.jsx @@ -1,33 +1,25 @@ -var classNames = require('classnames'); -var React = require('react'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./emoji-text.scss'); -var EmojiText = React.createClass({ - type: 'EmojiText', - propTyes: { - text: React.PropTypes.string.isRequired, - className: React.PropTypes.string - }, - getDefaultProps: function () { - return { - as: 'p' - }; - }, - render: function () { - var classes = classNames( - 'emoji-text', - this.props.className - ); - return ( - - ); - } -}); +const EmojiText = props => ( + +); + +EmojiText.propTypes = { + className: PropTypes.string, + text: PropTypes.string.isRequired +}; + +EmojiText.defaultProps = { + as: 'p' +}; module.exports = EmojiText; diff --git a/src/components/flex-row/flex-row.jsx b/src/components/flex-row/flex-row.jsx index 4a2deb36e..4dc8582c6 100644 --- a/src/components/flex-row/flex-row.jsx +++ b/src/components/flex-row/flex-row.jsx @@ -1,26 +1,22 @@ -var classNames = require('classnames'); -var React = require('react'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./flex-row.scss'); -var FlexRow = React.createClass({ - type: 'FlexRow', - getDefaultProps: function () { - return { - as: 'div' - }; - }, - render: function () { - var classes = classNames( - 'flex-row', - this.props.className - ); - return ( - - {this.props.children} - - ); - } -}); +const FlexRow = props => ( + + {props.children} + +); + +FlexRow.propTypes = { + children: PropTypes.node, + className: PropTypes.string +}; + +FlexRow.defaultProps = { + as: 'div' +}; module.exports = FlexRow; diff --git a/src/components/footer/conference/2016/footer.jsx b/src/components/footer/conference/2016/footer.jsx index b342e59fd..76207f6af 100644 --- a/src/components/footer/conference/2016/footer.jsx +++ b/src/components/footer/conference/2016/footer.jsx @@ -1,125 +1,152 @@ -var React = require('react'); +const React = require('react'); -var FlexRow = require('../../../flex-row/flex-row.jsx'); -var FooterBox = require('../../container/footer.jsx'); +const FlexRow = require('../../../flex-row/flex-row.jsx'); +const FooterBox = require('../../container/footer.jsx'); require('../footer.scss'); -var ConferenceFooter = React.createClass({ - type: 'ConferenceFooter', - render: function () { - return ( - -
    -

    Sponsors

    +const ConferenceFooter = () => ( + +
    +

    Sponsors

    + +
  • + + MIT Office of Digital Learning + +
  • +
  • + + Intel + +
  • +
  • + + LEGO Foundation + +
  • +
  • + + Google + +
  • +
  • + + Siegel Family Endowment + +
  • +
  • + + No Starch Press + +
  • +
  • + + Scratch Foundation + +
  • +
    +
    + +
    +

    Scratch Family

    + + +
  • + Scratch +
  • +
  • + ScratchJr +
  • +
    + +
  • + Scratch Foundation +
  • +
  • + ScratchEd +
  • +
    + +
  • + Scratch Day +
  • +
    +
    +

    + Scratch is a project of the Lifelong Kindergarten Group at the MIT Media Lab. +

    +
    +
    +
    +

    Contact

    +

    + + Email Us + +

    +
    + - -
    -

    Scratch Family

    - - -
  • - Scratch -
  • -
  • - ScratchJr -
  • -
    - -
  • - Scratch Foundation -
  • -
  • - ScratchEd -
  • -
    - -
  • - Scratch Day -
  • -
    -
    -

    - Scratch is a project of the Lifelong Kindergarten Group at the MIT Media Lab. -

    -
    -
    -
    -

    Contact

    -

    - - Email Us - -

    -
    -
    - -
  • - - scratch twitter - -
  • -
  • - - scratch facebook - -
  • -
  • - - scratch foundation blog - -
  • -
    -
    -
    -
    - - ); - } -}); +
    +
    +
    +); module.exports = ConferenceFooter; diff --git a/src/components/footer/conference/2017/footer.jsx b/src/components/footer/conference/2017/footer.jsx index ebd11f36d..d026ce7ee 100644 --- a/src/components/footer/conference/2017/footer.jsx +++ b/src/components/footer/conference/2017/footer.jsx @@ -1,84 +1,100 @@ -var React = require('react'); -var ReactIntl = require('react-intl'); +const injectIntl = require('react-intl').injectIntl; +const intlShape = require('react-intl').intlShape; +const FormattedMessage = require('react-intl').FormattedMessage; +const React = require('react'); -var injectIntl = ReactIntl.injectIntl; -var FormattedMessage = ReactIntl.FormattedMessage; - -var FlexRow = require('../../../flex-row/flex-row.jsx'); -var FooterBox = require('../../container/footer.jsx'); -var LanguageChooser = require('../../../languagechooser/languagechooser.jsx'); +const FlexRow = require('../../../flex-row/flex-row.jsx'); +const FooterBox = require('../../container/footer.jsx'); +const LanguageChooser = require('../../../languagechooser/languagechooser.jsx'); require('../footer.scss'); -var ConferenceFooter = React.createClass({ - type: 'ConferenceFooter', - render: function () { - return ( - - -
    -

    - - -
  • - Scratch -
  • -
  • - ScratchJr -
  • -
    - -
  • - Scratch Foundation -
  • -
  • - ScratchEd -
  • -
    - -
  • - Scratch Day -
  • -
    -
    -

    - -

    -
    -
    -
    -

    Contact

    -

    - - Email Us - -

    -
    -
    - -
  • - - scratch twitter - -
  • -
  • - - scratch facebook - -
  • -
  • - - scratch foundation blog - -
  • -
    -
    -
    +const ConferenceFooter = props => ( + + +
    +

    + + +
  • + Scratch +
  • +
  • + ScratchJr +
  • +
    + +
  • + Scratch Foundation +
  • +
  • + ScratchEd +
  • +
    + +
  • + Scratch Day +
  • +
    - - - ); - } -}); +

    + +

    +
    +
    +
    +

    Contact

    +

    + + Email Us + +

    +
    +
    + +
  • + + scratch twitter + +
  • +
  • + + scratch facebook + +
  • +
  • + + scratch foundation blog + +
  • +
    +
    +
    +
    + +
    +); + +ConferenceFooter.propTypes = { + intl: intlShape +}; module.exports = injectIntl(ConferenceFooter); diff --git a/src/components/footer/conference/2018/footer.jsx b/src/components/footer/conference/2018/footer.jsx index 06daa2e92..1a08cc823 100644 --- a/src/components/footer/conference/2018/footer.jsx +++ b/src/components/footer/conference/2018/footer.jsx @@ -1,84 +1,146 @@ -var React = require('react'); -var ReactIntl = require('react-intl'); +const FormattedMessage = require('react-intl').FormattedMessage; +const injectIntl = require('react-intl').injectIntl; +const intlShape = require('react-intl').intlShape; +const React = require('react'); -var injectIntl = ReactIntl.injectIntl; -var FormattedMessage = ReactIntl.FormattedMessage; - -var FlexRow = require('../../../flex-row/flex-row.jsx'); -var FooterBox = require('../../container/footer.jsx'); -var LanguageChooser = require('../../../languagechooser/languagechooser.jsx'); +const FlexRow = require('../../../flex-row/flex-row.jsx'); +const FooterBox = require('../../container/footer.jsx'); +const LanguageChooser = require('../../../languagechooser/languagechooser.jsx'); require('../footer.scss'); -var ConferenceFooter = React.createClass({ - type: 'ConferenceFooter', - render: function () { - return ( - - -
    -

    - - -
  • - Scratch -
  • -
  • - ScratchJr -
  • -
    - -
  • - Scratch Foundation -
  • -
  • - ScratchEd -
  • -
    - -
  • - Scratch Day -
  • -
    -
    -

    - -

    -
    -
    -
    -

    Contact

    -

    - - Email Us - -

    -
    -
    - -
  • - - scratch twitter - -
  • -
  • - - scratch facebook - -
  • -
  • - - scratch foundation blog - -
  • -
    -
    -
    +const ConferenceFooter = props => ( + + +
    +

    + + +
  • + + Scratch + +
  • +
  • + + ScratchJr + +
  • +
    + +
  • + + Scratch Foundation + +
  • +
  • + + ScratchEd + +
  • +
    + +
  • + + Scratch Day + +
  • +
    - - - ); - } -}); +

    + +

    +
    +
    +
    +

    Contact

    +

    + + Email Us + +

    +
    +
    + +
  • + + scratch twitter + +
  • +
  • + + scratch facebook + +
  • +
  • + + scratch foundation blog + +
  • +
    +
    +
    +
    + +
    +); + +ConferenceFooter.propTypes = { + intl: intlShape +}; module.exports = injectIntl(ConferenceFooter); diff --git a/src/components/footer/container/footer.jsx b/src/components/footer/container/footer.jsx index 53f7eba59..f629e9f39 100644 --- a/src/components/footer/container/footer.jsx +++ b/src/components/footer/container/footer.jsx @@ -1,16 +1,16 @@ -var React = require('react'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./footer.scss'); -var FooterBox = React.createClass({ - type: 'FooterBox', - render: function () { - return ( -
    - {this.props.children} -
    - ); - } -}); +const FooterBox = props => ( +
    + {props.children} +
    +); + +FooterBox.propTypes = { + children: PropTypes.node +}; module.exports = FooterBox; diff --git a/src/components/footer/www/footer.jsx b/src/components/footer/www/footer.jsx index 0cfaa46cd..e983b4f8b 100644 --- a/src/components/footer/www/footer.jsx +++ b/src/components/footer/www/footer.jsx @@ -1,226 +1,225 @@ -var React = require('react'); -var ReactIntl = require('react-intl'); -var FormattedMessage = ReactIntl.FormattedMessage; -var injectIntl = ReactIntl.injectIntl; +const FormattedMessage = require('react-intl').FormattedMessage; +const injectIntl = require('react-intl').injectIntl; +const intlShape = require('react-intl').intlShape; +const MediaQuery = require('react-responsive').default; +const React = require('react'); -var FooterBox = require('../container/footer.jsx'); -var LanguageChooser = require('../../languagechooser/languagechooser.jsx'); +const FooterBox = require('../container/footer.jsx'); +const LanguageChooser = require('../../languagechooser/languagechooser.jsx'); -var MediaQuery = require('react-responsive'); -var frameless = require('../../../lib/frameless'); +const frameless = require('../../../lib/frameless'); require('./footer.scss'); -var Footer = React.createClass({ - type: 'Footer', - render: function () { - return ( - - -
    -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    -
    -
    - -
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    +const Footer = props => ( + + +
    +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +
    +
    + +
    +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - - -
    -
    +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    -
    -
    - -
    -
    - - - -
    -
    - - - -
    -
    - - Scratch Day - -
    -
    - - - -
    -
    - - - -
    -
    -
    -
    - +
    +
    + +
    +
    + + + +
    +
    + + + +
    +
    + + Scratch Day + +
    +
    + + + +
    +
    + + + +
    +
    +
    +
    + -
    -

    - -

    -
    -
    - ); - } -}); +
    +

    + +

    +
    +
    +); + +Footer.propTypes = { + intl: intlShape.isRequired +}; module.exports = injectIntl(Footer); diff --git a/src/components/forms/button.jsx b/src/components/forms/button.jsx index 2c12d7db7..b5b97e39a 100644 --- a/src/components/forms/button.jsx +++ b/src/components/forms/button.jsx @@ -1,22 +1,26 @@ -var React = require('react'); -var classNames = require('classnames'); +const classNames = require('classnames'); +const omit = require('lodash.omit'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./button.scss'); -var Button = React.createClass({ - type: 'Button', - propTypes: { - - }, - render: function () { - var classes = classNames( - 'button', - this.props.className - ); - return ( - - ); - } -}); +const Button = props => { + const classes = classNames('button', props.className); + + return ( + + ); +}; + +Button.propTypes = { + children: PropTypes.node, + className: PropTypes.string +}; module.exports = Button; diff --git a/src/components/forms/charcount.jsx b/src/components/forms/charcount.jsx index af6192ebe..bf46c95f4 100644 --- a/src/components/forms/charcount.jsx +++ b/src/components/forms/charcount.jsx @@ -1,28 +1,28 @@ -var classNames = require('classnames'); -var React = require('react'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./charcount.scss'); -var CharCount = React.createClass({ - type: 'CharCount', - getDefaultProps: function () { - return { - maxCharacters: 0, - currentCharacters: 0 - }; - }, - render: function () { - var classes = classNames( - 'char-count', - this.props.className, - {overmax: (this.props.currentCharacters > this.props.maxCharacters)} - ); - return ( -

    - {this.props.currentCharacters}/{this.props.maxCharacters} -

    - ); - } -}); +const CharCount = props => ( +

    props.maxCharacters) + })} + > + {props.currentCharacters}/{props.maxCharacters} +

    +); + +CharCount.propTypes = { + className: PropTypes.string, + currentCharacters: PropTypes.number, + maxCharacters: PropTypes.number +}; + +CharCount.defaultProps = { + currentCharacters: 0, + maxCharacters: 0 +}; module.exports = CharCount; diff --git a/src/components/forms/checkbox-group.jsx b/src/components/forms/checkbox-group.jsx index 29321d268..c98a0e5dd 100644 --- a/src/components/forms/checkbox-group.jsx +++ b/src/components/forms/checkbox-group.jsx @@ -1,25 +1,25 @@ -var classNames = require('classnames'); -var FRCCheckboxGroup = require('formsy-react-components').CheckboxGroup; -var React = require('react'); -var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -var inputHOC = require('./input-hoc.jsx'); +const classNames = require('classnames'); +const FRCCheckboxGroup = require('formsy-react-components').CheckboxGroup; +const PropTypes = require('prop-types'); +const React = require('react'); + +const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +const inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./checkbox-group.scss'); -var CheckboxGroup = React.createClass({ - type: 'CheckboxGroup', - render: function () { - var classes = classNames( - 'checkbox-group', - this.props.className - ); - return ( -
    - -
    - ); - } -}); +const CheckboxGroup = props => ( +
    + +
    +); + +CheckboxGroup.propTypes = { + className: PropTypes.string +}; module.exports = inputHOC(defaultValidationHOC(CheckboxGroup)); diff --git a/src/components/forms/checkbox.jsx b/src/components/forms/checkbox.jsx index f0aa295b8..fcaac2293 100644 --- a/src/components/forms/checkbox.jsx +++ b/src/components/forms/checkbox.jsx @@ -1,23 +1,23 @@ -var classNames = require('classnames'); -var FRCCheckbox = require('formsy-react-components').Checkbox; -var React = require('react'); -var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -var inputHOC = require('./input-hoc.jsx'); +const classNames = require('classnames'); +const FRCCheckbox = require('formsy-react-components').Checkbox; +const PropTypes = require('prop-types'); +const React = require('react'); + +const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +const inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./checkbox.scss'); -var Checkbox = React.createClass({ - type: 'Checkbox', - render: function () { - var classes = classNames( - 'checkbox-row', - this.props.className - ); - return ( - - ); - } -}); +const Checkbox = props => ( + +); + +Checkbox.propTypes = { + className: PropTypes.string +}; module.exports = inputHOC(defaultValidationHOC(Checkbox)); diff --git a/src/components/forms/form.jsx b/src/components/forms/form.jsx index 17ada223a..1514787b7 100644 --- a/src/components/forms/form.jsx +++ b/src/components/forms/form.jsx @@ -1,47 +1,61 @@ -var classNames = require('classnames'); -var Formsy = require('formsy-react'); -var omit = require('lodash.omit'); -var React = require('react'); -var validations = require('./validations.jsx').validations; +const bindAll = require('lodash.bindall'); +const classNames = require('classnames'); +const Formsy = require('formsy-react'); +const omit = require('lodash.omit'); +const PropTypes = require('prop-types'); +const React = require('react'); -for (var validation in validations) { +const validations = require('./validations.jsx').validations; + +for (const validation in validations) { Formsy.addValidationRule(validation, validations[validation]); } -var Form = React.createClass({ - getDefaultProps: function () { - return { - noValidate: true, - onChange: function () {} - }; - }, - getInitialState: function () { - return { +class Form extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleChange' + ]); + this.state = { allValues: {} }; - }, - onChange: function (currentValues, isChanged) { + } + handleChange (currentValues, isChanged) { this.setState({allValues: omit(currentValues, 'all')}); this.props.onChange(currentValues, isChanged); - }, - render: function () { - var classes = classNames( - 'form', - this.props.className - ); + } + render () { return ( - - {React.Children.map(this.props.children, function (child) { + { + this.formsy = form; + }} + onChange={this.handleChange} + {...this.props} + > + {React.Children.map(this.props.children, child => { if (!child) return child; if (child.props.name === 'all') { return React.cloneElement(child, {value: this.state.allValues}); - } else { - return child; } - }.bind(this))} + return child; + })} ); } -}); +} + +Form.propTypes = { + children: PropTypes.node, + className: PropTypes.string, + onChange: PropTypes.func +}; + +Form.defaultProps = { + noValidate: true, + onChange: function () {} +}; module.exports = Form; diff --git a/src/components/forms/general-error.jsx b/src/components/forms/general-error.jsx index d9e20463b..270e3ca39 100644 --- a/src/components/forms/general-error.jsx +++ b/src/components/forms/general-error.jsx @@ -1,5 +1,6 @@ -var Formsy = require('formsy-react'); -var React = require('react'); +const Formsy = require('formsy-react'); +const PropTypes = require('prop-types'); +const React = require('react'); require('./general-error.scss'); @@ -10,13 +11,18 @@ require('./general-error.scss'); * give it a name, and apply your validation error to * the name of the GeneralError component. */ -module.exports = Formsy.HOC(React.createClass({ - render: function () { - if (!this.props.showError()) return null; - return ( -

    - {this.props.getErrorMessage()} -

    - ); - } -})); +const GeneralError = props => { + if (!props.showError()) return null; + return ( +

    + {props.getErrorMessage()} +

    + ); +}; + +GeneralError.propTypes = { + getErrorMessage: PropTypes.func, + showError: PropTypes.func +}; + +module.exports = Formsy.HOC(GeneralError); diff --git a/src/components/forms/input-hoc.jsx b/src/components/forms/input-hoc.jsx index 1532eaefd..1ce3c1c0b 100644 --- a/src/components/forms/input-hoc.jsx +++ b/src/components/forms/input-hoc.jsx @@ -1,20 +1,32 @@ -var React = require('react'); +const omit = require('lodash.omit'); +const PropTypes = require('prop-types'); +const React = require('react'); -module.exports = function InputComponentMixin (Component) { - var InputComponent = React.createClass({ - getDefaultProps: function () { - return { - messages: { - 'general.notRequired': 'Not Required' - } - }; - }, - render: function () { - return ( - - ); +/** + * Higher-order component for building an input field + * @param {React.Component} Component an input component + * @return {React.Component} a wrapped input component + */ +module.exports = Component => { + const InputComponent = props => ( + + ); + + InputComponent.propTypes = { + messages: PropTypes.shape({ + 'general.notRequired': PropTypes.string + }), + required: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]) + }; + + InputComponent.defaultProps = { + messages: { + 'general.notRequired': 'Not Required' } - }); + }; + return InputComponent; }; diff --git a/src/components/forms/input.jsx b/src/components/forms/input.jsx index 3244ade3c..a9992a40c 100644 --- a/src/components/forms/input.jsx +++ b/src/components/forms/input.jsx @@ -1,46 +1,57 @@ -var classNames = require('classnames'); -var FRCInput = require('formsy-react-components').Input; -var React = require('react'); -var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -var inputHOC = require('./input-hoc.jsx'); +const bindAll = require('lodash.bindall'); +const classNames = require('classnames'); +const FRCInput = require('formsy-react-components').Input; +const omit = require('lodash.omit'); +const PropTypes = require('prop-types'); +const React = require('react'); + +const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +const inputHOC = require('./input-hoc.jsx'); require('./input.scss'); require('./row.scss'); -var Input = React.createClass({ - type: 'Input', - getDefaultProps: function () { - return {}; - }, - getInitialState: function () { - return { +class Input extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleInvalid', + 'handleValid' + ]); + this.state = { status: '' }; - }, - onValid: function () { + } + handleValid () { this.setState({ status: 'pass' }); - }, - onInvalid: function () { + } + handleInvalid () { this.setState({ status: 'fail' }); - }, - render: function () { - var classes = classNames( - this.state.status, - this.props.className, - {'no-label': (typeof this.props.label === 'undefined')} - ); + } + render () { return ( - + ); } -}); +} + +Input.propTypes = { + className: PropTypes.string, + label: PropTypes.string +}; module.exports = inputHOC(defaultValidationHOC(Input)); diff --git a/src/components/forms/phone-input.jsx b/src/components/forms/phone-input.jsx index 260c5a2ef..69d8ab23f 100644 --- a/src/components/forms/phone-input.jsx +++ b/src/components/forms/phone-input.jsx @@ -1,23 +1,33 @@ -var allCountries = require('react-telephone-input/lib/country_data').allCountries; -var classNames = require('classnames'); -var ComponentMixin = require('formsy-react-components').ComponentMixin; -var FormsyMixin = require('formsy-react').Mixin; -var React = require('react'); -var ReactPhoneInput = require('react-telephone-input/lib/withStyles'); -var Row = require('formsy-react-components').Row; +const allCountries = require('react-telephone-input/lib/country_data').allCountries; +const classNames = require('classnames'); +const ComponentMixin = require('formsy-react-components').ComponentMixin; +const createReactClass = require('create-react-class'); +const FormsyMixin = require('formsy-react').Mixin; +const omit = require('lodash.omit'); +const PropTypes = require('prop-types'); +const React = require('react'); +const ReactPhoneInput = require('react-telephone-input/lib/withStyles').default; +const Row = require('formsy-react-components').Row; -var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -var inputHOC = require('./input-hoc.jsx'); -var intl = require('../../lib/intl.jsx'); -var validationHOCFactory = require('./validations.jsx').validationHOCFactory; +const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +const inputHOC = require('./input-hoc.jsx'); +const intl = require('../../lib/intl.jsx'); +const validationHOCFactory = require('./validations.jsx').validationHOCFactory; -var allIso2 = allCountries.map(function (country) {return country.iso2;}); +const allIso2 = allCountries.map(country => (country.iso2)); require('./row.scss'); require('./phone-input.scss'); -var PhoneInput = React.createClass({ +const PhoneInput = createReactClass({ // eslint-disable-line react/prefer-es6-class displayName: 'PhoneInput', + propTypes: { + className: PropTypes.string, + defaultCountry: PropTypes.string, + disabled: PropTypes.bool, + name: PropTypes.string, + onChange: PropTypes.func + }, mixins: [ FormsyMixin, ComponentMixin @@ -31,29 +41,34 @@ var PhoneInput = React.createClass({ defaultCountry: 'us' }; }, - onChangeInput: function (number, country) { - var value = {national_number: number, country_code: country}; + handleChangeInput: function (number, country) { + const value = { + national_number: number, + country_code: country + }; this.setValue(value); this.props.onChange(this.props.name, value); }, render: function () { - var defaultCountry = PhoneInput.getDefaultProps().defaultCountry; + let defaultCountry = PhoneInput.getDefaultProps().defaultCountry; if (allIso2.indexOf(this.props.defaultCountry.toLowerCase()) !== -1) { - defaultCountry = this.props.defaultCountry.toLowerCase(); + defaultCountry = this.props.defaultCountry.toLowerCase(); } return ( -
    - {this.renderHelp()} {this.renderErrorMessage()} @@ -63,7 +78,7 @@ var PhoneInput = React.createClass({ } }); -var phoneValidationHOC = validationHOCFactory({ +const phoneValidationHOC = validationHOCFactory({ isPhone: }); diff --git a/src/components/forms/radio-group.jsx b/src/components/forms/radio-group.jsx index fcdf928a6..168f0a926 100644 --- a/src/components/forms/radio-group.jsx +++ b/src/components/forms/radio-group.jsx @@ -1,23 +1,23 @@ -var classNames = require('classnames'); -var FRCRadioGroup = require('formsy-react-components').RadioGroup; -var React = require('react'); -var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -var inputHOC = require('./input-hoc.jsx'); +const classNames = require('classnames'); +const FRCRadioGroup = require('formsy-react-components').RadioGroup; +const PropTypes = require('prop-types'); +const React = require('react'); + +const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +const inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./radio-group.scss'); -var RadioGroup = React.createClass({ - type: 'RadioGroup', - render: function () { - var classes = classNames( - 'radio-group', - this.props.className - ); - return ( - - ); - } -}); +const RadioGroup = props => ( + +); + +RadioGroup.propTypes = { + className: PropTypes.string +}; module.exports = inputHOC(defaultValidationHOC(RadioGroup)); diff --git a/src/components/forms/select.jsx b/src/components/forms/select.jsx index a17053942..16a7e1ee2 100644 --- a/src/components/forms/select.jsx +++ b/src/components/forms/select.jsx @@ -1,33 +1,31 @@ -var classNames = require('classnames'); -var defaults = require('lodash.defaultsdeep'); -var FRCSelect = require('formsy-react-components').Select; -var React = require('react'); -var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -var inputHOC = require('./input-hoc.jsx'); +const classNames = require('classnames'); +const defaults = require('lodash.defaultsdeep'); +const FRCSelect = require('formsy-react-components').Select; +const PropTypes = require('prop-types'); +const React = require('react'); + +const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +const inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./select.scss'); -var Select = React.createClass({ - type: 'Select', - propTypes: { - - }, - render: function () { - var classes = classNames( - 'select', - this.props.className - ); - var props = this.props; - if (this.props.required && !this.props.value) { - props = defaults({}, this.props, {value: this.props.options[0].value}); - } - return ( -
    - -
    - ); +const Select = props => { + if (props.required && !props.value) { + props = defaults({}, props, {value: props.options[0].value}); } -}); + return ( +
    + +
    + ); +}; + +Select.propTypes = { + className: PropTypes.string, + options: PropTypes.arrayOf(PropTypes.any), + required: PropTypes.bool, + value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) +}; module.exports = inputHOC(defaultValidationHOC(Select)); diff --git a/src/components/forms/textarea.jsx b/src/components/forms/textarea.jsx index ec90f8b59..0c488f995 100644 --- a/src/components/forms/textarea.jsx +++ b/src/components/forms/textarea.jsx @@ -1,25 +1,25 @@ -var classNames = require('classnames'); -var FRCTextarea = require('formsy-react-components').Textarea; -var React = require('react'); -var defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; -var inputHOC = require('./input-hoc.jsx'); +const classNames = require('classnames'); +const FRCTextarea = require('formsy-react-components').Textarea; +const omit = require('lodash.omit'); +const PropTypes = require('prop-types'); +const React = require('react'); + +const defaultValidationHOC = require('./validations.jsx').defaultValidationHOC; +const inputHOC = require('./input-hoc.jsx'); require('./row.scss'); require('./textarea.scss'); -var TextArea = React.createClass({ - type: 'TextArea', - render: function () { - var classes = classNames( - 'textarea-row', - this.props.className - ); - return ( - - ); - } -}); +const TextArea = props => ( + +); + +TextArea.propTypes = { + className: PropTypes.string +}; module.exports = inputHOC(defaultValidationHOC(TextArea)); diff --git a/src/components/forms/validations.jsx b/src/components/forms/validations.jsx index 113cd6fb4..c83ce63cb 100644 --- a/src/components/forms/validations.jsx +++ b/src/components/forms/validations.jsx @@ -1,48 +1,46 @@ -var defaults = require('lodash.defaultsdeep'); -var intl = require('../../lib/intl.jsx'); -var libphonenumber = require('google-libphonenumber'); -var phoneNumberUtil = libphonenumber.PhoneNumberUtil.getInstance(); -var React = require('react'); - -module.exports = {}; +const defaults = require('lodash.defaultsdeep'); +const intl = require('../../lib/intl.jsx'); +const libphonenumber = require('google-libphonenumber'); +const omit = require('lodash.omit'); +const phoneNumberUtil = libphonenumber.PhoneNumberUtil.getInstance(); +const PropTypes = require('prop-types'); +const React = require('react'); module.exports.validations = { - notEquals: function (values, value, neq) { - return value !== neq; - }, - notEqualsField: function (values, value, field) { - return value !== values[field]; - }, - isPhone: function (values, value) { + notEquals: (values, value, neq) => (value !== neq), + notEqualsField: (values, value, field) => (value !== values[field]), + isPhone: (values, value) => { if (typeof value === 'undefined') return true; if (value && value.national_number === '+') return true; try { - var parsed = phoneNumberUtil.parse(value.national_number, value.country_code.iso2); + const parsed = phoneNumberUtil.parse(value.national_number, value.country_code.iso2); + return phoneNumberUtil.isValidNumber(parsed); } catch (err) { return false; } - return phoneNumberUtil.isValidNumber(parsed); } }; + module.exports.validations.notEqualsUsername = module.exports.validations.notEquals; -module.exports.validationHOCFactory = function (defaultValidationErrors) { - return function (Component) { - var ValidatedComponent = React.createClass({ - render: function () { - var validationErrors = defaults( - {}, - defaultValidationErrors, - this.props.validationErrors - ); - return ( - - ); - } - }); - return ValidatedComponent; +module.exports.validationHOCFactory = defaultValidationErrors => (Component => { + const ValidatedComponent = props => ( + + ); + + ValidatedComponent.propTypes = { + validationErrors: PropTypes.object // eslint-disable-line react/forbid-prop-types }; -}; + + return ValidatedComponent; +}); module.exports.defaultValidationHOC = module.exports.validationHOCFactory({ isDefaultRequiredValue: diff --git a/src/components/grid/grid.jsx b/src/components/grid/grid.jsx index f130e5bbd..0bc8c9286 100644 --- a/src/components/grid/grid.jsx +++ b/src/components/grid/grid.jsx @@ -1,79 +1,68 @@ -var classNames = require('classnames'); -var React = require('react'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); -var Thumbnail = require('../thumbnail/thumbnail.jsx'); -var FlexRow = require('../flex-row/flex-row.jsx'); +const Thumbnail = require('../thumbnail/thumbnail.jsx'); +const FlexRow = require('../flex-row/flex-row.jsx'); require('./grid.scss'); -var Grid = React.createClass({ - type: 'Grid', - getDefaultProps: function () { - return { - items: require('./grid.json'), - itemType: 'projects', - showLoves: false, - showFavorites: false, - showRemixes: false, - showViews: false, - showAvatar: false - }; - }, - render: function () { - var classes = classNames( - 'grid', - this.props.className - ); - return ( -
    - - {this.props.items.map(function (item, key) { - var href = '/' + this.props.itemType + '/' + item.id + '/'; +const Grid = props => ( +
    + + {props.items.map((item, key) => { + const href = `/${props.itemType}/${item.id}/`; + if (props.itemType === 'projects') { + return ( + + ); + } + return ( + + ); + })} + +
    +); - if (this.props.itemType == 'projects') { - return ( - - ); - } - else { - return ( - - ); - } - }.bind(this))} -
    -
    - ); - } -}); +Grid.propTypes = { + className: PropTypes.string, + itemType: PropTypes.string, + items: PropTypes.arrayOf(PropTypes.object) +}; + +Grid.defaultProps = { + items: require('./grid.json'), + itemType: 'projects', + showLoves: false, + showFavorites: false, + showRemixes: false, + showViews: false, + showAvatar: false +}; module.exports = Grid; diff --git a/src/components/informationpage/informationpage.jsx b/src/components/informationpage/informationpage.jsx index acc68da77..94a8bd740 100644 --- a/src/components/informationpage/informationpage.jsx +++ b/src/components/informationpage/informationpage.jsx @@ -1,39 +1,34 @@ -var classNames = require('classnames'); -var React = require('react'); -var TitleBanner = require('../../components/title-banner/title-banner.jsx'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); + +const TitleBanner = require('../../components/title-banner/title-banner.jsx'); require('./informationpage.scss'); -/** +/* * Container for a table of contents * alongside a long body of text */ -var InformationPage = React.createClass({ - type: 'InformationPage', - propTypes: { - title: React.PropTypes.string.isRequired - }, - render: function () { - var classes = classNames( - 'info-outer', - 'inner', - this.props.className - ); - return ( -
    - -
    -

    - {this.props.title} -

    -
    -
    -
    - {this.props.children} -
    +const InformationPage = props => ( +
    + +
    +

    + {props.title} +

    - ); - } -}); +
    +
    + {props.children} +
    +
    +); + +InformationPage.propTypes = { + children: PropTypes.node, + className: PropTypes.string, + title: PropTypes.string.isRequired +}; module.exports = InformationPage; diff --git a/src/components/intro/intro.jsx b/src/components/intro/intro.jsx index d1f7c4275..efe0473a7 100644 --- a/src/components/intro/intro.jsx +++ b/src/components/intro/intro.jsx @@ -1,111 +1,128 @@ -var connect = require('react-redux').connect; -var React = require('react'); +const bindAll = require('lodash.bindall'); +const connect = require('react-redux').connect; +const PropTypes = require('prop-types'); +const React = require('react'); -var sessionActions = require('../../redux/session.js'); +const sessionActions = require('../../redux/session.js'); -var IframeModal = require('../modal/iframe/modal.jsx'); -var Registration = require('../registration/registration.jsx'); +const IframeModal = require('../modal/iframe/modal.jsx'); +const Registration = require('../registration/registration.jsx'); require('./intro.scss'); -var Intro = React.createClass({ - type: 'Intro', - getDefaultProps: function () { - return { - messages: { - 'intro.aboutScratch': 'ABOUT SCRATCH', - 'intro.forEducators': 'FOR EDUCATORS', - 'intro.forParents': 'FOR PARENTS', - 'intro.itsFree': 'it\'s free!', - 'intro.joinScratch': 'JOIN SCRATCH', - 'intro.seeExamples': 'SEE EXAMPLES', - 'intro.tagLine': 'Create stories, games, and animations
    Share with others around the world', - 'intro.tryItOut': 'TRY IT OUT', - 'intro.description': 'A creative learning community with ' + - 'over 14 million projects shared' - }, - session: {} - }; - }, - getInitialState: function () { - return { +class Intro extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleShowVideo', + 'handleCloseVideo', + 'handleJoinClick', + 'handleCloseRegistration', + 'handleCompleteRegistration' + ]); + this.state = { videoOpen: false }; - }, - showVideo: function () { + } + handleShowVideo () { this.setState({videoOpen: true}); - }, - closeVideo: function () { + } + handleCloseVideo () { this.setState({videoOpen: false}); - }, - handleJoinClick: function (e) { + } + handleJoinClick (e) { e.preventDefault(); - this.setState({'registrationOpen': true}); - }, - closeRegistration: function () { - this.setState({'registrationOpen': false}); - }, - completeRegistration: function () { + this.setState({registrationOpen: true}); + } + handleCloseRegistration () { + this.setState({registrationOpen: false}); + } + handleCompleteRegistration () { this.props.dispatch(sessionActions.refreshSession()); this.closeRegistration(); - }, - render: function () { + } + render () { return (
    -

    -

    +

    - + Scratch Cat + /> Scratch Cat -
    + /> +
    {this.props.messages['intro.tryItOut']}
    - + Tera + /> Tera -
    + /> +
    {this.props.messages['intro.seeExamples']}
    - + Gobo + /> Gobo -
    + /> +
    -
    +
    -
    - Intro Video +
    + Intro Video
    ); } -}); +} -var mapStateToProps = function (state) { - return { - session: state.session - }; +Intro.propTypes = { + dispatch: PropTypes.func.isRequired, + messages: PropTypes.shape({ + 'intro.aboutScratch': PropTypes.string, + 'intro.forEducators': PropTypes.string, + 'intro.forParents': PropTypes.string, + 'intro.itsFree': PropTypes.string, + 'intro.joinScratch': PropTypes.string, + 'intro.seeExamples': PropTypes.string, + 'intro.tagLine': PropTypes.string, + 'intro.tryItOut': PropTypes.string, + 'intro.description': PropTypes.string + }) }; -var ConnectedIntro = connect(mapStateToProps)(Intro); +Intro.defaultProps = { + messages: { + 'intro.aboutScratch': 'ABOUT SCRATCH', + 'intro.forEducators': 'FOR EDUCATORS', + 'intro.forParents': 'FOR PARENTS', + 'intro.itsFree': 'it\'s free!', + 'intro.joinScratch': 'JOIN SCRATCH', + 'intro.seeExamples': 'SEE EXAMPLES', + 'intro.tagLine': 'Create stories, games, and animations
    Share with others around the world', + 'intro.tryItOut': 'TRY IT OUT', + 'intro.description': 'A creative learning community with ' + + 'over 14 million projects shared' + }, + session: {} +}; + +const mapStateToProps = state => ({ + session: state.session +}); + +const ConnectedIntro = connect(mapStateToProps)(Intro); module.exports = ConnectedIntro; diff --git a/src/components/languagechooser/languagechooser.jsx b/src/components/languagechooser/languagechooser.jsx index c538fb923..1e9258853 100644 --- a/src/components/languagechooser/languagechooser.jsx +++ b/src/components/languagechooser/languagechooser.jsx @@ -1,46 +1,57 @@ -var classNames = require('classnames'); -var React = require('react'); +const bindAll = require('lodash.bindall'); +const classNames = require('classnames'); +const PropTypes = require('prop-types'); +const React = require('react'); -var jar = require('../../lib/jar.js'); -var languages = require('../../../languages.json'); -var Form = require('../forms/form.jsx'); -var Select = require('../forms/select.jsx'); +const jar = require('../../lib/jar.js'); +const languages = require('../../../languages.json'); +const Form = require('../forms/form.jsx'); +const Select = require('../forms/select.jsx'); require('./languagechooser.scss'); /** * Footer dropdown menu that allows one to change their language. */ -var LanguageChooser = React.createClass({ - type: 'LanguageChooser', - getDefaultProps: function () { - return { - languages: languages, - locale: 'en' - }; - }, - onSetLanguage: function (name, value) { +class LanguageChooser extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleSetLanguage' + ]); + } + handleSetLanguage (name, value) { jar.set('scratchlanguage', value); window.location.reload(); - }, - render: function () { - var classes = classNames( - 'language-chooser', - this.props.className - ); - var languageOptions = Object.keys(this.props.languages).map(function (value) { - return {value: value, label: this.props.languages[value]}; - }.bind(this)); + } + render () { + const languageOptions = Object.keys(this.props.languages).map(value => ({ + value: value, + label: this.props.languages[value] + })); return ( -
    -
    ); } -}); +} + +LanguageChooser.propTypes = { + className: PropTypes.string, + languages: PropTypes.object, // eslint-disable-line react/forbid-prop-types + locale: PropTypes.string +}; + +LanguageChooser.defaultProps = { + languages: languages, + locale: 'en' +}; module.exports = LanguageChooser; diff --git a/src/components/login/login.jsx b/src/components/login/login.jsx index c7243d7a6..58586e5e5 100644 --- a/src/components/login/login.jsx +++ b/src/components/login/login.jsx @@ -1,66 +1,108 @@ -var React = require('react'); -var FormattedMessage = require('react-intl').FormattedMessage; +const bindAll = require('lodash.bindall'); +const FormattedMessage = require('react-intl').FormattedMessage; +const PropTypes = require('prop-types'); +const React = require('react'); -var log = require('../../lib/log.js'); +const log = require('../../lib/log.js'); -var Form = require('../forms/form.jsx'); -var Input = require('../forms/input.jsx'); -var Button = require('../forms/button.jsx'); -var Spinner = require('../spinner/spinner.jsx'); +const Form = require('../forms/form.jsx'); +const Input = require('../forms/input.jsx'); +const Button = require('../forms/button.jsx'); +const Spinner = require('../spinner/spinner.jsx'); require('./login.scss'); -var Login = React.createClass({ - type: 'Login', - propTypes: { - onLogIn: React.PropTypes.func, - error: React.PropTypes.string - }, - getInitialState: function () { - return { +class Login extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'handleSubmit' + ]); + this.state = { waiting: false }; - }, - handleSubmit: function (formData) { + } + handleSubmit (formData) { this.setState({waiting: true}); - this.props.onLogIn(formData, function (err) { + this.props.onLogIn(formData, err => { if (err) log.error(err); this.setState({waiting: false}); - }.bind(this)); - }, - render: function () { - var error; + }); + } + render () { + let error; if (this.props.error) { error =
    {this.props.error}
    ; } return (
    -
    ); } -}); +} + +Login.propTypes = { + error: PropTypes.string, + onLogIn: PropTypes.func +}; module.exports = Login; diff --git a/src/components/masonrygrid/masonrygrid.jsx b/src/components/masonrygrid/masonrygrid.jsx index ef32172e5..5f654488d 100644 --- a/src/components/masonrygrid/masonrygrid.jsx +++ b/src/components/masonrygrid/masonrygrid.jsx @@ -1,60 +1,68 @@ -var classNames = require('classnames'); -var React = require('react'); -var MediaQuery = require('react-responsive'); -var frameless = require('../../lib/frameless'); +const bindAll = require('lodash.bindall'); +const classNames = require('classnames'); +const MediaQuery = require('react-responsive').default; +const PropTypes = require('prop-types'); +const React = require('react'); + +const frameless = require('../../lib/frameless'); require('./masonrygrid.scss'); -var MasonryGrid = React.createClass({ - type: 'MasonryGrid', - getDefaultProps: function () { - return { - as: 'div' - }; - }, - reorderColumns: function (items, cols) { - var a1 = []; - var a2 = []; - var a3 = []; - var i = 0; - //only implemented for 2 and 3 columns so far - easy to extend if needed +class MasonryGrid extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'reorderColumns' + ]); + } + reorderColumns (items, cols) { + const a1 = []; + const a2 = []; + const a3 = []; + let i = 0; + // only implemented for 2 and 3 columns so far - easy to extend if needed if (cols > 1 && cols < 4) { - for (i=0;i - + + {this.props.children} - + {this.reorderColumns(this.props.children, 2)} - + {this.reorderColumns(this.props.children, 3)} ); } -}); +} + +MasonryGrid.propTypes = { + children: PropTypes.node, + className: PropTypes.string +}; + +MasonryGrid.defaultProps = { + as: 'div' +}; module.exports = MasonryGrid; diff --git a/src/components/microworld/microworld.jsx b/src/components/microworld/microworld.jsx index ec21d5a87..5923f7ac4 100644 --- a/src/components/microworld/microworld.jsx +++ b/src/components/microworld/microworld.jsx @@ -1,39 +1,53 @@ -var React = require('react'); +const bindAll = require('lodash.bindall'); +const PropTypes = require('prop-types'); +const React = require('react'); + +const Box = require('../box/box.jsx'); +const LegacyCarousel = require('../carousel/legacy-carousel.jsx'); +const IframeModal = require('../modal/iframe/modal.jsx'); +const NestedCarousel = require('../nestedcarousel/nestedcarousel.jsx'); require('./microworld.scss'); -var Box = require('../box/box.jsx'); -var LegacyCarousel = require('../carousel/legacy-carousel.jsx'); -var IframeModal = require('../modal/iframe/modal.jsx'); -var NestedCarousel = require('../nestedcarousel/nestedcarousel.jsx'); - -var Microworld = React.createClass({ - type: 'Microworld', - propTypes: { - microworldData: React.PropTypes.node.isRequired - }, - markVideoOpen: function (key) { - {/* When a video is clicked, mark it as an open video, so the video Modal will open. - Key is the number of the video, so distinguish between different videos on the page */} - - var videoOpenArr = this.state.videoOpen; - videoOpenArr[key] = true; - this.setState({videoOpen: videoOpenArr}); - }, - markVideoClosed: function (key) { - {/* When a video's x is clicked, mark it as closed, so the video Modal will disappear. - Key is the number of the video, so distinguish between different videos on the page */} - var videoOpenArr = this.state.videoOpen; - videoOpenArr[key] = false; - this.setState({videoOpen: videoOpenArr}); - }, - getInitialState: function () { - return { +class Microworld extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'markVideoOpen', + 'markVideoClosed', + 'renderVideos', + 'renderVideo', + 'renderEditorWindow', + 'renderTips', + 'renderStarterProject', + 'renderProjectIdeasBox', + 'renderForum', + 'renderDesignStudio' + ]); + this.state = { videoOpen: {} }; - }, - renderVideos: function () { - var videos = this.props.microworldData.videos; + } + markVideoOpen (key) { + /* + When a video is clicked, mark it as an open video, so the video Modal will open. + Key is the number of the video, so distinguish between different videos on the page + */ + const videoOpenArr = this.state.videoOpen; + videoOpenArr[key] = true; + this.setState({videoOpen: videoOpenArr}); + } + markVideoClosed (key) { + /* + When a video's x is clicked, mark it as closed, so the video Modal will disappear. + Key is the number of the video, so distinguish between different videos on the page + */ + const videoOpenArr = this.state.videoOpen; + videoOpenArr[key] = false; + this.setState({videoOpen: videoOpenArr}); + } + renderVideos () { + const videos = this.props.microworldData.videos; if (!videos || videos.length <= 0) { return null; } @@ -48,26 +62,32 @@ var Microworld = React.createClass({
    ); - }, - renderVideo: function (video, key) { + } + renderVideo (video, key) { return (
    -
    -
    +
    { // eslint-disable-line react/jsx-no-bind + this.markVideoOpen(key); + }} + />
    { // eslint-disable-line react/jsx-no-bind + this.markVideoClosed(key); + }} />
    ); - }, - renderEditorWindow: function () { - var projectId = this.props.microworldData.microworld_project_id; + } + renderEditorWindow () { + const projectId = this.props.microworldData.microworld_project_id; if (!projectId) { return null; @@ -75,30 +95,37 @@ var Microworld = React.createClass({ return (

    Start Creating!

    - + + -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - -
    - -

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - - ); - } -})); +const InformationPage = require('../../../components/informationpage/informationpage.jsx'); -render(, document.getElementById('app')); +const TeacherFaq = props => ( + +
    +
    + +

    +
    +
    +
    + -
    - +const Landing = () => ( +
    + +
    +

    + +

    + +

    + +

    +
    +