Merge branch 'develop' of https://github.com/LLK/scratch-www into feature/conference-schedule

* 'develop' of https://github.com/LLK/scratch-www: (32 commits)
  Lint
  Bundle all locale data
  Don't bundle polyfills
  Set up Raven within init.js
  Prefix privacyPolicy message string
  Exclude minified javascript from linting
  One space more
  Changes "interfacesto" to "interfaces to"
  Remove tag target
  Filter before mapping to avoid returning undefined
  Fix Pass condition for "static" routes
  Spacing2
  Mangling is the default
  Spacing
  Update for typography fixes
  Cherry pick PR #476 into master
  Add invisible spacer to anchored sections
  For Developers
  Lint JSON, expand and simplify lint step
  Fix banned user redirect
  ...

# Conflicts:
#	src/redux/actions.js
#	src/redux/reducer.js
This commit is contained in:
Matthew Taylor 2016-05-19 13:25:36 -04:00
commit d69de477a1
42 changed files with 1125 additions and 26236 deletions

5
.eslintignore Normal file
View file

@ -0,0 +1,5 @@
node_modules/*
static/*
build/*
intl/*
**/*.min.js

View file

@ -25,7 +25,8 @@
"jsx": true
},
"plugins": [
"react"
"react",
"json"
],
"extends": "eslint:recommended"
}

View file

@ -4,6 +4,7 @@ node_js:
sudo: required
cache:
directories:
- /home/travis/virtualenv/python2.7/lib/python2.7/site-packages
- node_modules
notifications:
slack:
@ -21,7 +22,6 @@ env:
- secure: EX1fyov+f6ytWN2ZSL4dLslwrVkp6Ho/uoSLO38/qNG3XdGmBN4VprxddcQiWfo+Mrg3GdWcfcM/VazhhStBi1uLfZiw3RHZaSGuWbiuD2EtzqtlC+OVvoajgy91QFajh9Zzuwa0rYbEPd/sw01R53NoWJYl0GSteWk7C8Wv6anl4FUJCqgvvTV2ZEcyTtGcVJgUhKi1MfNpTSM6JWBy0DWszcyxj7C8LSs1+l9ZjAtnlUBWY13HsrNu8G5d+FwqGHZLUAjdu2O602wxV897/xLARLduZ+01ALpVefNEEGMB1Wd+xMw4dm2B0Uk86a4TBRCeOgJZ1yoJoPpGPOHTo+dgNXcU8ReszGVoy7uOjFWwu82FQq8gzfcf75yzaRJgG8/BJ6BkJfa0EmFg3iO5CwixQyHR5+CqsedtoLAWVT8zlOfQ/Z6yx4Pm7jXQSOkyvo09YJ2QIn4IFGPvwOVS7Firzi+fLl8GYApeSV9G10e1IzA4pPrKdJMRA4qRMPt9zJGq7ZO1J/d9aW/5KIsJUDnodnl7yXJyDMOyNeljT9I82ciHZcURxRRY080vrW6dgNJE1V9jxBhWEvr2iCeWMMedWaGuC41I7K9L79eW8lmaE+cQ+OZrzpOJP4GbfmIiXrh+0M4ChL/xBpjtiFwpNdkCXXhzWMnjJ4wCrii4yuc=
- AWS_ACCESS_KEY_ID=$EB_AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY=$EB_AWS_SECRET_ACCESS_KEY
- CXX=g++-4.8
- FASTLY_ACTIVATE_CHANGES=true
# FASTLY_API_KEY
- secure: XNWcCnqSAd4MpKg6FVe3WeFmdqfdH753+PBCOEkJrHS+AHmLMuWsjIQFJ3LUR9ylEQRVPR2OyXJW/R8NI9toStREgwE4fwIVo0l4fwYqLStxYpEKlcWfkJ3uNpRZhvcVmUBycelrnjJqXVdrtlxPCKX0tNkpcKH2b98We7A2/r7HxKv13upDxWTQ/qRUv0+SJCRTB4n/QInABi87Ef8Q2rNGrL0WQzQvVBeiEXOP0JSkyYK4+q65gswMKPehgiFagnYVgJN9J9Q1VrBDc06gidbznBcEpPaBAYvsTTY9dWTJxaaKNSrmOIe/OiuJUEHjb+8NL+j6Lp7wX8lzEjbr0FkVlFnxS9VbftS2KFkN7+c3RF57+tsq0xwJ6vgomIVS5FupHgl/oCJicnH/FLfynditOLZhmhF+Ed5GCAoIEamRRzcVHdjvglsEtYsDX1/z2t+HKYtPQuXYOywDRVTSPf88eEbu8ehfgNcYaIAuD6eedyDnKTOIv7owWs3Y7GsxQ2jBLGXq1YoUEkPtB0vfaHi72CeEhDQ53mEn2Ure47UMGMgUjKtiIhDBNTbECwP/ZDJv1accGRljKjDy93aCJeRi1T7Op7tDbHSl4ScieeOwOeKJMcD1U5JGdA/sRnjjgSKb24P2ys4NYr95dgqWNNGPGMxca+lGufzdEaTQT44=
@ -50,15 +50,9 @@ env:
- SKIP_CLEANUP=true
- NODE_ENV=production
- WWW_VERSION=${TRAVIS_COMMIT:0:5}
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
install:
- sudo -H pip install -r requirements.txt
- npm install
- npm --production=false install
deploy:
- provider: script
skip_cleanup: $SKIP_CLEANUP

View file

@ -24,9 +24,6 @@ deploy:
@make build
@make sync
tag:
echo $(GIT_VERSION) > ./build/version.txt
translations:
./bin/build-locales intl
@ -62,18 +59,9 @@ test:
@echo ""
lint:
$(ESLINT) ./*.js
$(ESLINT) ./dev-server/*.js
$(ESLINT) ./bin/**/*.js
$(ESLINT) ./src/*.js
$(ESLINT) ./src/mixins/*.jsx
$(ESLINT) ./src/views/**/*.jsx
$(ESLINT) ./src/components/**/*.jsx
$(ESLINT) ./src/components/**/**/*.jsx
$(ESLINT) . --ext .js,.jsx,.json
$(SASSLINT) ./src/*.scss
$(SASSLINT) ./src/views/**/*.scss
$(SASSLINT) ./src/components/**/*.scss
$(SASSLINT) ./src/components/**/**/*.scss
$(SASSLINT) ./src/**/*.scss
unit:
$(TAP) ./test/unit/*.js

View file

@ -19,8 +19,6 @@ var extraAppRoutes = [
// Homepage with querystring.
// TODO: Should this be added for every route?
'^/\\?',
// Version output by build
'/version\.txt$',
// View html
'^/[^\/]*\.html'
];
@ -31,7 +29,10 @@ var extraAppRoutes = [
*/
var getStaticPaths = function (pathToStatic) {
var staticPaths = glob.sync(path.resolve(__dirname, pathToStatic));
return staticPaths.map(function (pathName) {
return staticPaths.filter(function (pathName) {
// Exclude view html, resolve everything else in the build
return path.extname(pathName) !== '.html';
}).map(function (pathName) {
// Reduce absolute path to relative paths like '/js'
var base = path.dirname(path.resolve(__dirname, pathToStatic));
return '^' + pathName.replace(base, '') + (path.extname(pathName) ? '' : '/');
@ -106,7 +107,7 @@ async.auto({
});
},
notPassRequestCondition: ['version', function (cb, results) {
var statement = getAppRouteCondition('../static/*', routes, extraAppRoutes);
var statement = getAppRouteCondition('../build/*', routes, extraAppRoutes);
var condition = {
name: NOT_PASS_REQUEST_CONDITION_NAME,
statement: statement,

View file

@ -38,6 +38,7 @@
"copy-webpack-plugin": "0.2.0",
"css-loader": "0.23.1",
"eslint": "1.3.1",
"eslint-plugin-json": "1.2.0",
"eslint-plugin-react": "3.3.1",
"exenv": "1.2.0",
"fastly": "1.2.1",
@ -56,13 +57,17 @@
"minilog": "2.0.8",
"node-sass": "3.3.3",
"pako": "0.2.8",
"po2icu": "git://github.com/LLK/po2icu.git#develop",
"po2icu": "0.0.2",
"postcss-loader": "0.8.2",
"react-addons-test-utils": "0.14.7",
"raven-js": "3.0.4",
"react": "0.14.0",
"react-dom": "0.14.0",
"react-intl": "2.1.2",
"react-modal": "0.6.1",
"react-onclickoutside": "4.1.1",
"react-redux": "4.4.0",
"react-slick": "0.9.2",
"redux": "3.5.2",
"redux-thunk": "2.0.1",
"sass-lint": "1.5.1",
"sass-loader": "2.0.1",

View file

@ -14,201 +14,145 @@ var Footer = React.createClass({
<div className="lists">
<dl>
<dt>
<FormattedMessage
id='general.about'
defaultMessage={'About'} />
<FormattedMessage id='general.about' />
</dt>
<dd>
<a href="/about/">
<FormattedMessage
id='footer.about'
defaultMessage={'About Scratch'} />
<FormattedMessage id='general.aboutScratch' />
</a>
</dd>
<dd>
<a href="/parents/">
<FormattedMessage
id='general.forParents'
defaultMessage={'For Parents'} />
<FormattedMessage id='general.forParents' />
</a>
</dd>
<dd>
<a href="/educators/">
<FormattedMessage
id='general.forEducators'
defaultMessage={'For Educators'} />
<FormattedMessage id='general.forEducators' />
</a>
</dd>
<dd>
<a href="/info/credits/">
<FormattedMessage
id='general.credits'
defaultMessage={'Credits'} />
<FormattedMessage id='general.credits' />
</a>
</dd>
<dd>
<a href="/jobs/">
<FormattedMessage
id='general.jobs'
defaultMessage={'Jobs'} />
<FormattedMessage id='general.jobs' />
</a>
</dd>
<dd>
<a href="http://wiki.scratch.mit.edu/wiki/Scratch_Press">
<FormattedMessage
id='general.press'
defaultMessage={'Press'} />
<FormattedMessage id='general.press' />
</a>
</dd>
</dl>
<dl>
<dt>
<FormattedMessage
id='general.community'
defaultMessage={'Community'} />
<FormattedMessage id='general.community' />
</dt>
<dd>
<a href="/community_guidelines/">
<FormattedMessage
id='general.guidelines'
defaultMessage={'Community Guidelines'} />
<FormattedMessage id='general.guidelines' />
</a>
</dd>
<dd>
<a href="/discuss/">
<FormattedMessage
id='footer.discuss'
defaultMessage={'Discussion Forums'} />
<FormattedMessage id='footer.discuss' />
</a>
</dd>
<dd>
<a href="https://wiki.scratch.mit.edu/">
<FormattedMessage
id='general.wiki'
defaultMessage={'Scratch Wiki'} />
<FormattedMessage id='general.wiki' />
</a>
</dd>
<dd>
<a href="/statistics/">
<FormattedMessage
id='general.statistics'
defaultMessage={'Statistics'} />
<FormattedMessage id='general.statistics' />
</a>
</dd>
</dl>
<dl>
<dt>
<FormattedMessage
id='general.support'
defaultMessage={'Support'} />
<FormattedMessage id='general.support' />
</dt>
<dd>
<a href="/help/">
<FormattedMessage
id='footer.help'
defaultMessage={'Help Page'} />
<FormattedMessage id='footer.help' />
</a>
</dd>
<dd>
<a href="/info/faq/">
<FormattedMessage
id='general.faq'
defaultMessage={'FAQ'} />
<FormattedMessage id='general.faq' />
</a>
</dd>
<dd>
<a href="/scratch2download/">
<FormattedMessage
id='general.offlineEditor'
defaultMessage={'Offline Editor'} />
<FormattedMessage id='general.offlineEditor' />
</a>
</dd>
<dd>
<a href="/contact-us/">
<FormattedMessage
id='general.contactUs'
defaultMessage={'Contact Us'} />
<FormattedMessage id='general.contactUs' />
</a>
</dd>
<dd>
<a href="https://secure.donationpay.org/scratchfoundation/">
<FormattedMessage
id='general.donate'
defaultMessage={'Donate'} />
<FormattedMessage id='general.donate'/>
</a>
</dd>
</dl>
<dl>
<dt>
<FormattedMessage
id='general.legal'
defaultMessage={'Legal'} />
<FormattedMessage id='general.legal'/>
</dt>
<dd>
<a href="/terms_of_use/">
<FormattedMessage
id='general.termsOfUse'
defaultMessage={'Terms of Use'} />
<FormattedMessage id='general.termsOfUse' />
</a>
</dd>
<dd>
<a href="/privacy_policy/">
<FormattedMessage
id='privacyPolicy'
defaultMessage={'Privacy Policy'} />
<FormattedMessage id='general.privacyPolicy' />
</a>
</dd>
<dd>
<a href="/DMCA/">
<FormattedMessage
id='general.dmca'
defaultMessage={'DMCA'} />
<FormattedMessage id='general.dmca' />
</a>
</dd>
</dl>
<dl>
<dt>
<FormattedMessage
id='footer.scratchFamily'
defaultMessage={'Scratch Family'} />
<FormattedMessage id='footer.scratchFamily' />
</dt>
<dd>
<a href="http://scratched.gse.harvard.edu/">
<FormattedMessage
id='general.scratchEd'
defaultMessage={'ScratchEd'} />
<FormattedMessage id='general.scratchEd' />
</a>
</dd>
<dd>
<a href="http://www.scratchjr.org/">
<FormattedMessage
id='general.scratchJr'
defaultMessage={'ScratchJr'} />
<FormattedMessage id='general.scratchJr' />
</a>
</dd>
<dd>
<a href="http://day.scratch.mit.edu/">
<FormattedMessage
id='general.scratchday'
defaultMessage={'Scratch Day'} />
<FormattedMessage id='general.scratchday' />
</a>
</dd>
<dd>
<a href="/conference/">
<FormattedMessage
id='general.scratchConference'
defaultMessage={'Scratch Conference'} />
<FormattedMessage id='general.scratchConference' />
</a>
</dd>
<dd>
<a href="http://www.scratchfoundation.org/">
<FormattedMessage
id='general.scratchFoundation'
defaultMessage={'Scratch Foundation'} />
<FormattedMessage id='general.scratchFoundation' />
</a>
</dd>
</dl>
@ -218,11 +162,7 @@ var Footer = React.createClass({
<div className="copyright">
<p>
<FormattedMessage
id='general.copyright'
defaultMessage={
'Scratch is a project of the Lifelong Kindergarten Group at the MIT Media Lab'
} />
<FormattedMessage id='general.copyright' />
</p>
</div>
</FooterBox>

View file

@ -15,9 +15,9 @@
li {
display: inline-block;
margin: 5px;
border: 2px solid $active-gray;
border: 1px solid $active-gray;
border-radius: 50px;
padding: .75em 1em;
padding: .75em 1.5em;
text-decoration: none;
color: $type-white;
list-style-type: none;
@ -32,7 +32,7 @@
border: 0 solid transparent;
box-shadow: inset 0 0 5px $box-shadow-gray;
background-color: $active-dark-gray;
padding: calc(.75em + 2px) calc(1em + 2px);
padding: calc(.75em + 1px) calc(1.5em + 1px);
}
&.description {

View file

@ -1,5 +1,16 @@
var jar = require('./lib/jar');
var Raven = require('raven-js');
/**
* -----------------------------------------------------------------------------
* Error handling
* -----------------------------------------------------------------------------
*/
(function () {
if (process.env.SENTRY_DSN !== '') {
Raven.config(process.env.SENTRY_DSN).install();
}
})();
/**
* -----------------------------------------------------------------------------

View file

@ -26,6 +26,7 @@
"general.myClasses": "My Classes",
"general.myStuff": "My Stuff",
"general.offlineEditor": "Offline Editor",
"general.privacyPolicy": "Privacy Policy",
"general.profile": "Profile",
"general.scratchConference": "Scratch Conference",
"general.scratchday": "Scratch Day",
@ -49,7 +50,6 @@
"general.whatsHappening": "What's Happening?",
"general.wiki": "Scratch Wiki",
"footer.about": "About Scratch",
"footer.discuss": "Discussion Forums",
"footer.help": "Help Page",
"footer.scratchFamily": "Scratch Family",

View file

@ -1,12 +1,21 @@
var requireAll = require('./require-all');
var ReactIntl = require('react-intl');
var customLanguages = require('../../custom-locales.json');
var allLocaleData = requireAll(require.context('react-intl/locale-data', true, /^\.\/.*\.js$/));
var customLocaleData = require('../../custom-locales.json');
/**
* Add all locales
*/
for (var locale in allLocaleData) {
ReactIntl.addLocaleData(allLocaleData[locale]);
}
/**
* Add custom locales to react-intl if it doesn't have them.
*/
for (var locale in customLanguages) {
ReactIntl.addLocaleData(customLanguages[locale]);
for (var customLocale in customLocaleData) {
ReactIntl.addLocaleData(customLocaleData[customLocale]);
}
module.exports = ReactIntl;

View file

@ -1,5 +1,7 @@
var redux = require('redux');
var thunk = require('redux-thunk').default;
// JSX syntax transforms to React.createElement
var React = require('react'); // eslint-disable-line
var ReactDOM = require('react-dom');
var StoreProvider = require('react-redux').Provider;

5
src/lib/require-all.js Normal file
View file

@ -0,0 +1,5 @@
var requireAll = function (requireContext) {
return requireContext.keys().map(requireContext);
};
module.exports = requireAll;

View file

@ -17,6 +17,12 @@
"view": "components/components",
"title": "Components"
},
{
"name": "developers",
"pattern": "^/developers/?$",
"view": "developers/developers",
"title": "Developers"
},
{
"name": "hoc",
"pattern": "^/hoc/?$",
@ -104,5 +110,11 @@
"pattern": "^/community_guidelines$",
"view": "guidelines/guidelines",
"title": "Scratch Community Guidelines"
},
{
"name": "privacypolicy",
"pattern": "^/privacy_policy/?$",
"view": "privacypolicy/privacypolicy",
"title": "Privacy Policy"
}
]

View file

@ -19,14 +19,5 @@ module.exports = {
og_image_height: 860,
// Analytics & Monitoring
ga_tracker: process.env.GA_TRACKER || '',
// Error handling
sentry_dsn: process.env.SENTRY_DSN || '',
// Use minified JS libraries
min: (process.env.NODE_ENV === 'production') ? '.min' : '',
// Redux likes to have this
NODE_ENV: process.env.NODE_ENV
ga_tracker: process.env.GA_TRACKER || ''
};

View file

@ -38,31 +38,19 @@
};
</script>
<!-- Polyfill & Initialize (Session & Localization)-->
<script src="/js/lib/polyfill.min.js"></script>
<script src="/js/init.bundle.js"></script>
<!-- Polyfills -->
<script src="/js/polyfill.min.js"></script>
</head>
<body>
<div id="app"></div>
<!-- Vendor & Initialize (Session & Localization)-->
<script src="/js/common.bundle.js"></script>
<!-- Scripts -->
<script src="/js/lib/react{{min}}.js"></script>
<script src="/js/lib/react-dom{{min}}.js"></script>
<script src="/js/lib/redux{{min}}.js"></script>
<script src="/js/lib/react-intl-with-locales{{min}}.js"></script>
<script src="/js/lib/raven.min.js"></script>
<script src="/js/{{name}}.intl.js"></script>
<script src="/js/{{name}}.bundle.js"></script>
<!-- Error logging (Sentry) -->
<script>
if ('{{&sentry_dsn}}' !== '') {
Raven.config('{{&sentry_dsn}}').install();
}
</script>
<!-- Analytics (GA) -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
@ -75,5 +63,21 @@
});
ga('send', 'pageview');
</script>
<!-- translate title element -->
<script>
var loc = window._locale || 'en';
if (typeof window._messages !== 'undefined' && loc !== 'en') {
if (typeof window._messages[loc] === 'undefined') {
loc = loc.split('-')[0];
}
if (typeof window._messages[loc] !== 'undefined') {
var localizedTitle = window._messages[loc]['general.' + '{{title}}'.toLowerCase()] || '';
if (localizedTitle.length > 0) {
document.title = 'Scratch - ' + localizedTitle;
}
}
}
</script>
</body>
</html>

View file

@ -1,6 +1,7 @@
@import "../../../colors";
@import "../../../frameless";
.expect {
.flex-row {
align-items: flex-start;
justify-content: space-between;
@ -172,3 +173,4 @@
}
}
}
}

View file

@ -6,6 +6,7 @@
min-height: initial;
}
.index {
.title-banner {
margin-bottom: 0;
background-image: url("/images/conference/index/title-banner.jpg");
@ -55,8 +56,6 @@
}
}
}
.index {
.flex-row {
align-items: flex-start;

View file

@ -1,6 +1,7 @@
@import "../../../colors";
@import "../../../frameless";
.plan {
section {
border-bottom: 2px solid $ui-border;
@ -109,3 +110,4 @@ section {
}
}
}
}

View file

@ -0,0 +1,281 @@
var React = require('react');
var render = require('../../lib/render.jsx');
var Page = require('../../components/page/www/page.jsx');
var FlexRow = require('../../components/flex-row/flex-row.jsx');
var SubNavigation = require('../../components/subnavigation/subnavigation.jsx');
var TitleBanner = require('../../components/title-banner/title-banner.jsx');
require('./developers.scss');
var Developers = React.createClass({
type: 'About',
render: function () {
return (
<div className="developers">
<TitleBanner className="masthead">
<div className="inner">
<h1>Scratch for Developers</h1>
<p className="intro">
On this page, youll find information about open source projects created and maintained{' '}
by the <a href="https://scratch.mit.edu/info/credits">Scratch Team at MIT</a>, as well{' '}
as our thoughts on best practices for designing learning experiences for children.
</p>
</div>
<div className="band">
<SubNavigation className="inner">
<a href="#projects">
<li>
Projects
</li>
</a>
<a href="#principles">
<li>
Principles
</li>
</a>
<a href="#donate">
<li>
Donate
</li>
</a>
<a href="#partners">
<li>
Partners
</li>
</a>
<a href="#faq">
<li>
FAQ
</li>
</a>
</SubNavigation>
</div>
</TitleBanner>
<div className="inner">
<section id="projects">
<span className="nav-spacer"></span>
<h2>Projects</h2>
<p className="intro">
The following projects are open source and available for any purpose.
</p>
<FlexRow className="sidebar-row">
<div className="body-copy column">
<h3>Scratch Blocks</h3>
<p>
Scratch Blocks is a new development project for the next generation of{' '}
graphical programming blocks, based on a collaboration between Google and MITs{' '}
Scratch Team building on Googles{' '}
<a href="https://developers.google.com/blockly/">Blockly technology</a>{' '}
and informed by the Scratch Teams expertise in developing creative{' '}
learning tools for young people. Scratch Blocks will provide a framework{' '}
for building programming blocks in both vertical (text-based) and horizontal{' '}
(icon-based) formats. You can access the code (currently as a{' '}
developer-preview) and documentation{' '}
<a href="https://github.com/llk/scratch-blocks">here</a>.
</p>
<p>
This first release includes code for Scratchs Horizontal Grammar. Looking{' '}
ahead, we plan to release additional code including but not limited to the{' '}
Vertical Grammar (currently used by Scratch), a new Rendering Engine to support{' '}
sprites and graphic effects, and a new Audio Engine to support creation with{' '}
sound and music.
</p>
</div>
<img className="sidebar column" src="/images/developers/block-sketch.png" alt="blocks" />
</FlexRow>
<FlexRow className="sidebar-row">
<div className="body-copy column">
<h3>Scratch WWW</h3>
<p>
Scratch-www is a standalone web client for the Scratch Community, built{' '}
using React and Redux. Access the code and documentation{' '}
<a href="https://github.com/LLK/scratch-www">here</a>.
</p>
</div>
<img className="sidebar column" src="/images/developers/www-sketch.png" alt="www" />
</FlexRow>
</section>
<section id="principles">
<span className="nav-spacer"></span>
<h2>Principles</h2>
<p className="intro">
We created Scratch to empower young people to think creatively, reason systematically,{' '}
and work collaboratively. We are guided by a set of <b>Learning Principles</b> and{' '}
<b>Design Principles</b> that we hope you will follow as you develop new tools and{' '}
technologies with Scratch Blocks.
</p>
<FlexRow className="sidebar-row">
<div className="body-copy column">
<h3>Learning Principles</h3>
<dl>
<dt>Projects</dt>
<dd>
People learn best when they are actively working on projects generating{' '}
new ideas, designing prototypes, making improvements and creating final{' '}
products.
</dd>
<dt>Passion</dt>
<dd>
When people focus on things they care about, they work longer and harder,{' '}
persist in the face of challenges, and learn more in the process.
</dd>
<dt>Peers</dt>
<dd>
Learning flourishes as a social activity, with people sharing ideas,{' '}
collaborating on projects, and building on one another's work.
</dd>
<dt>Play</dt>
<dd>
Learning involves playful experimentation trying new things, tinkering{' '}
with materials, testing boundaries, taking risks, iterating again and again.
</dd>
</dl>
</div>
</FlexRow>
<FlexRow className="sidebar-row">
<div className="body-copy column">
<h3>Design Principles</h3>
<dl>
<dt>Low Floor & Wide Walls</dt>
<dd>
In order to encourage a varied and diverse set of interactions, we{' '}
explicitly include elements and features that are easy for kids to{' '}
understand (low floor), but general enough to support diverse uses (wide walls).
</dd>
<dt>Make it as Simple as Possible And Maybe Even Simpler</dt>
<dd>
Despite the common drive to add more features to software products, we{' '}
have found that reducing the number of features often improves the user{' '}
experience. What initially seems like a constraint or limitation can foster{' '}
new forms of creativity.
</dd>
<dt>Many Paths, Many Styles</dt>
<dd>
Many math and science activities have traditionally been biased towards{' '}
specific populations. By paying special attention to creating accessible{' '}
and appealing technologies, we are working to close the gap.
</dd>
<dt>Design for Tinkerability</dt>
<dd>
We believe that the learning process is inherently iterative. Tinkerers{' '}
start by exploring and experimenting, then revising and refining their{' '}
goals and creations. To support this style of interaction, we design{' '}
our interfaces to encourage quick experimentation and rapid cycles of iteration.
</dd>
</dl>
</div>
</FlexRow>
</section>
<section id="donate">
<span className="nav-spacer"></span>
<h2>Donate</h2>
<p>
We are pleased to provide Scratch free of charge. If you enjoy using Scratch, please{' '}
consider <a href="https://secure.donationpay.org/scratchfoundation/">making a donation{' '}
to support Scratch</a>. Donations of any size are appreciated.
</p>
<p>
Your donation to the Scratch Foundation will be used to support future development of{' '}
Scratch software and the Scratch website.
</p>
<p>
Thanks for supporting Scratch!
</p>
</section>
<section id="partners">
<span className="nav-spacer"></span>
<h3>Partners</h3>
<p>
The creation and maintenance of this open source code would not be possible without{' '}
generous technical and financial support from our partners:
</p>
<FlexRow className="logos">
<img className="logo" src="/images/developers/google.png" alt="google" />
<img className="logo" src="/images/developers/intel.png" alt="intel" />
<img className="logo" src="/images/developers/cn.png" alt="cartoon network" />
<img className="logo" src="/images/developers/lemann.png" alt="lemann foundation" />
</FlexRow>
</section>
</div>
<TitleBanner className="faq-banner">
<div className="inner">
<section id="faq">
<span className="nav-spacer"></span>
<h3>FAQ</h3>
<FlexRow className="three-col-row">
<div className="faq column">
<h4>Where can I learn more about Scratch?</h4>
<p>
Scratch is a free programming language and online community where young{' '}
people can create their own interactive stories, games, and animations.{' '}
Scratch is a project of the{' '}
<a href="https://llk.media.mit.edu/">Lifelong Kindergarten</a>{' '}
Group at the <a href="http://media.mit.edu/">MIT Media Lab</a>.{' '}
You can learn more about Scratch{' '}
<a href="https://scratch.mit.edu/about">here</a>.
</p>
</div>
<div className="faq column">
<h4>Are there rules to using this code in my application?</h4>
<p>
You may use this code in accordance with the{' '}
<a href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0</a> license
which governs this project. We also strongly encourage you to consider{' '}
the learning and design principles (above, on this page) when building{' '}
creative learning experiences for kids of all ages.
</p>
</div>
<div className="faq column">
<h4>
Am I allowed to use the name "Scratch Blocks" in the description of my{' '}
app and other public messaging?
</h4>
<p>
If you wish, you can publicly state that your application is powered by{' '}
Scratch Blocks. If you do so, we would also encourage you to link back to{' '}
code repository.
</p>
</div>
<div className="faq column">
<h4>Are you releasing more code and when?</h4>
<p>
We plan to open source additional code relating to the Scratch programming{' '}
language over the next few months. Keep an eye on this page!
</p>
</div>
<div className="faq column">
<h4>Whats the difference between Blockly and Scratch Blocks?</h4>
<p>
Scratch Blocks builds upon the Blockly code base, and is specifically{' '}
designed with our principles in mind to support creative learning experiences.
</p>
</div>
<div className="faq column">
<h4>Id like to collaborate. How do I get in touch?</h4>
<p>
You can reach us over on <a href="https://github.com/LLK/">github</a> or{' '}
you can send an email to{' '}
<a href="mailto:help@scratch.mit.edu">help@scratch.mit.edu.</a>{' '}
We look forward to hearing from you!
</p>
</div>
</FlexRow>
</section>
</div>
</TitleBanner>
</div>
);
}
});
render(<Page><Developers /></Page>, document.getElementById('app'));

View file

@ -0,0 +1,246 @@
@import "../../colors";
@import "../../frameless";
$developer-spot: $ui-aqua;
#view {
padding: 0;
}
.developers {
.title-banner {
&.masthead {
background-color: $developer-spot;
padding-bottom: 0;
h1 {
margin: 0 0 2rem 0;
text-align: left;
color: $ui-white;
}
p {
margin: 0;
width: $cols6;
text-align: left;
color: $ui-white;
a {
border-bottom: 1px solid $ui-white;
color: $ui-white;
}
}
.band {
$band-color: hsla(360, 100, 100, .15);
margin-top: 2rem;
background-color: $band-color;
padding: 1rem 0;
}
.sub-nav {
text-align: left;
justify-content: flex-start;
li {
margin: 0 .5rem 0 0;
}
}
}
&.faq-banner {
margin-bottom: 0;
background-color: $ui-gray;
}
}
.flex-row {
&.sidebar-row {
margin: 2rem 0;
justify-content: space-between;
align-items: flex-start;
.body-copy {
width: $cols8;
}
.sidebar {
width: $cols3;
}
}
&.three-col-row {
align-items: flex-start;
justify-content: flex-start;
flex-wrap: wrap;
.column {
$column-margin: 1rem;
margin: $column-margin;
width: calc(#{$cols4} - (#{$column-margin} * 2));
p {
text-align: left;
}
}
}
}
section {
margin-bottom: 3rem;
p {
max-width: $cols8;
}
}
#projects,
#principles,
#donate,
#partners,
#faq {
.nav-spacer {
display: block;
visibility: hidden;
margin-top: -50px; // height of nav bar
height: 50px;
}
}
#projects,
#principles,
#donate {
h3 {
border-bottom: 1px solid $ui-border;
}
dl {
dt {
margin-bottom: .25rem;
}
dd {
margin-bottom: 1.25rem;
margin-left: 0;
}
}
}
#donate {
border-bottom: 1px solid $ui-border;
padding-bottom: 2rem;
}
#partners {
text-align: center;
p {
margin: 0 auto;
margin-bottom: 2rem;
}
.logos {
justify-content: center;
.logo {
margin: 10px;
width: $cols2;
}
}
}
#faq {
border-bottom: 1px solid $ui-border;
padding-bottom: 2rem;
h3 {
margin-bottom: 2rem;
text-align: center;
}
p {
color: $type-gray;
}
}
}
//4 columns
@media only screen and (max-width: $mobile - 1) {
#view {
text-align: left;
}
.title-banner {
&.masthead {
padding-bottom: 2rem;
}
.band {
display: none;
}
}
.flex-row {
&.sidebar-row {
.body-copy {
width: 100%;
}
}
}
}
//6 columns
@media only screen and (min-width: $mobile) and (max-width: $tablet - 1) {
#view {
text-align: left;
}
.flex-row {
&.sidebar-row {
.body-copy {
width: 100%;
}
.sidebar {
margin: 0 auto;
}
}
}
}
//8 columns
@media only screen and (min-width: $tablet) and (max-width: $desktop - 1) {
#view {
text-align: left;
}
.flex-row {
&.sidebar-row {
.body-copy {
width: 100%;
}
.sidebar {
margin: 0 auto;
}
}
}
section {
p {
width: 100%;
}
}
}

