Hi orgmode folks,
There is a special case that might need a clarification in the orgmode
implementation and/or the org-syntax [0]
The affiliated keyword, when it's before a dynamic block [1] it does not
work.
Example:
#+NAME: test
#+BEGIN: something-that-generates-a-table
| State | ID | Task | RESPONSIBLE |
|-------+----+---------+-------------|
| TODO | T1 | [[file:/tmp/affiliated-keyword-dynamic-block.org::*My
task][My task]] | Laura |
| TODO | T2 |
[[file:/tmp/affiliated-keyword-dynamic-block.org::*Task2][Task2]] |
Anna |
#+END:
It must be
#+BEGIN: something-that-generates-a-table
#+NAME: test
| State | ID | Task | RESPONSIBLE |
|-------+----+---------+-------------|
| TODO | T1 | [[file:/tmp/affiliated-keyword-dynamic-block.org::*My
task][My task]] | Laura |
| TODO | T2 |
[[file:/tmp/affiliated-keyword-dynamic-block.org::*Task2][Task2]] |
Anna |
#+END:
But right now, this is not available for org-ql, org-kanban, propview
(the things I am using)
Tested with orgmode version 9.7.10, org-ql 20241107.345 and org-kanban
cb96fa3ae5 source
So It needs to be after the dynamic block declaration; and that forces
all dynamic block to handle that kind of construction.
I think it is reasonable to say that a NAME given before a BEGIN dynamic
block element, applies to the thing that the dynamic block generates
The ability to clearly identify elements of exported html document is
nice to improve the visibility of things, for example here I experienced
how a table that represents a kanban might be better visualized using
css and js [2]
Coming back to the org syntax, I suspect that the table rows are not an
exception, #+NAME before table rows is specifically what I am using to
identify the table, and what does not work when there is in the middle
the dynamic block
#+begin_src diff
-With the exception of comments, clocks, headings, inlinetasks, items,
node properties, planning, property drawers, sections, and table rows,
every other element type can be assigned attributes.
+With the exception of comments, clocks, headings, inlinetasks, items,
node properties, planning, property drawers, and sections, every other
element type can be assigned attributes.
#+end_src
Cheers,
pinmacs
[0] section 4.3.8.2 https://orgmode.org/worg/org-syntax.html#Keywords
[1] https://orgmode.org/manual/Dynamic-Blocks.html
[2] (see screenshot in part 3, source shared too)
https://github.com/gizmomogwai/org-kanban/issues/50#issuecomment-2719546145#+TODO: TODO DONE
#+COLUMNS: %TODO(State) %CUSTOM_ID(ID) %ITEM(Task) %RESPONSIBLE
# #+EXPORT_FILE_NAME: /tmp/org-kanban
#+TITLE: org-kanban html example
#+AUTHOR: Name
#+ATTR_HTML: :id abstract
#+begin_abstract
In this example I test different dynamic blocks and NAME keyword
#+end_abstract
#+OPTIONS: prop:t toc:nil tags:not-in-toc d:(not "BACKLINKS" not "TRACE")
#+LANGUAGE: en
#+TOC: headlines 3
run these exports to test:
#+name: sourceblock_created_2025-03-12_14-06-44
#+begin_src emacs-lisp
(org-dblock-update t)
(org-html-export-to-html)
(org-gfm-export-to-markdown)
#+end_src
* Panel
** columnview
columnview works fine for =NAME= and =CAPTION=
#+BEGIN: columnview :id global :match "TODO={.+}-TODO=\"QUIT\"-TODO=\"DONE\"" :link t
#+NAME: test
#+CAPTION: Table with columnview
| State | ID | Task | RESPONSIBLE |
|-------+----+---------+-------------|
| TODO | T1 | [[file:/tmp/affiliated-keyword-dynamic-block.org::*My task][My task]] | Laura |
| TODO | T2 | [[file:/tmp/affiliated-keyword-dynamic-block.org::*Task2][Task2]] | Anna |
#+END:
** org-ql
org-ql does not work with =NAME= and =CAPTION=
# TODO caption keyword not working neither after begin neither after end
#+CAPTION: Table with org-ql
#+BEGIN: org-ql :query "todo:" :columns ((todo "State") ((property "CUSTOM_ID") "ID") (heading "Task") ((property "RESPONSIBLE") "Responsible"))
| State | ID | Task | Responsible |
|-------+----+---------+-------------|
| TODO | T1 | [[My task][My task]] | Laura |
| TODO | T2 | [[Task2][Task2]] | Anna |
#+END
** propview
org-ql does not work with =NAME= and =CAPTION=
I use this custom function sometimes to evaluate a link using that feature from propview
#+name: sourceblock_created_2025-03-12_14-06-12
#+begin_src emacs-lisp
(defun __item-cid ()
"link for propview when using CUSTOM_ID"
(concat "[[#" CUSTOM_ID "][" ITEM "]]"))
#+end_src
#+RESULTS: sourceblock_created_2025-03-12_14-06-12
# propview allows CAPTION keyword if it is before end, but not after begin
# anyway, the caption does not render fine
#+BEGIN: propview :scope ("./org-kanban.org") :match "TODO={.+}-TODO=\"QUIT\"-TODO=\"DONE\"" :noquote all :cols (TODO CUSTOM_ID (__item-cid) RESPONSIBLE) :colnames ("State" "ID" "Task" "Responsible")
| State | ID | Task | Responsible |
|-------+----+---------+-------------|
| TODO | T1 | [[#T1][My task]] | Laura |
| TODO | T2 | [[#T2][Task2]] | Anna |
|-------+----+---------+-------------|
| | | | |
#+END:
** org-kanban
#+name: sourceblock_created_2025-03-12_14-15-42
#+begin_export html
<style>
/* 1) Reset all table borders and spacing */
#kanban-table,
#kanban-table tr,
#kanban-table th,
#kanban-table td {
border: none !important;
border-color: transparent !important;
padding: 0;
margin: 0;
background: none;
box-sizing: border-box;
}
/* 2) Use border-spacing to add gaps (like "cards") */
#kanban-table {
border-collapse: separate !important;
/* Adjust spacing between cells (horizontal, vertical) */
border-spacing: 1rem 0.5rem;
width: 100%;
/* Light background for the overall board area */
background-color: #f5f5f5;
padding: 1rem;
/* Optional: center the table on the page */
margin: 1rem auto;
}
/* 3) Style the column headers (TH) */
#kanban-table th {
background-color: #eaeaea;
font-weight: bold;
text-align: center;
padding: 0.75rem 1rem;
border-radius: 6px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
/* 4) Style each cell (TD) as a "card" */
#kanban-table td {
background-color: #ffffff;
padding: 0.75rem 1rem;
border-radius: 6px;
vertical-align: top;
text-align: center;
/* Subtle shadow to make it look like a card */
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
</style>
<script>
// Function to clean and reorder the kanban table
function cleanAndReorderKanbanTable() {
const table = document.getElementById("kanban-table");
const tbody = table.querySelector("tbody");
const rows = Array.from(tbody.querySelectorAll("tr"));
// Get number of columns
const columnCount = table.querySelectorAll("thead th").length;
// Prepare arrays for columns content
const columns = Array.from({ length: columnCount }, () => []);
// Distribute cells into their respective column arrays if they contain links (content)
rows.forEach((row) => {
const cells = Array.from(row.children);
cells.forEach((cell, idx) => {
if (cell.querySelector("a")) {
columns[idx].push(cell.innerHTML);
}
});
});
// Clear tbody content
tbody.innerHTML = "";
// Find max number of rows to create
const maxRows = Math.max(...columns.map(col => col.length));
// Rebuild tbody with content close to headers
for (let i = 0; i < maxRows; i++) {
const newRow = document.createElement("tr");
let isRowEmpty = true;
for (let j = 0; j < columnCount; j++) {
const newCell = document.createElement("td");
newCell.className = "org-left";
if (columns[j][i]) {
newCell.innerHTML = columns[j][i];
isRowEmpty = false;
} else {
newCell.innerHTML = " ";
newCell.style.visibility = "hidden";
}
newRow.appendChild(newCell);
}
// Append only if row is not empty (all )
if (!isRowEmpty) {
tbody.appendChild(newRow);
}
}
}
// Run the function on page load or after DOM is ready
document.addEventListener("DOMContentLoaded", cleanAndReorderKanbanTable);
</script>
#+end_export
not working =#+NAME: kanban-table= introduced by hand
not working specific ID, useful to give kanban a styling, but that also might need (setq org-html-prefer-user-labels t)
# #+NAME: kanban-table
# #+BEGIN: kanban :layout (";" . 15)
# #+NAME: kanban-table
#+BEGIN: kanban :caption "my table" :name kanban-table
#+CAPTION: my table
#+NAME: kanban-table
| TODO | DONE |
|---------+-------|
| [[file:org-kanban.org::#T1][My task]] | |
| [[file:org-kanban.org::#T2][Task2]] | |
| | [[file:org-kanban.org::#T3][Task3]] |
#+END
* Active Tasks
** TODO My task
:PROPERTIES:
:RESPONSIBLE: Laura
:CUSTOM_ID: T1
:END:
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
** TODO Task2
:PROPERTIES:
:RESPONSIBLE: Anna
:CUSTOM_ID: T2
:END:
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
Content
** DONE Task3
CLOSED: [2025-03-12 Wed 13:17]
:PROPERTIES:
:CUSTOM_ID: T3
:END:
Content
Content
Content
Content
Content