pypercard.core
¶
PyperCard is a simple HyperCard inspired framework for PyScript for building graphical apps in Python.
Based on original pre-COVID work by Nicholas H.Tollervey.
Copyright (c) 2023 Anaconda Inc.
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
Module Contents¶
Classes¶
|
Represents a card in the application. A card defines what is presented to the user. |
|
Represents a card based application. |
API¶
- class pypercard.core.Card(name, template=None, on_show=None, on_hide=None, auto_advance=None, transition=None, sound=None, sound_loop=False, background=None, background_repeat=False)
Represents a card in the application. A card defines what is presented to the user.
The app ensures that only one card is ever displayed at once. Each card has a
name
and an HTMLtemplate
that defines how it looks on the page. If atemplate
is not passed in on instantiation, theCard
will look for atemplate
element within the DOM with the sameid
as the givenname
to use as the template instead.Cards may also have optional
auto_advance
andtransition
attributes for transitioning to a target card after a given period of time.Cards are rendered from the
template
in theshow
method. The first timeshow
is called it creates apyper-card
HTML element for the app to insert into the DOM.Bespoke behaviour for rendering can be defined by the user. This should be passed in as the optional
on_show
argument when initialising the card. It will be called, at the end of the card’sshow
function, but before the element to insert into the DOM is returned to the app. Theon_show
function is called with the same arguments as a transition function: a reference to the app and the current card.The
hide
method hides card’s HTML element, but leaves it in the DOM.Card’s can optionally take some action each time a card is hidden using the
on_hide
method. Theon_hide
method is called with the same arguments as a transition function: a reference to the app and the current card.It’s also possible to use the
register_transition
method to register a user defined function to handle events dispatched by elements found in the card’s HTML. These contain application logic and transition the app to new cards by returning a string indicating the name of the next card to show.The convenience functions called
get_by_id
,get_element
andget_elements
return individual or groups of matching HTML elements rendered by this card, given a valid id or CSS selector (comments attached to the functions explain the specific behaviours).Cards can optionally define the nature of their background, via the
background
andbackground_repeat
attributes. Thebackground
should either be a valid CSScolor
or a URL to an image. If thebackground
is an image, thebackground_repeat
flag will indicate if the image will fill the whole screen or repeat in a tiled fashion (the default is to fill the whole screen).Initialization
Initialise the card with a
name
unique within the application in which it is used.The following optional arguments are available to customize the card’s appearance and behaviour.
The string content of the
template
argument is used to render the card. If not given, the card will attempt to extract theinnerHTML
from atemplate
tag with an id of the given name of the card. Otherwise, the card will raise aRuntimeError
.The
on_show
function is called every time the card is shown. It should takeapp
andcard
arguments (just like transitions) and be used for customising the rendered card.The
on_hide
function is called every time the card is hidden. It should takeapp
andcard
arguments (just like transitions) and be used for stopping actions (sounds etc.).The
auto_advance
is the number of seconds, as afloat
orint
, to wait until thetransition
is evaluated to discern the next card to which to automatically transition.The
transition
can be either a string containing the name of the card to which to automatically transition, or a transition function to call that returns a string containing the name of the next card.Either both
auto_advance
andtransition
need to be given, or both need to beNone
. Otherwise, the card will raise aValueError
. If thetransition
is not a string or function or theauto_advance
is not an integer or float, aTypeError
will be raised.The optional
background
argument can either contain a valid CSScolor
or a URL to an image to display as the background.The optional
background_repeat
flag defines if thebackground
image fills the whole screen (the default) or repeats in a tiled fashion (if the flag is set toTrue
).- register_app(app)
Add a reference to the hosting app, of which this card is a part.
- show()
Show the card to the user.
If this is the first time the card has been shown a
pyper-card
element will be created for it and inserted into the DOM (as a child of the app’spyper-app
element).If the card has already been shown then we simply make it visible by setting the element’s
display
attribute toblock
.Ensures the template is
.format
-ed with theself.app.datastore
dictionary (so named custom values can be inserted into the template).Rebinds any user defined transitions to the newly rendered elements created by the card.
- _add_dom_event_listeners()
Add DOM event listeners for any transitions added via “app.transition”.
- _start_auto_advance_timer()
Start the card’s auto-advance timer.
- hide()
Hide the card from the user.
This leaves the card in the DOM but just sets
display
tonone
, and removes any DOM event listeners.
- _remove_dom_event_listeners()
Remove any DOM event listeners that were hooked up when the card was shown.
- register_transition(dom_event_name, element_id=None, query=None)
event_name
- e.g. “click”element_id
- the unique ID identifying the target element.query
- a CSS selector identifying the target element(s).
- get_by_id(element_id)
Convenience function for getting a child element by id. Returns
None
if no element is found.
- get_element(selector)
Convenience function for getting a child element that matches the passed in CSS selector. Returns
None
if no element is found.
- get_elements(selector)
Convenience function for getting a Python list of child elements that match the passed in CSS selector. Returns an empty list if no elements are found.
- class pypercard.core.App(name=None, datastore=None, cards=None, sounds=None)
Represents a card based application.
This encapsulates the state (as a
DataStore
), stack ofCard
instances, and registering transitions.Other app-wide functions (such as playing or pausing sounds) are methods of this class. To add your own app-wide functions, create a sub-class of this one.
TODO: It will be possible to dump and load a declarative
JSON
representation of the application, once the specification and capabilities of an app are finalised.If no default arguments given, the app will assume sensible defaults.
Initialization
Initialise a PyperCard app.
If no
name
is given, the page’stitle
value is used, otherwise the givenname
becomes the pagetitle
.The
datastore
is an optional pre-populatedDataStore
instance.The
cards
are an optional list ofCard
instances with which to initialise the app. If no cards are given, the app will look in the DOM fortemplate
tags to populate the card stack.The
sounds
dict contains defaultname
/url
pairs that define the initial sounds the app may need to play.- _new_id()
Gets a likely unique id to be attached to an element that doesn’t have one (but should).
Why not UUID? MicroPython.
- _harvest_cards_from_dom()
Harvest any cards defined in the DOM.
This queries the DOM for all ‘template’ tags. The contents and attributes of each template tag is used to configure a card in the app’s stack of cards.
Returns a (possibly empty) list of the Card instances.
- _resolve_card(card_reference)
Given a card reference, that could be either a string containing the card’s name, or a card object, returns the correct card instance if the card is in the app’s stack.
Otherwise, raises a
ValueError
.
- show_card(card)
Show the referenced card into the DOM via
self.placeholder
.TODO: enable different types of visual transition between cards (e.g. fade, slide etc…).
- hide_card(card)
Hide the specified card.
- add_card(card)
Add a card to the stack.
- get_next_card(card)
Get the next card sequentially in the card list.
Returns
None
if ‘card’ is the last card.
- remove_card(card_reference)
Remove a card from the stack.
The reference to the card can be an instance of the card itself, or a string containing the card’s
name
.
- add_sound(name, url)
Add a named Audio object to the application, to play the sound file found at the given URL.
NOTE The URL is NOT a reference to a file on the PyScript filesystem, but a file accessible to the browser via an HTTP request.
- get_sound(name)
Get the sound referenced by the given name.
If the name doesn’t reference a sound, a ValueError is raised.
- remove_sound(name)
Remove the Audio object referenced by the given name.
- play_sound(name, loop=False, multitrack=False, restart=False)
Play the sound, added to self with the given name. If the sound was paused with the
keep_place
flag set toTrue
, the sound will resume playing from the place at which it was paused. Otherwise, the sound will play from the start.If
loop
isTrue
the sound will keep repeating until paused or removed from the application.If
multitrack
isTrue
then any currently playing sounds will continue to play. The default is false, so only one track will play at any given time (the most recet track to be played).If
restart
isTrue
then, if the sound is already playing when this function is called, it will be restarted from the beginning, otherwise the sound will be allowed to continue to play as is.
- pause_sound(name, keep_place=False)
If the sound, added to self with the given name, is playing, pause it. If
keep_place
isTrue
the sound will pause at its current location. Otherwise, should the sound be played again, it will play from the start.
- register_transition(dom_event_name, element_id=None, selector=None)
event_name
- e.g. “click”element_id
- the unique ID identifying the target element.query
- a CSS selector identifying the target element(s).
- set_background(background='')
Set the body tag’s background style attribute to the given value. If no value is given, resets it to blank.
- transition(from_card_name_or_list, dom_event_name, id=None, query=None)
A decorator to create transitions for DOM events within the specified card.
This just adds a transition to the app’s state machine.
The
from_card_name_or_list
can be either a string of the name of the target card, or a list of target card names. If the card name is “*” the transition applies to ALL cards in.The
dom_event_name
is the name of the event, as dispatched by the browser, e.g. “click”.The
id
is the uniqueid
attribute of the target element within the referenced card[s], that will dispatch the event.Finally,
query
is a way to provide a valid CSS query to match elements within the referenced card[s], that will dispatch the event.
- start(card_reference=None)
Start the app with the referenced card.
The reference to the card can be an instance of the card itself, or a string containing the card’s
name
.If no
card_reference
is given, the app will start with the first card that was added to its stack.
- dump()
TODO: Dump a tree (JSON) representation of the app.
- load(tree)
TODO: Load a tree (JSON) representation of the app.
- _create_auto_advance_transition(from_card)
Create a transition that accepts a timeout and advances to another card.
- _create_dom_event_transition(from_card_name, transition_fn_or_card_name, dom_event_name, element_id=None, selector=None)
Create a transition that is triggered by a DOM event.
- _create_card_state(card)
Create a state machine state for the specified card.
Returns a
tuple
in the form (State, [Transition])
- _get_name_of_card_to_transition_to(from_card, transition_fn_or_card_name, input_)
Get the name of the card to transition to.