Initial commit (after 2 months)

This commit is contained in:
Andrew Illarionov 2023-09-25 22:31:25 +03:00
parent 0a8167144b
commit 38a022e8a2
60 changed files with 5929 additions and 0 deletions

79
.gitignore vendored Normal file
View File

@ -0,0 +1,79 @@
### PhpStorm+all template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/index-static.iml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/index-static.iml" filepath="$PROJECT_DIR$/.idea/index-static.iml" />
</modules>
</component>
</project>

19
.idea/php.xml Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

23
blog/index.html Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/png" href="/favicon.png" />
<title>Enderman's Blog</title>
</head>
<body>
<h1>Enderman's Blog</h1>
<p>
<strong>An incredibly professional and profound placeholder for an index.html!</strong> What else do you need? It works. It navigates.<br>
Just kidding. I'm just busy with my actual job and life. I'll make a dynamic Vue website later.
</p>
<h3>Available blog posts:</h3>
<ul>
<li><a href="the-windows-context-menu">The Windows Context Menu &ndash; Is It a Lost Cause?</a></li>
</ul>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

View File

@ -0,0 +1,953 @@
<!DOCTYPE html>
<html>
<head>
<title>The Windows Context Menu &ndash; Is It a Lost Cause?</title>
<base href="./">
<meta id="root-path" root-path="./">
<link rel="icon" href="/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="UTF-8">
<meta name="Author" content="Endermanch">
<meta name="Keywords" content="windows, microsoft, microsoft windows, context menu, customization, winaero">
<meta name="Description" content="The Windows context menu is... poorly done. And third-party software developers adding oil into the dumpster fire aren't helping with it. It's not their fault, though.">
<meta property="og:type" content="article">
<meta property="og:title" content="The Windows Context Menu &ndash; Is It a Lost Cause?">
<meta property="og:description" content="The Windows context menu is... poorly done. And third-party software developers adding oil into the dumpster fire aren't helping with it. It's not their fault, though.">
<meta property="og:url" content="https://enderman.ch/blogs/the-windows-context-menu">
<meta property="og:image" content="http://enderman.ch/blogs/the-windows-context-menu/thumbnail.png">
<meta property="og:image:secure_url" content="https://enderman.ch/blogs/the-windows-context-menu/thumbnail.png">
<meta property="og:image:width" content="1920">
<meta property="og:image:height" content="1050">
<meta property="og:image:alt" content="Blog Thumbnail">
<meta property="og:image:type" content="image/png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content="@endermanch" />
<meta name="twitter:site" content="@endermanch" />
<meta name="twitter:label1" content="Written by" />
<meta name="twitter:data1" content="Andrew Illarionov" />
<meta name="twitter:label2" content="Est. reading time" />
<meta name="twitter:data2" content="15 minutes" />
<script src="https://code.iconify.design/iconify-icon/1.0.3/iconify-icon.min.js"></script>
<link rel="stylesheet" href="lib/styles/obsidian-styles.css">
<link rel="stylesheet" href="lib/styles/theme.css">
<link rel="stylesheet" href="lib/styles/plugin-styles.css">
<link rel="stylesheet" href="lib/styles/snippets.css">
<style>
div.absolute-container {
position: absolute;
z-index: 69;
top: 0;
left: 0;
}
div.less-than-opaque {
opacity: 0.85;
}
@media (max-width:960px) {
.the-export-html-plugin-developer-is-a-clown-that-cant-make-a-mobile-layout {
display: none;
}
}
@media (min-width:960px) {
.the-export-html-plugin-developer-is-a-clown-that-cant-make-a-mobile-layout {
display: block;
}
}
</style>
<script src="lib/scripts/webpage.js"></script>
</head>
<body class="mod-windows is-frameless is-hidden-frameless obsidian-app show-inline-title show-view-header is-maximized theme-light" style="--zoom-factor:1; --font-text-size:16px; --line-width:50em; --line-width-adaptive:50em; --file-line-width:50em; --content-width:500em; --sidebar-width:25em; --collapse-arrow-size:0.4em; --tree-horizontal-spacing:1em; --tree-vertical-spacing:0.5em; --sidebar-margin:12px;">
<div class="webpage-container">
<div class="absolute-container less-than-opaque">
<div>
<label class="theme-toggle-container" for="theme_toggle"><input class="theme-toggle-input" type="checkbox" id="theme_toggle">
<div class="toggle-background"></div>
</label>
</div>
</div>
<div class="document-container">
<div class="markdown-preview-view markdown-rendered node-insert-event is-readable-line-width allow-fold-headings show-indentation-guide allow-fold-lists" tabindex="-1" style="tab-size: 4;">
<style id="MJX-CHTML-styles"></style>
<div class="markdown-preview-sizer markdown-preview-section" style="padding-bottom: ; padding-top: var(--file-margins); padding-right: var(--file-margins); padding-left: var(--file-margins); width: 100%; position: absolute;">
<div class="markdown-preview-pusher" style="width: 1px; height: 0.1px; margin-bottom: 0px;"></div>
<div>
<h1 data-heading="The Windows Context Menu - Is It a Lost Cause?" id="The_Windows_Context_Menu_-_Is_It_a_Lost_Cause?">The Windows Context Menu &ndash; Is It a Lost Cause?</h1>
</div>
<div>
<p><span alt="Thumbnail.png" src="Thumbnail.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Thumbnail.png" src="thumbnail.png"></span></p>
</div>
<div>
<p>The Windows context menu is... poorly done.</p>
</div>
<div>
<p>And third-party software developers adding oil into the dumpster fire aren't helping with it. It's not their fault, though. There's no common standard and almost no documentation for adding entries into the context menu.</p>
</div>
<div>
<p>At this point, there's no return and no salvation for it. At very least it's working. What actually doesn't help is that Microsoft continued with their all time classic - piling up layers upon layers of indirection with their all new Windows 11 context menu, which is also poorly done and even more enclosed in terms of the API.</p>
</div>
<div>
<p>I want to dedicate this blog post to <em>actually customizing</em> the Windows 10/11 Legacy context menu to your liking instead of simply complaining about its inner workings. Using methods described in this article, you will be able to bring your menu from this abomination... </p>
</div>
<div>
<p><span alt="Before.png" src="Before.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Before.png" src="before.png"></span></p>
</div>
<div>
<p><strong>...to this!</strong></p>
</div>
<div>
<p><span alt="After.png" src="After.png" class="internal-embed media-embed image-embed is-loaded"><img alt="After.png" src="after.png"></span></p>
</div>
<div>
<p>Be aware - there's <em>plenty</em> of registry digging involved. And the truly worst part is...</p>
</div>
<div>
<p><strong>Forget any logic when dealing with registry keys.</strong> The idea of registry's structural integrity has long since been abandoned and nobody seems to care about it as, well, the end user is never going to care about it, and if they do - they know what they're doing and they will not complain.<br>
While there are layers of abstraction applied to the most Windows settings, the context menu is, unfortunately, left aside. And much to our dismay, its backend is also janky, terrible and tangled up.</p>
</div>
<div>
<p>The only fair question to reader from me is "Do you really believe it's worth your time?". And if your answer is yes, and you're as much of a perfectionist as I am, buckle up and get ready for upcoming few hours of pure joy. </p>
</div>
<div>
<p>Please note that any <code>sfc /scannow</code> or <code>dism /restorehealth</code> invocations will probably interfere with your context menu as Microsoft are really weird - they seem to allow customization of it, but still don't fully support it. It's been like this for at least 20 years.</p>
</div>
<div>
<h2 data-heading="Shell entries &amp; Context Menu handlers" id="Shell_entries_&amp;_Context_Menu_handlers" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Shell entries &amp; Context Menu handlers
</h2>
</div>
<div>
<p>There are two main ways to insert entries into the context menu:</p>
</div>
<div>
<ul class="has-list-bullet">
<li data-line="0">
<div class="list-bullet"></div>Shell entries
</li>
<li data-line="1">
<div class="list-bullet"></div>Context Menu handlers
</li>
</ul>
</div>
<div>
<p>Both of them are very poorly documented, but the idea is very simple: whereas Shell entries are managed by the registry, the Context Menu handlers are managed by the software in question.<br>
Shell entries are much, much better in terms of flexibility and customization (in fact, you don't get any customization with Context Menu handlers at all, unless the developer was nice enough to let you tweak context menu settings through their app or provide necessary documentation for registry endpoints). 7-Zip would serve as a neat example of <strong>good software design</strong>, as the creator allows you to tweak settings of their handler.</p>
</div>
<div>
<p><span alt="7-Zip Context Menu Settings.png" src="7-Zip Context Menu Settings.png" class="internal-embed media-embed image-embed is-loaded"><img alt="7-Zip Context Menu Settings.png" src="7-zip-context-menu-settings.png"></span></p>
</div>
<div>
<p>MobaXterm would also serve as a nice example for the case, where shell entries are used, but you can tweak them from the app itself.</p>
</div>
<div>
<p><span alt="MobaXterm Context Menu Settings.png" src="MobaXterm Context Menu Settings.png" class="internal-embed media-embed image-embed is-loaded"><img alt="MobaXterm Context Menu Settings.png" src="mobaxterm-context-menu-settings.png"></span></p>
</div>
<div>
<p>And so, there are 3 types of applications in terms of their context menu customization-friendliness:</p>
</div>
<div>
<ul class="has-list-bullet">
<li data-line="0">
<div class="list-bullet"></div>Context Menu handler apps with in-app settings <em>(the easiest)</em>
</li>
<li data-line="1">
<div class="list-bullet"></div>Apps using shell entries <em>(customizable via registry hacks or from within software)</em>
</li>
<li data-line="2">
<div class="list-bullet"></div>Context Menu handler apps without anything <em>(uneditable entries)</em>
</li>
</ul>
</div>
<div>
<p>The first case is the simplest - you just have to consult the documentation of software you're using to find out whether it supports context menu customization or not.</p>
</div>
<div>
<p>The other two cases is what I'm going to tackle in this write-up.</p>
</div>
<div>
<p>For starters, all modifications are done under <code>HKEY_CLASSES_ROOT</code> (the <code>HKEY_LOCAL_MACHINE\Software\Classes</code> alias). That hive contains data about shell components and file extensions. For example, any data under <code>exefile</code> will apply to all executable files. That's one of the methods companion viruses utilized back in the day to accompany their victims - the <code>.exe</code>/<code>.com</code> files. Either way, since the <code>HKCR</code> hive is basically divided into file/shell extensions, we will have to edit context menu for <em>each file and shell extension</em> manually. Yeah. This is absolutely <strong>abysmal</strong>. There is no better way to approach this. And while you might already be reconsidering your choices, <strong>let me teach you the basics so you could at least bring your most used extensions and most noticeable context menu areas up to par...</strong> Some generalizations are also made within the registry. For instance, there are wildcard entries for ALL files, or for ALL images and so on. That still does not excuse the horrible approach Microsoft has taken with the file extensions from the beginning.</p>
</div>
<div>
<p>Even though the incompleteness always annoyed me, unfortunately, that's how sometimes life is.</p>
</div>
<div>
<p><strong>This is how the general structure of an extension looks like:</strong><br>
<span alt="EXE File Registry Structure.png" src="EXE File Registry Structure.png" class="internal-embed media-embed image-embed is-loaded"><img alt="EXE File Registry Structure.png" src="exe-file-registry-structure.png"></span>
</p>
</div>
<div>
<p>Editable entries are stored under the <code>Shell</code> key. Uneditable/highly customizable (thanks to the developer) entires are stored under <code>ShellEx</code>. Capitalization plays no role, the Windows registry key names is case-insensitive. The value names, however, are. <del>What a nice spec!</del></p>
</div>
<div>
<h3 data-heading="Sort of editable entries?" id="Sort_of_editable_entries?" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Sort of editable entries?
</h3>
</div>
<div>
<p>The structure varies from extension to extension, but you know you've found it when you see the <code>Shell</code> key. Subkeys of it represent the "shell entries" - or, well, customizable entries of the context menu.</p>
</div>
<div>
<p><span alt="Directory.png" src="Directory.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Directory.png" src="directory.png"></span></p>
</div>
<div>
<p>Each shell entry contains the <code>command</code> subkey, default value of which controls <em>what</em> executes upon clicking on the context menu entry.<br>
The default entry follows the Batch syntax, albeit very poorly. You <strong>cannot</strong> have extended Batch logic in the entries, which made me immeasurably sad and also made me write utilities called <code>quiet</code> and <code>elevate</code> for that specific purpose. No matter how hard I tried, I could not find the spec for the extents of the Batch logic in the default value for <code>command</code>.</p>
</div>
<div>
<p><span alt="Shell Entry Structure.png" src="Shell Entry Structure.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Shell Entry Structure.png" src="shell-entry-structure.png"></span><br>
<span alt="Command Verb.png" src="Command Verb.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Command Verb.png" src="command-verb.png"></span>
</p>
</div>
<div>
<p>In general, I'd suggest you to treat the <code>command</code> value as the raw command line, but with the <code>%1</code> macro for the full input file path without quotation marks (e.g. if you right-click <code>C:\Users\bleh\p.txt</code>, and click on your own shell entry, the <code>%1</code> within <code>command</code> will be equivalent to <code>C:\Users\bleh\p.txt</code>) and <code>%V</code> for the full directory path. That must be one of the few values to be consistent across all the shell entries.</p>
</div>
<div>
<p>Sometimes <code>command</code>'s default value is left unused for <code>DelegateExecute</code> to take its place.<br>
If that's the case, that means the command handler is implemented as an IExecuteCommand COM object, or, well, you can't really customize it. All it contains is the UUID of the read-only object.</p>
</div>
<div>
<p><span alt="DelegateExecute.png" src="DelegateExecute.png" class="internal-embed media-embed image-embed is-loaded"><img alt="DelegateExecute.png" src="delegateexecute.png"></span></p>
</div>
<div>
<h4 data-heading="Adding entries" id="Adding_entries" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Adding entries
</h4>
</div>
<div>
<ol>
<li data-line="0">Locate the extension (be it a file, or a shell one) you want to target.</li>
<li data-line="1">Careful! Some extensions can be buried within other extensions. For example, the folder background extension is located inside the folder extension under the <code>Background</code> key.</li>
<li data-line="2">Navigate to the <code>shell</code> key. If there is none and you're confident there should be one (by feel!), try creating one (it's highly likely not going to affect the system stability).</li>
<li data-line="3">Create a new entry, you can call it whatever you want, but it should be alphanumeric.</li>
<li data-line="4">Create a <code>command</code> key.</li>
<li data-line="5">Specify the command line you want to execute upon the click of your entry.</li>
<li data-line="6">The entry should appear in the context menu. If it does not, restart Explorer. If it still doesn't appear, you've probably messed up the procedure or the extension isn't registered in Windows.</li>
</ol>
</div>
<div>
<h4 data-heading="Nesting entries" id="Nesting_entries" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Nesting entries
</h4>
</div>
<div>
<p>You can nest entries too! Repeat the first 4 steps from <a data-href="The Windows Context Menu#Adding entries" href="the-windows-context-menu.html#Adding_entries" class="internal-link" target="_self" rel="noopener">The Windows Context Menu &gt; Adding entries</a>, but don't add the <code>command</code> key yet. Instead, create another <code>shell</code> key, and then inside of it create a key <em>not called</em> <code>command</code>. And working in that new key, repeat last 3 steps. Finally, get back to your initial ancestor entry and add an empty REG_SZ value called <code>SubCommands</code>.</p>
</div>
<div>
<p><span alt="Nested Entries Structure.png" src="Nested Entries Structure.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Nested Entries Structure.png" src="nested-entries-structure.png"></span><br>
<span alt="SubCommands.png" src="SubCommands.png" class="internal-embed media-embed image-embed is-loaded"><img alt="SubCommands.png" src="subcommands.png"></span>
</p>
</div>
<div>
<p>You can make an entry have only a single nested entry as well, I've tested it. </p>
</div>
<div>
<p><span alt="Nested Entries.png" src="Nested Entries.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Nested Entries.png" src="nested-entries.png"></span></p>
</div>
<div>
<p>To control the parent context menu entry, use the outer <code>Shell</code> entry subkey.</p>
</div>
<div>
<p><span alt="Nested Entries Order.png" src="Nested Entries Order.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Nested Entries Order.png" src="nested-entries-order.png"></span></p>
</div>
<div>
<p>To control its children, use the inner <code>Shell</code> entry subkeys.</p>
</div>
<div>
<p><span alt="Nested Entries Order 2.png" src="Nested Entries Order 2.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Nested Entries Order 2.png" src="nested-entries-order-2.png"></span></p>
</div>
<div>
<h4 data-heading="Editing entries" id="Editing_entries" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Editing entries
</h4>
</div>
<div>
<p>Now you're probably wondering how to name the entries and add nice little icons next to them.<br>
By default, the context menu entries duplicate their names from their respective shell subkeys.</p>
</div>
<div>
<h6 data-heading="Name" id="Name" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Name
</h6>
</div>
<div>
<p>To override the default name, you can use either the <code>(Default)</code> or <code>MUIVerb</code> REG_SZ values inside the respective shell entry (not <code>command</code>). <code>MUIVerb</code> takes precedence over the default value.</p>
</div>
<div>
<p>You can put in anything you want, it's going to work.</p>
</div>
<div>
<h6 data-heading="Icon" id="Icon" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Icon
</h6>
</div>
<div>
<p>To enable the icon for your shell entry, you should use the <code>Icon</code> REG_SZ value inside the respective shell entry. It uses that weird WinAPI resource syntax to create a direct link to the icon.</p>
</div>
<div>
<pre class="language-c" tabindex="0"><code class="language-c is-loaded">PATH_TO_FILE_WITH_ICON_RESOURCES<span class="token punctuation">,</span>INDEX
</code><button class="copy-code-button">Copy</button></pre>
</div>
<div>
<p>If you want to select the first icon (in that case, the <code>INDEX</code> part is 0), the <code>INDEX</code> part can be omitted completely, as in:</p>
</div>
<div>
<pre class="language-c" tabindex="0"><code class="language-c is-loaded">PATH_TO_FILE_WITH_ICON_RESOURCES
</code><button class="copy-code-button">Copy</button></pre>
</div>
<div>
<p>For example, the following expressions are completely valid and are going to work:</p>
</div>
<div>
<pre class="language-c" tabindex="0"><code class="language-c is-loaded"><span class="token string">"C:\Windows\system32\cmd.exe"</span>
C<span class="token operator">:</span>\Windows\regedit<span class="token punctuation">.</span>exe
<span class="token string">"C:\Windows\explorer.exe"</span><span class="token punctuation">,</span><span class="token number">0</span>
C<span class="token operator">:</span>\Windows\system32\cmd<span class="token punctuation">.</span>exe<span class="token punctuation">,</span><span class="token number">0</span>
cmd<span class="token punctuation">.</span>exe
shell32<span class="token punctuation">.</span>dll<span class="token punctuation">,</span><span class="token number">3</span>
SHELL32<span class="token punctuation">.</span>DLL<span class="token punctuation">,</span><span class="token number">10</span>
<span class="token string">"C:\Windows\system32\SHELL32.DLL"</span><span class="token punctuation">,</span><span class="token number">9</span>
</code><button class="copy-code-button">Copy</button></pre>
</div>
<div>
<p>You can omit the quotes and full paths depending on the <code>%PATH%</code> variable that unholy concoction of an API uses. Only God knows what paths it's able to parse by default. <code>C:\Windows</code>, <code>C:\Windows\system32</code> work for sure, though.</p>
</div>
<div>
<p>I still highly suggest supplying the full path to file, as <strong>even the <code>%PATH%</code>s of the Explorer's icon picker and the <code>Icon</code> value do not seem to correspond</strong>.</p>
</div>
<div>
<p><strong>Tip:</strong> you can use the Explorer folder icon picker to acquire the icon DLL and calculate the offset of the desired icon. For example, the one I've selected in the screenshot has an index of <code>5</code>.</p>
</div>
<div>
<p>Indexing begins with <code>0</code> and ascends in columns. </p>
</div>
<div>
<p><span alt="Icon Viewer.png" src="Icon Viewer.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Icon Viewer.png" src="icon-viewer.png"></span></p>
</div>
<div>
<p><strong>You can also pull resource strings from files the same way for MUI Verbs and default values.</strong></p>
</div>
<div>
<p><span alt="DLL Syntax.png" src="DLL Syntax.png" class="internal-embed media-embed image-embed is-loaded"><img alt="DLL Syntax.png" src="dll-syntax.png"></span></p>
</div>
<div>
<h6 data-heading="Separators" id="Separators" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Separators
</h6>
</div>
<div>
<p>Another integral part of the context menu, which is hardly documented by anyone. Managing them is also rather quirky, but you get used to it after some time.</p>
</div>
<div>
<p>Separators in shell entries are <strong>relative to the element you're enabling them for</strong> and <strong>can overlap</strong> without any issue.</p>
</div>
<div>
<p>Use <code>SeparatorBefore</code> and <code>SeparatorAfter</code> empty REG_SZ values to add a separator before or after the entry you're editing, respectively. </p>
</div>
<div>
<p><span alt="Separators.png" src="Separators.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Separators.png" src="separators.png"></span></p>
</div>
<div>
<h6 data-heading="Appear in the Shift+Click context menu only" id="Appear_in_the_Shift+Click_context_menu_only" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Appear in the Shift+Click context menu only
</h6>
</div>
<div>
<p>You can make your shell entry be "hidden" from a normal context menu click. Such entry is called "extended". It's possible to enable that functionality by creating an empty REG_SZ value called <code>Extended</code> inside the respective shell entry. </p>
</div>
<div>
<h6 data-heading="Position override" id="Position_override" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Position override
</h6>
</div>
<div>
<p>See <a data-href="The Windows Context Menu#Sorting entries#Position override" href="the-windows-context-menu.html#Sorting_entries" class="internal-link" target="_self" rel="noopener">The Windows Context Menu &gt; Sorting entries &gt; Position override</a></p>
</div>
<div>
<h6 data-heading="Hide in Safe Mode" id="Hide_in_Safe_Mode" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Hide in Safe Mode
</h6>
</div>
<div>
<p>To hide the context menu entry in safe mode, create an empty REG_SZ value called <code>HideInSafeMode</code> inside the respective shell entry.</p>
</div>
<div>
<h6 data-heading="Never default" id="Never_default" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Never default
</h6>
</div>
<div>
<p>An example of a default entry would be "Open" for folders, or generally the bold context menu entry shown at the top. That's the entry Windows will default to when you open the file with a certain extension. </p>
</div>
<div>
<p><span alt="Media.png" src="Media.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Media.png" src="media.png"></span></p>
</div>
<div>
<p>There can be no default entry at all, and that's perfectly fine. If you don't want your entry to show up as a default one, add an empty REG_SZ value called <code>NeverDefault</code> into the respective shell entry.</p>
</div>
<div>
<h6 data-heading="Pass through to Context Menu handlers" id="Pass_through_to_Context_Menu_handlers" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Pass through to Context Menu handlers
</h6>
</div>
<div>
<p>If you know what context handler you want to invoke on shell entry click, you can specify a so-called Verb Handler.</p>
</div>
<div>
<p>Create a new REG_SZ value <code>VerbHandler</code> and specify the context menu handler's UUID as data.</p>
</div>
<div>
<p><span alt="Context Menu Handler 1.png" src="Context Menu Handler 1.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Context Menu Handler 1.png" src="context-menu-handler-1.png"></span><br>
<span alt="Context Menu Handler 2.png" src="Context Menu Handler 2.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Context Menu Handler 2.png" src="context-menu-handler-2.png"></span>
</p>
</div>
<div>
<h6 data-heading="Other options" id="Other_options" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Other options
</h6>
</div>
<div>
<p>I am not ashamed to admit that I have absolutely zero idea what some of the options do, even though they might sound obvious.</p>
</div>
<div>
<p><strong>If you do have the knowledge, please contact me on Twitter: @endermanch or send a mail my way: <a data-tooltip-position="top" aria-label="mailto:blogs@enderman.ch" rel="noopener" class="external-link" href="mailto:blogs@enderman.ch" target="_blank">blogs@enderman.ch</a></strong></p>
</div>
<div>
<p><strong>For example:</strong><br>
<code>NoWorkingDirectory</code> - could be hiding the working directory from the app it's starting?<br>
<code>CanonicalName</code><br>
<code>CommandStateHandler</code><br>
<code>CommandStateSync</code><br>
<code>Description</code><br>
<code>VerbName</code>
</p>
</div>
<div>
<h4 data-heading="Deleting entries" id="Deleting_entries" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Deleting entries
</h4>
</div>
<div>
<p>Pretty much the opposite of adding one.</p>
</div>
<div>
<ol>
<li data-line="0">Locate the extension (be it a file, or a shell one) you want to target.</li>
<li data-line="1">Sometimes multiple locations can correspond to the same place in the context menu, which might result in the entry remaining in place, even though you've deleted it.</li>
<li data-line="2">Navigate to the <code>shell</code> key.</li>
<li data-line="3">Find the shell entry you want to delete. You can find out the application behind it by looking into the default value of the <code>command</code> key. </li>
<li data-line="4">Delete the key.</li>
</ol>
</div>
<div>
<h4 data-heading="Sorting entries" id="Sorting_entries" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Sorting entries
</h4>
</div>
<div>
<p>Now that's the funniest one. I even memed about it on Twitter.<br>
The only way to sort the context menu is <strong>via the alphabetical order of its respective shell entries in the registry</strong>. Yes. I am not kidding. Let the screenshots speak for themselves.</p>
</div>
<div>
<p><span alt="Alphabetical Sort 1.png" src="Alphabetical Sort 1.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Alphabetical Sort 1.png" src="alphabetical-sort-1.png"></span><br>
<span alt="Alphabetical Sort 2.png" src="Alphabetical Sort 2.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Alphabetical Sort 2.png" src="alphabetical-sort-2.png"></span>
</p>
</div>
<div>
<p>Yeah... <em>I'd rather not comment that.</em></p>
</div>
<div>
<h6 data-heading="Position override" id="Position_override" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Position override
</h6>
</div>
<div>
<p>Another silly and janky feature that has a limited amount of use cases. You can manually override the position of your context menu item to be... either at the <strong>very top</strong>, or the <strong>very bottom</strong>. Not much better than alphabetical sorting if you ask me...</p>
</div>
<div>
<p>In your entry under <code>shell</code>, create a REG_SZ value called <code>Position</code>.<br>
If you want to force the context menu handler to the top, put <code>Top</code> as data, otherwise put <code>Bottom</code>. </p>
</div>
<div>
<p>Sometimes this may be necessary, as, for example, Microsoft dumps their regular alphabetical sorting strategy at the bottom of the context menu, where display and personalization settings reside. They simply specify the <code>Bottom</code> position for each of the entries. If I recall correctly, they're still sorted alphabetically between themselves, as position override takes precedence.</p>
</div>
<div>
<p><span alt="Position Override.png" src="Position Override.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Position Override.png" src="position-override.png"></span></p>
</div>
<div>
<h4 data-heading="Bottom line" id="Bottom_line" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Bottom line
</h4>
</div>
<div>
<p>Some of the default shell entries like <code>Powershell</code> have specific keys (for the sake of that example, <code>ProgrammaticAccessOnly</code>) to control their appearance context menu.</p>
</div>
<div>
<p>As a rule of thumb, every time you're dealing with existing shell entries, I <strong>REALLY</strong> suggest you to <strong>search for a way to modify them online before resorting to any of the general cases I've described above</strong>. If you can't find anything even on the Internet, well, anything works. </p>
</div>
<div>
<h3 data-heading="Uneditable entries" id="Uneditable_entries" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Uneditable entries
</h3>
</div>
<div>
<p>As for the Context Menu handlers, there's actually not much you can do. They're located under the <code>shellex\ContextMenuHandlers</code> subkey.</p>
</div>
<div>
<p><span alt="Context Menu Handler 3.png" src="Context Menu Handler 3.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Context Menu Handler 3.png" src="context-menu-handler-3.png"></span></p>
</div>
<div>
<p>Most of the times, the only data they contain is a lonely UUID. That doesn't help much.</p>
</div>
<div>
<p><span alt="Context Menu Handler 4.png" src="Context Menu Handler 4.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Context Menu Handler 4.png" src="context-menu-handler-4.png"></span></p>
</div>
<div>
<p>So, to remove the Context Menu handler, you should just delete the subkey under <code>ContextMenuHandlers</code>. I strongly suggest you save the UUID it contained so that you could roll back at any time later.</p>
</div>
<div>
<p><span alt="Context Menu Handler 5.png" src="Context Menu Handler 5.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Context Menu Handler 5.png" src="context-menu-handler-5.png"></span></p>
</div>
<div>
<p>Adding your own... Well, that's complicated. You actually have to write your own handler in a language supporting Windows API or any sort of an abstraction of it. For example, <strong>C# is a decent choice</strong>. I don't suggest you waste time on this, unless you're making full-on software that you want to make more accessible to Windows users.</p>
</div>
<div>
<h2 data-heading="Dealing with locked keys" id="Dealing_with_locked_keys" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Dealing with locked keys
</h2>
</div>
<div>
<p>If the registry key is locked and you don't have write permissions for it, it's owned by TrustedInstaller and you have to manually reclaim ownership of the key and allow yourself to make edits to it.</p>
</div>
<div>
<p><strong>Optimal way:</strong> Using Process Hacker with the TrustedInstaller plugin or Winaero Tweaker, run <code>regedit</code> as Trusted Installer and perform necessary tweaks.</p>
</div>
<div>
<p><strong>General solution:</strong></p>
</div>
<div>
<ol>
<li data-line="0">Navigate to the key you want to take ownership of</li>
<li data-line="1">Open the <code>Properties</code> window</li>
<li data-line="2">Head over to the <code>Advanced</code> tab</li>
<li data-line="3">At the top of the Advanced Security Settings it states <code>Owner: TrustedInstaller</code>. Click <code>Change</code></li>
<li data-line="4">Input your username into the <code>Enter the object name to select (examples)</code> text area.</li>
<li data-line="5">Click <code>OK</code></li>
<li data-line="6">Check the <code>Replace owner on subcontainers and objects</code> checkbox</li>
<li data-line="7">Check the <code>Replace all child object permission entries</code> checkbox</li>
<li data-line="8">Click <code>OK</code></li>
<li data-line="9">Select <code>Administrators (PC_NAME\Administrators)</code> in the group selector and then check <code>Full Control</code> box in the <code>Permissions</code> window down below</li>
<li data-line="10">Click <code>OK</code></li>
</ol>
</div>
<div>
<p>After performing above steps, you must have gotten full and almost complete <em>(some registry values and keys are still protected after the general procedure)</em> access to the desired key.</p>
</div>
<div>
<h2 data-heading="Registry paths involved" id="Registry_paths_involved" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Registry paths involved
</h2>
</div>
<div>
<ul class="has-list-bullet">
<li data-line="0">
<div class="list-bullet"></div>
<p>Bottom line of desktop:<br>
<code>Computer\HKEY_CLASSES_ROOT\DesktopBackground</code><br>
<span alt="Desktop Background.png" src="Desktop Background.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Desktop Background.png" src="desktop-background.png"></span>
</p>
</li>
<li data-line="3">
<div class="list-bullet"></div>
<p>Folder Background<br>
<code>Computer\HKEY_CLASSES_ROOT\Directory\Background\shell</code><br>
<span alt="Directory Background.png" src="Directory Background.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Directory Background.png" src="directory-background.png"></span>
</p>
</li>
<li data-line="6">
<div class="list-bullet"></div>
<p>Folder<br>
<code>Computer\HKEY_CLASSES_ROOT\Directory\shell</code><br>
<span alt="Folder.png" src="Folder.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Folder.png" src="folder.png"></span>
</p>
</li>
<li data-line="9">
<div class="list-bullet"></div>
<p>Folder Item (extends Folder)<br>
<code>Computer\HKEY_CLASSES_ROOT\Folder</code><br>
<span alt="File Item.png" src="File Item.png" class="internal-embed media-embed image-embed is-loaded"><img alt="File Item.png" src="file-item.png"></span>
</p>
</li>
<li data-line="12">
<div class="list-bullet"></div>
<p>Drive<br>
<code>Computer\HKEY_CLASSES_ROOT\Drive</code><br>
<span alt="Drive.png" src="Drive.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Drive.png" src="drive.png"></span>
</p>
</li>
<li data-line="15">
<div class="list-bullet"></div>
<p>Library folder<br>
<code>Computer\HKEY_CLASSES_ROOT\LibraryFolder</code><br>
<span alt="Library Item.png" src="Library Item.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Library Item.png" src="library-item.png"></span>
</p>
<p>Library background inherits from Folder Background, but can't parse the <code>%V</code> macro, which results in the following error. This is Microsoft's fault. To my knowledge, there is no way to fix that.<br>
<span alt="Library Background.png" src="Library Background.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Library Background.png" src="library-background.png"></span><br>
<span alt="Explorer Error.png" src="Explorer Error.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Explorer Error.png" src="explorer-error.png"></span>
</p>
</li>
<li data-line="22">
<div class="list-bullet"></div>
<p>All Files<br>
<code>Computer\HKEY_CLASSES_ROOT\*</code><br>
<span alt="All Files.png" src="All Files.png" class="internal-embed media-embed image-embed is-loaded"><img alt="All Files.png" src="all-files.png"></span>
</p>
</li>
<li data-line="25">
<div class="list-bullet"></div>
<p>All Filesystem Objects (yep, that's different from All Files - it's a generalization that includes drives and symbols)<br>
<code>Computer\HKEY_CLASSES_ROOT\AllFilesystemObjects</code><br>
<span alt="All Filesystem Objects.png" src="All Filesystem Objects.png" class="internal-embed media-embed image-embed is-loaded"><img alt="All Filesystem Objects.png" src="all-filesystem-objects.png"></span>
</p>
</li>
<li data-line="28">
<div class="list-bullet"></div>
<p>Text Files<br>
<code>Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text</code>
</p>
</li>
<li data-line="30">
<div class="list-bullet"></div>
<p>Image Files<br>
<code>Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\image</code>
</p>
</li>
<li data-line="32">
<div class="list-bullet"></div>
<p>Document Files<br>
<code>Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\document</code>
</p>
</li>
<li data-line="34">
<div class="list-bullet"></div>
<p>Audio Files<br>
<code>Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\audio</code>
</p>
</li>
<li data-line="36">
<div class="list-bullet"></div>
<p>Video Files<br>
<code>Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\video</code>
</p>
</li>
</ul>
</div>
<div>
<h2 data-heading="Cleaning up the context menu" id="Cleaning_up_the_context_menu" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Cleaning up the context menu
</h2>
</div>
<div>
<p>Most obnoxious default entries can be cleaned up using Winaero Tweaker. I suggest you use it to make the process way more bearable for yourself.</p>
</div>
<div>
<p><span alt="Winaero 1.png" src="Winaero 1.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Winaero 1.png" src="winaero-1.png"></span><br>
<span alt="Winaero 2.png" src="Winaero 2.png" class="internal-embed media-embed image-embed is-loaded"><img alt="Winaero 2.png" src="winaero-2.png"></span>
</p>
</div>
<div>
<h3 data-heading="Areas Winaero Tweaker does not reach" id="Areas_Winaero_Tweaker_does_not_reach" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Areas Winaero Tweaker does not reach
</h3>
</div>
<div>
<h6 data-heading="Remove &quot;Open PowerShell window here&quot;" id="Remove_&quot;Open_PowerShell_window_here&quot;" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Remove "Open PowerShell window here"
</h6>
</div>
<div>
<ol>
<li data-line="0">Navigate to <code>Computer\HKEY_CLASSES_ROOT\Directory\shell\Powershell</code></li>
<li data-line="1">Unlock key (<a data-href="The Windows Context Menu#Dealing with locked keys" href="the-windows-context-menu.html#Dealing_with_locked_keys" class="internal-link" target="_self" rel="noopener">The Windows Context Menu &gt; Dealing with locked keys</a>)</li>
<li data-line="2">Create a new REG_SZ value <code>ProgrammaticAccessOnly</code> without any data</li>
<li data-line="3">Navigate to <code>Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell</code></li>
<li data-line="4">Unlock key</li>
<li data-line="5">Create a new REG_SZ value <code>ProgrammaticAccessOnly</code> without any data</li>
</ol>
</div>
<div>
<h6 data-heading="Remove &quot;Open Linux shell here&quot;" id="Remove_&quot;Open_Linux_shell_here&quot;" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Remove "Open Linux shell here"
</h6>
</div>
<div>
<ol>
<li data-line="0">Navigate to <code>Computer\HKEY_CLASSES_ROOT\Directory\shell\WSL</code></li>
<li data-line="1">Unlock key</li>
<li data-line="2">Delete <code>WSL</code> key altogether</li>
<li data-line="3">Navigate to <code>Computer\HKEY_CLASSES_ROOT\Directory\Background\shell\Powershell</code></li>
<li data-line="4">Unlock key</li>
<li data-line="5">Create a new REG_SZ value <code>ProgrammaticAccessOnly</code> without any data</li>
</ol>
</div>
<div>
<h6 data-heading="Edit the &quot;Edit&quot; text context menu command" id="Edit_the_&quot;Edit&quot;_text_context_menu_command" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Edit the "Edit" text context menu command
</h6>
</div>
<div>
<ol>
<li data-line="0">Navigate to <code>Computer\HKEY_CLASSES_ROOT\SystemFileAssociations\text\shell\edit</code></li>
<li data-line="1">Make sure you've read the article thoroughly, then do anything you want with it.</li>
</ol>
</div>
<div>
<h2 data-heading="Bottom line" id="Bottom_line" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Bottom line
</h2>
</div>
<div>
<p>No matter how terrible the context menu API might be for Windows, there's still a way to customize it. Hope you found the tricks useful!</p>
</div>
<div>
<h2 data-heading="Contact" id="Contact" style="display: flex;">
<div class="heading-collapse-indicator collapse-indicator collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div>Contact
</h2>
</div>
<div>
<p>If <strong>you've spotted a mistake (be it orthographical, factual or any other)</strong> in this article or want to <strong>add some important details or share any important knowledge on the subject</strong>, please contact me on Twitter: @endermanch or hit me up on e-mail: <a data-tooltip-position="top" aria-label="mailto:blogs@enderman.ch" rel="noopener" class="external-link" href="mailto:blogs@enderman.ch" target="_blank">blogs@enderman.ch</a></p>
</div>
<div class="mod-footer">
<div class="embedded-backlinks" style="display: none;"></div>
</div>
</div>
</div>
</div>
<div class="sidebar-right sidebar the-export-html-plugin-developer-is-a-clown-that-cant-make-a-mobile-layout">
<div class="sidebar-content">
<div class="tree-container outline-tree" data-depth="0">
<div class="tree-header"><span class="sidebar-section-header">Table Of Contents</span><button class="clickable-icon collapse-tree-button"><iconify-icon icon="ph:arrows-in-line-horizontal-bold" width="18px" height="18px" rotate="90deg" color="currentColor"></iconify-icon></button></div>
<div class="tree-scroll-area">
<div class="tree-item mod-tree-heading" data-depth="1">
<div class="tree-item-contents"><a class="tree-item-link" href="#The_Windows_Context_Menu_-_Is_It_a_Lost_Cause?"><span class="tree-item-title">The Windows Context Menu - Is It a Lost Cause?</span></a></div>
<div class="tree-item-children">
<div class="tree-item mod-tree-heading mod-collapsible" data-depth="2">
<div class="tree-item-contents">
<div class="tree-item-icon collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div><a class="tree-item-link" href="#Shell_entries_&amp;_Context_Menu_handlers"><span class="tree-item-title">Shell entries &amp; Context Menu handlers</span></a>
</div>
<div class="tree-item-children">
<div class="tree-item mod-tree-heading mod-collapsible" data-depth="3">
<div class="tree-item-contents">
<div class="tree-item-icon collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div><a class="tree-item-link" href="#Sort_of_editable_entries?"><span class="tree-item-title">Sort of editable entries?</span></a>
</div>
<div class="tree-item-children">
<div class="tree-item mod-tree-heading" data-depth="4">
<div class="tree-item-contents"><a class="tree-item-link" href="#Adding_entries"><span class="tree-item-title">Adding entries</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="4">
<div class="tree-item-contents"><a class="tree-item-link" href="#Nesting_entries"><span class="tree-item-title">Nesting entries</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading mod-collapsible" data-depth="4">
<div class="tree-item-contents">
<div class="tree-item-icon collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div><a class="tree-item-link" href="#Editing_entries"><span class="tree-item-title">Editing entries</span></a>
</div>
<div class="tree-item-children">
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Name"><span class="tree-item-title">Name</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Icon"><span class="tree-item-title">Icon</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Separators"><span class="tree-item-title">Separators</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Appear_in_the_Shift+Click_context_menu_only"><span class="tree-item-title">Appear in the Shift+Click context menu only</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Position_override"><span class="tree-item-title">Position override</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Hide_in_Safe_Mode"><span class="tree-item-title">Hide in Safe Mode</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Never_default"><span class="tree-item-title">Never default</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Pass_through_to_Context_Menu_handlers"><span class="tree-item-title">Pass through to Context Menu handlers</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Other_options"><span class="tree-item-title">Other options</span></a></div>
<div class="tree-item-children"></div>
</div>
</div>
</div>
<div class="tree-item mod-tree-heading" data-depth="4">
<div class="tree-item-contents"><a class="tree-item-link" href="#Deleting_entries"><span class="tree-item-title">Deleting entries</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading mod-collapsible" data-depth="4">
<div class="tree-item-contents">
<div class="tree-item-icon collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div><a class="tree-item-link" href="#Sorting_entries"><span class="tree-item-title">Sorting entries</span></a>
</div>
<div class="tree-item-children">
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Position_override"><span class="tree-item-title">Position override</span></a></div>
<div class="tree-item-children"></div>
</div>
</div>
</div>
<div class="tree-item mod-tree-heading" data-depth="4">
<div class="tree-item-contents"><a class="tree-item-link" href="#Bottom_line"><span class="tree-item-title">Bottom line</span></a></div>
<div class="tree-item-children"></div>
</div>
</div>
</div>
<div class="tree-item mod-tree-heading" data-depth="3">
<div class="tree-item-contents"><a class="tree-item-link" href="#Uneditable_entries"><span class="tree-item-title">Uneditable entries</span></a></div>
<div class="tree-item-children"></div>
</div>
</div>
</div>
<div class="tree-item mod-tree-heading" data-depth="2">
<div class="tree-item-contents"><a class="tree-item-link" href="#Dealing_with_locked_keys"><span class="tree-item-title">Dealing with locked keys</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="2">
<div class="tree-item-contents"><a class="tree-item-link" href="#Registry_paths_involved"><span class="tree-item-title">Registry paths involved</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading mod-collapsible" data-depth="2">
<div class="tree-item-contents">
<div class="tree-item-icon collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div><a class="tree-item-link" href="#Cleaning_up_the_context_menu"><span class="tree-item-title">Cleaning up the context menu</span></a>
</div>
<div class="tree-item-children">
<div class="tree-item mod-tree-heading mod-collapsible" data-depth="3">
<div class="tree-item-contents">
<div class="tree-item-icon collapse-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon right-triangle">
<path d="M3 8L12 17L21 8"></path>
</svg></div><a class="tree-item-link" href="#Areas_Winaero_Tweaker_does_not_reach"><span class="tree-item-title">Areas Winaero Tweaker does not reach</span></a>
</div>
<div class="tree-item-children">
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Remove_&quot;Open_PowerShell_window_here&quot;"><span class="tree-item-title">Remove "Open PowerShell window here"</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Remove_&quot;Open_Linux_shell_here&quot;"><span class="tree-item-title">Remove "Open Linux shell here"</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="6">
<div class="tree-item-contents"><a class="tree-item-link" href="#Edit_the_&quot;Edit&quot;_text_context_menu_command"><span class="tree-item-title">Edit the "Edit" text context menu command</span></a></div>
<div class="tree-item-children"></div>
</div>
</div>
</div>
</div>
</div>
<div class="tree-item mod-tree-heading" data-depth="2">
<div class="tree-item-contents"><a class="tree-item-link" href="#Bottom_line"><span class="tree-item-title">Bottom line</span></a></div>
<div class="tree-item-children"></div>
</div>
<div class="tree-item mod-tree-heading" data-depth="2">
<div class="tree-item-contents"><a class="tree-item-link" href="#Contact"><span class="tree-item-title">Contact</span></a></div>
<div class="tree-item-children"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,937 @@
//#region Helpers
function getAbsoluteRootPath()
{
if (typeof rootPath == 'undefined') setupRootPath(document);
return new URL(window.location.href + "/../" + rootPath).pathname;
}
function getURLPath(url = window.location.pathname)
{
let absoluteRoot = getAbsoluteRootPath();
let pathname = url.substring(absoluteRoot.length);
return pathname;
}
function getURLRootPath(url = window.location.pathname)
{
let path = getURLPath(url);
let splitPath = path.split("/");
let rootPath = "";
for (let i = 0; i < splitPath.length - 1; i++)
{
rootPath += "../";
}
return rootPath;
}
async function setTreeCollapsed(element, collapsed, animate = true)
{
if (!element || !element.classList.contains("mod-collapsible")) return;
let children = element.querySelector(".tree-item-children");
if (collapsed)
{
element.classList.add("is-collapsed");
if(animate) slideUp(children, 100);
else children.style.display = "none";
}
else
{
element.classList.remove("is-collapsed");
if(animate) slideDown(children, 100);
else children.style.removeProperty("display");
}
}
async function setTreeCollapsedAll(elements, collapsed, animate = true)
{
let childrenList = [];
elements.forEach(async element =>
{
if (!element || !element.classList.contains("mod-collapsible")) return;
let children = element.querySelector(".tree-item-children");
if (collapsed)
{
element.classList.add("is-collapsed");
}
else
{
element.classList.remove("is-collapsed");
}
childrenList.push(children);
});
if (collapsed)
{
if(animate) slideUpAll(childrenList, 100);
else childrenList.forEach(async children => children.style.display = "none");
}
else
{
if(animate) slideDownAll(childrenList, 100);
else childrenList.forEach(async children => children.style.removeProperty("display"));
}
}
function toggleTreeCollapsed(element)
{
if (!element) return;
setTreeCollapsed(element, !element.classList.contains("is-collapsed"));
}
function toggleTreeCollapsedAll(elements)
{
if (!elements) return;
setTreeCollapsedAll(elements, !elements[0].classList.contains("is-collapsed"));
}
function getHeaderEl(headerDiv)
{
let possibleChildHeader = headerDiv.firstChild;
let isHeader = false;
while (possibleChildHeader != null)
{
isHeader = possibleChildHeader ? /[Hh][1-6]/g.test(possibleChildHeader.tagName) : false;
if (isHeader) break;
possibleChildHeader = possibleChildHeader.nextElementSibling;
}
return possibleChildHeader;
}
function getPreviousHeader(headerDiv)
{
let possibleParent = headerDiv.previousElementSibling;
let isHeader = false;
while (possibleParent != null)
{
let possibleChildHeader = getHeaderEl(possibleParent);
isHeader = possibleChildHeader ? /[Hh][1-6]/g.test(possibleChildHeader.tagName) : false;
if (isHeader) break;
possibleParent = possibleParent.previousElementSibling;
}
return possibleParent;
}
function setHeaderOpen(headerDiv, open, openParents = true)
{
if(headerDiv.tagName != "DIV" || !getHeaderEl(headerDiv))
{
console.error("setHeaderOpen() must be called with a header div");
return;
}
// let selector = getHeadingContentsSelector(header);
if (open)
{
headerDiv.classList.remove("is-collapsed");
headerDiv.style.display = "";
}
if (!open)
{
headerDiv.classList.add("is-collapsed");
}
let headerEl = getHeaderEl(headerDiv);
let childHeaders = [];
let possibleChild = headerDiv.nextElementSibling;
// loop through next siblings showing/ hiding children until we reach a header of the same or lower level
while (possibleChild != null)
{
let possibleChildHeader = getHeaderEl(possibleChild);
if(possibleChildHeader)
{
// if header is a sibling of this header then break
if (possibleChildHeader.tagName <= headerEl.tagName) break;
// save child headers to be re closed afterwards
childHeaders.push(possibleChild);
}
if (!open) possibleChild.style.display = "none";
else possibleChild.style.display = "";
possibleChild = possibleChild.nextElementSibling;
}
if(open)
{
// if we are opening the header then we need to make sure that all closed child headers stay closed
childHeaders.forEach(function(item)
{
if (item.classList.contains("is-collapsed"))
{
setHeaderOpen(item, false);
}
});
// if we are opening the header then we need to make sure that all parent headers are open
if (openParents)
{
let previousHeader = getPreviousHeader(headerDiv);
while (previousHeader != null)
{
let previousHeaderEl = getHeaderEl(previousHeader);
if (previousHeaderEl.tagName < headerEl.tagName)
{
// if header is a parent of this header then unhide
setHeaderOpen(previousHeader, true);
break;
}
previousHeader = getPreviousHeader(previousHeader);
}
}
}
}
let slideUp = (target, duration=500) => {
target.style.transitionProperty = 'height, margin, padding';
target.style.transitionDuration = duration + 'ms';
target.style.boxSizing = 'border-box';
target.style.height = target.offsetHeight + 'px';
target.offsetHeight;
target.style.overflow = 'hidden';
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
window.setTimeout(async () => {
target.style.display = 'none';
target.style.removeProperty('height');
target.style.removeProperty('padding-top');
target.style.removeProperty('padding-bottom');
target.style.removeProperty('margin-top');
target.style.removeProperty('margin-bottom');
target.style.removeProperty('overflow');
target.style.removeProperty('transition-duration');
target.style.removeProperty('transition-property');
}, duration);
}
let slideUpAll = (targets, duration=500) => {
targets.forEach(async target => {
target.style.transitionProperty = 'height, margin, padding';
target.style.transitionDuration = duration + 'ms';
target.style.boxSizing = 'border-box';
target.style.height = target.offsetHeight + 'px';
target.offsetHeight;
target.style.overflow = 'hidden';
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
});
window.setTimeout(async () => {
targets.forEach(async target => {
target.style.display = 'none';
target.style.removeProperty('height');
target.style.removeProperty('padding-top');
target.style.removeProperty('padding-bottom');
target.style.removeProperty('margin-top');
target.style.removeProperty('margin-bottom');
target.style.removeProperty('overflow');
target.style.removeProperty('transition-duration');
target.style.removeProperty('transition-property');
});
}, duration);
}
let slideDown = (target, duration=500) => {
target.style.removeProperty('display');
let display = window.getComputedStyle(target).display;
if (display === 'none') display = 'block';
target.style.display = display;
let height = target.offsetHeight;
target.style.overflow = 'hidden';
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
target.offsetHeight;
target.style.boxSizing = 'border-box';
target.style.transitionProperty = "height, margin, padding";
target.style.transitionDuration = duration + 'ms';
target.style.height = height + 'px';
target.style.removeProperty('padding-top');
target.style.removeProperty('padding-bottom');
target.style.removeProperty('margin-top');
target.style.removeProperty('margin-bottom');
window.setTimeout(async () => {
target.style.removeProperty('height');
target.style.removeProperty('overflow');
target.style.removeProperty('transition-duration');
target.style.removeProperty('transition-property');
}, duration);
}
let slideDownAll = (targets, duration=500) => {
targets.forEach(async target => {
target.style.removeProperty('display');
let display = window.getComputedStyle(target).display;
if (display === 'none') display = 'block';
target.style.display = display;
let height = target.offsetHeight;
target.style.overflow = 'hidden';
target.style.height = 0;
target.style.paddingTop = 0;
target.style.paddingBottom = 0;
target.style.marginTop = 0;
target.style.marginBottom = 0;
target.offsetHeight;
target.style.boxSizing = 'border-box';
target.style.transitionProperty = "height, margin, padding";
target.style.transitionDuration = duration + 'ms';
target.style.height = height + 'px';
target.style.removeProperty('padding-top');
target.style.removeProperty('padding-bottom');
target.style.removeProperty('margin-top');
target.style.removeProperty('margin-bottom');
});
window.setTimeout( async () => {
targets.forEach(async target => {
target.style.removeProperty('height');
target.style.removeProperty('overflow');
target.style.removeProperty('transition-duration');
target.style.removeProperty('transition-property');
});
}, duration);
}
var slideToggle = (target, duration = 500) => {
if (window.getComputedStyle(target).display === 'none') {
return slideDown(target, duration);
} else {
return slideUp(target, duration);
}
}
var slideToggleAll = (targets, duration = 500) => {
if (window.getComputedStyle(targets[0]).display === 'none') {
return slideDownAll(targets, duration);
} else {
return slideUpAll(targets, duration);
}
}
//#endregion
async function loadDocument(url, pushHistory = true, scrollTo = true)
{
console.log("Loading document: " + url);
// change the active file
setActiveDocument(url, scrollTo, pushHistory);
let response;
// if(typeof embeddedDocuments == 'undefined')
// {
try
{
response = await fetch(url);
}
catch (error)
{
console.log("Cannot use fetch API (likely due to CORS), just loading the page normally.");
window.location.assign(url);
return;
}
// }
// else
// {
// response = new Response(embeddedDocuments[url], {status: 200, statusText: "OK"});
// }
let doc = document.implementation.createHTMLDocument();
if (response.ok)
{
let html = (await response.text()).replaceAll("<!DOCTYPE html>", "").replaceAll("<html>", "").replaceAll("</html>", "");
doc.documentElement.innerHTML = html;
// copy document content and outline tree
document.querySelector(".document-container").innerHTML = doc.querySelector(".document-container").innerHTML;
document.querySelector(".outline-tree").innerHTML = doc.querySelector(".outline-tree").innerHTML;
// if the url has a heading, scroll to it
let splitURL = url.split("#");
let pathnameTarget = splitURL[0] ?? url;
let headingTarget = splitURL.length > 1 ? splitURL[1] : null;
if (headingTarget) document.getElementById(headingTarget).scrollIntoView();
// Change the root path to match the match from the new page
setupRootPath(doc);
// initialize events on the new page
initializePage(document.querySelector(".document-container"));
initializePage(document.querySelector(".outline-tree"));
document.title = doc.title;
}
else
{
// if the page is not able to load instead add a header saying the page doesn't exist
document.querySelector(".markdown-preview-view").innerHTML =
`
<div>
<center style='position: relative; transform: translateY(20vh); width: 100%; text-align: center;'>
<h1 style>Page Not Found</h1>
</center>
</div>
`;
document.querySelector(".outline-tree").innerHTML = "";
console.log("Page not found: " + getAbsoluteRootPath() + url);
let newRootPath = getURLRootPath(getAbsoluteRootPath() + url);
rootPath = newRootPath;
document.querySelector("base").href = newRootPath;
document.title = "Page Not Found";
}
return doc;
}
function setActiveDocument(url, scrollTo = true, pushHistory = true)
{
let pathnameTarget = url.split("#")[0] ?? url; // path with no header
// switch active file in file tree
document.querySelector(".tree-item.mod-active")?.classList.remove("mod-active");
let treeItems = Array.from(document.querySelectorAll(".tree-item > .tree-item-contents > .tree-item-link"));
let treeItem = undefined;
for (let item of treeItems)
{
if (item.getAttribute("href") == url)
{
let parent = item.parentElement.parentElement;
parent.classList.add("mod-active");
treeItem = parent;
while (parent.hasAttribute("data-depth"))
{
setTreeCollapsed(parent, false, false);
parent = parent.parentElement.parentElement;
}
continue;
}
}
if(scrollTo) treeItem?.scrollIntoView({block: "center", inline: "nearest"});
// set the active file in th graph view
if(typeof nodes != 'undefined' && window.renderWorker)
{
let activeNode = nodes?.paths.findIndex(function(item) { return item.endsWith(pathnameTarget); }) ?? -1;
if(activeNode >= 0)
{
window.renderWorker.activeNode = activeNode;
}
}
if(pushHistory && window.location.protocol != "file:") window.history.pushState({ path: pathnameTarget }, '', pathnameTarget);
}
//#region Initialization
function setupThemeToggle(setupOnNode)
{
if (localStorage.getItem("theme_toggle") != null)
{
setThemeToggle(localStorage.getItem("theme_toggle") == "true");
}
var lastScheme = "theme-dark";
// change theme to match current system theme
if (localStorage.getItem("theme_toggle") == null && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)
{
setThemeToggle(true);
lastScheme = "theme-dark";
}
if (localStorage.getItem("theme_toggle") == null && window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches)
{
setThemeToggle(true);
lastScheme = "theme-light";
}
// set initial toggle state based on body theme class
if (document.body.classList.contains("theme-light"))
{
setThemeToggle(false);
}
else
{
setThemeToggle(true);
}
function setThemeToggle(state, instant = false)
{
let toggle = document.querySelector(".theme-toggle-input");
toggle.checked = state;
if (instant)
{
var oldTransition = document.body.style.transition;
document.body.style.transition = "none";
}
if(!toggle.classList.contains("is-checked") && state)
{
toggle.classList.add("is-checked");
}
else if (toggle.classList.contains("is-checked") && !state)
{
toggle.classList.remove("is-checked");
}
if(!state)
{
if (document.body.classList.contains("theme-dark"))
{
document.body.classList.remove("theme-dark");
}
if (!document.body.classList.contains("theme-light"))
{
document.body.classList.add("theme-light");
}
}
else
{
if (document.body.classList.contains("theme-light"))
{
document.body.classList.remove("theme-light");
}
if (!document.body.classList.contains("theme-dark"))
{
document.body.classList.add("theme-dark");
}
}
if (instant)
{
setTimeout(function()
{
document.body.style.transition = oldTransition;
}, 100);
}
localStorage.setItem("theme_toggle", state ? "true" : "false");
}
setupOnNode.querySelector(".theme-toggle-input")?.addEventListener("change", event =>
{
setThemeToggle(!(localStorage.getItem("theme_toggle") == "true"));
});
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event =>
{
// return if we are printing
if (window.matchMedia('print').matches)
{
printing = true;
return;
}
let newColorScheme = event.matches ? "theme-dark" : "theme-light";
if (newColorScheme == lastScheme) return;
if (newColorScheme == "theme-dark")
{
setThemeToggle(true);
}
if (newColorScheme == "theme-light")
{
setThemeToggle(false);
}
lastScheme = newColorScheme;
});
}
function setupHeaders(setupOnNode)
{
// MAKE HEADERS COLLAPSIBLE
setupOnNode.querySelectorAll(".heading-collapse-indicator").forEach(function (element)
{
element.addEventListener("click", function ()
{
var isOpen = !this.parentElement.parentElement.classList.contains("is-collapsed");
setHeaderOpen(this.parentElement.parentElement, !isOpen);
});
});
// unfold header when an internal link that points to that header is clicked
setupOnNode.querySelectorAll("a.internal-link, a.tree-item-link").forEach(function (element)
{
element.addEventListener("click", function (event)
{
event.preventDefault();
let target = this.getAttribute("href");
// if the target is a header uncollapse it
if (target.startsWith("#"))
{
console.log("Uncollapsing header: " + target);
let header = document.getElementById(target.substring(1));
setHeaderOpen(header.parentElement, true);
}
});
});
}
function setupTrees(setupOnNode)
{
const fileTreeItems = Array.from(setupOnNode.querySelectorAll(".tree-container.file-tree .tree-item"));
setupOnNode.querySelectorAll(".tree-item-contents > .collapse-icon").forEach(function(item)
{
item.addEventListener("click", function()
{
toggleTreeCollapsed(item.parentElement.parentElement);
});
});
let fileTreeCollapse = setupOnNode.querySelector(".tree-container.file-tree .collapse-tree-button");
if (fileTreeCollapse) fileTreeCollapse.addEventListener("click", async function()
{
let fileTreeIsCollapsed = fileTreeCollapse.classList.contains("is-collapsed");
setTreeCollapsedAll(fileTreeItems, !fileTreeIsCollapsed, fileTreeItems.length < 100);
fileTreeCollapse.classList.toggle("is-collapsed");
fileTreeCollapse.querySelector("iconify-icon").setAttribute("icon", fileTreeIsCollapsed ? "ph:arrows-out-line-horizontal-bold" : "ph:arrows-in-line-horizontal-bold");
});
let outlineTreeCollapse = setupOnNode.querySelector(".tree-container.outline-tree .collapse-tree-button");
if(outlineTreeCollapse) outlineTreeCollapse.addEventListener("click", async function()
{
let outlineTreeIsCollapsed = outlineTreeCollapse.classList.contains("is-collapsed");
let items = Array.from(outlineTreeCollapse.parentElement.parentElement.querySelectorAll(".tree-item"));
setTreeCollapsedAll(items, !outlineTreeIsCollapsed, items.length < 100);
outlineTreeCollapse.classList.toggle("is-collapsed");
outlineTreeCollapse.querySelector("iconify-icon").setAttribute("icon", outlineTreeIsCollapsed ? "ph:arrows-out-line-horizontal-bold" : "ph:arrows-in-line-horizontal-bold");
});
// start with all closed
setupOnNode.querySelectorAll(".tree-container .tree-item").forEach(function(item)
{
if (item.classList.contains("is-collapsed")) setTreeCollapsed(item, true, false);
});
// make sure the icons match their starting collaped state
setupOnNode.querySelectorAll(".tree-container > .tree-header > .collapse-tree-button").forEach(function(item)
{
if (item.classList.contains("is-collapsed"))
{
item.querySelector("iconify-icon").setAttribute("icon", "ph:arrows-out-line-horizontal-bold");
}
else
{
item.querySelector("iconify-icon").setAttribute("icon", "ph:arrows-in-line-horizontal-bold");
}
});
}
function setupCallouts(setupOnNode)
{
// MAKE CALLOUTS COLLAPSIBLE
// if the callout title is clicked, toggle the display of .callout-content
setupOnNode.querySelectorAll(".callout.is-collapsible .callout-title").forEach(function (element)
{
element.addEventListener("click", function ()
{
var parent = this.parentElement;
var isCollapsed = parent.classList.contains("is-collapsed");
parent.classList.toggle("is-collapsed");
element.querySelector(".callout-fold").classList.toggle("is-collapsed");
slideToggle(parent.querySelector(".callout-content"), 100);
});
});
}
function setupCheckboxes(setupOnNode)
{
// Fix checkboxed toggling .is-checked
setupOnNode.querySelectorAll(".task-list-item-checkbox").forEach(function (element)
{
element.addEventListener("click", function ()
{
var parent = this.parentElement;
parent.classList.toggle("is-checked");
parent.setAttribute("data-task", parent.classList.contains("is-checked") ? "x" : " ");
});
});
setupOnNode.querySelectorAll(`.plugin-tasks-list-item input[type="checkbox"]`).forEach(function(checkbox)
{
checkbox.checked = checkbox.parentElement.classList.contains("is-checked");
});
setupOnNode.querySelectorAll('.kanban-plugin__item.is-complete').forEach(function(checkbox)
{
checkbox.querySelector('input[type="checkbox"]').checked = true;
});
}
function setupCanvas(setupOnNode)
{
let focusedNode = null;
// make canvas nodes selectable
setupOnNode.querySelectorAll(".canvas-node-content-blocker").forEach(function (element)
{
element.addEventListener("click", function ()
{
var parent = this.parentElement.parentElement;
parent.classList.toggle("is-focused");
this.style.display = "none";
if (focusedNode)
{
focusedNode.classList.remove("is-focused");
focusedNode.querySelector(".canvas-node-content-blocker").style.display = "";
}
focusedNode = parent;
});
});
// make canvas node deselect when clicking outside
// document.addEventListener("click", function (event)
// {
// if (!event.target.closest(".canvas-node"))
// {
// document.querySelectorAll(".canvas-node").forEach(function (node)
// {
// node.classList.remove("is-focused");
// node.querySelector(".canvas-node-content-blocker").style.display = "";
// });
// }
// });
}
function setupCodeblocks(setupOnNode)
{
// make code snippet block copy button copy the code to the clipboard
setupOnNode.querySelectorAll(".copy-code-button").forEach(function (element)
{
element.addEventListener("click", function ()
{
var code = this.parentElement.querySelector("code").textContent;
navigator.clipboard.writeText(code);
this.textContent = "Copied!";
// set a timeout to change the text back
setTimeout(function ()
{
setupOnNode.querySelectorAll(".copy-code-button").forEach(function (button)
{
button.textContent = "Copy";
});
}, 2000);
});
});
}
function setupLinks(setupOnNode)
{
setupOnNode.querySelectorAll(".internal-link, .footnote-link, .tree-item-link").forEach(function(link)
{
link.addEventListener("click", function(event)
{
let target = link.getAttribute("href");
event.preventDefault();
// this is linking to a different page
if (!target.startsWith("#"))
{
// load doc, if it is a tree link then don't scroll to the active doc in the file tree
loadDocument(target, true, !link.classList.contains("tree-item-link"));
return;
}
else
{
let headerTarget = document.getElementById(target.substring(1));
setHeaderOpen(headerTarget.parentElement, true);
headerTarget.scrollIntoView();
}
});
});
window.onpopstate = function(event)
{
loadDocument(getURLPath(), false);
}
}
// What the FUCK is this abomination??? - Endermanch, 2023
/* let sidebarWidth = undefined;
let lineWidth = undefined;
function setupResize(setupOnNode)
{
if (setupOnNode != document) return;
function updateSidebars()
{
let rightSidebar = document.querySelector(".sidebar-right");
let leftSidebar = document.querySelector(".sidebar-left");
let sidebarCount = (rightSidebar ? 1 : 0) + (leftSidebar ? 1 : 0);
if (sidebarCount == 0) return;
if(!sidebarWidth) sidebarWidth = Math.max(rightSidebar?.clientWidth, leftSidebar?.clientWidth);
if (!lineWidth)
{
let docWidthTestEl = document.createElement("div");
document.querySelector(".markdown-preview-view").appendChild(docWidthTestEl);
docWidthTestEl.style.width = "var(--line-width)";
docWidthTestEl.style.minWidth = "var(--line-width)";
docWidthTestEl.style.maxWidth = "var(--line-width)";
lineWidth = docWidthTestEl.clientWidth;
docWidthTestEl.remove();
}
let letHideRightThreshold = sidebarWidth * sidebarCount + lineWidth / 2;
if (window.innerWidth < letHideRightThreshold)
{
rightSidebar.style.display = "none";
}
else
{
rightSidebar.style.display = "";
}
let letHideLeftThreshold = lineWidth / 2 + sidebarWidth;
if (window.innerWidth < letHideLeftThreshold)
{
leftSidebar.style.display = "none";
}
else
{
leftSidebar.style.display = "";
}
}
window.addEventListener("resize", function()
{
updateSidebars();
});
updateSidebars();
}
*/
function setupRootPath(fromDocument)
{
let basePath = fromDocument.querySelector("#root-path").getAttribute("root-path");
document.querySelector("base").href = basePath;
document.querySelector("#root-path").setAttribute("root-path", basePath);
rootPath = basePath;
}
let touchDrag = false;
function initializePage(setupOnNode)
{
setupThemeToggle(setupOnNode);
setupHeaders(setupOnNode);
setupTrees(setupOnNode);
setupCallouts(setupOnNode);
setupCheckboxes(setupOnNode);
setupCanvas(setupOnNode);
setupCodeblocks(setupOnNode);
setupLinks(setupOnNode);
setupOnNode.querySelectorAll("*").forEach(function(element)
{
element.addEventListener("touchend", function(event)
{
if (touchDrag)
{
touchDrag = false;
event.stopPropagation();
return;
}
if (element instanceof HTMLElement) element.click();
});
});
if(setupOnNode == document)
{
document.body.addEventListener("touchmove", function(event)
{
event.stopImmediatePropagation();
touchDrag = true;
});
setupRootPath(document);
setActiveDocument(getURLPath());
}
}
function initializeForFileProtocol()
{
let graphEl = document.querySelector(".graph-view-placeholder");
if(graphEl)
{
console.log("Running locally, skipping graph view initialization and hiding graph.");
graphEl.style.display = "none";
graphEl.previousElementSibling.style.display = "none"; // hide the graph's header
}
}
//#endregion
window.onload = function()
{
if (window.location.protocol == "file:") initializeForFileProtocol();
initializePage(document);
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,733 @@
/*#region Code Copy */
/* Make code block copy button fade in and out */
.markdown-rendered pre:not(:hover) > button.copy-code-button
{
display: unset;
opacity: 0;
}
.markdown-rendered pre:hover > button.copy-code-button
{
opacity: 1;
}
.markdown-rendered pre button.copy-code-button
{
transition: opacity 0.2s ease-in-out, width 0.3s ease-in-out, background-color 0.2s ease-in-out;
text-overflow: clip;
}
.markdown-rendered pre > button.copy-code-button:hover
{
background-color: var(--interactive-normal);
}
.markdown-rendered pre > button.copy-code-button:active
{
background-color: var(--interactive-hover);
box-shadow: var(--input-shadow);
transition: none;
}
/*#endregion */
/*#region Canvas */
.canvas-card-menu {
display: none;
cursor: default !important;
}
.canvas-controls {
display: none;
cursor: default !important;
}
.canvas-node-connection-point
{
display: none;
cursor: default !important;
}
.canvas-menu-container {
display: none;
}
.canvas-node-content-blocker
{
display: none;
cursor: pointer !important;
}
.canvas-wrapper
{
position: relative;
cursor: default !important;
}
.canvas-node-resizer
{
cursor: default !important;
}
.canvas-node-container
{
cursor: default !important;
}
/*#endregion */
/*#region Sidebars */
.sidebar {
background-color: var(--background-secondary);
flex: 1 0 min-content;
display: flex;
align-items: flex-start;
font-size: 14px;
}
.sidebar-section-header
{
margin: 0em 0 0em var(--sidebar-margin);
text-transform: uppercase;
letter-spacing: 0.06em;
font-weight: 600;
}
.sidebar-content {
width: var(--sidebar-width);
line-height: var(--line-height-tight);
display: flex;
flex-direction: column;
padding: 10px;
padding-bottom: 0;
height: 100%;
}
.sidebar-scroll-area
{
width: 100%;
height: 100%;
line-height: var(--line-height-tight);
display: flex;
flex-direction: column;
overflow-y: scroll;
}
.sidebar-left
{
border-right: 1px dashed var(--divider-color);
z-index: 1000;
align-items: flex-end;
flex-direction: row-reverse;
}
.sidebar-right
{
border-left: 1px dashed var(--divider-color);
z-index: 1000;
align-items: flex-start;
flex-direction: row;
}
@media print
{
.sidebar, .outline-container, .theme-toggle-container, .theme-toggle-container-inline, .toggle-background, .theme-toggle-input
{
display: none !important;
}
}
/*#endregion */
/*#region Content / Markdown Preview View */
.webpage-container {
background-color: var(--background-primary);
display: flex;
flex-direction: row;
height: 100%;
width: 100%;
align-items: stretch;
position: fixed;
}
.document-container
{
flex-basis: var(--content-width);
}
.markdown-reading-view
{
align-self: center;
-ms-flex-align: center;
width: 100%;
}
.markdown-preview-view
{
display: flex;
width: 100%;
max-width: 100%;
padding-bottom: 30em;
align-items: flex-start;
justify-content: center;
}
.document-container > .markdown-preview-view > .markdown-preview-sizer
{
padding: unset;
width: unset;
height: unset;
margin: unset;
max-width: unset;
min-height: unset;
max-width: var(--line-width);
flex-basis: var(--line-width);
}
/*#endregion */
/*#region Kanban */
.markdown-preview-view.kanban-plugin__markdown-preview-view {
font-family: var(--font-text, var(--default-font));
font-size: .875rem;
line-height: var(--line-height-tight);
padding: unset;
width: unset;
height: unset;
position: unset;
overflow-y: unset;
overflow-wrap: unset;
color: unset;
user-select: unset;
-webkit-user-select: unset;
}
.kanban-plugin__item-button-wrapper, .kanban-plugin__lane-grip, .kanban-plugin__lane-settings-button.clickable-icon, .kanban-plugin__item-postfix-button.clickable-icon
{
display: none;
}
/*#endregion */
/*#region Tree */
/* Base tree */
.tree-container
{
/* padding-bottom: 12px; */
/* margin: 12px; */
/* height: 100%; */
/* position: relative; */
/* display: contents; */
position: relative;
height: 100%;
width: auto;
margin: var(--sidebar-margin);
margin-top: 3em;
margin-bottom: 0;
}
.tree-container .tree-header
{
display: flex;
flex-direction: row;
align-items: center;
position: absolute;
top: -3em;
}
.tree-container .tree-header .sidebar-section-header
{
margin: 1em;
margin-left: 0;
}
.tree-container:has(.tree-scroll-area:empty)
{
display: none;
}
.tree-container .tree-scroll-area
{
width: 100%;
height: 100%;
max-height: 100%;
overflow-y: scroll;
padding: 1em;
padding-right: calc(1em + var(--sidebar-margin));
padding-bottom: 3em;
border-radius: var(--radius-m);
position: absolute;
}
.tree-container .tree-item
{
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 0;
}
.tree-container .tree-item-children
{
padding: 0;
margin-left: 0;
border-left: none;
width: 100%;
}
.tree-container .tree-item.mod-active > .tree-item-contents > .tree-item-link
{
color: var(--color-accent);
}
.tree-container .tree-item-contents {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
border-radius: 0.4em;
color: var(--nav-item-color);
width: 100%;
margin-left: var(--tree-horizontal-spacing);
}
.tree-container .tree-item-contents:active
{
color: var(--nav-item-color-active);
}
.tree-container a.tree-item-link
{
width: 100%;
height: 100%;
transition: background-color 0.1s;
border-radius: var(--radius-s);
padding-left: calc(var(--tree-horizontal-spacing) + var(--collapse-arrow-size)/2 + 1px);
padding-bottom: calc(var(--tree-vertical-spacing) / 2);
padding-top: calc(var(--tree-vertical-spacing) / 2);
color: var(--nav-item-color);
text-decoration: none;
}
.tree-container .tree-item-icon.collapse-icon {
display: flex;
justify-content: flex-start;
align-items: center;
border-radius: var(--radius-s);
transition: background-color 0.1s;
position: absolute;
height: 100%;
}
.tree-container .tree-item.mod-tree-folder > .tree-item-contents > .tree-item-icon.collapse-icon
{
width: 100%;
}
.collapse-icon > svg {
color: unset !important;
}
.collapse-icon:hover
{
color: var(--nav-item-color-hover);
}
.tree-container a.tree-item-link:hover
{
cursor: pointer;
color: var(--nav-item-color-hover);
text-decoration: underline;
}
/* Indentation guide */
.tree-container > .tree-scroll-area > * .tree-item
{
margin-left: calc(var(--tree-horizontal-spacing) + var(--collapse-arrow-size) / 2 + 1px);
border-left: var(--nav-indentation-guide-width) solid var(--nav-indentation-guide-color);
}
.tree-container .tree-scroll-area > * > * > .tree-item
{
margin-left: calc(var(--collapse-arrow-size) / 2 + 1px);
}
.tree-container .tree-item.mod-active
{
border-left: var(--nav-indentation-guide-width) solid var(--color-accent);
}
.tree-container .tree-item:hover:not(.mod-active):not(.mod-collapsible):not(:has(.tree-item:hover)) /* Hover */
{
border-left: var(--nav-indentation-guide-width) solid var(--nav-item-color-hover);
}
.webpage-container .tree-container .tree-item:not(.mod-collapsible) > .tree-item-children > .tree-item,
.webpage-container .tree-container > .tree-scroll-area > .tree-item,
.webpage-container .tree-container:not(.mod-nav-indicator) .tree-item
{
border-left: none !important;
}
.webpage-container .tree-container .tree-item:not(.mod-collapsible) > .tree-item-children > .tree-item > .tree-item-contents,
.webpage-container .tree-container:not(.mod-nav-indicator) .tree-item .tree-item-contents,
.webpage-container .tree-container > .tree-scroll-area > .tree-item > .tree-item-contents
{
margin-left: 0 !important;
}
/* Special */
.tree-container.outline-tree .tree-item[data-depth='1'] > .tree-item-contents > .tree-item-link
{
font-weight: 900;
font-size: 1.1em;
margin-left: 0;
}
.tree-container .tree-item.is-collapsed > .tree-item-contents > .tree-item-icon.collapse-icon > svg
{
transition: transform 0.1s ease-in-out;
transform: rotate(-90deg);
}
/*#endregion */
/*#region Headers */
.collapse-icon svg.svg-icon {
color: var(--nav-collapse-icon-color);
stroke-width: 4px;
width: var(--collapse-arrow-size);
height: var(--collapse-arrow-size);
transition: transform 100ms ease-in-out 0s;
min-width: 10px;
min-height: 10px;
}
div.is-collapsed > * > .heading-collapse-indicator.collapse-icon > svg
{
transition: transform 0.1s ease-in-out;
transform: rotate(-90deg);
}
/*#endregion */
/*#region Text Wrapping */
a {
overflow-wrap: anywhere;
}
*
{
overflow-wrap: break-word;
}
/*#endregion */
/*#region Obsidian Columns Plugin */
.columnParent {
display: flex;
padding: 15px 20px;
flex-wrap: wrap;
gap: 20px;
}
.columnParent {
white-space: normal;
}
.columnChild {
flex-grow: 1;
flex-basis: 0px;
}
/*#endregion */
/*#region Theme Toggle */
.theme-toggle-container {
--toggle-width: 50px;
--toggle-height: 23px;
--border-radius: calc(var(--toggle-height) / 2);
--handle-width: calc(var(--toggle-height) * 0.65);
--handle-radius: calc(var(--handle-width) / 2);
--handle-margin: calc((var(--toggle-height) / 2.0) - var(--handle-radius));
--handle-translation: calc(var(--toggle-width) - var(--handle-width) - (var(--handle-margin) * 2));
display: inline-block;
cursor: pointer;
margin: 10px;
}
/* animation to expand width, move handle, then contract width */
@keyframes toggle-slide-right
{
0%
{
width: var(--handle-width);
transform: translateX(0);
}
50%
{
width: calc(var(--toggle-width) * 0.5);
}
90%
{
width: var(--handle-width);
}
100%
{
transform: translateX(var(--handle-translation));
}
}
@keyframes toggle-slide-left
{
0%
{
width: var(--handle-width);
transform: translateX(calc(var(--handle-translation) - ((var(--toggle-width) * 0.33) - var(--handle-width))));
}
70%
{
width: calc(var(--toggle-width) * 0.5);
}
100%
{
width: var(--handle-width);
transform: translateX(0);
}
}
/* just exapnd and contract */
@keyframes toggle-expand-right
{
0%
{
width: var(--handle-width);
}
100%
{
width: calc(var(--toggle-width) * 0.33);
}
}
@keyframes toggle-expand-left
{
0%
{
width: var(--handle-width);
transform: translateX(var(--handle-translation));
}
100%
{
width: calc(var(--toggle-width) * 0.33);
transform: translateX(calc(var(--handle-translation) - ((var(--toggle-width) * 0.33) - var(--handle-width))));
}
}
@keyframes toggle-contract
{
0%
{
width: calc(var(--toggle-width) * 0.33);
}
100%
{
width: var(--handle-width);
}
}
.theme-toggle-input {
display: none;
z-index: 1000;
}
/* Fill in dark mode / default */
.toggle-background {
position: relative;
width: var(--toggle-width);
height: var(--toggle-height);
border-radius: var(--border-radius);
background-color: var(--background-modifier-border);
transition: background-color 0.2s;
z-index: 1000;
/* box-shadow: inset 0px 0px 100px -70px var(--color-accent); */
}
/* Handle default */
.toggle-background::before
{
content: "";
position: absolute;
left: var(--handle-margin);
top: var(--handle-margin);
height: var(--handle-width);
width: var(--handle-width);
border-radius: var(--handle-radius);
background-color: var(--text-normal);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2);
animation: toggle-slide-left 0.2s ease-in-out normal both;
z-index: 1000;
}
/* handle light*/
.theme-toggle-input:checked ~ .toggle-background::before
{
animation: toggle-slide-right 0.2s ease-in-out normal both;
}
.theme-toggle-input:active ~ .toggle-background::before
{
animation: toggle-expand-right 0.2s ease-in-out normal both;
}
.theme-toggle-input:active:checked ~ .toggle-background::before
{
animation: toggle-expand-left 0.2s ease-in-out normal both;
}
/* sun moon icon icon default */
.toggle-background::after
{
content: "";
position: absolute;
right: var(--handle-margin);
top: calc(var(--handle-margin));
height: var(--handle-width);
width: var(--handle-width);
transition: transform 0.3s;
background: url('https://api.iconify.design/lucide/sun.svg') no-repeat center center;
transform: scale(0.9);
}
/* sun moon icon icon light */
.theme-toggle-input:checked ~ .toggle-background::after
{
transform: translateX(calc(var(--handle-translation) * -1)) scale(0.9);
background: url('https://api.iconify.design/lucide/moon.svg?color=white') no-repeat center center;
}
/*#endregion */
/*#region Graph View */
#graph-canvas
{
width: 100%;
height: 100%;
border: 1px solid var(--modal-border-color);
border-radius: var(--modal-radius);
aspect-ratio: 1/1;
}
.graph-view-container.expanded
{
position: fixed;
width: 60%;
height: 90%;
right: 20%;
top: 5%;
background-color: var(--background-secondary);
z-index: 1000;
}
.graph-view-container
{
position: relative;
width: 100%;
aspect-ratio: 1/1;
display: flex;
}
.graph-icon
{
cursor: pointer;
color: var(--text-muted);
}
.graph-view-container .graph-icon > svg
{
width: 24px;
height: 24px;
background-color: var(--color-base-00);
outline-width: 6px;
outline-color: var(--color-base-00);
outline-offset: -1px;
outline-style: solid;
border-radius: 100px;
margin: 10px;
}
.graph-view-placeholder
{
padding: 0;
width: auto;
aspect-ratio: 1/1;
position: relative;
flex: none;
margin: var(--sidebar-margin);
}
.graph-view-placeholder:has(.expanded)
{
border-radius: var(--modal-radius);
border: 1px solid var(--modal-border-color);
}
.scale-down
{
transition: transform 0.2s ease-in-out;
transform: scale(0.9);
}
.scale-up
{
transition: transform 0.2s ease-in-out;
transform: scale(1);
}
.graph-expand
{
position: absolute;
top: 5px;
right: 5px;
}
/*#endregion */
/*#region Tweaks */
hr
{
border: none;
border-top: var(--hr-thickness) solid;
border-color: var(--hr-color);
}
.markdown-embed-link
{
display: none;
}
/*#endregion */

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
/* Using default theme. */

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

