Modules pass

This commit is contained in:
Tim Mickel 2016-01-12 15:08:37 -05:00
parent f22472f8de
commit 41522cf4f1
12 changed files with 4793 additions and 906 deletions

View file

@ -1,5 +1,7 @@
{
"parser": "babel-eslint",
"rules": {
"strict": 0,
"curly": [2, "multi-line"],
"eol-last": [2],
"indent": [2, 4],
@ -20,42 +22,10 @@
"AndroidInterface": true,
"window": true,
"Cookie": true,
"getUrlVars": true,
"libInit": true,
"vlen": true,
"gn": true,
"CSSTransition": true,
"CSSTransition3D": true,
"WebKitCSSMatrix": true,
"globalx": true,
"globaly": true,
"localx": true,
"localy": true,
"getIdFor": true,
"hitRect": true,
"hit3DRect": true,
"rgb2hsb": true,
"colorToRGBA": true,
"drawScaled": true,
"getDocumentHeight": true,
"getDocumentWidth": true,
"setCanvasSizeScaledToWindowDocumentHeight": true,
"newHTML": true,
"newCanvas": true,
"newDiv": true,
"newP": true,
"newTextInput": true,
"newImage": true,
"getStringSize": true,
"setCanvasSize": true,
"setProps": true,
"frame": true,
"writeText": true,
"fitInRect": true,
"rgbToHex": true,
"Vector": true,
"DrawPath": true,
"drawThumbnail": true,
"ScratchJr": true,
"Runtime": true,
"Localization": true,
@ -93,7 +63,6 @@
"Lobby": true,
"Samples": true,
"Camera": true,
"getIdForCamera": true,
"Ghost": true,
"Layers": true,
"Paint": true,
@ -106,14 +75,9 @@
"Transform": true,
"Layer": true,
"Path": true,
"DEGTOR": true,
"xform": true,
"selxform": true,
"SVG2Canvas": true,
"isTablet": true,
"isiOS": true,
"isAndroid": true,
"scaleMultiplier": true,
"JSZip": true,
"Snap": true,
"IntlMessageFormat": true,

View file

@ -11,23 +11,13 @@
<script type="text/javascript" src="jssource/utils/Cookie.js"></script>
<script type="text/javascript" src="jssource/utils/lib.js"></script>
<script>
preprocessAndLoadCss("css", "css/font.css");
preprocessAndLoadCss("css", "css/base.css");
preprocessAndLoadCss("css", "css/editor.css");
preprocessAndLoadCss("css", "css/editorleftpanel.css");
preprocessAndLoadCss("css", "css/editorstage.css");
preprocessAndLoadCss("css", "css/editormodal.css");
preprocessAndLoadCss("css", "css/librarymodal.css");
preprocessAndLoadCss("css", "css/paintlook.css");
</script>
<!-- Localization includes -->
<script type="text/javascript" src="jssource/external/Intl/Intl.min.js"></script>
<script type="text/javascript" src="jssource/external/intl-messageformat/intl-messageformat.min.js"></script>
<script type="text/javascript" src="jssource/utils/Localization.js"></script>
<script>
Localization.includeLocales();
</script>
<!-- End localization includes -->
<script type="text/javascript" src="jssource/external/snap.svg-min.js"></script>
@ -91,23 +81,8 @@
<script type="text/javascript" src="jssource/painteditor/Layers.js"></script>
<script type="text/javascript" src="jssource/painteditor/Ghost.js"></script>
<script language="javascript">
function createScratchJr(){
iOS.getsettings(doNext);
function doNext (str){
var list = str.split(",");
iOS.path =list[1] == "0" ? list[0] + "/" : undefined ;
if (list.length > 2) Record.available = list[2] == "YES" ? true : false;
if (list.length > 3) Camera.available = list[3] == "YES" ? true : false;
ScratchJr.appinit(Settings.scratchJrVersion);
}
}
</script>
</head>
<body onload="iOS.waitForInterface(createScratchJr);" style="background: white;">
<body style="background: white;">
<div class="frame" id="frame"></div>
<div class="libframe" id="libframe"></div>
<div class="paintframe" id="paintframe"></div>

View file

@ -10,24 +10,20 @@
<head>
<title>ScratchJr Intro</title>
<script type="text/javascript" src="./Settings.js"></script>
<script type="text/javascript" src="jssource/utils/Cookie.js"></script>
<script type="text/javascript" src="jssource/utils/lib.js"></script>
<script type="text/javascript" src="jssource/build/bundles/index.bundle.js"></script>
<!--<script type="text/javascript" src="jssource/utils/Cookie.js"></script>
<script type="text/javascript" src="jssource/utils/lib.js"></script>-->
<!-- Localization includes -->
<script type="text/javascript" src="jssource/external/Intl/Intl.min.js"></script>
<!--<script type="text/javascript" src="jssource/external/Intl/Intl.min.js"></script>
<script type="text/javascript" src="jssource/external/intl-messageformat/intl-messageformat.min.js"></script>
<script type="text/javascript" src="jssource/utils/Localization.js"></script>
<script>
Localization.includeLocales();
</script>
</script>-->
<!-- End localization includes -->
<script type="text/javascript">
preprocessAndLoadCss("css", "css/font.css");
preprocessAndLoadCss("css", "css/base.css");
preprocessAndLoadCss("css", "css/start.css");
preprocessAndLoadCss("css", "css/thumbs.css");
</script>
<!--
<script type="text/javascript" src="jssource/utils/DrawPath.js"></script>
<script type="text/javascript" src="jssource/editor/ui/Alert.js"></script>
<script type="text/javascript" src="jssource/iPad/iOS.js"></script>
@ -40,80 +36,21 @@
<script type="text/javascript" src="jssource/painteditor/SVGImage.js"></script>
<script type="text/javascript" src="jssource/painteditor/Transform.js"></script>
<script type="text/javascript" src="jssource/painteditor/SVGTools.js"></script>
<script type="text/javascript" src="jssource/geom/Rectangle.js"></script>
<script language="javascript">
function startup(){
ScratchAudio.init();
var urlvars = getUrlVars();
if (urlvars["back"]) loadOptions();
else firstTime();
setTimeout(function(){gn('rays').className = "rays spinme";}, 250);
}
function firstTime() {
gn('authors').className = "credits show";
gn('authorsText').className = "creditsText show";
gn('purpleguy').className = "purple show";
gn('blueguy').className = "blue show";
gn('redguy').className = "red show";
iOS.askpermission(); // ask for sound recording
setTimeout(function(){iOS.hidesplash(doit);}, 500);
function doit (str){
ScratchAudio.sndFX("tap.wav");
window.ontouchend = function () {loadOptions();};
}
setTimeout(function(){loadOptions();}, 2000);
}
function loadOptions(){
gn('authors').className = "credits hide";
gn('authorsText').className = "creditsText hide";
gn('purpleguy').className = "purple hide";
gn('blueguy').className = "blue hide";
gn('redguy').className = "red hide";
gn('gettings').className = "gettings show";
gn('startcode').className = "startcode show";
document.ontouchmove = function(e){e.preventDefault()};
if (isAndroid) AndroidInterface.notifySplashDone();
}
function gohome(){
rays.className = 'rays';
// On iOS, sounds are loaded async, but the code as written expects to play tap.wav when we enter home.html
// (but since it isn't loaded yet, no sound is played).
// On Android, sync sounds means both calls to tap.wav result in a sound play.
// XXX: we should re-write the lobby loading to wait for the sounds to load, and not play a sound here.
if (isiOS) {
ScratchAudio.sndFX("tap.wav");
}
iOS.setfile("homescroll.sjr", 0, function (str) {doNext()});
function doNext() {window.location.href = "home.html";}
}
function gettingstarted(){
rays.className = 'rays';
ScratchAudio.sndFX("tap.wav");
window.location.href = "gettingstarted.html?place=home";
}
</script>
<script type="text/javascript" src="jssource/geom/Rectangle.js"></script>-->
</head>
<body onload="iOS.waitForInterface(startup);" style="margin:0px; background: black;">
<div class="frame" id="frame">
<div class="credits hide" id="authors"></div>
<div class="creditsText hide" id="authorsText"></div>
<div class="rays" id="rays"></div>
<div class="catface"></div>
<div class="jrlogo"></div>
<div class="purple hide" id="purpleguy"></div>
<div class="red hide" id="redguy"></div>
<div class="blue hide" id="blueguy"></div>
<div class="gettings hide" id="gettings" ontouchend="gettingstarted()"></div>
<div class="startcode hide" id="startcode" ontouchend="gohome()"></div>
</div>
</div>
<body style="margin:0px; background: black;">
<div class="frame" id="frame">
<div class="credits hide" id="authors"></div>
<div class="creditsText hide" id="authorsText"></div>
<div class="rays" id="rays"></div>
<div class="catface"></div>
<div class="jrlogo"></div>
<div class="purple hide" id="purpleguy"></div>
<div class="red hide" id="redguy"></div>
<div class="blue hide" id="blueguy"></div>
<div class="gettings hide" id="gettings"></div>
<div class="startcode hide" id="startcode"></div>
</div>
</body>
</html>

View file

@ -4,17 +4,26 @@
"description": "ScratchJr",
"private": "true",
"scripts": {
"lint": "eslint src/**"
"lint": "eslint src/**",
"build": "webpack"
},
"author": "MIT Media Lab",
"license": "MIT",
"devDependencies": {
"babel-core": "^6.4.0",
"babel-eslint": "^4.1.6",
"babel-loader": "^6.2.1",
"babel-preset-es2015": "^6.3.13",
"esformatter": "^0.8.1",
"esformatter-braces": "^1.2.1",
"esformatter-dot-notation": "^1.3.1",
"esformatter-quotes": "^1.0.3",
"esformatter-semicolons": "^1.1.2",
"eslint": "^1.10.3"
"eslint": "^1.10.3",
"webpack": "^1.12.11"
},
"dependencies": {}
"dependencies": {
"intl": "^1.0.1",
"intl-messageformat": "^1.2.0"
}
}

View file

@ -0,0 +1,819 @@
/******/ (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';
var _lib = __webpack_require__(1);
var _lib2 = _interopRequireDefault(_lib);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function createScratchJr() {
iOS.getsettings(doNext);
function doNext(str) {
var list = str.split(',');
iOS.path = list[1] == '0' ? list[0] + '/' : undefined;
if (list.length > 2) {
Record.available = list[2] == 'YES' ? true : false;
}
if (list.length > 3) {
Camera.available = list[3] == 'YES' ? true : false;
}
ScratchJr.appinit(Settings.scratchJrVersion);
}
}
window.onload = function () {
_lib2.default.preprocessAndLoadCss('css', 'css/font.css');
_lib2.default.preprocessAndLoadCss('css', 'css/base.css');
_lib2.default.preprocessAndLoadCss('css', 'css/editor.css');
_lib2.default.preprocessAndLoadCss('css', 'css/editorleftpanel.css');
_lib2.default.preprocessAndLoadCss('css', 'css/editorstage.css');
_lib2.default.preprocessAndLoadCss('css', 'css/editormodal.css');
_lib2.default.preprocessAndLoadCss('css', 'css/librarymodal.css');
_lib2.default.preprocessAndLoadCss('css', 'css/paintlook.css');
Localization.includeLocales();
iOS.waitForInterface(createScratchJr);
};
/***/ },
/* 1 */
/***/ function(module, exports) {
'use strict';
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
Object.defineProperty(exports, "__esModule", {
value: true
});
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var frame = exports.frame = undefined;
// XXX: isTablet is legacy code that can be used to detect if we're running on a desktop browser
// There are references to it throughout the codebase, should possibly be removed at some point
var isTablet = exports.isTablet = window.orientation != 'undefined';
var DEGTOR = exports.DEGTOR = Math.PI / 180;
var WINDOW_INNER_HEIGHT = exports.WINDOW_INNER_HEIGHT = window.innerHeight;
var WINDOW_INNER_WIDTH = exports.WINDOW_INNER_WIDTH = window.innerWidth;
var scaleMultiplier = exports.scaleMultiplier = WINDOW_INNER_HEIGHT / 768.0;
var isiOS = exports.isiOS = typeof AndroidInterface == 'undefined';
var isAndroid = exports.isAndroid = typeof AndroidInterface != 'undefined';
var Lib = function () {
function Lib() {
_classCallCheck(this, Lib);
}
_createClass(Lib, null, [{
key: 'libInit',
value: function libInit() {
exports.frame = frame = document.getElementById('frame');
}
/**
* Takes a string and evaluates all ${} as JavaScript and returns the resulting string.
*/
}, {
key: 'preprocess',
value: function preprocess(s) {
var result = '';
var len = s.length;
var i = 0;
var j;
while (i < len && (j = s.indexOf('$', i)) != -1) {
result += s.substring(i, j);
i = j + 1;
if (i < len - 1 && s[i] === '{') {
var start = i + 1;
var end = s.indexOf('}', start);
if (end != -1) {
var expression = s.substring(start, end);
result += eval(expression);
i = end + 1;
} else {
result += '$';
}
} else {
result += '$';
}
}
if (i < len) {
result += s.substring(i);
}
return result;
}
/**
* Load the URL synchronously (fine because it's file://), preprocess the result and return the string.
*/
}, {
key: 'preprocessAndLoad',
value: function preprocessAndLoad(url) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', url, false);
xmlhttp.send();
return this.preprocess(xmlhttp.responseText);
}
/**
* Load a CSS file, preprocess it using preprocessAndLoad() and then returns it as a style tag.
* Also rewrites all instances of url() with a different base
*/
}, {
key: 'preprocessAndLoadCss',
value: function preprocessAndLoadCss(baseUrl, url) {
document.write('<!-- ' + url + '-->\n');
document.write('<style type=\'text/css\'>\n');
var cssData = this.preprocessAndLoad(url);
cssData = cssData.replace(/url\('/g, 'url(\'' + baseUrl + '/');
cssData = cssData.replace(/url\(([^'])/g, 'url(' + baseUrl + '/$1');
document.write(cssData);
document.write('\n</style>\n');
}
}, {
key: 'rl',
value: function rl() {
window.location.reload();
}
}, {
key: 'newDiv',
value: function newDiv(parent, x, y, w, h, styles) {
var el = document.createElement('div');
el.style.position = 'absolute';
el.style.top = y + 'px';
el.style.left = x + 'px';
if (w) {
el.style.width = w + 'px';
}
if (h) {
el.style.height = h + 'px';
}
this.setProps(el.style, styles);
parent.appendChild(el);
return el;
}
}, {
key: 'newImage',
value: function newImage(parent, src, styles) {
var img = document.createElement('img');
img.src = src;
this.setProps(img.style, styles);
if (parent) {
parent.appendChild(img);
}
return img;
}
}, {
key: 'newCanvas',
value: function newCanvas(parent, x, y, w, h, styles) {
var canvas = document.createElement('canvas');
canvas.style.position = 'absolute';
canvas.style.top = y + 'px';
canvas.style.left = x + 'px';
this.setCanvasSize(canvas, w, h);
this.setProps(canvas.style, styles);
parent.appendChild(canvas);
return canvas;
}
}, {
key: 'newHTML',
value: function newHTML(type, c, p) {
var e = document.createElement(type);
if (c) {
e.setAttribute('class', c);
}
if (p) {
p.appendChild(e);
}
return e;
}
}, {
key: 'newP',
value: function newP(parent, text, styles) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(text));
this.setProps(p.style, styles);
parent.appendChild(p);
return p;
}
}, {
key: 'hitRect',
value: function hitRect(c, pt) {
if (!pt) {
return false;
}
if (!c) {
return false;
}
var x = pt.x;
var y = pt.y;
if (c.offsetLeft == undefined) {
return false;
}
if (c.offsetTop == undefined) {
return false;
}
if (x < c.offsetLeft) {
return false;
}
if (x > c.offsetLeft + c.offsetWidth) {
return false;
}
if (y < c.offsetTop) {
return false;
}
if (y > c.offsetTop + c.offsetHeight) {
return false;
}
return true;
}
}, {
key: 'hit3DRect',
value: function hit3DRect(c, pt) {
if (!pt) {
return;
}
var x = pt.x;
var y = pt.y;
var mtx = new WebKitCSSMatrix(window.getComputedStyle(c).webkitTransform);
if (mtx.m41 == undefined) {
return false;
}
if (mtx.m42 == undefined) {
return false;
}
if (x < mtx.m41) {
return false;
}
if (x > mtx.m41 + c.offsetWidth) {
return false;
}
if (y < mtx.m42) {
return false;
}
if (y > mtx.m42 + c.offsetHeight) {
return false;
}
return true;
}
}, {
key: 'hitTest',
value: function hitTest(c, pt) {
if (!pt) {
return;
}
var x = pt.x;
var y = pt.y;
if (x < c.offsetLeft) {
return false;
}
if (x > c.offsetLeft + c.offsetWidth) {
return false;
}
if (y < c.offsetTop) {
return false;
}
if (y > c.offsetTop + c.offsetHeight) {
return false;
}
var dx = pt.x - c.offsetLeft,
dy = pt.y - c.offsetTop;
var ctx = c.getContext('2d');
var pixel = ctx.getImageData(dx, dy, 1, 1).data;
if (pixel[3] == 0) {
return false;
}
return true;
}
}, {
key: 'setCanvasSize',
value: function setCanvasSize(c, w, h) {
c.width = w;
c.height = h;
c.style.width = w + 'px';
c.style.height = h + 'px';
}
}, {
key: 'setCanvasSizeScaledToWindowDocumentHeight',
value: function setCanvasSizeScaledToWindowDocumentHeight(c, w, h) {
var multiplier = window.devicePixelRatio * scaleMultiplier;
var scaledWidth = Math.floor(w * multiplier);
var scaledHeight = Math.floor(h * multiplier);
c.width = scaledWidth;
c.height = scaledHeight;
c.style.width = scaledWidth + 'px';
c.style.height = scaledHeight + 'px';
c.style.zoom = scaleMultiplier / multiplier;
}
}, {
key: 'localx',
value: function localx(el, gx) {
var lx = gx;
while (el && el.offsetTop != undefined) {
lx -= el.offsetLeft + el.clientLeft + new WebKitCSSMatrix(window.getComputedStyle(el).webkitTransform).m41;
el = el.parentNode;
}
return lx;
}
}, {
key: 'globalx',
value: function globalx(el) {
var lx = 0;
while (el && el.offsetLeft != undefined) {
var webkitTransform = new WebKitCSSMatrix(window.getComputedStyle(el).webkitTransform);
var transformScale = webkitTransform.m11;
lx += (el.clientWidth - transformScale * el.clientWidth) / 2;
var transformX = webkitTransform.m41;
lx += transformX;
lx += el.offsetLeft + el.clientLeft;
el = el.parentNode;
}
return lx;
}
}, {
key: 'localy',
value: function localy(el, gy) {
var ly = gy;
while (el && el.offsetTop != undefined) {
ly -= el.offsetTop + el.clientTop + new WebKitCSSMatrix(window.getComputedStyle(el).webkitTransform).m42;
el = el.parentNode;
}
return ly;
}
}, {
key: 'globaly',
value: function globaly(el) {
var ly = 0;
while (el && el.offsetTop != undefined) {
var webkitTransform = new WebKitCSSMatrix(window.getComputedStyle(el).webkitTransform);
var transformScale = webkitTransform.m22;
ly += (el.clientHeight - transformScale * el.clientHeight) / 2;
var transformY = webkitTransform.m42;
ly += transformY;
ly += el.offsetTop + el.clientTop;
el = el.parentNode;
}
return ly;
}
}, {
key: 'setProps',
value: function setProps(object, props) {
for (var i in props) {
object[i] = props[i];
}
}
// ["ease", "linear", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end"];
}, {
key: 'CSSTransition',
value: function CSSTransition(el, obj) {
// default
var duration = 1;
var transition = 'ease';
var style = {
left: el.offsetLeft + 'px',
top: el.offsetTop + 'px'
};
if (obj.duration) {
duration = obj.duration;
}
if (obj.transition) {
transition = obj.transition;
}
if (obj.style) {
style = obj.style;
}
var items = '';
for (var key in style) {
items += key + ' ' + duration + 's ' + transition + ', ';
}
items = items.substring(0, items.length - 2);
el.style.webkitTransition = items;
el.addEventListener('webkitTransitionEnd', transitionDene, true);
this.setProps(el.style, style);
function transitionDene() {
el.style.webkitTransition = '';
if (obj.onComplete) {
obj.onComplete();
}
}
}
}, {
key: 'CSSTransition3D',
value: function CSSTransition3D(el, obj) {
// default
var duration = 1;
var transition = 'ease';
var style = {
left: el.left + 'px',
top: el.top + 'px'
}; // keepit where it is
if (obj.duration) {
duration = obj.duration;
}
if (obj.transition) {
transition = obj.transition;
}
if (obj.style) {
for (var key in obj.style) {
style[key] = obj.style[key];
}
}
var items = '-webkit-transform ' + duration + 's ' + transition;
var translate = 'translate3d(' + style.left + ',' + style.top + ',0px)';
el.addEventListener('webkitTransitionEnd', transitionDone, true);
el.style.webkitTransition = items;
el.style.webkitTransform = translate;
function transitionDone() {
el.style.webkitTransition = '';
var mtx = new WebKitCSSMatrix(window.getComputedStyle(el).webkitTransform);
el.left = mtx.m41;
el.top = mtx.m42;
if (obj.onComplete) {
obj.onComplete();
}
}
}
}, {
key: 'drawThumbnail',
value: function drawThumbnail(img, c) {
// naturalWidth Height it gets the zoom scaling properly
var w = img.naturalWidth ? img.naturalWidth : img.width;
var h = img.naturalHeight ? img.naturalHeight : img.height;
var dx = (c.width - w) / 2;
var dy = (c.height - h) / 2;
var dw = c.width / w;
var dh = c.height / h;
var wi = w;
var he = h;
switch (this.getFit(dw, dh)) {
case 'noscale':
break;
case 'scaleh':
wi = w * dh;
he = h * dh;
dx = (c.width - wi) / 2;
dy = (c.height - he) / 2;
break;
case 'scalew':
wi = w * dw;
he = h * dw;
dx = (c.width - wi) / 2;
dy = (c.height - he) / 2;
break;
}
var ctx = c.getContext('2d');
ctx.drawImage(img, dx, dy, wi, he);
}
// Like drawThumbnail, but scales up if needed
}, {
key: 'drawScaled',
value: function drawScaled(img, c) {
var imgWidth = img.naturalWidth ? img.naturalWidth : img.width;
var imgHeight = img.naturalHeight ? img.naturalHeight : img.height;
var boxWidth = c.width;
var boxHeight = c.height;
var scale = boxWidth / imgWidth;
var w = imgWidth * scale;
var h = imgHeight * scale;
if (h > boxHeight) {
scale = boxHeight / imgHeight;
w = imgWidth * scale;
h = imgHeight * scale;
}
var x0 = (boxWidth - w) / 2;
var y0 = (boxHeight - h) / 2;
var ctx = c.getContext('2d');
ctx.drawImage(img, x0, y0, w, h);
}
}, {
key: 'fitInRect',
value: function fitInRect(srcw, srch, destw, desth) {
var dx = (destw - srcw) / 2;
var dy = (desth - srch) / 2;
var dw = destw / srcw;
var dh = desth / srch;
var wi = srcw;
var he = srch;
switch (this.getFit(dw, dh)) {
case 'noscale':
break;
case 'scaleh':
wi = srcw * dh;
he = srch * dh;
dx = (destw - wi) / 2;
dy = (desth - he) / 2;
break;
case 'scalew':
wi = srcw * dw;
he = srch * dw;
dx = (destw - wi) / 2;
dy = (desth - he) / 2;
break;
}
return [dx, dy, wi, he];
}
}, {
key: 'getFit',
value: function getFit(dw, dh) {
if (dw >= 1 && dh >= 1) {
return 'noscale';
}
if (dw >= 1 && dh < 1) {
return 'scaleh';
}
if (dw < 1 && dh >= 1) {
return 'scalew';
}
if (dw < dh) {
return 'scalew';
}
return 'scaleh';
}
}, {
key: 'getDocumentHeight',
value: function getDocumentHeight() {
return Math.max(document.body.clientHeight, document.documentElement.clientHeight);
}
}, {
key: 'getDocumentWidth',
value: function getDocumentWidth() {
return Math.max(document.body.clientWidth, document.documentElement.clientWidth);
}
}, {
key: 'getStringSize',
value: function getStringSize(ctx, f, label) {
ctx.font = f;
return ctx.measureText(label);
}
}, {
key: 'writeText',
value: function writeText(ctx, f, c, label, dy, dx) {
dx = dx == undefined ? 0 : dx;
ctx.font = f;
ctx.fillStyle = c;
ctx.textAlign = 'left';
ctx.textBaseline = 'bottom';
ctx.fillText(label, dx, dy);
}
}, {
key: 'gn',
value: function gn(str) {
return document.getElementById(str);
}
}, {
key: 'newForm',
value: function newForm(parent, str, x, y, w, h, styles) {
var el = document.createElement('form');
el.style.position = 'absolute';
el.style.top = y + 'px';
el.style.left = x + 'px';
if (w) {
el.style.width = w + 'px';
}
if (h) {
el.style.height = h + 'px';
}
this.setProps(el.style, styles);
parent.appendChild(el);
el.name = str;
return el;
}
}, {
key: 'newTextInput',
value: function newTextInput(p, type, str, mstyle) {
var input = document.createElement('input');
input.value = str;
this.setProps(input.style, mstyle);
input.type = type;
p.appendChild(input);
return input;
}
}, {
key: 'getUrlVars',
value: function getUrlVars() {
if (window.location.href.indexOf('?') < 0) {
return [];
}
var args = window.location.href.slice(window.location.href.indexOf('?') + 1);
var vars = [],
hash;
var hashes = args.split('&');
for (var i = 0; i < hashes.length; i++) {
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
}, {
key: 'getIdFor',
value: function getIdFor(name) {
var n = 1;
while (this.gn(name + ' ' + n) != undefined) {
n++;
}
return name + ' ' + n;
}
}, {
key: 'getIdForCamera',
value: function getIdForCamera(name) {
var n = 1;
while (this.gn(name + '_' + n) != undefined) {
n++;
}
return name + '_' + n;
}
////////////////////
// Color
/////////////////////
}, {
key: 'rgb2hsb',
value: function rgb2hsb(str) {
if (str == null) {
return [24, 1, 1];
}
var min, val, f, i, hue, sat;
str = str.indexOf('rgb') > -1 ? this.rgbToHex(str) : this.rgbaToHex(str);
var num = parseInt(str.substring(1, str.length), 16);
var rgb = this.getRGB(num);
var red = rgb[0];
red /= 255;
var grn = rgb[1];
grn /= 255;
var blu = rgb[2];
blu /= 255;
min = Math.min(Math.min(red, grn), blu);
val = Math.max(Math.max(red, grn), blu);
if (min == val) {
return new Array(0, 0, val);
}
f = red == min ? grn - blu : grn == min ? blu - red : red - grn;
i = red == min ? 3 : grn == min ? 5 : 1;
hue = Math.round((i - f / (val - min)) * 60) % 360;
sat = Math.round((val - min) / val * 100);
val = Math.round(val * 100);
return new Array(hue, sat / 100, val / 100);
}
}, {
key: 'rgbToHex',
value: function rgbToHex(str) {
if (str.indexOf('rgb') < 0) {
return str;
}
var res = str.substring(4, str.length - 1);
var a = res.split(',');
var red = Number(a[0]);
var grn = Number(a[1]);
var blu = Number(a[2]);
return this.rgbToString({
r: red,
g: grn,
b: blu
});
}
}, {
key: 'rgbaToHex',
value: function rgbaToHex(str) {
if (str.indexOf('rgba') < 0) {
return str;
}
var res = str.substring(5, str.length - 1);
var a = res.split(',');
var red = Number(a[0]);
var grn = Number(a[1]);
var blu = Number(a[2]);
return this.rgbToString({
r: red,
g: grn,
b: blu
});
}
}, {
key: 'rgbToString',
value: function rgbToString(obj) {
return '#' + this.getHex(obj.r) + this.getHex(obj.g) + this.getHex(obj.b);
}
}, {
key: 'getRGB',
value: function getRGB(color) {
return [Number(color >> 16 & 255), Number(color >> 8 & 255), Number(color & 255)];
}
}, {
key: 'getHex',
value: function getHex(num) {
var hex = num.toString(16);
if (hex.length == 1) {
return '0' + hex;
}
return hex;
}
// findKeyframesRule ("swing");
}, {
key: 'findKeyframesRule',
value: function findKeyframesRule(rule) {
var ss = document.styleSheets;
for (var i = 0; i < ss.length; ++i) {
for (var j = 0; j < ss[i].cssRules.length; ++j) {
var styles = ss[i].cssRules[j].styleSheet.rules;
for (var k = 0; k < styles.length; ++k) {
if (styles[k].type == window.CSSRule.WEBKIT_KEYFRAMES_RULE && styles[k].name == rule) {
return styles[k];
}
}
}
} // rule not found
return null;
}
}, {
key: 'colorToRGBA',
value: function colorToRGBA(color, opacity) {
var val = parseInt('0x' + color.substr(1, color.length));
return 'rgba(' + (val >> 16) % 256 + ',' + (val >> 8) % 256 + ',' + val % 256 + ',' + opacity + ')';
}
/**
* css units vh and vw (for % of height and width) are not supported in Android 4.3 and earlier, so
* here we introduce functioncs (called from the preprocessed css) that emulate their behavior by
* turning them into pixel values.
*/
}, {
key: 'css_vh',
value: function css_vh(y) {
return y * WINDOW_INNER_HEIGHT / 100.0 + 'px';
}
}, {
key: 'css_vw',
value: function css_vw(x) {
return x * WINDOW_INNER_WIDTH / 100.0 + 'px';
}
}]);
return Lib;
}();
exports.default = Lib;
Number.prototype.mod = function (n) {
return (this % n + n) % n;
};
/***/ }
/******/ ]);

File diff suppressed because it is too large Load diff

29
src/entry/editor.js Normal file
View file

@ -0,0 +1,29 @@
import Lib from '../utils/lib';
function createScratchJr () {
iOS.getsettings(doNext);
function doNext (str) {
var list = str.split(',');
iOS.path = list[1] == '0' ? list[0] + '/' : undefined;
if (list.length > 2) {
Record.available = list[2] == 'YES' ? true : false;
}
if (list.length > 3) {
Camera.available = list[3] == 'YES' ? true : false;
}
ScratchJr.appinit(Settings.scratchJrVersion);
}
}
window.onload = () => {
Lib.preprocessAndLoadCss('css', 'css/font.css');
Lib.preprocessAndLoadCss('css', 'css/base.css');
Lib.preprocessAndLoadCss('css', 'css/editor.css');
Lib.preprocessAndLoadCss('css', 'css/editorleftpanel.css');
Lib.preprocessAndLoadCss('css', 'css/editorstage.css');
Lib.preprocessAndLoadCss('css', 'css/editormodal.css');
Lib.preprocessAndLoadCss('css', 'css/librarymodal.css');
Lib.preprocessAndLoadCss('css', 'css/paintlook.css');
Localization.includeLocales();
iOS.waitForInterface(createScratchJr);
};

85
src/entry/index.js Normal file
View file

@ -0,0 +1,85 @@
import {Lib, isAndroid, isiOS} from '../utils/lib';
import Localization from '../utils/Localization';
function startup () {
ScratchAudio.init();
var urlvars = Lib.getUrlVars();
if (urlvars.back) {
loadOptions();
} else {
firstTime();
}
setTimeout(function () {
Lib.gn('rays').className = 'rays spinme';
}, 250);
}
function firstTime () {
Lib.gn('authors').className = 'credits show';
Lib.gn('authorsText').className = 'creditsText show';
Lib.gn('purpleguy').className = 'purple show';
Lib.gn('blueguy').className = 'blue show';
Lib.gn('redguy').className = 'red show';
iOS.askpermission(); // ask for sound recording
setTimeout(function () {
iOS.hidesplash(doit);
}, 500);
function doit () {
ScratchAudio.sndFX('tap.wav');
window.ontouchend = function () {
loadOptions();
};
}
setTimeout(function () {
loadOptions();
}, 2000);
}
function loadOptions () {
Lib.gn('authors').className = 'credits hide';
Lib.gn('authorsText').className = 'creditsText hide';
Lib.gn('purpleguy').className = 'purple hide';
Lib.gn('blueguy').className = 'blue hide';
Lib.gn('redguy').className = 'red hide';
Lib.gn('gettings').className = 'gettings show';
Lib.gn('startcode').className = 'startcode show';
document.ontouchmove = function (e) {
e.preventDefault();
};
if (isAndroid) {
AndroidInterface.notifySplashDone();
}
}
function gohome () {
// On iOS, sounds are loaded async, but the code as written expects to play tap.wav when we enter home.html
// (but since it isn't loaded yet, no sound is played).
// On Android, sync sounds means both calls to tap.wav result in a sound play.
// XXX: we should re-write the lobby loading to wait for the sounds to load, and not play a sound here.
if (isiOS) {
ScratchAudio.sndFX('tap.wav');
}
iOS.setfile('homescroll.sjr', 0, function () {
doNext();
});
function doNext () {
window.location.href = 'home.html';
}
}
function gettingstarted () {
ScratchAudio.sndFX('tap.wav');
window.location.href = 'gettingstarted.html?place=home';
}
window.onload = () => {
Localization.includeLocales();
Lib.preprocessAndLoadCss('css', 'css/font.css');
Lib.preprocessAndLoadCss('css', 'css/base.css');
Lib.preprocessAndLoadCss('css', 'css/start.css');
Lib.preprocessAndLoadCss('css', 'css/thumbs.css');
Lib.gn('gettings').ontouchend = gettingstarted;
Lib.gn('startcode').ontouchend = gohome;
iOS.waitForInterface(startup);
};

View file

@ -1,24 +1,24 @@
var Cookie = {};
// Thanks to http://www.quirksmode.org/js/cookies.html
Cookie.set = function (key, value) {
var year = new Date();
year.setTime(year.getTime() + (365 * 24 * 60 * 60 * 1000));
var expires = '; expires=' + year.toGMTString();
document.cookie = key + '=' + value + expires + '; path=/';
};
Cookie.get = function (key) {
key += '=';
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var c = cookies[i];
while (c.charAt(0) == ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(key) == 0) {
return c.substring(key.length, c.length);
}
export default class Cookie {
// Thanks to http://www.quirksmode.org/js/cookies.html
static set (key, value) {
var year = new Date();
year.setTime(year.getTime() + (365 * 24 * 60 * 60 * 1000));
var expires = '; expires=' + year.toGMTString();
document.cookie = key + '=' + value + expires + '; path=/';
}
return null;
};
static get (key) {
key += '=';
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var c = cookies[i];
while (c.charAt(0) == ' ') {
c = c.substring(1, c.length);
}
if (c.indexOf(key) == 0) {
return c.substring(key.length, c.length);
}
}
return null;
}
}

View file

@ -1,95 +1,102 @@
window.Localization = function () {};
import Cookie from './Cookie';
import IntlMessageFormat from 'intl-messageformat';
let currentLocale;
let root = '';
let localizationMessages = {};
let defaultLocalizationMessages = {};
// Configuration
Localization.defaultLocale = Settings.defaultLocale;
Localization.defaultLocaleShort = Settings.defaultLocaleShort;
Localization.supportedLocales = Settings.supportedLocales;
Localization.root = '';
const defaultLocale = window.Settings.defaultLocale;
const defaultLocaleShort = window.Settings.defaultLocaleShort;
const supportedLocales = window.Settings.supportedLocales;
const sampleKeyPrefix = 'key_';
// Take the browser's reported locale from navigator.language
// Normalize this value and find a match in Localization.supportedLocales
// If we support a similar language but not the specific one, it's returned.
// E.g., if we support 'en-US' but not 'en-GB', the user gets 'en-US'
// The match in supported locales (or the default locale) is returned.
Localization.determineLocaleFromBrowser = function () {
var localizationLanguage = window.navigator.userLanguage || window.navigator.language || 'en-us';
export default class Localization {
// Take the browser's reported locale from navigator.language
// Normalize this value and find a match in supportedLocales
// If we support a similar language but not the specific one, it's returned.
// E.g., if we support 'en-US' but not 'en-GB', the user gets 'en-US'
// The match in supported locales (or the default locale) is returned.
static determineLocaleFromBrowser () {
var localizationLanguage = window.navigator.userLanguage || window.navigator.language || 'en-us';
var localizationLanguageParts = localizationLanguage.split('-');
// Capitalize last part of localization for includes
localizationLanguageParts[localizationLanguageParts.length - 1] = (
localizationLanguageParts[localizationLanguageParts.length - 1].toUpperCase()
);
var localizationLanguageParts = localizationLanguage.split('-');
// Capitalize last part of localization for includes
localizationLanguageParts[localizationLanguageParts.length - 1] = (
localizationLanguageParts[localizationLanguageParts.length - 1].toUpperCase()
);
var desiredLocale = localizationLanguageParts.join('-');
if (desiredLocale in Object.keys(Localization.supportedLocales)) {
return desiredLocale;
}
// We're not supporting this locale yet - do we support an ancestor?
for (var localeKey in Localization.supportedLocales) {
var supportedLocale = Localization.supportedLocales[localeKey];
var parts = supportedLocale.split('-');
if (parts[0] == localizationLanguageParts[0]) {
return supportedLocale; // Top-level is the same
var desiredLocale = localizationLanguageParts.join('-');
if (desiredLocale in Object.keys(supportedLocales)) {
return desiredLocale;
}
// We're not supporting this locale yet - do we support an ancestor?
for (var localeKey in supportedLocales) {
var supportedLocale = supportedLocales[localeKey];
var parts = supportedLocale.split('-');
if (parts[0] == localizationLanguageParts[0]) {
return supportedLocale; // Top-level is the same
}
}
return defaultLocale;
}
return Localization.defaultLocale;
};
// Include locale support files and load the messages
// Call this when the app is initialized
static includeLocales () {
var localizationCookie = Cookie.get('localization');
if (localizationCookie === null) {
currentLocale = this.determineLocaleFromBrowser();
} else {
currentLocale = localizationCookie;
}
// Intl locale-data
document.write('<script src="' + root +
'jssource/external/Intl/locale-data/jsonp/' + currentLocale + '.js"><\/script>');
// Include locale support files and load the messages
// Call this when the app is initialized
Localization.includeLocales = function () {
var localizationCookie = Cookie.get('localization');
if (localizationCookie === null) {
Localization.currentLocale = Localization.determineLocaleFromBrowser();
} else {
Localization.currentLocale = localizationCookie;
// MessageFormat locale-data
var topLevel = currentLocale.split('-')[0];
document.write('<script src="' + root +
'jssource/external/intl-messageformat/locale-data/' + topLevel + '.js"><\/script>');
// Always load default locale
document.write('<script src="' + root +
'jssource/external/Intl/locale-data/jsonp/' + defaultLocale + '.js"><\/script>');
document.write('<script src="' + root +
'jssource/external/intl-messageformat/locale-data/' + defaultLocaleShort + '.js"><\/script>');
// Get messages synchronously
var xhr = new XMLHttpRequest();
xhr.open('GET', root + 'localizations/' + currentLocale + '.json', false);
xhr.send(null);
localizationMessages = JSON.parse(xhr.responseText);
xhr = new XMLHttpRequest();
xhr.open('GET', this.root + 'localizations/' + this.defaultLocale + '.json', false);
xhr.send(null);
defaultLocalizationMessages = JSON.parse(xhr.responseText);
}
// Intl locale-data
document.write('<script src="' + Localization.root +
'jssource/external/Intl/locale-data/jsonp/' + Localization.currentLocale + '.js"><\/script>');
// MessageFormat locale-data
var topLevel = Localization.currentLocale.split('-')[0];
document.write('<script src="' + Localization.root +
'jssource/external/intl-messageformat/locale-data/' + topLevel + '.js"><\/script>');
// Always load default locale
document.write('<script src="' + Localization.root +
'jssource/external/Intl/locale-data/jsonp/' + Localization.defaultLocale + '.js"><\/script>');
document.write('<script src="' + Localization.root +
'jssource/external/intl-messageformat/locale-data/' + Localization.defaultLocaleShort + '.js"><\/script>');
// Get messages synchronously
var xhr = new XMLHttpRequest();
xhr.open('GET', Localization.root + 'localizations/' + Localization.currentLocale + '.json', false);
xhr.send(null);
Localization.localizationMessages = JSON.parse(xhr.responseText);
xhr = new XMLHttpRequest();
xhr.open('GET', Localization.root + 'localizations/' + Localization.defaultLocale + '.json', false);
xhr.send(null);
Localization.defaultLocalizationMessages = JSON.parse(xhr.responseText);
};
// Translate a particular message given the message key and info
Localization.localize = function (key, formatting) {
var message;
if (key in Localization.localizationMessages) {
message = new IntlMessageFormat(Localization.localizationMessages[key], Localization.currentLocale);
return message.format(formatting);
} else if (key in Localization.defaultLocalizationMessages) {
message = new IntlMessageFormat(Localization.defaultLocalizationMessages[key], Localization.defaultLocale);
return message.format(formatting);
// Translate a particular message given the message key and info
static localize (key, formatting) {
var message;
if (key in localizationMessages) {
message = new IntlMessageFormat(localizationMessages[key], currentLocale);
return message.format(formatting);
} else if (key in defaultLocalizationMessages) {
message = new IntlMessageFormat(defaultLocalizationMessages[key], defaultLocale);
return message.format(formatting);
}
return 'String missing: ' + key;
}
return 'String missing: ' + key;
};
// For sample projects, some fields (sprite names, text on stage, and text in say blocks)
// may have a special prefix to indicate that it should be replaced with a localized value.
// E.g., we might have some text on the stage that says "Touch me" in English. This gets translated.
Localization.sampleKeyPrefix = 'key_';
Localization.isSampleLocalizedKey = function (str) {
return str.slice(0, Localization.sampleKeyPrefix.length) == Localization.sampleKeyPrefix;
};
// For sample projects, some fields (sprite names, text on stage, and text in say blocks)
// may have a special prefix to indicate that it should be replaced with a localized value.
// E.g., we might have some text on the stage that says "Touch me" in English. This gets translated.
static isSampleLocalizedKey (str) {
return str.slice(0, sampleKeyPrefix.length) == sampleKeyPrefix;
}
}

File diff suppressed because it is too large Load diff

22
webpack.config.js Normal file
View file

@ -0,0 +1,22 @@
module.exports = {
entry: {
index: './src/entry/index.js',
editor: './src/entry/editor.js'
},
output: {
path: './src/build/bundles',
filename: '[name].bundle.js'
},
module: {
loaders: [
{
loader: 'babel-loader',
exclude: /node_modules/,
test: /\.jsx?$/,
query: {
presets: ['es2015']
}
}
]
}
};