2017-10-03 14:51:29 +00:00
import QtQml 2.0
import QOwnNotesTypes 1.0
/ * *
* This script handles tagging in a note for tags in the note text like:
* @ tag1 @ tag2 @ tag3
2017-10-04 18:55:16 +00:00
* @ tag_one would tag the note with "tag one" tag .
2017-10-03 14:51:29 +00:00
* /
2017-10-18 18:49:51 +00:00
2017-10-03 14:51:29 +00:00
Script {
2017-10-04 18:55:16 +00:00
property string tagMarker
2018-11-28 14:20:35 +00:00
property bool ignoreDoubleMarkers
2017-10-18 18:49:51 +00:00
property bool putToBeginning
property string tagHighlightColor
2017-10-04 18:55:16 +00:00
property variant settingsVariables: [
{
"identifier" : "tagMarker" ,
"name" : "Tag word marker" ,
2017-10-04 19:23:10 +00:00
"description" : "A word that starts with this characters is recognized as tag" ,
2017-10-04 18:55:16 +00:00
"type" : "string" ,
"default" : "@" ,
2017-10-18 18:49:51 +00:00
} ,
2018-11-28 14:20:35 +00:00
{
"identifier" : "ignoreDoubleMarkers" ,
"name" : "Ignore repeated tag markers" ,
"description" : "If enabled tags preceded by the same marker multiple times (such as @@no_tag) will be ignored." ,
"type" : "boolean" ,
"default" : "false" ,
} ,
2017-10-18 18:49:51 +00:00
{
"identifier" : "putToBeginning" ,
"name" : "Put tags to beginning of note rather than to end" ,
"description" : "If enabled tags, added by UI, will be put to the first line of note or right after top headline" ,
"type" : "boolean" ,
"default" : "false" ,
} ,
{
"identifier" : "tagHighlightColor" ,
"name" : "The color for tag highlighting in note preview" ,
"description" : "Put a <a href=\"https://www.w3.org/TR/SVG/types.html#ColorKeywords\">color name</a> or a <a href=\"http://doc.qt.io/qt-5/qcolor.html#setNamedColor\">supported</a> color code here. Leave empty to disable tag highlighting in preview." ,
"type" : "string" ,
"default" : "purple" ,
} ,
2017-10-04 18:55:16 +00:00
]
2017-10-03 14:51:29 +00:00
/ * *
* Handles note tagging for a note
*
* This function is called when tags are added to , removed from or renamed in
* a note or the tags of a note should be listed
*
* @ param note
* @ param action can be "add" , "remove" , "rename" or "list"
* @ param tagName tag name to be added , removed or renamed
* @ param newTagName tag name to be renamed to if action = "rename"
* @ return string or string - list ( if action = "list" )
* /
function noteTaggingHook ( note , action , tagName , newTagName ) {
var noteText = note . noteText ;
2017-10-18 18:49:51 +00:00
var tagRegExp = RegExp ( "\\B%1(?=($|\\s|\\b)) ?" . arg ( escapeRegExp ( tagMarker + tagName ) . replace ( / /g , "_" ) ) ) ;
2017-10-03 14:51:29 +00:00
switch ( action ) {
// adds the tag "tagName" to the note
// the new note text has to be returned so that the note can be updated
// returning an empty string indicates that nothing has to be changed
case "add" :
// check if tag already exists
if ( noteText . search ( tagRegExp ) > 0 ) {
return "" ;
}
2017-10-18 18:49:51 +00:00
const tag = tagMarker + tagName . replace ( / /g , "_" ) ;
// add the tag to the beginning or to the end of the note
if ( putToBeginning ) {
// make an array of up to 3 first lines and other text as last item
var textLines = [ ] ;
for ( var lineCount = 0 , lineStart = 0 , lineEnd = 0 ; lineCount != 3 ; lineCount ++ ) {
lineEnd = noteText . indexOf ( "\n" , lineStart + 1 ) ;
2017-10-03 14:51:29 +00:00
2017-10-18 18:49:51 +00:00
if ( lineEnd == - 1 )
continue ;
textLines . push ( noteText . substring ( lineStart , lineEnd ) ) ;
lineStart = lineEnd ;
}
textLines . push ( noteText . substring ( lineStart ) ) ;
// if line after headline is a line for tags add tag there,
// or make a new line for tags after headline
function appendTag ( text , tag , prepend ) {
if ( text . substring ( 0 , tagMarker . length ) == tagMarker ||
text . substring ( 1 , tagMarker . length + 1 ) == tagMarker )
return text + " " + tag ;
else
return prepend + tag + "\n" + text ;
}
// use different tag line number depending on a headline type
if ( textLines [ 0 ] . substring ( 0 , 1 ) == "#" )
textLines [ 1 ] = appendTag ( textLines [ 1 ] , tag , "\n" ) ;
else if ( textLines [ 1 ] . search ( /=+/ ) != - 1 )
textLines [ 2 ] = appendTag ( textLines [ 2 ] , tag , "\n" ) ;
else
textLines [ 0 ] = appendTag ( textLines [ 0 ] , tag , "" ) ;
noteText = textLines . join ( "" ) ;
}
else
noteText += "\n" + tag ;
2017-10-03 14:51:29 +00:00
return noteText ;
// removes the tag "tagName" from the note
// the new note text has to be returned so that the note can be updated
// returning an empty string indicates that nothing has to be changed
case "remove" :
2017-10-18 18:49:51 +00:00
return noteText . replace ( tagRegExp , "" ) ;
2017-10-03 14:51:29 +00:00
// renames the tag "tagName" in the note to "newTagName"
// the new note text has to be returned so that the note can be updated
// returning an empty string indicates that nothing has to be changed
case "rename" :
2017-10-18 18:49:51 +00:00
return noteText . replace ( tagRegExp , tagMarker + newTagName . replace ( / /g , "_" ) ) ;
2017-10-03 14:51:29 +00:00
// returns a list of all tag names of the note
case "list" :
2017-10-04 18:55:16 +00:00
var re = new RegExp ( "\\B%1([^\\s,;]+)" . arg ( escapeRegExp ( tagMarker ) ) , "gi" ) ,
2017-10-03 14:51:29 +00:00
result , tagNameList = [ ] ;
while ( ( result = re . exec ( noteText ) ) !== null ) {
2017-10-18 18:49:51 +00:00
tagName = result [ 1 ] . replace ( /_/g , " " ) ;
2017-10-03 14:51:29 +00:00
// add the tag if it wasn't in the list
if ( tagNameList . indexOf ( tagName ) == - 1 ) {
2018-11-28 14:20:35 +00:00
// add the tag if it contains no duplicate tagMarkers or the check is disabled
if ( ignoreDoubleMarkers == false || tagName . startsWith ( escapeRegExp ( tagMarker ) ) == false ) {
tagNameList . push ( tagName ) ;
}
2017-10-03 14:51:29 +00:00
}
}
return tagNameList ;
}
return "" ;
}
2017-10-18 18:49:51 +00:00
// Removes tag marker in note preview and highlights tag name with set color
function noteToMarkdownHtmlHook ( note , html ) {
if ( tagHighlightColor == "" )
return ;
var re = new RegExp ( "\\B%1([^\\s,;]+)" . arg ( escapeRegExp ( tagMarker ) ) , "gi" ) , result ;
while ( ( result = re . exec ( html ) ) !== null )
html = html . replace ( result [ 0 ] , '<b><font color="%1">%2</font></b>' . arg ( tagHighlightColor ) . arg ( result [ 1 ] ) ) ;
return html ;
}
// Escapes a string for regular expressions
2017-10-03 14:51:29 +00:00
function escapeRegExp ( str ) {
return str . replace ( /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g , "\\$&" ) ;
}
2018-02-03 11:52:17 +00:00
/ * *
* Hook to feed the autocompletion with tags if the current word starts with the tag marker
* /
function autocompletionHook ( ) {
// get the current word plus non-word-characters before the word to also get the tag marker
var word = script . noteTextEditCurrentWord ( true ) ;
if ( ! word . startsWith ( tagMarker ) ) {
return [ ] ;
}
2018-02-05 19:04:29 +00:00
2018-02-03 11:52:17 +00:00
// cut the tag marker off of the string and do a substring search for tags
var tags = script . searchTagsByName ( word . substr ( tagMarker . length ) ) ;
2018-02-05 19:04:29 +00:00
// convert tag names with spaces to in-text tags with "_", "tag one" to @tag_one
for ( var i = 0 ; i < tags . length ; i ++ ) {
2018-02-06 16:46:08 +00:00
tags [ i ] = tags [ i ] . replace ( / /g , "_" ) ;
2018-02-05 19:04:29 +00:00
}
2018-02-03 11:52:17 +00:00
return tags ;
}
2017-10-03 14:51:29 +00:00
}