2015-09-03 23:12:46 +02:00
Template . editor . onRendered ( ( ) => {
2019-07-22 13:53:37 -04:00
const textareaSelector = 'textarea' ;
const mentions = [
Renaissance
_,,ad8888888888bba,_
,ad88888I888888888888888ba,
,88888888I88888888888888888888a,
,d888888888I8888888888888888888888b,
d88888PP"""" ""YY88888888888888888888b,
,d88"'__,,--------,,,,.;ZZZY8888888888888,
,8IIl'" ;;l"ZZZIII8888888888,
,I88l;' ;lZZZZZ888III8888888,
,II88Zl;. ;llZZZZZ888888I888888,
,II888Zl;. .;;;;;lllZZZ888888I8888b
,II8888Z;; `;;;;;''llZZ8888888I8888,
II88888Z;' .;lZZZ8888888I888b
II88888Z; _,aaa, .,aaaaa,__.l;llZZZ88888888I888
II88888IZZZZZZZZZ, .ZZZZZZZZZZZZZZ;llZZ88888888I888,
II88888IZZ<'(@@>Z| |ZZZ<'(@@>ZZZZ;;llZZ888888888I88I
,II88888; `""" ;| |ZZ; `""" ;;llZ8888888888I888
II888888l `;; .;llZZ8888888888I888,
,II888888Z; ;;; .;;llZZZ8888888888I888I
III888888Zl; .., `;; ,;;lllZZZ88888888888I888
II88888888Z;;...;(_ _) ,;;;llZZZZ88888888888I888,
II88888888Zl;;;;;' `--'Z;. .,;;;;llZZZZ88888888888I888b
]I888888888Z;;;;' ";llllll;..;;;lllZZZZ88888888888I8888,
II888888888Zl.;;"Y88bd888P";;,..;lllZZZZZ88888888888I8888I
II8888888888Zl;.; `"PPP";;;,..;lllZZZZZZZ88888888888I88888
II888888888888Zl;;. `;;;l;;;;lllZZZZZZZZW88888888888I88888
`II8888888888888Zl;. ,;;lllZZZZZZZZWMZ88888888888I88888
II8888888888888888ZbaalllZZZZZZZZZWWMZZZ8888888888I888888,
`II88888888888888888b"WWZZZZZWWWMMZZZZZZI888888888I888888b
`II88888888888888888;ZZMMMMMMZZZZZZZZllI888888888I8888888
`II8888888888888888 `;lZZZZZZZZZZZlllll888888888I8888888,
II8888888888888888, `;lllZZZZllllll;;.Y88888888I8888888b,
,II8888888888888888b .;;lllllll;;;.;..88888888I88888888b,
II888888888888888PZI;. .`;;;.;;;..; ...88888888I8888888888,
II888888888888PZ;;';;. ;. .;. .;. .. Y8888888I88888888888b,
,II888888888PZ;;' `8888888I8888888888888b,
II888888888' 888888I8888888888888888
,II888888888 ,888888I8888888888888888
,d88888888888 d888888I8888888888ZZZZZZ
,ad888888888888I 8888888I8888ZZZZZZZZZZZZ
888888888888888' 888888IZZZZZZZZZZZZZZZZZ
8888888888P'8P' Y888ZZZZZZZZZZZZZZZZZZZZ
888888888, " ,ZZZZZZZZZZZZZZZZZZZZZZZ
8888888888, ,ZZZZZZZZZZZZZZZZZZZZZZZZZZ
888888888888a, _ ,ZZZZZZZZZZZZZZZZZZZZ88888888
888888888888888ba,_d' ,ZZZZZZZZZZZZZZZZZ8888888888888
8888888888888888888888bbbaaa,,,______,ZZZZZZZZZZZZZZZ88888888888888888
88888888888888888888888888888888888ZZZZZZZZZZZZZZZ88888888888888888888
8888888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888
888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888
8888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888
88888888888888888888888888888ZZZZZZZZZZZZZZ888888888888888888888888888
8888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888 Normand 8
88888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888 Veilleux 8
8888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888888
2015-05-12 19:20:58 +02:00
// User mentions
{
2017-08-25 08:22:20 +02:00
match : /\B@([\w.]*)$/ ,
2015-09-03 23:12:46 +02:00
search ( term , callback ) {
const currentBoard = Boards . findOne ( Session . get ( 'currentBoard' ) ) ;
2019-06-28 12:52:09 -05:00
callback (
currentBoard
. activeMembers ( )
. map ( member => {
2020-03-23 22:29:20 +02:00
const username = Users . findOne ( member . userId ) . username ;
2019-06-28 12:52:09 -05:00
return username . includes ( term ) ? username : null ;
} )
. filter ( Boolean ) ,
) ;
Renaissance
_,,ad8888888888bba,_
,ad88888I888888888888888ba,
,88888888I88888888888888888888a,
,d888888888I8888888888888888888888b,
d88888PP"""" ""YY88888888888888888888b,
,d88"'__,,--------,,,,.;ZZZY8888888888888,
,8IIl'" ;;l"ZZZIII8888888888,
,I88l;' ;lZZZZZ888III8888888,
,II88Zl;. ;llZZZZZ888888I888888,
,II888Zl;. .;;;;;lllZZZ888888I8888b
,II8888Z;; `;;;;;''llZZ8888888I8888,
II88888Z;' .;lZZZ8888888I888b
II88888Z; _,aaa, .,aaaaa,__.l;llZZZ88888888I888
II88888IZZZZZZZZZ, .ZZZZZZZZZZZZZZ;llZZ88888888I888,
II88888IZZ<'(@@>Z| |ZZZ<'(@@>ZZZZ;;llZZ888888888I88I
,II88888; `""" ;| |ZZ; `""" ;;llZ8888888888I888
II888888l `;; .;llZZ8888888888I888,
,II888888Z; ;;; .;;llZZZ8888888888I888I
III888888Zl; .., `;; ,;;lllZZZ88888888888I888
II88888888Z;;...;(_ _) ,;;;llZZZZ88888888888I888,
II88888888Zl;;;;;' `--'Z;. .,;;;;llZZZZ88888888888I888b
]I888888888Z;;;;' ";llllll;..;;;lllZZZZ88888888888I8888,
II888888888Zl.;;"Y88bd888P";;,..;lllZZZZZ88888888888I8888I
II8888888888Zl;.; `"PPP";;;,..;lllZZZZZZZ88888888888I88888
II888888888888Zl;;. `;;;l;;;;lllZZZZZZZZW88888888888I88888
`II8888888888888Zl;. ,;;lllZZZZZZZZWMZ88888888888I88888
II8888888888888888ZbaalllZZZZZZZZZWWMZZZ8888888888I888888,
`II88888888888888888b"WWZZZZZWWWMMZZZZZZI888888888I888888b
`II88888888888888888;ZZMMMMMMZZZZZZZZllI888888888I8888888
`II8888888888888888 `;lZZZZZZZZZZZlllll888888888I8888888,
II8888888888888888, `;lllZZZZllllll;;.Y88888888I8888888b,
,II8888888888888888b .;;lllllll;;;.;..88888888I88888888b,
II888888888888888PZI;. .`;;;.;;;..; ...88888888I8888888888,
II888888888888PZ;;';;. ;. .;. .;. .. Y8888888I88888888888b,
,II888888888PZ;;' `8888888I8888888888888b,
II888888888' 888888I8888888888888888
,II888888888 ,888888I8888888888888888
,d88888888888 d888888I8888888888ZZZZZZ
,ad888888888888I 8888888I8888ZZZZZZZZZZZZ
888888888888888' 888888IZZZZZZZZZZZZZZZZZ
8888888888P'8P' Y888ZZZZZZZZZZZZZZZZZZZZ
888888888, " ,ZZZZZZZZZZZZZZZZZZZZZZZ
8888888888, ,ZZZZZZZZZZZZZZZZZZZZZZZZZZ
888888888888a, _ ,ZZZZZZZZZZZZZZZZZZZZ88888888
888888888888888ba,_d' ,ZZZZZZZZZZZZZZZZZ8888888888888
8888888888888888888888bbbaaa,,,______,ZZZZZZZZZZZZZZZ88888888888888888
88888888888888888888888888888888888ZZZZZZZZZZZZZZZ88888888888888888888
8888888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888
888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888
8888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888
88888888888888888888888888888ZZZZZZZZZZZZZZ888888888888888888888888888
8888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888 Normand 8
88888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888 Veilleux 8
8888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888888
2015-05-12 19:20:58 +02:00
} ,
2015-09-03 23:12:46 +02:00
template ( value ) {
Renaissance
_,,ad8888888888bba,_
,ad88888I888888888888888ba,
,88888888I88888888888888888888a,
,d888888888I8888888888888888888888b,
d88888PP"""" ""YY88888888888888888888b,
,d88"'__,,--------,,,,.;ZZZY8888888888888,
,8IIl'" ;;l"ZZZIII8888888888,
,I88l;' ;lZZZZZ888III8888888,
,II88Zl;. ;llZZZZZ888888I888888,
,II888Zl;. .;;;;;lllZZZ888888I8888b
,II8888Z;; `;;;;;''llZZ8888888I8888,
II88888Z;' .;lZZZ8888888I888b
II88888Z; _,aaa, .,aaaaa,__.l;llZZZ88888888I888
II88888IZZZZZZZZZ, .ZZZZZZZZZZZZZZ;llZZ88888888I888,
II88888IZZ<'(@@>Z| |ZZZ<'(@@>ZZZZ;;llZZ888888888I88I
,II88888; `""" ;| |ZZ; `""" ;;llZ8888888888I888
II888888l `;; .;llZZ8888888888I888,
,II888888Z; ;;; .;;llZZZ8888888888I888I
III888888Zl; .., `;; ,;;lllZZZ88888888888I888
II88888888Z;;...;(_ _) ,;;;llZZZZ88888888888I888,
II88888888Zl;;;;;' `--'Z;. .,;;;;llZZZZ88888888888I888b
]I888888888Z;;;;' ";llllll;..;;;lllZZZZ88888888888I8888,
II888888888Zl.;;"Y88bd888P";;,..;lllZZZZZ88888888888I8888I
II8888888888Zl;.; `"PPP";;;,..;lllZZZZZZZ88888888888I88888
II888888888888Zl;;. `;;;l;;;;lllZZZZZZZZW88888888888I88888
`II8888888888888Zl;. ,;;lllZZZZZZZZWMZ88888888888I88888
II8888888888888888ZbaalllZZZZZZZZZWWMZZZ8888888888I888888,
`II88888888888888888b"WWZZZZZWWWMMZZZZZZI888888888I888888b
`II88888888888888888;ZZMMMMMMZZZZZZZZllI888888888I8888888
`II8888888888888888 `;lZZZZZZZZZZZlllll888888888I8888888,
II8888888888888888, `;lllZZZZllllll;;.Y88888888I8888888b,
,II8888888888888888b .;;lllllll;;;.;..88888888I88888888b,
II888888888888888PZI;. .`;;;.;;;..; ...88888888I8888888888,
II888888888888PZ;;';;. ;. .;. .;. .. Y8888888I88888888888b,
,II888888888PZ;;' `8888888I8888888888888b,
II888888888' 888888I8888888888888888
,II888888888 ,888888I8888888888888888
,d88888888888 d888888I8888888888ZZZZZZ
,ad888888888888I 8888888I8888ZZZZZZZZZZZZ
888888888888888' 888888IZZZZZZZZZZZZZZZZZ
8888888888P'8P' Y888ZZZZZZZZZZZZZZZZZZZZ
888888888, " ,ZZZZZZZZZZZZZZZZZZZZZZZ
8888888888, ,ZZZZZZZZZZZZZZZZZZZZZZZZZZ
888888888888a, _ ,ZZZZZZZZZZZZZZZZZZZZ88888888
888888888888888ba,_d' ,ZZZZZZZZZZZZZZZZZ8888888888888
8888888888888888888888bbbaaa,,,______,ZZZZZZZZZZZZZZZ88888888888888888
88888888888888888888888888888888888ZZZZZZZZZZZZZZZ88888888888888888888
8888888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888
888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888
8888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888
88888888888888888888888888888ZZZZZZZZZZZZZZ888888888888888888888888888
8888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888 Normand 8
88888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888 Veilleux 8
8888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888888
2015-05-12 19:20:58 +02:00
return value ;
} ,
2015-09-03 23:12:46 +02:00
replace ( username ) {
return ` @ ${ username } ` ;
Renaissance
_,,ad8888888888bba,_
,ad88888I888888888888888ba,
,88888888I88888888888888888888a,
,d888888888I8888888888888888888888b,
d88888PP"""" ""YY88888888888888888888b,
,d88"'__,,--------,,,,.;ZZZY8888888888888,
,8IIl'" ;;l"ZZZIII8888888888,
,I88l;' ;lZZZZZ888III8888888,
,II88Zl;. ;llZZZZZ888888I888888,
,II888Zl;. .;;;;;lllZZZ888888I8888b
,II8888Z;; `;;;;;''llZZ8888888I8888,
II88888Z;' .;lZZZ8888888I888b
II88888Z; _,aaa, .,aaaaa,__.l;llZZZ88888888I888
II88888IZZZZZZZZZ, .ZZZZZZZZZZZZZZ;llZZ88888888I888,
II88888IZZ<'(@@>Z| |ZZZ<'(@@>ZZZZ;;llZZ888888888I88I
,II88888; `""" ;| |ZZ; `""" ;;llZ8888888888I888
II888888l `;; .;llZZ8888888888I888,
,II888888Z; ;;; .;;llZZZ8888888888I888I
III888888Zl; .., `;; ,;;lllZZZ88888888888I888
II88888888Z;;...;(_ _) ,;;;llZZZZ88888888888I888,
II88888888Zl;;;;;' `--'Z;. .,;;;;llZZZZ88888888888I888b
]I888888888Z;;;;' ";llllll;..;;;lllZZZZ88888888888I8888,
II888888888Zl.;;"Y88bd888P";;,..;lllZZZZZ88888888888I8888I
II8888888888Zl;.; `"PPP";;;,..;lllZZZZZZZ88888888888I88888
II888888888888Zl;;. `;;;l;;;;lllZZZZZZZZW88888888888I88888
`II8888888888888Zl;. ,;;lllZZZZZZZZWMZ88888888888I88888
II8888888888888888ZbaalllZZZZZZZZZWWMZZZ8888888888I888888,
`II88888888888888888b"WWZZZZZWWWMMZZZZZZI888888888I888888b
`II88888888888888888;ZZMMMMMMZZZZZZZZllI888888888I8888888
`II8888888888888888 `;lZZZZZZZZZZZlllll888888888I8888888,
II8888888888888888, `;lllZZZZllllll;;.Y88888888I8888888b,
,II8888888888888888b .;;lllllll;;;.;..88888888I88888888b,
II888888888888888PZI;. .`;;;.;;;..; ...88888888I8888888888,
II888888888888PZ;;';;. ;. .;. .;. .. Y8888888I88888888888b,
,II888888888PZ;;' `8888888I8888888888888b,
II888888888' 888888I8888888888888888
,II888888888 ,888888I8888888888888888
,d88888888888 d888888I8888888888ZZZZZZ
,ad888888888888I 8888888I8888ZZZZZZZZZZZZ
888888888888888' 888888IZZZZZZZZZZZZZZZZZ
8888888888P'8P' Y888ZZZZZZZZZZZZZZZZZZZZ
888888888, " ,ZZZZZZZZZZZZZZZZZZZZZZZ
8888888888, ,ZZZZZZZZZZZZZZZZZZZZZZZZZZ
888888888888a, _ ,ZZZZZZZZZZZZZZZZZZZZ88888888
888888888888888ba,_d' ,ZZZZZZZZZZZZZZZZZ8888888888888
8888888888888888888888bbbaaa,,,______,ZZZZZZZZZZZZZZZ88888888888888888
88888888888888888888888888888888888ZZZZZZZZZZZZZZZ88888888888888888888
8888888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888
888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888
8888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888
88888888888888888888888888888ZZZZZZZZZZZZZZ888888888888888888888888888
8888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888 Normand 8
88888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888 Veilleux 8
8888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888888
2015-05-12 19:20:58 +02:00
} ,
2015-09-03 23:12:46 +02:00
index : 1 ,
} ,
2019-07-22 13:53:37 -04:00
] ;
2019-07-22 23:33:44 -04:00
const enableTextarea = function ( ) {
const $textarea = this . $ ( textareaSelector ) ;
autosize ( $textarea ) ;
$textarea . escapeableTextComplete ( mentions ) ;
} ;
2019-08-10 00:48:05 -04:00
if ( Meteor . settings . public . RICHER _CARD _COMMENT _EDITOR !== false ) {
2019-07-22 13:53:37 -04:00
const isSmall = Utils . isMiniScreen ( ) ;
const toolbar = isSmall
? [
2019-07-22 23:33:44 -04:00
[ 'view' , [ 'fullscreen' ] ] ,
[ 'table' , [ 'table' ] ] ,
2020-03-23 22:29:20 +02:00
[ 'font' , [ 'bold' , 'underline' ] ] ,
2019-09-19 15:16:48 -04:00
//['fontsize', ['fontsize']],
2020-03-23 22:29:20 +02:00
[ 'color' , [ 'color' ] ] ,
2019-07-22 13:53:37 -04:00
]
: [
[ 'style' , [ 'style' ] ] ,
[ 'font' , [ 'bold' , 'underline' , 'clear' ] ] ,
[ 'fontsize' , [ 'fontsize' ] ] ,
[ 'fontname' , [ 'fontname' ] ] ,
[ 'color' , [ 'color' ] ] ,
[ 'para' , [ 'ul' , 'ol' , 'paragraph' ] ] ,
[ 'table' , [ 'table' ] ] ,
2020-03-23 22:29:20 +02:00
//['insert', ['link', 'picture', 'video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
2019-07-22 23:33:44 -04:00
//['insert', ['link', 'picture']], // modal popup has issue somehow :(
2019-07-22 13:53:37 -04:00
[ 'view' , [ 'fullscreen' , 'help' ] ] ,
] ;
2020-03-23 22:29:20 +02:00
const cleanPastedHTML = function ( input ) {
const badTags = [
'style' ,
'script' ,
'applet' ,
'embed' ,
'noframes' ,
'noscript' ,
'meta' ,
'link' ,
'button' ,
'form' ,
] . join ( '|' ) ;
const badPatterns = new RegExp (
` (?: ${ [
` <( ${ badTags } )s*[^>][ \\ s \\ S]*?< \\ / \\ 1> ` ,
` <( ${ badTags } )[^>]*? \\ /> ` ,
] . join ( '|' ) } ) ` ,
'gi' ,
) ;
let output = input ;
// remove bad Tags
output = output . replace ( badPatterns , '' ) ;
// remove attributes ' style="..."'
const badAttributes = new RegExp (
` (?: ${ [
'on\\S+=([\'"]?).*?\\1' ,
'href=([\'"]?)javascript:.*?\\2' ,
'style=([\'"]?).*?\\3' ,
'target=\\S+' ,
] . join ( '|' ) } ) ` ,
'gi' ,
) ;
output = output . replace ( badAttributes , '' ) ;
output = output . replace ( /(<a )/gi , '$1target=_ ' ) ; // always to new target
return output ;
} ;
2019-07-22 13:53:37 -04:00
const editor = '.editor' ;
const selectors = [
2020-11-02 21:58:13 +02:00
` .js-new-description-form ${ editor } ` ,
2019-07-22 13:53:37 -04:00
` .js-new-comment-form ${ editor } ` ,
` .js-edit-comment ${ editor } ` ,
] . join ( ',' ) ; // only new comment and edit comment
2019-07-22 23:33:44 -04:00
const inputs = $ ( selectors ) ;
if ( inputs . length === 0 ) {
// only enable richereditor to new comment or edit comment no others
enableTextarea ( ) ;
} else {
const placeholder = inputs . attr ( 'placeholder' ) || '' ;
const mSummernotes = [ ] ;
const getSummernote = function ( input ) {
const idx = inputs . index ( input ) ;
if ( idx > - 1 ) {
return mSummernotes [ idx ] ;
}
return undefined ;
} ;
inputs . each ( function ( idx , input ) {
mSummernotes [ idx ] = $ ( input ) . summernote ( {
placeholder ,
callbacks : {
onInit ( object ) {
const originalInput = this ;
2019-08-07 23:44:45 -04:00
$ ( originalInput ) . on ( 'submitted' , function ( ) {
2020-03-23 22:29:20 +02:00
// when comment is submitted, the original textarea will be set to '', so shall we
2019-07-22 23:33:44 -04:00
if ( ! this . value ) {
const sn = getSummernote ( this ) ;
2019-09-17 09:27:23 -04:00
sn && sn . summernote ( 'code' , '' ) ;
2019-07-22 23:33:44 -04:00
}
} ) ;
const jEditor = object && object . editable ;
const toolbar = object && object . toolbar ;
2020-03-23 22:29:20 +02:00
if ( jEditor !== undefined ) {
jEditor . escapeableTextComplete ( mentions ) ;
}
2019-07-22 23:33:44 -04:00
if ( toolbar !== undefined ) {
const fBtn = toolbar . find ( '.btn-fullscreen' ) ;
fBtn . on ( 'click' , function ( ) {
const $this = $ ( this ) ,
isActive = $this . hasClass ( 'active' ) ;
2019-08-15 14:23:14 -04:00
$ ( '.minicards,#header-quick-access' ) . toggle ( ! isActive ) ; // mini card is still showing when editor is in fullscreen mode, we hide here manually
2019-07-22 23:33:44 -04:00
} ) ;
}
} ,
2020-03-31 16:56:32 +03:00
2019-08-07 23:44:45 -04:00
onImageUpload ( files ) {
const $summernote = getSummernote ( this ) ;
if ( files && files . length > 0 ) {
const image = files [ 0 ] ;
2019-08-10 21:21:42 -04:00
const currentCard = Cards . findOne ( Session . get ( 'currentCard' ) ) ;
2019-08-07 23:44:45 -04:00
const MAX _IMAGE _PIXEL = Utils . MAX _IMAGE _PIXEL ;
const COMPRESS _RATIO = Utils . IMAGE _COMPRESS _RATIO ;
2019-08-10 21:21:42 -04:00
const insertImage = src => {
2019-08-07 23:44:45 -04:00
const img = document . createElement ( 'img' ) ;
2019-08-10 21:21:42 -04:00
img . src = src ;
2019-08-07 23:44:45 -04:00
img . setAttribute ( 'width' , '100%' ) ;
$summernote . summernote ( 'insertNode' , img ) ;
} ;
2019-08-10 21:21:42 -04:00
const processData = function ( fileObj ) {
Utils . processUploadedAttachment (
currentCard ,
2020-05-25 17:54:51 +03:00
fileObj ,
attachment => {
if (
attachment &&
attachment . _id &&
attachment . isImage ( )
) {
attachment . one ( 'uploaded' , function ( ) {
const maxTry = 3 ;
const checkItvl = 500 ;
let retry = 0 ;
const checkUrl = function ( ) {
// even though uploaded event fired, attachment.url() is still null somehow //TODO
const url = attachment . url ( ) ;
if ( url ) {
insertImage (
` ${ location . protocol } // ${ location . host } ${ url } ` ,
) ;
} else {
retry ++ ;
if ( retry < maxTry ) {
setTimeout ( checkUrl , checkItvl ) ;
2019-08-10 21:21:42 -04:00
}
2020-05-25 17:54:51 +03:00
}
} ;
checkUrl ( ) ;
} ) ;
2019-08-10 21:21:42 -04:00
}
} ,
) ;
} ;
if ( MAX _IMAGE _PIXEL ) {
const reader = new FileReader ( ) ;
reader . onload = function ( e ) {
const dataurl = e && e . target && e . target . result ;
if ( dataurl !== undefined ) {
2019-08-07 23:44:45 -04:00
// need to shrink image
Utils . shrinkImage ( {
dataurl ,
maxSize : MAX _IMAGE _PIXEL ,
ratio : COMPRESS _RATIO ,
2019-08-10 21:21:42 -04:00
toBlob : true ,
callback ( blob ) {
if ( blob !== false ) {
blob . name = image . name ;
processData ( blob ) ;
2019-08-07 23:44:45 -04:00
}
} ,
} ) ;
}
2019-08-10 21:21:42 -04:00
} ;
reader . readAsDataURL ( image ) ;
} else {
processData ( image ) ;
}
2019-08-07 23:44:45 -04:00
}
} ,
2019-07-22 23:33:44 -04:00
onPaste ( ) {
// clear up unwanted tag info when user pasted in text
const thisNote = this ;
const updatePastedText = function ( object ) {
const someNote = getSummernote ( object ) ;
2020-03-24 20:39:49 +02:00
// Fix Pasting text into a card is adding a line before and after
// (and multiplies by pasting more) by changing paste "p" to "br".
// Fixes https://github.com/wekan/wekan/2890 .
// == Fix Start ==
someNote . execCommand ( 'defaultParagraphSeparator' , false , 'br' ) ;
// == Fix End ==
2019-07-22 23:33:44 -04:00
const original = someNote . summernote ( 'code' ) ;
const cleaned = cleanPastedHTML ( original ) ; //this is where to call whatever clean function you want. I have mine in a different file, called CleanPastedHTML.
2019-09-17 09:27:23 -04:00
someNote . summernote ( 'code' , '' ) ; //clear original
2019-07-22 23:33:44 -04:00
someNote . summernote ( 'pasteHTML' , cleaned ) ; //this sets the displayed content editor to the cleaned pasted code.
} ;
setTimeout ( function ( ) {
//this kinda sucks, but if you don't do a setTimeout,
//the function is called before the text is really pasted.
updatePastedText ( thisNote ) ;
} , 10 ) ;
} ,
} ,
dialogsInBody : true ,
disableDragAndDrop : true ,
toolbar ,
popover : {
image : [
[
'image' ,
[ 'resizeFull' , 'resizeHalf' , 'resizeQuarter' , 'resizeNone' ] ,
] ,
[ 'float' , [ 'floatLeft' , 'floatRight' , 'floatNone' ] ] ,
[ 'remove' , [ 'removeMedia' ] ] ,
] ,
table : [
[ 'add' , [ 'addRowDown' , 'addRowUp' , 'addColLeft' , 'addColRight' ] ] ,
[ 'delete' , [ 'deleteRow' , 'deleteCol' , 'deleteTable' ] ] ,
] ,
air : [
[ 'color' , [ 'color' ] ] ,
[ 'font' , [ 'bold' , 'underline' , 'clear' ] ] ,
] ,
} ,
height : 200 ,
} ) ;
} ) ;
}
2019-07-22 13:53:37 -04:00
} else {
2019-07-22 23:33:44 -04:00
enableTextarea ( ) ;
2019-07-22 13:53:37 -04:00
}
2015-05-26 20:30:01 +02:00
} ) ;
2020-03-23 22:29:20 +02:00
import sanitizeXss from 'xss' ;
2020-11-10 18:03:17 -03:00
// Additional safeAttrValue function to allow for other specific protocols
// See https://github.com/leizongmin/js-xss/issues/52#issuecomment-241354114
function mySafeAttrValue ( tag , name , value , cssFilter ) {
// only when the tag is 'a' and attribute is 'href'
// then use your custom function
if ( tag === 'a' && name === 'href' ) {
// only filter the value if starts with 'cbthunderlink:' or 'aodroplink'
2020-11-29 04:19:28 +02:00
if (
/^thunderlink:/gi . test ( value ) ||
/^cbthunderlink:/gi . test ( value ) ||
2021-01-13 00:02:17 +02:00
/^aodroplink:/gi . test ( value ) ||
/^onenote:/gi . test ( value ) ||
/^file:/gi . test ( value ) ||
2021-01-26 13:54:22 +01:00
/^abasurl:/gi . test ( value ) ||
/^conisio:/gi . test ( value ) ||
2021-01-13 00:02:17 +02:00
/^mailspring:/gi . test ( value )
2020-11-29 04:19:28 +02:00
) {
2020-11-10 18:03:17 -03:00
return value ;
2020-11-29 04:19:28 +02:00
} else {
2020-11-10 22:01:04 -03:00
// use the default safeAttrValue function to process all non cbthunderlinks
return sanitizeXss . safeAttrValue ( tag , name , value , cssFilter ) ;
}
2020-11-10 18:03:17 -03:00
} else {
// use the default safeAttrValue function to process it
return sanitizeXss . safeAttrValue ( tag , name , value , cssFilter ) ;
}
2020-11-29 04:19:28 +02:00
}
2020-11-10 18:03:17 -03:00
2015-09-06 23:42:52 +02:00
// XXX I believe we should compute a HTML rendered field on the server that
2018-02-12 23:52:22 +02:00
// would handle markdown and user mentions. We can simply have two
2015-09-06 23:42:52 +02:00
// fields, one source, and one compiled version (in HTML) and send only the
// compiled version to most users -- who don't need to edit.
// In the meantime, all the transformation are done on the client using the
// Blaze API.
2019-06-28 12:52:09 -05:00
const at = HTML . CharRef ( { html : '@' , str : '@' } ) ;
Blaze . Template . registerHelper (
'mentions' ,
new Template ( 'mentions' , function ( ) {
const view = this ;
let content = Blaze . toHTML ( view . templateContentBlock ) ;
const currentBoard = Boards . findOne ( Session . get ( 'currentBoard' ) ) ;
2020-11-29 04:19:28 +02:00
if ( ! currentBoard )
return HTML . Raw ( sanitizeXss ( content , { safeAttrValue : mySafeAttrValue } ) ) ;
2019-06-28 12:52:09 -05:00
const knowedUsers = currentBoard . members . map ( member => {
const u = Users . findOne ( member . userId ) ;
if ( u ) {
member . username = u . username ;
}
return member ;
} ) ;
2020-03-23 22:29:20 +02:00
const mentionRegex = /\B@([\w.]*)/gi ;
2015-09-06 23:42:52 +02:00
2019-06-28 12:52:09 -05:00
let currentMention ;
while ( ( currentMention = mentionRegex . exec ( content ) ) !== null ) {
2019-09-19 15:16:48 -04:00
const [ fullMention , quoteduser , simple ] = currentMention ;
const username = quoteduser || simple ;
2019-06-28 12:52:09 -05:00
const knowedUser = _ . findWhere ( knowedUsers , { username } ) ;
if ( ! knowedUser ) {
continue ;
}
2015-09-06 23:42:52 +02:00
2019-06-28 12:52:09 -05:00
const linkValue = [ ' ' , at , knowedUser . username ] ;
let linkClass = 'atMention js-open-member' ;
if ( knowedUser . userId === Meteor . userId ( ) ) {
linkClass += ' me' ;
}
2020-03-24 20:39:49 +02:00
// This @user mention link generation did open same Wekan
// window in new tab, so now A is changed to U so it's
// underlined and there is no link popup. This way also
// text can be selected more easily.
//const link = HTML.A(
const link = HTML . U (
2019-06-28 12:52:09 -05:00
{
class : linkClass ,
// XXX Hack. Since we stringify this render function result below with
// `Blaze.toHTML` we can't rely on blaze data contexts to pass the
// `userId` to the popup as usual, and we need to store it in the DOM
// using a data attribute.
'data-userId' : knowedUser . userId ,
} ,
linkValue ,
) ;
2015-09-06 23:42:52 +02:00
2019-06-28 12:52:09 -05:00
content = content . replace ( fullMention , Blaze . toHTML ( link ) ) ;
}
2020-03-23 22:29:20 +02:00
2020-11-10 18:03:17 -03:00
return HTML . Raw ( sanitizeXss ( content , { safeAttrValue : mySafeAttrValue } ) ) ;
2019-06-28 12:52:09 -05:00
} ) ,
) ;
2020-03-23 22:29:20 +02:00
2015-09-01 22:26:48 +02:00
Template . viewer . events ( {
// Viewer sometimes have click-able wrapper around them (for instance to edit
// the corresponding text). Clicking a link shouldn't fire these actions, stop
// we stop these event at the viewer component level.
2019-06-28 12:52:09 -05:00
'click a' ( event , templateInstance ) {
2020-05-03 00:33:15 +02:00
const prevent = true ;
2019-06-28 12:52:09 -05:00
const userId = event . currentTarget . dataset . userid ;
2016-07-11 12:04:42 +02:00
if ( userId ) {
2019-06-28 12:52:09 -05:00
Popup . open ( 'member' ) . call ( { userId } , event , templateInstance ) ;
} else {
const href = event . currentTarget . href ;
2020-03-23 22:29:20 +02:00
if ( href ) {
2016-07-11 12:04:42 +02:00
window . open ( href , '_blank' ) ;
}
2015-09-06 23:42:52 +02:00
}
2019-08-07 23:44:45 -04:00
if ( prevent ) {
event . stopPropagation ( ) ;
// XXX We hijack the build-in browser action because we currently don't have
// `_blank` attributes in viewer links, and the transformer function is
// handled by a third party package that we can't configure easily. Fix that
// by using directly `_blank` attribute in the rendered HTML.
event . preventDefault ( ) ;
}
2015-09-03 23:12:46 +02:00
} ,
2015-09-01 22:26:48 +02:00
} ) ;