diff --git a/CHANGELOG.md b/CHANGELOG.md
index a505f09..5c82969 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+### v2.0.4
+- Fix pasting markdown and html
+- Add pasting of images (with autoupload)
+
### v2.0.3
- Fixed an issue, where links are converted wrong
diff --git a/composer.json b/composer.json
index f5edccb..ef8e58f 100644
--- a/composer.json
+++ b/composer.json
@@ -5,7 +5,7 @@
"homepage": "https://github.com/Offerel/roundcube_primitivenotes",
"type": "roundcube-plugin",
"license": "AGPL-3.0",
- "version": "2.0.3",
+ "version": "2.0.4",
"authors": [
{
"name": "Offerel",
diff --git a/js/notes.js b/js/notes.js
index ee6e8bf..4dfaa68 100644
--- a/js/notes.js
+++ b/js/notes.js
@@ -1,7 +1,7 @@
/**
* Roundcube Notes Plugin
*
- * @version 2.0.3
+ * @version 2.0.4
* @author Offerel
* @copyright Copyright (c) 2021, Offerel
* @license GNU General Public License, version 3
@@ -23,7 +23,9 @@ $(document).ready(function(){
delimiters: ',|;| ',
placeholder: 'Tags'
});
-
+
+ var editor1 = document.getElementById("editor1");
+
$.ajax({
'type': "POST",
'url': "notes.php",
@@ -39,9 +41,9 @@ $(document).ready(function(){
let cookie = element.split('=');
if(cookie[0].indexOf('pn_') > 0) media_folder = JSON.parse(decodeURIComponent(cookie[1]));
});
-
+
var mde = new EasyMDE({
- element: document.getElementById('editor1'),
+ element: editor1,
autoDownloadFontAwesome: false,
autofocus: true,
previewImagesInEditor: false,
@@ -51,8 +53,8 @@ $(document).ready(function(){
promptURLs: true,
inputStyle: 'contenteditable',
nativeSpellcheck: true,
- forceSync: true,
- //sideBySideFullscreen: false,
+ forceSync: false,
+ sideBySideFullscreen: true,
renderingConfig: {
codeSyntaxHighlighting: true,
sanitizerFunction: function(renderedHTML) {
@@ -61,7 +63,7 @@ $(document).ready(function(){
},
},
toolbar: [{ name: 'Save',
- action: saveFile,
+ action: saveFile,
className: 'fa fa-floppy-o',
title: 'Save',
}, '|',
@@ -69,12 +71,12 @@ $(document).ready(function(){
'code', 'quote', 'unordered-list', 'ordered-list', '|',
'link',
{ name: 'Image',
- action: uplInsertImage,
+ action: uplInsertImage,
className: 'fa fa-picture-o',
title: 'Add image from URL',
},
{ name: 'Image',
- action: uplLocalImage,
+ action: uplLocalImage,
className: 'fa fa-file-image-o',
title: 'Upload and insert local image',
},
@@ -111,7 +113,6 @@ $(document).ready(function(){
document.getElementById('author').value = '';
document.getElementById('date').value = '';
document.getElementById('source').value = '';
- document.querySelector('#main_area .EasyMDEContainer').addEventListener('paste', pasteParse, false);
} else {
let toolbar = document.createElement('div');
toolbar.id = 'atoolbar';
@@ -166,7 +167,7 @@ $(document).ready(function(){
}
}
});
-
+
document.addEventListener("keyup", event => {
if(event.key == 'Escape') {
if(document.getElementById('estate').value == 'e') {
@@ -185,7 +186,6 @@ $(document).ready(function(){
});
document.getElementById('notesearch').addEventListener('keyup', searchList, false);
-
document.getElementById('save_button').addEventListener('click', function() {
document.getElementById('metah').submit();
});
@@ -194,42 +194,104 @@ $(document).ready(function(){
new rcube_splitter({ id:'notessplitter', p1:'#sidebar', p2:'#main', orientation:'v', relative:true, start:400, min:250, size:12 }).init();
+ document.querySelector('.EasyMDEContainer').addEventListener('paste', pasteParse, true);
+
function pasteParse(event) {
- const pastedText = event.clipboardData.getData('text');
- const pastedHTML = event.clipboardData.getData('text/html');
- let textArr = pastedText.split('\n');
- if(textArr[0] == '---') {
- let cstart = pastedText.indexOf('---',4) + 3;
- for(var i = 1; i < 10; i++) {
- if(textArr[i] == '---') break;
- let yentry = textArr[i].split(':');
+ event.preventDefault();
+ event.stopPropagation();
+
+ const pastedString = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain');
+
+ for (var i = 0; i < event.clipboardData.items.length ; i++) {
+ let item = event.clipboardData.items[i];
+ if(item.type.indexOf("image") != -1) {
+ let imageT = event.clipboardData.getData('text/html');
+ if(imageT.indexOf('alt="') >= 0) {
+ let altS = imageT.indexOf('alt="') + 5;
+ let altE = imageT.indexOf('"',altS);
+ var alt = imageT.substr(altS, altE - altS);
+ } else var alt = '';
+
+ if(imageT.indexOf('title="') >= 0) {
+ let titleS = imageT.indexOf('title="') + 7;
+ let titleE = imageT.indexOf('"',titleS);
+ var title = imageT.substr(titleS, titleE - titleS);
+ } else var title = '';
+ let loader = document.createElement("div");
+
+ loader.classList.add("db-spinner");
+ loader.id = "db-spinner";
+ document.getElementById("main").appendChild(loader);
+
+ uploadFile(item.getAsFile(), alt, title);
+ return false;
+ }
+ }
+
+ function uploadFile(file, alt, title) {
+ var xhr = new XMLHttpRequest();
+ xhr.onload = function() {
+ if (xhr.status == 200) {
+ if(title) title = ' "'+title+'"';
+ mde.codemirror.replaceSelection('!['+alt+']('+xhr.responseText+title+')');
+ document.getElementById("db-spinner").remove();
+ } else {
+ console.log("Error! Upload failed");
+ }
+ };
+
+ xhr.onerror = function() {
+ console.log("Error! Upload failed. Can not connect to server.");
+ };
+
+ var formData = new FormData();
+ formData.append("localFile", file);
+ xhr.open('POST', 'notes.php', true);
+ xhr.send(formData);
+ }
+
+ let options = {
+ headingStyle: 'atx',
+ hr: '-',
+ bulletListMarker: '-',
+ codeBlockStyle: 'fenced',
+ fence: '```',
+ emDelimiter: '*',
+ strongDelimiter: '**',
+ linkStyle: 'inlined',
+ linkReferenceStyle: 'full',
+ collapseMultipleWhitespaces: true,
+ preformattedCode: true,
+ };
+
+ let turndownService = new window.TurndownService(options);
+
+ turndownService.addRule('kbd',{
+ filter:['kbd'],
+ replacement: function(content) {
+ return '' + content + '';
+ }
+ });
+
+ let markdownString = pastedString.startsWith('') ? turndownService.turndown(pastedString) : pastedString;
+
+ if(markdownString.startsWith('---')) {
+ let mdArr = markdownString.split('\n');
+ let cstart = markdownString.indexOf('---',4) + 3;
+ for(let i = 1; i < 10; i++) {
+ if(mdArr[i] == '---') break;
+ let yentry = mdArr[i].split(':');
if(yentry[0] == 'title') document.getElementById('note_name').value = yentry[1].trim();
if(yentry[0] == 'tags') tagify.addTags(yentry[1]);
if(yentry[0] == 'author') document.getElementById('author').value = yentry[1].trim();
if(yentry[0] == 'date') document.getElementById('date').value = yentry.slice(1).join(':').trim();
+ if(yentry[0] == 'updated') document.getElementById('updated').value = yentry.slice(1).join(':').trim();
if(yentry[0] == 'source') document.getElementById('source').value = yentry.slice(1).join(':').trim();
}
- mde.value(pastedText.substr(cstart).trim());
- }
-
- if(pastedHTML) {
- var options = {
- headingStyle: 'atx',
- hr: '-',
- bulletListMarker: '-',
- codeBlockStyle: 'fenced',
- fence: '```',
- emDelimiter: '*',
- strongDelimiter: '**',
- linkStyle: 'inlined',
- linkReferenceStyle: 'full',
- collapseMultipleWhitespaces: true,
- preformattedCode: true,
- };
- var turndownService = new window.TurndownService(options);
- turndownService.keep(['kbd', 'ins']);
- mde.value(turndownService.turndown(pastedHTML));
+ markdownString = markdownString.substr(cstart).trim();
}
+
+ mde.codemirror.replaceSelection(markdownString);
}
function firstNote() {
diff --git a/js/notes.min.js b/js/notes.min.js
index 7f38217..49b9fd7 100644
--- a/js/notes.min.js
+++ b/js/notes.min.js
@@ -1,9 +1,9 @@
/**
* Roundcube Notes Plugin
*
- * @version 2.0.3
+ * @version 2.0.4
* @author Offerel
* @copyright Copyright (c) 2021, Offerel
* @license GNU General Public License, version 3
*/
-$(document).ready((function(){var tagify=new Tagify(document.querySelector("#ntags"),{whitelist:[],dropdown:{classname:"color-blue",enabled:0,maxItems:0,position:"text",closeOnSelect:!1,highlightFirst:!0},trim:!0,duplicates:!1,enforceWhitelist:!1,delimiters:",|;| ",placeholder:"Tags"});let cookiesArr;var media_folder;$.ajax({type:"POST",url:"notes.php",data:{action:"getTags"},success:function(data){tagify.settings.whitelist=JSON.parse(data)}}),document.cookie.split(";").forEach((function(element){let cookie=element.split("=");cookie[0].indexOf("pn_")>0&&(media_folder=JSON.parse(decodeURIComponent(cookie[1])))}));var mde=new EasyMDE({element:document.getElementById("editor1"),autoDownloadFontAwesome:!1,autofocus:!0,previewImagesInEditor:!1,spellChecker:!1,autofocus:!0,status:!1,promptURLs:!0,inputStyle:"contenteditable",nativeSpellcheck:!0,forceSync:!0,renderingConfig:{codeSyntaxHighlighting:!0,sanitizerFunction:function(renderedHTML){let output;return renderedHTML.replaceAll(media_folder,"notes.php?blink=")}},toolbar:[{name:"Save",action:saveFile,className:"fa fa-floppy-o",title:"Save"},"|","undo","redo","|","bold","italic","strikethrough","clean-block","|","heading","heading-smaller","heading-bigger","|","code","quote","unordered-list","ordered-list","|","link",{name:"Image",action:uplInsertImage,className:"fa fa-picture-o",title:"Add image from URL"},{name:"Image",action:uplLocalImage,className:"fa fa-file-image-o",title:"Upload and insert local image"},"table","|","preview","side-by-side","fullscreen","guide","|"]});function pasteParse(event){const pastedText=event.clipboardData.getData("text"),pastedHTML=event.clipboardData.getData("text/html");let textArr=pastedText.split("\n");if("---"==textArr[0]){let cstart=pastedText.indexOf("---",4)+3;for(var i=1;i<10&&"---"!=textArr[i];i++){let yentry=textArr[i].split(":");"title"==yentry[0]&&(document.getElementById("note_name").value=yentry[1].trim()),"tags"==yentry[0]&&tagify.addTags(yentry[1]),"author"==yentry[0]&&(document.getElementById("author").value=yentry[1].trim()),"date"==yentry[0]&&(document.getElementById("date").value=yentry.slice(1).join(":").trim()),"source"==yentry[0]&&(document.getElementById("source").value=yentry.slice(1).join(":").trim())}mde.value(pastedText.substr(cstart).trim())}if(pastedHTML){var options={headingStyle:"atx",hr:"-",bulletListMarker:"-",codeBlockStyle:"fenced",fence:"```",emDelimiter:"*",strongDelimiter:"**",linkStyle:"inlined",linkReferenceStyle:"full",collapseMultipleWhitespaces:!0,preformattedCode:!0},turndownService=new window.TurndownService(options);turndownService.keep(["kbd","ins"]),mde.value(turndownService.turndown(pastedHTML))}}function firstNote(){showNote(document.getElementById("filelist").firstElementChild.classList[0])}function sbfile(){let tags=tagify.value,tArr=[];for(let tag in tags)tArr.push(tags[tag].value);$.ajax({type:"POST",url:"notes.php",data:{action:"sbfile",name:document.getElementById("note_name").value,fname:document.getElementById("fname").value,tags:tArr,content:document.getElementById("editor1").value},success:function(response){""==response?(console.log("Note saved successfully"),location.reload()):alert(response)}})}function showNote(id){document.querySelector("#main_area .editor-toolbar").style.display="none",document.getElementById("atoolbar")&&document.getElementById("atoolbar").remove(),document.getElementById("tbutton")&&document.getElementById("tbutton").remove();let loader=document.createElement("div");loader.classList.add("db-spinner"),loader.id="db-spinner",document.getElementById("main").appendChild(loader),document.getElementById("save_button").style.display="none";for(var elements=document.getElementsByClassName("selected");elements.length>0;)elements[0].classList.remove("selected");document.getElementById(id).classList.add("selected"),window.parent.document.getElementById("editnote").classList.remove("disabled"),window.parent.document.getElementById("deletenote").classList.remove("disabled"),window.parent.document.getElementById("sendnote").classList.remove("disabled");var fname=document.getElementById("entry"+id).value;$.ajax({type:"POST",url:"notes.php",data:{action:"showNote",filename:fname,id:id},success:function(data){var note=JSON.parse(data);document.getElementById("bcontent")&&document.getElementById("bcontent").remove(),document.querySelector(".EasyMDEContainer").classList.remove("EasyMDEContainerH"),document.getElementById("tocdiv")&&document.getElementById("tocdiv").remove();let headerTitle=document.createElement("span");if(headerTitle.id="headerTitle",headerTitle.classList.add("headerTitle"),document.querySelector("#main_header #note_name")&&document.querySelector("#main_header #note_name").replaceWith(headerTitle),document.querySelector("tags").classList.remove("edit"),document.getElementById("headerTitle").innerText=note.notename,document.getElementById("fname").value=note.filename,document.getElementById("author").value=note.author,document.getElementById("date").value=note.date,document.getElementById("source").value=note.source,tagify.setReadonly(!0),tagify.removeAllTags(),tagify.addTags(note.tags),document.querySelector(".EasyMDEContainer").style="display: block;",document.getElementById("editor1").style="display none;",document.getElementById("editor1").value=note.content,mde.value(note.content),"text"==note.mime_type.substr(0,4)){"e"==document.getElementById("estate").value&&(document.getElementById("estate").value="s",mde.togglePreview());var headings=document.querySelectorAll("h1, h2, h3, h4, h5, h6");if(headings.length>0){let tbutton=document.createElement("button");tbutton.id="tbutton",tbutton.innerText="ToC",document.getElementById("main_header").appendChild(tbutton);let tocdiv=document.createElement("div");tocdiv.id="tocdiv";let o=0,a=0,list="c%";headings.forEach((function(element){a=element.tagName.substr(1,1),list=o"):o>a?list.replace("c%",''+element.innerText+"c%"):list.replace("c%",''+element.innerText+"c%"),o=a})),list=list.replace("c%",""),tocdiv.innerHTML=list,tbutton.addEventListener("click",(function(e){e.preventDefault(),tocdiv.classList.toggle("tdhidden")})),document.querySelector(".EasyMDEContainer").appendChild(tocdiv),document.querySelectorAll("#tocdiv a").forEach((function(elem){elem.addEventListener("click",(function(){tocdiv.classList.toggle("tdhidden")}))}))}}else{let bcontent=document.createElement("object");bcontent.data="data:"+note.mime_type+";base64,"+note.content,bcontent.type=note.mime_type,bcontent.id="bcontent",note.mime_type.includes("pdf")&&(bcontent.style="width: 100%; height: 100%;"),document.querySelector(".EasyMDEContainer").classList.add("EasyMDEContainerH"),document.getElementById("main_area").appendChild(bcontent),document.getElementById("editor1").style="display: none",document.getElementById("atoolbar")&&document.getElementById("atoolbar").remove()}document.getElementById("db-spinner").parentNode.removeChild(loader)}})}function simage(){for(var allowed_extensions=new Array("jpg","jpeg","png"),file_extension=document.getElementById("localimg").value.split(".").pop().toLowerCase(),i=0;i<=allowed_extensions.length;i++)if(allowed_extensions[i]==file_extension){var file_data=$("#localimg").prop("files")[0],formData=new FormData;return formData.append("localFile",file_data),$.ajax({type:"POST",url:"notes.php",dataType:"text",cache:!1,contentType:!1,processData:!1,data:formData,success:function(data){pos=mde.codemirror.getCursor(),mde.codemirror.setSelection(pos,pos),mde.codemirror.replaceSelection("![]("+data+")")}}),!0}return alert("Unsupported file format"),!1}function saveFile(editor){let loader=document.createElement("div");loader.classList.add("db-spinner"),loader.id="db-spinner",document.getElementById("main").appendChild(loader);let fname=document.getElementById("fname").value,extb=fname.lastIndexOf(".")+1,tags=tagify.value,tArr=[];for(let tag in tags)tArr.push(tags[tag].value);$.ajax({type:"POST",url:"notes.php",data:{action:"editNote",note_name:document.getElementById("note_name").value,fname:fname,ntags:tArr,editor1:mde.value(),ftype:fname.substr(extb),author:document.getElementById("author").value,date:document.getElementById("date").value,source:document.getElementById("source").value},success:function(response){""==response?(console.log("Note saved successfully"),location.reload()):alert(response),loader.remove()}})}function uplLocalImage(){document.getElementById("localimg").click()}function uplInsertImage(){var imageURL=prompt("URL of the image","");if(!imageURL)return!1;$.ajax({type:"POST",url:"notes.php",data:{action:"uplImage",imageURL:imageURL},success:function(data){pos=mde.codemirror.getCursor(),mde.codemirror.setSelection(pos,pos),mde.codemirror.replaceSelection("![]("+data+")")}})}function searchList(){var input,filter,ul,li,a,i;for(filter=(input=document.getElementById("notesearch")).value.toUpperCase(),li=(ul=document.getElementById("filelist")).getElementsByTagName("li"),i=0;i-1?li[i].style.display="":li[i].style.display="none"}document.querySelectorAll("#filelist li a").forEach((function(note){note.addEventListener("click",(function(){showNote(note.parentElement.id),tagify.setReadonly(!0)}))})),window.addEventListener("message",e=>{let estate=document.getElementById("estate");if("tstate"in e.data&&tagify.setReadonly(e.data.tstate),"ttags"in e.data&&""==e.data.ttags&&tagify.removeAllTags(),"editor"in e.data&&"new"==e.data.editor){"s"==estate.value&&(mde.togglePreview(),estate.value="e"),mde.value(""),document.getElementById("fname").value="";let editor1=document.getElementById("editor1");if(editor1.value="","md"==e.data.format)document.querySelector("#main_area .editor-toolbar").style.display="block",document.querySelector(".EasyMDEContainer").style="display: block",mde.value(""),editor1.style="display: none;",document.getElementById("author").value="",document.getElementById("date").value="",document.getElementById("source").value="",document.querySelector("#main_area .EasyMDEContainer").addEventListener("paste",pasteParse,!1);else{let toolbar=document.createElement("div");toolbar.id="atoolbar";let bSave=document.createElement("li");bSave.id="bSave",bSave.classList.add("fa","fa-floppy-o"),bSave.addEventListener("click",sbfile,!1),toolbar.appendChild(bSave);let bSeperator=document.createElement("i");bSeperator.classList.add("separator"),toolbar.appendChild(bSeperator),editor1.parentNode.insertBefore(toolbar,editor1),document.querySelector(".EasyMDEContainer").style="display: none",editor1.style="display: block"}}if("editor"in e.data&&"edit"==e.data.editor){"s"==estate.value&&(mde.togglePreview(),estate.value="e");let file=document.getElementById("fname").value.split("."),format=file[file.length-1];switch(document.getElementById("atoolbar")&&document.getElementById("atoolbar").remove(),format){case"md":document.querySelector(".EasyMDEContainer").style="display: block;",document.querySelector("#main_area .editor-toolbar").style.display="block",document.querySelector("#editor1").style="display: none;";break;default:let toolbar=document.createElement("div"),editor=document.getElementById("editor1");toolbar.id="atoolbar";let bSave=document.createElement("li");bSave.id="bSave",bSave.classList.add("fa","fa-floppy-o"),bSave.addEventListener("click",sbfile,!1),toolbar.appendChild(bSave);let bSeperator=document.createElement("i");bSeperator.classList.add("separator"),toolbar.appendChild(bSeperator),editor.parentNode.insertBefore(toolbar,editor),document.querySelector(".EasyMDEContainer").style="display: none",editor.style="display: block",document.getElementById("bcontent")&&(document.getElementById("editor1").style="display: none")}}}),document.addEventListener("keyup",event=>{if("Escape"==event.key&&"e"==document.getElementById("estate").value){mde.togglePreview(),document.querySelector("#main_area .editor-toolbar").style.display="none",document.getElementById("estate").value="s";let headerTitle=document.createElement("span");headerTitle.id="headerTitle",headerTitle.classList.add("headerTitle"),headerTitle.innerText=document.getElementById("note_name").value,document.querySelector("#main_header #note_name").replaceWith(headerTitle),document.querySelector("tags").classList.remove("edit"),tagify.setReadonly(!0)}}),document.getElementById("notesearch").addEventListener("keyup",searchList,!1),document.getElementById("save_button").addEventListener("click",(function(){document.getElementById("metah").submit()})),document.getElementById("localimg").addEventListener("change",simage,!1),new rcube_splitter({id:"notessplitter",p1:"#sidebar",p2:"#main",orientation:"v",relative:!0,start:400,min:250,size:12}).init(),firstNote()}));
\ No newline at end of file
+$(document).ready((function(){var tagify=new Tagify(document.querySelector("#ntags"),{whitelist:[],dropdown:{classname:"color-blue",enabled:0,maxItems:0,position:"text",closeOnSelect:!1,highlightFirst:!0},trim:!0,duplicates:!1,enforceWhitelist:!1,delimiters:",|;| ",placeholder:"Tags"}),editor1=document.getElementById("editor1");let cookiesArr;var media_folder;$.ajax({type:"POST",url:"notes.php",data:{action:"getTags"},success:function(data){tagify.settings.whitelist=JSON.parse(data)}}),document.cookie.split(";").forEach((function(element){let cookie=element.split("=");cookie[0].indexOf("pn_")>0&&(media_folder=JSON.parse(decodeURIComponent(cookie[1])))}));var mde=new EasyMDE({element:editor1,autoDownloadFontAwesome:!1,autofocus:!0,previewImagesInEditor:!1,spellChecker:!1,autofocus:!0,status:!1,promptURLs:!0,inputStyle:"contenteditable",nativeSpellcheck:!0,forceSync:!1,sideBySideFullscreen:!0,renderingConfig:{codeSyntaxHighlighting:!0,sanitizerFunction:function(renderedHTML){let output;return renderedHTML.replaceAll(media_folder,"notes.php?blink=")}},toolbar:[{name:"Save",action:saveFile,className:"fa fa-floppy-o",title:"Save"},"|","undo","redo","|","bold","italic","strikethrough","clean-block","|","heading","heading-smaller","heading-bigger","|","code","quote","unordered-list","ordered-list","|","link",{name:"Image",action:uplInsertImage,className:"fa fa-picture-o",title:"Add image from URL"},{name:"Image",action:uplLocalImage,className:"fa fa-file-image-o",title:"Upload and insert local image"},"table","|","preview","side-by-side","fullscreen","guide","|"]});function pasteParse(event){event.preventDefault(),event.stopPropagation();const pastedString=event.clipboardData.getData("text/html")||event.clipboardData.getData("text/plain");for(var i=0;i=0){let altS=imageT.indexOf('alt="')+5,altE=imageT.indexOf('"',altS);var alt=imageT.substr(altS,altE-altS)}else var alt="";if(imageT.indexOf('title="')>=0){let titleS=imageT.indexOf('title="')+7,titleE=imageT.indexOf('"',titleS);var title=imageT.substr(titleS,titleE-titleS)}else var title="";let loader=document.createElement("div");return loader.classList.add("db-spinner"),loader.id="db-spinner",document.getElementById("main").appendChild(loader),uploadFile(item.getAsFile(),alt,title),!1}}function uploadFile(file,alt,title){var xhr=new XMLHttpRequest;xhr.onload=function(){200==xhr.status?(title&&(title=' "'+title+'"'),mde.codemirror.replaceSelection("!["+alt+"]("+xhr.responseText+title+")"),document.getElementById("db-spinner").remove()):console.log("Error! Upload failed")},xhr.onerror=function(){console.log("Error! Upload failed. Can not connect to server.")};var formData=new FormData;formData.append("localFile",file),xhr.open("POST","notes.php",!0),xhr.send(formData)}let options={headingStyle:"atx",hr:"-",bulletListMarker:"-",codeBlockStyle:"fenced",fence:"```",emDelimiter:"*",strongDelimiter:"**",linkStyle:"inlined",linkReferenceStyle:"full",collapseMultipleWhitespaces:!0,preformattedCode:!0},turndownService=new window.TurndownService(options);turndownService.addRule("kbd",{filter:["kbd"],replacement:function(content){return""+content+""}});let markdownString=pastedString.startsWith("")?turndownService.turndown(pastedString):pastedString;if(markdownString.startsWith("---")){let mdArr=markdownString.split("\n"),cstart=markdownString.indexOf("---",4)+3;for(let i=1;i<10&&"---"!=mdArr[i];i++){let yentry=mdArr[i].split(":");"title"==yentry[0]&&(document.getElementById("note_name").value=yentry[1].trim()),"tags"==yentry[0]&&tagify.addTags(yentry[1]),"author"==yentry[0]&&(document.getElementById("author").value=yentry[1].trim()),"date"==yentry[0]&&(document.getElementById("date").value=yentry.slice(1).join(":").trim()),"updated"==yentry[0]&&(document.getElementById("updated").value=yentry.slice(1).join(":").trim()),"source"==yentry[0]&&(document.getElementById("source").value=yentry.slice(1).join(":").trim())}markdownString=markdownString.substr(cstart).trim()}mde.codemirror.replaceSelection(markdownString)}function firstNote(){showNote(document.getElementById("filelist").firstElementChild.classList[0])}function sbfile(){let tags=tagify.value,tArr=[];for(let tag in tags)tArr.push(tags[tag].value);$.ajax({type:"POST",url:"notes.php",data:{action:"sbfile",name:document.getElementById("note_name").value,fname:document.getElementById("fname").value,tags:tArr,content:document.getElementById("editor1").value},success:function(response){""==response?(console.log("Note saved successfully"),location.reload()):alert(response)}})}function showNote(id){document.querySelector("#main_area .editor-toolbar").style.display="none",document.getElementById("atoolbar")&&document.getElementById("atoolbar").remove(),document.getElementById("tbutton")&&document.getElementById("tbutton").remove();let loader=document.createElement("div");loader.classList.add("db-spinner"),loader.id="db-spinner",document.getElementById("main").appendChild(loader),document.getElementById("save_button").style.display="none";for(var elements=document.getElementsByClassName("selected");elements.length>0;)elements[0].classList.remove("selected");document.getElementById(id).classList.add("selected"),window.parent.document.getElementById("editnote").classList.remove("disabled"),window.parent.document.getElementById("deletenote").classList.remove("disabled"),window.parent.document.getElementById("sendnote").classList.remove("disabled");var fname=document.getElementById("entry"+id).value;$.ajax({type:"POST",url:"notes.php",data:{action:"showNote",filename:fname,id:id},success:function(data){var note=JSON.parse(data);document.getElementById("bcontent")&&document.getElementById("bcontent").remove(),document.querySelector(".EasyMDEContainer").classList.remove("EasyMDEContainerH"),document.getElementById("tocdiv")&&document.getElementById("tocdiv").remove();let headerTitle=document.createElement("span");if(headerTitle.id="headerTitle",headerTitle.classList.add("headerTitle"),document.querySelector("#main_header #note_name")&&document.querySelector("#main_header #note_name").replaceWith(headerTitle),document.querySelector("tags").classList.remove("edit"),document.getElementById("headerTitle").innerText=note.notename,document.getElementById("fname").value=note.filename,document.getElementById("author").value=note.author,document.getElementById("date").value=note.date,document.getElementById("source").value=note.source,tagify.setReadonly(!0),tagify.removeAllTags(),tagify.addTags(note.tags),document.querySelector(".EasyMDEContainer").style="display: block;",document.getElementById("editor1").style="display none;",document.getElementById("editor1").value=note.content,mde.value(note.content),"text"==note.mime_type.substr(0,4)){"e"==document.getElementById("estate").value&&(document.getElementById("estate").value="s",mde.togglePreview());var headings=document.querySelectorAll("h1, h2, h3, h4, h5, h6");if(headings.length>0){let tbutton=document.createElement("button");tbutton.id="tbutton",tbutton.innerText="ToC",document.getElementById("main_header").appendChild(tbutton);let tocdiv=document.createElement("div");tocdiv.id="tocdiv";let o=0,a=0,list="c%";headings.forEach((function(element){a=element.tagName.substr(1,1),list=o"):o>a?list.replace("c%",''+element.innerText+"c%"):list.replace("c%",''+element.innerText+"c%"),o=a})),list=list.replace("c%",""),tocdiv.innerHTML=list,tbutton.addEventListener("click",(function(e){e.preventDefault(),tocdiv.classList.toggle("tdhidden")})),document.querySelector(".EasyMDEContainer").appendChild(tocdiv),document.querySelectorAll("#tocdiv a").forEach((function(elem){elem.addEventListener("click",(function(){tocdiv.classList.toggle("tdhidden")}))}))}}else{let bcontent=document.createElement("object");bcontent.data="data:"+note.mime_type+";base64,"+note.content,bcontent.type=note.mime_type,bcontent.id="bcontent",note.mime_type.includes("pdf")&&(bcontent.style="width: 100%; height: 100%;"),document.querySelector(".EasyMDEContainer").classList.add("EasyMDEContainerH"),document.getElementById("main_area").appendChild(bcontent),document.getElementById("editor1").style="display: none",document.getElementById("atoolbar")&&document.getElementById("atoolbar").remove()}document.getElementById("db-spinner").parentNode.removeChild(loader)}})}function simage(){for(var allowed_extensions=new Array("jpg","jpeg","png"),file_extension=document.getElementById("localimg").value.split(".").pop().toLowerCase(),i=0;i<=allowed_extensions.length;i++)if(allowed_extensions[i]==file_extension){var file_data=$("#localimg").prop("files")[0],formData=new FormData;return formData.append("localFile",file_data),$.ajax({type:"POST",url:"notes.php",dataType:"text",cache:!1,contentType:!1,processData:!1,data:formData,success:function(data){pos=mde.codemirror.getCursor(),mde.codemirror.setSelection(pos,pos),mde.codemirror.replaceSelection("![]("+data+")")}}),!0}return alert("Unsupported file format"),!1}function saveFile(editor){let loader=document.createElement("div");loader.classList.add("db-spinner"),loader.id="db-spinner",document.getElementById("main").appendChild(loader);let fname=document.getElementById("fname").value,extb=fname.lastIndexOf(".")+1,tags=tagify.value,tArr=[];for(let tag in tags)tArr.push(tags[tag].value);$.ajax({type:"POST",url:"notes.php",data:{action:"editNote",note_name:document.getElementById("note_name").value,fname:fname,ntags:tArr,editor1:mde.value(),ftype:fname.substr(extb),author:document.getElementById("author").value,date:document.getElementById("date").value,source:document.getElementById("source").value},success:function(response){""==response?(console.log("Note saved successfully"),location.reload()):alert(response),loader.remove()}})}function uplLocalImage(){document.getElementById("localimg").click()}function uplInsertImage(){var imageURL=prompt("URL of the image","");if(!imageURL)return!1;$.ajax({type:"POST",url:"notes.php",data:{action:"uplImage",imageURL:imageURL},success:function(data){pos=mde.codemirror.getCursor(),mde.codemirror.setSelection(pos,pos),mde.codemirror.replaceSelection("![]("+data+")")}})}function searchList(){var input,filter,ul,li,a,i;for(filter=(input=document.getElementById("notesearch")).value.toUpperCase(),li=(ul=document.getElementById("filelist")).getElementsByTagName("li"),i=0;i-1?li[i].style.display="":li[i].style.display="none"}document.querySelectorAll("#filelist li a").forEach((function(note){note.addEventListener("click",(function(){showNote(note.parentElement.id),tagify.setReadonly(!0)}))})),window.addEventListener("message",e=>{let estate=document.getElementById("estate");if("tstate"in e.data&&tagify.setReadonly(e.data.tstate),"ttags"in e.data&&""==e.data.ttags&&tagify.removeAllTags(),"editor"in e.data&&"new"==e.data.editor){"s"==estate.value&&(mde.togglePreview(),estate.value="e"),mde.value(""),document.getElementById("fname").value="";let editor1=document.getElementById("editor1");if(editor1.value="","md"==e.data.format)document.querySelector("#main_area .editor-toolbar").style.display="block",document.querySelector(".EasyMDEContainer").style="display: block",mde.value(""),editor1.style="display: none;",document.getElementById("author").value="",document.getElementById("date").value="",document.getElementById("source").value="";else{let toolbar=document.createElement("div");toolbar.id="atoolbar";let bSave=document.createElement("li");bSave.id="bSave",bSave.classList.add("fa","fa-floppy-o"),bSave.addEventListener("click",sbfile,!1),toolbar.appendChild(bSave);let bSeperator=document.createElement("i");bSeperator.classList.add("separator"),toolbar.appendChild(bSeperator),editor1.parentNode.insertBefore(toolbar,editor1),document.querySelector(".EasyMDEContainer").style="display: none",editor1.style="display: block"}}if("editor"in e.data&&"edit"==e.data.editor){"s"==estate.value&&(mde.togglePreview(),estate.value="e");let file=document.getElementById("fname").value.split("."),format=file[file.length-1];switch(document.getElementById("atoolbar")&&document.getElementById("atoolbar").remove(),format){case"md":document.querySelector(".EasyMDEContainer").style="display: block;",document.querySelector("#main_area .editor-toolbar").style.display="block",document.querySelector("#editor1").style="display: none;";break;default:let toolbar=document.createElement("div"),editor=document.getElementById("editor1");toolbar.id="atoolbar";let bSave=document.createElement("li");bSave.id="bSave",bSave.classList.add("fa","fa-floppy-o"),bSave.addEventListener("click",sbfile,!1),toolbar.appendChild(bSave);let bSeperator=document.createElement("i");bSeperator.classList.add("separator"),toolbar.appendChild(bSeperator),editor.parentNode.insertBefore(toolbar,editor),document.querySelector(".EasyMDEContainer").style="display: none",editor.style="display: block",document.getElementById("bcontent")&&(document.getElementById("editor1").style="display: none")}}}),document.addEventListener("keyup",event=>{if("Escape"==event.key&&"e"==document.getElementById("estate").value){mde.togglePreview(),document.querySelector("#main_area .editor-toolbar").style.display="none",document.getElementById("estate").value="s";let headerTitle=document.createElement("span");headerTitle.id="headerTitle",headerTitle.classList.add("headerTitle"),headerTitle.innerText=document.getElementById("note_name").value,document.querySelector("#main_header #note_name").replaceWith(headerTitle),document.querySelector("tags").classList.remove("edit"),tagify.setReadonly(!0)}}),document.getElementById("notesearch").addEventListener("keyup",searchList,!1),document.getElementById("save_button").addEventListener("click",(function(){document.getElementById("metah").submit()})),document.getElementById("localimg").addEventListener("change",simage,!1),new rcube_splitter({id:"notessplitter",p1:"#sidebar",p2:"#main",orientation:"v",relative:!0,start:400,min:250,size:12}).init(),document.querySelector(".EasyMDEContainer").addEventListener("paste",pasteParse,!0),firstNote()}));
\ No newline at end of file
diff --git a/js/primitivenotes.js b/js/primitivenotes.js
index c091ef5..a01b252 100644
--- a/js/primitivenotes.js
+++ b/js/primitivenotes.js
@@ -1,7 +1,7 @@
/**
* Roundcube Notes Plugin
*
- * @version 2.0.3
+ * @version 2.0.4
* @author Offerel
* @copyright Copyright (c) 2021, Offerel
* @license GNU General Public License, version 3
diff --git a/js/primitivenotes.min.js b/js/primitivenotes.min.js
index fe47099..fff32fc 100644
--- a/js/primitivenotes.min.js
+++ b/js/primitivenotes.min.js
@@ -1,7 +1,7 @@
/**
* Roundcube Notes Plugin
*
- * @version 2.0.3
+ * @version 2.0.4
* @author Offerel
* @copyright Copyright (c) 2021, Offerel
* @license GNU General Public License, version 3
diff --git a/js/turndown/turndown.js b/js/turndown/turndown.js
index 716ff22..deb57cd 100644
--- a/js/turndown/turndown.js
+++ b/js/turndown/turndown.js
@@ -1,932 +1,956 @@
var TurndownService = (function () {
-'use strict';
+ 'use strict';
-function extend (destination) {
- for (var i = 1; i < arguments.length; i++) {
- var source = arguments[i];
- for (var key in source) {
- if (source.hasOwnProperty(key)) destination[key] = source[key];
+ function extend (destination) {
+ for (var i = 1; i < arguments.length; i++) {
+ var source = arguments[i];
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) destination[key] = source[key];
+ }
}
+ return destination
}
- return destination
-}
-
-function repeat (character, count) {
- return Array(count + 1).join(character)
-}
-var blockElements = [
- 'address', 'article', 'aside', 'audio', 'blockquote', 'body', 'canvas',
- 'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption',
- 'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
- 'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav',
- 'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table',
- 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'
-];
+ function repeat (character, count) {
+ return Array(count + 1).join(character)
+ }
-function isBlock (node) {
- return blockElements.indexOf(node.nodeName.toLowerCase()) !== -1
-}
+ var blockElements = [
+ 'ADDRESS', 'ARTICLE', 'ASIDE', 'AUDIO', 'BLOCKQUOTE', 'BODY', 'CANVAS',
+ 'CENTER', 'DD', 'DIR', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE',
+ 'FOOTER', 'FORM', 'FRAMESET', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER',
+ 'HGROUP', 'HR', 'HTML', 'ISINDEX', 'LI', 'MAIN', 'MENU', 'NAV', 'NOFRAMES',
+ 'NOSCRIPT', 'OL', 'OUTPUT', 'P', 'PRE', 'SECTION', 'TABLE', 'TBODY', 'TD',
+ 'TFOOT', 'TH', 'THEAD', 'TR', 'UL'
+ ];
+
+ function isBlock (node) {
+ return is(node, blockElements)
+ }
-var voidElements = [
- 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
- 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'
-];
+ var voidElements = [
+ 'AREA', 'BASE', 'BR', 'COL', 'COMMAND', 'EMBED', 'HR', 'IMG', 'INPUT',
+ 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR'
+ ];
-function isVoid (node) {
- return voidElements.indexOf(node.nodeName.toLowerCase()) !== -1
-}
+ function isVoid (node) {
+ return is(node, voidElements)
+ }
-var voidSelector = voidElements.join();
-function hasVoid (node) {
- return node.querySelector && node.querySelector(voidSelector)
-}
+ function hasVoid (node) {
+ return has(node, voidElements)
+ }
-var rules = {};
+ var meaningfulWhenBlankElements = [
+ 'A', 'TABLE', 'THEAD', 'TBODY', 'TFOOT', 'TH', 'TD', 'IFRAME', 'SCRIPT',
+ 'AUDIO', 'VIDEO'
+ ];
-rules.paragraph = {
- filter: 'p',
+ function isMeaningfulWhenBlank (node) {
+ return is(node, meaningfulWhenBlankElements)
+ }
- replacement: function (content) {
- return '\n\n' + content + '\n\n'
+ function hasMeaningfulWhenBlank (node) {
+ return has(node, meaningfulWhenBlankElements)
}
-};
-rules.lineBreak = {
- filter: 'br',
+ function is (node, tagNames) {
+ return tagNames.indexOf(node.nodeName) >= 0
+ }
- replacement: function (content, node, options) {
- return options.br + '\n'
+ function has (node, tagNames) {
+ return (
+ node.getElementsByTagName &&
+ tagNames.some(function (tagName) {
+ return node.getElementsByTagName(tagName).length
+ })
+ )
}
-};
-rules.heading = {
- filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
+ var rules = {};
- replacement: function (content, node, options) {
- var hLevel = Number(node.nodeName.charAt(1));
+ rules.paragraph = {
+ filter: 'p',
- if (options.headingStyle === 'setext' && hLevel < 3) {
- var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
- return (
- '\n\n' + content + '\n' + underline + '\n\n'
- )
- } else {
- return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
+ replacement: function (content) {
+ return '\n\n' + content + '\n\n'
}
- }
-};
+ };
-rules.blockquote = {
- filter: 'blockquote',
+ rules.lineBreak = {
+ filter: 'br',
- replacement: function (content) {
- content = content.replace(/^\n+|\n+$/g, '');
- content = content.replace(/^/gm, '> ');
- return '\n\n' + content + '\n\n'
- }
-};
+ replacement: function (content, node, options) {
+ return options.br + '\n'
+ }
+ };
-rules.list = {
- filter: ['ul', 'ol'],
+ rules.heading = {
+ filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
- replacement: function (content, node) {
- var parent = node.parentNode;
- if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
- return '\n' + content
- } else {
+ replacement: function (content, node, options) {
+ var hLevel = Number(node.nodeName.charAt(1));
+
+ if (options.headingStyle === 'setext' && hLevel < 3) {
+ var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
+ return (
+ '\n\n' + content + '\n' + underline + '\n\n'
+ )
+ } else {
+ return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
+ }
+ }
+ };
+
+ rules.blockquote = {
+ filter: 'blockquote',
+
+ replacement: function (content) {
+ content = content.replace(/^\n+|\n+$/g, '');
+ content = content.replace(/^/gm, '> ');
return '\n\n' + content + '\n\n'
}
- }
-};
-
-rules.listItem = {
- filter: 'li',
-
- replacement: function (content, node, options) {
- content = content
- .replace(/^\n+/, '') // remove leading newlines
- .replace(/\n+$/, '\n') // replace trailing newlines with just a single one
- .replace(/\n/gm, '\n '); // indent
- var prefix = options.bulletListMarker + ' ';
- var parent = node.parentNode;
- if (parent.nodeName === 'OL') {
- var start = parent.getAttribute('start');
- var index = Array.prototype.indexOf.call(parent.children, node);
- prefix = (start ? Number(start) + index : index + 1) + '. ';
+ };
+
+ rules.list = {
+ filter: ['ul', 'ol'],
+
+ replacement: function (content, node) {
+ var parent = node.parentNode;
+ if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
+ return '\n' + content
+ } else {
+ return '\n\n' + content + '\n\n'
+ }
}
- return (
- prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
- )
- }
-};
+ };
-rules.indentedCodeBlock = {
- filter: function (node, options) {
- return (
- options.codeBlockStyle === 'indented' &&
- node.nodeName === 'PRE' &&
- node.firstChild &&
- node.firstChild.nodeName === 'CODE'
- )
- },
+ rules.listItem = {
+ filter: 'li',
+
+ replacement: function (content, node, options) {
+ content = content
+ .replace(/^\n+/, '') // remove leading newlines
+ .replace(/\n+$/, '\n') // replace trailing newlines with just a single one
+ .replace(/\n/gm, '\n '); // indent
+ var prefix = options.bulletListMarker + ' ';
+ var parent = node.parentNode;
+ if (parent.nodeName === 'OL') {
+ var start = parent.getAttribute('start');
+ var index = Array.prototype.indexOf.call(parent.children, node);
+ prefix = (start ? Number(start) + index : index + 1) + '. ';
+ }
+ return (
+ prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
+ )
+ }
+ };
- replacement: function (content, node, options) {
- return (
- '\n\n ' +
- node.firstChild.textContent.replace(/\n/g, '\n ') +
- '\n\n'
- )
- }
-};
+ rules.indentedCodeBlock = {
+ filter: function (node, options) {
+ return (
+ options.codeBlockStyle === 'indented' &&
+ node.nodeName === 'PRE' &&
+ node.firstChild &&
+ node.firstChild.nodeName === 'CODE'
+ )
+ },
-rules.fencedCodeBlock = {
- filter: function (node, options) {
- return (
- options.codeBlockStyle === 'fenced' &&
- node.nodeName === 'PRE' &&
- node.firstChild &&
- node.firstChild.nodeName === 'CODE'
- )
- },
+ replacement: function (content, node, options) {
+ return (
+ '\n\n ' +
+ node.firstChild.textContent.replace(/\n/g, '\n ') +
+ '\n\n'
+ )
+ }
+ };
- replacement: function (content, node, options) {
- var className = node.firstChild.className || '';
- var language = (className.match(/language-(\S+)/) || [null, ''])[1];
+ rules.fencedCodeBlock = {
+ filter: function (node, options) {
+ return (
+ options.codeBlockStyle === 'fenced' &&
+ node.nodeName === 'PRE' &&
+ node.firstChild &&
+ node.firstChild.nodeName === 'CODE'
+ )
+ },
- return (
- '\n\n' + options.fence + language + '\n' +
- node.firstChild.textContent +
- '\n' + options.fence + '\n\n'
- )
- }
-};
+ replacement: function (content, node, options) {
+ var className = node.firstChild.getAttribute('class') || '';
+ var language = (className.match(/language-(\S+)/) || [null, ''])[1];
+ var code = node.firstChild.textContent;
-rules.horizontalRule = {
- filter: 'hr',
+ var fenceChar = options.fence.charAt(0);
+ var fenceSize = 3;
+ var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm');
- replacement: function (content, node, options) {
- return '\n\n' + options.hr + '\n\n'
- }
-};
+ var match;
+ while ((match = fenceInCodeRegex.exec(code))) {
+ if (match[0].length >= fenceSize) {
+ fenceSize = match[0].length + 1;
+ }
+ }
-rules.inlineLink = {
- filter: function (node, options) {
- return (
- options.linkStyle === 'inlined' &&
- node.nodeName === 'A' &&
- node.getAttribute('href')
- )
- },
+ var fence = repeat(fenceChar, fenceSize);
- replacement: function (content, node) {
- var href = node.getAttribute('href');
- var title = node.title ? ' "' + node.title + '"' : '';
- return '[' + content + '](' + href + title + ')'
- }
-};
+ return (
+ '\n\n' + fence + language + '\n' +
+ code.replace(/\n$/, '') +
+ '\n' + fence + '\n\n'
+ )
+ }
+ };
-rules.referenceLink = {
- filter: function (node, options) {
- return (
- options.linkStyle === 'referenced' &&
- node.nodeName === 'A' &&
- node.getAttribute('href')
- )
- },
-
- replacement: function (content, node, options) {
- var href = node.getAttribute('href');
- var title = node.title ? ' "' + node.title + '"' : '';
- var replacement;
- var reference;
-
- switch (options.linkReferenceStyle) {
- case 'collapsed':
- replacement = '[' + content + '][]';
- reference = '[' + content + ']: ' + href + title;
- break
- case 'shortcut':
- replacement = '[' + content + ']';
- reference = '[' + content + ']: ' + href + title;
- break
- default:
- var id = this.references.length + 1;
- replacement = '[' + content + '][' + id + ']';
- reference = '[' + id + ']: ' + href + title;
+ rules.horizontalRule = {
+ filter: 'hr',
+
+ replacement: function (content, node, options) {
+ return '\n\n' + options.hr + '\n\n'
}
+ };
+
+ rules.inlineLink = {
+ filter: function (node, options) {
+ return (
+ options.linkStyle === 'inlined' &&
+ node.nodeName === 'A' &&
+ node.getAttribute('href')
+ )
+ },
+
+ replacement: function (content, node) {
+ var href = node.getAttribute('href');
+ var title = cleanAttribute(node.getAttribute('title'));
+ if (title) title = ' "' + title + '"';
+ return '[' + content + '](' + href + title + ')'
+ }
+ };
- this.references.push(reference);
- return replacement
- },
+ rules.referenceLink = {
+ filter: function (node, options) {
+ return (
+ options.linkStyle === 'referenced' &&
+ node.nodeName === 'A' &&
+ node.getAttribute('href')
+ )
+ },
- references: [],
+ replacement: function (content, node, options) {
+ var href = node.getAttribute('href');
+ var title = cleanAttribute(node.getAttribute('title'));
+ if (title) title = ' "' + title + '"';
+ var replacement;
+ var reference;
+
+ switch (options.linkReferenceStyle) {
+ case 'collapsed':
+ replacement = '[' + content + '][]';
+ reference = '[' + content + ']: ' + href + title;
+ break
+ case 'shortcut':
+ replacement = '[' + content + ']';
+ reference = '[' + content + ']: ' + href + title;
+ break
+ default:
+ var id = this.references.length + 1;
+ replacement = '[' + content + '][' + id + ']';
+ reference = '[' + id + ']: ' + href + title;
+ }
+
+ this.references.push(reference);
+ return replacement
+ },
- append: function (options) {
- var references = '';
- if (this.references.length) {
- references = '\n\n' + this.references.join('\n') + '\n\n';
- this.references = []; // Reset references
+ references: [],
+
+ append: function (options) {
+ var references = '';
+ if (this.references.length) {
+ references = '\n\n' + this.references.join('\n') + '\n\n';
+ this.references = []; // Reset references
+ }
+ return references
}
- return references
- }
-};
+ };
-rules.emphasis = {
- filter: ['em', 'i'],
+ rules.emphasis = {
+ filter: ['em', 'i'],
- replacement: function (content, node, options) {
- if (!content.trim()) return ''
- return options.emDelimiter + content + options.emDelimiter
- }
-};
+ replacement: function (content, node, options) {
+ if (!content.trim()) return ''
+ return options.emDelimiter + content + options.emDelimiter
+ }
+ };
-rules.strong = {
- filter: ['strong', 'b'],
+ rules.strong = {
+ filter: ['strong', 'b'],
- replacement: function (content, node, options) {
- if (!content.trim()) return ''
- return options.strongDelimiter + content + options.strongDelimiter
- }
-};
+ replacement: function (content, node, options) {
+ if (!content.trim()) return ''
+ return options.strongDelimiter + content + options.strongDelimiter
+ }
+ };
+
+ rules.code = {
+ filter: function (node) {
+ var hasSiblings = node.previousSibling || node.nextSibling;
+ var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
-rules.code = {
- filter: function (node) {
- var hasSiblings = node.previousSibling || node.nextSibling;
- var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
+ return node.nodeName === 'CODE' && !isCodeBlock
+ },
+
+ replacement: function (content) {
+ if (!content.trim()) return ''
+
+ var delimiter = '`';
+ var leadingSpace = '';
+ var trailingSpace = '';
+ var matches = content.match(/`+/gm);
+ if (matches) {
+ if (/^`/.test(content)) leadingSpace = ' ';
+ if (/`$/.test(content)) trailingSpace = ' ';
+ while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
+ }
- return node.nodeName === 'CODE' && !isCodeBlock
- },
+ return delimiter + leadingSpace + content + trailingSpace + delimiter
+ }
+ };
- replacement: function (content) {
- if (!content.trim()) return ''
+ rules.image = {
+ filter: 'img',
- var delimiter = '`';
- var leadingSpace = '';
- var trailingSpace = '';
- var matches = content.match(/`+/gm);
- if (matches) {
- if (/^`/.test(content)) leadingSpace = ' ';
- if (/`$/.test(content)) trailingSpace = ' ';
- while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
+ replacement: function (content, node) {
+ var alt = cleanAttribute(node.getAttribute('alt'));
+ var src = node.getAttribute('src') || '';
+ var title = cleanAttribute(node.getAttribute('title'));
+ var titlePart = title ? ' "' + title + '"' : '';
+ return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
}
+ };
- return delimiter + leadingSpace + content + trailingSpace + delimiter
+ function cleanAttribute (attribute) {
+ return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
}
-};
-rules.image = {
- filter: 'img',
+ /**
+ * Manages a collection of rules used to convert HTML to Markdown
+ */
+
+ function Rules (options) {
+ this.options = options;
+ this._keep = [];
+ this._remove = [];
+
+ this.blankRule = {
+ replacement: options.blankReplacement
+ };
- replacement: function (content, node) {
- var alt = node.alt || '';
- var src = node.getAttribute('src') || '';
- var title = node.title || '';
- var titlePart = title ? ' "' + title + '"' : '';
- return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
+ this.keepReplacement = options.keepReplacement;
+
+ this.defaultRule = {
+ replacement: options.defaultReplacement
+ };
+
+ this.array = [];
+ for (var key in options.rules) this.array.push(options.rules[key]);
}
-};
-/**
- * Manages a collection of rules used to convert HTML to Markdown
- */
+ Rules.prototype = {
+ add: function (key, rule) {
+ this.array.unshift(rule);
+ },
-function Rules (options) {
- this.options = options;
- this._keep = [];
- this._remove = [];
+ keep: function (filter) {
+ this._keep.unshift({
+ filter: filter,
+ replacement: this.keepReplacement
+ });
+ },
- this.blankRule = {
- replacement: options.blankReplacement
- };
+ remove: function (filter) {
+ this._remove.unshift({
+ filter: filter,
+ replacement: function () {
+ return ''
+ }
+ });
+ },
- this.keepReplacement = options.keepReplacement;
+ forNode: function (node) {
+ if (node.isBlank) return this.blankRule
+ var rule;
- this.defaultRule = {
- replacement: options.defaultReplacement
+ if ((rule = findRule(this.array, node, this.options))) return rule
+ if ((rule = findRule(this._keep, node, this.options))) return rule
+ if ((rule = findRule(this._remove, node, this.options))) return rule
+
+ return this.defaultRule
+ },
+
+ forEach: function (fn) {
+ for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
+ }
};
- this.array = [];
- for (var key in options.rules) this.array.push(options.rules[key]);
-}
+ function findRule (rules, node, options) {
+ for (var i = 0; i < rules.length; i++) {
+ var rule = rules[i];
+ if (filterValue(rule, node, options)) return rule
+ }
+ return void 0
+ }
-Rules.prototype = {
- add: function (key, rule) {
- this.array.unshift(rule);
- },
+ function filterValue (rule, node, options) {
+ var filter = rule.filter;
+ if (typeof filter === 'string') {
+ if (filter === node.nodeName.toLowerCase()) return true
+ } else if (Array.isArray(filter)) {
+ if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
+ } else if (typeof filter === 'function') {
+ if (filter.call(rule, node, options)) return true
+ } else {
+ throw new TypeError('`filter` needs to be a string, array, or function')
+ }
+ }
- keep: function (filter) {
- this._keep.unshift({
- filter: filter,
- replacement: this.keepReplacement
- });
- },
+ /**
+ * The collapseWhitespace function is adapted from collapse-whitespace
+ * by Luc Thevenard.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014 Luc Thevenard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
- remove: function (filter) {
- this._remove.unshift({
- filter: filter,
- replacement: function () {
- return ''
- }
- });
- },
-
- forNode: function (node) {
- if (node.isBlank) return this.blankRule
- var rule;
-
- if ((rule = findRule(this.array, node, this.options))) return rule
- if ((rule = findRule(this._keep, node, this.options))) return rule
- if ((rule = findRule(this._remove, node, this.options))) return rule
-
- return this.defaultRule
- },
-
- forEach: function (fn) {
- for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
- }
-};
-
-function findRule (rules, node, options) {
- for (var i = 0; i < rules.length; i++) {
- var rule = rules[i];
- if (filterValue(rule, node, options)) return rule
- }
- return void 0
-}
-
-function filterValue (rule, node, options) {
- var filter = rule.filter;
- if (typeof filter === 'string') {
- if (filter === node.nodeName.toLowerCase()) return true
- } else if (Array.isArray(filter)) {
- if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
- } else if (typeof filter === 'function') {
- if (filter.call(rule, node, options)) return true
- } else {
- throw new TypeError('`filter` needs to be a string, array, or function')
- }
-}
-
-/**
- * The collapseWhitespace function is adapted from collapse-whitespace
- * by Luc Thevenard.
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Luc Thevenard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/**
- * collapseWhitespace(options) removes extraneous whitespace from an the given element.
- *
- * @param {Object} options
- */
-function collapseWhitespace (options) {
- var element = options.element;
- var isBlock = options.isBlock;
- var isVoid = options.isVoid;
- var isPre = options.isPre || function (node) {
- return node.nodeName === 'PRE'
- };
+ /**
+ * collapseWhitespace(options) removes extraneous whitespace from an the given element.
+ *
+ * @param {Object} options
+ */
+ function collapseWhitespace (options) {
+ var element = options.element;
+ var isBlock = options.isBlock;
+ var isVoid = options.isVoid;
+ var isPre = options.isPre || function (node) {
+ return node.nodeName === 'PRE'
+ };
- if (!element.firstChild || isPre(element)) return
+ if (!element.firstChild || isPre(element)) return
- var prevText = null;
- var prevVoid = false;
+ var prevText = null;
+ var prevVoid = false;
- var prev = null;
- var node = next(prev, element, isPre);
+ var prev = null;
+ var node = next(prev, element, isPre);
- while (node !== element) {
- if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
- var text = node.data.replace(/[ \r\n\t]+/g, ' ');
+ while (node !== element) {
+ if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
+ var text = node.data.replace(/[ \r\n\t]+/g, ' ');
- if ((!prevText || / $/.test(prevText.data)) &&
- !prevVoid && text[0] === ' ') {
- text = text.substr(1);
- }
+ if ((!prevText || / $/.test(prevText.data)) &&
+ !prevVoid && text[0] === ' ') {
+ text = text.substr(1);
+ }
- // `text` might be empty at this point.
- if (!text) {
+ // `text` might be empty at this point.
+ if (!text) {
+ node = remove(node);
+ continue
+ }
+
+ node.data = text;
+
+ prevText = node;
+ } else if (node.nodeType === 1) { // Node.ELEMENT_NODE
+ if (isBlock(node) || node.nodeName === 'BR') {
+ if (prevText) {
+ prevText.data = prevText.data.replace(/ $/, '');
+ }
+
+ prevText = null;
+ prevVoid = false;
+ } else if (isVoid(node)) {
+ // Avoid trimming space around non-block, non-BR void elements.
+ prevText = null;
+ prevVoid = true;
+ }
+ } else {
node = remove(node);
continue
}
- node.data = text;
-
- prevText = node;
- } else if (node.nodeType === 1) { // Node.ELEMENT_NODE
- if (isBlock(node) || node.nodeName === 'BR') {
- if (prevText) {
- prevText.data = prevText.data.replace(/ $/, '');
- }
+ var nextNode = next(prev, node, isPre);
+ prev = node;
+ node = nextNode;
+ }
- prevText = null;
- prevVoid = false;
- } else if (isVoid(node)) {
- // Avoid trimming space around non-block, non-BR void elements.
- prevText = null;
- prevVoid = true;
+ if (prevText) {
+ prevText.data = prevText.data.replace(/ $/, '');
+ if (!prevText.data) {
+ remove(prevText);
}
- } else {
- node = remove(node);
- continue
}
+ }
+
+ /**
+ * remove(node) removes the given node from the DOM and returns the
+ * next node in the sequence.
+ *
+ * @param {Node} node
+ * @return {Node} node
+ */
+ function remove (node) {
+ var next = node.nextSibling || node.parentNode;
+
+ node.parentNode.removeChild(node);
- var nextNode = next(prev, node, isPre);
- prev = node;
- node = nextNode;
+ return next
}
- if (prevText) {
- prevText.data = prevText.data.replace(/ $/, '');
- if (!prevText.data) {
- remove(prevText);
+ /**
+ * next(prev, current, isPre) returns the next node in the sequence, given the
+ * current and previous nodes.
+ *
+ * @param {Node} prev
+ * @param {Node} current
+ * @param {Function} isPre
+ * @return {Node}
+ */
+ function next (prev, current, isPre) {
+ if ((prev && prev.parentNode === current) || isPre(current)) {
+ return current.nextSibling || current.parentNode
}
+
+ return current.firstChild || current.nextSibling || current.parentNode
}
-}
-
-/**
- * remove(node) removes the given node from the DOM and returns the
- * next node in the sequence.
- *
- * @param {Node} node
- * @return {Node} node
- */
-function remove (node) {
- var next = node.nextSibling || node.parentNode;
-
- node.parentNode.removeChild(node);
-
- return next
-}
-
-/**
- * next(prev, current, isPre) returns the next node in the sequence, given the
- * current and previous nodes.
- *
- * @param {Node} prev
- * @param {Node} current
- * @param {Function} isPre
- * @return {Node}
- */
-function next (prev, current, isPre) {
- if ((prev && prev.parentNode === current) || isPre(current)) {
- return current.nextSibling || current.parentNode
- }
-
- return current.firstChild || current.nextSibling || current.parentNode
-}
-
-/*
- * Set up window for Node.js
- */
-
-var root = (typeof window !== 'undefined' ? window : {});
-
-/*
- * Parsing HTML strings
- */
-
-function canParseHTMLNatively () {
- var Parser = root.DOMParser;
- var canParse = false;
-
- // Adapted from https://gist.github.com/1129031
- // Firefox/Opera/IE throw errors on unsupported types
- try {
- // WebKit returns null on unsupported types
- if (new Parser().parseFromString('', 'text/html')) {
- canParse = true;
- }
- } catch (e) {}
-
- return canParse
-}
-
-function createHTMLParser () {
- var Parser = function () {};
-
- {
- if (shouldUseActiveX()) {
- Parser.prototype.parseFromString = function (string) {
- var doc = new window.ActiveXObject('htmlfile');
- doc.designMode = 'on'; // disable on-page scripts
- doc.open();
- doc.write(string);
- doc.close();
- return doc
- };
- } else {
- Parser.prototype.parseFromString = function (string) {
- var doc = document.implementation.createHTMLDocument('');
- doc.open();
- doc.write(string);
- doc.close();
- return doc
- };
+
+ /*
+ * Set up window for Node.js
+ */
+
+ var root = (typeof window !== 'undefined' ? window : {});
+
+ /*
+ * Parsing HTML strings
+ */
+
+ function canParseHTMLNatively () {
+ var Parser = root.DOMParser;
+ var canParse = false;
+
+ // Adapted from https://gist.github.com/1129031
+ // Firefox/Opera/IE throw errors on unsupported types
+ try {
+ // WebKit returns null on unsupported types
+ if (new Parser().parseFromString('', 'text/html')) {
+ canParse = true;
+ }
+ } catch (e) {}
+
+ return canParse
+ }
+
+ function createHTMLParser () {
+ var Parser = function () {};
+
+ {
+ if (shouldUseActiveX()) {
+ Parser.prototype.parseFromString = function (string) {
+ var doc = new window.ActiveXObject('htmlfile');
+ doc.designMode = 'on'; // disable on-page scripts
+ doc.open();
+ doc.write(string);
+ doc.close();
+ return doc
+ };
+ } else {
+ Parser.prototype.parseFromString = function (string) {
+ var doc = document.implementation.createHTMLDocument('');
+ doc.open();
+ doc.write(string);
+ doc.close();
+ return doc
+ };
+ }
}
+ return Parser
}
- return Parser
-}
-
-function shouldUseActiveX () {
- var useActiveX = false;
- try {
- document.implementation.createHTMLDocument('').open();
- } catch (e) {
- if (window.ActiveXObject) useActiveX = true;
- }
- return useActiveX
-}
-
-var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
-
-function RootNode (input) {
- var root;
- if (typeof input === 'string') {
- var doc = htmlParser().parseFromString(
- // DOM parsers arrange elements in the and .
- // Wrapping in a custom element ensures elements are reliably arranged in
- // a single element.
- '' + input + '',
- 'text/html'
- );
- root = doc.getElementById('turndown-root');
- } else {
- root = input.cloneNode(true);
- }
- collapseWhitespace({
- element: root,
- isBlock: isBlock,
- isVoid: isVoid
- });
-
- return root
-}
-
-var _htmlParser;
-function htmlParser () {
- _htmlParser = _htmlParser || new HTMLParser();
- return _htmlParser
-}
-
-function Node (node) {
- node.isBlock = isBlock(node);
- node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode;
- node.isBlank = isBlank(node);
- node.flankingWhitespace = flankingWhitespace(node);
- return node
-}
-
-function isBlank (node) {
- return (
- ['A', 'TH', 'TD'].indexOf(node.nodeName) === -1 &&
- /^\s*$/i.test(node.textContent) &&
- !isVoid(node) &&
- !hasVoid(node)
- )
-}
-
-function flankingWhitespace (node) {
- var leading = '';
- var trailing = '';
-
- if (!node.isBlock) {
- var hasLeading = /^[ \r\n\t]/.test(node.textContent);
- var hasTrailing = /[ \r\n\t]$/.test(node.textContent);
-
- if (hasLeading && !isFlankedByWhitespace('left', node)) {
- leading = ' ';
+
+ function shouldUseActiveX () {
+ var useActiveX = false;
+ try {
+ document.implementation.createHTMLDocument('').open();
+ } catch (e) {
+ if (window.ActiveXObject) useActiveX = true;
}
- if (hasTrailing && !isFlankedByWhitespace('right', node)) {
- trailing = ' ';
+ return useActiveX
+ }
+
+ var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
+
+ function RootNode (input) {
+ var root;
+ if (typeof input === 'string') {
+ var doc = htmlParser().parseFromString(
+ // DOM parsers arrange elements in the and .
+ // Wrapping in a custom element ensures elements are reliably arranged in
+ // a single element.
+ '' + input + '',
+ 'text/html'
+ );
+ root = doc.getElementById('turndown-root');
+ } else {
+ root = input.cloneNode(true);
}
+ collapseWhitespace({
+ element: root,
+ isBlock: isBlock,
+ isVoid: isVoid
+ });
+
+ return root
}
- return { leading: leading, trailing: trailing }
-}
+ var _htmlParser;
+ function htmlParser () {
+ _htmlParser = _htmlParser || new HTMLParser();
+ return _htmlParser
+ }
-function isFlankedByWhitespace (side, node) {
- var sibling;
- var regExp;
- var isFlanked;
+ function Node (node) {
+ node.isBlock = isBlock(node);
+ node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode;
+ node.isBlank = isBlank(node);
+ node.flankingWhitespace = flankingWhitespace(node);
+ return node
+ }
- if (side === 'left') {
- sibling = node.previousSibling;
- regExp = / $/;
- } else {
- sibling = node.nextSibling;
- regExp = /^ /;
+ function isBlank (node) {
+ return (
+ !isVoid(node) &&
+ !isMeaningfulWhenBlank(node) &&
+ /^\s*$/i.test(node.textContent) &&
+ !hasVoid(node) &&
+ !hasMeaningfulWhenBlank(node)
+ )
}
- if (sibling) {
- if (sibling.nodeType === 3) {
- isFlanked = regExp.test(sibling.nodeValue);
- } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
- isFlanked = regExp.test(sibling.textContent);
+ function flankingWhitespace (node) {
+ var leading = '';
+ var trailing = '';
+
+ if (!node.isBlock) {
+ var hasLeading = /^\s/.test(node.textContent);
+ var hasTrailing = /\s$/.test(node.textContent);
+ var blankWithSpaces = node.isBlank && hasLeading && hasTrailing;
+
+ if (hasLeading && !isFlankedByWhitespace('left', node)) {
+ leading = ' ';
+ }
+
+ if (!blankWithSpaces && hasTrailing && !isFlankedByWhitespace('right', node)) {
+ trailing = ' ';
+ }
}
+
+ return { leading: leading, trailing: trailing }
}
- return isFlanked
-}
-
-var reduce = Array.prototype.reduce;
-var leadingNewLinesRegExp = /^\n*/;
-var trailingNewLinesRegExp = /\n*$/;
-
-function TurndownService (options) {
- if (!(this instanceof TurndownService)) return new TurndownService(options)
-
- var defaults = {
- rules: rules,
- headingStyle: 'setext',
- hr: '* * *',
- bulletListMarker: '*',
- codeBlockStyle: 'indented',
- fence: '```',
- emDelimiter: '_',
- strongDelimiter: '**',
- linkStyle: 'inlined',
- linkReferenceStyle: 'full',
- br: ' ',
- blankReplacement: function (content, node) {
- return node.isBlock ? '\n\n' : ''
+
+ function isFlankedByWhitespace (side, node) {
+ var sibling;
+ var regExp;
+ var isFlanked;
+
+ if (side === 'left') {
+ sibling = node.previousSibling;
+ regExp = / $/;
+ } else {
+ sibling = node.nextSibling;
+ regExp = /^ /;
+ }
+
+ if (sibling) {
+ if (sibling.nodeType === 3) {
+ isFlanked = regExp.test(sibling.nodeValue);
+ } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
+ isFlanked = regExp.test(sibling.textContent);
+ }
+ }
+ return isFlanked
+ }
+
+ var reduce = Array.prototype.reduce;
+ var leadingNewLinesRegExp = /^\n*/;
+ var trailingNewLinesRegExp = /\n*$/;
+ var escapes = [
+ [/\\/g, '\\\\'],
+ [/\*/g, '\\*'],
+ [/^-/g, '\\-'],
+ [/^\+ /g, '\\+ '],
+ [/^(=+)/g, '\\$1'],
+ [/^(#{1,6}) /g, '\\$1 '],
+ [/`/g, '\\`'],
+ [/^~~~/g, '\\~~~'],
+ [/\[/g, '\\['],
+ [/\]/g, '\\]'],
+ [/^>/g, '\\>'],
+ [/_/g, '\\_'],
+ [/^(\d+)\. /g, '$1\\. ']
+ ];
+
+ function TurndownService (options) {
+ if (!(this instanceof TurndownService)) return new TurndownService(options)
+
+ var defaults = {
+ rules: rules,
+ headingStyle: 'setext',
+ hr: '* * *',
+ bulletListMarker: '*',
+ codeBlockStyle: 'indented',
+ fence: '```',
+ emDelimiter: '_',
+ strongDelimiter: '**',
+ linkStyle: 'inlined',
+ linkReferenceStyle: 'full',
+ br: ' ',
+ blankReplacement: function (content, node) {
+ return node.isBlock ? '\n\n' : ''
+ },
+ keepReplacement: function (content, node) {
+ return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
+ },
+ defaultReplacement: function (content, node) {
+ return node.isBlock ? '\n\n' + content + '\n\n' : content
+ }
+ };
+ this.options = extend({}, defaults, options);
+ this.rules = new Rules(this.options);
+ }
+
+ TurndownService.prototype = {
+ /**
+ * The entry point for converting a string or DOM node to Markdown
+ * @public
+ * @param {String|HTMLElement} input The string or DOM node to convert
+ * @returns A Markdown representation of the input
+ * @type String
+ */
+
+ turndown: function (input) {
+ if (!canConvert(input)) {
+ throw new TypeError(
+ input + ' is not a string, or an element/document/fragment node.'
+ )
+ }
+
+ if (input === '') return ''
+
+ var output = process.call(this, new RootNode(input));
+ return postProcess.call(this, output)
+ },
+
+ /**
+ * Add one or more plugins
+ * @public
+ * @param {Function|Array} plugin The plugin or array of plugins to add
+ * @returns The Turndown instance for chaining
+ * @type Object
+ */
+
+ use: function (plugin) {
+ if (Array.isArray(plugin)) {
+ for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
+ } else if (typeof plugin === 'function') {
+ plugin(this);
+ } else {
+ throw new TypeError('plugin must be a Function or an Array of Functions')
+ }
+ return this
+ },
+
+ /**
+ * Adds a rule
+ * @public
+ * @param {String} key The unique key of the rule
+ * @param {Object} rule The rule
+ * @returns The Turndown instance for chaining
+ * @type Object
+ */
+
+ addRule: function (key, rule) {
+ this.rules.add(key, rule);
+ return this
},
- keepReplacement: function (content, node) {
- return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
+
+ /**
+ * Keep a node (as HTML) that matches the filter
+ * @public
+ * @param {String|Array|Function} filter The unique key of the rule
+ * @returns The Turndown instance for chaining
+ * @type Object
+ */
+
+ keep: function (filter) {
+ this.rules.keep(filter);
+ return this
+ },
+
+ /**
+ * Remove a node that matches the filter
+ * @public
+ * @param {String|Array|Function} filter The unique key of the rule
+ * @returns The Turndown instance for chaining
+ * @type Object
+ */
+
+ remove: function (filter) {
+ this.rules.remove(filter);
+ return this
},
- defaultReplacement: function (content, node) {
- return node.isBlock ? '\n\n' + content + '\n\n' : content
+
+ /**
+ * Escapes Markdown syntax
+ * @public
+ * @param {String} string The string to escape
+ * @returns A string with Markdown syntax escaped
+ * @type String
+ */
+
+ escape: function (string) {
+ return escapes.reduce(function (accumulator, escape) {
+ return accumulator.replace(escape[0], escape[1])
+ }, string)
}
};
- this.options = extend({}, defaults, options);
- this.rules = new Rules(this.options);
-}
-TurndownService.prototype = {
/**
- * The entry point for converting a string or DOM node to Markdown
- * @public
- * @param {String|HTMLElement} input The string or DOM node to convert
- * @returns A Markdown representation of the input
+ * Reduces a DOM node down to its Markdown string equivalent
+ * @private
+ * @param {HTMLElement} parentNode The node to convert
+ * @returns A Markdown representation of the node
* @type String
*/
- turndown: function (input) {
- if (!canConvert(input)) {
- throw new TypeError(
- input + ' is not a string, or an element/document/fragment node.'
- )
- }
+ function process (parentNode) {
+ var self = this;
+ return reduce.call(parentNode.childNodes, function (output, node) {
+ node = new Node(node);
- if (input === '') return ''
+ var replacement = '';
+ if (node.nodeType === 3) {
+ replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
+ } else if (node.nodeType === 1) {
+ replacement = replacementForNode.call(self, node);
+ }
- var output = process.call(this, new RootNode(input));
- return postProcess.call(this, output)
- },
+ return join(output, replacement)
+ }, '')
+ }
/**
- * Add one or more plugins
- * @public
- * @param {Function|Array} plugin The plugin or array of plugins to add
- * @returns The Turndown instance for chaining
- * @type Object
+ * Appends strings as each rule requires and trims the output
+ * @private
+ * @param {String} output The conversion output
+ * @returns A trimmed version of the ouput
+ * @type String
*/
- use: function (plugin) {
- if (Array.isArray(plugin)) {
- for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
- } else if (typeof plugin === 'function') {
- plugin(this);
- } else {
- throw new TypeError('plugin must be a Function or an Array of Functions')
- }
- return this
- },
+ function postProcess (output) {
+ var self = this;
+ this.rules.forEach(function (rule) {
+ if (typeof rule.append === 'function') {
+ output = join(output, rule.append(self.options));
+ }
+ });
+
+ return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
+ }
/**
- * Adds a rule
- * @public
- * @param {String} key The unique key of the rule
- * @param {Object} rule The rule
- * @returns The Turndown instance for chaining
- * @type Object
+ * Converts an element node to its Markdown equivalent
+ * @private
+ * @param {HTMLElement} node The node to convert
+ * @returns A Markdown representation of the node
+ * @type String
*/
- addRule: function (key, rule) {
- this.rules.add(key, rule);
- return this
- },
+ function replacementForNode (node) {
+ var rule = this.rules.forNode(node);
+ var content = process.call(this, node);
+ var whitespace = node.flankingWhitespace;
+ if (whitespace.leading || whitespace.trailing) content = content.trim();
+ return (
+ whitespace.leading +
+ rule.replacement(content, node, this.options) +
+ whitespace.trailing
+ )
+ }
/**
- * Keep a node (as HTML) that matches the filter
- * @public
- * @param {String|Array|Function} filter The unique key of the rule
- * @returns The Turndown instance for chaining
- * @type Object
+ * Determines the new lines between the current output and the replacement
+ * @private
+ * @param {String} output The current conversion output
+ * @param {String} replacement The string to append to the output
+ * @returns The whitespace to separate the current output and the replacement
+ * @type String
*/
- keep: function (filter) {
- this.rules.keep(filter);
- return this
- },
+ function separatingNewlines (output, replacement) {
+ var newlines = [
+ output.match(trailingNewLinesRegExp)[0],
+ replacement.match(leadingNewLinesRegExp)[0]
+ ].sort();
+ var maxNewlines = newlines[newlines.length - 1];
+ return maxNewlines.length < 2 ? maxNewlines : '\n\n'
+ }
- /**
- * Remove a node that matches the filter
- * @public
- * @param {String|Array|Function} filter The unique key of the rule
- * @returns The Turndown instance for chaining
- * @type Object
- */
+ function join (string1, string2) {
+ var separator = separatingNewlines(string1, string2);
+
+ // Remove trailing/leading newlines and replace with separator
+ string1 = string1.replace(trailingNewLinesRegExp, '');
+ string2 = string2.replace(leadingNewLinesRegExp, '');
- remove: function (filter) {
- this.rules.remove(filter);
- return this
- },
+ return string1 + separator + string2
+ }
/**
- * Escapes Markdown syntax
- * @public
- * @param {String} string The string to escape
- * @returns A string with Markdown syntax escaped
- * @type String
+ * Determines whether an input can be converted
+ * @private
+ * @param {String|HTMLElement} input Describe this parameter
+ * @returns Describe what it returns
+ * @type String|Object|Array|Boolean|Number
*/
- escape: function (string) {
+ function canConvert (input) {
return (
- string
- // Escape backslash escapes!
- .replace(/\\(\S)/g, '\\\\$1')
-
- // Escape headings
- .replace(/^(#{1,6} )/gm, '\\$1')
-
- // Escape hr
- .replace(/^([-*_] *){3,}$/gm, function (match, character) {
- return match.split(character).join('\\' + character)
- })
-
- // Escape ol bullet points
- .replace(/^(\W* {0,3})(\d+)\. /gm, '$1$2\\. ')
-
- // Escape ul bullet points
- .replace(/^([^\\\w]*)[*+-] /gm, function (match) {
- return match.replace(/([*+-])/g, '\\$1')
- })
-
- // Escape blockquote indents
- .replace(/^(\W* {0,3})> /gm, '$1\\> ')
-
- // Escape em/strong *
- .replace(/\*+(?![*\s\W]).+?\*+/g, function (match) {
- return match.replace(/\*/g, '\\*')
- })
-
- // Escape em/strong _
- .replace(/_+(?![_\s\W]).+?_+/g, function (match) {
- return match.replace(/_/g, '\\_')
- })
-
- // Escape code _
- .replace(/`+(?![`\s\W]).+?`+/g, function (match) {
- return match.replace(/`/g, '\\`')
- })
-
- // Escape link brackets
- .replace(/[\[\]]/g, '\\$&') // eslint-disable-line no-useless-escape
+ input != null && (
+ typeof input === 'string' ||
+ (input.nodeType && (
+ input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
+ ))
+ )
)
}
-};
-
-/**
- * Reduces a DOM node down to its Markdown string equivalent
- * @private
- * @param {HTMLElement} parentNode The node to convert
- * @returns A Markdown representation of the node
- * @type String
- */
-
-function process (parentNode) {
- var self = this;
- return reduce.call(parentNode.childNodes, function (output, node) {
- node = new Node(node);
-
- var replacement = '';
- if (node.nodeType === 3) {
- replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
- } else if (node.nodeType === 1) {
- replacement = replacementForNode.call(self, node);
- }
-
- return join(output, replacement)
- }, '')
-}
-
-/**
- * Appends strings as each rule requires and trims the output
- * @private
- * @param {String} output The conversion output
- * @returns A trimmed version of the ouput
- * @type String
- */
-
-function postProcess (output) {
- var self = this;
- this.rules.forEach(function (rule) {
- if (typeof rule.append === 'function') {
- output = join(output, rule.append(self.options));
- }
- });
-
- return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
-}
-
-/**
- * Converts an element node to its Markdown equivalent
- * @private
- * @param {HTMLElement} node The node to convert
- * @returns A Markdown representation of the node
- * @type String
- */
-
-function replacementForNode (node) {
- var rule = this.rules.forNode(node);
- var content = process.call(this, node);
- var whitespace = node.flankingWhitespace;
- if (whitespace.leading || whitespace.trailing) content = content.trim();
- return (
- whitespace.leading +
- rule.replacement(content, node, this.options) +
- whitespace.trailing
- )
-}
-
-/**
- * Determines the new lines between the current output and the replacement
- * @private
- * @param {String} output The current conversion output
- * @param {String} replacement The string to append to the output
- * @returns The whitespace to separate the current output and the replacement
- * @type String
- */
-
-function separatingNewlines (output, replacement) {
- var newlines = [
- output.match(trailingNewLinesRegExp)[0],
- replacement.match(leadingNewLinesRegExp)[0]
- ].sort();
- var maxNewlines = newlines[newlines.length - 1];
- return maxNewlines.length < 2 ? maxNewlines : '\n\n'
-}
-
-function join (string1, string2) {
- var separator = separatingNewlines(string1, string2);
-
- // Remove trailing/leading newlines and replace with separator
- string1 = string1.replace(trailingNewLinesRegExp, '');
- string2 = string2.replace(leadingNewLinesRegExp, '');
-
- return string1 + separator + string2
-}
-
-/**
- * Determines whether an input can be converted
- * @private
- * @param {String|HTMLElement} input Describe this parameter
- * @returns Describe what it returns
- * @type String|Object|Array|Boolean|Number
- */
-
-function canConvert (input) {
- return (
- input != null && (
- typeof input === 'string' ||
- (input.nodeType && (
- input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
- ))
- )
- )
-}
-return TurndownService;
+ return TurndownService;
}());
diff --git a/js/turndown/turndown.min.js b/js/turndown/turndown.min.js
index 8ea7878..2762d75 100644
--- a/js/turndown/turndown.min.js
+++ b/js/turndown/turndown.min.js
@@ -1 +1 @@
-var TurndownService=function(){"use strict";function extend(destination){for(var i=1;i-1)return!0}else{if("function"!=typeof filter)throw new TypeError("`filter` needs to be a string, array, or function");if(filter.call(rule,node,options))return!0}}function collapseWhitespace(options){var element=options.element,isBlock=options.isBlock,isVoid=options.isVoid,isPre=options.isPre||function(node){return"PRE"===node.nodeName};if(element.firstChild&&!isPre(element)){for(var prevText=null,prevVoid=!1,prev=null,node=next(prev,element,isPre);node!==element;){if(3===node.nodeType||4===node.nodeType){var text=node.data.replace(/[ \r\n\t]+/g," ");if(prevText&&!/ $/.test(prevText.data)||prevVoid||" "!==text[0]||(text=text.substr(1)),!text){node=remove(node);continue}node.data=text,prevText=node}else{if(1!==node.nodeType){node=remove(node);continue}isBlock(node)||"BR"===node.nodeName?(prevText&&(prevText.data=prevText.data.replace(/ $/,"")),prevText=null,prevVoid=!1):isVoid(node)&&(prevText=null,prevVoid=!0)}var nextNode=next(prev,node,isPre);prev=node,node=nextNode}prevText&&(prevText.data=prevText.data.replace(/ $/,""),prevText.data||remove(prevText))}}function remove(node){var next=node.nextSibling||node.parentNode;return node.parentNode.removeChild(node),next}function next(prev,current,isPre){return prev&&prev.parentNode===current||isPre(current)?current.nextSibling||current.parentNode:current.firstChild||current.nextSibling||current.parentNode}rules.paragraph={filter:"p",replacement:function(content){return"\n\n"+content+"\n\n"}},rules.lineBreak={filter:"br",replacement:function(content,node,options){return options.br+"\n"}},rules.heading={filter:["h1","h2","h3","h4","h5","h6"],replacement:function(content,node,options){var hLevel=Number(node.nodeName.charAt(1)),underline;return"setext"===options.headingStyle&&hLevel<3?"\n\n"+content+"\n"+repeat(1===hLevel?"=":"-",content.length)+"\n\n":"\n\n"+repeat("#",hLevel)+" "+content+"\n\n"}},rules.blockquote={filter:"blockquote",replacement:function(content){return"\n\n"+(content=(content=content.replace(/^\n+|\n+$/g,"")).replace(/^/gm,"> "))+"\n\n"}},rules.list={filter:["ul","ol"],replacement:function(content,node){var parent=node.parentNode;return"LI"===parent.nodeName&&parent.lastElementChild===node?"\n"+content:"\n\n"+content+"\n\n"}},rules.listItem={filter:"li",replacement:function(content,node,options){content=content.replace(/^\n+/,"").replace(/\n+$/,"\n").replace(/\n/gm,"\n ");var prefix=options.bulletListMarker+" ",parent=node.parentNode;if("OL"===parent.nodeName){var start=parent.getAttribute("start"),index=Array.prototype.indexOf.call(parent.children,node);prefix=(start?Number(start)+index:index+1)+". "}return prefix+content+(node.nextSibling&&!/\n$/.test(content)?"\n":"")}},rules.indentedCodeBlock={filter:function(node,options){return"indented"===options.codeBlockStyle&&"PRE"===node.nodeName&&node.firstChild&&"CODE"===node.firstChild.nodeName},replacement:function(content,node,options){return"\n\n "+node.firstChild.textContent.replace(/\n/g,"\n ")+"\n\n"}},rules.fencedCodeBlock={filter:function(node,options){return"fenced"===options.codeBlockStyle&&"PRE"===node.nodeName&&node.firstChild&&"CODE"===node.firstChild.nodeName},replacement:function(content,node,options){var className,language=((node.firstChild.className||"").match(/language-(\S+)/)||[null,""])[1];return"\n\n"+options.fence+language+"\n"+node.firstChild.textContent+"\n"+options.fence+"\n\n"}},rules.horizontalRule={filter:"hr",replacement:function(content,node,options){return"\n\n"+options.hr+"\n\n"}},rules.inlineLink={filter:function(node,options){return"inlined"===options.linkStyle&&"A"===node.nodeName&&node.getAttribute("href")},replacement:function(content,node){var href,title;return"["+content+"]("+node.getAttribute("href")+(node.title?' "'+node.title+'"':"")+")"}},rules.referenceLink={filter:function(node,options){return"referenced"===options.linkStyle&&"A"===node.nodeName&&node.getAttribute("href")},replacement:function(content,node,options){var href=node.getAttribute("href"),title=node.title?' "'+node.title+'"':"",replacement,reference;switch(options.linkReferenceStyle){case"collapsed":replacement="["+content+"][]",reference="["+content+"]: "+href+title;break;case"shortcut":replacement="["+content+"]",reference="["+content+"]: "+href+title;break;default:var id=this.references.length+1;replacement="["+content+"]["+id+"]",reference="["+id+"]: "+href+title}return this.references.push(reference),replacement},references:[],append:function(options){var references="";return this.references.length&&(references="\n\n"+this.references.join("\n")+"\n\n",this.references=[]),references}},rules.emphasis={filter:["em","i"],replacement:function(content,node,options){return content.trim()?options.emDelimiter+content+options.emDelimiter:""}},rules.strong={filter:["strong","b"],replacement:function(content,node,options){return content.trim()?options.strongDelimiter+content+options.strongDelimiter:""}},rules.code={filter:function(node){var hasSiblings=node.previousSibling||node.nextSibling,isCodeBlock="PRE"===node.parentNode.nodeName&&!hasSiblings;return"CODE"===node.nodeName&&!isCodeBlock},replacement:function(content){if(!content.trim())return"";var delimiter="`",leadingSpace="",trailingSpace="",matches=content.match(/`+/gm);if(matches)for(/^`/.test(content)&&(leadingSpace=" "),/`$/.test(content)&&(trailingSpace=" ");-1!==matches.indexOf(delimiter);)delimiter+="`";return delimiter+leadingSpace+content+trailingSpace+delimiter}},rules.image={filter:"img",replacement:function(content,node){var alt=node.alt||"",src=node.getAttribute("src")||"",title=node.title||"",titlePart;return src?"!["+alt+"]("+src+(title?' "'+title+'"':"")+")":""}},Rules.prototype={add:function(key,rule){this.array.unshift(rule)},keep:function(filter){this._keep.unshift({filter:filter,replacement:this.keepReplacement})},remove:function(filter){this._remove.unshift({filter:filter,replacement:function(){return""}})},forNode:function(node){return node.isBlank?this.blankRule:(rule=findRule(this.array,node,this.options))?rule:(rule=findRule(this._keep,node,this.options))?rule:(rule=findRule(this._remove,node,this.options))?rule:this.defaultRule;var rule},forEach:function(fn){for(var i=0;i'+input+"","text/html").getElementById("turndown-root"):root=input.cloneNode(!0);return collapseWhitespace({element:root,isBlock:isBlock,isVoid:isVoid}),root}function htmlParser(){return _htmlParser=_htmlParser||new HTMLParser}function Node(node){return node.isBlock=isBlock(node),node.isCode="code"===node.nodeName.toLowerCase()||node.parentNode.isCode,node.isBlank=isBlank(node),node.flankingWhitespace=flankingWhitespace(node),node}function isBlank(node){return-1===["A","TH","TD"].indexOf(node.nodeName)&&/^\s*$/i.test(node.textContent)&&!isVoid(node)&&!hasVoid(node)}function flankingWhitespace(node){var leading="",trailing="";if(!node.isBlock){var hasLeading=/^[ \r\n\t]/.test(node.textContent),hasTrailing=/[ \r\n\t]$/.test(node.textContent);hasLeading&&!isFlankedByWhitespace("left",node)&&(leading=" "),hasTrailing&&!isFlankedByWhitespace("right",node)&&(trailing=" ")}return{leading:leading,trailing:trailing}}function isFlankedByWhitespace(side,node){var sibling,regExp,isFlanked;return"left"===side?(sibling=node.previousSibling,regExp=/ $/):(sibling=node.nextSibling,regExp=/^ /),sibling&&(3===sibling.nodeType?isFlanked=regExp.test(sibling.nodeValue):1!==sibling.nodeType||isBlock(sibling)||(isFlanked=regExp.test(sibling.textContent))),isFlanked}var reduce=Array.prototype.reduce,leadingNewLinesRegExp=/^\n*/,trailingNewLinesRegExp=/\n*$/;function TurndownService(options){if(!(this instanceof TurndownService))return new TurndownService(options);var defaults={rules:rules,headingStyle:"setext",hr:"* * *",bulletListMarker:"*",codeBlockStyle:"indented",fence:"```",emDelimiter:"_",strongDelimiter:"**",linkStyle:"inlined",linkReferenceStyle:"full",br:" ",blankReplacement:function(content,node){return node.isBlock?"\n\n":""},keepReplacement:function(content,node){return node.isBlock?"\n\n"+node.outerHTML+"\n\n":node.outerHTML},defaultReplacement:function(content,node){return node.isBlock?"\n\n"+content+"\n\n":content}};this.options=extend({},defaults,options),this.rules=new Rules(this.options)}function process(parentNode){var self=this;return reduce.call(parentNode.childNodes,(function(output,node){var replacement="";return 3===(node=new Node(node)).nodeType?replacement=node.isCode?node.nodeValue:self.escape(node.nodeValue):1===node.nodeType&&(replacement=replacementForNode.call(self,node)),join(output,replacement)}),"")}function postProcess(output){var self=this;return this.rules.forEach((function(rule){"function"==typeof rule.append&&(output=join(output,rule.append(self.options)))})),output.replace(/^[\t\r\n]+/,"").replace(/[\t\r\n\s]+$/,"")}function replacementForNode(node){var rule=this.rules.forNode(node),content=process.call(this,node),whitespace=node.flankingWhitespace;return(whitespace.leading||whitespace.trailing)&&(content=content.trim()),whitespace.leading+rule.replacement(content,node,this.options)+whitespace.trailing}function separatingNewlines(output,replacement){var newlines=[output.match(trailingNewLinesRegExp)[0],replacement.match(leadingNewLinesRegExp)[0]].sort(),maxNewlines=newlines[newlines.length-1];return maxNewlines.length<2?maxNewlines:"\n\n"}function join(string1,string2){var separator=separatingNewlines(string1,string2);return(string1=string1.replace(trailingNewLinesRegExp,""))+separator+(string2=string2.replace(leadingNewLinesRegExp,""))}function canConvert(input){return null!=input&&("string"==typeof input||input.nodeType&&(1===input.nodeType||9===input.nodeType||11===input.nodeType))}return TurndownService.prototype={turndown:function(input){if(!canConvert(input))throw new TypeError(input+" is not a string, or an element/document/fragment node.");if(""===input)return"";var output=process.call(this,new RootNode(input));return postProcess.call(this,output)},use:function(plugin){if(Array.isArray(plugin))for(var i=0;i /gm,"$1\\> ").replace(/\*+(?![*\s\W]).+?\*+/g,(function(match){return match.replace(/\*/g,"\\*")})).replace(/_+(?![_\s\W]).+?_+/g,(function(match){return match.replace(/_/g,"\\_")})).replace(/`+(?![`\s\W]).+?`+/g,(function(match){return match.replace(/`/g,"\\`")})).replace(/[\[\]]/g,"\\$&")}},TurndownService}();
\ No newline at end of file
+var TurndownService=function(){"use strict";function extend(destination){for(var i=1;i=0}function has(node,tagNames){return node.getElementsByTagName&&tagNames.some((function(tagName){return node.getElementsByTagName(tagName).length}))}var rules={};function cleanAttribute(attribute){return attribute?attribute.replace(/(\n+\s*)+/g,"\n"):""}function Rules(options){for(var key in this.options=options,this._keep=[],this._remove=[],this.blankRule={replacement:options.blankReplacement},this.keepReplacement=options.keepReplacement,this.defaultRule={replacement:options.defaultReplacement},this.array=[],options.rules)this.array.push(options.rules[key])}function findRule(rules,node,options){for(var i=0;i-1)return!0}else{if("function"!=typeof filter)throw new TypeError("`filter` needs to be a string, array, or function");if(filter.call(rule,node,options))return!0}}function collapseWhitespace(options){var element=options.element,isBlock=options.isBlock,isVoid=options.isVoid,isPre=options.isPre||function(node){return"PRE"===node.nodeName};if(element.firstChild&&!isPre(element)){for(var prevText=null,prevVoid=!1,prev=null,node=next(prev,element,isPre);node!==element;){if(3===node.nodeType||4===node.nodeType){var text=node.data.replace(/[ \r\n\t]+/g," ");if(prevText&&!/ $/.test(prevText.data)||prevVoid||" "!==text[0]||(text=text.substr(1)),!text){node=remove(node);continue}node.data=text,prevText=node}else{if(1!==node.nodeType){node=remove(node);continue}isBlock(node)||"BR"===node.nodeName?(prevText&&(prevText.data=prevText.data.replace(/ $/,"")),prevText=null,prevVoid=!1):isVoid(node)&&(prevText=null,prevVoid=!0)}var nextNode=next(prev,node,isPre);prev=node,node=nextNode}prevText&&(prevText.data=prevText.data.replace(/ $/,""),prevText.data||remove(prevText))}}function remove(node){var next=node.nextSibling||node.parentNode;return node.parentNode.removeChild(node),next}function next(prev,current,isPre){return prev&&prev.parentNode===current||isPre(current)?current.nextSibling||current.parentNode:current.firstChild||current.nextSibling||current.parentNode}rules.paragraph={filter:"p",replacement:function(content){return"\n\n"+content+"\n\n"}},rules.lineBreak={filter:"br",replacement:function(content,node,options){return options.br+"\n"}},rules.heading={filter:["h1","h2","h3","h4","h5","h6"],replacement:function(content,node,options){var hLevel=Number(node.nodeName.charAt(1)),underline;return"setext"===options.headingStyle&&hLevel<3?"\n\n"+content+"\n"+repeat(1===hLevel?"=":"-",content.length)+"\n\n":"\n\n"+repeat("#",hLevel)+" "+content+"\n\n"}},rules.blockquote={filter:"blockquote",replacement:function(content){return"\n\n"+(content=(content=content.replace(/^\n+|\n+$/g,"")).replace(/^/gm,"> "))+"\n\n"}},rules.list={filter:["ul","ol"],replacement:function(content,node){var parent=node.parentNode;return"LI"===parent.nodeName&&parent.lastElementChild===node?"\n"+content:"\n\n"+content+"\n\n"}},rules.listItem={filter:"li",replacement:function(content,node,options){content=content.replace(/^\n+/,"").replace(/\n+$/,"\n").replace(/\n/gm,"\n ");var prefix=options.bulletListMarker+" ",parent=node.parentNode;if("OL"===parent.nodeName){var start=parent.getAttribute("start"),index=Array.prototype.indexOf.call(parent.children,node);prefix=(start?Number(start)+index:index+1)+". "}return prefix+content+(node.nextSibling&&!/\n$/.test(content)?"\n":"")}},rules.indentedCodeBlock={filter:function(node,options){return"indented"===options.codeBlockStyle&&"PRE"===node.nodeName&&node.firstChild&&"CODE"===node.firstChild.nodeName},replacement:function(content,node,options){return"\n\n "+node.firstChild.textContent.replace(/\n/g,"\n ")+"\n\n"}},rules.fencedCodeBlock={filter:function(node,options){return"fenced"===options.codeBlockStyle&&"PRE"===node.nodeName&&node.firstChild&&"CODE"===node.firstChild.nodeName},replacement:function(content,node,options){for(var className,language=((node.firstChild.getAttribute("class")||"").match(/language-(\S+)/)||[null,""])[1],code=node.firstChild.textContent,fenceChar=options.fence.charAt(0),fenceSize=3,fenceInCodeRegex=new RegExp("^"+fenceChar+"{3,}","gm"),match;match=fenceInCodeRegex.exec(code);)match[0].length>=fenceSize&&(fenceSize=match[0].length+1);var fence=repeat(fenceChar,fenceSize);return"\n\n"+fence+language+"\n"+code.replace(/\n$/,"")+"\n"+fence+"\n\n"}},rules.horizontalRule={filter:"hr",replacement:function(content,node,options){return"\n\n"+options.hr+"\n\n"}},rules.inlineLink={filter:function(node,options){return"inlined"===options.linkStyle&&"A"===node.nodeName&&node.getAttribute("href")},replacement:function(content,node){var href=node.getAttribute("href"),title=cleanAttribute(node.getAttribute("title"));return title&&(title=' "'+title+'"'),"["+content+"]("+href+title+")"}},rules.referenceLink={filter:function(node,options){return"referenced"===options.linkStyle&&"A"===node.nodeName&&node.getAttribute("href")},replacement:function(content,node,options){var href=node.getAttribute("href"),title=cleanAttribute(node.getAttribute("title")),replacement,reference;switch(title&&(title=' "'+title+'"'),options.linkReferenceStyle){case"collapsed":replacement="["+content+"][]",reference="["+content+"]: "+href+title;break;case"shortcut":replacement="["+content+"]",reference="["+content+"]: "+href+title;break;default:var id=this.references.length+1;replacement="["+content+"]["+id+"]",reference="["+id+"]: "+href+title}return this.references.push(reference),replacement},references:[],append:function(options){var references="";return this.references.length&&(references="\n\n"+this.references.join("\n")+"\n\n",this.references=[]),references}},rules.emphasis={filter:["em","i"],replacement:function(content,node,options){return content.trim()?options.emDelimiter+content+options.emDelimiter:""}},rules.strong={filter:["strong","b"],replacement:function(content,node,options){return content.trim()?options.strongDelimiter+content+options.strongDelimiter:""}},rules.code={filter:function(node){var hasSiblings=node.previousSibling||node.nextSibling,isCodeBlock="PRE"===node.parentNode.nodeName&&!hasSiblings;return"CODE"===node.nodeName&&!isCodeBlock},replacement:function(content){if(!content.trim())return"";var delimiter="`",leadingSpace="",trailingSpace="",matches=content.match(/`+/gm);if(matches)for(/^`/.test(content)&&(leadingSpace=" "),/`$/.test(content)&&(trailingSpace=" ");-1!==matches.indexOf(delimiter);)delimiter+="`";return delimiter+leadingSpace+content+trailingSpace+delimiter}},rules.image={filter:"img",replacement:function(content,node){var alt=cleanAttribute(node.getAttribute("alt")),src=node.getAttribute("src")||"",title=cleanAttribute(node.getAttribute("title")),titlePart;return src?"!["+alt+"]("+src+(title?' "'+title+'"':"")+")":""}},Rules.prototype={add:function(key,rule){this.array.unshift(rule)},keep:function(filter){this._keep.unshift({filter:filter,replacement:this.keepReplacement})},remove:function(filter){this._remove.unshift({filter:filter,replacement:function(){return""}})},forNode:function(node){return node.isBlank?this.blankRule:(rule=findRule(this.array,node,this.options))?rule:(rule=findRule(this._keep,node,this.options))?rule:(rule=findRule(this._remove,node,this.options))?rule:this.defaultRule;var rule},forEach:function(fn){for(var i=0;i'+input+"","text/html").getElementById("turndown-root"):root=input.cloneNode(!0);return collapseWhitespace({element:root,isBlock:isBlock,isVoid:isVoid}),root}function htmlParser(){return _htmlParser=_htmlParser||new HTMLParser}function Node(node){return node.isBlock=isBlock(node),node.isCode="code"===node.nodeName.toLowerCase()||node.parentNode.isCode,node.isBlank=isBlank(node),node.flankingWhitespace=flankingWhitespace(node),node}function isBlank(node){return!isVoid(node)&&!isMeaningfulWhenBlank(node)&&/^\s*$/i.test(node.textContent)&&!hasVoid(node)&&!hasMeaningfulWhenBlank(node)}function flankingWhitespace(node){var leading="",trailing="";if(!node.isBlock){var hasLeading=/^\s/.test(node.textContent),hasTrailing=/\s$/.test(node.textContent),blankWithSpaces=node.isBlank&&hasLeading&&hasTrailing;hasLeading&&!isFlankedByWhitespace("left",node)&&(leading=" "),blankWithSpaces||!hasTrailing||isFlankedByWhitespace("right",node)||(trailing=" ")}return{leading:leading,trailing:trailing}}function isFlankedByWhitespace(side,node){var sibling,regExp,isFlanked;return"left"===side?(sibling=node.previousSibling,regExp=/ $/):(sibling=node.nextSibling,regExp=/^ /),sibling&&(3===sibling.nodeType?isFlanked=regExp.test(sibling.nodeValue):1!==sibling.nodeType||isBlock(sibling)||(isFlanked=regExp.test(sibling.textContent))),isFlanked}var reduce=Array.prototype.reduce,leadingNewLinesRegExp=/^\n*/,trailingNewLinesRegExp=/\n*$/,escapes=[[/\\/g,"\\\\"],[/\*/g,"\\*"],[/^-/g,"\\-"],[/^\+ /g,"\\+ "],[/^(=+)/g,"\\$1"],[/^(#{1,6}) /g,"\\$1 "],[/`/g,"\\`"],[/^~~~/g,"\\~~~"],[/\[/g,"\\["],[/\]/g,"\\]"],[/^>/g,"\\>"],[/_/g,"\\_"],[/^(\d+)\. /g,"$1\\. "]];function TurndownService(options){if(!(this instanceof TurndownService))return new TurndownService(options);var defaults={rules:rules,headingStyle:"setext",hr:"* * *",bulletListMarker:"*",codeBlockStyle:"indented",fence:"```",emDelimiter:"_",strongDelimiter:"**",linkStyle:"inlined",linkReferenceStyle:"full",br:" ",blankReplacement:function(content,node){return node.isBlock?"\n\n":""},keepReplacement:function(content,node){return node.isBlock?"\n\n"+node.outerHTML+"\n\n":node.outerHTML},defaultReplacement:function(content,node){return node.isBlock?"\n\n"+content+"\n\n":content}};this.options=extend({},defaults,options),this.rules=new Rules(this.options)}function process(parentNode){var self=this;return reduce.call(parentNode.childNodes,(function(output,node){var replacement="";return 3===(node=new Node(node)).nodeType?replacement=node.isCode?node.nodeValue:self.escape(node.nodeValue):1===node.nodeType&&(replacement=replacementForNode.call(self,node)),join(output,replacement)}),"")}function postProcess(output){var self=this;return this.rules.forEach((function(rule){"function"==typeof rule.append&&(output=join(output,rule.append(self.options)))})),output.replace(/^[\t\r\n]+/,"").replace(/[\t\r\n\s]+$/,"")}function replacementForNode(node){var rule=this.rules.forNode(node),content=process.call(this,node),whitespace=node.flankingWhitespace;return(whitespace.leading||whitespace.trailing)&&(content=content.trim()),whitespace.leading+rule.replacement(content,node,this.options)+whitespace.trailing}function separatingNewlines(output,replacement){var newlines=[output.match(trailingNewLinesRegExp)[0],replacement.match(leadingNewLinesRegExp)[0]].sort(),maxNewlines=newlines[newlines.length-1];return maxNewlines.length<2?maxNewlines:"\n\n"}function join(string1,string2){var separator=separatingNewlines(string1,string2);return(string1=string1.replace(trailingNewLinesRegExp,""))+separator+(string2=string2.replace(leadingNewLinesRegExp,""))}function canConvert(input){return null!=input&&("string"==typeof input||input.nodeType&&(1===input.nodeType||9===input.nodeType||11===input.nodeType))}return TurndownService.prototype={turndown:function(input){if(!canConvert(input))throw new TypeError(input+" is not a string, or an element/document/fragment node.");if(""===input)return"";var output=process.call(this,new RootNode(input));return postProcess.call(this,output)},use:function(plugin){if(Array.isArray(plugin))for(var i=0;iconfig->get('notes_basepath', false).$rcmail->user->get_username().$rcmail->config->get('notes_folder', false);
- if(file_exists($notes_path.$old_name && $old_name != '')) {
+
+ if(file_exists($notes_path.$old_name) && $old_name != '') {
if($old_name != $new_name) if(!rename($notes_path.$old_name, $notes_path.$new_name)) die('Could not rename file.');
} elseif ($old_name != "") {
error_log('PrimitiveNotes: Note not found, can\`t save note.');
@@ -401,6 +402,7 @@ function human_filesize($bytes, $decimals = 2) {
+
@@ -420,7 +422,7 @@ function human_filesize($bytes, $decimals = 2) {
-
+