Friday, December 23, 2011

TextWrangler Saved Pattern Reordering

TextWrangler has the ability to save your search-and-replace regular expressions.

You can usually find this by opening the Find/Search dialog (Command-F) and notice the 'g' dropdown on the right:



As of TextWrangler 3.5.3 (2890), there is no method for reordering these saved search patterns.

I have found that I want my most-recently added patterns near the top, since I intend on using them most frequently.  In order to do this, you need to open an XML file which contains these values:

$HOME/Library/Preferences/com.barebones.textwrangler.PreferenceData/Grep Patterns.xml

Here, you'll find an array of <dict> entries. For example, I have:


<dict>
  <key>ReplacePattern</key>
  <string></string>
  <key>SearchPattern</key>
  <string>(?&lt;![ \t\r])[ \t]+$</string>
  <key>Title</key>
  <string>Trailing Spaces</string>
  <key>UniqueID</key>
  <string>BD891F29-F04A-4951-B66C-40CE64A590FD</string>
 </dict>
<dict>
<key>ReplacePattern</key>
<string>\1 \(</string>
<key>SearchPattern</key>
<string>\b(if|for|while|switch)\(</string>
<key>Title</key>
<string>Space if|for|while|switch</string>
<key>UniqueID</key>
<string>6555C867-BBF4-4DC3-B2C0-B51EA7B64486</string>
</dict>


To rearrange them in TextWrangler, simply rearrange the entire <dict>...</dict> sections as you prefer and save!

Update 2012-02-09:

If you have access to a plist editor (free with Apple's Xcode or other alternatives online), this XML plist format can be rearranged with those tools a little safer. Find one that accepts simple drag-and-drop and you're set!

Tuesday, June 28, 2011

Windows and Mac: Custom Ringtones in iTunes 10

If you are a Mac user and wanted to create your own ringtones in iTunes 10, you may have searched online and found online guides, such as OSXdaily.com, which walk you through the process of clipping your song, renaming the file in Finder, etc.

If you are a Windows user, the steps are essentially the same but you may not be able to see the file extension by default. Here are a few steps that may help:

  1. From the Microsoft article, you will need to show filename extensions (so you can see the ".txt" or ".mp3" extension on your files)
  2. Load your song into iTunes. This can be music you imported from your CDs, downloaded online, or even sound bytes you made yourself.
  3. Following the same steps from the article above, you essentially select the song in iTunes, then use "Get Info". You can right-click (or Control-click on a Mac, if right-click isn't working) the song OR click on the Edit menu at the top of iTunes to find the "Get Info" option.
  4. When you are looking at the tabs within the "Get Info" screen, click on the tab named Options. You should see something that shows a "Start Time" (and a checkbox next to it) as well as "Stop Time" (and a checkbox next to that).
  5. Select a timeframe of music that you would like to "clip" and save as your ringtone. You should keep it under about 35 seconds (less is fine, more is not).
  6. Make sure that both the "Start Time" and "Stop Time" checkboxes are checked and hit OK
  7. It will look like nothing has happened, which is fine.
  8. Right-click (or Control-click on a Mac) the song you just modified. About halfway down the menu you see will says "Create AAC Version".
    Note: if you don't see "Create AAC Version" but it has a different format in there, such as "Create MP3 Version", you need to change some of your settings in iTunes. Open iTunes preferences (usually under Edit|Preferences, or iTunes|Preferences on a Mac) and select the General tab (if it is not selected already). Next to "When you insert a CD:" you see a dropdown menu as well as an "Import Settings..." button. Click that "Import Settings..." button and change the "Import Using:" from "MP3 Encoder" (or whatever other format is listed) to "AAC Encoder" and hit OK for this screen, as well as for the Preferences window behind it. Now repeat this step of right-clicking and selecting "Create AAC Version".
  9. This will create a duplicate entry of your song (album artwork and everything, if you have any), but the "Time" category will show the "cropped" time.
  10. Right-click the same song (the original larger, not new "smaller", one) and uncheck the "Start Time" and "Stop Time" settings, else the songs will not play normally for their full lengths.
  11. Now, working with the new, smaller file, right-click (Mac: Control-click) the song and choose "Show in Explorer" (Mac: "Show in Finder"). It should open the file location where your music is stored.
  12. At this stage, you are going to be switching back and forth between two different windows for a bit. This is what is happening and why you'll switch between the windows:
    1. iTunes sees the new song in its library
    2. You see the new song on the hard drive in that second window
    3. You are going to rename a part of the new song's name and iTunes will no longer be able to access it
    4. iTunes will not remove the name out of the iTunes Library just because the file is "no longer there" and will give you some problems when you try to re-add the file
    5. You are going to remove the new song from the iTunes library, change the song's file name in the other window, then add that file back into iTunes
  13. In iTunes, right-click the new song's name and choose "Delete" near the bottom. It will prompt you for two things:
    1. Do you want to remove this song from your library? (YES, you do want to remove it from your library)
    2. Do you want to remove this song from the hard drive (or in other words, keep this file, or put it in the Recycle/Trash bin? (NO, you do not want to remove it -- or YES you want to keep the file)
  14. In Windows Explorer (Mac: Finder), the file's extension will say ".m4a". You will replace this with ".m4r". You will be prompted whether you want to change the file extension (YES, you want to change it). This changes it from an ".m4audio" file to an ".m4ringtone" file.
  15. Drag the new song (with the new .m4r extension) from the Windows Explorer (Mac: Finder) window and drop it onto the iTunes library.

This new ringtone should now appear in the left column of iTunes under the Ringtones category, which can now be sent to your iPhone.

If you find any omissions or errors with this, please let me know and I'll be happy to update the information.

Sunday, June 5, 2011

Javascript autocomplete



Searching for "javascript autocomplete" yielded many results. I just wanted to link to one that I thought was just AMAZING. With minimal tweaks, it can be dropped into its own .js file for inclusion of your own files:

http://simpleandeasycodes.blogspot.com/2009/03/javascript-simple-autocomplete-textbox.html

UPDATE:
The source code for this project can be found here:http://www.codeproject.com/KB/scripting/jsactb.aspx. The original link appears to be identical code, except that the variable names have been changed from "actb*" to "saec*". Let's give credit where credit's due (and preserve a valid copyright notice at the time), huh?.


Step 1) Move the "var customarray = new Array (...);" out of the file. You'll be generating this yourself anyway.

Step 2) Create your own custom array of strings in a file.

Step 3) Tweak a few settings at the top of actb() to your liking (they are the ones under "Public Variables") such as delimiter, firstText, etc.

Step 4) Optional: Within the actb_checkkey() function, add one more case statement before default:

   case 27:                      // Escape key
      actb_mouse_on_list = 0;
      actb_removedisp();
      return false;
      break;





This way, if someone is typing something and does NOT want the autocomplete, they can hit the ESC key to close the autocomplete window (else they'll hit TAB or ENTER and the auto-suggested word will overwrite their entry).

Next, in your HTML, initialize the class by calling actb() on the field you want. It takes two arguments: the ID of the input field (a text or textarea), and the string array you created in Step 2. Start typing, and you'll have your own results.

One thing I like to use it for is to create a list of names found in an SQL database. Use PHP (or some other server-side language) to create a Javascript array of those names, and then allow the user search through those names with the autocomplete feature.

This script looks like it took the author quite a while to complete. Good job on an excellent piece of code!

Wednesday, June 1, 2011

Useful Javascript snippets: Get multiple selections in a SELECT


Scenario: You have an HTML <select> list like so:
<select id="idAuthors" multiple="true" name="authors" size="12">
    <optgroup label="C">
        <option>Cummings, E E</option>
    </optgroup>
    <optgroup label="S">
        <option>Shakespeare, William</option>
        <option>Steinbeck, John</option>
    </optgroup>
    <optgroup label="T">
        <option>Talmage, James E</option>
        <option>Tolkien, J R R</option>
        <option>Tolstoy, Leo</option>
        <option>Twain, Mark</option>
    </optgroup>
</select>
This gives you the following:

You can choose one or more of these names. However, if you use Javascript to show the element's selectedIndex, it will only give you the first result:
<script language="javascript" type="text/javascript">
    alert(document.getElementById('idAuthors').selectedIndex);
</script>
If you select Shakespeare, Talmage, and Twain, the only result you will see is Shakespeare, William.
Solution: Grab the first selectedIndex from the <select>, and store it into an array. Then, de-select that entry. The next call to selectedIndex will yield the next result, Talmage, James E. Add that one to your array, and remove it. Lather, rinse, repeat.
At the end, none of the items will be selected anymore. You may want to be nice and re-select them all so the user doesn't have to (that could get pretty annoying for the user).
With everything stored in the array, simply return that array (or a string concatenated with all of the array entries).
Below is a code snippet:
function find_selected(id_name, id_out)
{
    // Names of all selected items, before they are de-selected by this script
    var option_name = new Array();

    // Indices of all selected items
    var option_index = new Array();

    var obj = document.getElementById(id_name);

    // Save the name and index of each selected item, then de-select the item
    while (obj.selectedIndex != -1)
    {
        option_name.push(obj.options[obj.selectedIndex].text);
        option_index.push(obj.selectedIndex);
        obj.options[obj.selectedIndex].selected = false;
    }

    // All of the items have now been de-selected; re-select all of them
    for (i = 0; i < option_index.length; ++i)
    {
        obj.options[option_index[i]].selected = true;
    }

    // Return the list of all selected items
    document.getElementById(id_out).value = option_name.join(';');
}
Hopefully, the comments make everything clear. You may also notice that I store both the name and its index. Referencing the option's index prevents our code from just finding the first occurance of the name; it re-highlights the same ones that the user selected. Finally, if you wish, you could return the array itself, or change the delimiter between the results.
If you plan on submitting these values to your server, you may find that pushing the results into an <input type="hidden"/> will let you see each one that was selected, and respond appropriately.
For a complete code solution, try this out:
<html>
<head>
<script type="text/javascript" language="javascript">
/**
   Finds all selected items from `id_name' and outputs the list to `id_out'.
   An example could be:
     <select id="idTxt" multiple="true">
       <option>One</option>
       <option>Two</option>
       <option>Three</option>
     </select>
     <input type="hidden" id="idHid" value="" />
   You would call "find_selected('idTxt', 'idHid');"
   Anything that is selected within 'idTxt' will be added to the value of the
   hidden 'idHid' input.
 */
function find_selected(id_name, id_out)
{
    // Names of all selected items, before they are de-selected by this script
    var option_name = new Array();

    // Indices of all selected items
    var option_index = new Array();

    var obj = document.getElementById(id_name);

    // Save the name and index of each selected item, then de-select the item
    while (obj.selectedIndex != -1)
    {
        option_name.push(obj.options[obj.selectedIndex].text);
        option_index.push(obj.selectedIndex);
        obj.options[obj.selectedIndex].selected = false;
    }

    // All of the items have now been de-selected; re-select all of them
    for (i = 0; i < option_index.length; ++i)
    {
        obj.options[option_index[i]].selected = true;
    }

    // Return the list of all selected items
    document.getElementById(id_out).value = option_name.join(';');
}
</script>

<title>Selection Example</title></head>
<body>

<form action="" onsubmit="alert(document.getElementById('idSelection').value); return false;">

<input type="hidden" name="selection" id="idSelection" />

<select id="idAuthors" multiple="true" name="authors" size="12">
    <optgroup label="C">
        <option>Cummings, E E</option>
    </optgroup>
    <optgroup label="S">
        <option>Shakespeare, William</option>
        <option>Steinbeck, John</option>
    </optgroup>
    <optgroup label="T">
        <option>Talmage, James E</option>
        <option>Tolkien, J R R</option>
        <option>Tolstoy, Leo</option>
        <option>Twain, Mark</option>
    </optgroup>
</select>

<input type="submit" value="Submit" onclick="find_selected('idAuthors', 'idSelection');" />
<input type="reset" value="Reset" />

</form>

</body>
</html>

Useful SQL snippets: Resetting AUTO_INCREMENT

Scenario: You've created a table in SQL with an auto-incrementing identifier. You've got records 1-99 all entered and, for the most part, there are no "holes" where you've deleted any records. But then somehow, you add one more entry to the table and instead of assigning its ID to 100, the ID gets set to 150 (or some other value than you were expecting). How do you reset that?

Solution:
   ALTER TABLE your_table AUTO_INCREMENT=100;

Q: Is it guaranteed that SQL will increment at the number I specify, no matter what?

A: No. SQL is smart enough to first count your records, find the highest-used ID value, and then use the next one. If you have 100 records already, it will start at 101, even if you specify:
   ALTER TABLE your_table AUTO_INCREMENT=13;

This will NOT "fill in the gaps" if you have removed records in the middle of the recordset:

+----+-------------------------+---------------------+---------------------+
| Id | Name                    | Creation            | Modified            |
+----+-------------------------+---------------------+---------------------+
| 10 | Shakespeare, William    | 2011-05-30 23:05:43 | 2011-05-30 23:05:43 |
| 11 | Steinbeck, John         | 2011-05-30 23:05:43 | 2011-05-30 23:05:43 |
| 12 | Talmage, James E        | 2011-05-30 23:05:43 | 2011-05-30 23:05:43 |
| 15 | Tolkien, J R R          | 2011-05-30 23:05:43 | 2011-05-30 23:05:43 |
| 16 | Tolstoy, Leo            | 2011-05-30 23:05:43 | 2011-05-30 23:05:43 |
| 17 | Twain, Mark             | 2011-05-30 23:05:43 | 2011-05-30 23:05:43 |
+----+-------------------------+---------------------+---------------------+

Here, setting the AUTO_INCREMENT to 13 will NOT fill in records #13 or #14: it will start at 18 (after the last record).