Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save glennhefley/902a81a33e316486e22293890db6690e to your computer and use it in GitHub Desktop.
Save glennhefley/902a81a33e316486e22293890db6690e to your computer and use it in GitHub Desktop.
Word Count for Notion page
// ==UserScript==
// @name Compteur de mots et caractères Notion
// @name:en Notion word and caracters count
// @namespace https://github.com/paulverbeke
// @version 1.2
// @downloadURL https://gist.github.com/paulverbeke/092fbc514267b2fa56af6ffe43141119/raw/Compteur%2520de%2520mots%2520et%2520caract%25C3%25A8res%2520Notion.user.js
// @updateURL https://gist.github.com/paulverbeke/092fbc514267b2fa56af6ffe43141119/raw/Compteur%2520de%2520mots%2520et%2520caract%25C3%25A8res%2520Notion.user.js
// @description Affiche un simple compteur de mots et caractères dans Notion
// @description:en Displays a simple word and caracters count in Notion
// @author paulv
// @match https://www.notion.so/*
// @icon https://www.google.com/s2/favicons?domain=notion.so
// @grant none
// ==/UserScript==
//styling: modify as desired
const styles = document.createElement('style');
styles.innerHTML = `
.word-count {
z-index: 500;
position: absolute;
bottom: 20px;
right: 25px;
font: 16px ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
color:white;
}
.char-count {
z-index: 500;
position: absolute;
bottom: 5px;
right: 25px;
font: 16px ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, "Apple Color Emoji", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
}
.notion-help-button {
bottom: 40px !important;
}
`;
document.head.appendChild(styles);
//create + insert word count element
const wordCount = document.createElement('span');
wordCount.classList.add('word-count');
document.body.appendChild(wordCount);
//create + insert char count element
const charCount = document.createElement('span');
charCount.classList.add('char-count');
document.body.appendChild(charCount);
/* Word Count Function */
let pattern = /[a-zA-Z0-9_\u0392-\u03c9\u00c0-\u00ff\u0600-\u06ff\u0400-\u04ff]+|[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g;
function wordCountFunc(str) {
let m = str.match(pattern);
let count = 0;
if (!m) {
return 0;
}
for (let i = 0; i < m.length; i++) {
if (m[i].charCodeAt(0) >= 0x4e00) {
count += m[i].length;
} else {
count += 1;
}
}
return count;
};
/* Word Count Function */
//fill chars and words count element
function updateCount () {
try {
let text = '';
let selection = document.getSelection(); //display char count of selection only
//debugger;
if (selection.type === 'Range') { //char/words selected (not caret)
text = selection.toString();
}
else {
const pageContents = document.querySelectorAll('.notion-page-content');
const mainContentPage = pageContents[pageContents.length - 1]; // to get content of the correct page if in peek mode
//check if nodes selected
selection = mainContentPage.querySelectorAll('.notion-selectable-halo');
for (const block of selection) {//get contents of selected nodes
text += block.previousSibling.innerText + '\n';
}
if (!text) { //no selection or selection empty
//get content of entire page
text = mainContentPage.innerText;
}
}
//count chars, words, and display
const cCount = text.length;
const wCount = wordCountFunc(text);
charCount.innerText = `${cCount} caractère${cCount === 1 ? '' : 's'}`;
wordCount.innerText = `${wCount} mot${wCount === 1 ? '' : 's'}`;
} catch (err) {
//console.log('No content detected. Are you on a database page?'); //some pages do not have .notion-page-content
charCount.innerText = ''; //empty char count display
wordCount.innerText = ''; //empty word count display
}
}
//updates counts 500 seconds after last key press or selection change
document.addEventListener('keyup', debounce(updateCount, 500));
document.addEventListener('selectionchange', debounce(updateCount, 500));
setTimeout(updateCount, 500); //initial counts
//update word & chars count after navigation between pages
var pushState = history.pushState;
history.pushState = function () {
pushState.apply(history, arguments);
setTimeout(updateCount, 500);
};
//helper function
//minified from https://github.com/component/debounce
function debounce(l,n,u){var e,i,t,o,f;if(null==n)n=100;function a(){var r=Date.now()-o;if(r<n&&r>=0){e=setTimeout(a,n-r)}else{e=null;if(!u){f=l.apply(t,i);t=i=null}}}var r=function(){t=this;i=arguments;o=Date.now();var r=u&&!e;if(!e)e=setTimeout(a,n);if(r){f=l.apply(t,i);t=i=null}return f};r.clear=function(){if(e){clearTimeout(e);e=null}};r.flush=function(){if(e){f=l.apply(t,i);t=i=null;clearTimeout(e);e=null}};return r}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment