Created
May 4, 2024 04:04
-
-
Save glennhefley/902a81a33e316486e22293890db6690e to your computer and use it in GitHub Desktop.
Word Count for Notion page
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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