vault backup: 2026-02-12 17:29:41
This commit is contained in:
Vendored
+1
-1
@@ -25,5 +25,5 @@
|
|||||||
"digitalgarden",
|
"digitalgarden",
|
||||||
"pdf-plus",
|
"pdf-plus",
|
||||||
"obsidian-tracker",
|
"obsidian-tracker",
|
||||||
"copy-as-html"
|
"copy-document-as-html"
|
||||||
]
|
]
|
||||||
Vendored
+9
@@ -59,5 +59,14 @@
|
|||||||
],
|
],
|
||||||
"key": "C"
|
"key": "C"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"copy-document-as-html:copy-selection-as-html": [
|
||||||
|
{
|
||||||
|
"modifiers": [
|
||||||
|
"Mod",
|
||||||
|
"Shift"
|
||||||
|
],
|
||||||
|
"key": "C"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
-3747
File diff suppressed because it is too large
Load Diff
-10
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "copy-as-html",
|
|
||||||
"name": "Copy as HTML",
|
|
||||||
"version": "1.1.3",
|
|
||||||
"minAppVersion": "0.12.0",
|
|
||||||
"description": "This is a simple plugin that converts the selected markdown to HTML and copies it to the clipboard.",
|
|
||||||
"author": "Bailey Jennings",
|
|
||||||
"authorUrl": "https://twitter.com/Bailey_Jennings",
|
|
||||||
"isDesktopOnly": false
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"removeFrontMatter": true,
|
||||||
|
"convertSvgToBitmap": true,
|
||||||
|
"useCustomStylesheet": true,
|
||||||
|
"useCustomHtmlTemplate": true,
|
||||||
|
"embedExternalLinks": false,
|
||||||
|
"removeDataviewMetadataLines": false,
|
||||||
|
"formatCodeWithTables": false,
|
||||||
|
"formatCalloutsWithTables": false,
|
||||||
|
"footnoteHandling": 2,
|
||||||
|
"internalLinkHandling": 0,
|
||||||
|
"styleSheet": "body,input {\n font-family: \"Roboto\",\"Helvetica Neue\",Helvetica,Arial,sans-serif\n}\n\ncode, kbd, pre {\n font-family: \"Roboto Mono\", \"Courier New\", Courier, monospace;\n background-color: #f5f5f5;\n}\n\npre {\n padding: 1em 0.5em;\n}\n\nmark {\n background-color: yellow;\n background: yellow;\n mso-highlight: yellow;\n color: red;\n}\n\ndel {\n text-decoration: line-through;\n}\n\nem {\n color: grey;\n font-style: italic;\n}\n\nstrong {\n font-style: bold;\n}\n\ntable {\n background: white;\n border: 1px solid #666;\n border-collapse: collapse;\n padding: 0.5em;\n}\n\ntable thead th,\ntable tfoot th {\n text-align: left;\n background-color: #eaeaea;\n color: black;\n}\n\ntable th, table td {\n border: 1px solid #ddd;\n padding: 0.5em;\n}\n\ntable td {\n color: #222222;\n}\n\n.callout[data-callout=\"abstract\"] .callout-title,\n.callout[data-callout=\"summary\"] .callout-title,\n.callout[data-callout=\"tldr\"] .callout-title,\n.callout[data-callout=\"faq\"] .callout-title,\n.callout[data-callout=\"info\"] .callout-title,\n.callout[data-callout=\"help\"] .callout-title {\n background-color: #828ee7;\n}\n.callout[data-callout=\"tip\"] .callout-title,\n.callout[data-callout=\"hint\"] .callout-title,\n.callout[data-callout=\"important\"] .callout-title {\n background-color: #34bbe6;\n}\n.callout[data-callout=\"success\"] .callout-title,\n.callout[data-callout=\"check\"] .callout-title,\n.callout[data-callout=\"done\"] .callout-title {\n background-color: #a3e048;\n}\n.callout[data-callout=\"question\"] .callout-title,\n.callout[data-callout=\"todo\"] .callout-title {\n background-color: #49da9a;\n}\n.callout[data-callout=\"caution\"] .callout-title,\n.callout[data-callout=\"attention\"] .callout-title {\n background-color: #f7d038;\n}\n.callout[data-callout=\"warning\"] .callout-title,\n.callout[data-callout=\"missing\"] .callout-title,\n.callout[data-callout=\"bug\"] .callout-title {\n background-color: #eb7532;\n}\n.callout[data-callout=\"failure\"] .callout-title,\n.callout[data-callout=\"fail\"] .callout-title,\n.callout[data-callout=\"danger\"] .callout-title,\n.callout[data-callout=\"error\"] .callout-title {\n background-color: #e6261f;\n}\n.callout[data-callout=\"example\"] .callout-title {\n background-color: #d23be7;\n}\n.callout[data-callout=\"quote\"] .callout-title,\n.callout[data-callout=\"cite\"] .callout-title {\n background-color: #aaaaaa;\n}\n\n.callout-icon {\n flex: 0 0 auto;\n display: flex;\n align-self: center;\n}\n\nsvg.svg-icon {\n height: 18px;\n width: 18px;\n stroke-width: 1.75px;\n}\n\n.callout {\n overflow: hidden;\n margin: 1em 0;\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);\n border-radius: 4px;\n}\n\n.callout-title {\n padding: .5em;\n display: flex;\n gap: 8px;\n font-size: inherit;\n color: black;\n line-height: 1.3em;\n}\n\n.callout-title-inner {\n font-weight: bold;\n color: black;\n}\n\n.callout-content {\n overflow-x: auto;\n padding: 0.25em .5em;\n color: #222222;\n background-color: white !important;\n}\n\nul.contains-task-list {\n padding-left: 0;\n list-style: none;\n}\n\nul.contains-task-list ul.contains-task-list {\n padding-left: 2em;\n}\n\nul.contains-task-list li input[type=\"checkbox\"] {\n margin-right: .5em;\n}\n\n.callout-table,\n.callout-table tr,\n.callout-table p {\n width: 100%;\n padding: 0;\n}\n\n.callout-table td {\n width: 100%;\n padding: 0 1em;\n}\n\n.callout-table p {\n padding-bottom: 0.5em;\n}\n\n.source-table {\n width: 100%;\n background-color: #f5f5f5;\n}\n",
|
||||||
|
"htmlTemplate": "<!DOCTYPE html>\n<html xmlns:o=\"urn:schemas-microsoft-com:office:office\"\n xmlns:w=\"urn:schemas-microsoft-com:office:word\">\n<head>\n <meta charset=\"utf-8\">\n <title>${title}</title>\n <style>\n ${MERMAID_STYLESHEET}\n ${stylesheet}\n </style>\n</head>\n<body>\n${body}\n</body>\n</html>\n",
|
||||||
|
"bareHtmlOnly": false,
|
||||||
|
"fileNameAsHeader": false,
|
||||||
|
"disableImageEmbedding": false
|
||||||
|
}
|
||||||
+897
@@ -0,0 +1,897 @@
|
|||||||
|
/*
|
||||||
|
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||||
|
if you want to view the source, please visit the github repository of this plugin
|
||||||
|
*/
|
||||||
|
|
||||||
|
var __defProp = Object.defineProperty;
|
||||||
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||||
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||||
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||||
|
var __export = (target, all) => {
|
||||||
|
for (var name in all)
|
||||||
|
__defProp(target, name, { get: all[name], enumerable: true });
|
||||||
|
};
|
||||||
|
var __copyProps = (to, from, except, desc) => {
|
||||||
|
if (from && typeof from === "object" || typeof from === "function") {
|
||||||
|
for (let key of __getOwnPropNames(from))
|
||||||
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||||
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||||
|
}
|
||||||
|
return to;
|
||||||
|
};
|
||||||
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||||
|
|
||||||
|
// main.ts
|
||||||
|
var main_exports = {};
|
||||||
|
__export(main_exports, {
|
||||||
|
default: () => CopyDocumentAsHTMLPlugin
|
||||||
|
});
|
||||||
|
module.exports = __toCommonJS(main_exports);
|
||||||
|
var import_obsidian = require("obsidian");
|
||||||
|
function allWithProgress(promises, callback) {
|
||||||
|
let count = 0;
|
||||||
|
callback(0);
|
||||||
|
for (const promise of promises) {
|
||||||
|
promise.then(() => {
|
||||||
|
count++;
|
||||||
|
callback(count * 100 / promises.length);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.all(promises);
|
||||||
|
}
|
||||||
|
async function delay(milliseconds) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
||||||
|
}
|
||||||
|
var DEFAULT_STYLESHEET = `body,input {
|
||||||
|
font-family: "Roboto","Helvetica Neue",Helvetica,Arial,sans-serif
|
||||||
|
}
|
||||||
|
|
||||||
|
code, kbd, pre {
|
||||||
|
font-family: "Roboto Mono", "Courier New", Courier, monospace;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 1em 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #666;
|
||||||
|
border-collapse: collapse;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table thead th,
|
||||||
|
table tfoot th {
|
||||||
|
text-align: left;
|
||||||
|
background-color: #eaeaea;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th, table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td {
|
||||||
|
color: #222222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout[data-callout="abstract"] .callout-title,
|
||||||
|
.callout[data-callout="summary"] .callout-title,
|
||||||
|
.callout[data-callout="tldr"] .callout-title,
|
||||||
|
.callout[data-callout="faq"] .callout-title,
|
||||||
|
.callout[data-callout="info"] .callout-title,
|
||||||
|
.callout[data-callout="help"] .callout-title {
|
||||||
|
background-color: #828ee7;
|
||||||
|
}
|
||||||
|
.callout[data-callout="tip"] .callout-title,
|
||||||
|
.callout[data-callout="hint"] .callout-title,
|
||||||
|
.callout[data-callout="important"] .callout-title {
|
||||||
|
background-color: #34bbe6;
|
||||||
|
}
|
||||||
|
.callout[data-callout="success"] .callout-title,
|
||||||
|
.callout[data-callout="check"] .callout-title,
|
||||||
|
.callout[data-callout="done"] .callout-title {
|
||||||
|
background-color: #a3e048;
|
||||||
|
}
|
||||||
|
.callout[data-callout="question"] .callout-title,
|
||||||
|
.callout[data-callout="todo"] .callout-title {
|
||||||
|
background-color: #49da9a;
|
||||||
|
}
|
||||||
|
.callout[data-callout="caution"] .callout-title,
|
||||||
|
.callout[data-callout="attention"] .callout-title {
|
||||||
|
background-color: #f7d038;
|
||||||
|
}
|
||||||
|
.callout[data-callout="warning"] .callout-title,
|
||||||
|
.callout[data-callout="missing"] .callout-title,
|
||||||
|
.callout[data-callout="bug"] .callout-title {
|
||||||
|
background-color: #eb7532;
|
||||||
|
}
|
||||||
|
.callout[data-callout="failure"] .callout-title,
|
||||||
|
.callout[data-callout="fail"] .callout-title,
|
||||||
|
.callout[data-callout="danger"] .callout-title,
|
||||||
|
.callout[data-callout="error"] .callout-title {
|
||||||
|
background-color: #e6261f;
|
||||||
|
}
|
||||||
|
.callout[data-callout="example"] .callout-title {
|
||||||
|
background-color: #d23be7;
|
||||||
|
}
|
||||||
|
.callout[data-callout="quote"] .callout-title,
|
||||||
|
.callout[data-callout="cite"] .callout-title {
|
||||||
|
background-color: #aaaaaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-icon {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg.svg-icon {
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
stroke-width: 1.75px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout {
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 1em 0;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-title {
|
||||||
|
padding: .5em;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: inherit;
|
||||||
|
color: black;
|
||||||
|
line-height: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-title-inner {
|
||||||
|
font-weight: bold;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-content {
|
||||||
|
overflow-x: auto;
|
||||||
|
padding: 0.25em .5em;
|
||||||
|
color: #222222;
|
||||||
|
background-color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.contains-task-list {
|
||||||
|
padding-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.contains-task-list ul.contains-task-list {
|
||||||
|
padding-left: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul.contains-task-list li input[type="checkbox"] {
|
||||||
|
margin-right: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-table,
|
||||||
|
.callout-table tr,
|
||||||
|
.callout-table p {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-table td {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.callout-table p {
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.source-table {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
var MERMAID_STYLESHEET = `
|
||||||
|
:root {
|
||||||
|
--default-font: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Microsoft YaHei Light", sans-serif;
|
||||||
|
--font-monospace: 'Source Code Pro', monospace;
|
||||||
|
--background-primary: #ffffff;
|
||||||
|
--background-modifier-border: #ddd;
|
||||||
|
--text-accent: #705dcf;
|
||||||
|
--text-accent-hover: #7a6ae6;
|
||||||
|
--text-normal: #2e3338;
|
||||||
|
--background-secondary: #f2f3f5;
|
||||||
|
--background-secondary-alt: #fcfcfc;
|
||||||
|
--text-muted: #888888;
|
||||||
|
--font-mermaid: ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Microsoft YaHei Light", sans-serif;
|
||||||
|
--text-error: #E4374B;
|
||||||
|
--background-primary-alt: '#fafafa';
|
||||||
|
--background-accent: '';
|
||||||
|
--interactive-accent: hsl( 254, 80%, calc( 68% + 2.5%));
|
||||||
|
--background-modifier-error: #E4374B;
|
||||||
|
--background-primary-alt: #fafafa;
|
||||||
|
--background-modifier-border: #e0e0e0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
var DEFAULT_HTML_TEMPLATE = `<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>\${title}</title>
|
||||||
|
<style>
|
||||||
|
\${MERMAID_STYLESHEET}
|
||||||
|
\${stylesheet}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
\${body}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
var copyIsRunning = false;
|
||||||
|
var ppIsProcessing = false;
|
||||||
|
var ppLastBlockDate = Date.now();
|
||||||
|
var documentRendererDefaults = {
|
||||||
|
convertSvgToBitmap: true,
|
||||||
|
removeFrontMatter: true,
|
||||||
|
formatCodeWithTables: false,
|
||||||
|
formatCalloutsWithTables: false,
|
||||||
|
embedExternalLinks: false,
|
||||||
|
removeDataviewMetadataLines: false,
|
||||||
|
footnoteHandling: 2 /* REMOVE_LINK */,
|
||||||
|
internalLinkHandling: 0 /* CONVERT_TO_TEXT */,
|
||||||
|
disableImageEmbedding: false
|
||||||
|
};
|
||||||
|
var DocumentRenderer = class {
|
||||||
|
constructor(app, options = documentRendererDefaults) {
|
||||||
|
this.app = app;
|
||||||
|
this.options = options;
|
||||||
|
this.optionRenderSettlingDelay = 100;
|
||||||
|
this.mimeMap = /* @__PURE__ */ new Map([
|
||||||
|
["svg", "image/svg+xml"],
|
||||||
|
["jpg", "image/jpeg"]
|
||||||
|
]);
|
||||||
|
this.externalSchemes = ["http", "https"];
|
||||||
|
this.vaultPath = this.app.vault.getRoot().vault.adapter.getBasePath().replace(/\\/g, "/");
|
||||||
|
this.vaultLocalUriPrefix = `app://local/${this.vaultPath}`;
|
||||||
|
this.vaultOpenUri = `obsidian://open?vault=${encodeURIComponent(this.app.vault.getName())}`;
|
||||||
|
this.vaultSearchUri = `obsidian://search?vault=${encodeURIComponent(this.app.vault.getName())}`;
|
||||||
|
this.view = new import_obsidian.Component();
|
||||||
|
}
|
||||||
|
async renderDocument(markdown, path) {
|
||||||
|
this.modal = new CopyingToHtmlModal(this.app);
|
||||||
|
this.modal.open();
|
||||||
|
try {
|
||||||
|
const topNode = await this.renderMarkdown(markdown, path);
|
||||||
|
return await this.transformHTML(topNode);
|
||||||
|
} finally {
|
||||||
|
this.modal.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async renderMarkdown(markdown, path) {
|
||||||
|
const processedMarkdown = this.preprocessMarkdown(markdown);
|
||||||
|
const wrapper = document.createElement("div");
|
||||||
|
wrapper.style.display = "hidden";
|
||||||
|
document.body.appendChild(wrapper);
|
||||||
|
await import_obsidian.MarkdownRenderer.render(this.app, processedMarkdown, wrapper, path, this.view);
|
||||||
|
await this.untilRendered();
|
||||||
|
await this.loadComponents(this.view);
|
||||||
|
const result = wrapper.cloneNode(true);
|
||||||
|
document.body.removeChild(wrapper);
|
||||||
|
this.view.unload();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
async loadComponents(view) {
|
||||||
|
const internalView = view;
|
||||||
|
const loadChildren = async (component, visited = /* @__PURE__ */ new Set()) => {
|
||||||
|
var _a, _b;
|
||||||
|
if (visited.has(component)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
visited.add(component);
|
||||||
|
const internalComponent = component;
|
||||||
|
if ((_a = internalComponent._children) == null ? void 0 : _a.length) {
|
||||||
|
for (const child of internalComponent._children) {
|
||||||
|
await loadChildren(child, visited);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (((_b = component == null ? void 0 : component.constructor) == null ? void 0 : _b.name) === "SheetElement") {
|
||||||
|
await component.onload();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error calling onload()`, error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await loadChildren(internalView);
|
||||||
|
}
|
||||||
|
preprocessMarkdown(markdown) {
|
||||||
|
let processed = markdown;
|
||||||
|
if (this.options.removeDataviewMetadataLines) {
|
||||||
|
processed = processed.replace(/^[^ \t:#`<>][^:#`<>]+::.*$/gm, "");
|
||||||
|
}
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
async untilRendered() {
|
||||||
|
while (ppIsProcessing || Date.now() - ppLastBlockDate < this.optionRenderSettlingDelay) {
|
||||||
|
if (ppLastBlockDate === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await delay(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async transformHTML(element) {
|
||||||
|
const node = element.cloneNode(true);
|
||||||
|
node.removeAttribute("style");
|
||||||
|
if (this.options.removeFrontMatter) {
|
||||||
|
this.removeFrontMatter(node);
|
||||||
|
}
|
||||||
|
this.replaceLinksOfClass(node, "internal-link");
|
||||||
|
this.replaceLinksOfClass(node, "tag");
|
||||||
|
this.makeCheckboxesReadOnly(node);
|
||||||
|
this.removeCollapseIndicators(node);
|
||||||
|
this.removeButtons(node);
|
||||||
|
this.removeStrangeNewWorldsLinks(node);
|
||||||
|
if (this.options.formatCodeWithTables) {
|
||||||
|
this.transformCodeToTables(node);
|
||||||
|
}
|
||||||
|
if (this.options.formatCalloutsWithTables) {
|
||||||
|
this.transformCalloutsToTables(node);
|
||||||
|
}
|
||||||
|
if (this.options.footnoteHandling == 0 /* REMOVE_ALL */) {
|
||||||
|
this.removeAllFootnotes(node);
|
||||||
|
}
|
||||||
|
if (this.options.footnoteHandling == 2 /* REMOVE_LINK */) {
|
||||||
|
this.removeFootnoteLinks(node);
|
||||||
|
} else if (this.options.footnoteHandling == 3 /* TITLE_ATTRIBUTE */) {
|
||||||
|
}
|
||||||
|
if (!this.options.disableImageEmbedding) {
|
||||||
|
await this.embedImages(node);
|
||||||
|
await this.renderSvg(node);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
removeFrontMatter(node) {
|
||||||
|
node.querySelectorAll(".frontmatter, .frontmatter-container").forEach((node2) => node2.remove());
|
||||||
|
}
|
||||||
|
replaceLinksOfClass(node, className) {
|
||||||
|
if (this.options.internalLinkHandling === 3 /* LEAVE_AS_IS */) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
node.querySelectorAll(`a.${className}`).forEach((node2) => {
|
||||||
|
switch (this.options.internalLinkHandling) {
|
||||||
|
case 1 /* CONVERT_TO_OBSIDIAN_URI */:
|
||||||
|
{
|
||||||
|
const linkNode = node2.parentNode.createEl("a");
|
||||||
|
linkNode.innerText = node2.getText();
|
||||||
|
if (className === "tag") {
|
||||||
|
linkNode.href = this.vaultSearchUri + "&query=tag:" + encodeURIComponent(node2.getAttribute("href"));
|
||||||
|
} else {
|
||||||
|
if (node2.getAttribute("href").startsWith("#")) {
|
||||||
|
linkNode.href = node2.getAttribute("href");
|
||||||
|
} else {
|
||||||
|
linkNode.href = this.vaultOpenUri + "&file=" + encodeURIComponent(node2.getAttribute("href"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
linkNode.className = className;
|
||||||
|
node2.parentNode.replaceChild(linkNode, node2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2 /* LINK_TO_HTML */:
|
||||||
|
{
|
||||||
|
const linkNode = node2.parentNode.createEl("a");
|
||||||
|
linkNode.innerText = node2.getAttribute("href");
|
||||||
|
linkNode.className = className;
|
||||||
|
if (node2.getAttribute("href").startsWith("#")) {
|
||||||
|
linkNode.href = node2.getAttribute("href");
|
||||||
|
} else {
|
||||||
|
linkNode.href = node2.getAttribute("href").replace(/^(.*?)(?:\.md)?(#.*?)?$/, "$1.html$2");
|
||||||
|
}
|
||||||
|
node2.parentNode.replaceChild(linkNode, node2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0 /* CONVERT_TO_TEXT */:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
const textNode = node2.parentNode.createEl("span");
|
||||||
|
textNode.innerText = node2.getText();
|
||||||
|
textNode.className = className;
|
||||||
|
node2.parentNode.replaceChild(textNode, node2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
makeCheckboxesReadOnly(node) {
|
||||||
|
node.querySelectorAll('input[type="checkbox"]').forEach((node2) => node2.setAttribute("disabled", "disabled"));
|
||||||
|
}
|
||||||
|
removeCollapseIndicators(node) {
|
||||||
|
node.querySelectorAll(".collapse-indicator").forEach((node2) => node2.remove());
|
||||||
|
}
|
||||||
|
removeButtons(node) {
|
||||||
|
node.querySelectorAll("button").forEach((node2) => node2.remove());
|
||||||
|
}
|
||||||
|
removeStrangeNewWorldsLinks(node) {
|
||||||
|
node.querySelectorAll(".snw-reference").forEach((node2) => node2.remove());
|
||||||
|
}
|
||||||
|
transformCodeToTables(node) {
|
||||||
|
node.querySelectorAll("pre").forEach((node2) => {
|
||||||
|
const codeEl = node2.querySelector("code");
|
||||||
|
if (codeEl) {
|
||||||
|
const code = codeEl.innerHTML.replace(/\n*$/, "");
|
||||||
|
const table = node2.parentElement.createEl("table");
|
||||||
|
table.className = "source-table";
|
||||||
|
table.innerHTML = `<tr><td><pre>${code}</pre></td></tr>`;
|
||||||
|
node2.parentElement.replaceChild(table, node2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
transformCalloutsToTables(node) {
|
||||||
|
node.querySelectorAll(".callout").forEach((node2) => {
|
||||||
|
var _a;
|
||||||
|
const callout = node2.parentElement.createEl("table");
|
||||||
|
callout.addClass("callout-table", "callout");
|
||||||
|
callout.setAttribute("data-callout", (_a = node2.getAttribute("data-callout")) != null ? _a : "quote");
|
||||||
|
const headRow = callout.createEl("tr");
|
||||||
|
const headColumn = headRow.createEl("td");
|
||||||
|
headColumn.addClass("callout-title");
|
||||||
|
const title = node2.querySelector(".callout-title-inner");
|
||||||
|
if (title) {
|
||||||
|
const span = headColumn.createEl("span");
|
||||||
|
span.innerHTML = title.innerHTML;
|
||||||
|
}
|
||||||
|
const originalContent = node2.querySelector(".callout-content");
|
||||||
|
if (originalContent) {
|
||||||
|
const row = callout.createEl("tr");
|
||||||
|
const column = row.createEl("td");
|
||||||
|
column.innerHTML = originalContent.innerHTML;
|
||||||
|
}
|
||||||
|
node2.replaceWith(callout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
removeAllFootnotes(node) {
|
||||||
|
node.querySelectorAll("section.footnotes").forEach((section) => section.parentNode.removeChild(section));
|
||||||
|
node.querySelectorAll(".footnote-link").forEach((link) => {
|
||||||
|
link.parentNode.parentNode.removeChild(link.parentNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
removeFootnoteLinks(node) {
|
||||||
|
node.querySelectorAll(".footnote-link").forEach((link) => {
|
||||||
|
const text = link.getText();
|
||||||
|
if (text === "\u21A9\uFE0E") {
|
||||||
|
link.parentNode.removeChild(link);
|
||||||
|
} else {
|
||||||
|
const span = link.parentNode.createEl("span", { text: link.getText(), cls: "footnote-link" });
|
||||||
|
link.parentNode.replaceChild(span, link);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async embedImages(node) {
|
||||||
|
const promises = [];
|
||||||
|
node.querySelectorAll("img").forEach((img) => {
|
||||||
|
if (img.src) {
|
||||||
|
if (img.src.startsWith("data:image/svg+xml") && this.options.convertSvgToBitmap) {
|
||||||
|
promises.push(this.replaceImageSource(img));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.options.embedExternalLinks) {
|
||||||
|
const [scheme] = img.src.split(":", 1);
|
||||||
|
if (this.externalSchemes.includes(scheme.toLowerCase())) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!img.src.startsWith("data:")) {
|
||||||
|
promises.push(this.replaceImageSource(img));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.modal.progress.max = 100;
|
||||||
|
await allWithProgress(promises, (percentCompleted) => this.modal.progress.value = percentCompleted);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
async renderSvg(node) {
|
||||||
|
const xmlSerializer = new XMLSerializer();
|
||||||
|
if (!this.options.convertSvgToBitmap) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
const promises = [];
|
||||||
|
const replaceSvg = async (svg) => {
|
||||||
|
const style = svg.querySelector("style") || svg.appendChild(document.createElement("style"));
|
||||||
|
style.innerHTML += MERMAID_STYLESHEET;
|
||||||
|
const svgAsString = xmlSerializer.serializeToString(svg);
|
||||||
|
const svgData = `data:image/svg+xml;base64,` + Buffer.from(svgAsString).toString("base64");
|
||||||
|
const dataUri = await this.imageToDataUri(svgData);
|
||||||
|
const img = svg.createEl("img");
|
||||||
|
img.style.cssText = svg.style.cssText;
|
||||||
|
img.src = dataUri;
|
||||||
|
svg.parentElement.replaceChild(img, svg);
|
||||||
|
};
|
||||||
|
node.querySelectorAll("svg").forEach((svg) => {
|
||||||
|
promises.push(replaceSvg(svg));
|
||||||
|
});
|
||||||
|
this.modal.progress.max = 0;
|
||||||
|
await allWithProgress(promises, (percentCompleted) => this.modal.progress.value = percentCompleted);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
async replaceImageSource(image) {
|
||||||
|
const imageSourcePath = decodeURI(image.src);
|
||||||
|
if (imageSourcePath.startsWith(this.vaultLocalUriPrefix)) {
|
||||||
|
let path = imageSourcePath.substring(this.vaultLocalUriPrefix.length + 1).replace(/[?#].*/, "");
|
||||||
|
path = decodeURI(path);
|
||||||
|
const mimeType = this.guessMimeType(path);
|
||||||
|
const data = await this.readFromVault(path, mimeType);
|
||||||
|
if (this.isSvg(mimeType) && this.options.convertSvgToBitmap) {
|
||||||
|
image.src = await this.imageToDataUri(data);
|
||||||
|
} else {
|
||||||
|
image.src = data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
image.src = await this.imageToDataUri(image.src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async imageToDataUri(url) {
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
const image = new Image();
|
||||||
|
image.setAttribute("crossOrigin", "anonymous");
|
||||||
|
const dataUriPromise = new Promise((resolve, reject) => {
|
||||||
|
image.onload = () => {
|
||||||
|
canvas.width = image.naturalWidth;
|
||||||
|
canvas.height = image.naturalHeight;
|
||||||
|
ctx.drawImage(image, 0, 0);
|
||||||
|
try {
|
||||||
|
const uri = canvas.toDataURL("image/png");
|
||||||
|
resolve(uri);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`failed ${url}`, err);
|
||||||
|
resolve(url);
|
||||||
|
}
|
||||||
|
canvas.remove();
|
||||||
|
};
|
||||||
|
image.onerror = (err) => {
|
||||||
|
console.log("could not load data uri");
|
||||||
|
resolve(url);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
image.src = url;
|
||||||
|
return dataUriPromise;
|
||||||
|
}
|
||||||
|
async readFromVault(path, mimeType) {
|
||||||
|
const tfile = this.app.vault.getAbstractFileByPath(path);
|
||||||
|
const data = await this.app.vault.readBinary(tfile);
|
||||||
|
return `data:${mimeType};base64,` + (0, import_obsidian.arrayBufferToBase64)(data);
|
||||||
|
}
|
||||||
|
guessMimeType(filePath) {
|
||||||
|
const extension = this.getExtension(filePath) || "png";
|
||||||
|
return this.mimeMap.get(extension) || `image/${extension}`;
|
||||||
|
}
|
||||||
|
getExtension(filePath) {
|
||||||
|
const fileName = filePath.slice(filePath.lastIndexOf("/") + 1);
|
||||||
|
return fileName.slice(fileName.lastIndexOf(".") + 1 || fileName.length).toLowerCase();
|
||||||
|
}
|
||||||
|
isSvg(mimeType) {
|
||||||
|
return mimeType === "image/svg+xml";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var CopyingToHtmlModal = class extends import_obsidian.Modal {
|
||||||
|
constructor(app) {
|
||||||
|
super(app);
|
||||||
|
}
|
||||||
|
get progress() {
|
||||||
|
return this._progress;
|
||||||
|
}
|
||||||
|
onOpen() {
|
||||||
|
const { titleEl, contentEl } = this;
|
||||||
|
titleEl.setText("Copying to clipboard");
|
||||||
|
this._progress = contentEl.createEl("progress");
|
||||||
|
this._progress.style.width = "100%";
|
||||||
|
}
|
||||||
|
onClose() {
|
||||||
|
const { contentEl } = this;
|
||||||
|
contentEl.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var _CopyDocumentAsHTMLSettingsTab = class extends import_obsidian.PluginSettingTab {
|
||||||
|
constructor(app, plugin) {
|
||||||
|
super(app, plugin);
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
display() {
|
||||||
|
const { containerEl } = this;
|
||||||
|
containerEl.empty();
|
||||||
|
containerEl.createEl("h2", { text: "Copy document as HTML Settings" });
|
||||||
|
containerEl.createEl("h3", { text: "Compatibility" });
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Convert SVG files to bitmap").setDesc("If checked, SVG files are converted to bitmap. This makes the copied documents heavier but improves compatibility (eg. with gmail).").addToggle((toggle) => toggle.setValue(this.plugin.settings.convertSvgToBitmap).onChange(async (value) => {
|
||||||
|
this.plugin.settings.convertSvgToBitmap = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Embed external images").setDesc("If checked, external images are downloaded and embedded. If unchecked, the resulting document may contain links to external resources").addToggle((toggle) => toggle.setValue(this.plugin.settings.embedExternalLinks).onChange(async (value) => {
|
||||||
|
this.plugin.settings.embedExternalLinks = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Render code with tables").setDesc("If checked code blocks are rendered as tables, which makes pasting into Google docs somewhat prettier.").addToggle((toggle) => toggle.setValue(this.plugin.settings.formatCodeWithTables).onChange(async (value) => {
|
||||||
|
this.plugin.settings.formatCodeWithTables = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Render callouts with tables").setDesc("If checked callouts are rendered as tables, which makes pasting into Google docs somewhat prettier.").addToggle((toggle) => toggle.setValue(this.plugin.settings.formatCalloutsWithTables).onChange(async (value) => {
|
||||||
|
this.plugin.settings.formatCalloutsWithTables = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
containerEl.createEl("h3", { text: "Rendering" });
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Include filename as header").setDesc("If checked, the filename is inserted as a level 1 header. (only if an entire document is copied)").addToggle((toggle) => toggle.setValue(this.plugin.settings.fileNameAsHeader).onChange(async (value) => {
|
||||||
|
this.plugin.settings.fileNameAsHeader = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Copy HTML fragment only").setDesc("If checked, only generate a HTML fragment and not a full HTML document. This excludes the header, and effectively disables all styling.").addToggle((toggle) => toggle.setValue(this.plugin.settings.bareHtmlOnly).onChange(async (value) => {
|
||||||
|
this.plugin.settings.bareHtmlOnly = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Remove properties / front-matter sections").setDesc("If checked, the YAML content between --- lines at the front of the document are removed. If you don't know what this means, leave it on.").addToggle((toggle) => toggle.setValue(this.plugin.settings.removeFrontMatter).onChange(async (value) => {
|
||||||
|
this.plugin.settings.removeFrontMatter = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Remove dataview metadata lines").setDesc(_CopyDocumentAsHTMLSettingsTab.createFragmentWithHTML(`
|
||||||
|
<p>Remove lines that only contain dataview meta-data, eg. "rating:: 9". Metadata between square brackets is left intact.</p>
|
||||||
|
<p>Current limitations are that lines starting with a space are not removed, and lines that look like metadata in code blocks are removed if they don't start with a space</p>`)).addToggle((toggle) => toggle.setValue(this.plugin.settings.removeDataviewMetadataLines).onChange(async (value) => {
|
||||||
|
this.plugin.settings.removeDataviewMetadataLines = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Footnote handling").setDesc(_CopyDocumentAsHTMLSettingsTab.createFragmentWithHTML(`
|
||||||
|
<ul>
|
||||||
|
<li>Remove everything: Remove references and links.</li>
|
||||||
|
<li>Display only: leave reference and foot-note, but don't display as a link.</li>
|
||||||
|
<li>Display and link: attempt to link the reference to the footnote, may not work depending on paste target.</li>
|
||||||
|
</ul>`)).addDropdown((dropdown) => dropdown.addOption(0 /* REMOVE_ALL */.toString(), "Remove everything").addOption(2 /* REMOVE_LINK */.toString(), "Display only").addOption(1 /* LEAVE_LINK */.toString(), "Display and link").setValue(this.plugin.settings.footnoteHandling.toString()).onChange(async (value) => {
|
||||||
|
switch (value) {
|
||||||
|
case 3 /* TITLE_ATTRIBUTE */.toString():
|
||||||
|
this.plugin.settings.footnoteHandling = 3 /* TITLE_ATTRIBUTE */;
|
||||||
|
break;
|
||||||
|
case 0 /* REMOVE_ALL */.toString():
|
||||||
|
this.plugin.settings.footnoteHandling = 0 /* REMOVE_ALL */;
|
||||||
|
break;
|
||||||
|
case 2 /* REMOVE_LINK */.toString():
|
||||||
|
this.plugin.settings.footnoteHandling = 2 /* REMOVE_LINK */;
|
||||||
|
break;
|
||||||
|
case 1 /* LEAVE_LINK */.toString():
|
||||||
|
default:
|
||||||
|
this.plugin.settings.footnoteHandling = 1 /* LEAVE_LINK */;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Link handling").setDesc(_CopyDocumentAsHTMLSettingsTab.createFragmentWithHTML(`
|
||||||
|
This option controls how links to Obsidian documents and tags are handled.
|
||||||
|
<ul>
|
||||||
|
<li>Don't link: only render the link title</li>
|
||||||
|
<li>Open with Obsidian: convert the link to an obsidian:// URI</li>
|
||||||
|
<li>Link to HTML: keep the link, but convert the extension to .html</li>
|
||||||
|
<li>Leave as is: keep the generated link</li>
|
||||||
|
</ul>`)).addDropdown((dropdown) => dropdown.addOption(0 /* CONVERT_TO_TEXT */.toString(), "Don't link").addOption(1 /* CONVERT_TO_OBSIDIAN_URI */.toString(), "Open with Obsidian").addOption(2 /* LINK_TO_HTML */.toString(), "Link to HTML").addOption(3 /* LEAVE_AS_IS */.toString(), "Leave as is").setValue(this.plugin.settings.internalLinkHandling.toString()).onChange(async (value) => {
|
||||||
|
switch (value) {
|
||||||
|
case 1 /* CONVERT_TO_OBSIDIAN_URI */.toString():
|
||||||
|
this.plugin.settings.internalLinkHandling = 1 /* CONVERT_TO_OBSIDIAN_URI */;
|
||||||
|
break;
|
||||||
|
case 2 /* LINK_TO_HTML */.toString():
|
||||||
|
this.plugin.settings.internalLinkHandling = 2 /* LINK_TO_HTML */;
|
||||||
|
break;
|
||||||
|
case 3 /* LEAVE_AS_IS */.toString():
|
||||||
|
this.plugin.settings.internalLinkHandling = 3 /* LEAVE_AS_IS */;
|
||||||
|
break;
|
||||||
|
case 0 /* CONVERT_TO_TEXT */.toString():
|
||||||
|
default:
|
||||||
|
this.plugin.settings.internalLinkHandling = 0 /* CONVERT_TO_TEXT */;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
containerEl.createEl("h3", { text: "Custom templates (advanced)" });
|
||||||
|
const useCustomStylesheetSetting = new import_obsidian.Setting(containerEl).setName("Provide a custom stylesheet").setDesc("The default stylesheet provides minimalistic theming. You may want to customize it for better looks. Disabling this setting will restore the default stylesheet.");
|
||||||
|
const customStylesheetSetting = new import_obsidian.Setting(containerEl).setClass("customizable-text-setting").addTextArea((textArea) => textArea.setValue(this.plugin.settings.styleSheet).onChange(async (value) => {
|
||||||
|
this.plugin.settings.styleSheet = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
useCustomStylesheetSetting.addToggle((toggle) => {
|
||||||
|
customStylesheetSetting.settingEl.toggle(this.plugin.settings.useCustomStylesheet);
|
||||||
|
toggle.setValue(this.plugin.settings.useCustomStylesheet).onChange(async (value) => {
|
||||||
|
this.plugin.settings.useCustomStylesheet = value;
|
||||||
|
customStylesheetSetting.settingEl.toggle(this.plugin.settings.useCustomStylesheet);
|
||||||
|
if (!value) {
|
||||||
|
this.plugin.settings.styleSheet = DEFAULT_STYLESHEET;
|
||||||
|
}
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const useCustomHtmlTemplateSetting = new import_obsidian.Setting(containerEl).setName("Provide a custom HTML template").setDesc(_CopyDocumentAsHTMLSettingsTab.createFragmentWithHTML(`For even more customization, you can
|
||||||
|
provide a custom HTML template. Disabling this setting will restore the default template.<br/><br/>
|
||||||
|
Note that the template is not used if the "Copy HTML fragment only" setting is enabled.`));
|
||||||
|
const customHtmlTemplateSetting = new import_obsidian.Setting(containerEl).setDesc(_CopyDocumentAsHTMLSettingsTab.createFragmentWithHTML(`
|
||||||
|
The template should include the following placeholders :<br/>
|
||||||
|
<ul>
|
||||||
|
<li><code>\${title}</code>: the document title</li>
|
||||||
|
<li><code>\${stylesheet}</code>: the CSS stylesheet. The custom stylesheet will be applied if any is specified</li>
|
||||||
|
<li><code>\${MERMAID_STYLESHEET}</code>: the CSS for mermaid diagrams</li>
|
||||||
|
<li><code>\${body}</code>: the document body</li>
|
||||||
|
</ul>`)).setClass("customizable-text-setting").addTextArea((textArea) => textArea.setValue(this.plugin.settings.htmlTemplate).onChange(async (value) => {
|
||||||
|
this.plugin.settings.htmlTemplate = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
useCustomHtmlTemplateSetting.addToggle((toggle) => {
|
||||||
|
customHtmlTemplateSetting.settingEl.toggle(this.plugin.settings.useCustomHtmlTemplate);
|
||||||
|
toggle.setValue(this.plugin.settings.useCustomHtmlTemplate).onChange(async (value) => {
|
||||||
|
this.plugin.settings.useCustomHtmlTemplate = value;
|
||||||
|
customHtmlTemplateSetting.settingEl.toggle(this.plugin.settings.useCustomHtmlTemplate);
|
||||||
|
if (!value) {
|
||||||
|
this.plugin.settings.htmlTemplate = DEFAULT_HTML_TEMPLATE;
|
||||||
|
}
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
containerEl.createEl("h3", { text: "Exotic / Developer options" });
|
||||||
|
new import_obsidian.Setting(containerEl).setName("Don't embed images").setDesc("When this option is enabled, images will not be embedded in the HTML document, but <em>broken</em> links will be left in place. This is not recommended.").addToggle((toggle) => toggle.setValue(this.plugin.settings.disableImageEmbedding).onChange(async (value) => {
|
||||||
|
this.plugin.settings.disableImageEmbedding = value;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var CopyDocumentAsHTMLSettingsTab = _CopyDocumentAsHTMLSettingsTab;
|
||||||
|
CopyDocumentAsHTMLSettingsTab.createFragmentWithHTML = (html) => createFragment((documentFragment) => documentFragment.createDiv().innerHTML = html);
|
||||||
|
var DEFAULT_SETTINGS = {
|
||||||
|
removeFrontMatter: true,
|
||||||
|
convertSvgToBitmap: true,
|
||||||
|
useCustomStylesheet: false,
|
||||||
|
useCustomHtmlTemplate: false,
|
||||||
|
embedExternalLinks: false,
|
||||||
|
removeDataviewMetadataLines: false,
|
||||||
|
formatCodeWithTables: false,
|
||||||
|
formatCalloutsWithTables: false,
|
||||||
|
footnoteHandling: 2 /* REMOVE_LINK */,
|
||||||
|
internalLinkHandling: 0 /* CONVERT_TO_TEXT */,
|
||||||
|
styleSheet: DEFAULT_STYLESHEET,
|
||||||
|
htmlTemplate: DEFAULT_HTML_TEMPLATE,
|
||||||
|
bareHtmlOnly: false,
|
||||||
|
fileNameAsHeader: false,
|
||||||
|
disableImageEmbedding: false
|
||||||
|
};
|
||||||
|
var CopyDocumentAsHTMLPlugin = class extends import_obsidian.Plugin {
|
||||||
|
async onload() {
|
||||||
|
await this.loadSettings();
|
||||||
|
this.addCommand({
|
||||||
|
id: "smart-copy-as-html",
|
||||||
|
name: "Copy selection or document to clipboard",
|
||||||
|
checkCallback: this.buildCheckCallback((view) => this.copyFromView(view, view.editor.somethingSelected()))
|
||||||
|
});
|
||||||
|
this.addCommand({
|
||||||
|
id: "copy-as-html",
|
||||||
|
name: "Copy entire document to clipboard",
|
||||||
|
checkCallback: this.buildCheckCallback((view) => this.copyFromView(view, false))
|
||||||
|
});
|
||||||
|
this.addCommand({
|
||||||
|
id: "copy-selection-as-html",
|
||||||
|
name: "Copy current selection to clipboard",
|
||||||
|
checkCallback: this.buildCheckCallback((view) => this.copyFromView(view, true))
|
||||||
|
});
|
||||||
|
const beforeAllPostProcessor = this.registerMarkdownPostProcessor(async () => {
|
||||||
|
ppIsProcessing = true;
|
||||||
|
});
|
||||||
|
beforeAllPostProcessor.sortOrder = -1e4;
|
||||||
|
const afterAllPostProcessor = this.registerMarkdownPostProcessor(async () => {
|
||||||
|
ppLastBlockDate = Date.now();
|
||||||
|
ppIsProcessing = false;
|
||||||
|
});
|
||||||
|
afterAllPostProcessor.sortOrder = 1e4;
|
||||||
|
this.addSettingTab(new CopyDocumentAsHTMLSettingsTab(this.app, this));
|
||||||
|
this.setupEditorMenuEntry();
|
||||||
|
}
|
||||||
|
async loadSettings() {
|
||||||
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||||
|
if (!this.settings.useCustomStylesheet) {
|
||||||
|
this.settings.styleSheet = DEFAULT_STYLESHEET;
|
||||||
|
}
|
||||||
|
if (!this.settings.useCustomHtmlTemplate) {
|
||||||
|
this.settings.htmlTemplate = DEFAULT_HTML_TEMPLATE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async saveSettings() {
|
||||||
|
await this.saveData(this.settings);
|
||||||
|
}
|
||||||
|
buildCheckCallback(action) {
|
||||||
|
return (checking) => {
|
||||||
|
if (copyIsRunning) {
|
||||||
|
console.log("Document is already being copied");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const activeView = this.app.workspace.getActiveViewOfType(import_obsidian.MarkdownView);
|
||||||
|
if (!activeView) {
|
||||||
|
console.log("Nothing to copy: No active markdown view");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!checking) {
|
||||||
|
action(activeView);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async copyFromView(activeView, onlySelected) {
|
||||||
|
if (!activeView.editor) {
|
||||||
|
console.error("No editor in active view, nothing to copy");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!activeView.file) {
|
||||||
|
console.error("No file in active view, nothing to copy");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const markdown = onlySelected ? activeView.editor.getSelection() : activeView.data;
|
||||||
|
const path = activeView.file.path;
|
||||||
|
const name = activeView.file.name;
|
||||||
|
return this.doCopy(markdown, path, name, !onlySelected);
|
||||||
|
}
|
||||||
|
async copyFromFile(file) {
|
||||||
|
if (!(file instanceof import_obsidian.TFile)) {
|
||||||
|
console.log(`cannot copy folder to HTML: ${file.path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (file.extension.toLowerCase() !== "md") {
|
||||||
|
console.log(`cannot only copy .md files to HTML: ${file.path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const markdown = await file.vault.cachedRead(file);
|
||||||
|
return this.doCopy(markdown, file.path, file.name, true);
|
||||||
|
}
|
||||||
|
async doCopy(markdown, path, name, isFullDocument) {
|
||||||
|
console.log(`Copying "${path}" to clipboard...`);
|
||||||
|
const title = name.replace(/\.md$/i, "");
|
||||||
|
const copier = new DocumentRenderer(this.app, this.settings);
|
||||||
|
try {
|
||||||
|
copyIsRunning = true;
|
||||||
|
ppLastBlockDate = Date.now();
|
||||||
|
ppIsProcessing = true;
|
||||||
|
const htmlBody = await copier.renderDocument(markdown, path);
|
||||||
|
if (this.settings.fileNameAsHeader && isFullDocument) {
|
||||||
|
const h1 = htmlBody.createEl("h1");
|
||||||
|
h1.innerHTML = title;
|
||||||
|
htmlBody.insertBefore(h1, htmlBody.firstChild);
|
||||||
|
}
|
||||||
|
const htmlDocument = this.settings.bareHtmlOnly ? htmlBody.outerHTML : this.expandHtmlTemplate(htmlBody.outerHTML, title);
|
||||||
|
const data = new ClipboardItem({
|
||||||
|
"text/html": new Blob([htmlDocument], {
|
||||||
|
type: ["text/html", "text/plain"]
|
||||||
|
}),
|
||||||
|
"text/plain": new Blob([htmlDocument], {
|
||||||
|
type: "text/plain"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
await navigator.clipboard.write([data]);
|
||||||
|
console.log(`Copied to clipboard as HTML`);
|
||||||
|
new import_obsidian.Notice(`Copied to clipboard as HTML`);
|
||||||
|
} catch (error) {
|
||||||
|
new import_obsidian.Notice(`copy failed: ${error}`);
|
||||||
|
console.error("copy failed", error);
|
||||||
|
} finally {
|
||||||
|
copyIsRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expandHtmlTemplate(html, title) {
|
||||||
|
const template = this.settings.useCustomHtmlTemplate ? this.settings.htmlTemplate : DEFAULT_HTML_TEMPLATE;
|
||||||
|
return template.replace("${title}", title).replace("${body}", html).replace("${stylesheet}", this.settings.styleSheet).replace("${MERMAID_STYLESHEET}", MERMAID_STYLESHEET);
|
||||||
|
}
|
||||||
|
setupEditorMenuEntry() {
|
||||||
|
this.registerEvent(this.app.workspace.on("file-menu", (menu, file, view) => {
|
||||||
|
menu.addItem((item) => {
|
||||||
|
item.setTitle("Copy as HTML").setIcon("clipboard-copy").onClick(async () => {
|
||||||
|
return this.copyFromFile(file);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* nosourcemap */
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"id": "copy-document-as-html",
|
||||||
|
"name": "Copy document as HTML",
|
||||||
|
"version": "0.8.1",
|
||||||
|
"minAppVersion": "1.6.3",
|
||||||
|
"description": "Copy the current document to clipboard as HTML, including images, diagrams etc...",
|
||||||
|
"author": "mvdkwast",
|
||||||
|
"authorUrl": "https://github.com/mvdkwast",
|
||||||
|
"isDesktopOnly": true
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
.customizable-text-setting {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizable-text-setting .setting-item-info {
|
||||||
|
width: 100%;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizable-text-setting .setting-item-info .setting-item-description {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizable-text-setting .setting-item-control {
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizable-text-setting .setting-item-control textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 15em;
|
||||||
|
}
|
||||||
+126
-82
@@ -18,30 +18,31 @@ yearly: "[[2026]]"
|
|||||||
|
|
||||||
Hello Team,
|
Hello Team,
|
||||||
|
|
||||||
Below is a comprehensive list of means & methods for {Project Name}.
|
Below is a comprehensive list of means & methods for **1990 K Street**.
|
||||||
Please confirm you have received this email and respond with any questions or comments.
|
Please confirm you have received this email
|
||||||
|
and respond with any questions or comments.
|
||||||
|
|
||||||
* **Takeoff Request Stage:** Full Takeoff
|
* **Takeoff Request Stage:** Full Takeoff
|
||||||
<!-- Stage 1, Stage 1 + Units, Full takeoff -->
|
%% Stage 1, Stage 1 + Units, Full takeoff %%
|
||||||
* **Delivery Method:** Plans & Specs
|
* **Delivery Method:** Plans & Specs
|
||||||
<!-- Plans & Specs, Design Build, Design Assist, P&S with Approved VE -->
|
%% Plans & Specs, Design Build, Design Assist, P&S with Approved VE %%
|
||||||
* **Document Stage:** Permit
|
* **Document Stage:** Permit
|
||||||
<!-- DD, CD, Permit, GMP, Bid, Awarded -->
|
%% DD, CD, Permit, GMP, Bid, Awarded %%
|
||||||
* **Drawings Date:** 2025-12-05
|
* **Drawings Date:** 2025-12-05
|
||||||
* **Project Manual Date:** 2025-10-29
|
* **Project Manual Date:** 2025-12-05
|
||||||
* **Proposal Date:** 2026-02-11
|
* **Proposal Date:** 2026-01-22
|
||||||
|
|
||||||
## Project Specification Callouts
|
### Project Specification Callouts
|
||||||
|
|
||||||
<!-- Put page of Drawing or PM after answer -->
|
%% Put page of Drawing or PM after answer %%
|
||||||
|
|
||||||
* **Conduit:**
|
* **Conduit:**
|
||||||
* EMT Fittings: Set-screw. _---Spec 260533.13 (p. 1423)_
|
* EMT Fittings: Set-screw _---Spec 260533.13 (p. 1423)_
|
||||||
<!-- GRC, coupling specs, etc. -->
|
%% GRC, coupling specs, etc. %%
|
||||||
|
|
||||||
* **Wire:**
|
* **Wire:**
|
||||||
* Material: Aluminum 100A and larger
|
* Material: Aluminum 100A and larger _---E021 "ALUMINUM FEEDER SCHEDULE" Note 1(b)_
|
||||||
* Acceptable Manufacturers:
|
* Acceptable Manufacturers: _---Spec 260519 (p. 1384)_
|
||||||
* Alpha Wire; Brand of Belden, Inc.
|
* Alpha Wire; Brand of Belden, Inc.
|
||||||
* Belden Inc.
|
* Belden Inc.
|
||||||
* Cerro Wire LLC
|
* Cerro Wire LLC
|
||||||
@@ -52,10 +53,10 @@ Please confirm you have received this email and respond with any questions or co
|
|||||||
* Southwire Company, LLC
|
* Southwire Company, LLC
|
||||||
* WESCO
|
* WESCO
|
||||||
|
|
||||||
* **MC Cable:**
|
* **MC Cable:**
|
||||||
* Application:
|
* Application: Concealed feeders and branch circuits _---Spec 260519 (p. 1389)_
|
||||||
<!-- Branch homeruns only; Not permitted -->
|
%% Branch homeruns only; Not permitted %%
|
||||||
* Acceptable Manufacturers:
|
* Acceptable Manufacturers: _---Spec 260519 (p. 1385-1386)_
|
||||||
* AFC Cable Systems; Atkore International
|
* AFC Cable Systems; Atkore International
|
||||||
* Alpha Wire; Brand of Belden, Inc.
|
* Alpha Wire; Brand of Belden, Inc.
|
||||||
* Belden Inc.
|
* Belden Inc.
|
||||||
@@ -65,26 +66,29 @@ Please confirm you have received this email and respond with any questions or co
|
|||||||
* Okonite Company
|
* Okonite Company
|
||||||
* Southwire Company, LLC
|
* Southwire Company, LLC
|
||||||
* WESCO
|
* WESCO
|
||||||
|
* ==Conductors: Copper _---Spec 260519 (p. 1386)_==
|
||||||
|
* ==Armor: Steel _---Spec 260519 (p. 1386)_==
|
||||||
|
* ==Jacket: PVC _---Spec 260519 (p. 1386)_==
|
||||||
|
|
||||||
* **Steel Box Depth:**
|
* **Steel Box Depth:**
|
||||||
* Telecom: 2-1/8" _---Spec 270500 (p. 1673)_
|
* Telecom: 2-1/8" _---Spec 270500 (p. 1673)_
|
||||||
* Security: 2-1/8" _---Spec 280500 (p. 1753)_
|
* Security: 2-1/8" _---Spec 280500 (p. 1753)_
|
||||||
* Other Applications: Not specified
|
* Other Applications: Not specified
|
||||||
<!-- 1-1/2", 2-1/8" -->
|
%% 1-1/2", 2-1/8" %%
|
||||||
|
|
||||||
* **Floor Boxes:**
|
* **Floor Boxes:** Sheet metal with brass or aluminum covers _---Spec 262719 (p. 1541)_
|
||||||
* Box Material:
|
|
||||||
<!-- Box: PVC, Sheet metal, Cast iron -->
|
|
||||||
* Cover Material:
|
|
||||||
<!-- Covers: Brass, Aluminum -->
|
|
||||||
|
|
||||||
* **Wiring Devices:**
|
* **Wiring Devices:**
|
||||||
* Units:
|
* Units:
|
||||||
<!-- 15A Decora -->
|
* Current rating: Unspecified. Assuming 15A for takeoff.
|
||||||
|
* Standard/Decora: Unspecified. Assuming Toggle/Duplex for takeoff.
|
||||||
|
%% 15A Decora %%
|
||||||
* BOH/Common Areas:
|
* BOH/Common Areas:
|
||||||
<!-- 20A Toggle/Duplex -->
|
* Current rating: Unspecified. Assuming 20A for takeoff.
|
||||||
|
* Standard/Decora: Unspecified. Assuming Toggle/Duplex for takeoff.
|
||||||
|
%% 20A Toggle/Duplex %%
|
||||||
|
|
||||||
* **Switchboards:**
|
* **Switchboards:**
|
||||||
* Acceptable Manufacturers: _---Spec 262413 (p. 1502)_
|
* Acceptable Manufacturers: _---Spec 262413 (p. 1502)_
|
||||||
* ABB, Electrification Business
|
* ABB, Electrification Business
|
||||||
* Eaton
|
* Eaton
|
||||||
@@ -92,31 +96,38 @@ Please confirm you have received this email and respond with any questions or co
|
|||||||
* Square D; Schneider Electric USA
|
* Square D; Schneider Electric USA
|
||||||
* General Electric
|
* General Electric
|
||||||
* Bus Material: Aluminum _---Spec 262413 (p. 1503)_
|
* Bus Material: Aluminum _---Spec 262413 (p. 1503)_
|
||||||
* Breaker Types:
|
* Interrupting Current Rating: Not specified.
|
||||||
<!-- Snap-on, bolt on -->
|
|
||||||
* AIC Ratings:
|
|
||||||
|
|
||||||
* **Panelboards:**
|
* **Distribution Panelboards:**
|
||||||
|
* Acceptable Manufacturers: _---Spec 262413 (p. 1514-1515)_
|
||||||
|
* Eaton
|
||||||
|
* Bus Material: Aluminum _---Spec 262413 (p. 1513)_
|
||||||
|
* Breaker Types: Bolt-on _---Spec 262413 (p. 1515)_
|
||||||
|
%% Snap-on, bolt on %%
|
||||||
|
* Interrupting Current Rating: Not specified.
|
||||||
|
|
||||||
|
* **Load Centers:**
|
||||||
* Acceptable Manufacturers: _---Spec 262413 (p. 1514-1515)_
|
* Acceptable Manufacturers: _---Spec 262413 (p. 1514-1515)_
|
||||||
* ABB, Electrification Business
|
* ABB, Electrification Business
|
||||||
* Eaton
|
* Eaton
|
||||||
* Siemens Industry, Inc., Energy Management Division
|
* Siemens Industry, Inc., Energy Management Division
|
||||||
* Square D; Schneider Electric USA
|
* Square D; Schneider Electric USA
|
||||||
* Bus Material:
|
* Bus Material: Aluminum _---Spec 262413 (p. 1513)_
|
||||||
* Breaker Types:
|
* Breaker Types: Plug-in _---Spec 262413 (p. 1515)_
|
||||||
<!-- Snap-on, bolt on -->
|
%% Snap-on, bolt on %%
|
||||||
* ACI Ratings:
|
* Interrupting Current Rating: Not specified.
|
||||||
|
* ==Covers shall be factory-applied white paint.== _---Dwg. E401-E405 "ELECTRICAL DRAWING NOTES" (P)_
|
||||||
|
|
||||||
* **Transformers:**
|
* **Transformers:**
|
||||||
* Winding Material: Aluminum _---Spec 262213 (p. 1495)_
|
* Winding Material: Aluminum _---Spec 262213 (p. 1495)_
|
||||||
* K-Rating: Not specified
|
* K-Rating: Not specified.
|
||||||
<!-- Windings AL or CU, K-rating -->
|
%% Windings AL or CU, K-rating %%
|
||||||
|
|
||||||
* **Generator:** (1) 600kW Diesel
|
* **Generator:** (1) 600kW Diesel
|
||||||
* Enclosure Specs: Level 2 Sound Attenuating Weatherproof Enclosure. _---Dwg. E014_
|
* Enclosure Specs: Level 2 Sound Attenuating Weatherproof Enclosure _---Dwg. E014_
|
||||||
* Remote Tank: None shown or specified.
|
* Remote Tank: None shown or specified.
|
||||||
* Tank Size: 24hrs at 100% load. _---Spec 263213.13 (p. 1604)_
|
* Tank Size: 24hrs at 100% load _---Spec 263213.13 (p. 1604)_
|
||||||
* Load Banks: Internal, 50% load. _---Dwg. E014, Spec 263213.13 (p. 1608)_
|
* Load Banks: Internal, 50% load _---Dwg. E014, Spec 263213.13 (p. 1608)_
|
||||||
* Acceptable Manufacturers: _---Spec 263213.13 (p. 1600)_
|
* Acceptable Manufacturers: _---Spec 263213.13 (p. 1600)_
|
||||||
* Caterpillar, Inc.; Electric Power Division
|
* Caterpillar, Inc.; Electric Power Division
|
||||||
* Cummins Power Generation
|
* Cummins Power Generation
|
||||||
@@ -125,58 +136,91 @@ Please confirm you have received this email and respond with any questions or co
|
|||||||
* Kohler Power Systems
|
* Kohler Power Systems
|
||||||
* Rolls-Royce Solutions America Inc
|
* Rolls-Royce Solutions America Inc
|
||||||
|
|
||||||
## Project Drawing/Detail Callouts
|
### Project Drawing/Detail Callouts
|
||||||
|
|
||||||
* **Describe conflicts between drawings / proposal:**
|
Dwg. IDS-01A "OUTLET SPECIFICATIONS": Screwless Cover
|
||||||
<!-- Plans show CU feeders, proposal calls for aluminum; Specification grade devices, etc. -->
|
|
||||||
|
|
||||||
* **Cost drivers in details not shown elsewhere on plans:**
|
Dwg. IDS-01A "SWITCHING SPECIFICATIONS": Legrand Tru-Universal Rocker/Dimmers
|
||||||
* <!-- Assuming this refers to lighting control -->
|
(Is this for Amenity/Common Areas?)
|
||||||
|
|
||||||
## PDI System Execution Plan
|
<!--
|
||||||
|
* **Describe conflicts between drawings / proposal**
|
||||||
|
%% Plans show CU feeders, proposal calls for aluminum; Specification grade devices, etc. %%
|
||||||
|
|
||||||
|
* **Cost drivers in details not shown elsewhere on plans**
|
||||||
|
%% Assuming this refers to lighting control %%
|
||||||
|
-->
|
||||||
|
|
||||||
|
### PDI System Execution Plan
|
||||||
|
|
||||||
* **Primaries:** Conduit and wiring excluded. _---Proposal 2026-01-22, Ex. B, Exclusions, Line 27_
|
* **Primaries:** Conduit and wiring excluded. _---Proposal 2026-01-22, Ex. B, Exclusions, Line 27_
|
||||||
<!-- Installation only, (9) 6" PVC -->
|
%% Installation only, (9) 6" PVC %%
|
||||||
* **Secondaries:** Wiring excluded. _---Proposal 2026-01-22, Ex. B, Exclusions, Line 28_
|
|
||||||
<!-- PVC UG, GRC Stub-ups, AL -->
|
* **Secondaries:**
|
||||||
* **Feeders:**
|
* Schedule 40 PVC UG; _---Proposal 2026-01-22, Ex. B, Inclusions Line 54-55_
|
||||||
<!-- PVC UG, EMT OH, AL over 100A, 2% VD -->
|
* wiring excluded. _---Proposal 2026-01-22, Ex. B, Exclusions, Line 28_
|
||||||
* **Unit Subfeeds:** EMT-SS, MC OH; PVC UG
|
%% PVC UG, GRC Stub-ups, AL %%
|
||||||
<!-- MC OH AL, VD per Chart on E5.01 -->
|
|
||||||
* **Units:**
|
* **Feeders:** PVC UG, EMT OH; AL 100A and larger; 2% voltage drop.
|
||||||
<!-- 15A Decora, Disposals, T-stat, Floor Boxes, Shade Control, Doorbells, Dimmer Switches, etc. -->
|
%% PVC UG, EMT OH, AL over 100A, 2% VD %%
|
||||||
* **Telecom:**
|
%% Emergency Feeds MI Cable %%
|
||||||
<!-- 42" MSDE, No Cable Homeruns, (1) 1" Back to IDF, CAT6 with Stub-ups -->
|
|
||||||
* **EV Chargers:**
|
* **Unit Subfeeds:** MC OH; size per E025-E028 meter bank schedules; 3% voltage drop.
|
||||||
<!-- (42) Conduit only, (56) Conduit & Wire, (20) Conduit, Wire & Equipment -->
|
%% MC OH AL, VD per Chart on E5.01 %%
|
||||||
|
|
||||||
|
* **Units:**
|
||||||
|
* DW/Disposal - Separate Circuit
|
||||||
|
* Range - \#6/3
|
||||||
|
* Kitchen Backsplash - Decora (Non-Combo Small Appliance Breakers)
|
||||||
|
* 120V Smokes
|
||||||
|
* EWH - \#8/2
|
||||||
|
* VRF HVAC
|
||||||
|
* 20A Toggle Switches
|
||||||
|
* 15A Duplex Receptacles
|
||||||
|
%% 15A Decora, Disposals, T-stat, Floor Boxes, Shade Control, Doorbells, Dimmer Switches, etc. %%
|
||||||
|
|
||||||
|
* **Telecom:**
|
||||||
|
* 30" MSDE; _---T0.32/1 Note 3: "PRIMEX SOHOPRO P3000ND"_
|
||||||
|
* (1) 1" innerduct to IDF. _---Proposal 2026-01-22, Ex. B, General Requirements, Line 114_
|
||||||
|
%% 42" MSDE, No Cable Homeruns, (1) 1" Back to IDF, CAT6 with Stub-ups %%
|
||||||
|
|
||||||
|
* **EV Chargers:** (2) dual circuit chargers with conduit, wire, data rough-in, and equipment.
|
||||||
|
%% (42) Conduit only, (56) Conduit & Wire, (20) Conduit, Wire & Equipment %%
|
||||||
|
|
||||||
* **Fire Alarm:** Devices PVC in-slab, Risers EMT.
|
* **Fire Alarm:** Devices PVC in-slab, Risers EMT.
|
||||||
<!-- Free-air where allowed by code. EMT Risers. -->
|
%% Free-air where allowed by code. EMT Risers. %%
|
||||||
* **DAS:** System included
|
|
||||||
<!-- Conduit only, Per PDI DAS Design -->
|
* **DAS:** System per PDI DAS Design.
|
||||||
|
%% Conduit only, Per PDI DAS Design %%
|
||||||
|
|
||||||
* **Low Voltage:** Free-air where allowed by code.
|
* **Low Voltage:** Free-air where allowed by code.
|
||||||
<!-- Free-air where allowed by code. Stub-ups to accessible ceilings. -->
|
%% Free-air where allowed by code. Stub-ups to accessible ceilings. %%
|
||||||
|
|
||||||
## Lighting Control
|
### Lighting Control
|
||||||
|
|
||||||
* **Scope:**
|
* **Basis of Takeoff:** Design per Plans and Specs _---Christian Pereiro 2026-02-11_
|
||||||
<!-- Code Minimum per Energy Code Assigned, P&S, PDI Design -->
|
%% Code Minimum per Energy Code Assigned, P&S, PDI Design %%
|
||||||
|
|
||||||
* **Area:** <!-- Assign Method to Areas: Line Voltage, Low-Voltage Stand Alone or Centralized System -->
|
* **Area:** _---Dwg. E021 "AUTOMATED LIGHTING CONTROL - SEQUENCES OF OPERATIONS"_
|
||||||
* BOH:
|
* BOH: Line Voltage Control, no dimming
|
||||||
* Corridor:
|
* Corridor: Digital Standalone Control, 0-10V dimming
|
||||||
* Amenity:
|
* Amenity: Digital Standalone Control, 0-10V dimming
|
||||||
* Site/Landscape:
|
* Offices: Digital Standalone Control, 0-10V dimming, controlled receptacles as shown
|
||||||
* Garage Entry Point
|
* Site/Landscape: Line Voltage Control, no dimming
|
||||||
* Office:
|
* Garage: Digital Standalone Control, 0-10V dimming
|
||||||
|
%% Assign Method to Areas: Line Voltage, Low-Voltage Stand Alone or Centralized System %%
|
||||||
|
|
||||||
## Tasks/Quotes Needed for WBS
|
Takeoff will utilize assemblies including
|
||||||
|
conduit rough-in, Cat5e cable, and device labor.
|
||||||
|
|
||||||
<!-- Delete any completed -->
|
### Tasks/Quotes Needed for WBS
|
||||||
|
|
||||||
<!-- * Electrical Constructability Review -->
|
%% Delete any completed %%
|
||||||
* Electrical VDC
|
|
||||||
|
%% * Electrical Constructability Review %%
|
||||||
|
%% * Electrical VDC %%
|
||||||
* Coordination Study
|
* Coordination Study
|
||||||
<!-- * DAS Public Safety Raceway Design -->
|
%% * DAS Public Safety Raceway Design %%
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
DAS Public Safety Raceway Design is necessary
|
DAS Public Safety Raceway Design is necessary
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
id:
|
||||||
|
aliases: []
|
||||||
|
title: 2026-02-12 09:49:56
|
||||||
|
tags:
|
||||||
|
- authorship/original
|
||||||
|
- destiny/permanent
|
||||||
|
- status/draft
|
||||||
|
- type/periodic/timestamped
|
||||||
|
daily: "[[2026-02-12]]"
|
||||||
|
dg-publish: true
|
||||||
|
monthly: "[[2026-02]]"
|
||||||
|
quarterly: "[[2026-Q1]]"
|
||||||
|
weekly: "[[2026-W07]]"
|
||||||
|
yearly: "[[2026]]"
|
||||||
|
---
|
||||||
|
# 2026-02-12 09:49:56
|
||||||
|
|
||||||
|
### Interrupting Rating
|
||||||
|
|
||||||
|
* "short-circuit interrupting rating"
|
||||||
|
|
||||||
|
Applies to "Equipment intended to interrupt current".
|
||||||
|
|
||||||
|
[[nfpa-70_110_requirements#110.9 Interrupting Rating.|110.9 Interrupting Rating.]]
|
||||||
|
|
||||||
|
Maximum current that the equipment can interrupt without damage.
|
||||||
|
Measured in amperes, usually shown as kAIC.
|
||||||
|
|
||||||
|
### Short-Circuit Current Rating (SCCR)
|
||||||
|
|
||||||
|
* "withstand rating"
|
||||||
|
|
||||||
|
[[nfpa-70_110_requirements#110.10 Circuit Impedance, Short-Circuit Current Ratings, and Other Characteristics.]]
|
||||||
|
|
||||||
|
Applies to **assemblies**: distribution equipment like switchboards, panelboards, switches, etc.
|
||||||
|
|
||||||
|
Maximum current that the equipment can withstand
|
||||||
|
in a short-circuit event without damage.
|
||||||
|
Measured in amperes, usually shown as kA.
|
||||||
Reference in New Issue
Block a user