View file

@ -0,0 +1 @@
{}

View file

@ -0,0 +1,192 @@
var React = require('react');
var render = require('../../lib/render.jsx');
var Page = require('../../components/page/www/page.jsx');
var Box = require('../../components/box/box.jsx');
var Privacypolicy = React.createClass({
type: 'Privacypolicy',
render: function () {
return (
<div className="inner privacypolicy">
<Box title={'Scratch Privacy Policy'}>
<p>
We made Scratch so people like you could create projects,
share ideas, and build a community. To make this happen,
we collect some information for our users. The Scratch Team
understands how important privacy is to our community,
especially kids and parents. We wrote this privacy policy
to explain what information we collect, how we use it,
and what we're doing to keep it safe. If you have any
questions regarding this privacy policy, you can{' '}
<a href="/contact-us">contact us</a>.
</p>
<p><i>
Please do not share personal contact information, such as
your name, physical address, email address, phone number,
or anything else that can be used to make contact outside
of the Scratch website. Please report projects, comments,
or forum posts that contain this kind of information so
the Scratch team can remove it, and please remind the
author of our policy.
</i></p>
<h3>What information does the Scratch Team collect about me?</h3>
<p>
<b>Account Information: </b>
In order to build projects or comment on other users' projects,
you need to make an account. During account creation, we ask you
for a username, your country, birth month and year, gender, and
your email address (or your parent or guardian's email address if
you are under 13 years old). We ask that you select a user name
that does not disclose your real name or other information that
could identify you. Other users can see your username and country,
but not your age, gender, or email address.
</p>
<p>
<b>User-generated Content: </b>
All of your Scratch projects, comments, and forum posts are stored
on the Scratch servers. Other users can see your shared projects,
comments, and forum posts, along with your username. Because the
Scratch Team is responsible for moderation, we have access to all
content stored on the Scratch website, including unshared projects.
If you prefer to work on projects in complete privacy, you can use
either the <a href="/scratch2download">Scratch 2 offline editor</a>{' '}
or <a href="/scratch_1.4">Scratch 1.4</a>.
</p>
<p>
<b>Usage Information: </b>
When you use Scratch, our servers will automatically store a limited
amount of information about how you use the website. This information
includes a number that identifies your computer (the IP address), which
pages you visited, and what browser you are using.
</p>
<p>
<b>Google Analytics: </b>
We also collect some data on where you click and which parts of the
site you visit using Google Analytics. This "click data" helps us figure
out ways to improve the website. Information collected and processed by
Google Analytics includes the user's IP address, network location, and
geographic location. Google Analytics acquires all its information
directly from the user, by installing a cookie (see below) on your
computer, if you have enabled JavaScript. Scratch does not share any
information it collects with Google, and Google does not collect any
personal identifying information about you.
</p>
<p>
<b>Cookies: </b>
When you log in, the Scratch website asks your browser to put an http
"cookie" on your computer. The cookie is actually a small text file
that our site can send to your browser for storage on your computer.
This allows the website to remember that you are logged in when you
go to a different page.
</p>
<h3>How does the Scratch Team use my information?</h3>
<ul>
<li>
We collect age and gender data so that we know who is using our
website.
</li>
<li>
If you forget your password, we will ask you to disclose to us
your birth month and year so that we can verify your account, and
your email address so that we can send you a new password.
</li>
<li>
We will use your email address to respond to messages you send us
or to communicate with you about the Scratch service or your account.
</li>
<li>
We send out occasional email updates about Scratch to the confirmed
email address on your account. Scratch will never sell or share your
email address without your permission. You can unsubscribe from these
updates by clicking the unsubscribe link found at the bottom of the
email.
</li>
<li>
Parents and guardians who register their under-13 year olds for
Scratch may also receive additional updates from the{' '}
<a href="http://www.codetolearn.org/">Scratch Foundation</a>,
a non-profit that supports Scratch educational initiatives.
The Scratch Foundation will never sell or share your email
address without your permission. You can unsubscribe from these
updates by clicking the unsubscribe link found at the bottom of
the email.
</li>
<li>
If we detect repeated abusive behavior from your account, IP address,
or email address, we may share your account name, IP address, and the
time and content of the abusive behavior with the IP address owner
(such as a school or internet service provided).
</li>
<li>
We may use de-identified location, age, gender, and usage data
in research studies intended to improve our understanding of
how people learn with Scratch. The results of this research are
shared with educators and researchers through conferences,
journals, and other publications. You can find out more on our{' '}
<a href="/info/research">Research page</a>.
</li>
<li>
We may disclose some of the information we collect to third-party
service providers that help us manage communications to and from
the Scratch website and improve website performance. We are
satisfied that these service providers have privacy policies that
restrict them from further disclosing any of your information.
</li>
<li>
Other than as described above, we will never share personally
identifiable information about you with any other person,
company, or organization, except:
<ul>
<li>
As required to comply with our obligations under the law.
</li>
<li>
For technical reasons, if we are required to transfer the
data on our servers to another location or organization.
</li>
</ul>
</li>
</ul>
<h3>How can I update my personal information?</h3>
<p>
You can update your password, email address, and country through
the <a href="/account/password_change">Account Settings</a> page.
You can also reset your password through the{' '}
<a href="/account/password_reset">Account Reset</a>{' '}
page. You cannot change your username, but you can make a new
account and manually copy your projects to the new account.
</p>
<p>
If you want to delete your account entirely, log in to Scratch,
and then click your username in the top right-hand corner. Select
"Account Settings," then click the "I want to delete my account"
link at the bottom of the page.
</p>
<h3>How does the Scratch Team protect my information?</h3>
<p>
The Scratch Team has in place physical and electronic procedures
to protect the information we collect on the Scratch website. We
strictly limit individual access to the Scratch servers and the
data we store on them. However, as effective as these measures
are, no security system is impenetrable. We cannot completely
guarantee the security of our database, nor can we guarantee that
the information you supply will not be intercepted while being
transmitted to us over the Internet.
</p>
<h3>Notifications of Changes to the Privacy Policy</h3>
<p>
We review our security measures and Privacy Policy on a periodic
basis, and we may modify our policies as appropriate. We may also
change or update our Privacy Policy if we add new services or
features. If we make any changes to our privacy practices, we will
amend this Privacy Policy accordingly and post the amended policy
on the Scratch website. We encourage you to review our Privacy
Policy on a regular basis.
</p>
</Box>
</div>
);
}
});
render(<Page><Privacypolicy /></Page>, document.getElementById('app'));

