summaryrefslogtreecommitdiff
path: root/blockly/demos/plane/plane.js
diff options
context:
space:
mode:
Diffstat (limited to 'blockly/demos/plane/plane.js')
-rw-r--r--blockly/demos/plane/plane.js445
1 files changed, 445 insertions, 0 deletions
diff --git a/blockly/demos/plane/plane.js b/blockly/demos/plane/plane.js
new file mode 100644
index 0000000..99e5c17
--- /dev/null
+++ b/blockly/demos/plane/plane.js
@@ -0,0 +1,445 @@
+/**
+ * Blockly Demos: Plane Seat Calculator
+ *
+ * Copyright 2012 Google Inc.
+ * https://developers.google.com/blockly/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview JavaScript for Blockly's Plane Seat Calculator demo.
+ * @author fraser@google.com (Neil Fraser)
+ */
+'use strict';
+
+/**
+ * Create a namespace for the application.
+ */
+var Plane = {};
+
+/**
+ * Lookup for names of supported languages. Keys should be in ISO 639 format.
+ */
+Plane.LANGUAGE_NAME = {
+ 'ar': 'العربية',
+ 'be-tarask': 'Taraškievica',
+ 'br': 'Brezhoneg',
+ 'ca': 'Català',
+ 'da': 'Dansk',
+ 'de': 'Deutsch',
+ 'el': 'Ελληνικά',
+ 'en': 'English',
+ 'es': 'Español',
+ 'fa': 'فارسی',
+ 'fr': 'Français',
+ 'he': 'עברית',
+ 'hrx': 'Hunsrik',
+ 'hu': 'Magyar',
+ 'ia': 'Interlingua',
+ 'is': 'Íslenska',
+ 'it': 'Italiano',
+ 'ja': '日本語',
+ 'ko': '한국어',
+ 'ms': 'Bahasa Melayu',
+ 'nb': 'Norsk Bokmål',
+ 'nl': 'Nederlands, Vlaams',
+ 'pl': 'Polski',
+ 'pms': 'Piemontèis',
+ 'pt-br': 'Português Brasileiro',
+ 'ro': 'Română',
+ 'ru': 'Русский',
+ 'sc': 'Sardu',
+ 'sv': 'Svenska',
+ 'th': 'ภาษาไทย',
+ 'tr': 'Türkçe',
+ 'uk': 'Українська',
+ 'vi': 'Tiếng Việt',
+ 'zh-hans': '简体中文',
+ 'zh-hant': '正體中文'
+};
+
+/**
+ * List of RTL languages.
+ */
+Plane.LANGUAGE_RTL = ['ar', 'fa', 'he'];
+
+/**
+ * Main Blockly workspace.
+ * @type {Blockly.WorkspaceSvg}
+ */
+Plane.workspace = null;
+
+/**
+ * Extracts a parameter from the URL.
+ * If the parameter is absent default_value is returned.
+ * @param {string} name The name of the parameter.
+ * @param {string} defaultValue Value to return if paramater not found.
+ * @return {string} The parameter value or the default value if not found.
+ */
+Plane.getStringParamFromUrl = function(name, defaultValue) {
+ var val = location.search.match(new RegExp('[?&]' + name + '=([^&]+)'));
+ return val ? decodeURIComponent(val[1].replace(/\+/g, '%20')) : defaultValue;
+};
+
+/**
+ * Extracts a numeric parameter from the URL.
+ * If the parameter is absent or less than min_value, min_value is
+ * returned. If it is greater than max_value, max_value is returned.
+ * @param {string} name The name of the parameter.
+ * @param {number} minValue The minimum legal value.
+ * @param {number} maxValue The maximum legal value.
+ * @return {number} A number in the range [min_value, max_value].
+ */
+Plane.getNumberParamFromUrl = function(name, minValue, maxValue) {
+ var val = Number(Plane.getStringParamFromUrl(name, 'NaN'));
+ return isNaN(val) ? minValue : Math.min(Math.max(minValue, val), maxValue);
+};
+
+/**
+ * Get the language of this user from the URL.
+ * @return {string} User's language.
+ */
+Plane.getLang = function() {
+ var lang = Plane.getStringParamFromUrl('lang', '');
+ if (Plane.LANGUAGE_NAME[lang] === undefined) {
+ // Default to English.
+ lang = 'en';
+ }
+ return lang;
+};
+
+/**
+ * Is the current language (Plane.LANG) an RTL language?
+ * @return {boolean} True if RTL, false if LTR.
+ */
+Plane.isRtl = function() {
+ return Plane.LANGUAGE_RTL.indexOf(Plane.LANG) != -1;
+};
+
+/**
+ * Load blocks saved in session/local storage.
+ * @param {string} defaultXml Text representation of default blocks.
+ */
+Plane.loadBlocks = function(defaultXml) {
+ try {
+ var loadOnce = window.sessionStorage.loadOnceBlocks;
+ } catch(e) {
+ // Firefox sometimes throws a SecurityError when accessing sessionStorage.
+ // Restarting Firefox fixes this, so it looks like a bug.
+ var loadOnce = null;
+ }
+ if (loadOnce) {
+ // Language switching stores the blocks during the reload.
+ delete window.sessionStorage.loadOnceBlocks;
+ var xml = Blockly.Xml.textToDom(loadOnce);
+ Blockly.Xml.domToWorkspace(xml, Plane.workspace);
+ } else if (defaultXml) {
+ // Load the editor with default starting blocks.
+ var xml = Blockly.Xml.textToDom(defaultXml);
+ Blockly.Xml.domToWorkspace(xml, Plane.workspace);
+ }
+ Plane.workspace.clearUndo();
+};
+
+/**
+ * Save the blocks and reload with a different language.
+ */
+Plane.changeLanguage = function() {
+ // Store the blocks for the duration of the reload.
+ // This should be skipped for the index page, which has no blocks and does
+ // not load Blockly.
+ // MSIE 11 does not support sessionStorage on file:// URLs.
+ if (typeof Blockly != 'undefined' && window.sessionStorage) {
+ var xml = Blockly.Xml.workspaceToDom(Plane.workspace);
+ var text = Blockly.Xml.domToText(xml);
+ window.sessionStorage.loadOnceBlocks = text;
+ }
+
+ var languageMenu = document.getElementById('languageMenu');
+ var newLang = encodeURIComponent(
+ languageMenu.options[languageMenu.selectedIndex].value);
+ var search = window.location.search;
+ if (search.length <= 1) {
+ search = '?lang=' + newLang;
+ } else if (search.match(/[?&]lang=[^&]*/)) {
+ search = search.replace(/([?&]lang=)[^&]*/, '$1' + newLang);
+ } else {
+ search = search.replace(/\?/, '?lang=' + newLang + '&');
+ }
+
+ window.location = window.location.protocol + '//' +
+ window.location.host + window.location.pathname + search;
+};
+
+/**
+ * Gets the message with the given key from the document.
+ * @param {string} key The key of the document element.
+ * @return {string} The textContent of the specified element,
+ * or an error message if the element was not found.
+ */
+Plane.getMsg = function(key) {
+ var element = document.getElementById(key);
+ if (element) {
+ var text = element.textContent;
+ // Convert newline sequences.
+ text = text.replace(/\\n/g, '\n');
+ return text;
+ } else {
+ return '[Unknown message: ' + key + ']';
+ }
+};
+
+/**
+ * User's language (e.g. "en").
+ * @type {string}
+ */
+Plane.LANG = Plane.getLang();
+
+Plane.MAX_LEVEL = 3;
+Plane.LEVEL = Plane.getNumberParamFromUrl('level', 1, Plane.MAX_LEVEL);
+
+Plane.rows1st = 0;
+Plane.rows2nd = 0;
+
+/**
+ * Redraw the rows when the slider has moved.
+ * @param {number} value New slider position.
+ */
+Plane.sliderChange = function(value) {
+ var newRows = Math.round(value * 410 / 20);
+ Plane.redraw(newRows);
+};
+
+/**
+ * Change the text of a label.
+ * @param {string} id ID of element to change.
+ * @param {string} text New text.
+ */
+Plane.setText = function(id, text) {
+ var el = document.getElementById(id);
+ while (el.firstChild) {
+ el.removeChild(el.firstChild);
+ }
+ el.appendChild(document.createTextNode(text));
+};
+
+/**
+ * Display a checkmark or cross next to the answer.
+ * @param {?boolean} ok True for checkmark, false for cross, null for nothing.
+ */
+Plane.setCorrect = function(ok) {
+ var yes = document.getElementById('seatYes');
+ var no = document.getElementById('seatNo');
+ yes.style.display = 'none';
+ no.style.display = 'none';
+ if (ok === true) {
+ yes.style.display = 'block';
+ } else if (ok === false) {
+ no.style.display = 'block';
+ }
+};
+
+/**
+ * Initialize Blockly and the SVG plane.
+ */
+Plane.init = function() {
+ Plane.initLanguage();
+
+ // Fixes viewport for small screens.
+ var viewport = document.querySelector('meta[name="viewport"]');
+ if (viewport && screen.availWidth < 725) {
+ viewport.setAttribute('content',
+ 'width=725, initial-scale=.35, user-scalable=no');
+ }
+
+ Plane.workspace = Blockly.inject('blockly',
+ {media: '../../media/',
+ rtl: Plane.isRtl(),
+ toolbox: document.getElementById('toolbox')});
+
+ var defaultXml =
+ '<xml>' +
+ ' <block type="plane_set_seats" deletable="false" x="70" y="70">' +
+ ' </block>' +
+ '</xml>';
+ Plane.loadBlocks(defaultXml);
+
+ Plane.workspace.addChangeListener(Plane.recalculate);
+ Plane.workspace.addChangeListener(Blockly.Events.disableOrphans);
+
+ // Initialize the slider.
+ var svg = document.getElementById('plane');
+ Plane.rowSlider = new Slider(60, 330, 425, svg, Plane.sliderChange);
+ Plane.rowSlider.setValue(0.225);
+
+ // Draw five 1st class rows.
+ Plane.redraw(5);
+};
+
+/**
+ * Initialize the page language.
+ */
+Plane.initLanguage = function() {
+ // Set the page title with the content of the H1 title.
+ document.title += ' ' + document.getElementById('title').textContent;
+
+ // Set the HTML's language and direction.
+ // document.dir fails in Mozilla, use document.body.parentNode.dir instead.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=151407
+ var rtl = Plane.isRtl();
+ document.head.parentElement.setAttribute('dir', rtl ? 'rtl' : 'ltr');
+ document.head.parentElement.setAttribute('lang', Plane.LANG);
+
+ // Sort languages alphabetically.
+ var languages = [];
+ for (var lang in Plane.LANGUAGE_NAME) {
+ languages.push([Plane.LANGUAGE_NAME[lang], lang]);
+ }
+ var comp = function(a, b) {
+ // Sort based on first argument ('English', 'Русский', '简体字', etc).
+ if (a[0] > b[0]) return 1;
+ if (a[0] < b[0]) return -1;
+ return 0;
+ };
+ languages.sort(comp);
+ // Populate the language selection menu.
+ var languageMenu = document.getElementById('languageMenu');
+ languageMenu.options.length = 0;
+ for (var i = 0; i < languages.length; i++) {
+ var tuple = languages[i];
+ var lang = tuple[tuple.length - 1];
+ var option = new Option(tuple[0], lang);
+ if (lang == Plane.LANG) {
+ option.selected = true;
+ }
+ languageMenu.options.add(option);
+ }
+ languageMenu.addEventListener('change', Plane.changeLanguage, true);
+};
+
+/**
+ * Use the blocks to calculate the number of seats.
+ * Display the calculated number.
+ */
+Plane.recalculate = function() {
+ // Find the 'set' block and use it as the formula root.
+ var rootBlock = null;
+ var blocks = Plane.workspace.getTopBlocks(false);
+ for (var i = 0, block; block = blocks[i]; i++) {
+ if (block.type == 'plane_set_seats') {
+ rootBlock = block;
+ }
+ }
+ var seats = NaN;
+ Blockly.JavaScript.init(Plane.workspace);
+ var code = Blockly.JavaScript.blockToCode(rootBlock);
+ try {
+ seats = eval(code);
+ } catch (e) {
+ // Allow seats to remain NaN.
+ }
+ Plane.setText('seatText',
+ Plane.getMsg('Plane_seats').replace(
+ '%1', isNaN(seats) ? '?' : seats));
+ Plane.setCorrect(isNaN(seats) ? null : (Plane.answer() == seats));
+
+ // Update blocks to show values.
+ function updateBlocks(blocks) {
+ for (var i = 0, block; block = blocks[i]; i++) {
+ block.customUpdate && block.customUpdate();
+ }
+ }
+ updateBlocks(Plane.workspace.getAllBlocks());
+ updateBlocks(Plane.workspace.flyout_.workspace_.getAllBlocks());
+};
+
+/**
+ * Calculate the correct answer.
+ * @return {number} Number of seats.
+ */
+Plane.answer = function() {
+ if (Plane.LEVEL == 1) {
+ return Plane.rows1st * 4;
+ } else if (Plane.LEVEL == 2) {
+ return 2 + (Plane.rows1st * 4);
+ } else if (Plane.LEVEL == 3) {
+ return 2 + (Plane.rows1st * 4) + (Plane.rows2nd * 5);
+ }
+ throw 'Unknown level.';
+};
+
+/**
+ * Redraw the SVG to show a new number of rows.
+ * @param {number} newRows
+ */
+Plane.redraw = function(newRows) {
+ var rows1st = Plane.rows1st;
+ var rows2nd = Plane.rows2nd;
+ var svg = document.getElementById('plane');
+ if (newRows != rows1st) {
+ while (newRows < rows1st) {
+ var row = document.getElementById('row1st' + rows1st);
+ row.parentNode.removeChild(row);
+ rows1st--;
+ }
+ while (newRows > rows1st) {
+ rows1st++;
+ var row = document.createElementNS('http://www.w3.org/2000/svg', 'use');
+ row.setAttribute('id', 'row1st' + rows1st);
+ // Row of 4 seats.
+ row.setAttribute('x', (rows1st - 1) * 20);
+ row.setAttributeNS('http://www.w3.org/1999/xlink',
+ 'xlink:href', '#row1st');
+ svg.appendChild(row);
+ }
+
+ if (Plane.LEVEL == 3) {
+ newRows = Math.floor((21 - newRows) * 1.11);
+ while (newRows < rows2nd) {
+ var row = document.getElementById('row2nd' + rows2nd);
+ row.parentNode.removeChild(row);
+ rows2nd--;
+ }
+ while (newRows > rows2nd) {
+ rows2nd++;
+ var row = document.createElementNS('http://www.w3.org/2000/svg',
+ 'use');
+ row.setAttribute('id', 'row2nd' + rows2nd);
+ row.setAttribute('x', 400 - (rows2nd - 1) * 18);
+ row.setAttributeNS('http://www.w3.org/1999/xlink',
+ 'xlink:href', '#row2nd');
+ svg.appendChild(row);
+ }
+ }
+
+ if (Plane.LEVEL < 3) {
+ Plane.setText('row1stText',
+ Plane.getMsg('Plane_rows').replace('%1', rows1st));
+ } else {
+ Plane.setText('row1stText',
+ Plane.getMsg('Plane_rows1').replace('%1', rows1st));
+ Plane.setText('row2ndText',
+ Plane.getMsg('Plane_rows2').replace('%1', rows2nd));
+ }
+
+ Plane.rows1st = rows1st;
+ Plane.rows2nd = rows2nd;
+ Plane.recalculate();
+ }
+};
+
+window.addEventListener('load', Plane.init);
+
+// Load the user's language pack.
+document.write('<script src="generated/' + Plane.LANG + '.js"></script>\n');