BIN
favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
images/background.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

BIN
images/background2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

BIN
images/enderman.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
images/wave.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

188
index.html Normal file
View File

@ -0,0 +1,188 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Enderman</title>
<meta property="og:type" content="website">
<meta property="og:title" content="Enderman">
<meta property="og:description" content="This is the official page for Enderman on YouTube.">
<meta property="og:url" content="https://enderman.ch/">
<meta property="og:image" content="http://enderman.ch/images/icon.png">
<meta property="og:image:secure_url" content="https://enderman.ch/images/icon.png">
<meta property="og:image:width" content="256">
<meta property="og:image:height" content="256">
<meta property="og:image:alt" content="Endermanch">
<link rel="icon" type="image/png" href="/favicon.png" />
<link href="https://cdn.jsdelivr.net/npm/fontawesome5-fullcss@1.1.0/css/all.min.css" rel="stylesheet" />
<link href="/styles/styles.css" rel="stylesheet" />
</head>
<body>
<div class="body-wrapper">
<div class="container">
<main>
<div class="text">
<h1>Enderman</h1>
<p>
<strong>Welcome to Enderman's official website!</strong><br><br>
Hello everyone! Enderman here. Good news - after 3 years, I have finally regained access to my vanity domain.<br>
For now, this website shall remain a crude landing page, but the actual version is
already in the works!<br>
</p>
<h2>Stay in touch</h2>
<ul>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-youtube"></i>
</div>
<a href="https://go.enderman.ch/youtube" target="_blank">Enderman</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-youtube"></i>
</div>
<a href="https://go.enderman.ch/andrew" target="_blank">Andrew</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-twitch"></i>
</div>
<a href="https://go.enderman.ch/twitch" target="_blank">Twitch</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-tiktok"></i>
</div>
<a href="https://go.enderman.ch/tiktok" target="_blank">TikTok</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-twitter"></i>
</div>
<a href="https://go.enderman.ch/twitter" target="_blank">Twitter</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-telegram"></i>
</div>
<a href="https://go.enderman.ch/telegram" target="_blank">Telegram</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-discord"></i>
</div>
<a href="https://go.enderman.ch/discord" target="_blank">Discord</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-github"></i>
</div>
<a href="https://go.enderman.ch/github" target="_blank">GitHub</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
<i class="fab fa-steam"></i>
</div>
<a href="https://go.enderman.ch/steam" target="_blank">Steam</a>
</div>
</li>
</ul>
<h2>Websites</h2>
<ul>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/malware" target="_blank">MalwareWatch</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/idiot" target="_blank">You Are An Idiot! (dot cc)</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/hurr-durr" target="_blank">HURR-DURR (dot cc)</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/malware-generator" target="_blank">Malware Generator</a>
</div>
</li>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/dont-click" target="_blank">ḑ̶̛̻̬̙̯̭̲͔͈̟̯͎̭̼̳͚̮̱̥̠͆͊͜͠ͅͅơ̶̢̭̫͔̝͖̫̲̓̉͆͛̏́̀͊̕͝͝ņ̴͍̗̰̝͈͚͖͕̻̟̮̯̼͙͎̦̻̍͒͋̐̓̈́͑͌̅̍̏̀̾̊̈̆͊͌͘͝ͅ'̷̢̛̛̼̟̭̳̀͛̂͌̽̄͆̔̄̏͝͝ẗ̵̛̛̤̞̰̗́̅̐͒́̇̚͜</a>
</div>
</li>
</ul>
<h2>Projects</h2>
<ul>
<li>
<div class="link-button">
<div class="link-icon">
</div>
<a href="https://go.enderman.ch/xpkeygen" target="_blank">Windows XP Keygen</a> (sister - <a href="https://go.enderman.ch/umskt" target="_blank">UMSKT</a>)
</div>
</li>
</ul>
<h2>Contact</h2>
<ul>
<li><p>Fanmail: <a href="mailto:contact@enderman.ch">contact@enderman.ch</a></p></li>
<li><p>Manager: <a href="mailto:manager@enderman.ch">manager@enderman.ch</a></p></li>
<li><p>Abuse: <a href="mailto:abuse@enderman.ch">abuse@enderman.ch</a></p></li>
</ul>
</div>
</main>
<hr>
<footer>
<div class="footer">
<p>Copyright © 2023 - <a href="/">enderman.ch</a></p>
</div>
</footer>
</div>
</div>
<div class="bottom-right">
<img src="/images/enderman.gif" alt="Hello!">
</div>
</body>
</html>

177
styles/styles.css Normal file
View File

@ -0,0 +1,177 @@
* {
margin: 0;
}
body {
background-color: black;
background-image: url("/images/background.jpg");
background-attachment: fixed;
background-size: cover;
background-repeat: no-repeat;
color: white;
font-family: "Lato", sans-serif;
font-size: 18px;
}
a {
color: lightskyblue;
-webkit-transition: ease 0.3s;
transition: ease 0.3s;
}
a:hover {
color: rgb(155, 186, 250);
}
a:active {
color: lightgray;
}
div.body-wrapper {
display: flex;
flex-direction: column;
align-items: center;
}
div.container {
display: flex;
flex-direction: column;
max-width: 80%;
background-color: rgba(0, 0, 0, 0.5);
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
}
div.text {
padding: 15px;
}
div.text h1 {
margin-bottom: 10px;
}
div.text h2, h3 {
margin-bottom: 5px;
}
div.text h4, h5, h6 {
margin-bottom: 3px;
}
div.text p {
line-height: 1.5;
margin-bottom: 10px;
}
div.text ul {
list-style-type: none;
padding: 0;
margin-bottom: 10px;
}
div.text i.fa-youtube:before {
color: rgb(236, 0, 0);
background: radial-gradient(at center, white 40%, transparent 10%);
background: -webkit-radial-gradient(at center, white 40%, transparent 10%);
}
div.text i.fa-twitch:before {
color: rgb(169, 112, 255);
background: radial-gradient(
ellipse 70% 55%,
white 60%,
transparent 50%
);
background: -webkit-radial-gradient(
ellipse 70% 55%,
white 60%,
transparent 50%
);
}
div.text i.fa-twitter:before {
color: rgb(73, 161, 242);
}
div.text i.fa-telegram:before {
color: rgb(88, 169, 243);
background: radial-gradient(at center, white 50%, transparent 10%);
background: -webkit-radial-gradient(at center, white 50%, transparent 10%);
}
div.text i.fa-discord:before {
color: rgb(86, 98, 246);
background: radial-gradient(at center, white 50%, transparent 10%);
background: -webkit-radial-gradient(at center, white 50%, transparent 10%);
}
div.text i.fa-github:before {
color: white;
background: radial-gradient(
ellipse 50% 65%,
rgb(1, 4, 9) 70%,
transparent 50%
);
background: -webkit-radial-gradient(at center, rgb(1, 4, 9) 50%, transparent 10%);
}
div.text i.fa-steam:before {
color: rgb(18, 27, 46);
background: radial-gradient(
ellipse 67% 60%,
white 67%,
transparent 60%
);
background: -webkit-radial-gradient(
ellipse 70% 60%,
white 70%,
transparent 60%
);
}
div.link-button {
display: flex;
flex-direction: row;
align-items: center;
gap: 10px;
}
div.link-icon > * {
width: 16px;
}
div.footer {
display: flex;
flex-direction: row;
justify-content: center;
padding: 10px;
}
div.bottom-right {
position: fixed;
right: 5%;
bottom: 0;
}
div.bottom-right img {
height: 30vmin;
}