hostilefork / replpad-js

Interactive Web Console for Rebol language (Ren-C branch)
GNU Lesser General Public License v3.0
13 stars 9 forks source link

Demo: UI Builder #35

Closed BrianOtto closed 5 years ago

BrianOtto commented 5 years ago

I originally started down the path of creating a UI framework like React. But as I used the REPL more and more, I started thinking about how it could be leveraged to do other things, and I went off in a different direction ...

I ended up creating a tool instead. A tool that allows you to create a UI in real-time, by entering commands into the REPL, and which you can then export as a standalone app. I think this last part is pretty exciting, and I'll go into it more at the end.

To run the demo you will need to use Firefox or Chrome and have the standard browser flags on for WASM and PTHREADS. It does not work with Emterpreter yet, and I'm not sure I want to spend the time figuring that out either. It tested it once, and the performance was pretty bad.

If you can, I highly suggest you use Firefox for this demo. The tool will work in Chrome, but if you use it, there is a workaround you will need to do at the end, when you run the exported app.

I also recommend you copy-paste the commands I will be providing. The tool has only been tested to work for this demo. There is probably a ton of bugs, I still haven't found, that may cause the app to freeze up if you type out something wrong.

Start by running the REPL located at http://rebol.brianotto.com/ui-builder/

Load up the UI Builder by entering this ...

run 'ui-builder

To give you a little background, I started this project before loading apps from a remote repository was fully working. So this was just my way of having a standard command to run an app. The run command assumes all apps are stored under the "app" sub-directory and are named after the literal word you used. It also assumes all apps have an index.reb that is used to launch them. So what that command above does, is it fetches the source code at %app/ui-builder/index.reb and runs a "do" on it.

Another modification I made was to allow an app to take over the REPL's command processing by registering it's own DSL. I thought it would be pretty powerful if an app had its own language that you could use with it. I didn't realize this feature already existed :)

How I implemented it was by declaring a global variable in the gui.js JavaScript.

var dsl_parser = null

When an app started up it would assign a function to this variable ...

window.dsl_parser = ui-parse

... and if a function existed, the REPL would wrap all commands with it.

if (dsl_parser !== null) {
    text = dsl_parser + " {" + text + "}"
}

This is why, when you start the ui-builder, you are able to enter commands that would normally give you an error in the language. My app parses the commands and runs the proper Rebol code for them.

So let's build a simple video player ...

First we want to add a row to place our video in.

add row

This will create a <div> that acts as our first row. Since rows are normally not visible in our layout, the app adds a dotted border around it so that you can see what you've added to the canvas. The app also gives it an ID, so that you don't need to think about names while your building the UI. This can always be changed later or it can be specified by providing a parameter to the row, e.g. add row myId

Now let's add a second row for our video's controls.

add row

Oops! You can't add a row inside of another row until you've added a column, and so an error is displayed. Also, we want the row to be below this one, not inside it. Any time you add an element to the page it will automatically get selected, and so what we need to do is select the top level canvas first.

get canvas add row

Now before we can add any content to it, we will need to add a column. However, we want to think about where the controls should be displayed. For our purposes, let's make the controls centered on the screen. To do this, we need to add 3 columns and put the controls in the center column.

Remember how elements automatically gets selected when they are added to the page? We want to prevent this from happening this time, and you can do this by providing the /more "refinement". Any time you provide this, you are telling the app that you need to add more elements to the same parent. This allows you to quickly add a group of elements to a parent.

add col/more add col/more add col

We want to add the buttons in the middle column and so we select it by id.

get col2

Let's add a button to Stop the video now.

add button

Let's change the text.

add text Stop

This is an add command, not a set command, because we are adding an actual HTML element to the page (i.e. <span>) and not just setting an attribute or style.

Let's add an icon. The names come from the Font Awesome class names.

add icon stop

Let's add a Play button now.

get col2 add button add text Play add icon play

Those buttons are too close together so let's move the Play button over a bit. Also, as you might notice, the button is still selected, even though we added a text and icon element to it. This is because those elements can't have any children and so the parent stays selected.

