This portable modern web framework is the application-neutral backbone of Civil Action Network. It includes: a pubsub WebSocket server and bot platform; swappable web backends capable of targeting high-concurrency standalone or cloud platforms; a variable-mode application compiler; a broad-spectrum ORM and database migration tools; a built in administrative interface; and a rich modular JavaScript library.
- Docs: http://ct.mkult.co
- License: MIT (see LICENSE)
- upside: includes full codebase (not just Python)
- site: https://github.com/bubbleboy14/cantools
- steps
- git clone https://github.com/bubbleboy14/cantools.git
- cd cantools
- pip3 install -e .
If you're running Debian or Fedora or BSD or OSX, you may consider running (probably as root or sudoer):
./bootstrap.sh
Instead of the pip3 install line. This will also install various dependencies that may not already be present on your system (some systems don't even come with Python).
- upside
- cantools and all dependencies installed in one line
- hidden away like any standard system library
- cleanest way to deploy your applications
- downside
- no easy access to ct source -- aren't you curious?
- OSX or Debian (especially Ubuntu) -only (until you add support for your system!)
- command: curl https://raw.githubusercontent.com/bubbleboy14/cantools/master/bootstrap.sh | cat | sh
- downside
- does not include full package (such as client-side web files)
- enough to mess around with cantools -- not enough to develop end-to-end applications
- package: https://pypi.python.org/pypi/ct
- command: easy_install ct
This takes less than a moment. Pop open a terminal in your home directory:
~$ git clone https://github.com/bubbleboy14/cantools.git
~$ cd cantools/
~/cantools$ pip3 install -e .
~/cantools$ cd ..
~$ ctinit hello_world
~$ cd hello_world/
~/hello_world$ ctstart
And that's it. Open http://localhost:8080/ in your browser and call it a day.
You just found out that you need to deploy a cantools project to a fresh, naked Ubuntu system that doesn't even have Python or git. Oh no, what do you do? This (as root or sudoer for first and last commands):
~$ curl https://raw.githubusercontent.com/bubbleboy14/cantools/master/bootstrap.sh | cat | sh
~$ git clone https://github.com/your_organization/your_project.git
~$ cd your_project
~/your_project$ ctinit -r
~/your_project$ ctstart -p80
Now just make sure port 80 is open, and you're good to go. Also, you should probably run ctstart in a screen or something (so that you can eventually log out) - that's it!
-h, --help show this help message and exit
-p PLUGINS, --plugins=PLUGINS
which plugins would you like to use in your project?
-c CANTOOLS_PATH, --cantools_path=CANTOOLS_PATH
where is cantools? (default: /guessed/path/from/__file__)
-w WEB_BACKEND, --web_backend=WEB_BACKEND
web backend. options: dez, gae. (default: dez)
-r, --refresh_symlinks
add symlinks to project, create any missing directories,
and configure version control path exclusion (if desired)
-u, --update update cantools and all managed plugins
-a, --admin compile admin pages [ctdev only]
NB: it may be necessary to specify --cantools_path. Normally, this is derived from the file property (the location of the ctinit script, init.py). However, if the package lives in your Python dist-packages (as with 'easy_install', as well as 'setup.py install', and now even 'pip3 install'), it does not contain the client-side files necessary for an end-to-end web application, and these files therefore cannot be symlinked into your new project. In these cases, indicate --cantools_path (the path to the cloned cantools repository on your computer), and everything should work fine.
Generally speaking, one should clone the cantools github repository, 'setup.py install' it (for the 'ct' commands), and then run 'setup.py develop' - actually now instead of setup.py anything, just use pip3 install -e - which will point 'cantools' at your cloned cantools repo and keep the package up to date as you periodically 'git pull' the latest version. Similarly, plugins should be kept in 'develop' mode, as they also will generally have non-python files of consequence.
In most cases, the developer won't have to pay much attention to this stuff, because initializing or refreshing a project will automatically install any necessary plugins that aren't already present. Similarly, the --update flag pulls down the latest versions of cantools and all managed plugins. Thus, plugins are dealt with under the hood without any need for the developer to know or do anything beyond 'ctinit -r'.
-h, --help show this help message and exit
-w WEB_BACKEND, --web_backend=WEB_BACKEND
web backend. options: dez, gae. (default: dez)
-p PORT, --port=PORT select your port (default=8080)
-a ADMIN_PORT, --admin_port=ADMIN_PORT
select your port (default=8002)
-d DATASTORE, --datastore=DATASTORE
select your datastore file (default=sqlite:///data.db)
-o, --overwrite_password
overwrite admin password (default=False)
-h, --help show this help message and exit
-d, --dynamic switch to dynamic (development) mode
-s, --static switch to static (debug) mode
-p, --production switch to production (garbled) mode
-u, --upload uploads project in specified mode and then (if
gae) switches back to dynamic (development) mode
-n, --no_build skip compilation step
-j JS_PATH, --js_path=JS_PATH
set javascript path (default=js)
- dynamic (files live in html)
- normal development files
- dynamic imports throughout
- original files are loaded ad-hoc
- chrome debugger plays nice
- no wire encryption
- all imports lazy
- static (files live in html-static)
- compiler builds same html files
- script imports in head
- otherwise unmodified source files
- original files are directly referenced
- chrome debugger prefers
- no wire encryption
- all hard requirements loaded in head
- lazy-designated imports still lazy
- production (files live in html-production)
- all code is compiled in head
- html is compressed
- javascript is minified and mangled
- original code is unrecognizable
- chrome debugger almost useless
- wire encryption
- designated lazy imports (indicated by second bool arg to CT.require)
Generates fresh 'static' and 'production' files (from 'development' source files in 'html' on every run, unless -n [or --no_build] flag is used). Mode is established in the app.yaml file, which routes requests to the appropriate directory, and the ct.cfg file, which determines backend behavior, especially regarding encryption.
-h, --help show this help message and exit
-d DOMAIN, --domain=DOMAIN
use a specific domain (default: localhost)
-p PORT, --port=PORT use a specific port (default: 8888)
Usage: ctmigrate [load|dump|blobdiff|snap] [--domain=DOMAIN] [--port=PORT] [--filename=FILENAME] [--skip=SKIP] [--tables=TABLES] [--cutoff=CUTOFF] [-n]
-h, --help show this help message and exit
-d DOMAIN, --domain=DOMAIN
domain of target server (default: localhost)
-p PORT, --port=PORT port of target server (default: 8080)
-c CUTOFF, --cutoff=CUTOFF
blobdiff cutoff - number to start after (default: 0)
-f FILENAME, --filename=FILENAME
name of sqlite data file for dumping/loading to/from
(default: dump.db)
-s SKIP, --skip=SKIP don't dump these tables - use '|' as separator, such
as 'table1|table2|table3' (default: none)
-t TABLES, --tables=TABLES
dump these tables - use '|' as separator, such as
'table1|table2|table3' (default: all)
-n, --no_binary disable binary download
-h, --help show this help message and exit
-m MODE, --mode=MODE may be: 'refcount' (default - count up all foreignkey
references for sort orders and such); 'index' (assign
each record a sequential integer index); 'urlsafekeys'
(update all key/keylist properties to use urlsafe keys
introduced in ct 0.8); 'cleanup' (delete zero-count
reference counters). Note regarding 'index' mode: it
_must_ happen remotely; it's generally unnecessary
unless you're trying to migrate an unindexed database
away from gae and need an index/key per record; it
should be invoked from _outside_ -- that's right,
outside -- of your project's directory (to avoid
loading up a bunch of google network tools that may be
crappy or cause issues outside of their normal
'dev_appserver' environment)
-d DOMAIN, --domain=DOMAIN
('index' mode only) what's the domain of the target
server? (default: localhost)
-p PORT, --port=PORT ('index' mode only) what's the port of the target
server? (default: 8080)
-s SKIP, --skip=SKIP skip these tables ('index' mode only) - use '|' as
separator, such as 'table1|table2|table3' (default:
none)
-i INDEX, --index=INDEX
start with this index ('index' mode only) (default: 0)
As you can see, this script's behavior changes according to the backend of the target project.
Run this if your CTRefCount records get messed up for some reason. It will go through and recount everything (in the default 'refcount' mode -- the other modes, 'urlsafekeys' and 'cleanup', are for migrating a CT-mediated database from an older deployment to CT 0.8 or newer).
Run this in 'index' mode on a database with lots of missing index values.
-h, --help show this help message and exit
-w, --web build web docs
-a, --auto use auto mode (even with a plugin)
-o, --omit omit any files from autodoc?
Run from cantools root (contains setup.py, cantools/, README.md, etc), from root of a CT plugin, or from within a custom project. In cantools, builds docs for all frontend (js) and CLI (py) files. In plugin, docs consist of about file (about.txt), initialization config (init.py) and default frontend config (js/config.js). In custom (project) mode (when ctdoc is run somewhere other than cantools root or a plugin root, and additionally a configuration file, doc.cfg, is present), for each path declared in doc.cfg, include the docstring of each file specified, as well as the contents of about.txt (if present). Lastly, auto mode doesn't require configuration (doc.cfg) -- instead, it recurses through the directories of your project, and includes the contents of any about.txt files, as well as (the top of) any py/js file that starts with a docstring.
This module contains a generic data browsing interface.
This class makes a drop-down menu, and can be subclassed into things like the CT.autocomplete classes.
This class is used to generate a pager, which is a self-refilling DOM element.
- renderCb: function that returns formatted content given an array of data objects
- requestCb: function that acquires new raw data
- limit (default: 20): number of items to request/display at a time
- nodeClass (optional): CSS class of pager DOM node
- nodeId (optional): CSS id of pager DOM node
This module includes submodules for interacting with the admin backend:
- CT.admin.core
- CT.admin.db
- CT.admin.memcache
- CT.admin.monitor
- CT.admin.pubsub
This module contains functions for determining dimensions of and positioning DOM elements.
This loader imports almost every CT module.
- CT.Browser
- CT.Drop
- CT.Pager
- CT.align
- CT.autocomplete
- CT.bound
- CT.cal
- CT.canvas
- CT.chat
- CT.data
- CT.db *
- CT.drag
- CT.dom
- CT.file
- CT.gesture
- CT.hover
- CT.key
- CT.memcache *
- CT.mobile
- CT.modal
- CT.panel
- CT.parse
- CT.pubsub *
- CT.recaptcha
- CT.slider
- CT.stream *
- CT.storage
- CT.trans
- CT.upload *
- CT.video
- tightly coupled to backend
- CT.map, CT.pay, and CT.rte, which require large script imports
- CT.admin, which is not for typical use
- CT.cc, which should be imported after core (for config)
The purpose of this module is to simplify the creation of DOM text fields that autocomplete user input based on some data set.
This module contains two classes, Guesser and DBGuesser.
Guesser is a subclass of CT.Drop.
- enterCb (default: doNothing): trigger when user hits enter
- keyUpCb (default: doNothing): trigger on key up
- expandCB (default: doNothing): trigger when autocomplete node expands
- tapCb (default: set input to data.label): trigger on option tap
- guessCb (default: this.guesser): trigger when it's time to guess
- input (required): the input node to which to attach the autocomplete guesser
- data (default: []): array of label-containing objects used by default guesser
To specify custom guessing behavior, either pass in a 'guessCb' function to the constructor or subclass Guesser, adding this function to the class (as 'guesser').
DBGuesser subclasses Guesser, and defines a 'guesser' function, which uses the CT.db module to acquire data.
- modelName: the name of the backend database model to query from
- property: the property (on specified model) to compare to text input
- filters (default: {}): filters to apply to database query
This module contains functions for binding DOM nodes and constructor functions to data objects (by key). When the data changes, the bound nodes are updated according to their constructor functions. Supports two modes, storage and db.
- CT.bound.register(key, node, constructor)
- CT.bound.mutate(data)
var n = CT.dom.div(),
b = CT.dom.div(null, "abs cbr biggest");
CT.dom.setBody([n, b]);
CT.bound.register("main", n, function(data) {
return JSON.stringify(data);
});
CT.bound.register("main", b, function(data) {
return data.anything;
});
CT.bound.mutate({
key: "main",
something: "whatever",
anything: "nothing"
});
This module provides a postMessage bridge between a vanilla javascript application and a generic CT-style widget.
This module contains a class, Cal, for calendar-based applications. Usage:
CT.dom.setBody((new CT.cal.Cal({
timeslots: "data", // or "key" (the default, for use w/ databases)
appointments: [{
name: "app 1",
description: "the first appointment",
editors: [],
commitments: [],
timeslots: [{
schedule: "once",
when: "Thu Oct 10 2019 14:15",
duration: 1
}, {
schedule: "weekly",
when: "Wed Oct 09 2019 18:45",
duration: 2
}]
}, {
name: "lunch",
description: "when we eat food",
editors: [],
commitments: [],
timeslots: [{
schedule: "daily",
when: "Mon Oct 07 2019 12:00",
duration: 1
}]
}, {
name: "number D",
description: "another one, blah blah bloo",
editors: [],
commitments: [],
timeslots: [{
schedule: "weekly",
when: "Fri Oct 04 2019 15:00",
duration: 1
}, {
schedule: "exception",
when: "Fri Oct 11 2019 18:45",
duration: 2
}]
}]
})).node);
This module contains classes that simplify use of the HTML5 canvas element:
- CT.canvas.Canvas
- CT.canvas.Controller
- CT.canvas.Node
- CT.canvas.Text
This module supports carecoin integration. Main ingredients:
Notify compensation platform of content view.
Class for generating interface elements for associating a user with a carecoin membership.
This module contains a chat widget that communicates with a ctpubsub backend via CT.pubsub.
This is the cantools bootstrapper. This means that it must be included in a regular script tag in the head of your html file. It contains the core functionality of the framework, as follows.
- CT.net.post(path, params, errMsg, cb, eb, headers, cbarg, ebarg)
- issues a POST request via asynchronous XHR
- CT.net.get(path, qsp, isjson, ctjson)
- issues a GET request via synchronous XHR
- optionally parses query string object and unpacks response as JSON
- CT.net.put(path, params, cb, headers)
- issues a PUT request via asynchronous XHR
- CT.net.delete(path, params, cb, headers)
- issues a DELETE request via asynchronous XHR
- CT.net.setMode(string) (default: 'ct')
- also supports:
- 'basic', which skips request prepping and response code processing
- 'passthrough', which does nothing (doesn't even JSON stringify)
- CT.net.setSpinner(bool) (default: false)
- enables/disables spinner (indicating outstanding request)
- CT.net.setCache(bool) (default: false)
- enables/disables client-side request caching
- CT.net.setSilentFail(bool) (default: true)
- enables/disables alert-level error reporting (if otherwise undefined)
- CT.net.setEncoder(func)
- sets encoder (upstream data processing function)
- must be used in conjunction with cantools.web.setenc()
- CT.net.setDecoder(func)
- sets decoder (downstream data processing function)
- must be used in conjunction with cantools.web.setdec()
- CT.net.xhr(path, method, params, async, cb, headers)
- thin wrapper around browser-level XHR abstraction
This is the basis of the cantools module system. Any time your code requires a module (CT or otherwise), simply call CT.require ('MyProject.submodule.whatever') to dynamically pull in the necessary code. When your project is compiled in production mode, these imports are baked into the host HTML file, except those flagged lazy. If lazy == true, the compiler will produce a standalone fragment; if lazy == "skip", the compiler will skip the module (for conditional cross-plugin imports, for instance).
This function supports the importation of libraries that only work if they know their path (which they ascertain by checking their own script tag). This includes many popular libraries, such as TinyMCE and Google Maps.
Registers a callback to be fired when the window loads.
Merges arbitrary number of objects into new object and returns result.
This function creates a cantools class. The first argument is a class definition, an object containing all the functions and properties belonging to the class. The second (optional) argument is the base class from which to inherit.
If the class definition includes a 'CLASSNAME' property, this is used for logging (each class instance has its own 'log' function). Otherwise, a warning is generated.
If the class definition includes an 'init' function, this function becomes the class constructor, which is called when an instance is created (var instance_of_ClassA = new ClassA([args])).
All class functions are bound to the instance, including those embedded in data structures.
This module contains functions for logging, acquiring specific loggers, and filtering log output, as well as timing functions for profiling code.
In addition to the above functions and modules, the cantools bootstrapper provides a number of shims - fallback implementations of key functionality - for old browsers. These are required lazily, meaning that they are not included in production-compiled code, and they're only imported as needed (when missing from browser).
- JSON
- sessionStorage
- classList
- requestAnimationFrame
- Object.values
- addEventListener
This module contains functions for:
- structure comparison
- array manipulation
- object caching
- data acquisition
This module provides direct integration with the cantools.db backend via the _db.py request handler. Some key functions are defined below.
Return the schema for the named model.
Sets CT.db._schema, which includes every model in the database. This is called automatically by CT.db.init(), which acquires it from the backend.
Acquire the data set defined by the given query parameters, add it to CT.data's map, and pass it back via callback function (cb).
Acquire data objects corresponding to members of 'keys' array, add them to CT.data's map, and pass them back via callback function (cb).
Acquire data object corresponding to 'key' string, add it to CT.data's map, and pass it back via callback function (cb).
Acquire and set the database schema. Establish CT.db._opts object used by UI elements for querying database and adding/editing records. These include:
- builder (required):
- this generator function, given a modelName, returns a render callback
for internal use with CT.panel.pager().
- panel_key (default: 'db'):
- this optional string argument may be used to indicate the desired parent
node of a pager element (generated by CT.db.pager()).
- post_pager (optional):
- this function is called whenever a pager is generated via CT.db.pager().
This function generates a modal (CT.modal.Modal) containing a query node (CT.db.Query) constructed with opts. The modal appears onscreen with the indicated transition (defaults to 'none').
This function creates a pager node (CT.Pager [via CT.panel.pager()] refilled via CT.db.get() used in conjunction with modelName, order, filters). It then adds this node to a parent indicated by cnode or (if undefined) determined by k (which falls back to modelName) and panel_key (set by CT.db.init(), defaults to 'db'). Finally, if a 'post_pager' callback has already been defined by CT.db.init(), this callback is invoked, passing in key and modelName.
This submodule contains functions for building interface elements that enable direct creation and modification of database records. This includes the CT.db.edit.EntityRow class, of which such interfaces primarily consist.
This class (often used in conjunction with CT.modal.Modal) builds a DOM node containing the interface elements necessary to define a query against the specified table. The constructor takes an options object ('opts') with three possible entries:
- showHelp: indicates whether or not to show help strings in the query node
- default: false
- pagerPanelId: specifies parent node for pager generated by default submit
- default: 'dbqueries'
- submit: the function to call when the 'submit' button is clicked
- default: pager node is created and added to parent indicated by pagerPanelId
This module contains functions for interacting with the DOM. This includes:
- content - what goes in the resulting DOM node. may be:
- a node
- a function
- an object
- a string or number
- an array containing any of the above
- type - tag name of resulting DOM node
- classname - class of resulting DOM node
- id - id of resulting DOM node
- attrs - object defining miscellaneous properties of resulting DOM node
- style - object mapping CSS properties to values
All other node generators use CT.dom.node() under the hood. There are many. See code.
- 'all' is a bool indicating whether to also search free-floating nodes.
- 'n' is the node to search. defaults to document.
- 'n' is the node to search. defaults to document.
- executes querySelectorAll(q) on n (defaults to document)
- 'opts' object must include:
- property: CSS property to modify
- value: new value
- 'opts' object must include one of:
- target (node)
- targets (node array)
- className (string)
- id (string)
- use EITHER text, href, or obj
- text: raw CSS text
- href: url of stylesheet
- obj: object mapping selector strings to style definitions (specified
via embedded objects mapping CSS properties to values)
This module enables cross-platform, sometimes-native dragging, mostly via CT.gesture module. The principle function is makeDraggable(), used as follows:
This function makes the 'node' node draggable. The 'opts' object may contain any or all of the following options:
- constraint ('horizontal' or 'vertical'): prevents drags in indicated direction.
- interval (number): 'chunks' total drag area into sections, causing drags to
always settle on areas corresponding to multiples of 'interval',
and swipes to slide between such areas. if value is 'auto',
we use width / number_of_child_nodes.
- force (bool, default false): forces non-native scrolling.
- up, down, drag, scroll, swipe (functions): optional gesture callbacks.
This module provides functions and a class (CT.file.File) for messing with (accessing, uploading, downloading) file objects.
This module contains functions for registering cross-platform gesture callbacks. The main one to look out for is listen, defined below.
- eventName - one of: drag, swipe, tap, up, down, hold, pinch, hover, wheel
- node - the node to listen to
- cb - the function to call when something happens
- stopPropagation - whether to propagate this event beyond node
- preventDefault - whether to prevent default behavior
This module is all about hover nodes. Want a hover node? Well, use this module.
This module supports global key bindings.
This module provides functions that generate common UI elements. These include:
logo: "Placeholder Logo"
right: []
rightPadding: "30px" // non-centerLogo only!
centerLogo: true
img: null
panDuration: null (falls back to CT.dom.panImg() default of 5000)
logo: "Placeholder Logo"
links: []
contact: {}
img: null
panDuration: null (falls back to CT.dom.panImg() default of 5000)
columns: 3
rows: 4
className: "w2-3 h1 noflow abs"
buttons: []
parent: "ctmain"
listClass: "ctlist big"
contentClass: "ctcontent"
titleClass: "biggerest bold bottompadded"
content: null
listNode: null
listContent: null
activeClass: null
fallback: null
hashcheck: null
path: ""
nameCb: null // generates name node content, falls back to name
branches: {}
cb: function() {}
name: opts.title || "root"
className: "m5 p5 vtop centered pointer inline-block"
className: "ctform"
items: []
This module loads the Google Maps API via CT.scriptImport(), as well as a utility submodule (CT.map.util) and five classes:
- CT.map.Map
- CT.map.Node
- CT.map.Marker
- CT.map.Shape
- CT.map.Panorama
To facilitate key injection, we recommend loading this module dynamically, like so:
CT.setVal("mapkey", MY_MAP_KEY);
CT.require("CT.map", true);
This module provides direct integration with the cantools memcache service via the _memcache.py request handler. Some key functions are defined below.
Return the (server-side) value for the specified key.
Instruct the server to remember the specified key and value.
Instruct the server to forget the specified key and any associated value.
Return the (server-side) TTL and token for the specified key.
Instruct the server to associate a countdown (seconds in the future) and token (randomly-generated) with the specified key.
This module takes a website formatted for a regular computer screen and, via configuration, mobilizes it by zooming in on specific sections of the page and providing user interface elements for scaling/translating between components.
This module contains three classes, Modal, LightBox, and Prompt.
Creates a DOM node that can be transitioned on- and off- screen to/from a configurable position.
defaults: { className: "basicpopup", innerClass: "h1 w1 scroller", transition: "none", // none|fade|slide center: true, noClose: false, // turns off 'x' in corner onclick: null, slide: { // only applies if transition is 'slide' origin: "top" } }
Note that the optional 'slide' object -- which only applies when transition is 'slide' -- may include 'top', 'left', 'bottom', and 'right' properties. For any other transition (when center is false), please position your node via css class (specified via 'className' property).
Centered, almost-fullscreen, fade-in, image-backed modal with translucent backdrop.
defaults: { className: "backdrop mosthigh", innerClass: "lightbox", transition: "fade", caption: "", noClose: true, outerClose: true }
Includes interface elements for obtaining user input, such as a string, a password, or one or more selections from a list.
defaults: { className: "basicpopup mosthigh flex col", style: "string", // string|multiple-string|password|single-choice|multiple-choice|file|number|time|date|form|icon|phone|email|sound|reorder|draggers prompt: "", clear: false, // string/password only data: [] // only applies to choice styles }
Additionally, CT.modal includes several convenience functions:
- prompt: prompt the user for a string
- choice: offer several options
- modal: basic popup
- img: slide in an image
This module contains functions for generating lists of items that, when clicked, show corresponding content or trigger corresponding logic. Here are three examples.
This function wraps CT.panel.load(), supporting a subset of load()'s options (the simple ones). It supports the following args, of which only the first is required:
- pnames (string array): short for 'panel names'
- keystring (string, default: 'sb'): identifier for collections of content/lister nodes
- itemnode (node, default: CT.dom.id(keystring + "items")): parent node for lister items
- panelnode (node, default: CT.dom.id(keystring + "panels")): parent node for content panels
- cbs (function array, optional): callbacks to invoke on lister item click post- panel swap
This function generates and returns a node containing a (CT.Pager-backed) paging lister node and a corresponding content panel.
- getContent (function): combined with CT.panel.simple() in pager's renderCb
- request (function): pager's requestCb
- limit (number, default: 20): pager's limit (chunk size)
- colClass (string, optional): class of generated pager (list selector) node
- dataClass (string, optional): class of generated data (content panel) node
- ks (string, default: "p" + CT.Pager._id): keystring of data and list nodes
This function fills the 'node' node with a list of clickable items, each of which triggers cb(d), where d is the corresponding object in the 'data' array.
- data (object array): data set used to generate list
- for d in data: link content equals d.label || d.title
- cb (function): the callback to invoke when an item is clicked
- node (node): the list parent node
This module contains functions for manipulating and processing text. This includes:
Mainly, you'll just want to call CT.parse.process(c, simple, customArg).
- c (string)
- the text to process
- simple (bool)
- if true, uses simple link wrapping
- else (default), embeds images and invokes custom processor (if any)
- customArg (anything)
- passed to custom link processor, if any (for indicating some mode, for instance)
- normalizes whitespace
- formats and embeds links for phone numbers
- generates mailto links as necessary
- processes remaining links via url2link() or processLink() (switching on simple)
This is done through CT.parse.processLink(url, customArg).
- url: url to parse
- customArg: passed to custom processor, for instance, for disabling embedded video
- embeds images
- linkifies other links
- adds 0-width whitespace characters to line-break url strings as necessary
- via CT.parse.breakurl(url)
- supports custom link processing callbacks
- via CT.parse.setLinkProcessor(cb)
CT.parse.validEmail(s): returns bool
CT.parse.validPassword(s): returns bool
CT.parse.numOnly(n, allowDot, noNeg): returns n
- turn 'n' input into a field that only allows numbers
- allowDot and noNeg toggle decimals and negative #s
Various functions for deriving different types of information, such as phone numbers and zip codes, from text; reformatting recognizable strings and generating links (as in the case of phone numbers); case-modding, soft-truncating, and removing script blocks from text; and otherwise messing with strings. Also, CT.parse.timeStamp(datetime) goes a long way toward making timestamps meaningful to humans.
This module contains a class, CT.pay.Form, and an initialization function, CT.pay.init(). The module can function in two ways.
In conjunction with a tightly-coupled backend component (_pay.py), this module provides integration with the Braintree payment platform, which supports:
- PayPal
- Credit Cards
- Venmo
- Apple Pay
- Android Pay
- Bitcoin?
Use it like this:
CT.pay.init({
mode: "braintree",
cb: function() {
new CT.pay.Form({
parent: pnode
});
}
});
To use the CC api, do something like this:
CT.pay.init({
mode: "cc",
cb: function() {
new CT.pay.Form({
parent: pnode,
item: {
amount: 1.2,
notes: "these are some notes",
membership: "VENDOR_MEMBERSHIP_KEY"
}
});
}
});
This module provides a direct interface with the ctpubsub backend. Here's how to use it.
CT.pubsub.connect(host, port, uname)
CT.pubsub.publish(channel, message)
CT.pubsub.subscribe(channel)
CT.pubsub.unsubscribe(channel)
CT.pubsub.meta(channel, meta)
CT.pubsub.chmeta(channel, meta, nomerge)
CT.pubsub.pm(user, message)
CT.pubsub.set_cb(action, cb)
CT.pubsub.set_reconnect(bool)
CT.pubsub.isInitialized() (returns bool)
This module provides functions, build() and submit(), for messing around with recaptcha botwalls.
TODO: this functionality requires backend integration - include complementary python module!
This module provides two functions, wysiwygize() and qwiz(), which both convert textareas (identified by id) into rich text editors.
- nodeid: id of target textarea (must exist in DOM)
- isrestricted: if true, disables media insertion
- val: string value with which to initialize target text area
- cb: callback to invoke once textarea is initialized
- mismatchcb: callback to invoke if the reformatted text doesn't match val
- tables: if true, include stuff for tables
- nodeid: id of target textarea (must exist in DOM)
- val: string value with which to initialize target text area
CT.rte.qwiz() just builds a simplified (isrestricted=true) rich text area after first waiting for the nodeid-indicated node to appear in the DOM.
CT.rte requires the open-source TinyMCE library, pulled in via CT.scriptImport().
This class is used to generate a slider, which is a segmented, directionally-constrained draggable DOM element.
The CT.slider.Slider constructor takes an options object, 'opts', which may define any of several properties. These individual properties, as well as the 'opts' object itself, are all optional.
- parent (default: document.body): DOM element in which to build the slider
- mode (default: 'peekaboo'): how to display each frame - 'peekaboo', 'chunk', 'menu', 'profile', or 'track'
- subMode (default: 'peekaboo'): which mode to use for chunk-mode frames ('peekaboo', 'menu', 'profile', 'track', 'custom')
- frameCb (default: null): frame generation callback ('custom' mode)
- defaultImg (default: undefined): fallback img for any frame mode
- img (default: undefined): panning background image for whole slider. also works per-chunk.
- tab (default: undefined): little thing to the side of the frame
- arrow (default: null): image for pointer arrow (falls back to pointy brackets)
- autoSlideInterval (default: 5000): how many milliseconds to wait before auto-sliding frames
- panDuration (default: autoSlideInterval): pan duration for background images
- translateDuration (default: 300): translation duration for frame advancement transition
- autoSlide (default: true): automatically proceed through frames (else, trigger later with .resume())
- visible (default: true): maps to visibility css property
- navButtons (default: true): include nav bubbles and arrows
- circular (default: false): allow shifting between 1st and last frames w/ nav buttons (arrows)
- pan (default: true): slow-pan frame background images
- translucentTeaser (default: true): translucent box around teaser text (otherwise opaque)
- startFrame (default: null): label (or index if frames are unlabeled) of frame to slide to initially (disables autoSlide)
- noStyle (default: false): if true, prevent carousel from overriding color/background rules
- bubblePosition (default: 'bottom'): where to position frame indicator bubbles ('top' or 'bottom')
- arrowPosition (default: 'middle'): where to position navigator arrows
- orientation (default: 'horizontal'): orientation for slider frames to arrange themselves
- keys (default: true): use arrow keys to navigate slider, as well as enter key for peekaboo transitions
- noEnter (default: false): disable enter key for peekaboo transitions
- frames (default: []): an array of items corresponding to the frames in the slider
- shuffle (default: false): for chunk mode, especially track subMode (randomize playlist) and autoSlide
The last one, 'frames', must be an array either of strings (interpreted as image urls) or of data objects (processed in the addFrame function).
This module provides an abstraction layer over a storage backend.
- CT.storage.get(key)
- CT.storage.set(key, val)
- CT.storage.clear()
- backend (one of: localStorage, sessionStorage) - default: localStorage
- json (bool) - default: true
- compress (bool) - default: true
Why call init(), you ask? Well, if 'compress' is true, the storage module needs to lazily import CT.lib.lz-string. Could be different, but there it is.
This module provides functions and classes for streaming video all over town.
Highlights include:
Starts up a video stream from your webcam. Breaks stream into segments as defined by CT.stream.opts.chunk (default 1000) and CT.stream.opts.segments (default 10).
Uses WebSocket pubsub server (ctpubsub/CT.pubsub) to manage multiple channels, each streaming metadata pertaining to multiple videos, over a single connection. The video segments are acquired from the server with the CT.memcache module and passed to individual CT.stream.Video instances.
Wraps an HTML5 video tag in a class with functions for streaming a video that arrives in chunks.
This module provides convenience functions for messing around with DOM elements via CSS transitions. Have at it.
CT.trans.rotate(node, opts)
CT.trans.translate(node, opts)
CT.trans.wobble(node, opts)
CT.trans.pan(node, opts, wait)
CT.trans.resize(node, opts)
CT.trans.fadeIn(node, opts)
CT.trans.fadeOut(node, opts)
CT.trans.pulse(node, opts)
CT.trans.trans(opts)
CT.trans.setVendorPrefixed(node, property, value)
- sets CSS properties for all vendor prefixes
- [ "-webkit-", "-moz-", "-ms-", "-o-", "" ]
trans: {
duration: 500,
property: "*",
ease: "ease-in-out"
},
rotate: {
degrees: 180,
duration: 1000,
property: "transform",
ease: "linear",
prefix: true
},
translate: {
duration: 300,
property: "transform",
ease: "linear",
prefix: true,
x: 0,
y: 0,
z: 0
},
wobble: {
axis: "x",
radius: 50,
duration: 100
},
pan: {
duration: 5000,
ease: "linear",
x: 0,
y: 0
},
resize: {
duration: 300,
ease: "linear"
},
fadeIn: {
duration: 1600,
property: "opacity",
value: 1
},
fadeOut: {
duration: 1600,
property: "opacity",
value: 0
},
pulse: {
wait: 1000
},
invert: {
direction: "horizontal", // or vertical
property: "transform",
prefix: true
}
TODO: let's add some more, like scale.
Certain functions (pan() and pulse()) return a CT.trans.Controller instance.
pause() - stop the transition (for now)
resume() - resume the transition
active() - returns status of transition (bool)
tick() - calls cb() if active()
init(cb) - cb() is called by tick() if active()
This module supports file uploads.
- uid: user id (if any)
- kval: upload key (if any)
- sbutton: submit button (if any)
- isize: input size (in characters)
- f: input field
- success: upload success callback
- failure: upload failure callback
- iskey: whether a key is expected as the return value
This module lazily imports CT.lib.aim (in submit()).
TODO: remove/replace uid/kval/iskey -- too application-specific
This module supports video playback.
We support DTube, BitChute, Rumble, Odysee, lbryplayer, UGETube, GabTV, Vimeo, YouTube, Google Video, Facebook, and uStream.
We support mp4, ogg, webm, and mov.
Typically, you'll want to use the fit() function.
- returns stringified html for a video node fitting snugly inside its parent