web-dev-knowledge-graph

Back to README

Application level requirements

This document holds requirements for the app.js file

Application should import, wire up and use the following modules:

App should have a set of functions:

Back to top

init()

Function should initialize the application. Have to be called only once on each page load after all the event handlers are registered, for the side effects only. It should run the following in that order:

If the app is running for the first time, data should be fetched from the example_graph.json file. Otherwise, it should be loaded from the localStorage, checked for validity with graphus.isValidGraph(data), to make sure the data is of expected shape, and passed to graphus.init(data).

Also, if the app is running for the first time, it should call dialogus.open('splash', {version, canClose: true}).

Back to top

isFirstRun()

Predicate function that returns true if the application is running for the first time, false otherwise. Have to be called only once on each page load after all the event handlers are registered. To determine if the app is running for the first time, should check if the localStorage has the graph_app_data entry. If it does, the app is not running for the first time.

Back to top

addCustomListeners()

Function should add all the event listeners for the custom events by calling the following functions in that order:

Have to be called only once on each page load, for side effects only.

Back to top

listenForHeadusEvents()

Function should add all the event listeners for the headus module custom events. It has to be called only once on each page load, for side effects only.

Add addnodetrigger event handler calling the dialogus.open('add node', {?name: event.detail.name, canClose: true}) method. If the name is not provided or if it is provided but the call to graphus.isNameTaken(name) returns true, the name property on the data argument is to be skipped.

Add querynode event handler calling the changeCurrentNodeBy({name}, true) function for the given event.detail.query.

Add menutrigger event handler calling the dialogus.open('menu', {canClose: true}) method.

Back to top

listenForNodusEvents()

Function should add all the event listeners for the nodus module custom events. It has to be called only once on each page load, for side effects only.

Add gotonodetrigger event handler calling the changeCurrentNodeBy({id}) function for the given event.detail.id.

Add editnodetrigger event handler calling the dialogus.open('edit node', {node, canClose: true}) method. It should get the node information with the graphus.getNodeById(event.detail.id) method and pass it as node property in the data argument.

Add deletenodetrigger event handler getting the node information with the graphus.getNodeById(event.detail.id) method and then calling the dialogus.open('delete node', {node, canClose: true}) method.

Add addlinktrigger event handler calling the graphus.getNameById(event.detail.id) method, and then calling the dialogus.open('add link', {from: name}, canClose: true}) method.

Add nodeselectedtrigger event handler, that accepts the event.detail.id and then calls the graphus.getLinksById(id.current, id.selected) method. Next it should call the linkus.showTwin(links, id.current) method.

Back to top

listenForLinkusEvents()

Function should add all the event listeners for the linkus module custom events. It has to be called only once on each page load, for side effects only.

Add gotolinktrigger event handler calling the changeCurrentNodeBy({id: id.from, select: {id: id.to}}) function for the given event.detail.id.

Add editlinktrigger event handler accepting the event.detail.id, then getting the node names with the graphus.getNameById(id.from) and graphus.getNameById(id.to) methods, and the link description with the graphus.getLinkDescription(id.from, id.to) method, and then calling the dialogus.open('edit link', {link: {id: {from: id.from, to: id.to}, from: fromName, to: toName}, description, canClose: true}) method.

Add deletelinktrigger event handler accepting the event.detail.id, then getting the link information with the graphus.getLinksById(id.from, id.to) calling the dialogus.open('delete link', {link, canClose: true}) method.

Back to top

listenForDialogusEvents()

Function should add all the event listeners for the dialogus module custom events. It has to be called only once on each page load, for side effects only.

Add splashtrigger event handler calling the dialogus.open('splash', {version, canClose: true}) method.

Add addnodetrigger event handler, that should check if event.detail.name is empty, and if is is, should call the dialogus.open('inform', {title: 'Name required', text: 'Node name cannot be empty or empty-like.', canClose: true}) method. Otherwise, it should call the graphus.isNameTaken(event.detail.name) method, and if it returns true, should call the dialogus.open('inform', {title: 'Name taken', text: 'There\'s already a node named ' + event.detail.name + '. Try another name.', canClose: true}) method. Otherwise, should call the dialogus.close('add node') method, and then call the graphus.addNode(event.detail.name, ?event.detail.description) method. Second argument is optional, it is passed if not empty.

Add savenodetrigger event handler, that should accept the event.detail.node object, then it should check if node.name is empty, and if it is, should call the dialogus.open('inform', {title: 'Name required', text: 'Node name cannot be empty or empty-like.', canClose: true}) method. Otherwise, it should call the graphus.isNameTaken(node.name) method, and if it returns true, it should call the graphus.getIdByName(node.name) method, and if it does not return the node.id, then call the dialogus.open('inform', {title: 'Name taken', text: 'There\'s already a node named ' + node.name + '. Try another name.', canClose: true}) method. Otherwise, should call the dialogus.close('edit node') method, and then call the graphus.updateNode(node.id, {name: node.name, description: node.description}) method.

Add deletenodetrigger event handler calling the graphus.deleteNode(event.detail.id) method.