set margin-left 10px

Let's center those buttons too.

get col2 set text-align center

Let's add the video.

get row1 add col add video http://www.youtube.com/embed/cSp1dM2Vj48

Doh, wait, our controls are not hooked up yet! I really wanted to use this video for the demo, because then you would be forced to watch it, with no way of stopping it, for a while :D ... but unfortunately YouTube does not allow you to play certain videos when a HTML page is launched from file:/// (which we will touch on later), and so I had to choose a movie Trailer instead. They appear to have less restrictions in place. I still need to look into why.

Anyway, let's hook up this player to some Rebol code!

get button1 set onclick ui-video-stop get button2 set onclick ui-video-play

Try it out. You can now Stop and Play the video. The ui-video-stop and ui-video-play values we entered are the names of functions I wrote in Rebol. These functions are pretty simple and just run some JavaScript code to control the video, but they don't have to be this way! You could use them to process some business logic in Rebol and then update the UI with your results.

Also, I have hard-coded these functions as part of the app code, for the purposes of this demo, but they don't have to be this way either ...

I plan on eventually adding a button that will let you open up a mini Rebol console, very similar to how replpad starts. It will let you play around with code until you've built what you need and then you can save it to your browser's local storage. This can then pushed through the console and be available as functions for your app!

Also, another alternative is we could provide a button that opens a list of 3rd party APIs. Do you need a full-featured video API for your app? Click here to download it into your local storage!

This is not only a rapid prototyping tool, but a way to create full featured apps. Well, at least full featured within the security context of a browser.

Okay, so now you have a working video player. Let's hide those layout borders, and it should look something like this.

hide layout

ui-builder-screen

Additionally, the app has commands for a few other things I didn't cover. You can move elements around to different parents, hide/show the ids of all elements on the page (in case you've forgotten what they're named), and eventually the Styles and Classes button will open a sidebar that will let you manually update all the styles at once, or add custom classes.

Hopefully you've made it this far, because now things get interesting ...

The final command I will cover is export. It allows you to export your design into a HTML file that embeds the Rebol interpreter with no outside dependencies. None whatsoever, there is not even any external JavaScript files required. You can distribute your Rebol-powered app in a single HTML file!

If your default browser is Firefox then try it out. Run the export command and save the file to your computer. Then double click it and the app will open in your browser and display the same as before, and the controls, which use Rebol code, will continue to work.

If your default browser is Chrome then you will need to give it access to local files by passing in this flag during startup --allow-file-access-from-files. On Windows, you do it like this.

start "" chrome --allow-file-access-from-files

So, the Chrome thing sucks. I wish the default access allowed this. However, there may be a way around this, but let me explain how I got this to work in the first place ...

At a high level, what I'm doing is base64 encoding all the JavaScript required to get the REPL running and writing this to JavaScript variables, in the HTML file, on export. When the exported HTML file runs, it saves these "files" to an IndexedDB storage location, which is accessible to web workers. I then modified the web worker slightly to load this JavaScript from storage, instead of directing importing the scripts... and volia, an embedded Rebol interpreter running on JavaScript blobs.

The problem with Chrome is that is sees the URI to these blobs as blob:file:///MYDATA, whereas Firefox sees them as blob:nul/MYDATA. So these aren't local files according to Firefox, but they are to Chrome and so it locks down access. I think there may be a way around this. This local access only becomes an issue when I push these blobs into a dynamically created script tag. I might be able to write out the JavaScript directly, instead of doing this, and get around this problem. But we'll see, it needs some research ...

Well, that's it for now. I was going to post my thoughts on use cases, next steps and some other experiments we could try, but this post got a little long and I have a busy day today. So I will follow up with that tomorrow.

Cheers!

hostilefork commented 5 years ago

That's AWESOME!!! Crazy cool. People are going to freak out. :)

