From 06352c0eea00549e22e9b00125c66f9430028662 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Jun 2021 17:27:01 +0000 Subject: [PATCH 01/36] Use selenium-standalone-service to automatically start and stop Selenium when running the test suite. --- package-lock.json | 144 ++++++++++++++++++ package.json | 12 +- tests/generators/run_generators_in_browser.js | 12 +- tests/mocha/run_mocha_tests_in_browser.js | 4 +- 4 files changed, 160 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5996d2bf6..deab056a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -414,6 +414,15 @@ "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==", "dev": true }, + "@types/fs-extra": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz", + "integrity": "sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/http-cache-semantics": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", @@ -456,6 +465,15 @@ "@types/node": "*" } }, + "@types/selenium-standalone": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/@types/selenium-standalone/-/selenium-standalone-6.15.2.tgz", + "integrity": "sha512-Jnt4AHHcUOPGuZ5cJRYfP3IpPalNc/o1BmFvuFFmLtU2PtvEGvyyJPdpErqzZDxsP8E4yjTst0GL+QMJiEWuBA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/vinyl": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.4.tgz", @@ -593,6 +611,121 @@ "@wdio/utils": "7.6.0" } }, + "@wdio/selenium-standalone-service": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/@wdio/selenium-standalone-service/-/selenium-standalone-service-6.12.1.tgz", + "integrity": "sha512-9R5iTAb5p7XEWfn9WkiH8K3tgArmUJ0U3CcOQCeaHQBZks5DhNQv6ZQIodnIDyWHjoEfwnF9n+/UKsfPOk4rCQ==", + "dev": true, + "requires": { + "@types/fs-extra": "^9.0.1", + "@types/selenium-standalone": "^6.15.2", + "@wdio/config": "6.12.1", + "@wdio/logger": "6.10.10", + "fs-extra": "^9.0.1", + "selenium-standalone": "^6.22.1" + }, + "dependencies": { + "@wdio/config": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-6.12.1.tgz", + "integrity": "sha512-V5hTIW5FNlZ1W33smHF4Rd5BKjGW2KeYhyXDQfXHjqLCeRiirZ9fABCo9plaVQDnwWSUMWYaAaIAifV82/oJCQ==", + "dev": true, + "requires": { + "@wdio/logger": "6.10.10", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + } + }, + "@wdio/logger": { + "version": "6.10.10", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-6.10.10.tgz", + "integrity": "sha512-2nh0hJz9HeZE0VIEMI+oPgjr/Q37ohrR9iqsl7f7GW5ik+PnKYCT9Eab5mR1GNMG60askwbskgGC1S9ygtvrSw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@wdio/types": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.6.0.tgz", @@ -1146,6 +1279,12 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -8539,6 +8678,11 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==" + }, "typescript-closure-tools": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/typescript-closure-tools/-/typescript-closure-tools-0.0.7.tgz", diff --git a/package.json b/package.json index 6adb5f0a1..1062d132d 100644 --- a/package.json +++ b/package.json @@ -40,12 +40,8 @@ "publish:beta": "gulp publishBeta", "recompile": "gulp recompile", "release": "gulp gitCreateRC", - "test": "concurrently 'npm run test:prepare' 'sleep 5 && npm run test:run'", - "test:generators": "concurrently 'npm run test:prepare' 'sleep 5 && tests/scripts/run_generators.sh'", - "test:prepare": "npm run test:setupselenium && npm run test:startselenium", - "test:run": "tests/run_all_tests.sh", - "test:setupselenium": "selenium-standalone install --config=./tests/scripts/selenium-config.js", - "test:startselenium": "selenium-standalone start --config=./tests/scripts/selenium-config.js", + "test": "tests/run_all_tests.sh", + "test:generators": "tests/scripts/run_generators.sh", "test:compile:advanced": "gulp buildAdvancedCompilationTest", "typings": "gulp typings", "updateGithubPages": "gulp gitUpdateGithubPages" @@ -65,6 +61,7 @@ "@blockly/dev-tools": "^2.0.1", "@blockly/theme-dark": "^1.0.0", "@blockly/theme-modern": "^2.1.1", + "@wdio/selenium-standalone-service": "^6.11.0", "babel-eslint": "^10.1.0", "chai": "^4.2.0", "clang-format": "^1.5.0", @@ -92,6 +89,7 @@ "yargs": "^16.0.3" }, "dependencies": { - "jsdom": "15.2.1" + "jsdom": "15.2.1", + "typescript": "^4.3.2" } } diff --git a/tests/generators/run_generators_in_browser.js b/tests/generators/run_generators_in_browser.js index f0bafe10c..9fe1ebb78 100644 --- a/tests/generators/run_generators_in_browser.js +++ b/tests/generators/run_generators_in_browser.js @@ -40,14 +40,18 @@ async function runLangGeneratorInBrowser(browser, filename, codegenFn) { async function runGeneratorsInBrowser() { var options = { capabilities: { - browserName: 'firefox' + browserName: 'chrome', }, - path: '/wd/hub' + services: ['selenium-standalone'] }; // Run in headless mode on Github Actions. if (process.env.CI) { - options.capabilities['moz:firefoxOptions'] = { - args: ['-headless'] + options.capabilities['goog:chromeOptions'] = { + args: ['--headless', '--no-sandbox', '--disable-dev-shm-usage', '--allow-file-access-from-files'] + }; + } else { + options.capabilities['goog:chromeOptions'] = { + args: ['--allow-file-access-from-files'] }; } diff --git a/tests/mocha/run_mocha_tests_in_browser.js b/tests/mocha/run_mocha_tests_in_browser.js index 5adeabc2d..15fc41e4a 100644 --- a/tests/mocha/run_mocha_tests_in_browser.js +++ b/tests/mocha/run_mocha_tests_in_browser.js @@ -22,7 +22,9 @@ async function runMochaTestsInBrowser() { capabilities: { browserName: 'chrome' }, - path: '/wd/hub' + services: [ + ['selenium-standalone'] + ] }; // Run in headless mode on Github Actions. if (process.env.CI) { From df7da795a3bd21a5687722efd7f98415a8db01ec Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Jun 2021 17:27:01 +0000 Subject: [PATCH 02/36] Use selenium-standalone-service to automatically start and stop Selenium when running the test suite. --- package-lock.json | 144 ++++++++++++++++++ package.json | 12 +- tests/generators/run_generators_in_browser.js | 12 +- tests/mocha/run_mocha_tests_in_browser.js | 4 +- 4 files changed, 160 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5996d2bf6..deab056a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -414,6 +414,15 @@ "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==", "dev": true }, + "@types/fs-extra": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz", + "integrity": "sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/http-cache-semantics": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", @@ -456,6 +465,15 @@ "@types/node": "*" } }, + "@types/selenium-standalone": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/@types/selenium-standalone/-/selenium-standalone-6.15.2.tgz", + "integrity": "sha512-Jnt4AHHcUOPGuZ5cJRYfP3IpPalNc/o1BmFvuFFmLtU2PtvEGvyyJPdpErqzZDxsP8E4yjTst0GL+QMJiEWuBA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/vinyl": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.4.tgz", @@ -593,6 +611,121 @@ "@wdio/utils": "7.6.0" } }, + "@wdio/selenium-standalone-service": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/@wdio/selenium-standalone-service/-/selenium-standalone-service-6.12.1.tgz", + "integrity": "sha512-9R5iTAb5p7XEWfn9WkiH8K3tgArmUJ0U3CcOQCeaHQBZks5DhNQv6ZQIodnIDyWHjoEfwnF9n+/UKsfPOk4rCQ==", + "dev": true, + "requires": { + "@types/fs-extra": "^9.0.1", + "@types/selenium-standalone": "^6.15.2", + "@wdio/config": "6.12.1", + "@wdio/logger": "6.10.10", + "fs-extra": "^9.0.1", + "selenium-standalone": "^6.22.1" + }, + "dependencies": { + "@wdio/config": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/@wdio/config/-/config-6.12.1.tgz", + "integrity": "sha512-V5hTIW5FNlZ1W33smHF4Rd5BKjGW2KeYhyXDQfXHjqLCeRiirZ9fABCo9plaVQDnwWSUMWYaAaIAifV82/oJCQ==", + "dev": true, + "requires": { + "@wdio/logger": "6.10.10", + "deepmerge": "^4.0.0", + "glob": "^7.1.2" + } + }, + "@wdio/logger": { + "version": "6.10.10", + "resolved": "https://registry.npmjs.org/@wdio/logger/-/logger-6.10.10.tgz", + "integrity": "sha512-2nh0hJz9HeZE0VIEMI+oPgjr/Q37ohrR9iqsl7f7GW5ik+PnKYCT9Eab5mR1GNMG60askwbskgGC1S9ygtvrSw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "loglevel": "^1.6.0", + "loglevel-plugin-prefix": "^0.8.4", + "strip-ansi": "^6.0.0" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "@wdio/types": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/@wdio/types/-/types-7.6.0.tgz", @@ -1146,6 +1279,12 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -8539,6 +8678,11 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==" + }, "typescript-closure-tools": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/typescript-closure-tools/-/typescript-closure-tools-0.0.7.tgz", diff --git a/package.json b/package.json index 6adb5f0a1..1062d132d 100644 --- a/package.json +++ b/package.json @@ -40,12 +40,8 @@ "publish:beta": "gulp publishBeta", "recompile": "gulp recompile", "release": "gulp gitCreateRC", - "test": "concurrently 'npm run test:prepare' 'sleep 5 && npm run test:run'", - "test:generators": "concurrently 'npm run test:prepare' 'sleep 5 && tests/scripts/run_generators.sh'", - "test:prepare": "npm run test:setupselenium && npm run test:startselenium", - "test:run": "tests/run_all_tests.sh", - "test:setupselenium": "selenium-standalone install --config=./tests/scripts/selenium-config.js", - "test:startselenium": "selenium-standalone start --config=./tests/scripts/selenium-config.js", + "test": "tests/run_all_tests.sh", + "test:generators": "tests/scripts/run_generators.sh", "test:compile:advanced": "gulp buildAdvancedCompilationTest", "typings": "gulp typings", "updateGithubPages": "gulp gitUpdateGithubPages" @@ -65,6 +61,7 @@ "@blockly/dev-tools": "^2.0.1", "@blockly/theme-dark": "^1.0.0", "@blockly/theme-modern": "^2.1.1", + "@wdio/selenium-standalone-service": "^6.11.0", "babel-eslint": "^10.1.0", "chai": "^4.2.0", "clang-format": "^1.5.0", @@ -92,6 +89,7 @@ "yargs": "^16.0.3" }, "dependencies": { - "jsdom": "15.2.1" + "jsdom": "15.2.1", + "typescript": "^4.3.2" } } diff --git a/tests/generators/run_generators_in_browser.js b/tests/generators/run_generators_in_browser.js index f0bafe10c..9fe1ebb78 100644 --- a/tests/generators/run_generators_in_browser.js +++ b/tests/generators/run_generators_in_browser.js @@ -40,14 +40,18 @@ async function runLangGeneratorInBrowser(browser, filename, codegenFn) { async function runGeneratorsInBrowser() { var options = { capabilities: { - browserName: 'firefox' + browserName: 'chrome', }, - path: '/wd/hub' + services: ['selenium-standalone'] }; // Run in headless mode on Github Actions. if (process.env.CI) { - options.capabilities['moz:firefoxOptions'] = { - args: ['-headless'] + options.capabilities['goog:chromeOptions'] = { + args: ['--headless', '--no-sandbox', '--disable-dev-shm-usage', '--allow-file-access-from-files'] + }; + } else { + options.capabilities['goog:chromeOptions'] = { + args: ['--allow-file-access-from-files'] }; } diff --git a/tests/mocha/run_mocha_tests_in_browser.js b/tests/mocha/run_mocha_tests_in_browser.js index 5adeabc2d..15fc41e4a 100644 --- a/tests/mocha/run_mocha_tests_in_browser.js +++ b/tests/mocha/run_mocha_tests_in_browser.js @@ -22,7 +22,9 @@ async function runMochaTestsInBrowser() { capabilities: { browserName: 'chrome' }, - path: '/wd/hub' + services: [ + ['selenium-standalone'] + ] }; // Run in headless mode on Github Actions. if (process.env.CI) { From 146840e09fc8c100d03c79f12839ea535b730376 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Jun 2021 18:54:13 +0000 Subject: [PATCH 03/36] Updated CI config to run new simplified test target. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a6b02f13f..f00730990 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,7 +37,7 @@ jobs: run: source ./tests/scripts/setup_osx_env.sh - name: Run - run: npm run test:run + run: npm run test env: CI: true From 5cd2d375ef44cb996fd71c3c10d164f982f52e64 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Jun 2021 19:06:28 +0000 Subject: [PATCH 04/36] Updated comment for runGeneratorsInBrowser to refer to Chrome instead of Firefox. --- tests/generators/run_generators_in_browser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/generators/run_generators_in_browser.js b/tests/generators/run_generators_in_browser.js index 9fe1ebb78..d0ed80009 100644 --- a/tests/generators/run_generators_in_browser.js +++ b/tests/generators/run_generators_in_browser.js @@ -32,8 +32,8 @@ async function runLangGeneratorInBrowser(browser, filename, codegenFn) { } /** - * Runs the generator tests in Firefox. It uses webdriverio to - * launch Firefox and load index.html. Outputs a summary of the test results + * Runs the generator tests in Chrome. It uses webdriverio to + * launch Chrome and load index.html. Outputs a summary of the test results * to the console and outputs files for later validation. * @return the Thenable managing the processing of the browser tests. */ From 1931c31aa6415cb4b37174b6d911f6827ae33a9c Mon Sep 17 00:00:00 2001 From: Monica Kozbial <6621618+moniika@users.noreply.github.com> Date: Mon, 14 Jun 2021 12:19:36 -0700 Subject: [PATCH 05/36] Update JsDoc for IDragTarget (#4907) --- core/interfaces/i_drag_target.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/interfaces/i_drag_target.js b/core/interfaces/i_drag_target.js index 186bc8cb9..0af765d57 100644 --- a/core/interfaces/i_drag_target.js +++ b/core/interfaces/i_drag_target.js @@ -30,7 +30,8 @@ Blockly.IDragTarget = function() {}; /** * Returns the bounding rectangle of the drag target area in pixel units * relative to viewport. - * @return {Blockly.utils.Rect} The component's bounding box. + * @return {?Blockly.utils.Rect} The component's bounding box. Null if drag + * target area should be ignored. */ Blockly.IDragTarget.prototype.getClientRect; From 65339377f4f0cc3dcb93c50dea43315f33821f4f Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Jun 2021 19:40:41 +0000 Subject: [PATCH 06/36] Moved Typescript to devDependencies. --- package-lock.json | 3 ++- package.json | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index deab056a8..964aa9cdc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8681,7 +8681,8 @@ "typescript": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", - "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==" + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", + "dev": true }, "typescript-closure-tools": { "version": "0.0.7", diff --git a/package.json b/package.json index 1062d132d..f0cb52773 100644 --- a/package.json +++ b/package.json @@ -84,12 +84,12 @@ "rimraf": "^3.0.2", "selenium-standalone": "^6.17.0", "through2": "^4.0.2", + "typescript": "^4.3.2", "typescript-closure-tools": "^0.0.7", "webdriverio": "^7.0.3", "yargs": "^16.0.3" }, "dependencies": { - "jsdom": "15.2.1", - "typescript": "^4.3.2" + "jsdom": "15.2.1" } } From ff34e067f8444eb4e920ac23a5cd7a3bc3b803ee Mon Sep 17 00:00:00 2001 From: Monica Kozbial <6621618+moniika@users.noreply.github.com> Date: Mon, 14 Jun 2021 13:14:01 -0700 Subject: [PATCH 07/36] Update positionable jsdoc (#4908) --- core/interfaces/i_positionable.js | 3 ++- core/trashcan.js | 3 ++- core/workspace_svg.js | 5 ++++- core/zoom_controls.js | 3 ++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core/interfaces/i_positionable.js b/core/interfaces/i_positionable.js index 89f4c8094..356510c81 100644 --- a/core/interfaces/i_positionable.js +++ b/core/interfaces/i_positionable.js @@ -37,6 +37,7 @@ Blockly.IPositionable.prototype.position; /** * Returns the bounding rectangle of the UI element in pixel units relative to * the Blockly injection div. - * @return {!Blockly.utils.Rect} The UI elements’s bounding box. + * @return {?Blockly.utils.Rect} The UI elements’s bounding box. Null if + * bounding box should be ignored by other UI elements. */ Blockly.IPositionable.prototype.getBoundingRectangle; diff --git a/core/trashcan.js b/core/trashcan.js index 968ee916c..f6ad48ba4 100644 --- a/core/trashcan.js +++ b/core/trashcan.js @@ -506,7 +506,8 @@ Blockly.Trashcan.prototype.position = function(metrics, savedPositions) { /** * Returns the bounding rectangle of the UI element in pixel units relative to * the Blockly injection div. - * @return {!Blockly.utils.Rect} The UI elements’s bounding box. + * @return {?Blockly.utils.Rect} The UI elements’s bounding box. Null if + * bounding box should be ignored by other UI elements. */ Blockly.Trashcan.prototype.getBoundingRectangle = function() { var bottom = this.top_ + this.BODY_HEIGHT_ + this.LID_HEIGHT_; diff --git a/core/workspace_svg.js b/core/workspace_svg.js index ea06193bc..95618dbef 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -1148,7 +1148,10 @@ Blockly.WorkspaceSvg.prototype.resize = function() { var savedPositions = []; for (var i = 0, positionable; (positionable = positionables[i]); i++) { positionable.position(metrics, savedPositions); - savedPositions.push(positionable.getBoundingRectangle()); + var boundingRect = positionable.getBoundingRectangle(); + if (boundingRect) { + savedPositions.push(boundingRect); + } } if (this.scrollbar) { diff --git a/core/zoom_controls.js b/core/zoom_controls.js index b86111a3b..07c63e904 100644 --- a/core/zoom_controls.js +++ b/core/zoom_controls.js @@ -228,7 +228,8 @@ Blockly.ZoomControls.prototype.dispose = function() { /** * Returns the bounding rectangle of the UI element in pixel units relative to * the Blockly injection div. - * @return {!Blockly.utils.Rect} The UI elements’s bounding box. + * @return {?Blockly.utils.Rect} The UI elements’s bounding box. Null if + * bounding box should be ignored by other UI elements. */ Blockly.ZoomControls.prototype.getBoundingRectangle = function() { var height = this.SMALL_SPACING_ + 2 * this.HEIGHT_; From c29afbcd2762f264a0cf952b6662d4a1c2736e50 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 14 Jun 2021 22:14:46 +0000 Subject: [PATCH 08/36] Updated user agent parsing to detect iPads posing as desktop Safari. --- core/utils/useragent.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/utils/useragent.js b/core/utils/useragent.js index 0df8467ed..8fa1f09e4 100644 --- a/core/utils/useragent.js +++ b/core/utils/useragent.js @@ -93,9 +93,11 @@ Blockly.utils.userAgent.MOBILE; !Blockly.utils.userAgent.EDGE; // Platforms. Logic from: - // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js and + // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/extra.js Blockly.utils.userAgent.ANDROID = has('Android'); - Blockly.utils.userAgent.IPAD = has('iPad'); + Blockly.utils.userAgent.IPAD = has('iPad') || + has('Macintosh') && navigator.maxTouchPoints > 0; Blockly.utils.userAgent.IPOD = has('iPod'); Blockly.utils.userAgent.IPHONE = has('iPhone') && !Blockly.utils.userAgent.IPAD && !Blockly.utils.userAgent.IPOD; From 0eef4f34f6f9acb7b12d734f7102b457a53dfb1d Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 14 Jun 2021 22:32:55 -0700 Subject: [PATCH 09/36] 'navigator' may be renamed by the compiler. Use quoted name instead. Also, navigator doesn't exist in Node, or non-browser environments. --- core/utils/useragent.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/utils/useragent.js b/core/utils/useragent.js index 8fa1f09e4..2eb854f72 100644 --- a/core/utils/useragent.js +++ b/core/utils/useragent.js @@ -96,8 +96,8 @@ Blockly.utils.userAgent.MOBILE; // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js and // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/extra.js Blockly.utils.userAgent.ANDROID = has('Android'); - Blockly.utils.userAgent.IPAD = has('iPad') || - has('Macintosh') && navigator.maxTouchPoints > 0; + var maxTouchPoints = Blockly.utils.global['navigator'] && Blockly.utils.global['navigator']['maxTouchPoints']; + Blockly.utils.userAgent.IPAD = has('iPad') || has('Macintosh') && maxTouchPoints > 0; Blockly.utils.userAgent.IPOD = has('iPod'); Blockly.utils.userAgent.IPHONE = has('iPhone') && !Blockly.utils.userAgent.IPAD && !Blockly.utils.userAgent.IPOD; From 289d8ac857b9296e33efb57139e3137d1700779d Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 15 Jun 2021 15:22:51 +0000 Subject: [PATCH 10/36] Adjusted line wrapping. --- core/utils/useragent.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/utils/useragent.js b/core/utils/useragent.js index 2eb854f72..fb6fadd69 100644 --- a/core/utils/useragent.js +++ b/core/utils/useragent.js @@ -96,8 +96,10 @@ Blockly.utils.userAgent.MOBILE; // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/platform.js and // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/extra.js Blockly.utils.userAgent.ANDROID = has('Android'); - var maxTouchPoints = Blockly.utils.global['navigator'] && Blockly.utils.global['navigator']['maxTouchPoints']; - Blockly.utils.userAgent.IPAD = has('iPad') || has('Macintosh') && maxTouchPoints > 0; + var maxTouchPoints = Blockly.utils.global['navigator'] && + Blockly.utils.global['navigator']['maxTouchPoints']; + Blockly.utils.userAgent.IPAD = has('iPad') || + has('Macintosh') && maxTouchPoints > 0; Blockly.utils.userAgent.IPOD = has('iPod'); Blockly.utils.userAgent.IPHONE = has('iPhone') && !Blockly.utils.userAgent.IPAD && !Blockly.utils.userAgent.IPOD; From e5a2df301a0ef9658ed47e85d7d40f8d7fe2f98b Mon Sep 17 00:00:00 2001 From: Monica Kozbial <6621618+moniika@users.noreply.github.com> Date: Tue, 15 Jun 2021 11:27:36 -0700 Subject: [PATCH 11/36] Add msg files (#4918) --- msg/js/bs.js | 434 ++++++++++++++++++++++++++++++++++++++++++++++++++ msg/js/zgh.js | 434 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 868 insertions(+) create mode 100644 msg/js/bs.js create mode 100644 msg/js/zgh.js diff --git a/msg/js/bs.js b/msg/js/bs.js new file mode 100644 index 000000000..567ce8471 --- /dev/null +++ b/msg/js/bs.js @@ -0,0 +1,434 @@ +// This file was automatically generated. Do not modify. + +'use strict'; + +Blockly.Msg["ADD_COMMENT"] = "Dodaj komentar"; +Blockly.Msg["CANNOT_DELETE_VARIABLE_PROCEDURE"] = "Ne mogu izbrisati varijablu \"%1\" jer je dio definicije funckije \"%2\""; +Blockly.Msg["CHANGE_VALUE_TITLE"] = "Promijeni vrijednost:"; +Blockly.Msg["CLEAN_UP"] = "Očisti blokove"; +Blockly.Msg["COLLAPSED_WARNINGS_WARNING"] = "Collapsed blocks contain warnings."; // untranslated +Blockly.Msg["COLLAPSE_ALL"] = "Skupi blokove"; +Blockly.Msg["COLLAPSE_BLOCK"] = "Skupi blok"; +Blockly.Msg["COLOUR_BLEND_COLOUR1"] = "boju 1"; +Blockly.Msg["COLOUR_BLEND_COLOUR2"] = "boju 2"; +Blockly.Msg["COLOUR_BLEND_HELPURL"] = "https://meyerweb.com/eric/tools/color-blend/#:::rgbp"; // untranslated +Blockly.Msg["COLOUR_BLEND_RATIO"] = "odnos"; +Blockly.Msg["COLOUR_BLEND_TITLE"] = "pomiješaj"; +Blockly.Msg["COLOUR_BLEND_TOOLTIP"] = "Pomiješaj dvije boje zajedno sa zadanim odnosom (0.0 - 1.0)."; +Blockly.Msg["COLOUR_PICKER_HELPURL"] = "https://bs.wikipedia.org/wiki/Boja"; +Blockly.Msg["COLOUR_PICKER_TOOLTIP"] = "Izaberi boju sa palete."; +Blockly.Msg["COLOUR_RANDOM_HELPURL"] = "http://randomcolour.com"; // untranslated +Blockly.Msg["COLOUR_RANDOM_TITLE"] = "nasumična boja"; +Blockly.Msg["COLOUR_RANDOM_TOOLTIP"] = "Odaberi boju nasumično."; +Blockly.Msg["COLOUR_RGB_BLUE"] = "plavom"; +Blockly.Msg["COLOUR_RGB_GREEN"] = "zelenom"; +Blockly.Msg["COLOUR_RGB_HELPURL"] = "https://www.december.com/html/spec/colorpercompact.html"; // untranslated +Blockly.Msg["COLOUR_RGB_RED"] = "crvenom"; +Blockly.Msg["COLOUR_RGB_TITLE"] = "boja sa"; +Blockly.Msg["COLOUR_RGB_TOOLTIP"] = "Napravi boju s određenom količinom crvene, zelene i plave boje. Sve vrijednosti moraju biti između 0 i 100."; +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#loop-termination-blocks"; // untranslated +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK"] = "izađi iz petlje"; +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE"] = "nastavi sa sljedećom iteracijom petlje"; +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK"] = "Napusti petlju koja sadrži ovaj blok."; +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE"] = "Preskoči ostatak ove petlje i nastavi sa sljedećom iteracijom."; +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_WARNING"] = "Upozorenje: Ovaj blok se može koristiti samo unutar petlje."; +Blockly.Msg["CONTROLS_FOREACH_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#for-each"; // untranslated +Blockly.Msg["CONTROLS_FOREACH_TITLE"] = "za svaku stavku %1 na spisku %2"; +Blockly.Msg["CONTROLS_FOREACH_TOOLTIP"] = "Za svaku stavku na spisku, dodjeljuje vrijednost stavke varijabli \"%1\", a zatim izvršava neke naredbe."; +Blockly.Msg["CONTROLS_FOR_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#count-with"; // untranslated +Blockly.Msg["CONTROLS_FOR_TITLE"] = "broji sa %1 od %2 do %3 po %4"; +Blockly.Msg["CONTROLS_FOR_TOOLTIP"] = "Neka varijabla \"%1\" uzima vrijednosti od početnog do krajnjeg broja, brojeći po određenom intervalu i neka izvršava određene blokove."; +Blockly.Msg["CONTROLS_IF_ELSEIF_TOOLTIP"] = "Dodajte uslov bloku \"ako\"."; +Blockly.Msg["CONTROLS_IF_ELSE_TOOLTIP"] = "Add a final, catch-all condition to the if block."; // untranslated +Blockly.Msg["CONTROLS_IF_HELPURL"] = "https://github.com/google/blockly/wiki/IfElse"; // untranslated +Blockly.Msg["CONTROLS_IF_IF_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this if block."; // untranslated +Blockly.Msg["CONTROLS_IF_MSG_ELSE"] = "inače"; +Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"] = "inače ako"; +Blockly.Msg["CONTROLS_IF_MSG_IF"] = "ako"; +Blockly.Msg["CONTROLS_IF_TOOLTIP_1"] = "Ako je vrijednost tačna, izvršava neke naredbe."; +Blockly.Msg["CONTROLS_IF_TOOLTIP_2"] = "Ako je vrijednost tačna, izvršava neke naredbe. U suprotnom, izvršava drugi blok naredbi."; +Blockly.Msg["CONTROLS_IF_TOOLTIP_3"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements."; // untranslated +Blockly.Msg["CONTROLS_IF_TOOLTIP_4"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements. If none of the values are true, do the last block of statements."; // untranslated +Blockly.Msg["CONTROLS_REPEAT_HELPURL"] = "https://en.wikipedia.org/wiki/For_loop"; // untranslated +Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"] = "izvrši"; +Blockly.Msg["CONTROLS_REPEAT_TITLE"] = "ponovi %1 puta"; +Blockly.Msg["CONTROLS_REPEAT_TOOLTIP"] = "Izvrši neku naredbu nekoliko puta."; +Blockly.Msg["CONTROLS_WHILEUNTIL_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#repeat"; // untranslated +Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_UNTIL"] = "ponavljati do"; +Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_WHILE"] = "ponavljati dok"; +Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL"] = "Dok je vrijednost netačna, izvršava neke naredbe."; +Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_WHILE"] = "Dok je vrijednost tačna, izvršava neke naredbe."; +Blockly.Msg["DELETE_ALL_BLOCKS"] = "Izbrisati svih %1 blokova?"; +Blockly.Msg["DELETE_BLOCK"] = "Obriši blok"; +Blockly.Msg["DELETE_VARIABLE"] = "Izbriši varijablu \"%1\""; +Blockly.Msg["DELETE_VARIABLE_CONFIRMATION"] = "Izbrisati %1 upotrebu varijable \"%2\"?"; +Blockly.Msg["DELETE_X_BLOCKS"] = "Obriši %1 blokova"; +Blockly.Msg["DISABLE_BLOCK"] = "Onemogući blok"; +Blockly.Msg["DUPLICATE_BLOCK"] = "Dupliciraj"; +Blockly.Msg["DUPLICATE_COMMENT"] = "Kopiraj komentar"; +Blockly.Msg["ENABLE_BLOCK"] = "Omogući blok"; +Blockly.Msg["EXPAND_ALL"] = "Proširi blokove"; +Blockly.Msg["EXPAND_BLOCK"] = "Proširi blok"; +Blockly.Msg["EXTERNAL_INPUTS"] = "Vanjski ulazi"; +Blockly.Msg["HELP"] = "Pomoć"; +Blockly.Msg["INLINE_INPUTS"] = "Redni ulazi"; +Blockly.Msg["IOS_CANCEL"] = "Otkaži"; +Blockly.Msg["IOS_ERROR"] = "Greška"; +Blockly.Msg["IOS_OK"] = "U redu"; +Blockly.Msg["IOS_PROCEDURES_ADD_INPUT"] = "+ Dodaj ulaz"; +Blockly.Msg["IOS_PROCEDURES_ALLOW_STATEMENTS"] = "Dozvoli naredbe"; +Blockly.Msg["IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR"] = "This function has duplicate inputs."; // untranslated +Blockly.Msg["IOS_PROCEDURES_INPUTS"] = "ULAZI"; +Blockly.Msg["IOS_VARIABLES_ADD_BUTTON"] = "Dodaj"; +Blockly.Msg["IOS_VARIABLES_ADD_VARIABLE"] = "+ Dodaj varijablu"; +Blockly.Msg["IOS_VARIABLES_DELETE_BUTTON"] = "Obriši"; +Blockly.Msg["IOS_VARIABLES_EMPTY_NAME_ERROR"] = "Ne možete koristiti prazno ime varijable."; +Blockly.Msg["IOS_VARIABLES_RENAME_BUTTON"] = "Preimenuj"; +Blockly.Msg["IOS_VARIABLES_VARIABLE_NAME"] = "Ime varijable"; +Blockly.Msg["LISTS_CREATE_EMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-empty-list"; // untranslated +Blockly.Msg["LISTS_CREATE_EMPTY_TITLE"] = "create empty list"; // untranslated +Blockly.Msg["LISTS_CREATE_EMPTY_TOOLTIP"] = "Returns a list, of length 0, containing no data records"; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TITLE_ADD"] = "list"; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this list block."; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_INPUT_WITH"] = "create list with"; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_ITEM_TOOLTIP"] = "Add an item to the list."; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_TOOLTIP"] = "Create a list with any number of items."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_FIRST"] = "first"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_FROM_END"] = "# from end"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_FROM_START"] = "#"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_GET"] = "get"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_GET_REMOVE"] = "get and remove"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_LAST"] = "last"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_RANDOM"] = "random"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_REMOVE"] = "remove"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TAIL"] = ""; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FIRST"] = "Returns the first item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FROM"] = "Returns the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_LAST"] = "Returns the last item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_RANDOM"] = "Returns a random item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST"] = "Removes and returns the first item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM"] = "Removes and returns the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST"] = "Removes and returns the last item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM"] = "Removes and returns a random item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST"] = "Removes the first item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM"] = "Removes the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST"] = "Removes the last item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM"] = "Removes a random item in a list."; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_END"] = "to # from end"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_START"] = "to #"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_END_LAST"] = "to last"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-a-sublist"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_START_FIRST"] = "get sub-list from first"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_END"] = "get sub-list from # from end"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_START"] = "get sub-list from #"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_TAIL"] = ""; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_TOOLTIP"] = "Creates a copy of the specified portion of a list."; // untranslated +Blockly.Msg["LISTS_INDEX_FROM_END_TOOLTIP"] = "%1 is the last item."; // untranslated +Blockly.Msg["LISTS_INDEX_FROM_START_TOOLTIP"] = "%1 is the first item."; // untranslated +Blockly.Msg["LISTS_INDEX_OF_FIRST"] = "pronađi prvo pojavljivanje stavke"; +Blockly.Msg["LISTS_INDEX_OF_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list"; // untranslated +Blockly.Msg["LISTS_INDEX_OF_LAST"] = "pronađi posljednje pojavljivanje stavke"; +Blockly.Msg["LISTS_INDEX_OF_TOOLTIP"] = "Returns the index of the first/last occurrence of the item in the list. Returns %1 if item is not found."; // untranslated +Blockly.Msg["LISTS_INLIST"] = "na spisku"; +Blockly.Msg["LISTS_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#is-empty"; // untranslated +Blockly.Msg["LISTS_ISEMPTY_TITLE"] = "%1 je prazan"; +Blockly.Msg["LISTS_ISEMPTY_TOOLTIP"] = "Vraća \"tačno\" ako je spisak prazan."; +Blockly.Msg["LISTS_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#length-of"; // untranslated +Blockly.Msg["LISTS_LENGTH_TITLE"] = "dužina spiska %1"; +Blockly.Msg["LISTS_LENGTH_TOOLTIP"] = "Vraća dužinu spiska."; +Blockly.Msg["LISTS_REPEAT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated +Blockly.Msg["LISTS_REPEAT_TITLE"] = "create list with item %1 repeated %2 times"; // untranslated +Blockly.Msg["LISTS_REPEAT_TOOLTIP"] = "Creates a list consisting of the given value repeated the specified number of times."; // untranslated +Blockly.Msg["LISTS_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#reversing-a-list"; // untranslated +Blockly.Msg["LISTS_REVERSE_MESSAGE0"] = "reverse %1"; // untranslated +Blockly.Msg["LISTS_REVERSE_TOOLTIP"] = "Reverse a copy of a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#in-list--set"; // untranslated +Blockly.Msg["LISTS_SET_INDEX_INPUT_TO"] = "as"; // untranslated +Blockly.Msg["LISTS_SET_INDEX_INSERT"] = "insert at"; // untranslated +Blockly.Msg["LISTS_SET_INDEX_SET"] = "set"; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST"] = "Inserts the item at the start of a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FROM"] = "Inserts the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_LAST"] = "Append the item to the end of a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM"] = "Inserts the item randomly in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FIRST"] = "Sets the first item in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FROM"] = "Sets the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_LAST"] = "Sets the last item in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_RANDOM"] = "Sets a random item in a list."; // untranslated +Blockly.Msg["LISTS_SORT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#sorting-a-list"; // untranslated +Blockly.Msg["LISTS_SORT_ORDER_ASCENDING"] = "ascending"; // untranslated +Blockly.Msg["LISTS_SORT_ORDER_DESCENDING"] = "descending"; // untranslated +Blockly.Msg["LISTS_SORT_TITLE"] = "sort %1 %2 %3"; // untranslated +Blockly.Msg["LISTS_SORT_TOOLTIP"] = "Sort a copy of a list."; // untranslated +Blockly.Msg["LISTS_SORT_TYPE_IGNORECASE"] = "alphabetic, ignore case"; // untranslated +Blockly.Msg["LISTS_SORT_TYPE_NUMERIC"] = "numeric"; // untranslated +Blockly.Msg["LISTS_SORT_TYPE_TEXT"] = "alphabetic"; // untranslated +Blockly.Msg["LISTS_SPLIT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#splitting-strings-and-joining-lists"; // untranslated +Blockly.Msg["LISTS_SPLIT_LIST_FROM_TEXT"] = "make list from text"; // untranslated +Blockly.Msg["LISTS_SPLIT_TEXT_FROM_LIST"] = "make text from list"; // untranslated +Blockly.Msg["LISTS_SPLIT_TOOLTIP_JOIN"] = "Join a list of texts into one text, separated by a delimiter."; // untranslated +Blockly.Msg["LISTS_SPLIT_TOOLTIP_SPLIT"] = "Split text into a list of texts, breaking at each delimiter."; // untranslated +Blockly.Msg["LISTS_SPLIT_WITH_DELIMITER"] = "with delimiter"; // untranslated +Blockly.Msg["LOGIC_BOOLEAN_FALSE"] = "netačno"; +Blockly.Msg["LOGIC_BOOLEAN_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#values"; // untranslated +Blockly.Msg["LOGIC_BOOLEAN_TOOLTIP"] = "Vraća ili tačno ili netačno."; +Blockly.Msg["LOGIC_BOOLEAN_TRUE"] = "tačno"; +Blockly.Msg["LOGIC_COMPARE_HELPURL"] = "https://bs.wikipedia.org/wiki/Nejednakost"; +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_EQ"] = "Return true if both inputs equal each other."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GT"] = "Return true if the first input is greater than the second input."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GTE"] = "Return true if the first input is greater than or equal to the second input."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LT"] = "Return true if the first input is smaller than the second input."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LTE"] = "Return true if the first input is smaller than or equal to the second input."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_NEQ"] = "Return true if both inputs are not equal to each other."; // untranslated +Blockly.Msg["LOGIC_NEGATE_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#not"; // untranslated +Blockly.Msg["LOGIC_NEGATE_TITLE"] = "nije %1"; +Blockly.Msg["LOGIC_NEGATE_TOOLTIP"] = "Returns true if the input is false. Returns false if the input is true."; // untranslated +Blockly.Msg["LOGIC_NULL"] = "bez vrijednosti"; +Blockly.Msg["LOGIC_NULL_HELPURL"] = "https://en.wikipedia.org/wiki/Nullable_type"; // untranslated +Blockly.Msg["LOGIC_NULL_TOOLTIP"] = "Vraća \"bez vrijednosti\"."; +Blockly.Msg["LOGIC_OPERATION_AND"] = "i"; +Blockly.Msg["LOGIC_OPERATION_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#logical-operations"; // untranslated +Blockly.Msg["LOGIC_OPERATION_OR"] = "ili"; +Blockly.Msg["LOGIC_OPERATION_TOOLTIP_AND"] = "Return true if both inputs are true."; // untranslated +Blockly.Msg["LOGIC_OPERATION_TOOLTIP_OR"] = "Return true if at least one of the inputs is true."; // untranslated +Blockly.Msg["LOGIC_TERNARY_CONDITION"] = "test"; +Blockly.Msg["LOGIC_TERNARY_HELPURL"] = "https://en.wikipedia.org/wiki/%3F:"; // untranslated +Blockly.Msg["LOGIC_TERNARY_IF_FALSE"] = "ako je netačno"; +Blockly.Msg["LOGIC_TERNARY_IF_TRUE"] = "ako je tačno"; +Blockly.Msg["LOGIC_TERNARY_TOOLTIP"] = "Check the condition in 'test'. If the condition is true, returns the 'if true' value; otherwise returns the 'if false' value."; // untranslated +Blockly.Msg["MATH_ADDITION_SYMBOL"] = "+"; // untranslated +Blockly.Msg["MATH_ARITHMETIC_HELPURL"] = "https://bs.wikipedia.org/wiki/Aritmetika"; +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_ADD"] = "Vraća zbir dva broja."; +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_DIVIDE"] = "Vraća količnik dva broja."; +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MINUS"] = "Vraća razliku dva broja."; +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MULTIPLY"] = "Vraća proizvod dva broja."; +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_POWER"] = "Vraća prvi broj na eksponent drugog broja."; +Blockly.Msg["MATH_ATAN2_HELPURL"] = "https://en.wikipedia.org/wiki/Atan2"; // untranslated +Blockly.Msg["MATH_ATAN2_TITLE"] = "atan2 of X:%1 Y:%2"; // untranslated +Blockly.Msg["MATH_ATAN2_TOOLTIP"] = "Return the arctangent of point (X, Y) in degrees from -180 to 180."; // untranslated +Blockly.Msg["MATH_CHANGE_HELPURL"] = "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter"; // untranslated +Blockly.Msg["MATH_CHANGE_TITLE"] = "promijeni %1 za %2"; +Blockly.Msg["MATH_CHANGE_TOOLTIP"] = "Dodaj broj varijabli \"%1\"."; +Blockly.Msg["MATH_CONSTANT_HELPURL"] = "https://bs.wikipedia.org/wiki/Matemati%C4%8Dka_konstanta"; +Blockly.Msg["MATH_CONSTANT_TOOLTIP"] = "Vraća jednu od uobičajenih konstanti: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…) ili ∞ (beskonačnost)."; +Blockly.Msg["MATH_CONSTRAIN_HELPURL"] = "https://en.wikipedia.org/wiki/Clamping_(graphics)"; // untranslated +Blockly.Msg["MATH_CONSTRAIN_TITLE"] = "constrain %1 low %2 high %3"; // untranslated +Blockly.Msg["MATH_CONSTRAIN_TOOLTIP"] = "Constrain a number to be between the specified limits (inclusive)."; // untranslated +Blockly.Msg["MATH_DIVISION_SYMBOL"] = "÷"; // untranslated +Blockly.Msg["MATH_IS_DIVISIBLE_BY"] = "je djeljiv sa"; +Blockly.Msg["MATH_IS_EVEN"] = "je paran"; +Blockly.Msg["MATH_IS_NEGATIVE"] = "je negativan"; +Blockly.Msg["MATH_IS_ODD"] = "je neparan"; +Blockly.Msg["MATH_IS_POSITIVE"] = "je pozitivan"; +Blockly.Msg["MATH_IS_PRIME"] = "je prost"; +Blockly.Msg["MATH_IS_TOOLTIP"] = "Provjerava da li je broj paran, neparan, prost, cijeli, pozitivan, negativan ili je djeljiv s određenim brojem. Vraća tačno ili netačno."; +Blockly.Msg["MATH_IS_WHOLE"] = "je cijeli"; +Blockly.Msg["MATH_MODULO_HELPURL"] = "https://en.wikipedia.org/wiki/Modulo_operation"; // untranslated +Blockly.Msg["MATH_MODULO_TITLE"] = "remainder of %1 ÷ %2"; // untranslated +Blockly.Msg["MATH_MODULO_TOOLTIP"] = "Return the remainder from dividing the two numbers."; // untranslated +Blockly.Msg["MATH_MULTIPLICATION_SYMBOL"] = "×"; // untranslated +Blockly.Msg["MATH_NUMBER_HELPURL"] = "https://bs.wikipedia.org/wiki/Broj"; +Blockly.Msg["MATH_NUMBER_TOOLTIP"] = "Broj."; +Blockly.Msg["MATH_ONLIST_HELPURL"] = ""; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_AVERAGE"] = "average of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_MAX"] = "max of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_MEDIAN"] = "median of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_MIN"] = "min of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_MODE"] = "modes of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_RANDOM"] = "random item of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_STD_DEV"] = "standard deviation of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_SUM"] = "zbir spiska"; +Blockly.Msg["MATH_ONLIST_TOOLTIP_AVERAGE"] = "Return the average (arithmetic mean) of the numeric values in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_MAX"] = "Return the largest number in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_MEDIAN"] = "Return the median number in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_MIN"] = "Return the smallest number in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_MODE"] = "Return a list of the most common item(s) in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_RANDOM"] = "Return a random element from the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_STD_DEV"] = "Return the standard deviation of the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_SUM"] = "Vraća zbir svih brojeva sa spiska."; +Blockly.Msg["MATH_POWER_SYMBOL"] = "^"; // untranslated +Blockly.Msg["MATH_RANDOM_FLOAT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation"; // untranslated +Blockly.Msg["MATH_RANDOM_FLOAT_TITLE_RANDOM"] = "random fraction"; // untranslated +Blockly.Msg["MATH_RANDOM_FLOAT_TOOLTIP"] = "Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive)."; // untranslated +Blockly.Msg["MATH_RANDOM_INT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation"; // untranslated +Blockly.Msg["MATH_RANDOM_INT_TITLE"] = "random integer from %1 to %2"; // untranslated +Blockly.Msg["MATH_RANDOM_INT_TOOLTIP"] = "Return a random integer between the two specified limits, inclusive."; // untranslated +Blockly.Msg["MATH_ROUND_HELPURL"] = "https://en.wikipedia.org/wiki/Rounding"; // untranslated +Blockly.Msg["MATH_ROUND_OPERATOR_ROUND"] = "zaokruži"; +Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDDOWN"] = "zaokruži naniže"; +Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDUP"] = "zaokruži naviše"; +Blockly.Msg["MATH_ROUND_TOOLTIP"] = "Zaokružuje broj na veću ili manju vrijednost."; +Blockly.Msg["MATH_SINGLE_HELPURL"] = "https://bs.wikipedia.org/wiki/Kvadratni_korijen"; +Blockly.Msg["MATH_SINGLE_OP_ABSOLUTE"] = "apsolutno"; +Blockly.Msg["MATH_SINGLE_OP_ROOT"] = "kvadratni korijen"; +Blockly.Msg["MATH_SINGLE_TOOLTIP_ABS"] = "Vraća absolutnu vrijednost broja."; +Blockly.Msg["MATH_SINGLE_TOOLTIP_EXP"] = "Vraća e na eksponent broja."; +Blockly.Msg["MATH_SINGLE_TOOLTIP_LN"] = "Vraća prirodni logoritam broja."; +Blockly.Msg["MATH_SINGLE_TOOLTIP_LOG10"] = "Vraća logoritam broja za bazu 10."; +Blockly.Msg["MATH_SINGLE_TOOLTIP_NEG"] = "Vraća negaciju broja."; +Blockly.Msg["MATH_SINGLE_TOOLTIP_POW10"] = "Vraća 10 na eksponent broja."; +Blockly.Msg["MATH_SINGLE_TOOLTIP_ROOT"] = "Vraća kvadratni korijen broja"; +Blockly.Msg["MATH_SUBTRACTION_SYMBOL"] = "-"; // untranslated +Blockly.Msg["MATH_TRIG_ACOS"] = "acos"; // untranslated +Blockly.Msg["MATH_TRIG_ASIN"] = "asin"; // untranslated +Blockly.Msg["MATH_TRIG_ATAN"] = "atan"; // untranslated +Blockly.Msg["MATH_TRIG_COS"] = "cos"; // untranslated +Blockly.Msg["MATH_TRIG_HELPURL"] = "https://bs.wikipedia.org/wiki/Trigonometrijska_funkcija"; +Blockly.Msg["MATH_TRIG_SIN"] = "sin"; // untranslated +Blockly.Msg["MATH_TRIG_TAN"] = "tan"; // untranslated +Blockly.Msg["MATH_TRIG_TOOLTIP_ACOS"] = "Vraća arkuskosinus broja."; +Blockly.Msg["MATH_TRIG_TOOLTIP_ASIN"] = "Vraća arkussinus broja."; +Blockly.Msg["MATH_TRIG_TOOLTIP_ATAN"] = "Vraća arkustangens broja."; +Blockly.Msg["MATH_TRIG_TOOLTIP_COS"] = "Vraća kosinus stepena (ne radijana)."; +Blockly.Msg["MATH_TRIG_TOOLTIP_SIN"] = "Vraća sinus stepena (ne radijana)."; +Blockly.Msg["MATH_TRIG_TOOLTIP_TAN"] = "Vraća tangens stepena (ne radijana)."; +Blockly.Msg["NEW_COLOUR_VARIABLE"] = "Napravi varijablu boje..."; +Blockly.Msg["NEW_NUMBER_VARIABLE"] = "Napravi varijablu broja..."; +Blockly.Msg["NEW_STRING_VARIABLE"] = "Napravi varijablu niza..."; +Blockly.Msg["NEW_VARIABLE"] = "Napravi varijablu..."; +Blockly.Msg["NEW_VARIABLE_TITLE"] = "Ime nove varijable:"; +Blockly.Msg["NEW_VARIABLE_TYPE_TITLE"] = "Vrsta nove varijable:"; +Blockly.Msg["ORDINAL_NUMBER_SUFFIX"] = ""; // untranslated +Blockly.Msg["PROCEDURES_ALLOW_STATEMENTS"] = "allow statements"; // untranslated +Blockly.Msg["PROCEDURES_BEFORE_PARAMS"] = "with:"; // untranslated +Blockly.Msg["PROCEDURES_CALLNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated +Blockly.Msg["PROCEDURES_CALLNORETURN_TOOLTIP"] = "Run the user-defined function '%1'."; // untranslated +Blockly.Msg["PROCEDURES_CALLRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated +Blockly.Msg["PROCEDURES_CALLRETURN_TOOLTIP"] = "Run the user-defined function '%1' and use its output."; // untranslated +Blockly.Msg["PROCEDURES_CALL_BEFORE_PARAMS"] = "with:"; // untranslated +Blockly.Msg["PROCEDURES_CREATE_DO"] = "Create '%1'"; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"] = "Describe this function..."; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_DO"] = ""; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"] = "do something"; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"] = "to"; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_TOOLTIP"] = "Creates a function with no output."; // untranslated +Blockly.Msg["PROCEDURES_DEFRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated +Blockly.Msg["PROCEDURES_DEFRETURN_RETURN"] = "return"; // untranslated +Blockly.Msg["PROCEDURES_DEFRETURN_TOOLTIP"] = "Creates a function with an output."; // untranslated +Blockly.Msg["PROCEDURES_DEF_DUPLICATE_WARNING"] = "Warning: This function has duplicate parameters."; // untranslated +Blockly.Msg["PROCEDURES_HIGHLIGHT_DEF"] = "Highlight function definition"; // untranslated +Blockly.Msg["PROCEDURES_IFRETURN_HELPURL"] = "http://c2.com/cgi/wiki?GuardClause"; // untranslated +Blockly.Msg["PROCEDURES_IFRETURN_TOOLTIP"] = "If a value is true, then return a second value."; // untranslated +Blockly.Msg["PROCEDURES_IFRETURN_WARNING"] = "Warning: This block may be used only within a function definition."; // untranslated +Blockly.Msg["PROCEDURES_MUTATORARG_TITLE"] = "ime ulaza:"; +Blockly.Msg["PROCEDURES_MUTATORARG_TOOLTIP"] = "Add an input to the function."; // untranslated +Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TITLE"] = "inputs"; // untranslated +Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TOOLTIP"] = "Add, remove, or reorder inputs to this function."; // untranslated +Blockly.Msg["REDO"] = "Ponovi"; +Blockly.Msg["REMOVE_COMMENT"] = "Ukloni komentare"; +Blockly.Msg["RENAME_VARIABLE"] = "Preimenuj varijablu..."; +Blockly.Msg["RENAME_VARIABLE_TITLE"] = "Preimenuj sve \"%1\" varijable u:"; +Blockly.Msg["TEXT_APPEND_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated +Blockly.Msg["TEXT_APPEND_TITLE"] = "to %1 append text %2"; // untranslated +Blockly.Msg["TEXT_APPEND_TOOLTIP"] = "Append some text to variable '%1'."; // untranslated +Blockly.Msg["TEXT_CHANGECASE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#adjusting-text-case"; // untranslated +Blockly.Msg["TEXT_CHANGECASE_OPERATOR_LOWERCASE"] = "to lower case"; // untranslated +Blockly.Msg["TEXT_CHANGECASE_OPERATOR_TITLECASE"] = "to Title Case"; // untranslated +Blockly.Msg["TEXT_CHANGECASE_OPERATOR_UPPERCASE"] = "to UPPER CASE"; // untranslated +Blockly.Msg["TEXT_CHANGECASE_TOOLTIP"] = "Return a copy of the text in a different case."; // untranslated +Blockly.Msg["TEXT_CHARAT_FIRST"] = "get first letter"; // untranslated +Blockly.Msg["TEXT_CHARAT_FROM_END"] = "get letter # from end"; // untranslated +Blockly.Msg["TEXT_CHARAT_FROM_START"] = "get letter #"; // untranslated +Blockly.Msg["TEXT_CHARAT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-text"; // untranslated +Blockly.Msg["TEXT_CHARAT_LAST"] = "get last letter"; // untranslated +Blockly.Msg["TEXT_CHARAT_RANDOM"] = "get random letter"; // untranslated +Blockly.Msg["TEXT_CHARAT_TAIL"] = ""; // untranslated +Blockly.Msg["TEXT_CHARAT_TITLE"] = "in text %1 %2"; // untranslated +Blockly.Msg["TEXT_CHARAT_TOOLTIP"] = "Returns the letter at the specified position."; // untranslated +Blockly.Msg["TEXT_COUNT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#counting-substrings"; // untranslated +Blockly.Msg["TEXT_COUNT_MESSAGE0"] = "count %1 in %2"; // untranslated +Blockly.Msg["TEXT_COUNT_TOOLTIP"] = "Count how many times some text occurs within some other text."; // untranslated +Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TOOLTIP"] = "Add an item to the text."; // untranslated +Blockly.Msg["TEXT_CREATE_JOIN_TITLE_JOIN"] = "join"; // untranslated +Blockly.Msg["TEXT_CREATE_JOIN_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this text block."; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_END"] = "to letter # from end"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_START"] = "to letter #"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_END_LAST"] = "to last letter"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_INPUT_IN_TEXT"] = "in text"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_START_FIRST"] = "get substring from first letter"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_END"] = "get substring from letter # from end"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_START"] = "get substring from letter #"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_TAIL"] = ""; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_TOOLTIP"] = "Returns a specified portion of the text."; // untranslated +Blockly.Msg["TEXT_INDEXOF_HELPURL"] = "https://github.com/google/blockly/wiki/Text#finding-text"; // untranslated +Blockly.Msg["TEXT_INDEXOF_OPERATOR_FIRST"] = "find first occurrence of text"; // untranslated +Blockly.Msg["TEXT_INDEXOF_OPERATOR_LAST"] = "find last occurrence of text"; // untranslated +Blockly.Msg["TEXT_INDEXOF_TITLE"] = "in text %1 %2 %3"; // untranslated +Blockly.Msg["TEXT_INDEXOF_TOOLTIP"] = "Returns the index of the first/last occurrence of the first text in the second text. Returns %1 if text is not found."; // untranslated +Blockly.Msg["TEXT_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Text#checking-for-empty-text"; // untranslated +Blockly.Msg["TEXT_ISEMPTY_TITLE"] = "%1 je prazan"; +Blockly.Msg["TEXT_ISEMPTY_TOOLTIP"] = "Returns true if the provided text is empty."; // untranslated +Blockly.Msg["TEXT_JOIN_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-creation"; // untranslated +Blockly.Msg["TEXT_JOIN_TITLE_CREATEWITH"] = "create text with"; // untranslated +Blockly.Msg["TEXT_JOIN_TOOLTIP"] = "Create a piece of text by joining together any number of items."; // untranslated +Blockly.Msg["TEXT_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated +Blockly.Msg["TEXT_LENGTH_TITLE"] = "dužina teksta %1"; +Blockly.Msg["TEXT_LENGTH_TOOLTIP"] = "Returns the number of letters (including spaces) in the provided text."; // untranslated +Blockly.Msg["TEXT_PRINT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#printing-text"; // untranslated +Blockly.Msg["TEXT_PRINT_TITLE"] = "print %1"; // untranslated +Blockly.Msg["TEXT_PRINT_TOOLTIP"] = "Print the specified text, number or other value."; // untranslated +Blockly.Msg["TEXT_PROMPT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#getting-input-from-the-user"; // untranslated +Blockly.Msg["TEXT_PROMPT_TOOLTIP_NUMBER"] = "Prompt for user for a number."; // untranslated +Blockly.Msg["TEXT_PROMPT_TOOLTIP_TEXT"] = "Prompt for user for some text."; // untranslated +Blockly.Msg["TEXT_PROMPT_TYPE_NUMBER"] = "prompt for number with message"; // untranslated +Blockly.Msg["TEXT_PROMPT_TYPE_TEXT"] = "prompt for text with message"; // untranslated +Blockly.Msg["TEXT_REPLACE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#replacing-substrings"; // untranslated +Blockly.Msg["TEXT_REPLACE_MESSAGE0"] = "replace %1 with %2 in %3"; // untranslated +Blockly.Msg["TEXT_REPLACE_TOOLTIP"] = "Replace all occurances of some text within some other text."; // untranslated +Blockly.Msg["TEXT_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#reversing-text"; // untranslated +Blockly.Msg["TEXT_REVERSE_MESSAGE0"] = "reverse %1"; // untranslated +Blockly.Msg["TEXT_REVERSE_TOOLTIP"] = "Reverses the order of the characters in the text."; // untranslated +Blockly.Msg["TEXT_TEXT_HELPURL"] = "https://en.wikipedia.org/wiki/String_(computer_science)"; // untranslated +Blockly.Msg["TEXT_TEXT_TOOLTIP"] = "A letter, word, or line of text."; // untranslated +Blockly.Msg["TEXT_TRIM_HELPURL"] = "https://github.com/google/blockly/wiki/Text#trimming-removing-spaces"; // untranslated +Blockly.Msg["TEXT_TRIM_OPERATOR_BOTH"] = "trim spaces from both sides of"; // untranslated +Blockly.Msg["TEXT_TRIM_OPERATOR_LEFT"] = "trim spaces from left side of"; // untranslated +Blockly.Msg["TEXT_TRIM_OPERATOR_RIGHT"] = "trim spaces from right side of"; // untranslated +Blockly.Msg["TEXT_TRIM_TOOLTIP"] = "Return a copy of the text with spaces removed from one or both ends."; // untranslated +Blockly.Msg["TODAY"] = "Danas"; +Blockly.Msg["UNDO"] = "Poništi"; +Blockly.Msg["UNNAMED_KEY"] = "neimenovano"; +Blockly.Msg["VARIABLES_DEFAULT_NAME"] = "stavka"; +Blockly.Msg["VARIABLES_GET_CREATE_SET"] = "Create 'set %1'"; // untranslated +Blockly.Msg["VARIABLES_GET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#get"; // untranslated +Blockly.Msg["VARIABLES_GET_TOOLTIP"] = "Returns the value of this variable."; // untranslated +Blockly.Msg["VARIABLES_SET"] = "set %1 to %2"; // untranslated +Blockly.Msg["VARIABLES_SET_CREATE_GET"] = "Create 'get %1'"; // untranslated +Blockly.Msg["VARIABLES_SET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#set"; // untranslated +Blockly.Msg["VARIABLES_SET_TOOLTIP"] = "Sets this variable to be equal to the input."; // untranslated +Blockly.Msg["VARIABLE_ALREADY_EXISTS"] = "Varijabla s imenom \"%1\" već postoji."; +Blockly.Msg["VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE"] = "Varijabla s imenom \"%1\" već postoji za drugu vrstu: \"%2\"."; +Blockly.Msg["WORKSPACE_ARIA_LABEL"] = "Blockly Workspace"; // untranslated +Blockly.Msg["WORKSPACE_COMMENT_DEFAULT_TEXT"] = "Say something..."; // untranslated +Blockly.Msg["CONTROLS_FOREACH_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"]; +Blockly.Msg["CONTROLS_FOR_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"]; +Blockly.Msg["CONTROLS_IF_ELSEIF_TITLE_ELSEIF"] = Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"]; +Blockly.Msg["CONTROLS_IF_ELSE_TITLE_ELSE"] = Blockly.Msg["CONTROLS_IF_MSG_ELSE"]; +Blockly.Msg["CONTROLS_IF_IF_TITLE_IF"] = Blockly.Msg["CONTROLS_IF_MSG_IF"]; +Blockly.Msg["CONTROLS_IF_MSG_THEN"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"]; +Blockly.Msg["CONTROLS_WHILEUNTIL_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"]; +Blockly.Msg["LISTS_CREATE_WITH_ITEM_TITLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"]; +Blockly.Msg["LISTS_GET_INDEX_HELPURL"] = Blockly.Msg["LISTS_INDEX_OF_HELPURL"]; +Blockly.Msg["LISTS_GET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"]; +Blockly.Msg["LISTS_GET_SUBLIST_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"]; +Blockly.Msg["LISTS_INDEX_OF_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"]; +Blockly.Msg["LISTS_SET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"]; +Blockly.Msg["MATH_CHANGE_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"]; +Blockly.Msg["PROCEDURES_DEFRETURN_COMMENT"] = Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"]; +Blockly.Msg["PROCEDURES_DEFRETURN_DO"] = Blockly.Msg["PROCEDURES_DEFNORETURN_DO"]; +Blockly.Msg["PROCEDURES_DEFRETURN_PROCEDURE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"]; +Blockly.Msg["PROCEDURES_DEFRETURN_TITLE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"]; +Blockly.Msg["TEXT_APPEND_VARIABLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"]; +Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"]; + +Blockly.Msg["MATH_HUE"] = "230"; +Blockly.Msg["LOOPS_HUE"] = "120"; +Blockly.Msg["LISTS_HUE"] = "260"; +Blockly.Msg["LOGIC_HUE"] = "210"; +Blockly.Msg["VARIABLES_HUE"] = "330"; +Blockly.Msg["TEXTS_HUE"] = "160"; +Blockly.Msg["PROCEDURES_HUE"] = "290"; +Blockly.Msg["COLOUR_HUE"] = "20"; +Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310"; \ No newline at end of file diff --git a/msg/js/zgh.js b/msg/js/zgh.js new file mode 100644 index 000000000..2242abaa4 --- /dev/null +++ b/msg/js/zgh.js @@ -0,0 +1,434 @@ +// This file was automatically generated. Do not modify. + +'use strict'; + +Blockly.Msg["ADD_COMMENT"] = "ⵔⵏⵓ ⴰⵅⴼⴰⵡⴰⵍ"; +Blockly.Msg["CANNOT_DELETE_VARIABLE_PROCEDURE"] = "Can't delete the variable '%1' because it's part of the definition of the function '%2'"; // untranslated +Blockly.Msg["CHANGE_VALUE_TITLE"] = "ⵙⵏⴼⵍ ⴰⵣⴰⵍ:"; +Blockly.Msg["CLEAN_UP"] = "Clean up Blocks"; // untranslated +Blockly.Msg["COLLAPSED_WARNINGS_WARNING"] = "Collapsed blocks contain warnings."; // untranslated +Blockly.Msg["COLLAPSE_ALL"] = "Collapse Blocks"; // untranslated +Blockly.Msg["COLLAPSE_BLOCK"] = "Collapse Block"; // untranslated +Blockly.Msg["COLOUR_BLEND_COLOUR1"] = "ⴰⴽⵍⵓ 1"; +Blockly.Msg["COLOUR_BLEND_COLOUR2"] = "ⴰⴽⵍⵓ 2"; +Blockly.Msg["COLOUR_BLEND_HELPURL"] = "https://meyerweb.com/eric/tools/color-blend/#:::rgbp"; // untranslated +Blockly.Msg["COLOUR_BLEND_RATIO"] = "ⴰⵙⵙⴰⵖ"; +Blockly.Msg["COLOUR_BLEND_TITLE"] = "ⵙⵎⵔⴽⵙ"; +Blockly.Msg["COLOUR_BLEND_TOOLTIP"] = "Blends two colours together with a given ratio (0.0 - 1.0)."; // untranslated +Blockly.Msg["COLOUR_PICKER_HELPURL"] = "https://en.wikipedia.org/wiki/Color"; +Blockly.Msg["COLOUR_PICKER_TOOLTIP"] = "Choose a colour from the palette."; // untranslated +Blockly.Msg["COLOUR_RANDOM_HELPURL"] = "http://randomcolour.com"; // untranslated +Blockly.Msg["COLOUR_RANDOM_TITLE"] = "random colour"; // untranslated +Blockly.Msg["COLOUR_RANDOM_TOOLTIP"] = "Choose a colour at random."; // untranslated +Blockly.Msg["COLOUR_RGB_BLUE"] = "ⴰⵏⵉⵍⵉ"; +Blockly.Msg["COLOUR_RGB_GREEN"] = "ⴰⵣⴳⵣⴰ"; +Blockly.Msg["COLOUR_RGB_HELPURL"] = "https://www.december.com/html/spec/colorpercompact.html"; // untranslated +Blockly.Msg["COLOUR_RGB_RED"] = "ⴰⵣⴳⴳⵯⴰⵖ"; +Blockly.Msg["COLOUR_RGB_TITLE"] = "ⴽⵍⵓ ⵙ"; +Blockly.Msg["COLOUR_RGB_TOOLTIP"] = "ⴰⵣⴰⵍⵏ ⵉⴼⵓⴽⴽ ⴰⴷ ⵉⵍⵉⵏ ⴳⵔ 0 ⴷ 100."; +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#loop-termination-blocks"; // untranslated +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK"] = "break out of loop"; // untranslated +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE"] = "continue with next iteration of loop"; // untranslated +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK"] = "Break out of the containing loop."; // untranslated +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE"] = "Skip the rest of this loop, and continue with the next iteration."; // untranslated +Blockly.Msg["CONTROLS_FLOW_STATEMENTS_WARNING"] = "Warning: This block may only be used within a loop."; // untranslated +Blockly.Msg["CONTROLS_FOREACH_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#for-each"; // untranslated +Blockly.Msg["CONTROLS_FOREACH_TITLE"] = "for each item %1 in list %2"; // untranslated +Blockly.Msg["CONTROLS_FOREACH_TOOLTIP"] = "For each item in a list, set the variable '%1' to the item, and then do some statements."; // untranslated +Blockly.Msg["CONTROLS_FOR_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#count-with"; // untranslated +Blockly.Msg["CONTROLS_FOR_TITLE"] = "count with %1 from %2 to %3 by %4"; // untranslated +Blockly.Msg["CONTROLS_FOR_TOOLTIP"] = "Have the variable '%1' take on the values from the start number to the end number, counting by the specified interval, and do the specified blocks."; // untranslated +Blockly.Msg["CONTROLS_IF_ELSEIF_TOOLTIP"] = "Add a condition to the if block."; // untranslated +Blockly.Msg["CONTROLS_IF_ELSE_TOOLTIP"] = "Add a final, catch-all condition to the if block."; // untranslated +Blockly.Msg["CONTROLS_IF_HELPURL"] = "https://github.com/google/blockly/wiki/IfElse"; // untranslated +Blockly.Msg["CONTROLS_IF_IF_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this if block."; // untranslated +Blockly.Msg["CONTROLS_IF_MSG_ELSE"] = "ⵎⴽ ⴷ ⵓⵀⵓ"; +Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"] = "ⵉⵙ"; +Blockly.Msg["CONTROLS_IF_MSG_IF"] = "ⵎⴽ"; +Blockly.Msg["CONTROLS_IF_TOOLTIP_1"] = "If a value is true, then do some statements."; // untranslated +Blockly.Msg["CONTROLS_IF_TOOLTIP_2"] = "If a value is true, then do the first block of statements. Otherwise, do the second block of statements."; // untranslated +Blockly.Msg["CONTROLS_IF_TOOLTIP_3"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements."; // untranslated +Blockly.Msg["CONTROLS_IF_TOOLTIP_4"] = "If the first value is true, then do the first block of statements. Otherwise, if the second value is true, do the second block of statements. If none of the values are true, do the last block of statements."; // untranslated +Blockly.Msg["CONTROLS_REPEAT_HELPURL"] = "https://en.wikipedia.org/wiki/For_loop"; +Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"] = "ⴳ"; +Blockly.Msg["CONTROLS_REPEAT_TITLE"] = "ⴰⵍⵙ ⴷⴰⵖ %1 ⵜⴽⴽⵍⵜ"; +Blockly.Msg["CONTROLS_REPEAT_TOOLTIP"] = "Do some statements several times."; // untranslated +Blockly.Msg["CONTROLS_WHILEUNTIL_HELPURL"] = "https://github.com/google/blockly/wiki/Loops#repeat"; // untranslated +Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_UNTIL"] = "ⴰⵍⵙ ⴰⵔⴷ"; +Blockly.Msg["CONTROLS_WHILEUNTIL_OPERATOR_WHILE"] = "ⴰⵍⵙ ⴰⴷⴷⴰⴳ"; +Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL"] = "While a value is false, then do some statements."; // untranslated +Blockly.Msg["CONTROLS_WHILEUNTIL_TOOLTIP_WHILE"] = "ⴽⵓⴷ ⵉⴷⵜⵜⴰ ⵡⴰⵣⴰⵍ, ⵙⵙⵍⴽⵎ ⴽⵔⴰ ⵏ ⵡⴰⵏⴰⴹⵏ."; +Blockly.Msg["DELETE_ALL_BLOCKS"] = "ⴽⴽⵙ %1 ⵉⴱⵍⵓⴽⵏ ⵎⴰⵕⵕⴰ?"; +Blockly.Msg["DELETE_BLOCK"] = "ⴽⴽⵙ ⴰⴱⵍⵓⴽ"; +Blockly.Msg["DELETE_VARIABLE"] = "ⴽⴽⵙ ⴰⵎⵙⴽⵉⵍ '%1'"; +Blockly.Msg["DELETE_VARIABLE_CONFIRMATION"] = "Delete %1 uses of the '%2' variable?"; // untranslated +Blockly.Msg["DELETE_X_BLOCKS"] = "ⴽⴽⵙ %1 ⵉⴱⵍⵓⴽⵏ"; +Blockly.Msg["DISABLE_BLOCK"] = "Disable Block"; // untranslated +Blockly.Msg["DUPLICATE_BLOCK"] = "Duplicate"; // untranslated +Blockly.Msg["DUPLICATE_COMMENT"] = "Duplicate Comment"; // untranslated +Blockly.Msg["ENABLE_BLOCK"] = "Enable Block"; // untranslated +Blockly.Msg["EXPAND_ALL"] = "Expand Blocks"; // untranslated +Blockly.Msg["EXPAND_BLOCK"] = "Expand Block"; // untranslated +Blockly.Msg["EXTERNAL_INPUTS"] = "External Inputs"; // untranslated +Blockly.Msg["HELP"] = "ⵜⵉⵡⵉⵙⵉ"; +Blockly.Msg["INLINE_INPUTS"] = "Inline Inputs"; // untranslated +Blockly.Msg["IOS_CANCEL"] = "ⵙⵔ"; +Blockly.Msg["IOS_ERROR"] = "ⴰⵣⴳⴰⵍ"; +Blockly.Msg["IOS_OK"] = "ⵡⴰⵅⵅⴰ"; +Blockly.Msg["IOS_PROCEDURES_ADD_INPUT"] = "+ ⵔⵏⵓ ⵢⴰⵜ ⵜⵏⴽⵛⵓⵎⵜ"; +Blockly.Msg["IOS_PROCEDURES_ALLOW_STATEMENTS"] = "Allow statements"; // untranslated +Blockly.Msg["IOS_PROCEDURES_DUPLICATE_INPUTS_ERROR"] = "This function has duplicate inputs."; // untranslated +Blockly.Msg["IOS_PROCEDURES_INPUTS"] = "ⵉⵏⴽⵛⵓⵎⵏ"; +Blockly.Msg["IOS_VARIABLES_ADD_BUTTON"] = "ⵔⵏⵓ"; +Blockly.Msg["IOS_VARIABLES_ADD_VARIABLE"] = "+ ⵔⵏⵓ ⴰⵎⵙⴽⵉⵍ"; +Blockly.Msg["IOS_VARIABLES_DELETE_BUTTON"] = "ⴽⴽⵙ"; +Blockly.Msg["IOS_VARIABLES_EMPTY_NAME_ERROR"] = "ⵓⵔ ⵜⵓⴼⵉⴷ ⴰⴷ ⵜⵙⵙⵎⵔⵙⴷ ⵢⴰⵏ ⵢⵉⵙⵎ ⵏ ⵓⵎⵙⴽⵉⵍ ⵢⵓⵔⴰⵏ."; +Blockly.Msg["IOS_VARIABLES_RENAME_BUTTON"] = "ⵙⵏⴼⵍ ⵉⵙⵎ"; +Blockly.Msg["IOS_VARIABLES_VARIABLE_NAME"] = "ⵉⵙⵎ ⵏ ⵓⵎⵙⴽⵉⵍ"; +Blockly.Msg["LISTS_CREATE_EMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-empty-list"; // untranslated +Blockly.Msg["LISTS_CREATE_EMPTY_TITLE"] = "create empty list"; // untranslated +Blockly.Msg["LISTS_CREATE_EMPTY_TOOLTIP"] = "Returns a list, of length 0, containing no data records"; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TITLE_ADD"] = "list"; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_CONTAINER_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this list block."; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_INPUT_WITH"] = "create list with"; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_ITEM_TOOLTIP"] = "Add an item to the list."; // untranslated +Blockly.Msg["LISTS_CREATE_WITH_TOOLTIP"] = "Create a list with any number of items."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_FIRST"] = "ⴰⵎⵣⵡⴰⵔⵓ"; +Blockly.Msg["LISTS_GET_INDEX_FROM_END"] = "# ⵙⴳ ⵜⵉⴳⵉⵔⴰ"; +Blockly.Msg["LISTS_GET_INDEX_FROM_START"] = "#"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_GET"] = "get"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_GET_REMOVE"] = "get and remove"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_LAST"] = "ⴰⵎⴳⴳⴰⵔⵓ"; +Blockly.Msg["LISTS_GET_INDEX_RANDOM"] = "random"; // untranslated +Blockly.Msg["LISTS_GET_INDEX_REMOVE"] = "ⵙⵉⵜⵜⵢ"; +Blockly.Msg["LISTS_GET_INDEX_TAIL"] = ""; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FIRST"] = "Returns the first item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_FROM"] = "Returns the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_LAST"] = "Returns the last item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_RANDOM"] = "Returns a random item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST"] = "Removes and returns the first item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM"] = "Removes and returns the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST"] = "Removes and returns the last item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM"] = "Removes and returns a random item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST"] = "Removes the first item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM"] = "Removes the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST"] = "Removes the last item in a list."; // untranslated +Blockly.Msg["LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM"] = "Removes a random item in a list."; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_END"] = "to # from end"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_END_FROM_START"] = "ⴰⵔ #"; +Blockly.Msg["LISTS_GET_SUBLIST_END_LAST"] = "ⴰⵔ ⵜⴳⵉⵔⴰ"; +Blockly.Msg["LISTS_GET_SUBLIST_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-a-sublist"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_START_FIRST"] = "get sub-list from first"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_END"] = "get sub-list from # from end"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_START_FROM_START"] = "get sub-list from #"; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_TAIL"] = ""; // untranslated +Blockly.Msg["LISTS_GET_SUBLIST_TOOLTIP"] = "Creates a copy of the specified portion of a list."; // untranslated +Blockly.Msg["LISTS_INDEX_FROM_END_TOOLTIP"] = "%1 is the last item."; // untranslated +Blockly.Msg["LISTS_INDEX_FROM_START_TOOLTIP"] = "%1 is the first item."; // untranslated +Blockly.Msg["LISTS_INDEX_OF_FIRST"] = "find first occurrence of item"; // untranslated +Blockly.Msg["LISTS_INDEX_OF_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#getting-items-from-a-list"; // untranslated +Blockly.Msg["LISTS_INDEX_OF_LAST"] = "find last occurrence of item"; // untranslated +Blockly.Msg["LISTS_INDEX_OF_TOOLTIP"] = "Returns the index of the first/last occurrence of the item in the list. Returns %1 if item is not found."; // untranslated +Blockly.Msg["LISTS_INLIST"] = "ⴳ ⵜⵍⴳⴰⵎⵜ"; +Blockly.Msg["LISTS_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#is-empty"; // untranslated +Blockly.Msg["LISTS_ISEMPTY_TITLE"] = "%1 is empty"; // untranslated +Blockly.Msg["LISTS_ISEMPTY_TOOLTIP"] = "Returns true if the list is empty."; // untranslated +Blockly.Msg["LISTS_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#length-of"; // untranslated +Blockly.Msg["LISTS_LENGTH_TITLE"] = "ⵜⵉⵖⵣⵉ ⵏ %1"; +Blockly.Msg["LISTS_LENGTH_TOOLTIP"] = "Returns the length of a list."; // untranslated +Blockly.Msg["LISTS_REPEAT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#create-list-with"; // untranslated +Blockly.Msg["LISTS_REPEAT_TITLE"] = "create list with item %1 repeated %2 times"; // untranslated +Blockly.Msg["LISTS_REPEAT_TOOLTIP"] = "Creates a list consisting of the given value repeated the specified number of times."; // untranslated +Blockly.Msg["LISTS_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#reversing-a-list"; // untranslated +Blockly.Msg["LISTS_REVERSE_MESSAGE0"] = "reverse %1"; // untranslated +Blockly.Msg["LISTS_REVERSE_TOOLTIP"] = "Reverse a copy of a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#in-list--set"; // untranslated +Blockly.Msg["LISTS_SET_INDEX_INPUT_TO"] = "ⴰⵎ"; +Blockly.Msg["LISTS_SET_INDEX_INSERT"] = "insert at"; // untranslated +Blockly.Msg["LISTS_SET_INDEX_SET"] = "set"; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST"] = "Inserts the item at the start of a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_FROM"] = "Inserts the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_LAST"] = "Append the item to the end of a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM"] = "Inserts the item randomly in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FIRST"] = "Sets the first item in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_FROM"] = "Sets the item at the specified position in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_LAST"] = "Sets the last item in a list."; // untranslated +Blockly.Msg["LISTS_SET_INDEX_TOOLTIP_SET_RANDOM"] = "Sets a random item in a list."; // untranslated +Blockly.Msg["LISTS_SORT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#sorting-a-list"; // untranslated +Blockly.Msg["LISTS_SORT_ORDER_ASCENDING"] = "ascending"; // untranslated +Blockly.Msg["LISTS_SORT_ORDER_DESCENDING"] = "descending"; // untranslated +Blockly.Msg["LISTS_SORT_TITLE"] = "sort %1 %2 %3"; // untranslated +Blockly.Msg["LISTS_SORT_TOOLTIP"] = "Sort a copy of a list."; // untranslated +Blockly.Msg["LISTS_SORT_TYPE_IGNORECASE"] = "alphabetic, ignore case"; // untranslated +Blockly.Msg["LISTS_SORT_TYPE_NUMERIC"] = "ⴰⵎⵓⵟⵟⵓⵏ"; +Blockly.Msg["LISTS_SORT_TYPE_TEXT"] = "alphabetic"; // untranslated +Blockly.Msg["LISTS_SPLIT_HELPURL"] = "https://github.com/google/blockly/wiki/Lists#splitting-strings-and-joining-lists"; // untranslated +Blockly.Msg["LISTS_SPLIT_LIST_FROM_TEXT"] = "make list from text"; // untranslated +Blockly.Msg["LISTS_SPLIT_TEXT_FROM_LIST"] = "make text from list"; // untranslated +Blockly.Msg["LISTS_SPLIT_TOOLTIP_JOIN"] = "Join a list of texts into one text, separated by a delimiter."; // untranslated +Blockly.Msg["LISTS_SPLIT_TOOLTIP_SPLIT"] = "Split text into a list of texts, breaking at each delimiter."; // untranslated +Blockly.Msg["LISTS_SPLIT_WITH_DELIMITER"] = "with delimiter"; // untranslated +Blockly.Msg["LOGIC_BOOLEAN_FALSE"] = "ⴰⵔⵎⵉⴷⵉ"; +Blockly.Msg["LOGIC_BOOLEAN_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#values"; // untranslated +Blockly.Msg["LOGIC_BOOLEAN_TOOLTIP"] = "Returns either true or false."; // untranslated +Blockly.Msg["LOGIC_BOOLEAN_TRUE"] = "ⴰⵎⵉⴷⵉ"; +Blockly.Msg["LOGIC_COMPARE_HELPURL"] = "https://en.wikipedia.org/wiki/Inequality_(mathematics)"; +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_EQ"] = "Return true if both inputs equal each other."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GT"] = "Return true if the first input is greater than the second input."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_GTE"] = "Return true if the first input is greater than or equal to the second input."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LT"] = "Return true if the first input is smaller than the second input."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_LTE"] = "Return true if the first input is smaller than or equal to the second input."; // untranslated +Blockly.Msg["LOGIC_COMPARE_TOOLTIP_NEQ"] = "Return true if both inputs are not equal to each other."; // untranslated +Blockly.Msg["LOGIC_NEGATE_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#not"; // untranslated +Blockly.Msg["LOGIC_NEGATE_TITLE"] = "ⵓⵔ ⴷ %1"; +Blockly.Msg["LOGIC_NEGATE_TOOLTIP"] = "Returns true if the input is false. Returns false if the input is true."; // untranslated +Blockly.Msg["LOGIC_NULL"] = "ⵢⵓⵔⴰ"; +Blockly.Msg["LOGIC_NULL_HELPURL"] = "https://en.wikipedia.org/wiki/Nullable_type"; // untranslated +Blockly.Msg["LOGIC_NULL_TOOLTIP"] = "Returns null."; // untranslated +Blockly.Msg["LOGIC_OPERATION_AND"] = "ⴷ"; +Blockly.Msg["LOGIC_OPERATION_HELPURL"] = "https://github.com/google/blockly/wiki/Logic#logical-operations"; // untranslated +Blockly.Msg["LOGIC_OPERATION_OR"] = "ⵏⵖ"; +Blockly.Msg["LOGIC_OPERATION_TOOLTIP_AND"] = "Return true if both inputs are true."; // untranslated +Blockly.Msg["LOGIC_OPERATION_TOOLTIP_OR"] = "Return true if at least one of the inputs is true."; // untranslated +Blockly.Msg["LOGIC_TERNARY_CONDITION"] = "ⴰⵔⵎ"; +Blockly.Msg["LOGIC_TERNARY_HELPURL"] = "https://en.wikipedia.org/wiki/%3F:"; // untranslated +Blockly.Msg["LOGIC_TERNARY_IF_FALSE"] = "ⵎⴽ ⵓⵔ ⵉⴷⵜⵜⵉ"; +Blockly.Msg["LOGIC_TERNARY_IF_TRUE"] = "ⵎⴽ ⵉⴷⵜⵜⴰ"; +Blockly.Msg["LOGIC_TERNARY_TOOLTIP"] = "Check the condition in 'test'. If the condition is true, returns the 'if true' value; otherwise returns the 'if false' value."; // untranslated +Blockly.Msg["MATH_ADDITION_SYMBOL"] = "+"; // untranslated +Blockly.Msg["MATH_ARITHMETIC_HELPURL"] = "https://en.wikipedia.org/wiki/Arithmetic"; +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_ADD"] = "Return the sum of the two numbers."; // untranslated +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_DIVIDE"] = "Return the quotient of the two numbers."; // untranslated +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MINUS"] = "Return the difference of the two numbers."; // untranslated +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_MULTIPLY"] = "Return the product of the two numbers."; // untranslated +Blockly.Msg["MATH_ARITHMETIC_TOOLTIP_POWER"] = "Return the first number raised to the power of the second number."; // untranslated +Blockly.Msg["MATH_ATAN2_HELPURL"] = "https://en.wikipedia.org/wiki/Atan2"; +Blockly.Msg["MATH_ATAN2_TITLE"] = "atan2 ⵙⴳ X:%1 Y:%2"; +Blockly.Msg["MATH_ATAN2_TOOLTIP"] = "Return the arctangent of point (X, Y) in degrees from -180 to 180."; // untranslated +Blockly.Msg["MATH_CHANGE_HELPURL"] = "https://en.wikipedia.org/wiki/Programming_idiom#Incrementing_a_counter"; // untranslated +Blockly.Msg["MATH_CHANGE_TITLE"] = "ⵙⵏⴼⵍ %1 ⵙ %2"; +Blockly.Msg["MATH_CHANGE_TOOLTIP"] = "ⵔⵏⵓ ⵢⴰⵏ ⵓⵎⴹⴰⵏ ⵖⵔ ⵓⵎⵙⴽⵉⵍ '%1'"; +Blockly.Msg["MATH_CONSTANT_HELPURL"] = "https://en.wikipedia.org/wiki/Mathematical_constant"; // untranslated +Blockly.Msg["MATH_CONSTANT_TOOLTIP"] = "Return one of the common constants: π (3.141…), e (2.718…), φ (1.618…), sqrt(2) (1.414…), sqrt(½) (0.707…), or ∞ (infinity)."; // untranslated +Blockly.Msg["MATH_CONSTRAIN_HELPURL"] = "https://en.wikipedia.org/wiki/Clamping_(graphics)"; // untranslated +Blockly.Msg["MATH_CONSTRAIN_TITLE"] = "constrain %1 low %2 high %3"; // untranslated +Blockly.Msg["MATH_CONSTRAIN_TOOLTIP"] = "Constrain a number to be between the specified limits (inclusive)."; // untranslated +Blockly.Msg["MATH_DIVISION_SYMBOL"] = "÷"; // untranslated +Blockly.Msg["MATH_IS_DIVISIBLE_BY"] = "is divisible by"; // untranslated +Blockly.Msg["MATH_IS_EVEN"] = "is even"; // untranslated +Blockly.Msg["MATH_IS_NEGATIVE"] = "is negative"; // untranslated +Blockly.Msg["MATH_IS_ODD"] = "is odd"; // untranslated +Blockly.Msg["MATH_IS_POSITIVE"] = "is positive"; // untranslated +Blockly.Msg["MATH_IS_PRIME"] = "is prime"; // untranslated +Blockly.Msg["MATH_IS_TOOLTIP"] = "Check if a number is an even, odd, prime, whole, positive, negative, or if it is divisible by certain number. Returns true or false."; // untranslated +Blockly.Msg["MATH_IS_WHOLE"] = "is whole"; // untranslated +Blockly.Msg["MATH_MODULO_HELPURL"] = "https://en.wikipedia.org/wiki/Modulo_operation"; +Blockly.Msg["MATH_MODULO_TITLE"] = "remainder of %1 ÷ %2"; // untranslated +Blockly.Msg["MATH_MODULO_TOOLTIP"] = "Return the remainder from dividing the two numbers."; // untranslated +Blockly.Msg["MATH_MULTIPLICATION_SYMBOL"] = "×"; // untranslated +Blockly.Msg["MATH_NUMBER_HELPURL"] = "https://en.wikipedia.org/wiki/Number"; +Blockly.Msg["MATH_NUMBER_TOOLTIP"] = "ⴽⵔⴰ ⵏ ⵓⵎⴹⴰⵏ."; +Blockly.Msg["MATH_ONLIST_HELPURL"] = ""; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_AVERAGE"] = "average of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_MAX"] = "max of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_MEDIAN"] = "median of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_MIN"] = "min of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_MODE"] = "modes of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_RANDOM"] = "random item of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_STD_DEV"] = "standard deviation of list"; // untranslated +Blockly.Msg["MATH_ONLIST_OPERATOR_SUM"] = "sum of list"; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_AVERAGE"] = "Return the average (arithmetic mean) of the numeric values in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_MAX"] = "Return the largest number in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_MEDIAN"] = "Return the median number in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_MIN"] = "Return the smallest number in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_MODE"] = "Return a list of the most common item(s) in the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_RANDOM"] = "Return a random element from the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_STD_DEV"] = "Return the standard deviation of the list."; // untranslated +Blockly.Msg["MATH_ONLIST_TOOLTIP_SUM"] = "Return the sum of all the numbers in the list."; // untranslated +Blockly.Msg["MATH_POWER_SYMBOL"] = "^"; // untranslated +Blockly.Msg["MATH_RANDOM_FLOAT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation"; // untranslated +Blockly.Msg["MATH_RANDOM_FLOAT_TITLE_RANDOM"] = "random fraction"; // untranslated +Blockly.Msg["MATH_RANDOM_FLOAT_TOOLTIP"] = "Return a random fraction between 0.0 (inclusive) and 1.0 (exclusive)."; // untranslated +Blockly.Msg["MATH_RANDOM_INT_HELPURL"] = "https://en.wikipedia.org/wiki/Random_number_generation"; // untranslated +Blockly.Msg["MATH_RANDOM_INT_TITLE"] = "random integer from %1 to %2"; // untranslated +Blockly.Msg["MATH_RANDOM_INT_TOOLTIP"] = "Return a random integer between the two specified limits, inclusive."; // untranslated +Blockly.Msg["MATH_ROUND_HELPURL"] = "https://en.wikipedia.org/wiki/Rounding"; +Blockly.Msg["MATH_ROUND_OPERATOR_ROUND"] = "round"; // untranslated +Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDDOWN"] = "round down"; // untranslated +Blockly.Msg["MATH_ROUND_OPERATOR_ROUNDUP"] = "round up"; // untranslated +Blockly.Msg["MATH_ROUND_TOOLTIP"] = "Round a number up or down."; // untranslated +Blockly.Msg["MATH_SINGLE_HELPURL"] = "https://en.wikipedia.org/wiki/Square_root"; // untranslated +Blockly.Msg["MATH_SINGLE_OP_ABSOLUTE"] = "absolute"; // untranslated +Blockly.Msg["MATH_SINGLE_OP_ROOT"] = "square root"; // untranslated +Blockly.Msg["MATH_SINGLE_TOOLTIP_ABS"] = "Return the absolute value of a number."; // untranslated +Blockly.Msg["MATH_SINGLE_TOOLTIP_EXP"] = "Return e to the power of a number."; // untranslated +Blockly.Msg["MATH_SINGLE_TOOLTIP_LN"] = "Return the natural logarithm of a number."; // untranslated +Blockly.Msg["MATH_SINGLE_TOOLTIP_LOG10"] = "Return the base 10 logarithm of a number."; // untranslated +Blockly.Msg["MATH_SINGLE_TOOLTIP_NEG"] = "Return the negation of a number."; // untranslated +Blockly.Msg["MATH_SINGLE_TOOLTIP_POW10"] = "Return 10 to the power of a number."; // untranslated +Blockly.Msg["MATH_SINGLE_TOOLTIP_ROOT"] = "Return the square root of a number."; // untranslated +Blockly.Msg["MATH_SUBTRACTION_SYMBOL"] = "-"; // untranslated +Blockly.Msg["MATH_TRIG_ACOS"] = "acos"; // untranslated +Blockly.Msg["MATH_TRIG_ASIN"] = "asin"; // untranslated +Blockly.Msg["MATH_TRIG_ATAN"] = "atan"; // untranslated +Blockly.Msg["MATH_TRIG_COS"] = "cos"; // untranslated +Blockly.Msg["MATH_TRIG_HELPURL"] = "https://en.wikipedia.org/wiki/Trigonometric_functions"; +Blockly.Msg["MATH_TRIG_SIN"] = "sin"; // untranslated +Blockly.Msg["MATH_TRIG_TAN"] = "tan"; // untranslated +Blockly.Msg["MATH_TRIG_TOOLTIP_ACOS"] = "Return the arccosine of a number."; // untranslated +Blockly.Msg["MATH_TRIG_TOOLTIP_ASIN"] = "Return the arcsine of a number."; // untranslated +Blockly.Msg["MATH_TRIG_TOOLTIP_ATAN"] = "Return the arctangent of a number."; // untranslated +Blockly.Msg["MATH_TRIG_TOOLTIP_COS"] = "Return the cosine of a degree (not radian)."; // untranslated +Blockly.Msg["MATH_TRIG_TOOLTIP_SIN"] = "Return the sine of a degree (not radian)."; // untranslated +Blockly.Msg["MATH_TRIG_TOOLTIP_TAN"] = "Return the tangent of a degree (not radian)."; // untranslated +Blockly.Msg["NEW_COLOUR_VARIABLE"] = "ⵙⴽⵔ ⴰⴽⵍⵓ ⴰⵎⵙⴽⵉⵍ..."; +Blockly.Msg["NEW_NUMBER_VARIABLE"] = "ⵙⴽⵔ ⴰⵎⴹⴰⵏ ⴰⵎⵙⴽⵉⵍ..."; +Blockly.Msg["NEW_STRING_VARIABLE"] = "Create string variable..."; // untranslated +Blockly.Msg["NEW_VARIABLE"] = "ⵙⴽⵔ ⴰⵎⵙⴽⵉⵍ..."; +Blockly.Msg["NEW_VARIABLE_TITLE"] = "ⵉⵙⵎ ⵏ ⵓⵎⵙⴽⵉⵍ ⴰⵎⴰⵢⵏⵓ:"; +Blockly.Msg["NEW_VARIABLE_TYPE_TITLE"] = "ⴰⵏⴰⵡ ⴰⵎⴰⵢⵏⵓ ⵏ ⵓⵎⵙⴽⵉⵍ:"; +Blockly.Msg["ORDINAL_NUMBER_SUFFIX"] = ""; // untranslated +Blockly.Msg["PROCEDURES_ALLOW_STATEMENTS"] = "allow statements"; // untranslated +Blockly.Msg["PROCEDURES_BEFORE_PARAMS"] = "ⵙ:"; +Blockly.Msg["PROCEDURES_CALLNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; +Blockly.Msg["PROCEDURES_CALLNORETURN_TOOLTIP"] = "Run the user-defined function '%1'."; // untranslated +Blockly.Msg["PROCEDURES_CALLRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; +Blockly.Msg["PROCEDURES_CALLRETURN_TOOLTIP"] = "Run the user-defined function '%1' and use its output."; // untranslated +Blockly.Msg["PROCEDURES_CALL_BEFORE_PARAMS"] = "ⵙ:"; +Blockly.Msg["PROCEDURES_CREATE_DO"] = "Create '%1'"; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"] = "Describe this function..."; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_DO"] = ""; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated +Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"] = "ⴳ ⴽⵔⴰ"; +Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"] = "ⵉ"; +Blockly.Msg["PROCEDURES_DEFNORETURN_TOOLTIP"] = "Creates a function with no output."; // untranslated +Blockly.Msg["PROCEDURES_DEFRETURN_HELPURL"] = "https://en.wikipedia.org/wiki/Subroutine"; // untranslated +Blockly.Msg["PROCEDURES_DEFRETURN_RETURN"] = "return"; // untranslated +Blockly.Msg["PROCEDURES_DEFRETURN_TOOLTIP"] = "Creates a function with an output."; // untranslated +Blockly.Msg["PROCEDURES_DEF_DUPLICATE_WARNING"] = "Warning: This function has duplicate parameters."; // untranslated +Blockly.Msg["PROCEDURES_HIGHLIGHT_DEF"] = "Highlight function definition"; // untranslated +Blockly.Msg["PROCEDURES_IFRETURN_HELPURL"] = "http://c2.com/cgi/wiki?GuardClause"; // untranslated +Blockly.Msg["PROCEDURES_IFRETURN_TOOLTIP"] = "If a value is true, then return a second value."; // untranslated +Blockly.Msg["PROCEDURES_IFRETURN_WARNING"] = "Warning: This block may be used only within a function definition."; // untranslated +Blockly.Msg["PROCEDURES_MUTATORARG_TITLE"] = "input name:"; // untranslated +Blockly.Msg["PROCEDURES_MUTATORARG_TOOLTIP"] = "ⵔⵏⵓ ⴰⵏⴽⵛⴰⵎ ⵖⵔ ⵜⵙⵖⵏⵜ."; +Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TITLE"] = "inputs"; // untranslated +Blockly.Msg["PROCEDURES_MUTATORCONTAINER_TOOLTIP"] = "Add, remove, or reorder inputs to this function."; // untranslated +Blockly.Msg["REDO"] = "ⴰⵍⵙ"; +Blockly.Msg["REMOVE_COMMENT"] = "ⴽⴽⵙ ⴰⵅⴼⴰⵡⴰⵍ"; +Blockly.Msg["RENAME_VARIABLE"] = "ⵙⵏⴼⵍ ⵉⵙⵎ ⵏ ⵓⵎⵙⴽⵉⵍ..."; +Blockly.Msg["RENAME_VARIABLE_TITLE"] = "ⵙⵏⴼⵍ ⵉⵎⵙⴽⵉⵍⵏ ⴰⴽⴽ '%1' ⵖⵔ:"; +Blockly.Msg["TEXT_APPEND_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated +Blockly.Msg["TEXT_APPEND_TITLE"] = "to %1 append text %2"; // untranslated +Blockly.Msg["TEXT_APPEND_TOOLTIP"] = "Append some text to variable '%1'."; // untranslated +Blockly.Msg["TEXT_CHANGECASE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#adjusting-text-case"; // untranslated +Blockly.Msg["TEXT_CHANGECASE_OPERATOR_LOWERCASE"] = "to lower case"; // untranslated +Blockly.Msg["TEXT_CHANGECASE_OPERATOR_TITLECASE"] = "to Title Case"; // untranslated +Blockly.Msg["TEXT_CHANGECASE_OPERATOR_UPPERCASE"] = "to UPPER CASE"; // untranslated +Blockly.Msg["TEXT_CHANGECASE_TOOLTIP"] = "Return a copy of the text in a different case."; // untranslated +Blockly.Msg["TEXT_CHARAT_FIRST"] = "get first letter"; // untranslated +Blockly.Msg["TEXT_CHARAT_FROM_END"] = "get letter # from end"; // untranslated +Blockly.Msg["TEXT_CHARAT_FROM_START"] = "get letter #"; // untranslated +Blockly.Msg["TEXT_CHARAT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-text"; // untranslated +Blockly.Msg["TEXT_CHARAT_LAST"] = "get last letter"; // untranslated +Blockly.Msg["TEXT_CHARAT_RANDOM"] = "get random letter"; // untranslated +Blockly.Msg["TEXT_CHARAT_TAIL"] = ""; // untranslated +Blockly.Msg["TEXT_CHARAT_TITLE"] = "in text %1 %2"; // untranslated +Blockly.Msg["TEXT_CHARAT_TOOLTIP"] = "Returns the letter at the specified position."; // untranslated +Blockly.Msg["TEXT_COUNT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#counting-substrings"; // untranslated +Blockly.Msg["TEXT_COUNT_MESSAGE0"] = "count %1 in %2"; // untranslated +Blockly.Msg["TEXT_COUNT_TOOLTIP"] = "Count how many times some text occurs within some other text."; // untranslated +Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TOOLTIP"] = "Add an item to the text."; // untranslated +Blockly.Msg["TEXT_CREATE_JOIN_TITLE_JOIN"] = "ⵍⴽⵎ"; +Blockly.Msg["TEXT_CREATE_JOIN_TOOLTIP"] = "Add, remove, or reorder sections to reconfigure this text block."; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_END"] = "to letter # from end"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_END_FROM_START"] = "to letter #"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_END_LAST"] = "ⴰⵔ ⵓⵙⴽⴽⵉⵍ ⴰⵎⴳⴳⴰⵔⵓ"; +Blockly.Msg["TEXT_GET_SUBSTRING_HELPURL"] = "https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_INPUT_IN_TEXT"] = "ⴳ ⵓⴹⵕⵉⵚ"; +Blockly.Msg["TEXT_GET_SUBSTRING_START_FIRST"] = "get substring from first letter"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_END"] = "get substring from letter # from end"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_START_FROM_START"] = "get substring from letter #"; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_TAIL"] = ""; // untranslated +Blockly.Msg["TEXT_GET_SUBSTRING_TOOLTIP"] = "Returns a specified portion of the text."; // untranslated +Blockly.Msg["TEXT_INDEXOF_HELPURL"] = "https://github.com/google/blockly/wiki/Text#finding-text"; // untranslated +Blockly.Msg["TEXT_INDEXOF_OPERATOR_FIRST"] = "find first occurrence of text"; // untranslated +Blockly.Msg["TEXT_INDEXOF_OPERATOR_LAST"] = "find last occurrence of text"; // untranslated +Blockly.Msg["TEXT_INDEXOF_TITLE"] = "ⴳ ⵓⴹⵕⵉⵚ %1 %2 %3"; +Blockly.Msg["TEXT_INDEXOF_TOOLTIP"] = "Returns the index of the first/last occurrence of the first text in the second text. Returns %1 if text is not found."; // untranslated +Blockly.Msg["TEXT_ISEMPTY_HELPURL"] = "https://github.com/google/blockly/wiki/Text#checking-for-empty-text"; // untranslated +Blockly.Msg["TEXT_ISEMPTY_TITLE"] = "%1 is empty"; // untranslated +Blockly.Msg["TEXT_ISEMPTY_TOOLTIP"] = "Returns true if the provided text is empty."; // untranslated +Blockly.Msg["TEXT_JOIN_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-creation"; // untranslated +Blockly.Msg["TEXT_JOIN_TITLE_CREATEWITH"] = "ⵙⵏⴼⵍⵓⵍ ⴰⴹⵕⵉⵚ ⵙ"; +Blockly.Msg["TEXT_JOIN_TOOLTIP"] = "Create a piece of text by joining together any number of items."; // untranslated +Blockly.Msg["TEXT_LENGTH_HELPURL"] = "https://github.com/google/blockly/wiki/Text#text-modification"; // untranslated +Blockly.Msg["TEXT_LENGTH_TITLE"] = "ⵜⵉⵖⵣⵉ ⵏ %1"; +Blockly.Msg["TEXT_LENGTH_TOOLTIP"] = "Returns the number of letters (including spaces) in the provided text."; // untranslated +Blockly.Msg["TEXT_PRINT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#printing-text"; // untranslated +Blockly.Msg["TEXT_PRINT_TITLE"] = "print %1"; // untranslated +Blockly.Msg["TEXT_PRINT_TOOLTIP"] = "Print the specified text, number or other value."; // untranslated +Blockly.Msg["TEXT_PROMPT_HELPURL"] = "https://github.com/google/blockly/wiki/Text#getting-input-from-the-user"; // untranslated +Blockly.Msg["TEXT_PROMPT_TOOLTIP_NUMBER"] = "Prompt for user for a number."; // untranslated +Blockly.Msg["TEXT_PROMPT_TOOLTIP_TEXT"] = "Prompt for user for some text."; // untranslated +Blockly.Msg["TEXT_PROMPT_TYPE_NUMBER"] = "prompt for number with message"; // untranslated +Blockly.Msg["TEXT_PROMPT_TYPE_TEXT"] = "prompt for text with message"; // untranslated +Blockly.Msg["TEXT_REPLACE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#replacing-substrings"; // untranslated +Blockly.Msg["TEXT_REPLACE_MESSAGE0"] = "replace %1 with %2 in %3"; // untranslated +Blockly.Msg["TEXT_REPLACE_TOOLTIP"] = "Replace all occurances of some text within some other text."; // untranslated +Blockly.Msg["TEXT_REVERSE_HELPURL"] = "https://github.com/google/blockly/wiki/Text#reversing-text"; // untranslated +Blockly.Msg["TEXT_REVERSE_MESSAGE0"] = "reverse %1"; // untranslated +Blockly.Msg["TEXT_REVERSE_TOOLTIP"] = "Reverses the order of the characters in the text."; // untranslated +Blockly.Msg["TEXT_TEXT_HELPURL"] = "https://en.wikipedia.org/wiki/String_(computer_science)"; // untranslated +Blockly.Msg["TEXT_TEXT_TOOLTIP"] = "A letter, word, or line of text."; // untranslated +Blockly.Msg["TEXT_TRIM_HELPURL"] = "https://github.com/google/blockly/wiki/Text#trimming-removing-spaces"; // untranslated +Blockly.Msg["TEXT_TRIM_OPERATOR_BOTH"] = "trim spaces from both sides of"; // untranslated +Blockly.Msg["TEXT_TRIM_OPERATOR_LEFT"] = "trim spaces from left side of"; // untranslated +Blockly.Msg["TEXT_TRIM_OPERATOR_RIGHT"] = "trim spaces from right side of"; // untranslated +Blockly.Msg["TEXT_TRIM_TOOLTIP"] = "Return a copy of the text with spaces removed from one or both ends."; // untranslated +Blockly.Msg["TODAY"] = "ⴰⵙⵙⴰ"; +Blockly.Msg["UNDO"] = "ⵙⵔ"; +Blockly.Msg["UNNAMED_KEY"] = "ⴰⵔⵉⵙⵎ"; +Blockly.Msg["VARIABLES_DEFAULT_NAME"] = "ⴰⴼⵔⴷⵉⵙ"; +Blockly.Msg["VARIABLES_GET_CREATE_SET"] = "Create 'set %1'"; // untranslated +Blockly.Msg["VARIABLES_GET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#get"; // untranslated +Blockly.Msg["VARIABLES_GET_TOOLTIP"] = "Returns the value of this variable."; // untranslated +Blockly.Msg["VARIABLES_SET"] = "set %1 to %2"; // untranslated +Blockly.Msg["VARIABLES_SET_CREATE_GET"] = "Create 'get %1'"; // untranslated +Blockly.Msg["VARIABLES_SET_HELPURL"] = "https://github.com/google/blockly/wiki/Variables#set"; // untranslated +Blockly.Msg["VARIABLES_SET_TOOLTIP"] = "Sets this variable to be equal to the input."; // untranslated +Blockly.Msg["VARIABLE_ALREADY_EXISTS"] = "A variable named '%1' already exists."; // untranslated +Blockly.Msg["VARIABLE_ALREADY_EXISTS_FOR_ANOTHER_TYPE"] = "A variable named '%1' already exists for another type: '%2'."; // untranslated +Blockly.Msg["WORKSPACE_ARIA_LABEL"] = "Blockly Workspace"; // untranslated +Blockly.Msg["WORKSPACE_COMMENT_DEFAULT_TEXT"] = "Say something..."; // untranslated +Blockly.Msg["CONTROLS_FOREACH_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"]; +Blockly.Msg["CONTROLS_FOR_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"]; +Blockly.Msg["CONTROLS_IF_ELSEIF_TITLE_ELSEIF"] = Blockly.Msg["CONTROLS_IF_MSG_ELSEIF"]; +Blockly.Msg["CONTROLS_IF_ELSE_TITLE_ELSE"] = Blockly.Msg["CONTROLS_IF_MSG_ELSE"]; +Blockly.Msg["CONTROLS_IF_IF_TITLE_IF"] = Blockly.Msg["CONTROLS_IF_MSG_IF"]; +Blockly.Msg["CONTROLS_IF_MSG_THEN"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"]; +Blockly.Msg["CONTROLS_WHILEUNTIL_INPUT_DO"] = Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"]; +Blockly.Msg["LISTS_CREATE_WITH_ITEM_TITLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"]; +Blockly.Msg["LISTS_GET_INDEX_HELPURL"] = Blockly.Msg["LISTS_INDEX_OF_HELPURL"]; +Blockly.Msg["LISTS_GET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"]; +Blockly.Msg["LISTS_GET_SUBLIST_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"]; +Blockly.Msg["LISTS_INDEX_OF_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"]; +Blockly.Msg["LISTS_SET_INDEX_INPUT_IN_LIST"] = Blockly.Msg["LISTS_INLIST"]; +Blockly.Msg["MATH_CHANGE_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"]; +Blockly.Msg["PROCEDURES_DEFRETURN_COMMENT"] = Blockly.Msg["PROCEDURES_DEFNORETURN_COMMENT"]; +Blockly.Msg["PROCEDURES_DEFRETURN_DO"] = Blockly.Msg["PROCEDURES_DEFNORETURN_DO"]; +Blockly.Msg["PROCEDURES_DEFRETURN_PROCEDURE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_PROCEDURE"]; +Blockly.Msg["PROCEDURES_DEFRETURN_TITLE"] = Blockly.Msg["PROCEDURES_DEFNORETURN_TITLE"]; +Blockly.Msg["TEXT_APPEND_VARIABLE"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"]; +Blockly.Msg["TEXT_CREATE_JOIN_ITEM_TITLE_ITEM"] = Blockly.Msg["VARIABLES_DEFAULT_NAME"]; + +Blockly.Msg["MATH_HUE"] = "230"; +Blockly.Msg["LOOPS_HUE"] = "120"; +Blockly.Msg["LISTS_HUE"] = "260"; +Blockly.Msg["LOGIC_HUE"] = "210"; +Blockly.Msg["VARIABLES_HUE"] = "330"; +Blockly.Msg["TEXTS_HUE"] = "160"; +Blockly.Msg["PROCEDURES_HUE"] = "290"; +Blockly.Msg["COLOUR_HUE"] = "20"; +Blockly.Msg["VARIABLES_DYNAMIC_HUE"] = "310"; \ No newline at end of file From 355c54f70a031acf5d02d2b6b6b9a329b4a90871 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 15 Jun 2021 19:10:13 +0000 Subject: [PATCH 12/36] Use captureWarning helper from dev-tools instead of mocha/test_helpers.js implementation. --- tests/mocha/.eslintrc.json | 2 +- tests/mocha/registry_test.js | 2 +- tests/mocha/test_helpers.js | 21 +-------------------- tests/mocha/workspace_test.js | 4 ++-- 4 files changed, 5 insertions(+), 24 deletions(-) diff --git a/tests/mocha/.eslintrc.json b/tests/mocha/.eslintrc.json index 34a32aba8..47ffaefb5 100644 --- a/tests/mocha/.eslintrc.json +++ b/tests/mocha/.eslintrc.json @@ -21,7 +21,7 @@ "assertVariableValues": true, "assertNoWarnings": true, "assertWarnings": true, - "captureWarnings": true, + "captureWarnings": false, "createDeprecationWarningStub": true, "createKeyDownEvent": true, "createRenderedBlock": true, diff --git a/tests/mocha/registry_test.js b/tests/mocha/registry_test.js index f4171197c..1ffff755a 100644 --- a/tests/mocha/registry_test.js +++ b/tests/mocha/registry_test.js @@ -85,7 +85,7 @@ suite('Registry', function() { test('Incorrect Plugin Name', function() { this.options['plugins']['test'] = 'random'; var testClass; - var warnings = captureWarnings(() => { + var warnings = testHelpers.captureWarnings(() => { testClass = Blockly.registry.getClassFromOptions('test', this.options); }); chai.assert.isNull(testClass); diff --git a/tests/mocha/test_helpers.js b/tests/mocha/test_helpers.js index 151095376..426929dfb 100644 --- a/tests/mocha/test_helpers.js +++ b/tests/mocha/test_helpers.js @@ -20,25 +20,6 @@ function assertVariableValues(container, name, type, id) { chai.assert.equal(variable.getId(), id); } -/** - * Captures the strings sent to console.warn() when calling a function. - * @param {function} innerFunc The function where warnings may called. - * @return {string[]} The warning messages (only the first arguments). - */ -function captureWarnings(innerFunc) { - var msgs = []; - var nativeConsoleWarn = console.warn; - try { - console.warn = function(msg) { - msgs.push(msg); - }; - innerFunc(); - } finally { - console.warn = nativeConsoleWarn; - } - return msgs; -} - /** * Asserts that the given function logs the provided warning messages. * @param {function} innerFunc The function to call. @@ -49,7 +30,7 @@ function assertWarnings(innerFunc, messages) { if (!Array.isArray(messages)) { messages = [messages]; } - var warnings = captureWarnings(innerFunc); + var warnings = testHelpers.captureWarnings(innerFunc); chai.assert.lengthOf(warnings, messages.length); messages.forEach((message, i) => { chai.assert.match(warnings[i], message); diff --git a/tests/mocha/workspace_test.js b/tests/mocha/workspace_test.js index e9bc9ece9..1467b06e9 100644 --- a/tests/mocha/workspace_test.js +++ b/tests/mocha/workspace_test.js @@ -1303,7 +1303,7 @@ function testAWorkspace() { this.workspace.createVariable('name1', 'type1', 'id1'); this.workspace.deleteVariableById('id1'); var workspace = this.workspace; - var warnings = captureWarnings(function() { + var warnings = testHelpers.captureWarnings(function() { workspace.deleteVariableById('id1'); }); chai.assert.equal(warnings.length, 1, @@ -1332,7 +1332,7 @@ function testAWorkspace() { createVarBlocksNoEvents(this.workspace, ['id1']); this.workspace.deleteVariableById('id1'); var workspace = this.workspace; - var warnings = captureWarnings(function() { + var warnings = testHelpers.captureWarnings(function() { workspace.deleteVariableById('id1'); }); chai.assert.equal(warnings.length, 1, From ee8e282360eeea2f2408027abf2b42704f608d0a Mon Sep 17 00:00:00 2001 From: jschanker Date: Tue, 8 Jun 2021 00:26:02 -0400 Subject: [PATCH 13/36] Fix #4830 for getting/setting unnamed fields * Returns null when getting unnamed field (value), throws error Field "undefined" not found when attempting to set value of unnamed field --- core/block.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/block.js b/core/block.js index 6989ffdfa..8f574498b 100644 --- a/core/block.js +++ b/core/block.js @@ -1026,7 +1026,7 @@ Blockly.Block.prototype.setOnChange = function(onchangeFn) { Blockly.Block.prototype.getField = function(name) { for (var i = 0, input; (input = this.inputList[i]); i++) { for (var j = 0, field; (field = input.fieldRow[j]); j++) { - if (field.name == name) { + if (typeof field.name !== "undefined" && field.name == name) { return field; } } From f9c5260fb0d54c45fef19fdc2de8896bf11b7f43 Mon Sep 17 00:00:00 2001 From: jschanker Date: Sat, 12 Jun 2021 03:16:12 -0400 Subject: [PATCH 14/36] Added tests/setFieldValue error message * Added tests for getting/setting field (values) when names are not supplied and test for getting a field value, setting it to a new value, and getting it again. * Added more user-friendly error message for setFieldValue telling the developer that he/she is missing the name rather than Field "undefined" not found. --- core/block.js | 4 ++++ tests/mocha/block_test.js | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/core/block.js b/core/block.js index 8f574498b..94ccbeb9c 100644 --- a/core/block.js +++ b/core/block.js @@ -1127,6 +1127,10 @@ Blockly.Block.prototype.getFieldValue = function(name) { * @param {!string} name The name of the field to set the value of. */ Blockly.Block.prototype.setFieldValue = function(newValue, name) { + if (typeof name === "undefined") { + throw Error("Call to Blockly.Block.prototype.setFieldValue without " + + "required second argument of field name."); + } var field = this.getField(name); if (!field) { throw Error('Field "' + name + '" not found.'); diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index 7995902ce..e9a2b9fbf 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -1104,6 +1104,31 @@ suite('Blocks', function() { }); }); }); + suite('Getting/Setting Field (Values)', function() { + setup(function() { + this.block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + 'test' + ), this.workspace); + }); + + test('Getting Field', function() { + chai.assert.instanceOf(this.block.getField("TEXT"), Blockly.Field); + }); + test('Getting Field without Name', function() { + chai.assert.isNull(this.block.getField()); + }); + test('Getting Value of Field without Name', function() { + chai.assert.isNull(this.block.getFieldValue()); + }); + test('Getting/Setting Field Value', function() { + chai.assert.equal(this.block.getFieldValue("TEXT"), "test"); + this.block.setFieldValue("abc", "TEXT"); + chai.assert.equal(this.block.getFieldValue("TEXT"), "abc"); + }); + test('Setting Field without Name', function() { + chai.assert.throws(this.block.setFieldValue.bind(this.block, 'test')); + }); + }); suite('Icon Management', function() { suite('Bubbles and Collapsing', function() { setup(function() { From 62bb663b38d860f85c81fd886fc96e5b39229825 Mon Sep 17 00:00:00 2001 From: jschanker Date: Sat, 12 Jun 2021 03:22:22 -0400 Subject: [PATCH 15/36] Added tests/setFieldValue error message * Added tests for getting/setting field (values) when names are not supplied and test for getting a field value, setting it to a new value, and getting it again. * Added more user-friendly error message for setFieldValue telling the developer that he/she is missing the name rather than Field "undefined" not found. * Fixed lint error by removing trailing space --- core/block.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/block.js b/core/block.js index 94ccbeb9c..c7faf8525 100644 --- a/core/block.js +++ b/core/block.js @@ -1128,7 +1128,7 @@ Blockly.Block.prototype.getFieldValue = function(name) { */ Blockly.Block.prototype.setFieldValue = function(newValue, name) { if (typeof name === "undefined") { - throw Error("Call to Blockly.Block.prototype.setFieldValue without " + + throw Error("Call to Blockly.Block.prototype.setFieldValue without " + "required second argument of field name."); } var field = this.getField(name); From 672574b0561b48928a079b7e6503123d995e9b4e Mon Sep 17 00:00:00 2001 From: jschanker Date: Wed, 16 Jun 2021 01:01:14 -0400 Subject: [PATCH 16/36] Require field name to be string, test changes * Now throws error for getField/getFieldValue/setFieldValue if provided name is not a string * Changed error to more specific TypeError * Type checking and error message moved up to getField * Tests added/modified to check that non-string types for field names produce type errors --- core/block.js | 14 +++++++------ tests/mocha/block_test.js | 42 +++++++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/core/block.js b/core/block.js index c7faf8525..0f4bf1cb0 100644 --- a/core/block.js +++ b/core/block.js @@ -1024,9 +1024,15 @@ Blockly.Block.prototype.setOnChange = function(onchangeFn) { * @return {?Blockly.Field} Named field, or null if field does not exist. */ Blockly.Block.prototype.getField = function(name) { + if (typeof name !== 'string') { + throw TypeError('Blockly.Block.prototype.getField expects a string ' + + 'with the field name but received ' + + (name === undefined ? 'nothing' : name + ' of type ' + typeof name) + + ' instead'); + } for (var i = 0, input; (input = this.inputList[i]); i++) { for (var j = 0, field; (field = input.fieldRow[j]); j++) { - if (typeof field.name !== "undefined" && field.name == name) { + if (field.name === name) { return field; } } @@ -1124,13 +1130,9 @@ Blockly.Block.prototype.getFieldValue = function(name) { /** * Sets the value of the given field for this block. * @param {*} newValue The value to set. - * @param {!string} name The name of the field to set the value of. + * @param {string} name The name of the field to set the value of. */ Blockly.Block.prototype.setFieldValue = function(newValue, name) { - if (typeof name === "undefined") { - throw Error("Call to Blockly.Block.prototype.setFieldValue without " + - "required second argument of field name."); - } var field = this.getField(name); if (!field) { throw Error('Field "' + name + '" not found.'); diff --git a/tests/mocha/block_test.js b/tests/mocha/block_test.js index e9a2b9fbf..4d310cac2 100644 --- a/tests/mocha/block_test.js +++ b/tests/mocha/block_test.js @@ -1112,22 +1112,52 @@ suite('Blocks', function() { }); test('Getting Field', function() { - chai.assert.instanceOf(this.block.getField("TEXT"), Blockly.Field); + chai.assert.instanceOf(this.block.getField('TEXT'), Blockly.Field); }); test('Getting Field without Name', function() { - chai.assert.isNull(this.block.getField()); + chai.assert.throws(this.block.getField.bind(this.block), TypeError); }); test('Getting Value of Field without Name', function() { - chai.assert.isNull(this.block.getFieldValue()); + chai.assert.throws(this.block.getFieldValue.bind(this.block), TypeError); + }); + test('Getting Field with Wrong Type', function() { + var testFunction = function() { + return 'TEXT'; + }; + var inputs = [1, null, testFunction, {toString: testFunction}, ['TEXT']]; + for (var i = 0; i < inputs.length; i++) { + chai.assert.throws(this.block.getField.bind(this.block, inputs[i]), + TypeError); + } + }); + test('Getting Value of Field with Wrong Type', function() { + var testFunction = function() { + return 'TEXT'; + }; + var inputs = [1, null, testFunction, {toString: testFunction}, ['TEXT']]; + for (var i = 0; i < inputs.length; i++) { + chai.assert.throws( + this.block.getFieldValue.bind(this.block, inputs[i]), TypeError); + } }); test('Getting/Setting Field Value', function() { - chai.assert.equal(this.block.getFieldValue("TEXT"), "test"); - this.block.setFieldValue("abc", "TEXT"); - chai.assert.equal(this.block.getFieldValue("TEXT"), "abc"); + chai.assert.equal(this.block.getFieldValue('TEXT'), 'test'); + this.block.setFieldValue('abc', 'TEXT'); + chai.assert.equal(this.block.getFieldValue('TEXT'), 'abc'); }); test('Setting Field without Name', function() { chai.assert.throws(this.block.setFieldValue.bind(this.block, 'test')); }); + test('Setting Field with Wrong Type', function() { + var testFunction = function() { + return 'TEXT'; + }; + var inputs = [1, null, testFunction, {toString: testFunction}, ['TEXT']]; + for (var i = 0; i < inputs.length; i++) { + chai.assert.throws(this.block.setFieldValue.bind(this.block, 'test', + inputs[i]), TypeError); + } + }); }); suite('Icon Management', function() { suite('Bubbles and Collapsing', function() { From a46dbb37e76a672579316e93842750707358edaf Mon Sep 17 00:00:00 2001 From: alschmiedt Date: Wed, 16 Jun 2021 08:18:28 -0700 Subject: [PATCH 17/36] Fixes workspace scroll bug (#4921) --- core/toolbox/toolbox.js | 1 + 1 file changed, 1 insertion(+) diff --git a/core/toolbox/toolbox.js b/core/toolbox/toolbox.js index d96bde6d2..ff039e1dd 100644 --- a/core/toolbox/toolbox.js +++ b/core/toolbox/toolbox.js @@ -407,6 +407,7 @@ Blockly.Toolbox.prototype.render = function(toolboxDef) { this.contentMap_ = Object.create(null); this.renderContents_(toolboxDef['contents']); this.position(); + this.handleToolboxItemResize(); }; /** From a15bbf17003403dceddf45735686e71341252317 Mon Sep 17 00:00:00 2001 From: Monica Kozbial <6621618+moniika@users.noreply.github.com> Date: Wed, 16 Jun 2021 09:36:39 -0700 Subject: [PATCH 18/36] Revert #4697 (#4917) --- blockly_uncompressed.js | 4 +- core/requires.js | 2 + core/theme/dark.js | 33 +++++++ core/theme/modern.js | 108 +++++++++++++++++++++ package-lock.json | 6 -- package.json | 1 - scripts/gulpfiles/appengine_tasks.js | 1 - tests/playgrounds/advanced_playground.html | 1 - 8 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 core/theme/dark.js create mode 100644 core/theme/modern.js diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index 3d4d7c0e6..9a52ca263 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -165,14 +165,16 @@ goog.addDependency('../../core/renderers/zelos/measurables/row_elements.js', ['B goog.addDependency('../../core/renderers/zelos/measurables/rows.js', ['Blockly.zelos.BottomRow', 'Blockly.zelos.TopRow'], ['Blockly.blockRendering.BottomRow', 'Blockly.blockRendering.TopRow', 'Blockly.utils.object']); goog.addDependency('../../core/renderers/zelos/path_object.js', ['Blockly.zelos.PathObject'], ['Blockly.blockRendering.PathObject', 'Blockly.utils.Svg', 'Blockly.utils.dom', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider']); goog.addDependency('../../core/renderers/zelos/renderer.js', ['Blockly.zelos.Renderer'], ['Blockly.InsertionMarkerManager', 'Blockly.blockRendering', 'Blockly.blockRendering.Renderer', 'Blockly.connectionTypes', 'Blockly.constants', 'Blockly.utils.object', 'Blockly.zelos.ConstantProvider', 'Blockly.zelos.Drawer', 'Blockly.zelos.MarkerSvg', 'Blockly.zelos.PathObject', 'Blockly.zelos.RenderInfo']); -goog.addDependency('../../core/requires.js', ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.ContextMenuItems', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.HorizontalFlyout', 'Blockly.Mutator', 'Blockly.ShortcutItems', 'Blockly.Themes.Classic', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.ZoomControls', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer']); +goog.addDependency('../../core/requires.js', ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.ContextMenuItems', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.HorizontalFlyout', 'Blockly.Mutator', 'Blockly.ShortcutItems', 'Blockly.Themes.Classic', 'Blockly.Themes.Dark', 'Blockly.Themes.Deuteranopia', 'Blockly.Themes.HighContrast', 'Blockly.Themes.Tritanopia', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.ZoomControls', 'Blockly.geras.Renderer', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer']); goog.addDependency('../../core/scrollbar.js', ['Blockly.Scrollbar', 'Blockly.ScrollbarPair'], ['Blockly.Events', 'Blockly.Touch', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Metrics', 'Blockly.utils.Svg', 'Blockly.utils.dom']); goog.addDependency('../../core/shortcut_items.js', ['Blockly.ShortcutItems'], ['Blockly.Gesture', 'Blockly.ShortcutRegistry', 'Blockly.utils.KeyCodes']); goog.addDependency('../../core/shortcut_registry.js', ['Blockly.ShortcutRegistry'], ['Blockly.utils.KeyCodes', 'Blockly.utils.object']); goog.addDependency('../../core/theme.js', ['Blockly.Theme'], ['Blockly.registry', 'Blockly.utils', 'Blockly.utils.object']); goog.addDependency('../../core/theme/classic.js', ['Blockly.Themes.Classic'], ['Blockly.Theme']); +goog.addDependency('../../core/theme/dark.js', ['Blockly.Themes.Dark'], ['Blockly.Theme']); goog.addDependency('../../core/theme/deuteranopia.js', ['Blockly.Themes.Deuteranopia'], ['Blockly.Theme']); goog.addDependency('../../core/theme/highcontrast.js', ['Blockly.Themes.HighContrast'], ['Blockly.Theme']); +goog.addDependency('../../core/theme/modern.js', ['Blockly.Themes.Modern'], ['Blockly.Theme']); goog.addDependency('../../core/theme/tritanopia.js', ['Blockly.Themes.Tritanopia'], ['Blockly.Theme']); goog.addDependency('../../core/theme/zelos.js', ['Blockly.Themes.Zelos'], ['Blockly.Theme']); goog.addDependency('../../core/theme_manager.js', ['Blockly.ThemeManager'], ['Blockly.Theme']); diff --git a/core/requires.js b/core/requires.js index 009ab3f9c..f08286ec4 100644 --- a/core/requires.js +++ b/core/requires.js @@ -82,6 +82,8 @@ goog.require('Blockly.zelos.Renderer'); // Blockly Themes. // Classic is the default theme. goog.require('Blockly.Themes.Classic'); +goog.require('Blockly.Themes.Dark'); goog.require('Blockly.Themes.Deuteranopia'); goog.require('Blockly.Themes.HighContrast'); goog.require('Blockly.Themes.Tritanopia'); +// goog.require('Blockly.Themes.Modern'); diff --git a/core/theme/dark.js b/core/theme/dark.js new file mode 100644 index 000000000..398497660 --- /dev/null +++ b/core/theme/dark.js @@ -0,0 +1,33 @@ +/** + * @license + * Copyright 2019 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Dark theme. + * @author samelh@google.com (Sam El-Husseini) + */ +'use strict'; + +goog.provide('Blockly.Themes.Dark'); + +goog.require('Blockly.Theme'); + +Blockly.Themes.Dark = Blockly.Theme.defineTheme('dark', { + 'base': Blockly.Themes.Classic, + 'componentStyles': { + 'workspaceBackgroundColour': '#1e1e1e', + 'toolboxBackgroundColour': 'blackBackground', + 'toolboxForegroundColour': '#fff', + 'flyoutBackgroundColour': '#252526', + 'flyoutForegroundColour': '#ccc', + 'flyoutOpacity': 1, + 'scrollbarColour': '#797979', + 'insertionMarkerColour': '#fff', + 'insertionMarkerOpacity': 0.3, + 'scrollbarOpacity': 0.4, + 'cursorColour': '#d0d0d0', + 'blackBackground': '#333' + } +}); diff --git a/core/theme/modern.js b/core/theme/modern.js new file mode 100644 index 000000000..2ed8a6845 --- /dev/null +++ b/core/theme/modern.js @@ -0,0 +1,108 @@ +/** + * @license + * Copyright 2018 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @fileoverview Modern theme. + * Same colours as classic, but single coloured border. + */ +'use strict'; + +goog.provide('Blockly.Themes.Modern'); + +goog.require('Blockly.Theme'); + + +// Temporary holding object. +Blockly.Themes.Modern = {}; + +Blockly.Themes.Modern.defaultBlockStyles = { + "colour_blocks": { + "colourPrimary": "#a5745b", + "colourSecondary": "#dbc7bd", + "colourTertiary": "#845d49" + }, + "list_blocks": { + "colourPrimary": "#745ba5", + "colourSecondary": "#c7bddb", + "colourTertiary": "#5d4984" + }, + "logic_blocks": { + "colourPrimary": "#5b80a5", + "colourSecondary": "#bdccdb", + "colourTertiary": "#496684" + }, + "loop_blocks": { + "colourPrimary": "#5ba55b", + "colourSecondary": "#bddbbd", + "colourTertiary": "#498449" + }, + "math_blocks": { + "colourPrimary": "#5b67a5", + "colourSecondary": "#bdc2db", + "colourTertiary": "#495284" + }, + "procedure_blocks": { + "colourPrimary": "#995ba5", + "colourSecondary": "#d6bddb", + "colourTertiary": "#7a4984" + }, + "text_blocks": { + "colourPrimary": "#5ba58c", + "colourSecondary": "#bddbd1", + "colourTertiary": "#498470" + }, + "variable_blocks": { + "colourPrimary": "#a55b99", + "colourSecondary": "#dbbdd6", + "colourTertiary": "#84497a" + }, + "variable_dynamic_blocks": { + "colourPrimary": "#a55b99", + "colourSecondary": "#dbbdd6", + "colourTertiary": "#84497a" + }, + "hat_blocks": { + "colourPrimary": "#a55b99", + "colourSecondary": "#dbbdd6", + "colourTertiary": "#84497a", + "hat": "cap" + } +}; + +Blockly.Themes.Modern.categoryStyles = { + "colour_category": { + "colour": "#a5745b" + }, + "list_category": { + "colour": "#745ba5" + }, + "logic_category": { + "colour": "#5b80a5" + }, + "loop_category": { + "colour": "#5ba55b" + }, + "math_category": { + "colour": "#5b67a5" + }, + "procedure_category": { + "colour": "#995ba5" + }, + "text_category": { + "colour": "#5ba58c" + }, + "variable_category": { + "colour": "#a55b99" + }, + "variable_dynamic_category": { + "colour": "#a55b99" + } +}; + +// This style is still being fleshed out and may change. +Blockly.Themes.Modern = + new Blockly.Theme('modern', Blockly.Themes.Modern.defaultBlockStyles, + Blockly.Themes.Modern.categoryStyles); diff --git a/package-lock.json b/package-lock.json index 964aa9cdc..d2f40ff1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -241,12 +241,6 @@ } } }, - "@blockly/theme-dark": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@blockly/theme-dark/-/theme-dark-1.0.7.tgz", - "integrity": "sha512-ohZRlrbKnRtzp63mDh/9XRFnTnnpyG110ff2UjGYmEuBcWeazgY1aISufrPbOANnPDfVV5SZI9DQnNvXjdmP9w==", - "dev": true - }, "@blockly/theme-modern": { "version": "2.1.17", "resolved": "https://registry.npmjs.org/@blockly/theme-modern/-/theme-modern-2.1.17.tgz", diff --git a/package.json b/package.json index f0cb52773..3df16bb0a 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,6 @@ "devDependencies": { "@blockly/block-test": "^1.0.0", "@blockly/dev-tools": "^2.0.1", - "@blockly/theme-dark": "^1.0.0", "@blockly/theme-modern": "^2.1.1", "@wdio/selenium-standalone-service": "^6.11.0", "babel-eslint": "^10.1.0", diff --git a/scripts/gulpfiles/appengine_tasks.js b/scripts/gulpfiles/appengine_tasks.js index e07b9f60f..08fb3ea85 100644 --- a/scripts/gulpfiles/appengine_tasks.js +++ b/scripts/gulpfiles/appengine_tasks.js @@ -59,7 +59,6 @@ function copyAppengineSrc() { function copyPlaygroundDeps() { const playgroundDeps = [ './node_modules/@blockly/dev-tools/dist/index.js', - './node_modules/@blockly/theme-dark/dist/index.js', './node_modules/@blockly/theme-modern/dist/index.js', './node_modules/@blockly/block-test/dist/index.js', ]; diff --git a/tests/playgrounds/advanced_playground.html b/tests/playgrounds/advanced_playground.html index 87e1f37e2..b142a6a00 100644 --- a/tests/playgrounds/advanced_playground.html +++ b/tests/playgrounds/advanced_playground.html @@ -67,7 +67,6 @@ - '); - document.write(''); -} -""") - f.close() - print("SUCCESS: " + self.target_filename) - - -class Gen_compressed(threading.Thread): - """Generate a JavaScript file that contains all of Blockly's core and all - required parts of Closure, compiled together. - Uses the Closure Compiler's online API. - Runs in a separate thread. - """ - def __init__(self, search_paths, bundles): - threading.Thread.__init__(self) - self.search_paths = search_paths - self.bundles = bundles - - def run(self): - if (self.bundles.core): - self.gen_core() - self.gen_blocks() - - if (self.bundles.generators): - self.gen_generator("javascript") - self.gen_generator("python") - self.gen_generator("php") - self.gen_generator("lua") - self.gen_generator("dart") - - def gen_core(self): - target_filename = "blockly_compressed.js" - # Define the parameters for the POST request. - params = [ - ("compilation_level", "SIMPLE_OPTIMIZATIONS"), - ("use_closure_library", "false"), - ("output_format", "json"), - ("output_info", "compiled_code"), - ("output_info", "warnings"), - ("output_info", "errors"), - ("output_info", "statistics"), - ("warning_level", "DEFAULT"), - ] - - # Read in all the source files. - filenames = calcdeps.CalculateDependencies(self.search_paths, - [os.path.join("core", "requires.js")]) - filenames.sort() # Deterministic build. - for filename in filenames: - # Filter out the Closure files (the compiler will add them). - if filename.startswith("closure"): - continue - f = codecs.open(filename, encoding="utf-8") - code = "".join(f.readlines()) - # Inject the Blockly version. - if filename == "core/blockly.js": - code = code.replace("Blockly.VERSION = 'uncompiled';", - "Blockly.VERSION = '%s';" % blocklyVersion) - # Strip out all requireType calls. - code = re.sub(r"goog.requireType(.*)", "", code) - params.append(("js_code", code.encode("utf-8"))) - f.close() - - self.do_compile(params, target_filename, filenames, "") - - def gen_blocks(self): - target_filename = "blocks_compressed.js" - # Define the parameters for the POST request. - params = [ - ("compilation_level", "SIMPLE_OPTIMIZATIONS"), - ("output_format", "json"), - ("output_info", "compiled_code"), - ("output_info", "warnings"), - ("output_info", "errors"), - ("output_info", "statistics"), - ("warning_level", "DEFAULT"), - ] - - # Add Blockly, Blockly.Blocks, and all fields to be compatible with the compiler. - params.append(("js_code", """ -goog.provide('Blockly'); -goog.provide('Blockly.Blocks'); -goog.provide('Blockly.Comment'); -goog.provide('Blockly.FieldCheckbox'); -goog.provide('Blockly.FieldColour'); -goog.provide('Blockly.FieldDropdown'); -goog.provide('Blockly.FieldImage'); -goog.provide('Blockly.FieldLabel'); -goog.provide('Blockly.FieldMultilineInput'); -goog.provide('Blockly.FieldNumber'); -goog.provide('Blockly.FieldTextInput'); -goog.provide('Blockly.FieldVariable'); -goog.provide('Blockly.Mutator'); -goog.provide('Blockly.Warning'); -""")) - # Read in all the source files. - filenames = glob.glob(os.path.join("blocks", "*.js")) - filenames.sort() # Deterministic build. - for filename in filenames: - f = codecs.open(filename, encoding="utf-8") - params.append(("js_code", "".join(f.readlines()).encode("utf-8"))) - f.close() - - # Remove Blockly, Blockly.Blocks and all fields to be compatible with Blockly. - remove = r"var Blockly=\{[^;]*\};\n?" - self.do_compile(params, target_filename, filenames, remove) - - def gen_generator(self, language): - target_filename = language + "_compressed.js" - # Define the parameters for the POST request. - params = [ - ("compilation_level", "SIMPLE_OPTIMIZATIONS"), - ("output_format", "json"), - ("output_info", "compiled_code"), - ("output_info", "warnings"), - ("output_info", "errors"), - ("output_info", "statistics"), - ("warning_level", "DEFAULT"), - ] - - # Read in all the source files. - # Add Blockly.Generator and Blockly.utils.string to be compatible - # with the compiler. - params.append(("js_code", """ -goog.provide('Blockly.Generator'); -goog.provide('Blockly.utils.global'); -goog.provide('Blockly.utils.string'); -""")) - filenames = glob.glob( - os.path.join("generators", language, "*.js")) - filenames.sort() # Deterministic build. - filenames.insert(0, os.path.join("generators", language + ".js")) - for filename in filenames: - f = codecs.open(filename, encoding="utf-8") - params.append(("js_code", "".join(f.readlines()).encode("utf-8"))) - f.close() - filenames.insert(0, "[goog.provide]") - - # Remove Blockly.Generator and Blockly.utils.string to be compatible - # with Blockly. - remove = r"var Blockly=\{[^;]*\};\s*Blockly.utils.global={};\s*Blockly.utils.string={};\n?" - self.do_compile(params, target_filename, filenames, remove) - - def do_compile(self, params, target_filename, filenames, remove): - # Send the request to Google. - headers = {"Content-type": "application/x-www-form-urlencoded"} - conn = httplib.HTTPSConnection("closure-compiler.appspot.com") - conn.request("POST", "/compile", urlencode(params), headers) - response = conn.getresponse() - - # Decode is necessary for Python 3.4 compatibility - json_str = response.read().decode("utf-8") - conn.close() - - # Parse the JSON response. - try: - json_data = json.loads(json_str) - except ValueError: - print("ERROR: Could not parse JSON for %s. Raw data:" % target_filename) - print(json_str) - return - - def file_lookup(name): - if not name.startswith("Input_"): - return "???" - n = int(name[6:]) - return filenames[n] - - if "serverErrors" in json_data: - errors = json_data["serverErrors"] - for error in errors: - print("SERVER ERROR: %s" % target_filename) - print(error["error"]) - elif "errors" in json_data: - errors = json_data["errors"] - for error in errors: - print("FATAL ERROR") - print(error["error"]) - if error["file"]: - print("%s at line %d:" % ( - file_lookup(error["file"]), error["lineno"])) - print(error["line"]) - print((" " * error["charno"]) + "^") - sys.exit(1) - else: - if "warnings" in json_data: - warnings = json_data["warnings"] - for warning in warnings: - print("WARNING") - print(warning["warning"]) - if warning["file"]: - print("%s at line %d:" % ( - file_lookup(warning["file"]), warning["lineno"])) - print(warning["line"]) - print((" " * warning["charno"]) + "^") - print() - - if not "compiledCode" in json_data: - print("FATAL ERROR: Compiler did not return compiledCode.") - sys.exit(1) - - code = HEADER + "\n" + json_data["compiledCode"] - # Remove Blockly definitions to be compatible with Blockly. - code = re.sub(remove, "", code) - code = self.trim_licence(code) - - stats = json_data["statistics"] - original_b = stats["originalSize"] - compressed_b = stats["compressedSize"] - if original_b > 0 and compressed_b > 0: - f = open(target_filename, "w") - f.write(code) - f.close() - - original_kb = int(original_b / 1024 + 0.5) - compressed_kb = int(compressed_b / 1024 + 0.5) - ratio = int(float(compressed_b) / float(original_b) * 100 + 0.5) - print("SUCCESS: " + target_filename) - print("Size changed from %d KB to %d KB (%d%%)." % ( - original_kb, compressed_kb, ratio)) - else: - print("UNKNOWN ERROR") - - def trim_licence(self, code): - """Strip out Google's and MIT's Apache licences. - - JS Compiler preserves dozens of Apache licences in the Blockly code. - Remove these if they belong to Google or MIT. - MIT's permission to do this is logged in Blockly issue 2412. - - Args: - code: Large blob of compiled source code. - - Returns: - Code with Google's and MIT's Apache licences trimmed. - """ - apache2 = re.compile("""/\\* - - (Copyright \\d+ (Google LLC|Massachusetts Institute of Technology)) -( All rights reserved. -)? SPDX-License-Identifier: Apache-2.0 -\\*/""") - return re.sub(apache2, "", code) - - -class Gen_langfiles(threading.Thread): - """Generate JavaScript file for each natural language supported. - - Runs in a separate thread. - """ - - def __init__(self): - threading.Thread.__init__(self) - - def run(self): - # The files msg/json/{en,qqq,synonyms}.json depend on msg/messages.js. - try: - subprocess.check_call([ - "python", - os.path.join("scripts", "i18n", "js_to_json.py"), - "--input_file", "msg/messages.js", - "--output_dir", "msg/json/", - "--quiet"]) - except (subprocess.CalledProcessError, OSError) as e: - # Documentation for subprocess.check_call says that CalledProcessError - # will be raised on failure, but I found that OSError is also possible. - print("Error running scripts/i18n/js_to_json.py: ", e) - sys.exit(1) - - # Checking whether it is necessary to rebuild the js files would be a lot of - # work since we would have to compare each .json file with each - # .js file. Rebuilding is easy and cheap, so just go ahead and do it. - try: - # Use create_messages.py to create .js files from .json files. - cmd = [ - "python", - os.path.join("scripts", "i18n", "create_messages.py"), - "--source_lang_file", os.path.join("msg", "json", "en.json"), - "--source_synonym_file", os.path.join("msg", "json", "synonyms.json"), - "--source_constants_file", os.path.join("msg", "json", "constants.json"), - "--key_file", os.path.join("msg", "json", "keys.json"), - "--output_dir", os.path.join("msg", "js"), - "--quiet"] - json_files = glob.glob(os.path.join("msg", "json", "*.json")) - json_files = [file for file in json_files if not - (file.endswith(("keys.json", "synonyms.json", "qqq.json", "constants.json")))] - cmd.extend(json_files) - subprocess.check_call(cmd) - except (subprocess.CalledProcessError, OSError) as e: - print("Error running scripts/i18n/create_messages.py: ", e) - sys.exit(1) - - # Output list of .js files created. - for f in json_files: - # This assumes the path to the current directory does not contain "json". - f = f.replace("json", "js") - if os.path.isfile(f): - print("SUCCESS: " + f) - else: - print("FAILED to create " + f) - -# Class to hold arguments if user passes in old argument style. -class Arguments: - def __init__(self): - self.core = False - self.generators = False - self.langfiles = False - -# Gets the command line arguments. -def get_args(): - parser = argparse.ArgumentParser(description="Decide which files to build.") - parser.add_argument('-core', action="store_true", default=False, help="Build core") - parser.add_argument('-generators', action="store_true", default=False, help="Build the generators") - parser.add_argument('-langfiles', action="store_true", default=False, help="Build all the language files") - - # New argument style: ./build.py -core - # Old argument style: ./build.py core - # Changed as of July 2019. - try: - args = parser.parse_args() - if (not args.core) and (not args.generators) and (not args.langfiles): - # No arguments, use these defaults: - args.core = True - args.generators = True - args.langfiles = True - except SystemExit: - # Fall back to old argument style. - args = Arguments() - args.core = 'core' in sys.argv - args.generators = 'generators' in sys.argv - args.langfiles = 'langfiles' in sys.argv - if 'accessible' in sys.argv: - print("The Blockly accessibility demo has moved to https://github.com/google/blockly-experimental") - return args - -if __name__ == "__main__": - args = get_args() - calcdeps = import_path(os.path.join("closure", "bin", "calcdeps.py")) - full_search_paths = calcdeps.ExpandDirectories(["core", "closure"]) - full_search_paths = sorted(full_search_paths) # Deterministic build. - - print("Deprecation Warning: (July 2020)\n This build script has been " + - "deprecated, please use 'npm run build' instead. \n The script will be " + - "removed from Blockly core in Q4 of 2020.\n") - - # Uncompressed and compressed are run in parallel threads. - # Uncompressed is limited by processor speed. - if (args.core): - Gen_uncompressed(full_search_paths, 'blockly_uncompressed.js').start() - - # Compressed is limited by network and server speed. - Gen_compressed(full_search_paths, args).start() - - # This is run locally in a separate thread - if (args.langfiles): - Gen_langfiles().start() diff --git a/core/blockly.js b/core/blockly.js index 2cef68caf..55758bae9 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -61,10 +61,10 @@ goog.requireType('Blockly.Workspace'); /** * Blockly core version. - * This constant is overridden by the build script (build.py) to the value of the version - * in package.json. This is done during the gen_core build step. - * For local builds, you can pass --define='Blockly.VERSION=X.Y.Z' to the compiler - * to override this constant. + * This constant is overridden by the build script (npm run build) to the value + * of the version in package.json. This is done during the gen_core build step. + * For local builds, you can pass --define='Blockly.VERSION=X.Y.Z' to the + * compiler to override this constant. * @define {string} */ Blockly.VERSION = 'uncompiled'; diff --git a/msg/messages.js b/msg/messages.js index 884c97245..a142f6fe9 100644 --- a/msg/messages.js +++ b/msg/messages.js @@ -8,8 +8,8 @@ * @fileoverview English strings. * @author fraser@google.com (Neil Fraser) * - * After modifying this file, either run "build.py" from the parent directory, - * or run (from this directory): + * After modifying this file, either run "npm run build:langfiles" from the + * parent directory, or run (from this directory): * ../scripts/i18n/js_to_json.py * to regenerate json/{en,qqq,synonyms}.json. * From 9ad50ea98a8b6bc37a39ad0bab8784c164853b85 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Sun, 27 Jun 2021 23:51:46 -0700 Subject: [PATCH 35/36] Fix escape key on all fields. (#4934) Currently the escape key fails to revert the value. This is the inherited root of all type-in fields, including number, angle, and note. Fixes #4910 --- core/field_textinput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/field_textinput.js b/core/field_textinput.js index bd97f5fcb..9b389c5a8 100644 --- a/core/field_textinput.js +++ b/core/field_textinput.js @@ -456,7 +456,7 @@ Blockly.FieldTextInput.prototype.onHtmlInputKeyDown_ = function(e) { Blockly.WidgetDiv.hide(); Blockly.DropDownDiv.hideWithoutAnimation(); } else if (e.keyCode == Blockly.utils.KeyCodes.ESC) { - this.htmlInput_.value = this.htmlInput_.defaultValue; + this.setValue(this.htmlInput_.untypedDefaultValue_); Blockly.WidgetDiv.hide(); Blockly.DropDownDiv.hideWithoutAnimation(); } else if (e.keyCode == Blockly.utils.KeyCodes.TAB) { From 5c48bfc18809f8407191d3ae48eb51b6e3ab81a8 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Mon, 28 Jun 2021 11:09:01 -0700 Subject: [PATCH 36/36] Tweak comment --- core/blockly.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/blockly.js b/core/blockly.js index 55758bae9..92716e4d1 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -62,7 +62,8 @@ goog.requireType('Blockly.Workspace'); /** * Blockly core version. * This constant is overridden by the build script (npm run build) to the value - * of the version in package.json. This is done during the gen_core build step. + * of the version in package.json. This is done by the Closure Compiler in the + * buildCompressed gulp task. * For local builds, you can pass --define='Blockly.VERSION=X.Y.Z' to the * compiler to override this constant. * @define {string}