Skip to content

Instantly share code, notes, and snippets.

@elahd
Last active April 10, 2024 03:28
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save elahd/28f64feddd9ece56f4f0566d195d0cbd to your computer and use it in GitHub Desktop.
Save elahd/28f64feddd9ece56f4f0566d195d0cbd to your computer and use it in GitHub Desktop.
Confluence Auto Numbered Headings (Tampermonkey UserScript)

Description

This is a Tampermonkey userscript that adds a heading numbering feature to the page editor in Atlassian Confluence. This will number headings as follows:

1. Header 1

1.2 Header 2

1.2.3 Header 3

2. Header 1

Based on work by Markus Jenu at https://community.atlassian.com/t5/Confluence-questions/Is-it-possible-to-add-numbering-to-headings-in-Confluence/qaq-p/315517#M87046.

The original script was intended to be installed as a Confluence user macro. Adding macros requires admin rights to your Confluence instance. This script allows non-admin users to run this script locally.

Install

  1. Install the Tampermonkey extension for your web browser.
  2. Add Confluence Auto Numbered Headings to Tampermonkey from its home on Greasy Fork using the "Install this script" button. (The script you see here on GitHub auto-syncs to Greasy Fork.)
  3. Configure this script in Tampermonkey, if needed (see below).
  4. Edit any page in confluence. Add heading numbers using the new button shown in the screenshot:

screenshot

Configure

This script is pre-configured to work with Confluence instances hosted by Atlassian. If you run an internal / on-premises instance of Confluence, you'll need to change the script's settings in Tampermonkey as follows:

  1. Go to Tampermonkey > Dashboard.
  2. Under the "Installed userscripts" tab, click on the edit icon for Confluence Auto Numbered Headings.
  3. Click on the "Settings" tab.
  4. Under "Includes/Excludes" > "User matches", add the URL for your internal Confluence instance. The format should be something like https://confluence.companyintranet.com/*

Change Log

  • 2020-03-18 v0.4: Fixed a bug in which extra text was added to the end of headings that contained HTML. For example, <h3>Example <strong>Heading</strong></h3> would be changed to <h3>1.3 Example Heading <strong>Heading</strong></h3>.
  • 2020-03-20 v0.5: Fixed a bug in which the button failed to appear when creating a new page.
  • 2021-03-29 v0.6: Made compatible with Atlassian's new ProseMirror-based editor.
  • 2022-07-14 v0.7: Fixed issue in which dependency that was deleted from GreasyFork (WaitForKeyElements) prevented this script from loading.