( Note: Nick Antonaccio of lengthy Rebol tutorial fame has historically been a fierce advocate of seeing Rebol in the browser. I think he'd be a huge fan of this, perhaps even interested in funding the work: http://rebolforum.com/index.cgi?f=printtopic&permalink=Nick19-Feb-2018/15:31:20-8:00&archiveflag=new )

While single-page forms apps may not be very popular in the era of "responsive" designs and infinite scroll, it makes a good and understandable demo. We'll have to do this tutorial as a screencast, and give a bit of insight into how it's implemented. Plus we definitely need to get an Ace Editor or something like it in there to let people do text editing on the functions that get called.

To give you a little background, I started this project before loading apps from a remote repository was fully working. So this was just my way of having a standard command to run an app.

Let me know when/if you want me to go over the code and do any tweaks or updates to sync it up. There's a lot of changes to come, we're far from stable. reb.Run() is going to become reb.Value() very soon (for instance).

There's a lot of cool new things in Ren-C, hopefully you've found the likes of -- "hello!" x (y + 1) for dumping variables, or elide for running things but making them invisible:

 >> 1 + 2 elide print "Like this!"
 == 3

So I can also get in with suggestions on how the new language features might be used...

The run command assumes all apps are stored under the "app" sub-directory and are named after the literal word you used. It also assumes all apps have an index.reb that is used to launch them. So what that command above does, is it fetches the source code at %app/ui-builder/index.reb and runs a "do" on it

We can make it the case that if you DO a directory, that it assumes there's a file in it called index.reb. It might save on typing, though calling it "index" may be a bit of a misnomer. I'd prefer to call it main.reb since it's code...that's familiar from C and other languages for when it's code.

The problem with Chrome is that is sees the URI to these blobs as blob:file:///MYDATA, whereas Firefox sees them as blob:nul/MYDATA.

StackOverflow is always a good place to ask, and I have more than enough points to burn on bounties. :-) Got one out right now on that promise question

I plan on eventually adding a button that will let you open up a mini Rebol console, very similar to how replpad starts. It will let you play around with code until you've built what you need and then you can save it to your browser's local storage. This can then pushed through the console and be available as functions for your app!

What I want to do is to make it so the console itself is a component you can pull in--on demand, so even if your app is not based on having the user type in a console, you can get it for poking around and debugging. So do <console>. That's going to take some figuring about how it brings its own CSS and JS in to the context of your page.

I really wanted to use this video for the demo, because then you would be forced to watch it, with no way of stopping it, for a while :D

Don't give us up! This is great! Let me know what you need most from the core...I'm going to try and attack the error design, again this week. :-/ It's hard...and there's a lot of big picture stuff always needing to get solved.

Respectech commented 5 years ago

Amazing!

I am in the process of evaluating web language technologies so we can start a fourth complete rewrite of our back-office service and inventory business software called Worklog. V1.0 was written in R2 CGI in 2003, v2.0 was written in R2/SDK in 2006, v3.0 was written in R3/View in 2012. A requirement of v4.0 is that it runs completely inside a browser, and I was hoping v4.0 could be written in another Rebol-family language like Ren/C.

Our project requires access to MySQL running on the webserver, so that will be a requirement.

Here are my impressions running Brian's demo on Win10 64-bit, and testing it on Firefox 64-bit v62 and v66.

The beginning part of the tutorial works fine, but if I press "Backspace", it activates Firefox's "Back" feature. Once this happens, it is possible to lose all progress even if going "Forward" again, although sometimes the progress is saved.

I can't get the "Stop" and "Play" buttons to affect the video at all, even after entering:

get button1
set onclick ui-video-stop
get button2
set onclick ui-video-play

If I type hide-layout, nothing appears to happen (the divs still have the red dashed borders) and I have no further control at the command prompt.

If I type export, nothing seems to happen except losing control of the command prompt.

Even with these roadblocks, I am extremely impressed! I'd be willing to help fund the development of this tool if it could be a viable alternative for development of our software in the near term. Ren-Garden

Respectech commented 5 years ago

Just FYI: I tried the demo again thinking that maybe after I assigned the functions to the buttons, I might need to do a get canvas again, but that did the same thing as hide-layout and export, as far as not affecting anything other than losing control of the command prompt.

BrianOtto commented 5 years ago

@hostilefork and @Respectech, thank you for the awesome feedback! I have a pretty busy day today, so I can't respond in-depth right now, but I will follow up tomorrow.

@Respectech thank you, I will look into that backspace issue you mentioned. I hadn't run into that. As for the console being non-responsive, I have a couple requests / questions ...

1) Are you running the demo at the site I linked to, or something you've setup locally? A local setup may not work properly right now.

That site is running on an older version of libr3, that I also customized with a larger total memory. I uploaded these changes to site, and they may not have been committed to the branch. So the app could be freezing up because you ran out of memory. The app has also not been sync up with master in a while and there may be some incompatibilities there. I do plan on syncing it soon, but for now, the site is the only place I know it will work. If it is breaking on the site, then please read further ...

2) Do you mind doing the demo over again, but having your browser console open (CTRL-SHIFT-I) this time? And then screenshot any errors you see in the console. That should help in determining the problem fairly quickly. I have run the app extensively, in the same version of Firefox as you, and did not run into those issues. So not sure what's up there, but the console will definitely help narrow that down. Thank you!

Respectech commented 5 years ago

In my effort above, I was attempting it from your link, not from a local copy.

I tried it again with the console open. First, there were two warnings when creating the video element, as you can see in the first attached image.

After assigning the button onclick actions, I attempted to click the Stop button, and received the following errors in the console:

uncaught exception: abort("Assertion failed: The call to RL_rebText is running asynchronously. If this was intended, add the async option to the ccall/cwrap call.") at jsStackTrace@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:525:12
stackTrace@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:540:11
abort@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:8847:43
assert@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:218:3
ccall@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:267:3
cwrap/<@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:285:10
onclick@http://rebol.brianotto.com/ui-builder/:1:15

This error happened during an emterpreter-async operation. Was there non-emterpreted code on the stack during save (which is unallowed)? If so, you may want to adjust EMTERPRETIFY_BLACKLIST, EMTERPRETIFY_WHITELIST. For reference, this is what the stack looked like when we tried to save it: 1,handle@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:6270:33
_emscripten_sleep_with_yield@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:6294:2
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x2d7a
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[535]:0xb8a6
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[489]:0xae92
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[552]:0xbbcf
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[503]:0xb10f
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[489]:0xae92
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[552]:0xbbcf
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[552]:0xbbcf
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[287]:0x8940
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[489]:0xae92
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[552]:0xbbcf
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[552]:0xbbcf
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[506]:0xb1a8
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[137]:0x6fef
Module.dynCall_ii@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:8419:9
invoke_ii@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:6607:10
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x2872
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[478]:0xac99
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[489]:0xae92
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[552]:0xbbcf
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x22fb
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[504]:0xb13b
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[137]:0x6fef
Module.dynCall_ii@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:8419:9
invoke_ii@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:6607:10
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x2872
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js line 878 > WebAssembly.instantiate:wasm-function[69]:0x20c1
Module.emterpret@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:8365:9
resume@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:6252:6
safeSetTimeout/<@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:5952:5

Let me know what you'd like me to do when testing again.

ui-builder-err1

hostilefork commented 5 years ago

@Respectech This means your WASM threading or SharedArrayBuffer aren't enabled in the browser config. Hence it's running in a bytecode interpreter and having to do some trickery with that. It limits what you can do in a JS-AWAITER, I don't know if @BrianOtto has been testing that configuration.

Good news is that if the problem is just rebText() inside a JS-AWAITER, we can actually allow that via the EMTERPRETER_BLACKLIST. Any API that doesn't do evaluation should work. I'll patch that.

We should get this sync'd up so it runs against the hosted lib. Which BTW, @BrianOtto, it is now completely hosted...no need even for a worker.js file in your client! Workaround currently submitted as feature concept to emscripten

Respectech commented 5 years ago

I'm not sure how to enable WASM theading or SharedArrayBuffer in FF. Am I reading your message correctly that this is something you're planning on not requiring by some magic in a near-term future release?

hostilefork commented 5 years ago

