Class: OKF::Render::Graph

Inherits:
Object
  • Object
show all
Defined in:
lib/okf/render/graph.rb

Overview

Renders an OKF::Bundle::Graph as the interactive graph page. The markup lives in graph/template.html.erb; #render returns the HTML string.

The page boots from a minimal payload — nodes carry only id + title, plus compact TYPES/TAGS inverted indexes for colouring and filtering. It has two data modes, both driven by one template:

server mode (embed: nil) — the default. Each concept's markdown body,
metadata, catalog, index and log are pulled from OKF::Server::App on
demand via fetch, so the initial payload stays small and bodies read
live from disk (edits show without a restart). Nothing extra embedded.
render mode (embed: payload) — `okf render` bakes the whole bundle in via
.static below: the same fetch getters resolve from the injected payload
instead, so the single file needs no server (e.g. GitHub Pages).

NOTE (trust boundary): the page loads Cytoscape + marked from a CDN, so it needs network for those libraries even in render mode. Fetched/embedded markdown is sanitized client-side (DOMPurify.sanitize(marked.parse(...))) and all inline--escaped by #json_for_script (stdlib ERB does not auto-escape). Still, only serve bundles you trust.

Constant Summary collapse

TEMPLATE =
File.expand_path("graph/template.html.erb", __dir__)
LAYOUTS =
%w[cose concentric breadthfirst circle grid].freeze
MIN_SIZE =

Node-diameter range in px; the template scales within it by node degree.

14
MAX_SIZE =
44
LT_ESCAPE =

The 6-character JSON unicode escape for < (backslash, u, 0, 0, 3, c), built from the backslash code point so no literal escape appears here.

(92.chr(Encoding::UTF_8) + "u003c").freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(graph, title: nil, link: nil, layout: "cose", node_endpoint: "node", meta_endpoint: "node/meta", embed: nil, siblings: nil, self_slug: nil, hub_path: nil) ⇒ Graph

+node_endpoint+/+meta_endpoint+ are the (mount-relative) URLs the page fetches a concept's raw markdown and metadata fragment from — relative so the page works whether served at "/" or mounted under a Rails prefix. embed is the render-mode payload (nil = server mode); see the class doc. +siblings+/+self_slug+/+hub_path+ carry the hub's bundle switcher into the page (server mode only). nil — the standalone-server and okf render default — injects an empty SIBLINGS, so the switcher never appears in a single bundle or a static file.



75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/okf/render/graph.rb', line 75

def initialize(graph, title: nil, link: nil, layout: "cose", node_endpoint: "node", meta_endpoint: "node/meta", embed: nil,
               siblings: nil, self_slug: nil, hub_path: nil)
  @graph = graph
  @title = title
  @link = link
  @layout = layout
  @node_endpoint = node_endpoint
  @meta_endpoint = meta_endpoint
  @embed = embed
  @siblings = siblings
  @self_slug = self_slug
  @hub_path = hub_path
end

Class Method Details

.payload(folder) ⇒ Object

What the baked page carries in place of the endpoints a live server would answer. Every key here is data a client getter reads from EMBED instead of fetching — and each derives from the same folder method the matching OKF::Server::App endpoint uses, so the bake and the live server cannot drift (/node/meta is the exception: the fragment is derived on the client from the catalog's raw description, so no map is baked for it).



58
59
60
61
62
63
64
65
# File 'lib/okf/render/graph.rb', line 58

def self.payload(folder)
  {
    catalog: folder.catalog,
    index: folder.directory_index,
    logs: folder.log_entries,
    bodies: folder.concepts.each_with_object({}) { |concept, map| map[concept.id] = concept.body.to_s }
  }
end

.static(folder, title: nil, link: nil, layout: "cose") ⇒ Object

okf render: the whole page as one self-contained file, the bundle baked in, so it hosts where no server answers a fetch. Takes any bundle handle (an OKF::Bundle::Folder) and returns the HTML string.



48
49
50
# File 'lib/okf/render/graph.rb', line 48

def self.static(folder, title: nil, link: nil, layout: "cose")
  new(folder.graph(minimal: true), title: title || folder.name, link: link, layout: layout, embed: payload(folder)).render
end

Instance Method Details

#renderObject



89
90
91
# File 'lib/okf/render/graph.rb', line 89

def render
  ERB.new(File.read(TEMPLATE, encoding: "UTF-8")).result(binding)
end