// ==UserScript==
// @name Confluence Auto Numbered Headings
// @namespace https://gist.github.com/elahd/28f64feddd9ece56f4f0566d195d0cbd
// @version 0.7
// @description Adds numbered headings button to the page editor in Atlassian Confluence. Based on work by Markus Jenu at https://community.atlassian.com/t5/Confluence-questions/Is-it-possible-to-add-numbering-to-headings-in-Confluence/qaq-p/315517#M87046.
// @author Elahd Bar-Shai
// @match https://*.atlassian.net/wiki/spaces/*
// @match https://*.atlassian.net/wiki/spaces/*
// @require https://greasyfork.org/scripts/383527-wait-for-key-elements/code/Wait_for_key_elements.js?version=701631
// @grant none
// ==/UserScript==
(function() {
'use strict';
var jQuery = window.jQuery;
var old_conf;
function addIndex() {
var indices = [];
if (old_conf) {
jQuery("#wysiwygTextarea_ifr").contents().find("h1,h2,h3,h4,h5,h6").each(function(i,e) {
var hIndex = parseInt(this.nodeName.substring(1)) - 1;
if (indices.length - 1 > hIndex) {
indices= indices.slice(0, hIndex + 1 );
}
if (indices[hIndex] == undefined) {
indices[hIndex] = 0;
}
indices[hIndex]++;
jQuery(this).html(indices.join(".")+". " + removeNo(jQuery(this).html()));
});
} else {
jQuery(".ak-editor-content-area .ProseMirror").find("h1,h2,h3,h4,h5,h6").each(function(i,e) {
var hIndex = parseInt(this.nodeName.substring(1)) - 1;
if (indices.length - 1 > hIndex) {
indices= indices.slice(0, hIndex + 1 );
}
if (indices[hIndex] == undefined) {
indices[hIndex] = 0;
}
indices[hIndex]++;
jQuery(this).html(indices.join(".")+". " + removeNo(jQuery(this).html()));
});
}
}
function removeNo(str) {
let newstr = str.trim();
newstr = newstr.replace(/[\u00A0\u1680​\u180e\u2000-\u2009\u200a​\u200b​\u202f\u205f​\u3000]/g,' ');
if(IsNumeric(newstr.substring(0,newstr.indexOf(' ')))){
return newstr.substring(newstr.indexOf(' ')+1).trim();
}
return newstr;
}
function IsNumeric(num) {
num = num.split('.').join("");
return (num >=0 || num < 0);
}
function createButton () {
old_conf = jQuery('.ProseMirror').length == 0 ? true : false;
if (old_conf) {
window.AJS.toInit(() => {
jQuery('#rte-toolbar > div.aui-toolbar2-primary.toolbar-primary').append('<ul class="aui-buttons rte-toolbar-group-link"><li class="toolbar-item" data-tooltip="Auto-Number Headings" id="addIndex"><a class="toolbar-trigger aui-button aui-button-subtle" href="#" ><span class="aui-icon aui-icon-small aui-iconfont-table-of-contents">Auto-Number Headings</span></a></li></ul>')
jQuery("#addIndex").click(function(e) {
e.preventDefault();
addIndex();
});
});
} else {
jQuery('.sc-kafWEX.eAQEwn > span').last().after('<span class="sc-jTzLTM jzOOfP"><div><div class="sc-cIShpX hVLmrw"><button aria-haspopup="false" class="css-1k4akzn" type="button" tabindex="0" id="addIndex" style="align-items:center"><span class="css-1ujqpe8"><span role="img" aria-label="Action item" class="css-1e9p0wv"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-list-stars" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5z"/><path d="M2.242 2.194a.27.27 0 0 1 .516 0l.162.53c.035.115.14.194.258.194h.551c.259 0 .37.333.164.493l-.468.363a.277.277 0 0 0-.094.3l.173.569c.078.256-.213.462-.423.3l-.417-.324a.267.267 0 0 0-.328 0l-.417.323c-.21.163-.5-.043-.423-.299l.173-.57a.277.277 0 0 0-.094-.299l-.468-.363c-.206-.16-.095-.493.164-.493h.55a.271.271 0 0 0 .259-.194l.162-.53zm0 4a.27.27 0 0 1 .516 0l.162.53c.035.115.14.194.258.194h.551c.259 0 .37.333.164.493l-.468.363a.277.277 0 0 0-.094.3l.173.569c.078.255-.213.462-.423.3l-.417-.324a.267.267 0 0 0-.328 0l-.417.323c-.21.163-.5-.043-.423-.299l.173-.57a.277.277 0 0 0-.094-.299l-.468-.363c-.206-.16-.095-.493.164-.493h.55a.271.271 0 0 0 .259-.194l.162-.53zm0 4a.27.27 0 0 1 .516 0l.162.53c.035.115.14.194.258.194h.551c.259 0 .37.333.164.493l-.468.363a.277.277 0 0 0-.094.3l.173.569c.078.255-.213.462-.423.3l-.417-.324a.267.267 0 0 0-.328 0l-.417.323c-.21.163-.5-.043-.423-.299l.173-.57a.277.277 0 0 0-.094-.299l-.468-.363c-.206-.16-.095-.493.164-.493h.55a.271.271 0 0 0 .259-.194l.162-.53z"/></svg></span></span></button></div></div></span>');
jQuery("#addIndex").click(function(e) {
e.preventDefault();
addIndex();
});
}
}
// Wait for editor to load before creating button.
//LEGACY EDITOR
waitForKeyElements ("form#editpageform.editor.aui", createButton); //For editing existing pages.
waitForKeyElements ("form#createpageform.editor.aui", createButton); //For creating new pages.
//NEW EDITOR
waitForKeyElements (".sc-kafWEX.eAQEwn", createButton);
})();
@csuka
Copy link