I think all you need to do is turn on shared memory.

http://hostilefork.com/media/shared/replpad-js/shared-memory-firefox.png

We'll be adding something in the startup that if it's not enabled, it will tell you that you are running a lot slower than you need to be... and tell you what to do for various browsers to avoid the emterpreter.

The ui-builder is currently not running the hosted main version, so changes I make won't be picked up yet. But I do plan on altering it so you can write things like:

foo: js-awaiter [...] {
    let x = await fetch(...)
    return reb.Text(...)
}

At the moment you have to do this one step removed:

foo: js-awaiter [...] {
    let x = await fetch(...)
    return function() {
         return reb.Text(...)
    }
}

So improving that a little where possible is good. But things that do evaluation will still need an indirection in the emterpreter (and threading build too for the reasonable future). I plan to do that via reb.Promise(). Technical details here:

https://stackoverflow.com/q/55186667/211160

BrianOtto commented 5 years ago

@Respectech

I'm not sure how to enable WASM theading or SharedArrayBuffer in FF. Am I reading your message correctly that this is something you're planning on not requiring by some magic in a near-term future release?

The demo only works when WASM threading and Shared memory is enabled. In Firefox, you will need to type about:config in the URL bar, search for "shared" and then enable the setting highlighted in the screenshot that @hostilefork provided (i.e. set the javascript.options.shared_memory value to true). Unfortunately, this is the only way to get those settings enabled. There is no magic that can turn those settings on programmatically.

Having said that, there might be a command line option to enable those and so you might be able to write a script that could launch a browser with those flags enabled. But I am just speculating, I haven't actually looked into this.

In theory, the demo could be made to run using Emterpreter, which does not require enabling those flags, but it would be really slow. I tried it once, and you're going to be waiting a second or two after every command is entered, and so the user experience is not very good. But if there is interest in this I could look into getting it working.

hostilefork commented 5 years ago

I tried it once, and you're going to be waiting a second or two after every command is entered, and so the user experience is not very good. But if there is interest in this I could look into getting it working.

We are now defaulting to building the emterpreter in WASM vs asm.js, so that improves things. And Giulio wants to do some other tuning. I think we can improve it, but it's just not a super high priority to do so.

Respectech commented 5 years ago

Turning on the shared memory did the trick! Thanks for the hand-holding...

One note is that after exporting the HTML page and reopening it from the saved app.htm file, the red-dashed border was still visible on the Play button.

Ren-Garden

Respectech commented 5 years ago

So if I wanted to look at the code of ui-builder, where would I find it?

Respectech commented 5 years ago

Another note - After creating a row with a col in it, trying to add text only seems to allow one-word text values:

add text Tracker

But the following do not work:

add text Time Tracker
add text 'Time Tracker'
add text "Time Tracker"
add text {Time Tracker}
BrianOtto commented 5 years ago

Turning on the shared memory did the trick! Thanks for the hand-holding...

Awesome, glad it's working!

One note is that after exporting the HTML page and reopening it from the saved app.htm file, the red-dashed border was still visible on the Play button.

Another note - After creating a row with a col in it, trying to add text only seems to allow one-word text values:

Yup, those would be bugs. I'm surprised add text "Time Tracker" didn't work for you. I thought I got the code to accept strings that have double quotes around them. Well, anyway, I will take a look and fix. Thanks for the bug reports!

So if I wanted to look at the code of ui-builder, where would I find it?

You can view the branch here: https://github.com/hostilefork/replpad-js/tree/ui-builder

Specifically, look at the files in app/ui-builder

Once I get things sync'd up with master again I will most likely be moving this stuff into it's own repository and then you can open issues for it there. I'll update this ticket when that happens.

BrianOtto commented 5 years ago

We are now defaulting to building the emterpreter in WASM vs asm.js, so that improves things. And Giulio wants to do some other tuning. I think we can improve it, but it's just not a super high priority to do so.

Oh, I didn't know that. Very nice! Maybe it would be worth the effort to try it again. I'll do more tests.

BrianOtto commented 5 years ago

Here are my thoughts on next steps ...

Sync with Master and updating the build process

There has been a ton of updates in Ren-C and Replpad-JS recently, and I need to sync up with all these changes so that the app stays compatible with recent development. This is my top priority.

Once I do this, I will move the app to a new repository and treat it as a seperate project, using ren/repl as libraries that power it.

I also need to look into incorporating the built-in console features, like skinning and the dialect hook, instead of rolling my own.

Finally I will need to work with @hostilefork and @gchiu on updating the build process to accomodate the needs of the app. Off the top of my head, I would like to get ALLOW_MEMORY_GROWTH working and add in a setting that allows me to build the worker JS to read from IndexedDB tables.

Lower on the priority list, I would like to do further testing with the app in Emterpreter and see if performance has improved enough to get that fully working.

UI Builder Updates

I need to add support for more HTML elements, fix the bugs that are starting to appear and start working on things like the mini REBOL console, incorporating an editor and finishing the style sidebar. As well as looking into that local blob issue in Chrome.

Also, if you look at the code, you will see the UI elements are tied to UIkit right now. I used this CSS framework only because it is my favorite to work with. However, I could see people wanting to use different ones. It would be a bit of work, but I believe I can abstract the code out enough so you could plugin other frameworks. It might be nice to support maybe 3 official ones, like UIkit, Bootstrap and one other, with a guide on how to integrate others.

Crazy Stuff

I have done a bit of work with speech recognition in the past, and I think something like that could be integrated fairly easily here. Imagine building the UI by speaking to your computer! Ha, I'm not sure how practical that would be, but it would be a cool demo :D

A more practical usage would be to use the concepts in this app to build another that works with a 2D / vector drawing library like Two.js. I could see this being used as an educational tool for kids where they could explore shapes or even just have fun building something using their voice. My kids love talking to Siri, and I think it would blow their minds if they could tell the computer to build simple cartoons.

hostilefork commented 5 years ago

A more practical usage would be to use the concepts in this app to build another that works with a vector drawing library like Two.js.

Looks neat!! I told @gchiu we should be aiming for something more original than the old-school turtle graphics "pen down, pen up" stuff, so if there are any "fresh" ideas to draw from, that would be good.

Or even just good ideas that are newer or less universally known? Red took one of Nicky Case's demos, on voting I like a lot of what Bret Victor does, and it would be neat to make some things along those lines.

Lower on the priority list, I would like to do further testing with the app in Emterpreter and see if performance has improved enough to get that fully working.

You shouldn't have to change your code. Once I update the blacklist to have things like rebText(), I bet it will work, and if it doesn't...that's my problem. Let's just wait until you're running against master; I'll look if there are issues.

It might be nice to support maybe 3 official ones, like UIkit, Bootstrap and one other, with a guide on how to integrate others.

My thought is it's probably enough to keep pluggability in the back of your mind...but in general to shift to more Rebol and less JavaScript. If we can get @rgchris on board then we should be doing things in StyleTalk

I know it's harder than it should be to Rebolify things right now since inside a JS-AWAITER you can't evaluate except by returning code that evaluates later :-( I've got ideas that might work in the pthreads build, and the UI builder may be a project that we endorse as only running on that build...just maybe the tutorials and smaller demos allow people to get their interest piqued enough to flip the setting.

But I am trying to wait on doing any large scale restructuring until I understand errors and cancellation, which is all beastly. And there's a lot of core stuff to tend!

BrianOtto commented 5 years ago

@Respectech

I am in the process of evaluating web language technologies so we can start a fourth complete rewrite of our back-office service and inventory business software called Worklog. V1.0 was written in R2 CGI in 2003, v2.0 was written in R2/SDK in 2006, v3.0 was written in R3/View in 2012. A requirement of v4.0 is that it runs completely inside a browser, and I was hoping v4.0 could be written in another Rebol-family language like Ren/C.

Our project requires access to MySQL running on the webserver, so that will be a requirement.

I would be interested in hearing more about your requirements for Worklog v4.0. For example ...

You mentioned needing MySQL, and so I'm not sure if UI Builder would really work for that. It's more of a way to do UI prototyping or distribute apps that are okay running client-side code.

You wouldn't want to store database credentials on the client side, and so I think what you're looking for is more of a web framework, like Django or Rebol on Rails :) ... or maybe even something slimmer like a web service framework.

