JXA: Reading/Using Data from the Clipboard

Rob, thanks for posting this JXA script. I always learn a lot from your scripts.

When I was testing it and trying to understand how it worked, I ran across this bug:
Your test for valid strClip fails if only an image is on the clipboard.

Here's a small snippet from your script:

var a = Application.currentApplication(),
        sa = (a.includeStandardAdditions = true, a),
        strClip = sa.theClipboard();

    if (strClip) 

The (strClip) returns true if there is only an object (and no text) on the clipboard.

Here's a test script you can run to verify this:

'use strict';

var app = Application.currentApplication()
app.includeStandardAdditions = true

//--- COPY ONLY AN IMAGE TO CLIPBOARD ---
//      Then run this script

var clipStr = app.theClipboard();

//--- This is NOT a valid test for the variable containing text ---
//    It also returns true if the variable is an object, like an
//    image on the clipboard.

if (clipStr) {
  console.log ("'clipStr IS TRUE'")
  console.log(typeof clipStr)
}

//---RESULTS---
/* 'clipStr IS TRUE' */
/* object */

Here is a revised script that fixes this issue, as well as adds some comments to help those like me who are still learning JXA.

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  SAVE TEXT ON CLIPBOARD TO FILE
  ------------------------------
  Ver: 2.0    2016-05-11
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DATE:   May 11, 2016
AUTHOR: Ver 1:  Rob Trew (@ComplexPoint)
        Ver 2:  JMichaelTX
        
CHANGE LOG:

  • Ver 2    2016-05-11 17:49 CT    JMichaelTX
      • Fixed issue where image only on clipboard caused script to fail.
      • Added return if no text was found, to indicate error.
      • Added clarity to code by decompressing some statements, and adding comments
      
REF:
  • Copy to New TXT File? - general - Keyboard Maestro Discourse
  • https://forum.keyboardmaestro.com/t/copy-to-new-txt-file/3689/2
  
REQUIREMENTS:
  • Use first line as file name
  • Save as TEXT file.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

function run() {
 
    var app = Application.currentApplication()
    app.includeStandardAdditions = true

        
    //--- READ CLIPBOARD ---
    var clipStr = app.theClipboard();

    //--- IF TEXT WAS FOUND ON CLIPBOARD, THEN PROCESS ---
    
    if (typeof clipStr === "string") {
    
      //--- SPLIT TEXT BY LINE INTO ARRAY ---
        var clipArray = clipStr.split(/[\n\r]/)
        
        var numLines = clipArray.length
        
      //--- GET FIRST LINE TO USE AS FILE NAME ---  
        var fileNameStr = numLines > 1 ? clipArray[0] : undefined
        
      //--- JOIN REMAINDER OF ELEMENTS INTO STRING FOR FILE CONTENTS ---
        var fileContentsStr = fileNameStr ? clipArray.slice(1).join('\n') : undefined;

      //--- ASK USER FOR FILE NAME/PATH ---
        if (fileContentsStr) {
        
          //--- ACTIVE CURRENT APP TO DISPLAY DIALOG ---
          app.activate
        
            var outputFilePathStr = (app.chooseFileName({
                    withPrompt: 'Save As',
                    defaultName: fileNameStr + '.txt'
                    })
              ).toString();

          //--- OUTPUT TO SELECTED FILE ---
            writeFile(outputFilePathStr, fileContentsStr);
          
            return (outputFilePathStr);
        }
    }  // END if (clipStr)
    
    else {
      return ("ERROR - No text was found on clipboard")
    }
    
    //~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~~~
    
     //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    function writeFile(pOutputFilePathStr, pFileContentsStr) {
      // writeFile :: FilePath -> String -> IO ()

        $.NSString.alloc.initWithUTF8String(pFileContentsStr)
            .writeToFileAtomicallyEncodingError(
                pOutputFilePathStr, true,
                $.NSUTF8StringEncoding, null
            );
    }  // END function writeFile()
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

}  // END function run()