csuka commented Mar 11, 2020

How can we enable this when our instance is hosted by Atlassian? What do you mean by it works out-of-the-box?
We currently don't see an option to install Macro's.

@elahd
Copy link
Author

elahd commented Mar 18, 2020

Hey @csuka: This is intended to be used with the Tampermonkey browser plugin, which must be installed locally for every user. Tampermonkey is available for all major browsers. Once that's installed, you can install this script from its home on the Greasy Fork userscript repository.

@alpapanik
Copy link

Hi,

After following the installation instructions, the script worked fine on Confluence 7.5.2 (with the old editor), but it doesn't seem to work with the new editor in Confluence cloud (current version 1000.0.0-a38692d0e846). Will there be an update anytime soon to work with the new editor?

@frankprill
Copy link

Is there any update concerning this what alpapanik asked?

@elahd
Copy link
Author

elahd commented Mar 30, 2021

@alpapanik @frankprill

Atlassian totally revamped Confluence's interface. I think I have this script working now in both the legacy and new editors, but my ability to test is limited. Try now w/ version 0.6.

Copy link

ghost commented Nov 10, 2021

Hello,
it seems the script does not work with Confluence 7.13.0

@drx777
Copy link

drx777 commented Apr 5, 2022

I have converted this concept into a bookmark

javascript:(function()%7Bfunction%20addIndex()%20%7Bvar%20indices%20%3D%20%5B%5D%3BjQuery(%22.ak-editor-content-area%20.ProseMirror%22).find(%22h1%2Ch2%2Ch3%2Ch4%2Ch5%2Ch6%22).each(function(i%2Ce)%20%7Bvar%20hIndex%20%3D%20parseInt(this.nodeName.substring(1))%20-%201%3Bif%20(indices.length%20-%201%20%3E%20hIndex)%20%7Bindices%3D%20indices.slice(0%2C%20hIndex%20%2B%201%20)%3B%7Dif%20(indices%5BhIndex%5D%20%3D%3D%20undefined)%20%7Bindices%5BhIndex%5D%20%3D%200%3B%7Dindices%5BhIndex%5D%2B%2B%3BjQuery(this).html(indices.join(%22.%22)%2B%22.%20%22%20%2B%20removeNo(jQuery(this).html()))%3B%7D)%3B%7Dfunction%20removeNo(str)%20%7Blet%20newstr%20%3D%20str.trim()%3Bnewstr%20%3D%20newstr.replace(%2F%5B%5Cu00A0%5Cu1680%E2%80%8B%5Cu180e%5Cu2000-%5Cu2009%5Cu200a%E2%80%8B%5Cu200b%E2%80%8B%5Cu202f%5Cu205f%E2%80%8B%5Cu3000%5D%2Fg%2C'%20')%3Bif(IsNumeric(newstr.substring(0%2Cnewstr.indexOf('%20'))))%7Breturn%20newstr.substring(newstr.indexOf('%20')%2B1).trim()%3B%7Dreturn%20newstr%3B%7Dfunction%20IsNumeric(num)%20%7Bnum%20%3D%20num.split('.').join(%22%22)%3Breturn%20(num%20%3E%3D0%20%7C%7C%20num%20%3C%200)%3B%7DaddIndex()%7D)()

more details here:

https://stackoverflow.com/questions/71749474/how-can-i-get-automatically-numbered-headings-in-confluence/71749475#71749475

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment