Last active
April 27, 2022 19:38
-
-
Save gjroelofs/554474a20482f00d2c3c666d3ec50b85 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*************** Hierarchical Sections *******************/ | |
var folders = { | |
// "<name>" : JQueryObject (section) | |
}; | |
var childMapping = { | |
// "PX-2": [ | |
// "Sprint Planning" | |
// ], | |
}; | |
var parentMapping = { | |
// "Sprint Planning": "PX-2", | |
}; | |
var DEBUG = false; | |
var codaDocID = window.location.href; | |
codaDocID = /https:\/\/coda.io\/d\/[^\/]*_d([^\/]*)\//g.exec(codaDocID)[1]; | |
function isEmpty(str) { | |
return (!str || 0 === str.length); | |
} | |
/* Get the folder display name. */ | |
function getFolderName(folder){ | |
return folder.find("div.section_list_item--folderInput--12MBfIRp") | |
.first() | |
.text(); | |
} | |
function isOpenFolder(folder){ | |
return folder.attr('class').includes("folder--open--2ZilK7HF"); | |
} | |
/* Retrieve the attachment div for a folder to which other folders can be attached. */ | |
function grabFolderList(folder){ | |
var listParent = folder.children(".details_with_chevron--root--3tk2hW-f"); | |
listParent = listParent.children(".details_view--root--pSxtTLYV"); | |
listParent = listParent.children().last(); | |
// Grab either the list view (folder has sections), or the div empty div above it. | |
return listParent; | |
} | |
/* Ensures that the child div is added as a visual child of the folder div. */ | |
function insertIntoFolder(child, folder){ | |
var list = grabFolderList(folder); | |
child.css('padding-left', '20px') | |
child.appendTo(list); | |
} | |
function setupChildrenForFolder(folder){ | |
// Find the name of this folder. | |
// Grab the first occurence as we can have child folders. | |
var name = getFolderName(folder); | |
if(DEBUG) console.log("Setting up children for Folder: "+ name); | |
// Go through all expected and existing children, and insert them into this parent. | |
if(!(name in childMapping)) return; | |
var children = childMapping[name]; | |
for (index = 0; index < children.length; ++index) { | |
var child = children[index] | |
if(!(child in folders)){ | |
console.error("Requested child was an unknown folder: " + child + " for parent folder: " + name + " with child mapping: " + children); | |
continue; | |
} | |
if(DEBUG) console.log("Folder "+ name + " will receive child: " + child); | |
insertIntoFolder(folders[child], folder); | |
} | |
} | |
// Define attrchange on JQuery objects as an adhoc MutationObserver implementation. | |
$(function() { | |
(function($) { | |
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; | |
$.fn.attrchange = function(callback) { | |
if (MutationObserver) { | |
var options = { | |
subtree: false, | |
attributes: true | |
}; | |
var observer = new MutationObserver(function(mutations) { | |
mutations.forEach(function(e) { | |
callback.call(e.target, e.attributeName); | |
}); | |
}); | |
return this.each(function() { | |
observer.observe(this, options); | |
}); | |
} | |
} | |
})(jQuery); | |
}); | |
function startup(){ | |
function handleFolderCreation(){ | |
// Find the name of this folder | |
// Grab the first occurence as we can have child folders. | |
var name = getFolderName($(this)); | |
// Store the folder under its name | |
folders[name] = $(this); | |
if(DEBUG) console.log("Setting up closed folder: "+ name); | |
// See if we can attach ourselves to a parent, if not, hide. | |
if(name in parentMapping){ | |
var parent = parentMapping[name] | |
if(parent in folders && isOpenFolder(folders[parent])){ | |
// Insert this folder into the appropriate parent. | |
if(DEBUG) console.log("Folder "+ name + " attached to parent: " + parent); | |
insertIntoFolder($(this), folders[parent]); | |
} else { | |
// If not yet created, hide | |
if(DEBUG){ | |
if(parent in folders){ | |
console.log("Folder "+ name + " detached, as parent was closed (folded)."); | |
} else { | |
console.log("Folder "+ name + " detached, as parent was unknown at the moment, awaiting creation."); | |
} | |
} | |
$(this).detach(); | |
} | |
} | |
// If the folder is open, setup children as well. | |
if(isOpenFolder($(this))){ | |
setupChildrenForFolder($(this)); | |
} | |
/** | |
* Attach a listener to the folder to run if it opens. | |
* Insert children into folders that are/become open and those children are available. | |
*/ | |
$(this).attrchange(function(attrName){ | |
if( attrName != 'class') return; | |
if( !isOpenFolder($(this))) return; | |
setupChildrenForFolder($(this)); | |
}); | |
} | |
/** | |
* Store any folder created, and detach if it is parented. | |
* (or reparent if the parent already exists.) | |
*/ | |
$(".folder--root--1pRx1koR").each(handleFolderCreation); | |
$(document).arrive(".folder--root--1pRx1koR", handleFolderCreation); | |
} | |
// Find the Folder Hierarchy table and record the child/parent mapping, then call startup. | |
$.getJSON('https://coda.io/apis/v1beta1/docs/' + codaDocID + '/tables/Folder%20Hierarchy/columns', function(data) { | |
// Create a folder <-> id mapping | |
var folderIDMapping = {}; | |
data.items.forEach(function(e){ | |
if(DEBUG) console.log("Mapped Folder: " + e.name + " to: " + e.id); | |
folderIDMapping[e.name] = e.id; | |
}); | |
$.getJSON('https://coda.io/apis/v1beta1/docs/' + codaDocID + '/tables/Folder%20Hierarchy/rows?limit=500', function(data) { | |
data.items.forEach(function(e){ | |
var parent = e.values[folderIDMapping["Parent"]]; | |
if(!isEmpty(parent)){ | |
if(DEBUG) console.log("Mapped parent for Folder: " + e.name + " to: " + parent); | |
parentMapping[e.name] = parent; | |
} | |
var childrenRaw = e.values[folderIDMapping["Children"]]; | |
if(!isEmpty(childrenRaw)){ | |
if(DEBUG) console.log("Mapped children for Folder: " + e.name + " to: " + childrenRaw); | |
childMapping[e.name] = childrenRaw.split(","); | |
} | |
}); | |
// Once we have the mapping, go set everything up. | |
startup(); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment