Coder Social home page Coder Social logo

bigskysoftware / _hyperscript Goto Github PK

View Code? Open in Web Editor NEW
2.8K 31.0 136.0 9.19 MB

a small scripting language for the web

License: BSD 2-Clause "Simplified" License

JavaScript 96.00% HTML 3.71% CSS 0.03% Nunjucks 0.02% Python 0.25%
htmx hyperscript scripting-language

_hyperscript's Introduction

//_hyperscript

the underscore is silent

introduction

_hyperscript is a small, open scripting language inspired by hypertalk

it is a companion project of https://htmx.org

quickstart

<script src="https://unpkg.com/[email protected]"></script>


<button _="on click toggle .clicked">
  Toggle the "clicked" class on me
</button>


<div hs="on mouseOver toggle mouse-over on #foo">
</div>

<div data-hs="on click call aJavascriptFunction() then
              wait 10s then
              call anotherJavascriptFunction()">
           Do some stuff
</div>

website & docs

contributing

  • please include test cases in /test and docs in /www
    • you can run the test suite by viewing test/index.html in a browser.
  • development pull requests should be against the dev branch, docs fixes can be made directly against master
  • you can build _hyperscript as shown: npm run dist. building is not necessary during development to run tests.

_hyperscript's People

Contributors

1cg avatar adamchainz avatar ajusa avatar apeckham avatar bencroker avatar benpate avatar dependabot[bot] avatar dz4k avatar dzerrenner avatar fdiskas avatar gnat avatar grantjenks avatar iredmail avatar jonesnc avatar jreviews avatar jvosloo avatar maio avatar mhadam avatar michaelsmanley avatar mill3n avatar nicobako avatar rajasegar avatar reedspool avatar renerick avatar robinvandernoord avatar rozek avatar sponsfreixes avatar szepeviktor avatar tomberek avatar wiverson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

_hyperscript's Issues

'remove [disabled]' seems not working

I'm trying to remove the disabled attribute following the example in DOCs but this very basic code does not work (console reports a number of errors).

	<button id="btn0" type="button" 
		_="on click remove [disabled] from #btn1">
		Disable MyButton
	</button>

	<button id="btn1" type="button" disabled>
		MyButton
	</button>

Examples on language home page don't work

There is an error in console:

VM59:10 Uncaught TypeError: Cannot read property 'applyEventListeners' of undefined
    at Object.applyEventListenersTo (eval at initElement (_hyperscript.js:638), <anonymous>:10:66)
    at initElement (_hyperscript.js:639)
    at _hyperscript.js:621
    at forEach (_hyperscript.js:525)
    at Object.processNode (_hyperscript.js:620)
    at processNode (_hyperscript.js:1736)
    at HTMLDocument.<anonymous> (_hyperscript.js:1778)
applyEventListenersTo @ VM59:10
initElement @ _hyperscript.js:639
(anonymous) @ _hyperscript.js:621
forEach @ _hyperscript.js:525
processNode @ _hyperscript.js:620
processNode @ _hyperscript.js:1736
(anonymous) @ _hyperscript.js:1778

Trouble with "measure" command

I love the new measure command, but I'm running into trouble using it. Here's my code:

def center(node) 
	with node measure me then log it end -- works
	measure node then log it -- doesn't work.
end

I want to make a function that takes an HTML Element and moves it around the screen. The first statement with node... works fine, and I'm able to get the measurement of the Element. But the second statement returns an error "Uncaught (in promise) No such measurement as node". I think this is because it does not recognize the variable as a node, and assumes that it is a (missing) dimension that it's supposed to find.

So, perhaps we need to update the syntax that measure is using?

Also, being able to pull specific measurements into variables is nice, but it's no use if I have to measure two items (like the window and the HTML Element I'm going to move). The best I've come up with is the rather clunky

measure #sourceNode then put it into sourceMeasurement
measure #targetNode then put it into targetMeasurement

... then use the two new variables below

How much flexibility do we have to tweak this command?

Relationship with Htmx?

Really interesting project!

Could you clarify the relationship with Htmx? I see you call it a companion project but I'm not entirely sure what that means.

This would help people like myself who are interested in both but want to understand where they are headed before committing time to one.

Can't call functions with _ or empty parameter lists

Tried to do on load call auto_select(). This crashes with a vague message about _. If I rename the function to autoSelect it crashes if I call it with zero parameters like that.

Still haven't gotten it to work with those two changes though...

PROPOSAL: Fetch syntax upgrades