I have been doing that kind of stuff in my day job, for a long time, and so you have piqued my interest. It would be pretty awesome to build up a Rebol / Ren-C web framework. I did initially start down that path, but ended where you see the demo now. I think there is a place for both things though, and it would be nice to have a real world use case to develop against. Especially if you're willing to fund some of it.

Feel free to post your thoughts here or email me at the address listed on my GitHub account.

Respectech commented 5 years ago

Presently, our system works entirely server-side. We can use a hybrid approach where some stuff is done in the browser and the other stuff (like MySQL queries) are done server-side.

hostilefork commented 5 years ago

How near term? ASAP. We'd like to get started on prototyping it in the next month or two.

I veto anyone who's in a rush depending on a language/library for which I am the only maintainer!

That doesn't rule out coming up with some interesting convergent ideas. If @BrianOtto likes this UIKit...and has a UI Builder concept vision, perhaps there's a way to map out an app structure that could run backed by conventional JS code but would be tailored in such a way it would be easy to flip the switch and use Rebol.

But I don't think any time pressure is appropriate at this stage on the Rebol side. And I'd really prefer to keep it light--games, tutorials--and let big business and enterprise applications come later. Though experimentation of all kinds helps to know what kinds of things it might be good for.

BrianOtto commented 5 years ago

Yea, things aren't far enough along for that kind of time frame.

I wouldn't mind exploring a web framework, and it probably could be built in a way where we flip the switch from JS to Rebol, like @hostilefork suggests, but you're not going to see anything significant in a month or two. Something like that takes time to architect correctly.

If this is an open source project, I'd be interested in collaborating.

gchiu commented 5 years ago

Is there a chance to use something like MongoDb from Javascript instead of a traditional RDBMS?

On Wed, 27 Mar 2019 at 13:34, Brian Otto notifications@github.com wrote:

Yea, things aren't far enough along for that kind of time frame.

I wouldn't mind exploring a web framework, and it probably could be built in a way where we flip the switch from JS to Rebol, like @hostilefork https://github.com/hostilefork suggests, but you're not going to see anything significant in a month or two. Something like that takes time to architect correctly.

If this is an open source project, I'd be interested in collaborating.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/hostilefork/replpad-js/issues/35#issuecomment-476911591, or mute the thread https://github.com/notifications/unsubscribe-auth/AAMeQtoqXucZF-D9bzxW2r4kgIeVm4I9ks5varysgaJpZM4cHfEV .

-- Graham Chiu

BrianOtto commented 5 years ago

Is there a chance to use something like MongoDb from Javascript instead of a traditional RDBMS?

Using MongoDB is really dependent on the type of application you are building. It is a very different kind of DB where there is no schema. This is great for unstructured / denormalized data, or sites requiring high scalability, but not so good when you need to do joins or transactions. A web framework usually provides a database layer that abstracts away the underlying DB specifics and so in theory you could support both. You just would have to write the underlying code to support it.

Respectech commented 5 years ago

I understand that development on the Ren/C side of things can take a lot of effort. I just REALLY wish we could start development using it.

As far as the UI-Builder portion of the project, we could probably lend a hand at getting the html elements and other general support added.

gchiu commented 5 years ago

so I mentioned MongoDB as an example of a web based DB since we have no idea of what Bo's app does. But if there is a web api for a nosql db, then I imagine there may well be some to sql rdbms. Amazon has a number of DBs which one could use but without knowing the app requirements ...

On Thu, 28 Mar 2019 at 09:13, Respectech notifications@github.com wrote:

I understand that development on the Ren/C side of things can take a lot of effort. I just REALLY wish we could start development using it. As far as the UI-Builder portion of the project, we could probably lend a hand at getting the html elements and other general support added.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/hostilefork/replpad-js/issues/35#issuecomment-477329380, or mute the thread https://github.com/notifications/unsubscribe-auth/AAMeQq6bi7UhebcuH8I4vKCeJpLSgaXCks5va9DXgaJpZM4cHfEV .