Add addlinktrigger event handler that should accept the event.detail.link object, then check if both link.from and link.to are empty, and if they are call the dialogus.open('inform', {title: 'Node names required', text: 'Links are linking pairs of nodes, so node names have to be specified.', canClose: true}) method. Otherwise, it should check if either link.from or link.to is empty, or they are equal, or graphus.getIdByName(link.from) or graphus.getIdByName(link.to) returns null, and if so call the dialogus.open('inform', {title: 'Two exising nodes required', text: 'Links can be created only between two distinct existing nodes'}) method. Otherwise, it should call graphus.doesLinkExist(link.from, link.to) and if it returns true, call the dialogus.open('inform', {title: 'Link exists', text: 'There\'s already a link between those two nodes in that direction.', canClose: true}) method. Otherwise, it should call the dialogus.close('add link') method, and then call the graphus.addLink(fromId, toId, link.description) method.

Add savelinktrigger event handler accepting the event.detail.link object, then check if both link.from and link.to are empty, and if they are call the dialogus.open('inform', {title: 'Node names required', text: 'Links are linking pairs of nodes, so node names have to be specified.', canClose: true}) method. Otherwise, it should check if either link.from or link.to is empty, or they are equal, or graphus.getIdByName(link.from) or graphus.getIdByName(link.to) returns null, and if so call the dialogus.open('inform', {title: 'Two exising nodes required', text: 'Links can be created only between two distinct existing nodes'}) method. Otherwise, it should call graphus.getIdByName(link.from) and graphus.getIdByName(link.to), and if not both are equal to link.id.from and link.id.to respectively, call the graphus.doesLinkExist(fromId, toId) and if it returns true, call the dialogus.open('inform', {title: 'Link exists', text: 'There\'s already a link between those two nodes in that direction.', canClose: true}) method. Otherwise, it should call the dialogus.close('edit link') method, and then call the graphus.updateLink(link.id.from, link.id.to, {?from: fromId, ?to: toId, description: link.description}) method with from and to properties present only if they are not equal to link.id.from and link.id.to respectively.

Add deletelinktrigger event handler accepting the event.detail.id, then calling the graphus.deleteLink(id.from, id.to) method.

Back to top

listenForGraphusEvents()

Function should add all the event listeners for the graphus module custom events. It has to be called only once on each page load, for side effects only.

Add graphloaded event handler calling the following functions in that order:

Add graphupdated event handler that acts based on the event.detail.change object.

If the change.type is node and change.action is add, call the headus.enlistNode(name) method. Also call the nodus.showOne(node) and linkus.showTwin(links, id) methods for the new node, using data from the change object and passing an empty array as links argument.

If the change.type is node and change.action is update, check if change.name.old equals change.name.new. If it does not, call the headus.unlistNode(change.name.old) and headus.enlistNode(change.name.new) methods. Also call the nodus.getCurrentId() method and if it returns change.id, call the nodus.updateOne({name: change.name.new, description: change.description}) method.

If the change.type is node and change.action is delete, call the headus.unlistNode(change.id) method. Also if the headus.getQuery() method returns change.name, call the headus.clearQuery() method. Also if the nodus.getCurrentId() method returns change.id, call the showMany() function. Also if the nodus.getListedNodes() method returns an array of ids that includes change.id, call the nodus.removeNode(change.id) method. Also if the linkus.geListedLinks() method returns an array of links that includes any of the id pairs of either change.id or change.links, call the linkus.removeLink(from, to) method for each such link id pair.

If the change.type is link and change.action is add, call the nodus.getCurrentId() method and if it returns the change.id.from, call the changeCurrentNodeBy({id: change.id.from, select: {id: change.id.to}) function. Otherwise, if it returns the change.id.to, call the changeCurrentNodeBy({id: change.id.to, select: {id: change.id.from}) function.

If the change.type is link and change.action is update, check if change.id.update is provided, and if it is, call the changeCurrentNodeBy({id: change.id.update.from, select: {id: change.id.update.to}) function. Otherwise, call the linkus.getListedLinks() method and if it returns an array of links that includes the change.id, call the linkus.updateLink(change.id.from, change.id.to, change.description) method.

If the change.type is link and change.action is delete, call the nodus.getCurrentId() method, and if it returns the change.id.from, call the changeCurrentNodeBy({id: change.id.from}) function. Otherwise, if it returns the change.id.to, call the changeCurrentNodeBy({id: change.id.to}) function.

Back to top

showBody()

Function should remove the hidden attribute from the <body> element. It is to be used for side effects only.

Back to top

changeCurrentNodeBy({id|name, ?select: {id|name}}, ?silent)

Function should try to change the current node to the node with the given id or name. It should be called for side effects only.

If id is given or acquired from the graphus.getIdByName(name) method, should call the graphus.getNodeById(id) method. If the node is not found and silent is not true, should call the dialogus.open('inform', {message: 'Node not found', canClose: true}) method. If node is found, should call the graphus.getLinksById(id) method for the same node id. Next nodus.showOne(node) and linkus.showTwin(links, id) methods should be called for the node and links respectively.

If second argument is a boolean it is to be assigned to silent, and select should become undefined.

If select is given, function should call the graphus.getLinksById(id, select.id) method. Also should pass select.id to nodus.showOne(node, select.id).

If name is given instead of id, function should call the graphus.getIdByName(name) method first. Same for select, if select.name is given instead of select.id.

Back to top

showMany()

Function should call the following functions in that order:

Back to top