View file

@ -4,7 +4,7 @@ var omit = require('lodash.omit');
var React = require('react');
var render = require('../../lib/render.jsx');
var authActions = require('../../redux/auth.js');
var authActions = require('../../redux/actions.js');
var Api = require('../../mixins/api.jsx');

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

File diff suppressed because one or more lines are too long

View file

@ -1,42 +0,0 @@
/**
* ReactDOM v0.14.0
*
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
;(function(f) {
// CommonJS
if (typeof exports === "object" && typeof module !== "undefined") {
module.exports = f(require('react'));
// RequireJS
} else if (typeof define === "function" && define.amd) {
define(['react'], f);
// <script>
} else {
var g
if (typeof window !== "undefined") {
g = window;
} else if (typeof global !== "undefined") {
g = global;
} else if (typeof self !== "undefined") {
g = self;
} else {
// works providing we're not in "use strict";
// needed for Java 8 Nashorn
// see https://github.com/facebook/react/issues/3037
g = this;
}
g.ReactDOM = f(g.React);
}
})(function(React) {
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
});

View file

@ -1,12 +0,0 @@
/**
* ReactDOM v0.14.0
*
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e(require("react"));else if("function"==typeof define&&define.amd)define(["react"],e);else{var f;f="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,f.ReactDOM=e(f.React)}}(function(e){return e.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

20707
static/js/lib/react.js vendored

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,775 +0,0 @@
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Redux"] = factory();
else
root["Redux"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
exports.compose = exports.applyMiddleware = exports.bindActionCreators = exports.combineReducers = exports.createStore = undefined;
var _createStore = __webpack_require__(2);
var _createStore2 = _interopRequireDefault(_createStore);
var _combineReducers = __webpack_require__(7);
var _combineReducers2 = _interopRequireDefault(_combineReducers);
var _bindActionCreators = __webpack_require__(6);
var _bindActionCreators2 = _interopRequireDefault(_bindActionCreators);
var _applyMiddleware = __webpack_require__(5);
var _applyMiddleware2 = _interopRequireDefault(_applyMiddleware);
var _compose = __webpack_require__(1);
var _compose2 = _interopRequireDefault(_compose);
var _warning = __webpack_require__(3);
var _warning2 = _interopRequireDefault(_warning);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
/*
* This is a dummy function to check if the function name has been altered by minification.
* If the function has been minified and NODE_ENV !== 'production', warn the user.
*/
function isCrushed() {}
if (("development") !== 'production' && typeof isCrushed.name === 'string' && isCrushed.name !== 'isCrushed') {
(0, _warning2["default"])('You are currently using minified code outside of NODE_ENV === \'production\'. ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) ' + 'to ensure you have the correct code for your production build.');
}
exports.createStore = _createStore2["default"];
exports.combineReducers = _combineReducers2["default"];
exports.bindActionCreators = _bindActionCreators2["default"];
exports.applyMiddleware = _applyMiddleware2["default"];
exports.compose = _compose2["default"];
/***/ },
/* 1 */
/***/ function(module, exports) {
"use strict";
exports.__esModule = true;
exports["default"] = compose;
/**
* Composes single-argument functions from right to left.
*
* @param {...Function} funcs The functions to compose.
* @returns {Function} A function obtained by composing functions from right to
* left. For example, compose(f, g, h) is identical to arg => f(g(h(arg))).
*/
function compose() {
for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {
funcs[_key] = arguments[_key];
}
return function () {
if (funcs.length === 0) {
return arguments.length <= 0 ? undefined : arguments[0];
}
var last = funcs[funcs.length - 1];
var rest = funcs.slice(0, -1);
return rest.reduceRight(function (composed, f) {
return f(composed);
}, last.apply(undefined, arguments));
};
}
/***/ },
/* 2 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
exports.ActionTypes = undefined;
exports["default"] = createStore;
var _isPlainObject = __webpack_require__(4);
var _isPlainObject2 = _interopRequireDefault(_isPlainObject);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
/**
* These are private action types reserved by Redux.
* For any unknown actions, you must return the current state.
* If the current state is undefined, you must return the initial state.
* Do not reference these action types directly in your code.
*/
var ActionTypes = exports.ActionTypes = {
INIT: '@@redux/INIT'
};
/**
* Creates a Redux store that holds the state tree.
* The only way to change the data in the store is to call `dispatch()` on it.
*
* There should only be a single store in your app. To specify how different
* parts of the state tree respond to actions, you may combine several reducers
* into a single reducer function by using `combineReducers`.
*
* @param {Function} reducer A function that returns the next state tree, given
* the current state tree and the action to handle.
*
* @param {any} [initialState] The initial state. You may optionally specify it
* to hydrate the state from the server in universal apps, or to restore a
* previously serialized user session.
* If you use `combineReducers` to produce the root reducer function, this must be
* an object with the same shape as `combineReducers` keys.
*
* @param {Function} enhancer The store enhancer. You may optionally specify it
* to enhance the store with third-party capabilities such as middleware,
* time travel, persistence, etc. The only store enhancer that ships with Redux
* is `applyMiddleware()`.
*
* @returns {Store} A Redux store that lets you read the state, dispatch actions
* and subscribe to changes.
*/
function createStore(reducer, initialState, enhancer) {
if (typeof initialState === 'function' && typeof enhancer === 'undefined') {
enhancer = initialState;
initialState = undefined;
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.');
}
return enhancer(createStore)(reducer, initialState);
}
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.');
}
var currentReducer = reducer;
var currentState = initialState;
var currentListeners = [];
var nextListeners = currentListeners;
var isDispatching = false;
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice();
}
}
/**
* Reads the state tree managed by the store.
*
* @returns {any} The current state tree of your application.
*/
function getState() {
return currentState;
}
/**
* Adds a change listener. It will be called any time an action is dispatched,
* and some part of the state tree may potentially have changed. You may then
* call `getState()` to read the current state tree inside the callback.
*
* You may call `dispatch()` from a change listener, with the following
* caveats:
*
* 1. The subscriptions are snapshotted just before every `dispatch()` call.
* If you subscribe or unsubscribe while the listeners are being invoked, this
* will not have any effect on the `dispatch()` that is currently in progress.
* However, the next `dispatch()` call, whether nested or not, will use a more
* recent snapshot of the subscription list.
*
* 2. The listener should not expect to see all states changes, as the state
* might have been updated multiple times during a nested `dispatch()` before
* the listener is called. It is, however, guaranteed that all subscribers
* registered before the `dispatch()` started will be called with the latest
* state by the time it exits.
*
* @param {Function} listener A callback to be invoked on every dispatch.
* @returns {Function} A function to remove this change listener.
*/
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.');
}
var isSubscribed = true;
ensureCanMutateNextListeners();
nextListeners.push(listener);
return function unsubscribe() {
if (!isSubscribed) {
return;
}
isSubscribed = false;
ensureCanMutateNextListeners();
var index = nextListeners.indexOf(listener);
nextListeners.splice(index, 1);
};
}
/**
* Dispatches an action. It is the only way to trigger a state change.
*
* The `reducer` function, used to create the store, will be called with the
* current state tree and the given `action`. Its return value will
* be considered the **next** state of the tree, and the change listeners
* will be notified.
*
* The base implementation only supports plain object actions. If you want to
* dispatch a Promise, an Observable, a thunk, or something else, you need to
* wrap your store creating function into the corresponding middleware. For
* example, see the documentation for the `redux-thunk` package. Even the
* middleware will eventually dispatch plain object actions using this method.
*
* @param {Object} action A plain object representing what changed. It is
* a good idea to keep actions serializable so you can record and replay user
* sessions, or use the time travelling `redux-devtools`. An action must have
* a `type` property which may not be `undefined`. It is a good idea to use
* string constants for action types.
*
* @returns {Object} For convenience, the same action object you dispatched.
*
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
* return something else (for example, a Promise you can await).
*/
function dispatch(action) {
if (!(0, _isPlainObject2["default"])(action)) {
throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
}
if (typeof action.type === 'undefined') {
throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}
try {
isDispatching = true;
currentState = currentReducer(currentState, action);
} finally {
isDispatching = false;
}
var listeners = currentListeners = nextListeners;
for (var i = 0; i < listeners.length; i++) {
listeners[i]();
}
return action;
}
/**
* Replaces the reducer currently used by the store to calculate the state.
*
* You might need this if your app implements code splitting and you want to
* load some of the reducers dynamically. You might also need this if you
* implement a hot reloading mechanism for Redux.
*
* @param {Function} nextReducer The reducer for the store to use instead.
* @returns {void}
*/
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.');
}
currentReducer = nextReducer;
dispatch({ type: ActionTypes.INIT });
}
// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
dispatch({ type: ActionTypes.INIT });
return {
dispatch: dispatch,
subscribe: subscribe,
getState: getState,
replaceReducer: replaceReducer
};
}
/***/ },
/* 3 */
/***/ function(module, exports) {
'use strict';
exports.__esModule = true;
exports["default"] = warning;
/**
* Prints a warning in the console if it exists.
*
* @param {String} message The warning message.
* @returns {void}
*/
function warning(message) {
/* eslint-disable no-console */
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(message);
}
/* eslint-enable no-console */
try {
// This error was thrown as a convenience so that you can use this stack
// to find the callsite that caused this warning to fire.
throw new Error(message);
/* eslint-disable no-empty */
} catch (e) {}
/* eslint-enable no-empty */
}
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
var isHostObject = __webpack_require__(8),
isObjectLike = __webpack_require__(9);
/** `Object#toString` result references. */
var objectTag = '[object Object]';
/** Used for built-in method references. */
var objectProto = Object.prototype;
/** Used to resolve the decompiled source of functions. */
var funcToString = Function.prototype.toString;
/** Used to infer the `Object` constructor. */
var objectCtorString = funcToString.call(Object);
/**
* Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
* of values.
*/
var objectToString = objectProto.toString;
/** Built-in value references. */
var getPrototypeOf = Object.getPrototypeOf;
/**
* Checks if `value` is a plain object, that is, an object created by the
* `Object` constructor or one with a `[[Prototype]]` of `null`.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
* @example
*
* function Foo() {
* this.a = 1;
* }
*
* _.isPlainObject(new Foo);
* // => false
*
* _.isPlainObject([1, 2, 3]);
* // => false
*
* _.isPlainObject({ 'x': 0, 'y': 0 });
* // => true
*
* _.isPlainObject(Object.create(null));
* // => true
*/
function isPlainObject(value) {
if (!isObjectLike(value) || objectToString.call(value) != objectTag || isHostObject(value)) {
return false;
}
var proto = objectProto;
if (typeof value.constructor == 'function') {
proto = getPrototypeOf(value);
}
if (proto === null) {
return true;
}
var Ctor = proto.constructor;
return (typeof Ctor == 'function' &&
Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
}
module.exports = isPlainObject;
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.__esModule = true;
exports["default"] = applyMiddleware;
var _compose = __webpack_require__(1);
var _compose2 = _interopRequireDefault(_compose);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
/**
* Creates a store enhancer that applies middleware to the dispatch method
* of the Redux store. This is handy for a variety of tasks, such as expressing
* asynchronous actions in a concise manner, or logging every action payload.
*
* See `redux-thunk` package as an example of the Redux middleware.
*
* Because middleware is potentially asynchronous, this should be the first
* store enhancer in the composition chain.
*
* Note that each middleware will be given the `dispatch` and `getState` functions
* as named arguments.
*
* @param {...Function} middlewares The middleware chain to be applied.
* @returns {Function} A store enhancer applying the middleware.
*/
function applyMiddleware() {
for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
middlewares[_key] = arguments[_key];
}
return function (createStore) {
return function (reducer, initialState, enhancer) {
var store = createStore(reducer, initialState, enhancer);
var _dispatch = store.dispatch;
var chain = [];
var middlewareAPI = {
getState: store.getState,
dispatch: function dispatch(action) {
return _dispatch(action);
}
};
chain = middlewares.map(function (middleware) {
return middleware(middlewareAPI);
});
_dispatch = _compose2["default"].apply(undefined, chain)(store.dispatch);
return _extends({}, store, {
dispatch: _dispatch
});
};
};
}
/***/ },
/* 6 */
/***/ function(module, exports) {
'use strict';
exports.__esModule = true;
exports["default"] = bindActionCreators;
function bindActionCreator(actionCreator, dispatch) {
return function () {
return dispatch(actionCreator.apply(undefined, arguments));
};
}
/**
* Turns an object whose values are action creators, into an object with the
* same keys, but with every function wrapped into a `dispatch` call so they
* may be invoked directly. This is just a convenience method, as you can call
* `store.dispatch(MyActionCreators.doSomething())` yourself just fine.
*
* For convenience, you can also pass a single function as the first argument,
* and get a function in return.
*
* @param {Function|Object} actionCreators An object whose values are action
* creator functions. One handy way to obtain it is to use ES6 `import * as`
* syntax. You may also pass a single function.
*
* @param {Function} dispatch The `dispatch` function available on your Redux
* store.
*
* @returns {Function|Object} The object mimicking the original object, but with
* every action creator wrapped into the `dispatch` call. If you passed a
* function as `actionCreators`, the return value will also be a single
* function.
*/
function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch);
}
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators) + '. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?');
}
var keys = Object.keys(actionCreators);
var boundActionCreators = {};
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var actionCreator = actionCreators[key];
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
}
}
return boundActionCreators;
}
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
exports.__esModule = true;
exports["default"] = combineReducers;
var _createStore = __webpack_require__(2);
var _isPlainObject = __webpack_require__(4);
var _isPlainObject2 = _interopRequireDefault(_isPlainObject);
var _warning = __webpack_require__(3);
var _warning2 = _interopRequireDefault(_warning);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
function getUndefinedStateErrorMessage(key, action) {
var actionType = action && action.type;
var actionName = actionType && '"' + actionType.toString() + '"' || 'an action';
return 'Reducer "' + key + '" returned undefined handling ' + actionName + '. ' + 'To ignore an action, you must explicitly return the previous state.';
}
function getUnexpectedStateShapeWarningMessage(inputState, reducers, action) {
var reducerKeys = Object.keys(reducers);
var argumentName = action && action.type === _createStore.ActionTypes.INIT ? 'initialState argument passed to createStore' : 'previous state received by the reducer';
if (reducerKeys.length === 0) {
return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';
}
if (!(0, _isPlainObject2["default"])(inputState)) {
return 'The ' + argumentName + ' has unexpected type of "' + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + '". Expected argument to be an object with the following ' + ('keys: "' + reducerKeys.join('", "') + '"');
}
var unexpectedKeys = Object.keys(inputState).filter(function (key) {
return !reducers.hasOwnProperty(key);
});
if (unexpectedKeys.length > 0) {
return 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('"' + unexpectedKeys.join('", "') + '" found in ' + argumentName + '. ') + 'Expected to find one of the known reducer keys instead: ' + ('"' + reducerKeys.join('", "') + '". Unexpected keys will be ignored.');
}
}
function assertReducerSanity(reducers) {
Object.keys(reducers).forEach(function (key) {
var reducer = reducers[key];
var initialState = reducer(undefined, { type: _createStore.ActionTypes.INIT });
if (typeof initialState === 'undefined') {
throw new Error('Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.');
}
var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.');
if (typeof reducer(undefined, { type: type }) === 'undefined') {
throw new Error('Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.');
}
});
}
/**
* Turns an object whose values are different reducer functions, into a single
* reducer function. It will call every child reducer, and gather their results
* into a single state object, whose keys correspond to the keys of the passed
* reducer functions.
*
* @param {Object} reducers An object whose values correspond to different
* reducer functions that need to be combined into one. One handy way to obtain
* it is to use ES6 `import * as reducers` syntax. The reducers may never return
* undefined for any action. Instead, they should return their initial state
* if the state passed to them was undefined, and the current state for any
* unrecognized action.
*
* @returns {Function} A reducer function that invokes every reducer inside the
* passed object, and builds a state object with the same shape.
*/
function combineReducers(reducers) {
var reducerKeys = Object.keys(reducers);
var finalReducers = {};
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i];
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key];
}
}
var finalReducerKeys = Object.keys(finalReducers);
var sanityError;
try {
assertReducerSanity(finalReducers);
} catch (e) {
sanityError = e;
}
return function combination() {
var state = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var action = arguments[1];
if (sanityError) {
throw sanityError;
}
if (true) {
var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action);
if (warningMessage) {
(0, _warning2["default"])(warningMessage);
}
}
var hasChanged = false;
var nextState = {};
for (var i = 0; i < finalReducerKeys.length; i++) {
var key = finalReducerKeys[i];
var reducer = finalReducers[key];
var previousStateForKey = state[key];
var nextStateForKey = reducer(previousStateForKey, action);
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(key, action);
throw new Error(errorMessage);
}
nextState[key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
}
return hasChanged ? nextState : state;
};
}
/***/ },
/* 8 */
/***/ function(module, exports) {
/**
* Checks if `value` is a host object in IE < 9.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a host object, else `false`.
*/
function isHostObject(value) {
// Many host objects are `Object` objects that can coerce to strings
// despite having improperly defined `toString` methods.
var result = false;
if (value != null && typeof value.toString != 'function') {
try {
result = !!(value + '');
} catch (e) {}
}
return result;
}
module.exports = isHostObject;
/***/ },
/* 9 */
/***/ function(module, exports) {
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
module.exports = isObjectLike;
/***/ }
/******/ ])
});
;

File diff suppressed because one or more lines are too long

View file

@ -35,7 +35,16 @@ VersionPlugin.prototype.apply = function (compiler) {
// Prepare all entry points
var entry = {
init: './src/init.js'
common: [
// Vendor
'raven-js',
'react',
'react-dom',
'react-intl',
'redux',
// Init
'./src/init.js'
]
};
routes.forEach(function (route) {
if (!route.redirect) {
@ -47,13 +56,6 @@ routes.forEach(function (route) {
module.exports = {
entry: entry,
devtool: 'source-map',
externals: {
'react': 'React',
'react/addons': 'React',
'react-dom': 'ReactDOM',
'react-intl': 'ReactIntl',
'redux': 'Redux'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: 'js/[name].bundle.js'
@ -101,6 +103,11 @@ module.exports = {
warnings: false
}
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"' + (process.env.NODE_ENV || 'development') + '"',
'process.env.SENTRY_DSN': '"' + (process.env.SENTRY_DSN || '') + '"'
}),
new webpack.optimize.CommonsChunkPlugin('common', 'js/common.bundle.js'),
new webpack.optimize.OccurenceOrderPlugin()
]
};