Wrap selection in HTML tag command


#1

Hello,

I created a command in my init.coffee script to wrap text in an html a tag with a target=“blank” attribute:

wrapSelection = (selection, before, after) ->
  after ?= before
  selectedText = selection.getText()
  selection.insertText("#{before}#{selectedText}#{after}")

atom.commands.add 'atom-text-editor',
  'custom:wrap-with-a-tag', ->
    editor = @getModel()
    editor.transact ->
      wrapSelection(selection, "<a href = \"\" target=\"blank\">", "</a>") for selection in editor.getSelections()

I found instructions for something similar to this on a forum that I can no longer find. Anyway, I have two questions. First, is there a way to modify the command so that my cursor winds up between the quotes after href? Right now, cursor goes after the closing tag when I run the command.

Second, can anyone tell me how to create a command that would move cursor to beginning of document and insert some text?

Needless to say, I’m not a coder. I use Atom for web stuff.

Thanks so much for your help.


Snippet to add tags to current selection?
#2

I changed it so you can put a $1 anywhere in the before string and it will place the cursor there after inserting the text. If $1 is not found it will place the cursor right after the before string.

wrapSelections = (editor, before, after) ->
  after ?= before
  cursorOffset = before.indexOf '$1'
  if cursorOffset < 0 then cursorOffset = before.length

  cursorPositions = for selection in editor.getSelections()
    cursorPosition = selection.getBufferRange().start.translate [0, cursorOffset]
    selectedText = selection.getText()
    selection.insertText("#{before.replace '$1', ''}#{selectedText}#{after}")
    cursorPosition

  for cursorPosition, i in cursorPositions
    if i == 0
      editor.setCursorBufferPosition cursorPosition
    else
      editor.addCursorAtBufferPosition cursorPosition

atom.commands.add 'atom-text-editor', 'custom:wrap-with-a-tag', ->
  editor = @getModel()
  editor.transact ->
    wrapSelections editor, '<a href="$1" target="blank">', '</a>'

To insert some text at the beginning of the document you can use

editor.setTextInBufferRange [[0, 0], [0, 0]], 'some text'

#3

Super cool! Thank you so much!


#4

One more question. I’d like to add a line to the wrapSelections function to break my selection into lines. That way, I could create a command to, say, wrap list items on different lines in

  • tags.

    I found splitSelectionsIntoLines in the API and tried adding both

    selection.splitSelectionsIntoLines()
    

    and

    selectedText.splitSelectionsIntoLines() 
    

    to your code, but Atom keeps insisting those aren’t functions. If this is an easy fix, would you mind telling me what I’m doing wrong?


  • Is there any Atom Package Available for HTML formatting with keyboard shortcuts?
    #5

    splitSelectionsIntoLines is actually a method on the TextEditor class, so try editor.splitSelectionsIntoLines() right before cursorPositions = ... :slight_smile:


    #6

    Works perfectly. Thanks so much! Let me know if you ever need a professional editor’s eye on something.


    #7

    You’re welcome, happy to help :smile: It’s a pretty useful script, I’m probably going to use this myself!

    I made some changes, by the way. You can now define for each command separately whether it should split the selections or not. It also fixes an issue when no after is supplied and there is a $1 in the before that wouldn’t be replaced in the after.

    # set multiLine to false to split selections into single line
    wrapSelections = (editor, before, after, multiLine = true) ->
      cursorOffset = before.indexOf '$1'
      cursorOffset = before.length if cursorOffset < 0
      before = before.replace '$1', ''
      after ?= before
    
      editor.transact ->
        editor.splitSelectionsIntoLines() unless multiLine
      
        cursorPositions = for selection in editor.getSelections()
          cursorPosition = selection.getBufferRange().start.translate [0, cursorOffset]
          selection.insertText("#{before}#{selection.getText()}#{after}")
          cursorPosition
    
        for cursorPosition, i in cursorPositions
          if i == 0
            editor.setCursorBufferPosition cursorPosition
          else
            editor.addCursorAtBufferPosition cursorPosition
    
    # multiLine disabled for <a> tags
    atom.commands.add 'atom-text-editor', 'custom:wrap-with-a-tag', ->
      wrapSelections @getModel(), '<a href="$1" target="blank">', '</a>', false
    
    # multiLine enabled for <p> tags
    atom.commands.add 'atom-text-editor', 'custom:wrap-with-p-tag', ->
      wrapSelections @getModel(), '<p>', '</p>'
    

    #8

    I retitled the topic to make it more searchable. Hope you don’t mind.


    #9

    Hmm looks like coffee.init is failing to load with this new version, and throwing up an error: “editor not defined.”

    What’s the advantage of disabling splitSelectionsIntoLines? Looks like it doesn’t do anything if you don’t have more than one line selected, so all the span-like wrapping commands (strong, em, a tags) work just as you’d expect them to even if we don’t disable the splitSelectionsIntoLines for them.


    #10

    The advantage is that one can easily define multiple commands, some disabling multiline, some not. I disable it when I want to wrap a bunch of <p>s into a <section>.

    The script works fine for me, by the way :confused: Did you also copy the new command definitions?