mmo-kanban
1 symbol · generated 5 Oct 2026
mmo-kanban
mmo-kanban.jhs:1A project board in the manner of GitHub Projects: tickets seen as a board, as a tree-shaped list or as a timeline (a Gantt chart drawing the constraints between tickets).
- Extends
- CustomShadowElement
Index
| mode | what is shown: board (default), list or timeline | |
| group | what the board's columns are made from: status (default), label or category | |
| zoom | the timeline's scale: day, week (default) or month | |
| readonly | nothing can be moved or edited | |
| lenient | a move that breaks a constraint is made anyway, with a warning, instead of refused | |
| busy | the board waits on its data, or on a save: a spinner says so, with the attribute's text if it has one (busy="Saving…"). | |
| MODES static | ||
| SCALES static | pixels per day, by zoom | |
| ROW static | the timeline's geometry: header, row and bar heights | |
| HEAD static | ||
| BAR static | ||
| GROUPS static | ||
| STATUSES static | ||
| TYPES static | ||
| AGENTS static | the languages of a description's fenced block that make it an AI prompt: an agent's name, ai for any | |
| COLORS static | the colours a status, a label or a category can take: the theme's, so they follow it into the dark | |
| ICONS static | the icons the settings offer | |
| TYPE_LOOKS static | a status's look by its type, until it has its own | |
| EDITOR_WIDTH static | the width a ticket's panel asks the application for, in pixels: the user's own wins | |
| EDITOR_COMPACT static | below this width an editor is one column, its properties above the rest | |
| CONDITIONS static | the conditions, by type: what the editor calls them and what kind of value they take | |
| OPS static | ||
| ORDERS static | the orders a discussion is shown in | |
| THREAD_DEPTH static | a reply deeper than this is shown at this depth, saying whom it answers | |
| ViewDefault static readonly accessor | ||
| mode accessor | What is shown: board, list or timeline. | |
| group accessor | What the board's columns are made from: status, label or category. | |
| zoom accessor | The timeline's scale: day, week or month. | |
| readonly accessor | Whether nothing can be moved or edited. | |
| lenient accessor | Whether a move breaking a constraint is made anyway (with a warning). | |
| busy accessor | Whether the board waits on its data, or on a save: true, or what it waits on ('Saving to GitHub…'). | |
| data accessor | The board's data: a copy of its statuses, labels, categories and tickets. | |
| discussion accessor | Where the tickets' discussions are: {load, add, update, remove} (the class's documentation), or null for none. | |
| prompts(text) static | The AI prompts of a ticket's description: as MMO.core.markdown reads a fence, and KanbanPrompts::Extract on the server -- a block nested in another fence is text. | |
| constructor() | ||
| init() | ||
| isSaving(id) | Whether a ticket waits on a save: it cannot be changed until it is over (busy). | |
| refuseSaving(id) | refuse a change of a ticket being saved, saying so: true when refused | |
| drawLocks() | show which tickets are being saved: their cards, rows and bars, and their editors (busy) | |
| drawBusy() | show, or hide, what says the board is busy (busy) | |
| load(data) | Replace the board's data. | |
| configure(lists) | Set the board's statuses, labels and categories, from lists of objects or of names. | |
| lookOf(item) | ||
| learnLabels(tickets) | the labels used by tickets and not known yet join the board's | |
| isOn(value) | ||
| normalizeTicket(t) | Make a ticket the board can use, whatever it was given. | |
| normalizeConstraint(node) | Make a condition tree the board can use: an array is an AND, an unknown type is dropped. | |
| index() | rebuild the lookups after a change of this.tickets | |
| childrenOf(tickets) | ||
| nextId() | ||
| isAncestor(ancestor, id) | Whether a ticket is an ancestor of another (or the same). | |
| statusType(id) | ||
| defaultStatus() | the status of a new ticket: the first that is not the backlog, when there is one before work starts | |
| toDay(value) | ────────────────────────────────────────────── Dates: days are 'YYYY-MM-DD' strings, events are local 'YYYY-MM-DDTHH:MM:SS' stamps ────────────────────────────────────────────── | |
| localDay(date) | ||
| now() | ||
| dayNumber(day) | ||
| dayString(n) | ||
| formatDay(day) | ||
| compareTime(a, b) | Compare two times at the precision of the less precise: a day against a stamp compares the days. | |
| world(tickets, now) | The world a constraint is checked in: tickets, their lookups and the time. | |
| isDone(t) | ||
| isStarted(t) | ||
| evaluate(node, b, world, mode) | Evaluate a condition tree for a ticket. | |
| stateTicket(type, a, b) | a condition on another ticket, against what happened | |
| planTicket(type, a, b) | a condition on another ticket, against the planned dates | |
| stateDate(node, b, world) | a condition on a date, against what happened: an event not yet happened may still keep it | |
| planDate(node, b) | a condition on a date, against the planned dates | |
| fullConstraint(t, world) | A ticket's whole constraint: its own, and being part of its parent. | |
| violations(tickets, now) | The tickets whose constraint is broken. | |
| attempt(mutate) | Try a change on a copy of the tickets: what it would break. | |
| commit(mutate, moved) | Make a change, unless it breaks a constraint (and the board is not lenient). | |
| whyBlocked(t) | Why a ticket cannot go to its next step (start, or be done), if it cannot. | |
| describe(node, world, nested) | Describe a condition tree in words. | |
| failing(node, b, world, mode) | Describe what makes a condition tree false: the items of an AND that are, the rest whole. | |
| shorten(text, length) | ||
| leaves(node, negated, alternative, found) | The conditions of a tree that name another ticket or a date, with how they are reached. | |
| prune(node, id) | Remove the conditions naming a ticket. | |
| setStatus(t, status, now) | Give a ticket a status, stamping when it started and was done. | |
| moveTicket(id, group, to, beforeId, from) | Drop a ticket in a column of the board: give it that column's status, label or category, and put it before another ticket. | |
| addTicket(ticket) | Add a ticket. | |
| updateTicket(id, changes) | Change a ticket's fields (a new status stamps it as a move does). | |
| removeTicket(id) | Remove a ticket: its sub-tickets go to its parent, and the conditions naming it go. | |
| schedule() | refresh once, after whatever else changes now | |
| refresh() | ||
| matchesFilter(t) | whether a ticket matches the filter | |
| look(kind, item) | How a status, a label or a category looks: its own colour and icon, or its kind's. | |
| labelItem(id) | ||
| badge(kind, item, text) | A status, a label or a category as a pill, in its colour, with its icon. | |
| person(person, css) | Someone, as a picture (or initials) and a name. | |
| assignable() | ||
| icon(name, css, title) | ||
| stateIcon(t) | the state of a ticket, as an icon: broken, blocked, done | |
| columnsFor(group) | The board's columns for a grouping: one per status, label or category — and, for labels and categories, one first for the tickets that have none. | |
| renderBoard(world) | ||
| mark(col) | what stands for a column before its name: its icon, in its colour, or a dot | |
| scrollToColumn(id) | bring a column of the board into sight | |
| markVisibleColumn() | the strip of columns says which one is in sight | |
| card(t, world, col) | ||
| onCardKey(event, t, col) | Enter opens a card; Alt+arrows move it across columns and within its column | |
| placePlaceholder(cards, clientY) | the gap a dragged card shows where it would land, in a column at a height of the screen | |
| placeholderNext() | the ticket the dragged card goes before: the card after the gap, null for the end | |
| clearDropMarks() | ||
| wireDrop(cards, group, col) | a column's cards take the dragged one, at the place the pointer shows | |
| wireTouchDrag(card, t, col) | Drag a card with a finger: a long press picks it up (a quick swipe still scrolls), it follows the finger, the board scrolls when it nears an edge, and it drops in the column under it — or on a colu… | |
| startTouchDrag(card, t, col, start) | ||
| moveTouchDrag(drag) | ||
| endTouchDrag(drag, cancelled) | ||
| scrollParent() | the box the page scrolls in, through the shadow roots and slots this element sits in | |
| quickAddFooter(col) | ||
| rows(world) | The tickets in tree order, as rows: the filtered ones and their ancestors, below an unfolded parent. | |
| toggle(id) | ||
| toggleButton(row) | ||
| renderList(world) | ||
| renderTimeline(world) | ||
| route(from, to, kind) | The path of an arrow between two bars, in right angles. | |
| wireBars(svg, bars, px) | a bar is moved by its body and resized by its ends, a day at a time | |
| edit(id, defaults) | Open a ticket, or a new one, in the side panel of the application (<mmo-app>): a tab per ticket, the same ticket twice shows its tab again. | |
| usesPanels() | whether tickets open in the application's side panel (its tabbed one) rather than in a dialog | |
| panelKey(id) | a panel's key: the same ticket of the same board is one panel | |
| editorTitle(editor) | ||
| refreshEditors() | Draw the open editors again after a change of the board: the ones with changes not saved are left as they are, the ones whose ticket is gone close. | |
| lockEditor(editor) | An editor whose ticket is being saved waits for it: its fields cannot be reached, and it says why (busy). | |
| closeEditor(editor) | close an editor: its panel, or the dialog | |
| renderEditor(editor) | Draw an editor: its tabs (the ticket, its discussion), and the ticket's form -- its text on the left, its properties on the right, picked from dropdowns. | |
| drawTabs(editor) | The tabs of an editor -- the ticket, its discussion -- drawn again when the count of comments changes; only an existing ticket with a discussion has them. | |
| isCompact(editor) | whether an editor is too narrow for two columns | |
| watchEditorWidth(editor) | an editor goes to one column, and back, as its panel or its dialog is resized | |
| dropdown(box, button, pop, onOpen) | A popover that opens under its button, and closes on Escape or on a click anywhere else. | |
| picker(spec) | A dropdown to pick a value, or several: a button showing what is picked, and a list to pick from, filtered by what is typed in it. | |
| lookPicker(kind, item) | The colour and the icon of a status, a label or a category, in the board's settings: a button showing them, and a popover to pick them. | |
| descriptionEditor(t, ro, bind) | The description of a ticket: markdown, in <mmo-markdown-editor> (a plain textarea when the page does not have it). | |
| addTriggers(editor, id, people) | # suggests the board's tickets, @ the people: the ones tickets are assigned to, and more. | |
| discussionSection(editor) | Start the discussion of an editor's ticket: its state lives in editor.talk, its section is drawn by | |
| canComment() | whether the viewer may write in the discussions | |
| loadDiscussion(editor) async | (Re)load the comments of an editor's ticket. | |
| normalizeComment(c) | ||
| countComments(editor) | the card says how many comments its ticket has | |
| drawDiscussion(editor) | Draw an editor's discussion: its header (the count, the order, reload), its comments, and the editor of a new one. | |
| commentList(editor) | The comments, in the viewer's order: by date, or in threads -- a reply under what it answers, a reply to a comment that is gone starting a thread of its own. | |
| commentNode(editor, c, byId, sayParent) | A comment: who wrote it and when, what it says, and what the viewer can do with it. | |
| commentEditor(editor, kind, target) | The editor of a comment: a new one, a reply, or a change of one's own. | |
| focusComposer(editor, key) | put the caret in a comment's editor, once it is drawn | |
| sendComment(editor, kind, target) async | Send what a comment's editor holds: a new comment, a reply, or a change. | |
| removeComment(editor, c) async | Delete one's own comment, once asked: its replies stay, answering a deleted comment. | |
| showComment(editor, id) | scroll to a comment of the discussion, and make it flash | |
| setDiscussionOrder(order) | ||
| storedOrder() | ||
| ago(date) | ||
| fullDate(date) | ||
| initials(name) | ||
| conditionEditor(t, node, set, redraw, preview, root) | The editor of one condition, and of the ones it holds. | |
| newCondition(t) | ||
| convertCondition(t, node, type) | a condition turned into another type, keeping what both share | |
| save(t, isNew) | Save a ticket being edited. | |
| configureBoard(lists) | Change the board's statuses, labels and categories. | |
| editSettings() | Open the board's settings: its statuses, labels and categories. | |
| confirmRemove(id, editor) async | ||
| notify(title, lines, tone) | Say something for a while, under the toolbar. | |
| (default) | a <script type="application/json"> holding the board's data |
Attributes6
mode
mmo-kanban.jhswhat is shown: board (default), list or timeline
mode="board"
group
mmo-kanban.jhswhat the board's columns are made from: status (default), label or category
group="status"
zoom
mmo-kanban.jhsthe timeline's scale: day, week (default) or month
zoom="week"
readonly
mmo-kanban.jhsnothing can be moved or edited
readonly
lenient
mmo-kanban.jhsa move that breaks a constraint is made anyway, with a warning, instead of refused
lenient
busy
mmo-kanban.jhsthe board waits on its data, or on a save: a spinner says so, with the attribute's text if it has one (busy="Saving…"). Without a ticket yet, it stands in for the board. The tickets changed since it was last busy are the ones being saved: until it is not, they cannot be moved, edited or deleted, and say so
busy
Constants18
MODES
staticmmo-kanban.jhs:150SCALES
staticmmo-kanban.jhs:153pixels per day, by zoom
ROW
staticmmo-kanban.jhs:156the timeline's geometry: header, row and bar heights
HEAD
staticmmo-kanban.jhs:157BAR
staticmmo-kanban.jhs:158GROUPS
staticmmo-kanban.jhs:160STATUSES
staticmmo-kanban.jhs:162TYPES
staticmmo-kanban.jhs:170AGENTS
staticmmo-kanban.jhs:173the languages of a description's fenced block that make it an AI prompt: an agent's name, ai for any
COLORS
staticmmo-kanban.jhs:201the colours a status, a label or a category can take: the theme's, so they follow it into the dark
ICONS
staticmmo-kanban.jhs:214the icons the settings offer
TYPE_LOOKS
staticmmo-kanban.jhs:224a status's look by its type, until it has its own
EDITOR_WIDTH
staticmmo-kanban.jhs:231the width a ticket's panel asks the application for, in pixels: the user's own wins
EDITOR_COMPACT
staticmmo-kanban.jhs:234below this width an editor is one column, its properties above the rest
CONDITIONS
staticmmo-kanban.jhs:237the conditions, by type: what the editor calls them and what kind of value they take
OPS
staticmmo-kanban.jhs:249ORDERS
staticmmo-kanban.jhs:2842the orders a discussion is shown in
THREAD_DEPTH
staticmmo-kanban.jhs:2845a reply deeper than this is shown at this depth, saying whom it answers
Properties9
ViewDefault
staticreadonlyaccessormmo-kanban.jhs:251mode
accessormmo-kanban.jhs:326What is shown: board, list or timeline.
- Type
string
group
accessormmo-kanban.jhs:341What the board's columns are made from: status, label or category.
- Type
string
zoom
accessormmo-kanban.jhs:359The timeline's scale: day, week or month.
- Type
string
readonly
accessormmo-kanban.jhs:375Whether nothing can be moved or edited.
- Type
boolean
lenient
accessormmo-kanban.jhs:388Whether a move breaking a constraint is made anyway (with a warning).
- Type
boolean
busy
accessormmo-kanban.jhs:400Whether the board waits on its data, or on a save: true, or what it waits on ('Saving to GitHub…').
- Type
boolean
data
accessormmo-kanban.jhs:470The board's data: a copy of its statuses, labels, categories and tickets.
- Type
object
discussion
accessormmo-kanban.jhs:483Where the tickets' discussions are: {load, add, update, remove} (the class's documentation), or null for none.
- Type
?object
Methods126
prompts(text)
staticmmo-kanban.jhs:182The AI prompts of a ticket's description: as MMO.core.markdown reads a fence, and KanbanPrompts::Extract on the server -- a block nested in another fence is text.
| text | string | - markdown |
| returns | Array<{agent: string, info: string, prompt: string, line: number | >} in its order; line from 1 |
constructor()
mmo-kanban.jhs:255init()
mmo-kanban.jhs:291isSaving(id)
mmo-kanban.jhs:426Whether a ticket waits on a save: it cannot be changed until it is over (busy).
| id | string | |
| returns | boolean |
refuseSaving(id)
mmo-kanban.jhs:431refuse a change of a ticket being saved, saying so: true when refused
| id |
drawLocks()
mmo-kanban.jhs:438show which tickets are being saved: their cards, rows and bars, and their editors (busy)
drawBusy()
mmo-kanban.jhs:458show, or hide, what says the board is busy (busy)
load(data)
mmo-kanban.jhs:504Replace the board's data.
| data | object | - {statuses, labels, categories, tickets}; a list left out keeps the current one |
| returns | void |
configure(lists)
mmo-kanban.jhs:529Set the board's statuses, labels and categories, from lists of objects or of names.
| lists | object | - {statuses, labels, categories}; a list left out is kept |
| returns | void |
lookOf(item)
mmo-kanban.jhs:556| item | object | - a status, a label or a category, as given |
| returns | object | its color and icon, the ones it has |
learnLabels(tickets)
mmo-kanban.jhs:564the labels used by tickets and not known yet join the board's
| tickets |
isOn(value)
mmo-kanban.jhs:576| value |
normalizeTicket(t)
mmo-kanban.jhs:585Make a ticket the board can use, whatever it was given.
| t | object | |
| returns | object |
normalizeConstraint(node)
mmo-kanban.jhs:616Make a condition tree the board can use: an array is an AND, an unknown type is dropped.
| node | * | |
| returns | ?object |
index()
mmo-kanban.jhs:632rebuild the lookups after a change of this.tickets
childrenOf(tickets)
mmo-kanban.jhs:637| tickets |
nextId()
mmo-kanban.jhs:649isAncestor(ancestor, id)
mmo-kanban.jhs:664Whether a ticket is an ancestor of another (or the same).
| ancestor | string | |
| id | string | |
| returns | boolean |
statusType(id)
mmo-kanban.jhs:674| id |
defaultStatus()
mmo-kanban.jhs:679the status of a new ticket: the first that is not the backlog, when there is one before work starts
toDay(value)
mmo-kanban.jhs:687────────────────────────────────────────────── Dates: days are 'YYYY-MM-DD' strings, events are local 'YYYY-MM-DDTHH:MM:SS' stamps ──────────────────────────────────────────────
| value |
localDay(date)
mmo-kanban.jhs:694| date |
now()
mmo-kanban.jhs:698dayNumber(day)
mmo-kanban.jhs:703| day |
dayString(n)
mmo-kanban.jhs:708| n |
formatDay(day)
mmo-kanban.jhs:712| day |
compareTime(a, b)
mmo-kanban.jhs:721Compare two times at the precision of the less precise: a day against a stamp compares the days.
| a | ||
| b | ||
| returns | ?number | <0, 0, >0, or null when one is unknown |
world(tickets, now)
mmo-kanban.jhs:737The world a constraint is checked in: tickets, their lookups and the time.
| tickets | object[] | |
| now = this.now() | ||
| returns | object |
isDone(t)
mmo-kanban.jhs:741| t |
isStarted(t)
mmo-kanban.jhs:745| t |
evaluate(node, b, world, mode)
mmo-kanban.jhs:759Evaluate a condition tree for a ticket.
| node | ?object | - the condition |
| b | object | - the ticket holding it |
| world | object | - world |
| mode = 'state' | string | - state or plan |
| returns | ?boolean | true, false, or null when it cannot be told (yet) |
stateTicket(type, a, b)
mmo-kanban.jhs:798a condition on another ticket, against what happened
| type | ||
| a | ||
| b |
planTicket(type, a, b)
mmo-kanban.jhs:819a condition on another ticket, against the planned dates
| type | ||
| a | ||
| b |
stateDate(node, b, world)
mmo-kanban.jhs:839a condition on a date, against what happened: an event not yet happened may still keep it
| node | ||
| b | ||
| world |
planDate(node, b)
mmo-kanban.jhs:855a condition on a date, against the planned dates
| node | ||
| b |
fullConstraint(t, world)
mmo-kanban.jhs:867A ticket's whole constraint: its own, and being part of its parent.
| t | object | |
| world | object | |
| returns | ?object |
violations(tickets, now)
mmo-kanban.jhs:880The tickets whose constraint is broken.
| tickets | object[] | |
| now | string | |
| returns | Map<string, string> | id => why |
attempt(mutate)
mmo-kanban.jhs:897Try a change on a copy of the tickets: what it would break.
| mutate | function(object[], string):void | - changes the copy it is given, at the time it is given |
| returns | next: object[], broken: string[] | } |
commit(mutate, moved)
mmo-kanban.jhs:917Make a change, unless it breaks a constraint (and the board is not lenient).
| mutate | function(object[], string):void | |
| moved = [] | string[] | - the tickets it moves, which their fields do not say |
| returns | ok: boolean, reasons: string[] | } |
whyBlocked(t)
mmo-kanban.jhs:950Why a ticket cannot go to its next step (start, or be done), if it cannot.
| t | object | |
| returns | string[] | the constraints it would break, empty when it can |
describe(node, world, nested)
mmo-kanban.jhs:968Describe a condition tree in words.
| node | ?object | |
| world = this.world(this.tickets) | object | |
| nested = false | boolean | - whether it sits in another, which a group is parenthesised in |
| returns | string |
failing(node, b, world, mode)
mmo-kanban.jhs:998Describe what makes a condition tree false: the items of an AND that are, the rest whole.
| node | ||
| b | ||
| world | ||
| mode = 'state' | ||
| returns | string[] |
shorten(text, length)
mmo-kanban.jhs:1005| text | ||
| length |
leaves(node, negated, alternative, found)
mmo-kanban.jhs:1014The conditions of a tree that name another ticket or a date, with how they are reached.
| node | ?object | |
| negated = false | ||
| alternative = false | ||
| found = [] | ||
| returns | object[] | [{node, negated, alternative}] |
prune(node, id)
mmo-kanban.jhs:1029Remove the conditions naming a ticket.
| node | ||
| id | ||
| returns | ?object | what is left of the tree |
setStatus(t, status, now)
mmo-kanban.jhs:1055Give a ticket a status, stamping when it started and was done.
| t | object | - the ticket, changed in place |
| status | string | |
| now | string |
moveTicket(id, group, to, beforeId, from)
mmo-kanban.jhs:1080Drop a ticket in a column of the board: give it that column's status, label or category, and put it before another ticket.
| id | string | |
| group | string | - what the columns are made from: status, label or category |
| to | ?string | - the column: a status, a label or a category id; null for "no label/category" |
| beforeId = null | ?string | - the ticket it goes before, null for the end |
| from = null | ?string | - the label it leaves, for label (a ticket is in a column per label it has) |
| returns | ok: boolean, reasons: string[] | } |
addTicket(ticket)
mmo-kanban.jhs:1139Add a ticket.
| ticket | object | - its fields; status defaults to the first "not started" one after the backlog |
| returns | ok: boolean, reasons: string[], id: string | } |
updateTicket(id, changes)
mmo-kanban.jhs:1154Change a ticket's fields (a new status stamps it as a move does).
| id | string | |
| changes | object | |
| returns | ok: boolean, reasons: string[] | } |
removeTicket(id)
mmo-kanban.jhs:1185Remove a ticket: its sub-tickets go to its parent, and the conditions naming it go.
| id | string | |
| returns | ok: boolean, reasons: string[] | } |
schedule()
mmo-kanban.jhs:1202refresh once, after whatever else changes now
refresh()
mmo-kanban.jhs:1211matchesFilter(t)
mmo-kanban.jhs:1245whether a ticket matches the filter
| t |
look(kind, item)
mmo-kanban.jhs:1261How a status, a label or a category looks: its own colour and icon, or its kind's.
| kind | string | - status, label or category |
| item | ?object | |
| returns | tone: string, icon: ?string | } a css colour, and an icon name (a label has none unless given one) |
labelItem(id)
mmo-kanban.jhs:1283| id | ||
| returns | object | a label of the board, or what stands for one it does not know |
badge(kind, item, text)
mmo-kanban.jhs:1294A status, a label or a category as a pill, in its colour, with its icon.
| kind | string | - status, label or category |
| item | object | |
| text = null | ?string | - what it says, its label by default |
| returns | HTMLElement |
person(person, css)
mmo-kanban.jhs:1306Someone, as a picture (or initials) and a name.
| person | object | - {id, label, avatar} |
| css = '' | string | |
| returns | HTMLElement |
assignable()
mmo-kanban.jhs:1316| returns | object[] | who a ticket can be assigned to: the board's people, and whoever tickets are assigned to |
icon(name, css, title)
mmo-kanban.jhs:1324| name | ||
| css = 'xs' | ||
| title = null |
stateIcon(t)
mmo-kanban.jhs:1331the state of a ticket, as an icon: broken, blocked, done
| t |
columnsFor(group)
mmo-kanban.jhs:1346The board's columns for a grouping: one per status, label or category — and, for labels and categories, one first for the tickets that have none.
| group | string | - status, label or category |
| returns | object[] | [{key, id, label, css, limit, defaults, has(ticket), tone, icon}] |
renderBoard(world)
mmo-kanban.jhs:1366| world |
mark(col)
mmo-kanban.jhs:1431what stands for a column before its name: its icon, in its colour, or a dot
| col |
scrollToColumn(id)
mmo-kanban.jhs:1436bring a column of the board into sight
| id |
markVisibleColumn()
mmo-kanban.jhs:1443the strip of columns says which one is in sight
card(t, world, col)
mmo-kanban.jhs:1462| t | ||
| world | ||
| col |
onCardKey(event, t, col)
mmo-kanban.jhs:1554Enter opens a card; Alt+arrows move it across columns and within its column
| event | ||
| t | ||
| col |
placePlaceholder(cards, clientY)
mmo-kanban.jhs:1583the gap a dragged card shows where it would land, in a column at a height of the screen
| cards | ||
| clientY |
placeholderNext()
mmo-kanban.jhs:1604the ticket the dragged card goes before: the card after the gap, null for the end
clearDropMarks()
mmo-kanban.jhs:1611wireDrop(cards, group, col)
mmo-kanban.jhs:1617a column's cards take the dragged one, at the place the pointer shows
| cards | ||
| group | ||
| col |
wireTouchDrag(card, t, col)
mmo-kanban.jhs:1646Drag a card with a finger: a long press picks it up (a quick swipe still scrolls), it follows the finger, the board scrolls when it nears an edge, and it drops in the column under it — or on a column's name in the strip above a narrow board.
| card | ||
| t | ||
| col |
startTouchDrag(card, t, col, start)
mmo-kanban.jhs:1688| card | ||
| t | ||
| col | ||
| start |
moveTouchDrag(drag)
mmo-kanban.jhs:1724| drag |
endTouchDrag(drag, cancelled)
mmo-kanban.jhs:1744| drag | ||
| cancelled |
scrollParent()
mmo-kanban.jhs:1766the box the page scrolls in, through the shadow roots and slots this element sits in
quickAddFooter(col)
mmo-kanban.jhs:1777| col |
rows(world)
mmo-kanban.jhs:1816The tickets in tree order, as rows: the filtered ones and their ancestors, below an unfolded parent.
| world | ||
| returns | object[] | [{ticket, depth, hasChildren}] |
toggle(id)
mmo-kanban.jhs:1839| id |
toggleButton(row)
mmo-kanban.jhs:1845| row |
renderList(world)
mmo-kanban.jhs:1858| world |
renderTimeline(world)
mmo-kanban.jhs:1907| world |
route(from, to, kind)
mmo-kanban.jhs:2139The path of an arrow between two bars, in right angles.
| from | number[] | - [x, y] |
| to | number[] | - [x, y] |
| kind | string | - fs end to start, ff end to end, ss start to start |
| returns | string |
wireBars(svg, bars, px)
mmo-kanban.jhs:2159a bar is moved by its body and resized by its ends, a day at a time
| svg | ||
| bars | ||
| px |
edit(id, defaults)
mmo-kanban.jhs:2230Open a ticket, or a new one, in the side panel of the application (<mmo-app>): a tab per ticket, the same ticket twice shows its tab again. Outside an application, in a dialog.
| id | ?string | - null for a new ticket |
| defaults = {} | object | - the fields of a new ticket (status, parent…) |
| returns | void |
usesPanels()
mmo-kanban.jhs:2271whether tickets open in the application's side panel (its tabbed one) rather than in a dialog
panelKey(id)
mmo-kanban.jhs:2276a panel's key: the same ticket of the same board is one panel
| id |
editorTitle(editor)
mmo-kanban.jhs:2280| editor |
refreshEditors()
mmo-kanban.jhs:2288Draw the open editors again after a change of the board: the ones with changes not saved are left as they are, the ones whose ticket is gone close.
lockEditor(editor)
mmo-kanban.jhs:2308An editor whose ticket is being saved waits for it: its fields cannot be reached, and it says why (busy).
| editor | object |
closeEditor(editor)
mmo-kanban.jhs:2319close an editor: its panel, or the dialog
| editor |
renderEditor(editor)
mmo-kanban.jhs:2331Draw an editor: its tabs (the ticket, its discussion), and the ticket's form -- its text on the left, its properties on the right, picked from dropdowns. The form is drawn again on every refresh of the board; the discussion only once (discussionSection), so what is being typed in it stays.
| editor | object | |
| returns | void |
drawTabs(editor)
mmo-kanban.jhs:2535The tabs of an editor -- the ticket, its discussion -- drawn again when the count of comments changes; only an existing ticket with a discussion has them.
| editor | object | |
| returns | void |
isCompact(editor)
mmo-kanban.jhs:2563whether an editor is too narrow for two columns
| editor |
watchEditorWidth(editor)
mmo-kanban.jhs:2569an editor goes to one column, and back, as its panel or its dialog is resized
| editor |
dropdown(box, button, pop, onOpen)
mmo-kanban.jhs:2587A popover that opens under its button, and closes on Escape or on a click anywhere else.
| box | HTMLElement | - holds the button and the popover |
| button | HTMLElement | |
| pop | HTMLElement | |
| onOpen | function():void | - fills the popover, each time it opens |
| returns | open: function():void, close: function(boolean=):void, isOpen: function():boolean | } |
picker(spec)
mmo-kanban.jhs:2632A dropdown to pick a value, or several: a button showing what is picked, and a list to pick from, filtered by what is typed in it.
| spec | object | - options(): [{value, text, render()}]: text is what the filter searches, render() draws the option - value: what is picked, an array when multiple - multiple: several can be picked; the list stays open - none: what "nothing" is called, when nothing is allowed (single only) - custom: a typed value that is not in the list can be picked, offered as {custom} "value" - placeholder: what the button says when nothing is picked - footer(): something to show under the list - readonly, label (for assistive technologies), onChange(value) |
| returns | HTMLElement |
lookPicker(kind, item)
mmo-kanban.jhs:2744The colour and the icon of a status, a label or a category, in the board's settings: a button showing them, and a popover to pick them.
| kind | string | - status, label or category |
| item | object | - changed in place |
| returns | HTMLElement |
descriptionEditor(t, ro, bind)
mmo-kanban.jhs:2801The description of a ticket: markdown, in <mmo-markdown-editor> (a plain textarea when the page does not have it). A ticket that has one opens on its preview, to be read; # suggests the board's tickets, @ the people it is assigned to.
| t | object | - the ticket being edited, changed in place |
| ro | boolean | |
| bind | function | - binds a plain control to a field of the ticket |
| returns | HTMLElement |
addTriggers(editor, id, people)
mmo-kanban.jhs:2826# suggests the board's tickets, @ the people: the ones tickets are assigned to, and more.
| editor | HTMLElement | - an <mmo-markdown-editor> |
| id | ?string | - the ticket written about, which # leaves out |
| people = () => [] | function():string[] | - more people to suggest |
| returns | void |
discussionSection(editor)
mmo-kanban.jhs:2853Start the discussion of an editor's ticket: its state lives in editor.talk, its section is drawn by
- See
drawDiscussion, and its comments are loaded now.
| editor | object | |
| returns | HTMLElement | the section |
canComment()
mmo-kanban.jhs:2873whether the viewer may write in the discussions
loadDiscussion(editor)
asyncmmo-kanban.jhs:2882(Re)load the comments of an editor's ticket.
| editor | object | |
| returns | Promise<void> |
normalizeComment(c)
mmo-kanban.jhs:2902| c | object | - a comment, as the discussion gave it |
| returns | object | a comment the board can use, whatever it was given |
countComments(editor)
mmo-kanban.jhs:2918the card says how many comments its ticket has
| editor |
drawDiscussion(editor)
mmo-kanban.jhs:2933Draw an editor's discussion: its header (the count, the order, reload), its comments, and the editor of a new one.
| editor | object | |
| returns | void |
commentList(editor)
mmo-kanban.jhs:2981The comments, in the viewer's order: by date, or in threads -- a reply under what it answers, a reply to a comment that is gone starting a thread of its own.
| editor | object | |
| returns | HTMLElement |
commentNode(editor, c, byId, sayParent)
mmo-kanban.jhs:3028A comment: who wrote it and when, what it says, and what the viewer can do with it.
| editor | object | |
| c | object | - the comment |
| byId | Map<string, object> | - the discussion's comments |
| sayParent | boolean | - whether to say which comment it answers |
| returns | HTMLElement |
commentEditor(editor, kind, target)
mmo-kanban.jhs:3101The editor of a comment: a new one, a reply, or a change of one's own.
| editor | object | |
| kind | string | - new, reply or edit |
| target | ?string | - the comment answered or changed |
| returns | HTMLElement |
focusComposer(editor, key)
mmo-kanban.jhs:3149put the caret in a comment's editor, once it is drawn
| editor | ||
| key |
sendComment(editor, kind, target)
asyncmmo-kanban.jhs:3166Send what a comment's editor holds: a new comment, a reply, or a change.
| editor | object | |
| kind | string | - new, reply or edit |
| target | ?string | |
| returns | Promise<void> |
removeComment(editor, c)
asyncmmo-kanban.jhs:3208Delete one's own comment, once asked: its replies stay, answering a deleted comment.
| editor | object | |
| c | object | |
| returns | Promise<void> |
showComment(editor, id)
mmo-kanban.jhs:3228scroll to a comment of the discussion, and make it flash
| editor | ||
| id |
setDiscussionOrder(order)
mmo-kanban.jhs:3236| order |
storedOrder()
mmo-kanban.jhs:3243| returns | string | the order the viewer picked last, threads unless they did |
ago(date)
mmo-kanban.jhs:3251| date | ||
| returns | string | 3 hours ago, yesterday… |
fullDate(date)
mmo-kanban.jhs:3262| date |
initials(name)
mmo-kanban.jhs:3268| name | ||
| returns | string | what stands for someone without a picture: MM for marc-mouret |
conditionEditor(t, node, set, redraw, preview, root)
mmo-kanban.jhs:3282The editor of one condition, and of the ones it holds.
| t | object | - the ticket being edited |
| node | ?object | |
| set | function(?object):void | - puts a new node in its place, null removes it |
| redraw | function():void | - draws the whole tree again, after a change of its shape |
| preview | HTMLElement | - the description to update after a change of a value |
| root = false | boolean | |
| returns | HTMLElement |
newCondition(t)
mmo-kanban.jhs:3380| t |
convertCondition(t, node, type)
mmo-kanban.jhs:3386a condition turned into another type, keeping what both share
| t | ||
| node | ||
| type |
save(t, isNew)
mmo-kanban.jhs:3403Save a ticket being edited.
| t | object | - the edited copy |
| isNew | boolean | |
| returns | ok: boolean, reasons: string[], id: ?string | } |
configureBoard(lists)
mmo-kanban.jhs:3428Change the board's statuses, labels and categories. A ticket whose status goes takes the first status left of the same type; a label or a category that goes leaves its tickets. A status changing type stamps its tickets as a move would, so the change is refused when it breaks a constraint.
| lists | object | - {statuses, labels, categories}, each [{id, label}] (a status also has type and limit); an item without id is new; a list left out is kept |
| returns | ok: boolean, reasons: string[] | } |
editSettings()
mmo-kanban.jhs:3491Open the board's settings: its statuses, labels and categories.
| returns | void |
confirmRemove(id, editor)
asyncmmo-kanban.jhs:3585| id | ||
| editor |
notify(title, lines, tone)
mmo-kanban.jhs:3602Say something for a while, under the toolbar.
| title | string | |
| lines = [] | string[] | |
| tone = 'info' | string | - bad, warn or info |
Slots1
(default)
mmo-kanban.jhsa <script type="application/json"> holding the board's data
<slot>