Advertisement
Thomas

Markdown Editor JS

Feb 5th, 2020
678
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
jQuery 19.29 KB | None | 0 0
  1. /* global marked */
  2.  
  3. ( function ( $ )
  4. {
  5.     $.fn.wcTextarea = function ( options )
  6.     {
  7.     let DEFAULTS = {
  8.         livePreview: false,
  9.         buttons: {
  10.         header: {
  11.             btnClass: 'btn btn-default',
  12.             html: '<i class="fa fa-header fa-fw"></i>'
  13.         },
  14.         bold: {
  15.             btnClass: 'btn btn-default',
  16.             html: '<i class="fa fa-bold fa-fw"></i>'
  17.         },
  18.         italic: {
  19.             btnClass: 'btn btn-default',
  20.             html: '<i class="fa fa-italic fa-fw"></i>'
  21.         },
  22.         ul: {
  23.             btnClass: 'btn btn-default',
  24.             html: '<i class="fa fa-list-ul fa-fw"></i>'
  25.         },
  26.         ol: {
  27.             btnClass: 'btn btn-default',
  28.             html: '<i class="fa fa-list-ol fa-fw"></i>'
  29.         },
  30.         link: {
  31.             btnClass: 'btn btn-default',
  32.             html: '<i class="fa fa-link fa-fw"></i>'
  33.         },
  34.         picture: {
  35.             btnClass: 'btn btn-default',
  36.             html: '<i class="fa fa-picture-o fa-fw"></i>'
  37.         },
  38.         codeInline: {
  39.             btnClass: 'btn btn-default',
  40.             html: '<i class="fa fa-code fa-fw"></i>'
  41.         },
  42.         quote: {
  43.             btnClass: 'btn btn-default',
  44.             html: '<i class="fa fa-quote-right fa-fw"></i>'
  45.         },
  46.         paragraph: {
  47.             btnClass: 'btn btn-default',
  48.             html: '<i class="fa fa-paragraph fa-fw"></i>'
  49.         },
  50.         preview: {
  51.             btnClass: 'btn btn-default',
  52.             html: '<i class="fa fa-eye fa-fw"></i>'
  53.         }
  54.  
  55.         }
  56.     };
  57.  
  58.  
  59.     let option = $.extend(true, DEFAULTS, options || { });
  60.  
  61.     console.log(option);
  62.  
  63.     let textarea = $(this),
  64.         wrapper = $('<div>', { class: 'my-textarea', css: { position: 'relative' } }),
  65.         lineSplittPattern = /\r?\n|\r/,
  66.         markedFound = 'function' === typeof marked,
  67.         vars = {
  68.         value: '',
  69.         start: 0,
  70.         end: 0,
  71.         length: 0,
  72.         selectedText: '',
  73.         selectedLength: 0,
  74.         words: 0,
  75.         lines: 0
  76.         },
  77.         buttons = {
  78.         bold: null,
  79.         italic: null,
  80.         codeInline: null,
  81.         h1: null,
  82.         h2: null,
  83.         h3: null,
  84.         h4: null,
  85.         h5: null,
  86.         h6: null,
  87.         quote: null,
  88.         paragraph: null,
  89.         ul: null,
  90.         ol: null,
  91.         link: null,
  92.         picture: null,
  93.         goBack: null,
  94.         goForward: null,
  95.         preview: null
  96.         },
  97.         counters = {
  98.         paragraphs: null,
  99.         lines: null,
  100.         words: null,
  101.         characters: null,
  102.         selected: null
  103.         };
  104.  
  105.     textarea.wrap(wrapper);
  106.     textarea.prop('rows', 10).addClass('rounded-0 shadow border-0').css({ 'display': 'block' });
  107.  
  108.     function buildButtons()
  109.     {
  110.         let btnGroup = $('<div>', {
  111.         class: 'btn-group btn-group-xs mb-2 shadow flex-nowrap rounded-0'
  112.         }).insertBefore(textarea);
  113.  
  114.  
  115.         let headlineBtnGroup = $('<div>', { class: "btn-group" }).appendTo(btnGroup);
  116.         $('<button>', {
  117.         type: 'button',
  118.         class: 'btn btn-default dropdown-toggle btn-xs',
  119.         'data-toggle': 'dropdown',
  120.         'aria-haspopup': 'true',
  121.         'aria-expanded': 'false',
  122.         html: [
  123.             '<i class="fa fa-header fa-fw"></i> <span class="caret"></span>'
  124.         ].join(''),
  125.         title: 'Überschrift'
  126.         }).appendTo(headlineBtnGroup);
  127.         let dropDownMenu = $('<ul>', { class: 'dropdown-menu' }).appendTo(headlineBtnGroup);
  128.  
  129.         let li;
  130.         for ( let i = 1; i <= 6; i ++ )
  131.         {
  132.         li = $('<li>').appendTo(dropDownMenu);
  133.         buttons['h' + i] = $('<a>', {
  134.             href: '#',
  135.             html: option.buttons.header.html + ' Überschrift ' + i
  136.         }).appendTo(li);
  137.         }
  138.  
  139.         buttons.bold = $('<button>', {
  140.         class: option.buttons.bold.btnClass,
  141.         html: option.buttons.bold.html,
  142.         title: 'Fett',
  143.         'data-toggle': 'tooltip'
  144.         }).appendTo(btnGroup);
  145.  
  146.         buttons.italic = $('<button>', {
  147.         class: option.buttons.italic.btnClass,
  148.         html: option.buttons.italic.html,
  149.         title: 'Kursiv',
  150.         'data-toggle': 'tooltip'
  151.         }).appendTo(btnGroup);
  152.  
  153.         buttons.ul = $('<button>', {
  154.         class: option.buttons.ul.btnClass,
  155.         html: option.buttons.ul.html,
  156.         title: 'unnummerierte Liste',
  157.         'data-toggle': 'tooltip'
  158.         }).appendTo(btnGroup);
  159.  
  160.         buttons.ol = $('<button>', {
  161.         class: option.buttons.ol.btnClass,
  162.         html: option.buttons.ol.html,
  163.         title: 'Nummerierte liste',
  164.         'data-toggle': 'tooltip'
  165.         }).appendTo(btnGroup);
  166.  
  167.         buttons.link = $('<button>', {
  168.         class: option.buttons.link.btnClass,
  169.         html: option.buttons.link.html,
  170.         title: 'Link',
  171.         'data-toggle': 'tooltip'
  172.         }).appendTo(btnGroup);
  173.  
  174.         buttons.picture = $('<button>', {
  175.         class: option.buttons.picture.btnClass,
  176.         html: option.buttons.picture.html,
  177.         title: 'Bild einfügen',
  178.         'data-toggle': 'tooltip'
  179.         }).appendTo(btnGroup);
  180.  
  181.         buttons.codeInline = $('<button>', {
  182.         class: option.buttons.codeInline.btnClass,
  183.         html: option.buttons.codeInline.html,
  184.         title: 'Inline Code',
  185.         'data-toggle': 'tooltip'
  186.         }).appendTo(btnGroup);
  187.  
  188.         buttons.quote = $('<button>', {
  189.         class: option.buttons.quote.btnClass,
  190.         html: option.buttons.quote.html,
  191.         title: 'Zitat',
  192.         'data-toggle': 'tooltip'
  193.         }).appendTo(btnGroup);
  194.  
  195.         buttons.paragraph = $('<button>', {
  196.         class: option.buttons.paragraph.btnClass,
  197.         html: option.buttons.paragraph.html,
  198.         title: 'neuer Absatz',
  199.         'data-toggle': 'tooltip'
  200.         }).appendTo(btnGroup);
  201.  
  202.         if ( markedFound && ! option.livePreview )
  203.         {
  204.         buttons.preview = $('<button>', {
  205.             class: option.buttons.preview.btnClass,
  206.             html: option.buttons.preview.html,
  207.             title: 'Vorschau',
  208.             'data-toggle': 'tooltip',
  209.             click: showPreview
  210.         }).appendTo(btnGroup);
  211.  
  212.         }
  213.  
  214.  
  215.     }
  216.  
  217.     function showPreview( e )
  218.     {
  219.         e.preventDefault();
  220.         buildModalPreview();
  221.     }
  222.  
  223.     function buildModalPreview()
  224.     {
  225.         if ( $('#modal_wc_textarea_preview').length )
  226.         {
  227.         $('#modal_wc_textarea_preview').modal('hide');
  228.         }
  229.  
  230.         let modal = $('<div>', {
  231.         id: 'modal_wc_textarea_preview',
  232.         class: 'modal',
  233.         tabindex: - 1,
  234.         'data-backdrop': 'static',
  235.         role: 'dialog',
  236.         html: [
  237.             '<div class="modal-dialog" role="document">',
  238.             '<div class="modal-content rounded-0">',
  239.             '<div class="modal-body" style="max-height:80vh; overflow-y:auto">',
  240.             marked(vars.value) || 'Es wurde kein Inhalt für die Vorschau gefunden.',
  241.             '</div>',
  242.             '<div class="modal-footer border-0 text-left">',
  243.             '<button type="button" class="btn btn-default btn-block rounded-0" data-dismiss="modal">Schließen</button>',
  244.             '</div>',
  245.             '</div>',
  246.             '</div>'
  247.         ].join('')
  248.         }).appendTo('body');
  249.  
  250.         modal.on('hidden.bs.modal', function ()
  251.         {
  252.         modal.remove();
  253.         });
  254.  
  255.         modal.modal('show');
  256.     }
  257.  
  258.     function buildCounters()
  259.     {
  260.         let counter = $('<div>', { class: 'd-flex justify-content-end text-muted', css: { 'position': 'absolute', right: '20px', bottom: '1px', background: 'white' } }).insertAfter(textarea);
  261.         counters.lines = $('<small>', { class: 'ml-2' }).appendTo(counter);
  262.         counters.paragraphs = $('<small>', { class: 'ml-2' }).appendTo(counter);
  263.         counters.words = $('<small>', { class: 'ml-2' }).appendTo(counter);
  264.         counters.characters = $('<small>', { class: 'ml-2' }).appendTo(counter);
  265.         counters.selected = $('<small>', { class: 'ml-2' }).appendTo(counter);
  266.         textarea.css('padding-bottom', '20px');
  267.     }
  268.  
  269.     function setData( e )
  270.     {
  271.         vars.value = textarea.val();
  272.         vars.start = textarea.prop('selectionStart');
  273.         vars.end = textarea.prop('selectionEnd');
  274.  
  275.         vars.selectedLength = vars.end - vars.start;
  276.         vars.selectedText = vars.value.substr(vars.start, vars.selectedLength);
  277.         vars.length = vars.value.length;
  278.  
  279.         vars.lines = ! vars.length ? 0 : vars.value.split(lineSplittPattern).length;
  280.  
  281.         vars.words = 0;
  282.         let parapgraphs = 0;
  283.         if ( vars.length )
  284.         {
  285.         let lines = vars.value.split(lineSplittPattern);
  286.         for ( let i = 0; i < lines.length; i ++ )
  287.         {
  288.             vars.words += lines[i].trim().replace(/\s\s+/g, ' ').split(' ').length;
  289.             if ( lines[i].length )
  290.             {
  291.             parapgraphs ++;
  292.             }
  293.         }
  294.         }
  295.  
  296.         counters.lines.text(vars.lines + ( vars.lines === 1 ? ' Zeile' : ' Zeilen' ));
  297.         counters.paragraphs.text(parapgraphs + ( parapgraphs === 1 ? ' Absatz' : ' Absätze' ));
  298.         counters.words.text(vars.words + ( vars.words === 1 ? ' Wort' : ' Wörter' ));
  299.         counters.characters.text(vars.length + ' Zeichen');
  300.         counters.selected.text(vars.selectedLength + ' markiert');
  301.  
  302.         if ( markedFound && option.livePreview && $(option.livePreview).length )
  303.         {
  304.         $(option.livePreview).html(marked(vars.value));
  305.         }
  306.  
  307.  
  308.  
  309.     }
  310.  
  311.     function setEvents()
  312.     {
  313.         textarea
  314.         .on('keyup change mousedown touchstart touchend mouseup focusIn click', setData)
  315.         .on('mouseenter', function ()
  316.         {
  317.  
  318.         })
  319.         .on('mouseleave', function ()
  320.         {
  321.  
  322.         });
  323.  
  324.         buttons.bold.on('click', function ( e )
  325.         {
  326.         e.preventDefault();
  327.         wrapWith('**');
  328.         });
  329.         buttons.italic.on('click', function ( e )
  330.         {
  331.         e.preventDefault();
  332.         wrapWith('_');
  333.         });
  334.         buttons.ul.on('click', function ( e )
  335.         {
  336.         e.preventDefault();
  337.         setUl();
  338.         });
  339.         buttons.ol.on('click', function ( e )
  340.         {
  341.         e.preventDefault();
  342.         setOl();
  343.         });
  344.         buttons.link.on('click', function ( e )
  345.         {
  346.         e.preventDefault();
  347.         buildModalLink();
  348.         });
  349.  
  350.         buttons.picture.on('click', function ( e )
  351.         {
  352.         e.preventDefault();
  353.         buildModalPicture();
  354.         });
  355.  
  356.         buttons.codeInline.on('click', function ( e )
  357.         {
  358.         e.preventDefault();
  359.         wrapWith('`');
  360.         });
  361.  
  362.         for ( let i = 1; i <= 6; i ++ )
  363.         {
  364.         buttons['h' + i].on('click', function ( e )
  365.         {
  366.             e.preventDefault();
  367.             setMultiLineStart('#'.repeat(i) + ' ');
  368.         });
  369.         }
  370.  
  371.         buttons.quote.on('click', function ( e )
  372.         {
  373.         e.preventDefault();
  374.         setMultiLineStart('> ');
  375.         });
  376.  
  377.         buttons.paragraph.on('click', function ( e )
  378.         {
  379.         e.preventDefault();
  380.         setSingleLineEnd('\n');
  381.         });
  382.  
  383.     }
  384.  
  385.     function buildModalLink()
  386.     {
  387.         if ( $('#modal_wc_textarea_link').length )
  388.         {
  389.         $('#modal_wc_textarea_link').modal('hide');
  390.         }
  391.  
  392.         let modal = $('<div>', {
  393.         id: 'modal_wc_textarea_link',
  394.         class: 'modal',
  395.         tabindex: - 1,
  396.         'data-backdrop': 'static',
  397.         role: 'dialog',
  398.         html: [
  399.             '<div class="modal-dialog" role="document">',
  400.             '<div class="modal-content rounded-0">',
  401.             '<form>',
  402.             '<div class="modal-body" style="max-height:80vh; overflow-y:auto">',
  403.             '<div class="form-group">',
  404.             '<label class="control-label">URL</label>',
  405.             '<input type="text" name="url" class="form-control" placeholder="https://..." value="' + vars.selectedText + '" required>',
  406.             '</div>',
  407.             '<div class="form-group">',
  408.             '<label class="control-label">Link Text</label>',
  409.             '<input type="text" name="name" class="form-control" placeholder="angezeigter Name" required>',
  410.             '</div>',
  411.             '<div class="form-group">',
  412.             '<label class="control-label">Tooltip</label>',
  413.             '<input type="text" name="tooltip" class="form-control" placeholder="Tooltip">',
  414.             '</div>',
  415.             '</div>',
  416.             '<div class="modal-footer border-0">',
  417.             '<button type="button" class="btn btn-default rounded-0" data-dismiss="modal">Abbrechen</button>',
  418.             '<button type="submit" class="btn btn-success rounded-0">Einfügen</button>',
  419.             '</div>',
  420.             '</form>',
  421.             '</div>',
  422.             '</div>'
  423.         ].join('')
  424.         }).appendTo('body');
  425.  
  426.         modal.find('form').on('submit', function ( e )
  427.         {
  428.         e.preventDefault();
  429.         setLink($(this).find('[name="url"]').val(), $(this).find('[name="name"]').val(), $(this).find('[name="tooltip"]').val());
  430.         modal.modal('hide');
  431.         });
  432.  
  433.         modal.on('hidden.bs.modal', function ()
  434.         {
  435.         modal.remove();
  436.         });
  437.  
  438.         modal.modal('show');
  439.     }
  440.  
  441.     function buildModalPicture()
  442.     {
  443.         if ( $('#modal_wc_textarea_picture').length )
  444.         {
  445.         $('#modal_wc_textarea_picture').modal('hide');
  446.         }
  447.  
  448.         let modal = $('<div>', {
  449.         id: 'modal_wc_textarea_picture',
  450.         class: 'modal',
  451.         tabindex: - 1,
  452.         'data-backdrop': 'static',
  453.         role: 'dialog',
  454.         html: [
  455.             '<div class="modal-dialog" role="document">',
  456.             '<div class="modal-content rounded-0">',
  457.             '<form>',
  458.             '<div class="modal-body" style="max-height:80vh; overflow-y:auto">', '<div class="form-group">',
  459.             '<label class="control-label">Bild URL</label>',
  460.             '<input type="text" name="src" class="form-control" placeholder="https://Bild.url" value="' + vars.selectedText + '" required>',
  461.             '</div>',
  462.             '<div class="form-group">',
  463.             '<label class="control-label">Alternativ Text</label>',
  464.             '<input type="text" name="alt" class="form-control" placeholder="Alternativ Text" required>',
  465.             '</div>',
  466.             '</div>',
  467.             '<div class="modal-footer border-0">',
  468.             '<button type="button" class="btn btn-default rounded-0" data-dismiss="modal">Abbrechen</button>',
  469.             '<button type="submit" class="btn btn-success rounded-0">Einfügen</button>',
  470.             '</div>',
  471.             '</form>',
  472.             '</div>',
  473.             '</div>'
  474.         ].join('')
  475.         }).appendTo('body');
  476.  
  477.         modal.find('form').on('submit', function ( e )
  478.         {
  479.         e.preventDefault();
  480.         setPicture($(this).find('[name="src"]').val(), $(this).find('[name="alt"]').val());
  481.         modal.modal('hide');
  482.         });
  483.  
  484.         modal.on('hidden.bs.modal', function ()
  485.         {
  486.         modal.remove();
  487.         });
  488.  
  489.         modal.modal('show');
  490.     }
  491.  
  492.     function setPicture( url, alternativeText )
  493.     {
  494.         if ( ! url )
  495.         {
  496.         return false;
  497.         }
  498.  
  499.         let startWithSpace = vars.selectedLength.length && vars.selectedLength.startsWith(' ');
  500.         let linktext = ( startWithSpace ? ' ' : '' ) + '![' + alternativeText + '](' + url + ')';
  501.  
  502.         textarea.val(vars.value.slice(0, vars.start) + linktext + vars.value.slice(vars.end));
  503.         textarea.focus();
  504.         textarea.trigger('change');
  505.     }
  506.  
  507.     function setLink( url, title, tooltip )
  508.     {
  509.         let startWithSpace = vars.selectedLength.length && vars.selectedLength.startsWith(' ');
  510.  
  511.         if ( ! ( url || title ) )
  512.         {
  513.         return false;
  514.         }
  515.  
  516.         if ( ! url.startsWith('http') )
  517.         {
  518.         url = '//' + url;
  519.         }
  520.  
  521.         let linktext = ( startWithSpace ? ' ' : '' ) + '[' + title + '](' + url + ' "' + tooltip + '")';
  522.  
  523.         textarea.val(vars.value.slice(0, vars.start) + linktext + vars.value.slice(vars.end));
  524.         textarea.focus();
  525.         textarea.trigger('change');
  526.  
  527.     }
  528.  
  529.     function setUl()
  530.     {
  531.         let selectedLines = getLineNumForSelection(),
  532.         lines = getLines(selectedLines.start, selectedLines.end),
  533.         result = [ ],
  534.         line;
  535.         for ( let i = 0, currLine = selectedLines.start; i < lines.length; i ++, currLine ++ )
  536.         {
  537.         line = lines[i]
  538.             .replace(/^\d+./, '')
  539.             .replace('-', '')
  540.             .trim();
  541.         lines[i] = '- ' + line;
  542.         result[currLine] = lines[i];
  543.         }
  544.         textarea.val(replaceLines(result));
  545.         textarea.trigger('change');
  546.     }
  547.     function setOl()
  548.     {
  549.         let selectedLines = getLineNumForSelection(),
  550.         lines = getLines(selectedLines.start, selectedLines.end),
  551.         result = [ ],
  552.         line;
  553.         for ( let i = 0, number = 1, currLine = selectedLines.start; i < lines.length; i ++, number ++, currLine ++ )
  554.         {
  555.         line = lines[i].replace(/^\d+./, '').replace('-', '').trim();
  556.         lines[i] = number + '. ' + line;
  557.         result[currLine] = lines[i];
  558.         }
  559.         textarea.val(replaceLines(result));
  560.         textarea.trigger('change');
  561.     }
  562.  
  563.     /**
  564.      * Holt die komplette Zeile als Zeichenkette
  565.      * @param {Integer} lineNum
  566.      * @returns {String}
  567.      */
  568.     function getLineByNumber( lineNum )
  569.     {
  570.         return vars.value.split(lineSplittPattern)[lineNum - 1];
  571.     }
  572.  
  573.     /**
  574.      * Holt die Zeilen die markiert worden sind
  575.      * @param {Integer} start
  576.      * @param {Integer} end
  577.      * @returns {Array}
  578.      */
  579.     function getLines( start, end )
  580.     {
  581.         let allLines = vars.value.split(lineSplittPattern);
  582.         let linesSelected = [ ];
  583.         for ( let i = 0; i < allLines.length; i ++ )
  584.         {
  585.         if ( ( i >= ( start - 1 ) ) && ( i <= ( end - 1 ) ) )
  586.         {
  587.             linesSelected.push(allLines[i]);
  588.         }
  589.         }
  590.         return linesSelected;
  591.     }
  592.  
  593.     function addParagraphBefore( )
  594.     {
  595.         let cache = getLineNumForSelection();
  596.         let lineNum = cache.start;
  597.         let line = getLineByNumber(lineNum);
  598.         textarea.val(replaceLine(lineNum, '\n' + line));
  599.         textarea.trigger('change');
  600.         return cache;
  601.     }
  602.  
  603.     /**
  604.      * Ersetzt eine Zeile und gibt die komplette Zeichenkette wieder zurück
  605.      * @param {Integer} lineNum
  606.      * @param {String} line
  607.      * @returns {String}
  608.      */
  609.     function replaceLine( lineNum, line )
  610.     {
  611.         let newLines = [ ];
  612.         let lines = vars.value.split(lineSplittPattern);
  613.         for ( let i = 0; i < lines.length; i ++ )
  614.         {
  615.         if ( i === ( lineNum - 1 ) )
  616.         {
  617.             newLines.push(line);
  618.         } else
  619.         {
  620.             newLines.push(lines[i]);
  621.         }
  622.         }
  623.  
  624.         return newLines.join('\n');
  625.  
  626.     }
  627.  
  628.     function replaceLines( replacedlines )
  629.     {
  630.  
  631.         let lines = vars.value.split(lineSplittPattern);
  632.         for ( let i = 0; i < lines.length; i ++ )
  633.         {
  634.         for ( let line in replacedlines )
  635.         {
  636.             if ( line - 1 === i )
  637.             {
  638.             lines[i] = replacedlines[line];
  639.             }
  640.         }
  641.         }
  642.  
  643.         return lines.join('\n');
  644.  
  645.     }
  646.  
  647.     function setMultiLineStart( str )
  648.     {
  649.         // Hole die Zeilen die betroffen sind
  650.         let selectedLines = getLineNumForSelection(),
  651.         lines = getLines(selectedLines.start, selectedLines.end),
  652.         result = [ ];
  653.  
  654.         for ( let i = 0, currLine = selectedLines.start; i < lines.length; i ++, currLine ++ )
  655.         {
  656.         // wen die Zeile bereits mit dem gewünschtem Zeichen anfängt, säubere die Zeile
  657.         while ( lines[i].startsWith(str[0]) )
  658.         {
  659.             lines[i] = lines[i].substring(1).trim();
  660.         }
  661.  
  662.         lines[i] = str + lines[i].trim();
  663.         result[currLine] = lines[i];
  664.         }
  665.  
  666.         // ersetze die alte mit der neuen Zeile
  667.         textarea.val(replaceLines(result));
  668.         // cursor zurück in die Textarea setzen
  669.         textarea.focus();
  670. //
  671. //      let cursorAt = vars.start + str.length;
  672. //      textarea
  673. //      .prop('selectionStart', cursorAt)
  674. //      .prop('selectionEnd', cursorAt);
  675.  
  676.  
  677.  
  678.         textarea.trigger('change');
  679.     }
  680.  
  681.     function setSingleLineEnd( str )
  682.     {
  683.         let lineNum = getLineNumForSelection().end,
  684.         line = getLineByNumber(lineNum) + str;
  685.  
  686.         textarea.val(replaceLine(lineNum, line));
  687.         textarea.trigger('change');
  688.  
  689.     }
  690.     function setSingleLineStart( str )
  691.     {
  692.         let lineNum = getLineNumForSelection().start,
  693.         line = getLineByNumber(lineNum);
  694.  
  695.         while ( line.startsWith(str[0]) )
  696.         {
  697.         line = line.substring(1);
  698.         }
  699.  
  700.         line = str + line.trim();
  701.  
  702.         textarea.val(replaceLine(lineNum, line));
  703.         textarea.trigger('change');
  704.  
  705.     }
  706.  
  707.     function wrapWith( str )
  708.     {
  709.         let txt = str + vars.selectedText.split(str).join("").trim() + str;
  710.         textarea.val(vars.value.slice(0, vars.start) + txt + vars.value.slice(vars.end));
  711.         textarea.focus();
  712.         if ( vars.selectedLength )
  713.         {
  714.         let cursorAt = vars.start + txt.length;
  715.         textarea.prop('selectionStart', cursorAt);
  716.         textarea.prop('selectionEnd', cursorAt);
  717.         } else
  718.         {
  719.         let cursorAt = vars.start + str.length;
  720.         textarea.prop('selectionStart', cursorAt);
  721.         textarea.prop('selectionEnd', cursorAt);
  722.         }
  723.         textarea.trigger('change');
  724.     }
  725.  
  726.     function getLineNumForSelection()
  727.     {
  728.         return {
  729.         'start': vars.value.substr(0, textarea.prop('selectionStart')).split(lineSplittPattern).length,
  730.         'end': vars.value.substr(0, textarea.prop('selectionEnd')).split(lineSplittPattern).length
  731.         };
  732.     }
  733.  
  734.     function init()
  735.     {
  736.         buildButtons();
  737.         buildCounters();
  738.         setEvents();
  739.         wrapper.find('[data-toggle="tooltip"]').tooltip();
  740.  
  741.         textarea.trigger('change');
  742.  
  743.  
  744.         return textarea;
  745.     }
  746.  
  747.  
  748.     return init();
  749.     };
  750. }(jQuery) );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement