I'm trying to create a tool where you can create HTML pages using Blockly blocks. I already have a page that shows my workspace and my self-created block. Now I want to write a script that gets the code from the workspace. Normally there is a workspaceToCode method in the Blockly library. Unfortunately I can't access any Blockly methods or really anything Blockly-related in my index.html.
I've looked up similar projects and can't seem to find any differences. I'm loading blockly_compressed.js, blocks_compressed.js and javascript_compressed.js. And because it shows me a workspace with "functioning" blocks I'm pretty sure that the paths are correct.
See below what I tried and thanks in advance for your help:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="styles.css">
<style>
...
</style>
<script src="node_modules/blockly/blockly_compressed.js"></script>
<script src="node_modules/blockly/blocks_compressed.js"></script>
<script src="node_modules/blockly/msg/en.js"></script>
<script src="node_modules/blockly/javascript_compressed.js"></script>
</head>
<body>
...
<script src="html_blocks.js"></script>
<script src="html_generator.js"></script>
<script src="main.js"></script>
<script>
function update(event) {
var code = HtmlGenerator.workspaceToCode(workspace);
document.getElementById('HTMLCodeDiv').innerText = code;
}
workspace.addChangeListener(update);
</script>
</body>
</html>
The error it is giving is "unresolved function or method" for the workspaceToCode method as well as the addChangeListener method.
Since you haven't shown all of your code, I can't provide a precise answer to explain exactly what's gone wrong for you here, but I can say that Blockly in a classical (non-module) script tag adds itself to the window as follows:
// ...
} else { // Browser
var factoryExports = factory();
root.Blockly = factoryExports;
}
// ...
where root is window (by way of this) and factory() is the entire Blockly code. All Blockly functions are namespaced inside of the window.Blockly object, so there is no such window.workspace variable that would be created unless one of your other scripts (not shown) created this and attached it to the window.
If you open your browser console, you can type Blockly. and see the list of available properties that were imported by the scripts. The other Blockly scripts simply attach more properties to the global Blockly object that was created by the first script tag. Blockly.Workspace and Blockly.workspaceToCode are some of these properties, and you can call Blockly.inject to create a workspace.
For example,
const blocklyWorkspace = Blockly.inject("blockly-container", {
toolbox: document.getElementById("toolbox")
});
document.querySelector("button")
.addEventListener("click", e => {
const code = Blockly.JavaScript
.workspaceToCode(blocklyWorkspace);
console.log(code);
});
#blockly-container {
height: 100vh;
}
xml {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/blockly/8.0.0/blockly.min.js" integrity="sha512-m19pjKFpHlhFqUAWB49IQt7ip1P7UDKyV0k0f7UGnN8pXSLFjtvsrRcDlwRw+ZhaNeqQTwHwE9+CJgPAWUyA9Q==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<button>Workspace to code</button>
<div id="blockly-container"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox">
<block type="text_print"></block>
<block type="text"></block>
</xml>
It strikes me as an antipattern to use node_modules in script tags like this, even though some of the Blockly examples do this. Usually, you'd use a bundler of some sort (webpack, parcel, vite, browserify, rollup, etc) to allow you to dynamically import the code using modules (example below). Or else keep your build without any local dependencies and use a CDN and take advantage of client caching (as shown above). Using node_modules directly seems like the worst of both worlds, especially without a minification build.
For example, you can use parcel to build your app for the web. A bundler makes it easy to use node_modules without specifying the paths. You can develop using modules rather than legacy UMD script tags, which help you organize the project into chunks and avoid polluting the window with shared data.
The example below is contrived for clarity, but hopefully you can extrapolate the approach (or something similar) to your project.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
#blockly-container {
height: 100vh;
}
xml {
display: none;
}
</style>
</head>
<body>
<div id="blockly-container"></div>
<xml xmlns="https://developers.google.com/blockly/xml" id="toolbox">
<block type="text_print"></block>
<block type="text"></block>
</xml>
<xml xmlns="https://developers.google.com/blockly/xml" id="start-blocks">
<block type="text_print" id="N4+B!H6xh[=wx]z^LqGk" x="38" y="38">
<value name="TEXT">
<shadow type="text" id="~uw6Vr9}hxZS-=a(Zjt{">
<field name="TEXT">hello world</field>
</shadow>
</value>
</block>
</xml>
<script src="src/index.js" type="module"></script>
</body>
</html>
src/index.js:
import Blockly from "blockly";
import generateCode from "./generate-code";
const blocklyWorkspace = Blockly.inject("blockly-container", {
toolbox: document.getElementById("toolbox")
});
Blockly.Xml.domToWorkspace(
document.getElementById("start-blocks"),
blocklyWorkspace
);
console.log(generateCode(blocklyWorkspace));
src/generate-code.js:
import Blockly from "blockly";
export default blocklyWorkspace =>
Blockly.JavaScript
.workspaceToCode(blocklyWorkspace);
package.json:
{
"scripts": {
"start": "node node_modules/parcel/lib/cli index.html"
},
"dependencies": {
"blockly": "^8.0.3"
},
"devDependencies": {
"parcel": "^2.6.2"
}
}
Building and running:
npm i
npm start
Now, navigate to (by default) http://localhost:1234 (or whatever parcel tells you on the console) and begin developing.
Hello,
I'm trying to create a simple PWA demo by following the steps of this article: "https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/get-started"
However when I reach the step to download and add the files: "pwabuilder-sw.js" and "pwabuilder-sw-register.js" to root and then add <script src="/pwabuilder-sw-register.js"></script> to the head of index.html I got error on Edge browser: "SCRIPT1086: SCRIPT1086: Module import or export statement unexpected here" I search around and I find that I have to add type="module" like this <script src="/pwabuilder-sw-register.js" type="module"></script> but now I'm getting another error: "0: Unable to get property 'define' of undefined or null reference" in
pwaupdate (175,5829)
My page code looks like:
Index.html
<html>
<head>
<title>Express</title>
<link rel="stylesheet" href="/stylesheets/style.css">
<link rel="manifest" href="/manifest.json">
<script src="/pwabuilder-sw-register.js" type="module"></script>
</head>
<body>
<h1>Express 2</h1>
<p>Welcome to Express</p>
</body>
</html>
pwabuilder-sw.js
// This is the service worker with the Cache-first network
const CACHE = "pwabuilder-precache";
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.0.0/workbox-sw.js');
self.addEventListener("message", (event) => {
if (event.data && event.data.type === "SKIP_WAITING") {
self.skipWaiting();
}
});
workbox.routing.registerRoute(
new RegExp('/*'),
new workbox.strategies.CacheFirst({
cacheName: CACHE
})
);
pwabuilder-sw-register.js
// This is the service worker with the Cache-first network
// Add this below content to your HTML page inside a <script type="module"></script> tag, or add the js file to your page at the very top to register service worker
import 'https://cdn.jsdelivr.net/npm/#pwabuilder/pwaupdate';
const el = document.createElement('pwa-update');
document.body.appendChild(el);
I searched a lot but I did not find any clue.
Please advise.
There are only 2 things you need to make this work:
Add pwabuilder-sw.js and pwabuilder-sw-register.js to your site root.
Add the following script tag to your <head>
<script type="module" src="pwabuilder-sw-register.js"></script>
Here's a quick sample that shows this working.
It looks like the MSDN article missed the "module" script type. My fault! I've updated the MSDN article to include this fix.
You normally don't need any more this script reference <script src="/pwabuilder-sw-register.js" type="module"></script>
The script will be loaded by the pwaupdate component. So simply add this code inside a block at the end of your HTML page:
import 'https://cdn.jsdelivr.net/npm/#pwabuilder/pwaupdate';
const el = document.createElement('pwa-update');
document.body.appendChild(el);
If it still doesn't work, please open an issue on our Github repo or ask to Justin who's in charge of this part on Twitter: https://twitter.com/Justinwillis96
Thanks!
David
I must be missing something simple, but can't seem to get the polyfill working for measuring the first input delay on my firebase project.
I have included the minified file as suggested here, and then in the body of my HTML I have run the code as suggested also.
So it looks like:
<head>
<title>My website</title>
<!--first-input-delay-->
!function(n,e){var t,o,i,c=[],f={passive:!0,capture:!0},r=new Date,a="pointerup",u="pointercancel";function p(n,c){t||(t=c,o=n,i=new Date,w(e),s())}function s(){o>=0&&o<i-r&&(c.forEach(function(n){n(o,t)}),c=[])}function l(t){if(t.cancelable){var o=(t.timeStamp>1e12?new Date:performance.now())-t.timeStamp;"pointerdown"==t.type?function(t,o){function i(){p(t,o),r()}function c(){r()}function r(){e(a,i,f),e(u,c,f)}n(a,i,f),n(u,c,f)}(o,t):p(o,t)}}function w(n){["click","mousedown","keydown","touchstart","pointerdown"].forEach(function(e){n(e,l,f)})}w(n),self.perfMetrics=self.perfMetrics||{},self.perfMetrics.onFirstInputDelay=function(n){c.push(n),s()}}(addEventListener,removeEventListener);
</head>
<body>
<!-- my react app -->
<div id="root"></div>
<script>
perfMetrics.onFirstInputDelay((delay, evt) => {
console.log("First Input Delay", delay)
console.log("Event details", evt)
})
</script>
</body>
When I include the console logs, the script runs as expected and console logs the data, but it never sends it to firebase. If I take out the console logs (perfMetrics.onFirstInputDelay()), the script fails with TypeError: n is not a function.
How should I be adding this to my app? Should I be sending the trace to Firebase somehow? I use performance tracing at the moment, but unsure how to send this specific event as it doesn't have a start and stop time.
Is the solution something like the below?
const performance = firebase.performance()
performance.trace(onFirstInputDelay)
So I was doing something silly. I only needed to include the polyfill and let the Firebase SDK handle the onFirstInputDelay event.
So just having this works.
<head>
<title>My website</title>
<!--first-input-delay-->
!function(n,e){var t,o,i,c=[],f={passive:!0,capture:!0},r=new Date,a="pointerup",u="pointercancel";function p(n,c){t||(t=c,o=n,i=new Date,w(e),s())}function s(){o>=0&&o<i-r&&(c.forEach(function(n){n(o,t)}),c=[])}function l(t){if(t.cancelable){var o=(t.timeStamp>1e12?new Date:performance.now())-t.timeStamp;"pointerdown"==t.type?function(t,o){function i(){p(t,o),r()}function c(){r()}function r(){e(a,i,f),e(u,c,f)}n(a,i,f),n(u,c,f)}(o,t):p(o,t)}}function w(n){["click","mousedown","keydown","touchstart","pointerdown"].forEach(function(e){n(e,l,f)})}w(n),self.perfMetrics=self.perfMetrics||{},self.perfMetrics.onFirstInputDelay=function(n){c.push(n),s()}}(addEventListener,removeEventListener);
</head>
<body>
<!-- my react app -->
<div id="root"></div>
</body>
I'm using angular version 1 with jasmine for my unit tests.
The test I want to do is:
When I load the index.html page in ie7 for example I load in a html banner saying download latest browser.
I'm currently loading a html template using JQuery on the index page.
Is it possible to test this since its outside the angular app.
This is my current code on my index.html page:
<!doctype html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<base href="/app/" />
<!-- Is Angular supported -->
<script>
if(window.angular === undefined)
$(function(){$("#angularNotSupportedModal").load("/app/noAngularModal.html");});
</script>
</head>
<body ng-app="app" ng-cloak>
<div id="angularNotSupportedModal"></div>
<div ui-view></div>
<!-- Application -->
<script src="/scripts/app.js"></script>
<!-- Config -->
<script src="/scripts/config.js"></script>
</body>
</html>
Any suggestions would be great.
Thanks
The task narrows down to good old jQuery testing, which is tedious but possible. It depends on the code if jQuery can be just spied or should be totally stubbed and mocked.
The tested script should be isolated to separate function to be tested properly. It may be something like this:
it('should call through $ chain', (done) => {
var angular = window.angular;
window.angular = undefined;
spyOn(jQuery.prototype, 'ready').and.callThrough();
spyOn(jQuery.prototype, 'load').and.callThrough();
// make spy not break the chain
var init = jQuery.prototype.init.bind(jQuery.prototype);
spyOn(jQuery.prototype, 'init').and.callFake(init);
window.runAngularNotSupportedFunction();
expect(jQuery.prototype.ready).toHaveBeenCalledWith(jasmine.any(Function));
expect(jQuery.prototype.init).toHaveBeenCalledWith('#angularNotSupportedModal', undefined);
expect(jQuery.prototype.load).toHaveBeenCalledWith('/app/noAngularModal.html');
window.angular = angular;
jQuery.ready.promise().done(done)
})
I am a newbie to require js and faced this strange problem while creating our first :
Following is the home page :index.html
<html>
<head lang="en">
<meta charset="UTF-8">
<title>My first JS app using require</title>
</head>
<body>
<strong> This is my first require js app</strong>
<span id="output"></span>
</body>
<script data-main="js/main" src="js/lib/require.js"></script>
</html>
main.js is as follows :
require(['lib/jquery','app/message'],function($,message){
$('#output').html(message);
});
message.js is as follows :
define(function(){
return "Message from message.js";
});
When i run index.html on browser, $ in main.js comes as undefined. It does not produce any other error on console. Also all files are loaded successfully(confirmed from networks tab in browser).
If i change the main.js to be as follows :
require(['jquery','app/message'],function($,message){
$('#output').html(message);
});
And accordingly place jquery.js in appropriate directory, everything works fine.
I am not able to figure out the reason here. Can anybody please help here. Thanks in advance.