I'm kicking around a number of updates to the fetch syntax, while still trying to keep things as short and expressive as possible. Can we use this ticket to start a discussion on the best way to make improvements?

HTTP Verbs

One thing that came up is the ability to use HTTP verbs as the specific command: enabling something like this:

get [from] <server-url> [using <headerValue>]
post [<object>] [into] <server-url>
put [<object>] [into] <server-url>
delete [<object>] [from] <server-url>
fetch <server-url> -- could still work as a "GET" request

I think this would bring HTTP verbs to the API surface with little or no cost to the language syntax. It also fits the spirit of hyperscript as "a scripting language designed for the web and inspired by HyperTalk." The one red flag is that put is already in use as a (virtual) synonym for set.

If we decide that we like this syntax, it would be a breaking change that we would need to manage carefully. The first step would probably be to confirm that set is able to accomplish everything that put does currently, and notify developers of the upcoming change.

Header Values

Though it might be possible to enumerate some of the common header values, I think the cost probably outweighs the benefits.

A statement like get from /my-url using authorization "12345" and cache-control "no-cache" is really cool, but unwieldy in practice. If I need to send complicated headers to the server, it's more likely that I'll want to manage them like this

set commonHTTPHeaders to {
    "Authorization: "12345",
    "Cache-Control": "no-cache"
}

get from /my-url using commonHTTPHeaders

Pluggable Fetch Backend

Add a default function into the hyperscript configuration object -- similar to the one in htmx -- that would let developers override the current behavior. For example, I wrote an htmx extension to save authorization headers supplied in any http response, then add them to every subsequent http request. I'd like to make the same feature available in hyperscript as well.

These custom function signatures might look something like this

var config = {
    // process request before sending via hyperscript
    beforeFetch: function(url, options:Object): Obje t {
        return {url:url, options:options};
    },
    // actually does the fetch command
    fetch: function(url:string, options:Object): Promise<Object> {
        return fetch(url, options);
    },
    // process response object before returning to hyperscript
    afterFetch: function(response:Object): Object {
        return response;
    }
}

htmx events not working

Trying to follow the docs and do:

<div _="on htmx:load log 'Loaded!'"></div>

And getting:

Uncaught Error: Unexpected Token : :

on htmx:load log 'Loaded!'
        ^^


    at Object.raiseParseError (_hyperscript.js?compile=false:395)
    at _hyperscript.js?compile=false:1153
    at parseElement (_hyperscript.js?compile=false:402)
    at Object.parseHyperScript (_hyperscript.js?compile=false:416)
    at Object.initElement (_hyperscript.js?compile=false:568)
    at init (_hyperscript.js?compile=false:1665)
    at _hyperscript.js?compile=false:1653
    at Object.forEach (_hyperscript.js?compile=false:478)
    at HTMLDocument.fn (_hyperscript.js?compile=false:1652)

I'm using the latest version of both HTMX and hyperscript.

What am I missing here?

ajax get access custom event parameters (reponse header value)

Hi, i am trying to do _="on redirect(url) log 'url is: ' + url then ajax GET '' + url then put response into test.innerHTML"> and it errors on '' + url

My server returns a custom response header: HX-Trigger: {"redirect":{"url":"/hello"}}

I also tried _="on redirect(url) log 'url is: ' + url then ajax GET url then put response into test.innerHTML">, but it tries to ajax to /mypath/url instead of going to /hello

If i did _="on redirect(url) log 'url is: ' + url then ajax GET /hello then put response into test.innerHTML"> then it works, but i'd like to avoid any hardcode in the command.

Any pointers ? Thank you ..

PROPOSAL: date/time functions

Without going overboard and re-developing something like Moment.js, I think Hyperscript could benefit from a few time/date commands. It could easily be wrapped into its own separate package so that it doesn't affect people who don't need it.

Tag Result Example
today dateTime value of current day
tomorrow dateTime value of next day
yesterday dateTime value of previous day
now dateTime value of current time
before, after modifies a dateTIme value 1 day before today
from same as after 1 year from now
year, month, week, day, hour, minute, second date range for 3 weeks after today\
is before, is after date comparison function if endDate is before 1 year from now then log endDate

Feature: Implement SSE

From discord:

server sse://whatever
    on foo
          -- additional commands.  "it" is populated with the event?
    end

    on message
        -- more commands
    end

on unhandled

PROPOSAL: "field" expression

HyperTalk used identifiers like field and button to locate screen elements for later use, using a string to match the element ID or NAME. I see several benefits to adding this:

  1. It makes code a little more explicit, because we can label what kind of element we're looking for.
  2. In the case of field (and possibly button) we could fall back to searching by the element name=""
  3. It allows us to use variables to identify DOM elements cleanly without a lot of magic characters: I'm looking at you, <#${dude}/>

How it Should Look

set field "MyField" to "123"
send click to button "MyButton"
add .className to tag "MyTag"

This syntax would work great with variables that name the field/button/tag instead of hard-coding tag names

set field VariableThatContainsAFieldName to "boo-ya"
tell novelist SelectorVariable remove me
Identifier Result
tag returns the first tag whose ID that matches the provided string
button returns the first button whose ID (or NAME?) matches the provided string
field returns the first input, select-box, or textarea whose ID or NAME matches the provided string (special handling for checkboxes and radio buttons
nodelist returns a NodeList (array) of elements that match the provided selector. (Similar to < /> but works with a string variable

PROPOSAL: Enhance Keyboard Events

There's an amazing javascript library called HotKeys that makes it stupid easy to build keyboard shortcuts. Hyperscript does this very well, but I think that we could make it even better by borrowing a couple of easy-to-implement ideas from Hotkeys.

We wouldn't need to change our event handlers, just enhance the events with some extra data that makes it easy for both humans and machines to recognize the keyboard combination being pressed:

on keypress(key)
    if key is "ctrl+s" return save() end
    if key is "ctrl+f" return find() end
    if key is "alt+q" return somethingElse() end
    if key is "ctrl+alt+M" return anotherCombo() end -- one way of handling uppercase characters.
    if key is "ctrl+alt+shift+m" return alt() end -- an alternate way of handling uppercase characters to consider.

This would really just require an extra function that looks at keyboard events, generates this string, then inserts it into the event details. Yes?

PROPOSAL: "global" keyword

Does hyperscript need a global keyword? HyperTalk had one, and it feels dirty to use window.variableName to define a value that's available everywhere.

init
set global greeting to "yo"

on click from button "myButton"
set greeting to "mama"

Wait for <x> and <y>

The wait syntax in hyperscript does a great job of enabling event controlled flow. However, it has trouble when waiting on more than one event at the same time. For example:

on closeModal(event) 
    add .closing to #modal 
    async do 
        if theURL is not null then 
            fetch theURL then 
            put it into #main.innerHTML
        end
        trigger fetchDone
    end
    wait for animationend
    wait for fetchDone
    remove #modal
end

This should work if animationend finishes before fetchDone, but it deadlocks if fetchDone completes first.

I think hyperscript would benefit from a wait for x and y syntax that is similar to Promise.all() that only returns after all of the events have triggered.

This might be generalized to other kinds of operations, such as wait for any of x and y and z but my first guess is that this would be less commonly useful.

Feature Request: Map Command

I think hyperscript would really benefit from a map command that takes an array and maps it to a series of values. We originally discussed this as a property of arrays, but I think it would work easier as a command on its own -- perhaps bundled into a separate library of other similar commands. Here's how it might work

Map takes a variable name (which must be an array) and a result template and returns a new array with values mapped from their original values into the result. It would work very similar to the built-in array.map function, without the lambda calculus. The syntax would look something like map <variable> (to|into) <expression>

When evaluating the result template for each item in the array, these variable names would be available for use:

index: the current index number of the item in the array
value: the value in the array at that particular location

Examples

fetch /my-server
map it into {}

This could also work with template literals

fetch /my-server as json
map it to 
`<tr>
    <td>Record #${index + 1}</td>
    <td>${value.firstName}</td>
    <td>${value.lastName}</td>
    <td>${value.emailAddress}</td>
</tr>`
put it into #my-table

If this syntax is acceptable, I'm happy to try submitting a PR. If I can figure out how to do it, I'll probably propose match (all|first) from <variable> (on|with) <expression> next :)

Trying to remove a class on click parsing error

Trying to use the following _="on click remove .hideme to #email-form" and it throws this error: Uncaught Error: Unexpected Token : to this is basically the same as one of the examples? Whats wrong with this?
[updated] Found that in another example it should have been from instead of to - however it would not work with #email-form id - had to add a class named email-form and then use .email-form as the from selector.

How to add data-* attribute?

How can an attribute of the type data-* be added to an element?
If I use
on click add [data-initial='name']
I get this error
Expected ']' but found 'data-initial'

ajax doesnt add htmx request headers

Hi, i did ajax using _hyperscript, and i notice the htmx request headers are not there yet.

Is this intentional or perhaps there is a way to get the headers sent ?

Thank you ...

Feature Request: `toggle between` syntax for elements

Basically:

<a _="on click toggle between .this-class and .that-class on #my-element">Click</a>
<div id="my-element" class="this-class">

When you click the <a>, it should remove this-class and add that-class, or vice versa, depending on the initial state.

Alternative syntax, maybe: on click toggle between .this-class, .that-class on #my-element but I think the 'and' works better here.

Very helpful for a broad range of UX patterns.

Error in Docs

Hey there,

There's an error in the following example page: https://hyperscript.org/commands/remove/

<div _="on click remove .not-clacked to #another-div">Remove Class From Another Div!</div>

I think the to should be from, so:

<div _="on click remove .not-clacked from #another-div">Remove Class From Another Div!</div>

Thanks!

Extracting part of HTML or JSON response from AJAX

Hi, is it possible to extract some part of the response from ajax command?

For now I'd need to do something like this:

on click ajax GET /my-data then put response(#content) before me end

This is of course just to give you an idea of what I would use. Important thing here to remember is that the response could be json or any other format, so the language should address that somehow.

Alternatively it could just be left to custom JS function that would extract the value.

Documentation for internal hyperscript functions

I think I just made my first operator for hyperscript (yay!). To flatten the learning curve, it would be very helpful to document the basic parameters required by the internal functions in hyperscript.

I don't know if it's best on the website, somewhere in a GitHub wiki, or as comments in the source code, but here are the functions/parameters that I'd love to understand better:

  • _runtime.unifiedEval(parseElement, op, ctx)
  • parser.parseElement(type, tokens, root)
  • parser.addGrammarElement(name, definition)
  • arguments to definition(parser, tokens) function passed in to addGrammarElement
  • structure returned by definition(parser, tokens)
  • when can I call expression.evaluate() and when must I call _runtime.unifiedEval()

Problem with version 0.0.9 and tell command

This code working with version 0.0.7 no longer works when upgrading to version 0.0.9

<button class="btn btn-primary d-none cropped-only" hx-post="..." 
_="on htmx:afterRequest get detail.xhr.response.includes('success') then
      if it with <.avatar img/> set me.src to zu.imageCropper.objectURL then remove .d-none from me end"
>Confirm</button>

I tried replacing "with" with "tell" but "me" always refers to the "button" and not all occurrences of ".avatar img" on the page.
Am I missing something?

Handle direct properties on events

Right now you can only destructure properties from the details property of an event into variables. This is fine for custom events, but does not work for properties directly on the event.

This logic:

return "var " + arg.value + " = event.detail." + arg.value + ";"

should check both places, when setting the value of a destructured variable.

Using variables in expressions

Now that hyperscript has behaviors, it could be useful to support using variables within expressions to make them more configurable. For example.

<div data-hidden-class="hide"></div>

And then be able to use the defined hidden-cass within hs code.

set `.${@data-hidden-class}`

PROPOSAL: & and && operators

The original HyperTalk used & for string concatenation, and && for string concatenation with a space in between. This would be really useful, and would help avoid statements like this set fullName to firstName + " " + lastName -- changing them into this instead set fullName to firstName && lastName

Right now, hyperscript uses && as a logical AND operator, and we should not change this. But, would it be possible (and not too confusing) to overload this behavior when dealing with two strings? Or, would it be better to use a different operator for this?

on load event on <img> is triggered twice

This code

<img src="image-url" _="on load log me.src" >

create two console log entry with same "image-url"

I suppose because is intercepted "load" node event and "load" image specific event.
Is there any way to distinguish the two events?

In addition if I use
<img src="" onload="myFunction(this)">
and programmatically I set src to image-url, myFunction is correctly executed after remote image-url is loaded

if I use
<img src="" onload="myFunction(this)"_="on click log me">
and I don't set src programmatically, myFunction is always executed on page load

Act upon the result of an event

Updated with customized JS code called upon onsubmit.

Playing with an example for bigskysoftware/htmx#398 , I am trying to trigger a submit event when hx-post is pressed.

<!DOCTYPE html>
<html lang="en">
<body>
  <form action="{{ request.path }}" method='post' id="myform" 
         onsubmit="return validateForm()">
  <label for="choose">Would you prefer a banana or cherry?</label>
  <input id="choose" name="i_like" required>
  <button>Submit</button>
  <a href='#' _="on click send submit to #myform" hx-post="{{ request.path }}">hx-post</a>
</form>
</body>
function validateForm() {
  var x = document.getElementById("choose").value;
  if (x != "apple") {
    return false;
  }
}
</script>
  <script src="https://unpkg.com/[email protected]"></script>
  <script src="https://unpkg.com/[email protected]"></script>
</html>

It appears that the form element did receive the submit event but hx-post did not wait for the completion of the submit event (result of validateForm) and went ahead with AJAX post. Is there anyway to wait for the completion of submit, cancel hx-post ifvalidateForm returns false?

PROPOSAL: "play" command

HyperTalk used play to trigger audio files. Hyperscript could use this for audio (or possibly video) files as well. This also sets a local variable called "the sound" that could be used to reference the audio after.

on click
    play /sounds/pop.mp3

on mousedown from AngerButton
    repeat until event mouseup
        play /sounds/klaxon.mp3
    end
    stop() the sound

Feature Request: stop/start commands

I stumbled into this while working on SSE Support (#52). I've now exposed functions like call MyConnection.start() and call MyConnection.stop() to the rest of hyperscript. This works fine, but it would be better if I could say something likestart MyConnection and stop MyConnection instead.

We have now added several kinds of background services: Workers, WebSockets, and SSE that could all use this kind of syntax. And it seems likely there could be others in the future that could implement this, too.

Interfaces
I think it could be implemented using something like a duck-typed interface, so the start keyword would take a single argument -- the name of the object in the hyperscript context -- and try to call the .start() method on that object. If the method doesn't exist, then hyperscript could log an error.

The stop keyword would do the same thing, searching for a .stop() method instead.

Naming
These names are not set in stone -- there are many other pairs that might work instead (connect/disconnect, open/close, etc) -- but these seem like the most generic terms that would be applicable in the widest range of circumstances.

The right way to use behaviors?

Hi,

I was playing with behaviors in [email protected], and I'm not sure what the expected way to write it is. Here's what I've tried.

If I add it into a script tag with text/hyperscript, and install it on an element, I get a No such behavior defined as Removable Error: No such behavior defined as Removable (e.g. using the Removable example in the docs at https://hyperscript.org/docs/#behaviors).

But if I add the behavior in the hyperscript attribute of an element, and add install Removable it in any element after, it works?

FEATURE: “is empty” and “is not empty”

I was recently working with a string comparison and I struggled to guarantee that an object was not null. While I eventually worked it out as not(no value) I think we could make hyperscript more readable with another pair of single argument operators: is empty and is not empty.

My first thought is that is empty should return truefor all values that are null, undefined, [empty string], or zero length Objects or ArrayLike values. But if someone else has a better definition, I'm open to whatever makes the most sense for the community. The is not empty operator would obviously return the opposite of is empty.

I'll happily take a shot at building this (along with tests and documentation) if I can get a hoo-ah from @1cg

Event name with `-`

I had to change my event name when I failed to use cart-updated or "cart-updated" in a piece of hyperscript code.

composability/encapsulation?

Is it possible to compose/encapsulate commands? it'd be nice to be able to do something like _="on blur validate-email me" rather than writing out a whole regex every time, especially if some email inputs have additional logic.

Documentation needed for using template tags

I'm using alpine with htmx/hyperscript.
I noticed that if I add htmx via the template tag the components are not initialized.
E.g.

<template x-if="popup === 'signup'">
    ... HTMX ...
</template>

It is important to init HTMX/Hyperscript via

htmx.process(addedTemplateTag);  
_hyperscript.processNode(addedTemplateTag);

It would be nice to have this documented for future users. Also is it possible to reduce both process calls into one?
One suggestion could be for html to check if _hyperscript is present and call processNode.

Thank you

on load event don't work

I create a JSFiddle to reproduce the issue

I used the syntax from the example page
<div _="on load wait 5s then remove me">Here is a temporary message!</div>

How do I access attribute values?

I noticed this gives me undefined:

log #element[attr-name]

as does log #element.attr-name and log attr-name of #element. What is the correct way to read an attribute value?

set not working with template literal value

Using template literal values for set fails and the browser hangs

<input type="text" id="txtName"/>
<button  type="button" _="on click set message to `hello ${#txtName.value}` then call alert(message)">Say Hello</button>

Does hyperscript supports variables?

Could someone kindly answer a question I posted on Stackoverflow asking if I can use variables with the add command?

For example:
without variable (id = #1022):

<button _="on click add .green to #1022" type="button">
    Click
</button>

with variable (id = my_variable):

<button _="on click add .green to my_variable" type="button">
    Click
</button>

and then something like this:

<script type="text/javascript">
    function setID() {
        // here the code to get the ID and set my_variable
        return id;
    }
</script>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.