-- Graham Chiu

Respectech commented 5 years ago

I'm not sure if this will tell you much, but this is Worklog v2.431 which is written totally in Rebol2/SDK. Worklog v3.x is written in Rebol3, but is not complete. We're hoping to rewrite v4.x so it runs completely within the browser.

worklog-v2

Respectech commented 5 years ago

Worklog v1 through v3 have been running on the same MySQL database since 2003 (upgraded MySQL along the way), which has been super reliable. Not too interested in moving to a different DB without knowing how reliable it will be and how supported it will be over the long run. But I'm totally open to running a hybrid client-side browser interface with a server backend that handles DB credentials and queries over SSL.

As you can see here, we have over 11,000 service agreements in the system, nearly 211,000 worklog entries, and many more tables that you cannot see with many more records than that in them.

hostilefork commented 5 years ago

uncaught exception: abort("Assertion failed: The call to RL_rebText is running asynchronously. If this was intended, add the async option to the ccall/cwrap call.") at jsStackTrace@http://rebol.brianotto.com/ui-builder/0.16.1/libr3.js:525:12

@BrianOtto I did some generation of a EMTERPRETER_BLACKLIST for entry points that aren't variadic functions, and a little tweak associated with that. I think JSON-COLLECT is a pretty neat function :-)

Anyway I hope that takes care of at least that issue. Also, you can now specify ?local in the URL and it will get the library from your local build.

Sorry I haven't done more on the error side of things, but it's little by little progress

BrianOtto commented 5 years ago

@hostilefork Nice! Great to see Emscripten and Emterpreter supporting the same logic. No need for special handling anymore.

Some news on UI Builder ...

I have re-written the code to be a standalone app now, and the official repository is here.

https://github.com/BrianOtto/ui-builder

There is a demo available at the site. Please report any bugs or feature requests there going forward.

I have also fixed the two bugs found here, where element borders were getting exported and text with spaces couldn't be added. It is using the latest build of Ren-C for the libr3 libraries too.

My next priority is getting the app to be able to import a previously exported HTML file. This will allow me to create example templates that people can use as a starting point and give you the ability to continue working where you left off. After that, it is back to the priorities I mention in previous comments.

hostilefork commented 5 years ago

It is using the latest build of Ren-C for the libr3 libraries

Cool! I know it will be a near-term pain point to be pulling the master due to changes, but as long as I can easily run my own installation, I can consider it part of my tests and be able to send PRs for it...

Great to see Emscripten and Emterpreter supporting the same logic. No need for special handling anymore.

Right now I get a dialog box saying there's no WASM/Pthreads and there's a "reb is undefined" error. So you probably want to turn that into a "hey you're running sub-optimally" warning box, and direct people to the page on browser settings.

I just took the graphics and slapped them into a GitHub page, because it was a wiki and I figured sufficiently-motivated-individuals could improve it. I don't know GitHub-markdown for images and the one thing I tried to change the size didn't work, so I just left it. :-) But I think having a standard page is good:

https://github.com/hostilefork/replpad-js/wiki/Enable-WASM-Threads

Let me know if you have any trouble making it work in the emterpreter...we also can do several things to speed the emterpreter up, which are probably worth looking into a little. But I still want to coax people to turn on the threads.

BrianOtto commented 5 years ago

Right now I get a dialog box saying there's no WASM/Pthreads and there's a "reb is undefined" error. So you probably want to turn that into a "hey you're running sub-optimally" warning box, and direct people to the page on browser settings.

Yea, Emterpreter isn't supported in UI Builder yet. That dialog was just my stop gap until I looked into it further. I do plan on adding a proper warning about running sub-optimally, but I didn't have a page built yet that describes the requirements and browser settings properly. I see you do though, so that's awesome. I can add a link to that.

Thanks, I'll let you know how the Emterpreter integration goes!