123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /**
- * 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');
|