Commit c6695862 authored by carlosperate's avatar carlosperate

Add support for language selection on front end.

The Arduino specific blocks still need to have their text moved in to language strings.
The front end strings still need to have their text moved in to language strings.
parent 79c8781a
......@@ -9,10 +9,24 @@
/** Create a namespace for the application. */
var Ardublockly = Ardublockly || {};
/** Lookup for names of supported languages. Keys in ISO 639 format. */
Ardublockly.LANGUAGE_NAME = {
'en': 'English',
'es': 'Español'
};
/**
* Selected language, default English.
* @type {string}
*/
Ardublockly.LANG = 'en';
/** Initialize function for Ardublockly on page load. */
window.addEventListener('load', function load(event) {
window.removeEventListener('load', load, false);
// Lang init must run first for the rest of the page to pick the right msgs
Ardublockly.initLanguage();
// Inject Blockly into content_blocks
Ardublockly.injectBlockly(
document.getElementById('content_blocks'), 'ardublockly_toolbox.xml');
......@@ -100,6 +114,100 @@ Ardublockly.bindActionFunctions = function() {
});
};
/** Initialize the page language. */
Ardublockly.initLanguage = function() {
// Save the current default state
var defaultLang = Ardublockly.LANG;
// Check server settings and url language, url gets priority
Ardublockly.LANG = Ardublockly.getUrlLanguage() ||
Ardublockly.getLanguageSetting();
Ardublockly.populateLanguageMenu(Ardublockly.LANG);
if (defaultLang !== Ardublockly.LANG) {
Ardublockly.injectLanguageJsSources();
Ardublockly.updateLanguageText();
}
};
/**
* Get the language previously set by the user from the server settings.
* @return {string} Language saved in the server settings.
*/
Ardublockly.getLanguageSetting = function() {
//TODO: Server feature still to be implemented, for now return default
return Ardublockly.LANG;
};
/**
* Get the language selected from the URL, format '?lang=en'.
* @return {string} Selected language.
*/
Ardublockly.getUrlLanguage = function() {
var langKey = 'lang';
var val = location.search.match(new RegExp('[?&]' + langKey + '=([^&]+)'));
var language = val ? decodeURIComponent(val[1].replace(/\+/g, '%20')) : '';
if (Ardublockly.LANGUAGE_NAME[language] === undefined) {
language = 'null';
}
return language;
};
/** Populates the settings language selection menu. */
Ardublockly.populateLanguageMenu = function(selectedLang) {
var languageMenu = document.getElementById('language');
languageMenu.options.length = 0;
for (var lang in Ardublockly.LANGUAGE_NAME) {
var option = new Option(Ardublockly.LANGUAGE_NAME[lang], lang);
if (lang == selectedLang) {
option.selected = true;
}
languageMenu.options.add(option);
}
languageMenu.onchange = Ardublockly.changeLanguage;
};
/** Updates the page displayed text with the new language. */
Ardublockly.updateLanguageText = function() {
//TODO: The page strings still need to be moved into language files
//document.getElementById('xxx').textContent = MSG['xxx'];
//document.getElementById('xxxButton').title = MSG['xxx'];
};
/** Injects the langauge javscript files into the html head element. */
Ardublockly.injectLanguageJsSources = function() {
var head = document.getElementsByTagName('head')[0];
var appLangJsLoad = document.createElement('script');
appLangJsLoad.src = 'msg/' + Ardublockly.LANG + '.js';
head.appendChild(appLangJsLoad);
var blocklyLangJsLoad = document.createElement('script');
blocklyLangJsLoad.src = '../blockly/msg/js/' + Ardublockly.LANG + '.js';
head.appendChild(blocklyLangJsLoad);
};
/** Saves the blocks and reloads with a different language. */
Ardublockly.changeLanguage = function() {
// Store the blocks for the duration of the reload only
Ardublockly.saveSessionStorageBlocks();
var languageMenu = document.getElementById('language');
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;
};
/** Sets the Ardublockly server IDE setting to upload and sends the code. */
Ardublockly.ideSendUpload = function() {
// Check if this is the currently selected option before edit sever setting
......@@ -162,7 +270,7 @@ Ardublockly.initialiseIdeButtons = function() {
/**
* Changes the IDE launch buttons based on the option indicated in the argument.
* @param {!string} value One of the 3 possible values from the drop down select
* in the settings modal: 'upload', 'verify', or 'open'.
* in the settings modal: 'upload', 'verify', or 'open'.
*/
Ardublockly.changeIdeButtons = function(value) {
if (value === 'upload') {
......@@ -429,10 +537,9 @@ Ardublockly.setIdeHtml = function(jsonResponse) {
/**
* Sets the IDE settings data with the selected user input from the drop down.
* @param {Event} e Event that triggered this function call. Required for link
* it to the listeners, but not used.
* it to the listeners, but not used.
* @param {string} preset A value to set the IDE settings bypassing the drop
* down selected value. Valid data: 'upload', 'verify',
* or 'open'.
* down selected value. Valid data: 'upload', 'verify', or 'open'.
*/
Ardublockly.setIdeSettings = function(e, preset) {
if (preset !== undefined) {
......
......@@ -42,6 +42,8 @@ Ardublockly.injectBlockly = function(blocklyEl, toolboxPath) {
// Once file is open, inject blockly into element with the toolbox string
request.onreadystatechange = function() {
if ((request.readyState == 4) && (request.status == 200)) {
var xmlTree = Blockly.Xml.textToDom(request.responseText);
Ardublockly.updateToolboxLanguage(xmlTree);
Ardublockly.workspace = Blockly.inject(blocklyEl, {
collapse: true,
comments: true,
......@@ -49,9 +51,10 @@ Ardublockly.injectBlockly = function(blocklyEl, toolboxPath) {
media: '../blockly/media/',
rtl: false,
scrollbars: true,
toolbox: request.responseText,
toolbox: xmlTree,
trashcan: true });
Ardublockly.BLOCKLY_INJECTED_ = true;
Ardublockly.loadSessionStorageBlocks();
}
};
......@@ -85,11 +88,11 @@ Ardublockly.bindBlocklyEventListeners = function() {
* workspace.
* @param {!string} xmlFile XML file path in a reachable server (no local path).
* @param {!function} callbackFileLoaded Function to be called once the file is
* loaded.
* loaded.
* @param {!function} callbackConectonError Function to be called if there is a
* connection error to the XML server.
* connection error to the XML server.
*/
Ardublockly.loadXmlBlockFile = function(xmlFile, callbackFileLoaded,
Ardublockly.loadXmlBlockFile = function(xmlFile, callbackFileLoaded,
callbackConectonError) {
// Create a an XML HTTP request
var request = Ardublockly.ajaxRequest();
......@@ -171,6 +174,34 @@ Ardublockly.loadBlocksfromXmlDom = function(blocksXmlDom) {
return true;
};
/**
* Save blocks into session storage. Note that MSIE 11 does not support
* sessionStorage on file:// URLs.
*/
Ardublockly.saveSessionStorageBlocks = function() {
if (window.sessionStorage) {
var xml = Blockly.Xml.workspaceToDom(Ardublockly.workspace);
var text = Blockly.Xml.domToText(xml);
window.sessionStorage.loadOnceBlocks = text;
}
};
/** Load blocks saved on session storage and deletes them from storage. */
Ardublockly.loadSessionStorageBlocks = function() {
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) {
delete window.sessionStorage.loadOnceBlocks;
var xml = Blockly.Xml.textToDom(loadOnce);
Blockly.Xml.domToWorkspace(Ardublockly.workspace, xml);
}
};
/** Discard all blocks from the workspace. */
Ardublockly.discardAllBlocks = function() {
var blockCount = Ardublockly.workspace.getAllBlocks().length;
......@@ -190,7 +221,7 @@ Ardublockly.discardAllBlocks = function() {
}
};
/**
/**
* Changes the Arduino board profile if different from the currently set one.
* @param {string} newBoard Name of the new profile to set.
*/
......@@ -200,6 +231,20 @@ Ardublockly.changeBlocklyArduinoBoard = function(newBoard) {
}
};
/** Update the toolbox categories language. */
Ardublockly.updateToolboxLanguage = function(xmlTree) {
var categories = ['catLogic', 'catLoops', 'catMath', 'catText',
'catVariables', 'catFunctions', 'catInputOutput',
'catTime', 'catMotors', 'catComms'];
var categoryNodes = xmlTree.getElementsByTagName('category');
for (var i = 0, cat; cat = categoryNodes[i]; i++) {
var catId = cat.getAttribute('id');
if (MSG[catId]) {
cat.setAttribute('name', MSG[catId]);
}
}
};
/** Closes the toolbox block container sub-menu. */
Ardublockly.blocklyCloseToolbox = function() {
Ardublockly.workspace.toolbox_.flyout_.hide();
......
......@@ -26,7 +26,8 @@ Ardublockly.materializeJsInit = function() {
$('.button-collapse').sideNav({
menuWidth: 240,
activationWidth: 70,
edge: 'left'});
edge: 'left'
});
// Drop down menus
$('.dropdown-button').dropdown({hover: false});
// Overlay content panels using modals (android dialogs)
......
<xml>
<sep></sep>
<category name="Logic">
<category id="catLogic" name="Logic">
<block type="controls_if"></block>
<block type="logic_compare"></block>
<block type="logic_operation"></block>
......@@ -10,7 +10,7 @@
<block type="logic_ternary"></block>
</category>
<sep></sep>
<category name="Loops">
<category id="catLoops" name="Loops">
<block type="controls_repeat_ext">
<value name="TIMES">
<block type="math_number">
......@@ -39,7 +39,7 @@
<block type="controls_flow_statements"></block>
</category>
<sep></sep>
<category name="Math">
<category id="catMath" name="Math">
<block type="math_number"></block>
<block type="math_arithmetic"></block>
<block type="math_single"></block>
......@@ -83,7 +83,7 @@
<block type="base_map"></block>
</category>
<sep></sep>
<category name="Text">
<category id="catText" name="Text">
<block type="text"></block>
<block type="text_join"></block>
<block type="text_append">
......@@ -97,7 +97,7 @@
<!--block type="text_print"></block Part of the serial comms -->
</category>
<sep></sep>
<category name="Variables">
<category id="catVariables" name="Variables">
<block type="variables_get"></block>
<block type="variables_set"></block>
<block type="variables_set">
......@@ -108,9 +108,9 @@
<block type="variables_set_type"></block>
</category>
<sep></sep>
<category name="Functions" custom="PROCEDURE"></category>
<category id="catFunctions" name="Functions" custom="PROCEDURE"></category>
<sep></sep>
<category name="Input/Output">
<category id="catInputOutput" name="Input/Output">
<block type="io_digitalwrite">
<value name="STATE">
<block type="io_highlow"></block>
......@@ -127,7 +127,7 @@
<block type="io_highlow"></block>
</category>
<sep></sep>
<category name="Time">
<category id="catTime" name="Time">
<block type="time_delay">
<value name="DELAY_TIME_MILI">
<block type="math_number">
......@@ -147,7 +147,7 @@
<block type="infinite_loop"></block>
</category>
<sep></sep>
<category name="Motors">
<category id="catMotors" name="Motors">
<block type="servo_write">
<value name="SERVO_ANGLE">
<block type="math_number">
......@@ -179,7 +179,7 @@
</block>
</category>
<sep></sep>
<category name="Comms">
<category id="catComms" name="Comms">
<block type="serial_setup"></block>
<block type="serial_print"></block>
<block type="text_prompt_ext">
......
......@@ -158,7 +158,7 @@ ArdublocklyServer.createElementFromJson = function(json_data) {
element.appendChild(el_err);
}
} else {
//TODO: Not recognised alert the user/developer somehow
//TODO: Not recognised, alert the user/developer somehow
}
return element;
......
......@@ -8,9 +8,9 @@
<title>Ardublockly</title>
<!-- Materialize, Prettify, and Ardublockly CSS -->
<link href="materialize/materialize.css" rel="stylesheet" media="screen,projection">
<link rel="stylesheet" href="materialize/materialize.css" media="screen,projection">
<link rel="stylesheet" href="prettify/arduino.css">
<link href="ardublockly.css" rel="stylesheet" media="screen,projection">
<link rel="stylesheet" href="ardublockly.css" media="screen,projection">
<!-- Ardublockly - For now uncompressed files -->
<!--script src="../blockly/blockly_compressed.js"></script-->
......@@ -49,7 +49,9 @@
<script src="../blockly/generators/arduino/text.js"></script>
<script src="../blockly/generators/arduino/time.js"></script>
<script src="../blockly/generators/arduino/variables.js"></script>
<!-- Default language js files, user selection appended to head -->
<script src="../blockly/msg/js/en.js"></script>
<script src="msg/en.js"></script>
</head>
<body>
......@@ -220,17 +222,19 @@
<div class="settings_div">
<label>COM Port:</label>
<select name="settings_serial" id="serial_port">
<option value="COM4">COM unknown</option>
<option value="COMX">COM unknown</option>
</select>
</div>
<div class="settings_div">
<label>Default IDE button:</label> <br>
<select name="settings_ide" id="ide_settings">
<option value="verify">Verify sketch</option>
<option value="open">Open sketch in IDE </option>
<option value="upload">Compile and Upload sketch</option>
<option value="verify">IDE ptions unknown</option>
</select>
</div>
<div class="settings_div">
<label>Language:</label> <br>
<select name="settings_language" id="language"></select>
</div>
</div>
<div class="modal-footer">
<a href="#" class="waves-effect btn-flat modal-close">Return</a>
......
var MSG = {
title: "Code",
blocks: "Blocks",
linkTooltip: "Save and link to blocks.",
runTooltip: "Run the program defined by the blocks in the workspace.",
badCode: "Program error:\n%1",
timeout: "Maximum execution iterations exceeded.",
discard: "Delete all %1 blocks?",
trashTooltip: "Discard all blocks.",
catLogic: "Logic",
catLoops: "Loops",
catMath: "Math",
catText: "Text",
catVariables: "Variables",
catFunctions: "Functions",
catInputOutput: "Input/Output",
catTime: "Time",
catMotors: "Motors",
catComms: "Comms",
textVariable: "text",
httpRequestError: "There was a problem with the request.",
linkAlert: "Share your blocks with this link:\n\n%1",
hashError: "Sorry, '%1' doesn't correspond with any saved program.",
xmlError: "Could not load your saved file. Perhaps it was created with a different version of Blockly?",
badXml: "Error parsing XML:\n%1\n\nSelect 'OK' to abandon your changes or 'Cancel' to further edit the XML."
};
var MSG = {
title: "Código",
blocks: "Bloques",
linkTooltip: "Guarda conexión a los bloques.",
runTooltip: "Ejecute el programa definido por los bloques en el área de trabajo.",
badCode: "Error del programa:\n%1",
timeout: "Se excedio el máximo de iteraciones ejecutadas permitidas.",
discard: "¿Eliminar todos los bloques %1?",
trashTooltip: "Descartar todos los bloques.",
catLogic: "Lógica",
catLoops: "Secuencias",
catMath: "Matemáticas",
catText: "Texto",
catVariables: "Variables",
catFunctions: "Funciones",
catInputOutput: "Input/Output",
catTime: "Tiempo",
catMotors: "Motores",
catComms: "Comunicación",
textVariable: "texto",
httpRequestError: "Hubo un problema con la petición.",
linkAlert: "Comparte tus bloques con este enlace:\n\n%1",
hashError: "«%1» no corresponde con ningún programa guardado.",
xmlError: "No se pudo cargar el archivo guardado. ¿Quizá fue creado con otra versión de Blockly?",
badXml: "Error de análisis XML:\n%1\n\nSelecciona OK para abandonar tus cambios o Cancelar para seguir editando el XML."
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment