<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>Two Mice and a Strawberry</title>
	<atom:link href="http://www.twomiceandastrawberry.com/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://www.twomiceandastrawberry.com/blog</link>
	<description>Data management, web apps, and the meaning of life</description>
	<pubDate>Wed, 12 May 2010 20:53:32 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>CiviCRM: &#8220;Individual Prefix&#8221; field as auto-complete text input</title>
		<link>http://www.twomiceandastrawberry.com/blog/46/civicrm-individual-prefix-field-as-auto-complete-text-input</link>
		<comments>http://www.twomiceandastrawberry.com/blog/46/civicrm-individual-prefix-field-as-auto-complete-text-input#comments</comments>
		<pubDate>Tue, 20 Apr 2010 01:45:00 +0000</pubDate>
		<dc:creator>Allen Shaw</dc:creator>
		
		<category><![CDATA[CiviCRM]]></category>

		<guid isPermaLink="false">http://www.twomiceandastrawberry.com/blog/?p=46</guid>
		<description><![CDATA[I recently had to modify CiviCRM to support a specific use case for a client.  In this project I needed to allow the user to enter anything in the Individual Prefix field, rather than choosing from a list of options.  The client in this case was very sensitive about presenting the individual's honorific precisely as the individual wants, so that "Dr.," "Rev. Dr.," and "Most Rt. Rev. Dr." should all be possible, along with anything else the user might want to enter.  ...

My solution was to implement a custom module ...]]></description>
			<content:encoded><![CDATA[<p><em class="note">Note: CiviCRM is a fantastic open-source software package for managing an organization&#8217;s contacts, targeted specifically at non-profit organizations.  You can learn more about it at <a href="http://CiviCRM.org">CiviCRM.org</a>.</em></p>
<p>I recently had to modify CiviCRM to support a specific use case for a client.  In this project I needed to allow the user to enter anything in the Individual Prefix field, rather than choosing from a list of options.<span id="more-46"></span>  The client in this case was very sensitive about presenting the individual&#8217;s honorific precisely as the individual wants, so that &#8220;Dr.,&#8221; &#8220;Rev. Dr.,&#8221; and &#8220;Most Rt. Rev. Dr.&#8221; should all be possible, along with anything else the user might want to enter.</p>
<p>To illustrate the scope of issue: out of the aprox. 20K records in the client&#8217;s existing database, there were over 400 distinct values for this field.  A select list that long is unwieldy in numerous ways, so we knew we&#8217;d have to come up with a solution before importing all those records to CiviCRM.</p>
<p>What I really wanted &#8212; and what the client  needed &#8212; was to present the &#8220;Individual Prefix&#8221; field as a text input that offers type-ahead auto-complete for a short list of preferred options, but still allows the user to enter whatever they want.</p>
<p>My solution was to implement a custom module which would use two <a href="http://wiki.civicrm.org/confluence/display/CRMDOC/CiviCRM+hook+specification">CiviCRM hooks</a>, hook_civicrm_buildForm and hook_civicrm_postProcess, to modify the field display and processing, and add a little custom JavaScript to provide the type-ahead effect.</p>
<p>A quick check on the incredibly helpful, active, and responsive <a href="http://forum.civicrm.org/">CiviCRM Forums</a> confirmed that my intended solution was probably a good one, so I created the module below.  Skip ahead if you just want the code.  In the mean time, a little explanation on why it does what it does:</p>
<p>In CiviCRM, the individual prefix is stored as an integer, not as text.  This number is value matching the unique ID of an item in CiviCRM&#8217;s list of individual prefixes, which are normally configured manually at <strong>Administer CiviCRM &gt; Option Lists &gt; Individual Prefixes</strong>.  Naturally CiviCRM already has a simple way of translating between this stored numeric value and the text that a user sees or enters; in the form for editing an individual contact, that translation happens with an HTML &lt;select&gt; element.<strong> </strong></p>
<p>For my modifications to work, the module has to be able to handle that translation itself.  To allow the user to enter any arbitrary text, the module must present the user with a text field instead of a &lt;select&gt; element.  That text field must be displayed in the right place in the form, and it must display the correct value when the form is first opened if the user is editing an existing contact.  When the form is submitted, the module has to accept whatever text the user has entered and match it to one of the items in CiviCRM&#8217;s list of individual prefixes &#8212; or, if no match exists, it has to add an item to the list and then use that value &#8212; and store the correct numeric value as the contact&#8217;s prefix.</p>
<p>Finally, at the client&#8217;s request, this text field needs to offer some kind of type-ahead auto-complete functionality to steer the user toward a short list of common prefixes.  This is accomplished with a simple JavaScript function triggered by the onKeyUp event.</p>
<h3>The module</h3>
<p>Here, then is the module.  I&#8217;ve included some lengthy notes in the code comments, explaining some of the unexpected turns I had to take to get the effect I was after.  <a href="#javascript">Jump below to see the JavaScript</a>.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #009933; font-style: italic;">/**
 * Project:     TwoMice CiviCRM modifications 
 * File: tmcivicrm.module
 */</span>
&nbsp;
&nbsp;
<span style="color: #009933; font-style: italic;">/**
 * Implementation of hook_civicrm_buildForm()
 */</span>
<span style="color: #000000; font-weight: bold;">function</span> tmcivicrm_civicrm_buildForm<span style="color: #009900;">&#40;</span><span style="color: #000088;">$formName</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>
        <span style="color: #000088;">$formName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'CRM_Contact_Form_Contact'</span> <span style="color: #339933;">&amp;&amp;</span>
        <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getElementType</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'prefix_id'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'select'</span>
    <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">/* For this form, we'll remove the existing &lt;select&gt; list for the
        Individual Prefix field and replace it with a text field,
        allowing the user to enter any value in this field. */</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">/* Get the text value for the existing prefix, if any
         */</span>
        <span style="color: #666666; font-style: italic;">/* First get the numeric value. getValue() returns an array, or
        NULL if there is no existing value */</span>
        <span style="color: #000088;">$values</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getElement</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'prefix_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getValue</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #666666; font-style: italic;">/* If there is any value for this field (as there will not be when
        adding a contact) */</span>
            <span style="color: #666666; font-style: italic;">/* Get the first element in the array; there should be only
            one anyway) */</span>
            <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>int<span style="color: #009900;">&#41;</span><span style="color: #000088;">$values</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #666666; font-style: italic;">/* Loop through the option lists to find one matching the
            numeric value, then use the text of that option as the text
            to display to the user. */</span>
            <span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getElement</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'prefix_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span>_options <span style="color: #b1b100;">as</span> <span style="color: #000088;">$option</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$option</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'attr'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'value'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">==</span> <span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$textVal</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$option</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'text'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                    <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Remove existing prefix_id field (&lt;select&gt;); we have no need of it.</span>
        <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">removeElement</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'prefix_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">/* Add a couple of new fields for the template.  Be sure to assign an
         * &quot;ID&quot; attribute, so they can be more easily accessed via JQuery in the
         * template.
         */</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Add a new prefix_id field, this time a text input.</span>
        <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addElement</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'text'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'prefix_id'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'Title'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'prefix_id'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">/* Set the value to any existing NUMERIC prefix value.  When the form is
        submitted, CiviCRM will be expecting this value as an integer and will
        use it to record the Individual Prefix.  See
        tmcivicrm_civicrm_postProcess() for how this works and how it is
        reconciled with what the user may type in. */</span>
        <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getElement</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'prefix_id'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValue</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>        
&nbsp;
        <span style="color: #666666; font-style: italic;">/* Add a hidden field, also containing any existing prefix_id text; We
        will use this in postProcess to check for changed values. */</span>
        <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">addElement</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'hidden'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'hidden_prefix_id_text'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">NULL</span><span style="color: #339933;">,</span>
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">'hidden_prefix_id_text'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getElement</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'hidden_prefix_id_text'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setValue</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$textVal</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">/* The ony form element we're NOT adding here is the one the user will
         * actually see.  Instead of adding it here, we use JQuery within the
         * template to append it in the correct location in the form.  This is
         * the only way we can do it without changing the template itself, since
         * the template is hard-coded to put in only specific form elements at
         * specific spots. Any new form elements we add here -- other than
         * hidden inputs -- will not make it into the template's HTML output.
         * See the template JavaScript for the code that inserts this element.
         */</span>
         <span style="color: #666666; font-style: italic;">// Insert the JavaScript file that will do the above-described magic.</span>
        drupal_add_js<span style="color: #009900;">&#40;</span>
            drupal_get_path<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'module'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'tmcivicrm'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">'/modules/tmcivicrm/js/Contact_Form_Contact.js'</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #009933; font-style: italic;">/**
 * Implementation of hook_civicrm_postProcess()
 *
 * This function performs additional handling of form inputs after CiviCRM has
processed the form.
 */</span>
<span style="color: #000000; font-weight: bold;">function</span> tmcivicrm_civicrm_postProcess<span style="color: #009900;">&#40;</span><span style="color: #000088;">$formName</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span><span style="color: #000088;">$form</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$formName</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'CRM_Contact_Form_Contact'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">/* Get the submitted prefix text and any existing prefix text, and
        compare to see if the prefix has changed. */</span>
        <span style="color: #000088;">$prefix</span> <span style="color: #339933;">=</span> CRM_Utils_Request<span style="color: #339933;">::</span><span style="color: #004000;">retrieve</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'prefix_id_text'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'String'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$form</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'REQUEST'</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$originalPrefix</span> <span style="color: #339933;">=</span> CRM_Utils_Request<span style="color: #339933;">::</span><span style="color: #004000;">retrieve</span><span style="color: #009900;">&#40;</span>
            <span style="color: #0000ff;">'hidden_prefix_id_text'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'String'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$form</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span>
            <span style="color: #0000ff;">'REQUEST'</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">/* If the prefix has changed, we'll need to do some work to update it.
         * If it hasn't changed, it's been saved correctly already, because
         * the form contained our the numeric value of the existing prefix in
         * the element prefix_id (added in tmcivicrm_civicrm_buildForm()).
         */</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$prefix</span> <span style="color: #339933;">&lt;&gt;</span> <span style="color: #000088;">$originalPrefix</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">/* Prefix has been changed. Get the correct numeric value for the
             * new prefix (creating a new Individual Prefix option list item if
             * necessary), and save the value in the contact record.
             */</span>
&nbsp;
            <span style="color: #666666; font-style: italic;">// We'll need this path below for including some files</span>
            <span style="color: #000000; font-weight: bold;">global</span> <span style="color: #000088;">$civicrm_root</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #666666; font-style: italic;">/* Search for the numeric value in case the option list item already
            exists, and store that as the new prefix numeric value. */</span>
            <span style="color: #000088;">$prefixValue</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span>
                <span style="color: #000088;">$prefix</span> <span style="color: #339933;">,</span>
                CRM_Core_PseudoConstant<span style="color: #339933;">::</span><span style="color: #004000;">individualPrefix</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #666666; font-style: italic;">/* If no matching option list item was found, we need to add the new
             * prefix to the Individual Prefix option list.
             */</span>
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$prefixValue</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #666666; font-style: italic;">/* We'll use CiviCRM BAO functions to add the new option.  To be
                sure we're adding to the correct option list (Individual
                Prefixes and not some other option list), fetch the option group
                ID from the database. */</span>
                <span style="color: #000088;">$group</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> CRM_Core_BAO_OptionGroup<span style="color: #339933;">;</span>
                <span style="color: #000088;">$group</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">name</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'individual_prefix'</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$group</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">find</span><span style="color: #009900;">&#40;</span><span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #666666; font-style: italic;">// Record the correct option group ID</span>
                <span style="color: #000088;">$optionGroupId</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$group</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">id</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #666666; font-style: italic;">// Prep the correct parameters for the new option list item</span>
                <span style="color: #000088;">$optionParams</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                    <span style="color: #0000ff;">'label'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$prefix</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'name'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$prefix</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'is_active'</span><span style="color: #339933;">=&gt;</span>true
                <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #666666; font-style: italic;">/* We'll also need these parameters to create the item in the
                correct option list: */</span>
                <span style="color: #000088;">$groupParams</span>  <span style="color: #339933;">=</span><span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'id'</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$optionGroupId</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #666666; font-style: italic;">/* Now use all those parameters and the Option Value functions
                to add the item to the list. */</span>
                <span style="color: #000088;">$action</span> <span style="color: #339933;">=</span> CRM_Core_Action<span style="color: #339933;">::</span><span style="color: #004000;">ADD</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$option</span> <span style="color: #339933;">=</span> CRM_Core_OptionValue<span style="color: #339933;">::</span><span style="color: #004000;">addOptionValue</span><span style="color: #009900;">&#40;</span>
                    <span style="color: #000088;">$optionParams</span><span style="color: #339933;">,</span> <span style="color: #000088;">$groupParams</span><span style="color: #339933;">,</span> <span style="color: #000088;">$action</span><span style="color: #339933;">,</span> <span style="color: #000088;">$optionValueID</span>
                <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #666666; font-style: italic;">/* $option now contains the newly added item, with its numeric
                value in $option-&gt;value.  Store that as the correct prefix
                value. */</span>
                <span style="color: #000088;">$prefixValue</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$option</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">value</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #666666; font-style: italic;">/* Now that we've added a new value to the Individual Prefix
                 * option list, we need to refresh CiviCRM's cache of possible
                 * Individual Prefix values.  This cache is built once per page,
                 * and it's already been built by the time this hook is fired.
                 * We need to refresh it so that the newly created prefix can be
                 * found and used in the contact's Display Name when we update
                 * the contact record below.
                 */</span>
                <span style="color: #b1b100;">require_once</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$civicrm_root</span> <span style="color: #339933;">.</span>
                    DIR_SEP <span style="color: #339933;">.</span> <span style="color: #0000ff;">'CRM'</span> <span style="color: #339933;">.</span>
                    DIR_SEP <span style="color: #339933;">.</span> <span style="color: #0000ff;">'Core'</span> <span style="color: #339933;">.</span>
                    DIR_SEP <span style="color: #339933;">.</span> <span style="color: #0000ff;">'PseudoConstant.php'</span>
                <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                CRM_Core_PseudoConstant<span style="color: #339933;">::</span><span style="color: #990000;">flush</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'individualPrefix'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
            <span style="color: #666666; font-style: italic;">/* By now, one way or another, we have a numeric value in
             * $prefixValue. Update the individual record using that value.
             */</span>
            <span style="color: #000088;">$params</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                <span style="color: #0000ff;">'contact_id'</span>    <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$form</span><span style="color: #339933;">-&gt;</span>_contactId<span style="color: #339933;">,</span>
                <span style="color: #0000ff;">'contact_type'</span>  <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Individual'</span><span style="color: #339933;">,</span>
                <span style="color: #0000ff;">'prefix_id'</span>     <span style="color: #339933;">=&gt;</span> <span style="color: #000088;">$prefixValue</span>
            <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #b1b100;">require_once</span><span style="color: #009900;">&#40;</span>
                <span style="color: #000088;">$civicrm_root</span> <span style="color: #339933;">.</span>
                DIR_SEP <span style="color: #339933;">.</span> <span style="color: #0000ff;">'api'</span> <span style="color: #339933;">.</span>
                DIR_SEP <span style="color: #339933;">.</span> <span style="color: #0000ff;">'v2'</span> <span style="color: #339933;">.</span>
                DIR_SEP <span style="color: #339933;">.</span> <span style="color: #0000ff;">'Contact.php'</span>
            <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$ret</span> <span style="color: #339933;">=</span> civicrm_contact_add<span style="color: #009900;">&#40;</span><span style="color: #000088;">$params</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$ret</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'is_error'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                drupal_set_message<span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Could not save changed Individual Prefix.
                    Error: '</span><span style="color: #339933;">.</span> <span style="color: #000088;">$ret</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'error_message'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'error'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #666666; font-style: italic;">/* Prefix is unchanged. Nothing to do, as the value will have been
            passed in from the form in prefix_id field. */</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p><a name="javascript"></a></p>
<h3>The JavaScript</h3>
<p>The module above makes use of Drupal&#8217;s <a href="http://api.drupal.org/api/function/drupal_add_js">drupal_add_js()</a> function to add the following JavaScript file. Thanks to <a href="http://civicrm.org/blogs/allenshaw/using-hooks-change-individual-prefix-auto-complete-text-input#comment-4491">hershel&#8217;s comment</a> for pointing out this method as a way to insert JavaScript code without relying on custom templates techniques. As far as possible I&#8217;ve tried to avoid using <a href="http://wiki.civicrm.org/confluence/display/CRMDOC/Theming+CiviCRM">custom templates</a> in order to preserve forward compatibility for future CiviCRM releases.</p>
<p>This JavaScript code provides both the type-ahead effect this field requires and some small but important data processing when the form is submitted. See the comments for detailed explanation of some points.</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
</pre></td><td class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #339933;">&lt;</span>script type<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;text/javascript&quot;</span><span style="color: #339933;">&gt;</span>
    <span style="color: #006600; font-style: italic;">/* Since we need our custom text element to be in exactly the right
     * place in the form, namely in the same place as the existing prefix
     * element, we add it here using JQuery's .append() method, by appending
     * it to the parent of the prefix element.  We give it the same value
     * as the value of the hidden_prefix_id element (see
     * tmcivicrm_civicrm_buildForm() in tmcivicrm.module).
     */</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#prefix_id&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">parent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">append</span><span style="color: #009900;">&#40;</span>
        <span style="color: #3366CC;">'&lt;input type=&quot;text&quot; name=&quot;prefix_id_text&quot; '</span> <span style="color: #339933;">+</span>
        <span style="color: #3366CC;">'id=&quot;prefix_id_text&quot; autocomplete=&quot;off&quot; value=&quot;'</span> <span style="color: #339933;">+</span>
        $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#hidden_prefix_id_text'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">val</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span><span style="color: #3366CC;">'&quot;&gt;'</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">// Add an onKeyUp event handler to the new field.</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#prefix_id_text&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">keyup</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            prefix_auto_complete<span style="color: #009900;">&#40;</span><span style="color: #000066; font-weight: bold;">this</span><span style="color: #339933;">,</span>event<span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">/* Finally, hide (but don't remove) the prefix field, which
     is actually a text field containing the numeric value of any existing
     prefix (see tmcivicrm_civicrm_buildForm() in tmcivicrm.module).
     CiviCRM will process this value when the form is submitted, as
     explained in tmcivicrm_civicrm_postProcess() in tmcivicrm.module)  */</span>
    $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#prefix_id&quot;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">css</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'display'</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'none'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #006600; font-style: italic;">/* I had this function lying around from previous projects.  How it works
    is not especially relevant to this article, but I leave it here for your 
    reference. */</span>
    <span style="color: #003366; font-weight: bold;">function</span> prefix_auto_complete<span style="color: #009900;">&#40;</span>element<span style="color: #339933;">,</span> event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        titles <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Array<span style="color: #009900;">&#40;</span>
            <span style="color: #3366CC;">&quot;Rev.&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Dr.&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Prof.&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Father&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Mr.&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Mrs.&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Ms.&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Hon.&quot;</span><span style="color: #339933;">,</span>
            <span style="color: #3366CC;">&quot;Ven.&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;H.E.&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Bishop&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Sheikh&quot;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;Imam&quot;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>element.<span style="color: #660066;">value</span> <span style="color: #339933;">==</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">/* if it's a backspace (keycode=8), just return (we do nothing on a
        backspace)*/</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>event.<span style="color: #660066;">keyCode</span> <span style="color: #339933;">==</span> <span style="color: #CC0000;">8</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">/* Find out if element has the function createTextRange (otherwise we
        should use setSelectionRange()) */</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>element.<span style="color: #660066;">createTextRange</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            useTextRange <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
            useTextRange <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">/* set up some temp variables
         */</span>
        origValue <span style="color: #339933;">=</span> element.<span style="color: #660066;">value</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// if the box is empty, just return.</span>
        <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>origValue <span style="color: #339933;">==</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #006600; font-style: italic;">// cycle through each element of Array titles() until we get a match:</span>
        <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>n<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> n <span style="color: #339933;">&lt;</span> titles.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> n<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
            title <span style="color: #339933;">=</span> titles<span style="color: #009900;">&#91;</span>n<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
            count <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
            <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> origValue.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>
                    title.<span style="color: #660066;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">charAt</span><span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span>
                    origValue.<span style="color: #660066;">toLowerCase</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">charAt</span><span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                    count<span style="color: #339933;">++</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
            <span style="color: #006600; font-style: italic;">/* if count == origValue.length, we know all the characters matched,
            so we have a match! */</span>
            <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>count <span style="color: #339933;">==</span> origValue.<span style="color: #660066;">length</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
&nbsp;
                <span style="color: #006600; font-style: italic;">/* find out how many characters remain to be filled in by
                auto-completion */</span>
                diff <span style="color: #339933;">=</span> title.<span style="color: #660066;">length</span> <span style="color: #339933;">-</span> origValue.<span style="color: #660066;">length</span><span style="color: #339933;">;</span>
                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>diff <span style="color: #339933;">&lt;=</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #000066; font-weight: bold;">break</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #006600; font-style: italic;">/* remainingChars is going to be a string of the remaining
                characters to be filled in */</span>
                remainingChars <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;&quot;</span><span style="color: #339933;">;</span>
                <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span>i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i <span style="color: #339933;">&lt;</span> title.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> i<span style="color: #339933;">++</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
                    <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>i <span style="color: #339933;">&gt;=</span> origValue.<span style="color: #660066;">length</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        remainingChars <span style="color: #339933;">+=</span> title.<span style="color: #660066;">charAt</span><span style="color: #009900;">&#40;</span>i<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                    <span style="color: #009900;">&#125;</span>
                <span style="color: #009900;">&#125;</span>
                element.<span style="color: #660066;">backspace</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #339933;">;</span>
&nbsp;
                <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>useTextRange<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #006600; font-style: italic;">// If useTextRange (Internet Explorer, et al)</span>
                    <span style="color: #003366; font-weight: bold;">var</span> textRange <span style="color: #339933;">=</span> element.<span style="color: #660066;">createTextRange</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
                    <span style="color: #006600; font-style: italic;">/* truncate the matching array item to the length of what
                    was typed */</span>
                    textRange.<span style="color: #660066;">text</span><span style="color: #339933;">=</span>title.<span style="color: #660066;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span>textRange.<span style="color: #660066;">text</span>.<span style="color: #660066;">length</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
                    <span style="color: #006600; font-style: italic;">// then we add remainingChars, select it, and we're done!</span>
                    textRange.<span style="color: #660066;">text</span> <span style="color: #339933;">+=</span> remainingChars<span style="color: #339933;">;</span>
                    textRange.<span style="color: #660066;">findText</span><span style="color: #009900;">&#40;</span>remainingChars<span style="color: #339933;">,</span>diff<span style="color: #339933;">*-</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                    textRange.<span style="color: #660066;">select</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
                <span style="color: #006600; font-style: italic;">// (Mozilla, et al)</span>
                    element.<span style="color: #660066;">value</span> <span style="color: #339933;">=</span>
                        title.<span style="color: #660066;">substr</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span>origValue.<span style="color: #660066;">length</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span>
                        remainingChars
                    element.<span style="color: #660066;">setSelectionRange</span><span style="color: #009900;">&#40;</span>
                        origValue.<span style="color: #660066;">length</span><span style="color: #339933;">,</span>
                        remainingChars.<span style="color: #660066;">length</span> <span style="color: #339933;">+</span> origValue.<span style="color: #660066;">length</span>
                    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                    <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        element.<span style="color: #660066;">backspace</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #339933;">;</span>
        <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #339933;">&lt;/</span>script<span style="color: #339933;">&gt;</span></pre></td></tr></table></div>

<h3>Conclusion</h3>
<p>This solution is working well for me now.  I&#8217;m sure there are ways to improve it.  Since I&#8217;m very new to CiviCRM, I look forward to any suggestions for improvements in the code above or in the general approach.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.twomiceandastrawberry.com/blog/46/civicrm-individual-prefix-field-as-auto-complete-text-input/feed</wfw:commentRss>
		</item>
		<item>
		<title>Twitter for Wordpress patch</title>
		<link>http://www.twomiceandastrawberry.com/blog/33/twitter-for-wordpress-patch</link>
		<comments>http://www.twomiceandastrawberry.com/blog/33/twitter-for-wordpress-patch#comments</comments>
		<pubDate>Tue, 21 Jul 2009 15:48:16 +0000</pubDate>
		<dc:creator>Allen Shaw</dc:creator>
		
		<category><![CDATA[Tech]]></category>

		<category><![CDATA[twitter wordpress link discovery hyperlinks bugfix patch]]></category>

		<guid isPermaLink="false">http://www.twomiceandastrawberry.com/blog/?p=33</guid>
		<description><![CDATA[I recently found a bug in the very cool  Twitter for Wordpress plugin (v.1.9.5), published by Rick over at Rick&#8217;s Hideout.  Here&#8217;s a fix for it, which Rick has already incorporated into the plugin.
The problem is that, in this version, the &#8220;Discover Hyperlinks&#8221; feature does not find all the hyperlinks in a tweet [...]]]></description>
			<content:encoded><![CDATA[<p>I recently found a bug in the very cool  <a title="Twitter for Wordpress" href="http://rick.jinlabs.com/code/twitter/">Twitter for Wordpress</a> plugin (v.1.9.5), published by Rick over at <a title="Rick's Hideout" href="http://rick.jinlabs.com">Rick&#8217;s Hideout</a>.  Here&#8217;s a fix for it, which Rick has already incorporated into the plugin.<span id="more-33"></span></p>
<p>The problem is that, in this version, the &#8220;Discover Hyperlinks&#8221; feature does not find all the hyperlinks in a tweet like this one:</p>
<blockquote><p><a class="moz-txt-link-freetext" href="http://example.com/example">http://example.com/example</a> has great examples (also more here: <a class="moz-txt-link-freetext" href="http://example.com/more">http://example.com/more</a>)</p></blockquote>
<p>The problem is with the regex pattern in the hyperlinks() function, which looks for a space character (\s) at the beginning and at the end a space character, comma, period, etc. ([\s|\.|\,]).  The tweet above has two links, but the first one doesn&#8217;t match since it starts from the first character of the tweet and so has no leading space character; and the second one doesn&#8217;t match since it is followed by a close-parentheses.</p>
<p>A better way to do it would be to use the \b meta-character to look for a word boundary.  Below is the hyperlinks() function re-written that way.</p>
<p><code><br />
function hyperlinks($text) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;// match protocol://address/path/file.extension?some=variable&amp;another=asf%<br />
&nbsp;&nbsp;&nbsp;&nbsp;$text = preg_replace(&quot;/\b([a-zA-Z]+:\/\/[a-z][a-z0-9\_\.\-]*[a-z]{2,6}[a-zA-Z0-9\/\*\-\?\&amp;\%]*)\b/i&quot;,&quot;&lt;a href=\&quot;$1\&quot; class=\&quot;twitter-link\&quot;&gt;$1&lt;/a&gt;&quot;, $text);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// match www.something.domain/path/file.extension?some=variable&amp;another=asf%<br />
&nbsp;&nbsp;&nbsp;&nbsp;$text = preg_replace(&quot;/\b(www\.[a-z][a-z0-9\_\.\-]*[a-z]{2,6}[a-zA-Z0-9\/\*\-\?\&amp;\%]*)\b/i&quot;,&quot;&lt;a href=\&quot;http://$1\&quot; class=\&quot;twitter-link\&quot;&gt;$1&lt;/a&gt;&quot;, $text);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;// match name@address<br />
&nbsp;&nbsp;&nbsp;&nbsp;$text = preg_replace(&quot;/\b([a-zA-Z][a-zA-Z0-9\_\.\-]*[a-zA-Z]*\@[a-zA-Z][a-zA-Z0-9\_\.\-]*[a-zA-Z]{2,6})\b/i&quot;,&quot;&lt;a href=\&quot;mailto://$1\&quot; class=\&quot;twitter-link\&quot;&gt;$1&lt;/a&gt;&quot;, $text);<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;return $text;<br />
}<br />
</code></p>
<p>Thanks to Rick for incorporating this fix into the next version (1.9.6) of the plugin.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.twomiceandastrawberry.com/blog/33/twitter-for-wordpress-patch/feed</wfw:commentRss>
		</item>
		<item>
		<title>Phone Toggler for Google Voice</title>
		<link>http://www.twomiceandastrawberry.com/blog/25/phone-toggler-for-google-voice</link>
		<comments>http://www.twomiceandastrawberry.com/blog/25/phone-toggler-for-google-voice#comments</comments>
		<pubDate>Thu, 16 Jul 2009 19:37:33 +0000</pubDate>
		<dc:creator>Allen Shaw</dc:creator>
		
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.twomiceandastrawberry.com/blog/?p=25</guid>
		<description><![CDATA[Here&#8217;s a PHP/curl hack that lets me manage my Google Voice phones easily.
Google Voice is great. One number for all my contacts, and I can answer an incoming call on my cell when I&#8217;m out and about, or penny-pinch my minutes by taking it on the office phone when I&#8217;m in.  But having an incoming [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a PHP/curl hack that lets me manage my Google Voice phones easily.</p>
<p>Google Voice is great. One number for all my contacts, and I can answer an incoming call on my cell when I&#8217;m out and about, or penny-pinch my minutes by taking it on the office phone when I&#8217;m in.  But having an incoming call ring on all phones is not enough for me.<span id="more-25"></span></p>
<p>I don&#8217;t want it to ring at my home office unless I&#8217;m there, because who knows who&#8217;ll answer it before I do, and then I&#8217;ve lost the call. I want it to ring on only one phone at a time, and it has to be the right phone, so I can save minutes where possible, but never risk the call landing somewhere I&#8217;m not.</p>
<p>The problem is that enabling and disabling phones in the GV web interface is so <strong><em>tedious</em></strong>, I don&#8217;t want to do that every time I enter or leave the office.</p>
<p>To solve this tedium, I hacked up a quick PHP script using CURL to sign in to GV, enable the phone I want, and disable all others.  One quick line at the command prompt, and I&#8217;m ready to go:</p>
<pre>$ togglePhones 1</pre>
<p>enables my cell phone and disables my home phone, while</p>
<pre>$ togglePhones 2</pre>
<p>does the reverse.</p>
<p><a title="Google Voice Toggle Phones" href="http://www.twomiceandastrawberry.com/media/google-voice-toggle-phones.zip">Download the script here</a> for your own use.  This is a command-line script. Call it without arguments to get a list of options. Edit the file directly to configure your GV username and password.</p>
<p>Thanks to tylerhall, Michal Migurski, and vladimir_wof_nikolaich_dot_ru for writing the bulk of the code in this script (see the code comments for credits).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.twomiceandastrawberry.com/blog/25/phone-toggler-for-google-voice/feed</wfw:commentRss>
		</item>
		<item>
		<title>GoDaddy rejecting tons of false positive spam/virii</title>
		<link>http://www.twomiceandastrawberry.com/blog/10/godaddy-rejecting-tons-of-false-positive-spamvirii</link>
		<comments>http://www.twomiceandastrawberry.com/blog/10/godaddy-rejecting-tons-of-false-positive-spamvirii#comments</comments>
		<pubDate>Wed, 29 Apr 2009 12:25:44 +0000</pubDate>
		<dc:creator>Allen Shaw</dc:creator>
		
		<category><![CDATA[Tech]]></category>

		<category><![CDATA[false positive]]></category>

		<category><![CDATA[godaddy]]></category>

		<category><![CDATA[spam]]></category>

		<category><![CDATA[virus]]></category>

		<guid isPermaLink="false">http://www.twomiceandastrawberry.com/blog/?p=10</guid>
		<description><![CDATA[Since I started using GoDaddy to host email for this site, I&#8217;ve had several users report several times that mail they send me is being bounced with this message: &#8220;554 The message was rejected because it contains prohibited virus or spam content&#8221;.  I struggled to understand it until I found several articles (here, here, [...]]]></description>
			<content:encoded><![CDATA[<p>Since I started using GoDaddy to host email for this site, I&#8217;ve had several users report several times that mail they send me is being bounced with this message: &#8220;554 The message was rejected because it contains prohibited virus or spam content&#8221;.  I struggled to understand it until I found several articles (<a title="Michael Orlitzky: GoDaddy's Spam Filter is Broken" href="http://michael.orlitzky.com/articles/godaddys_spam_filter_is_broken.php">here</a>, <a title="Evan Coonrod: Why GoDaddy is awful (Read this if you use EC2 or other virtualized server)" href="http://evan.coonrod.org/post/50937207/godaddy-sucks">here</a>, and <a title="Justin Mason: GoDaddy's Spam Filter is Broken" href="http://taint.org/2008/08/29/153922a.html">here</a>, for starters) pointing out that GoDaddy is <strong>wrongly</strong> blocking mail if it contains links to perfectly legitimate sites.  Obviously this<span id="more-10"></span> is completely braindead.</p>
<p>As far as I know, I&#8217;m the first GoDaddy customer to complain publicly about this.  This is probably because professionals in the world of hosting and web apps will usually not touch GoDaddy with a ten foot pole.  I thought I&#8217;d give them a shot.  It&#8217;s not looing good.</p>
<p>Let&#8217;s see if complaints from their own customers will make a difference.  If you&#8217;re a GoDaddy customer, read the articles above, then write GoDaddy now to tell them how ridiculous their policy is.  Other options for mail hosting are just a few clicks away.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.twomiceandastrawberry.com/blog/10/godaddy-rejecting-tons-of-false-positive-spamvirii/feed</wfw:commentRss>
		</item>
		<item>
		<title>Vodez-better component for Joomla! 1.5 Legacy</title>
		<link>http://www.twomiceandastrawberry.com/blog/5/vodes-better-component-for-joomla-15-legacy</link>
		<comments>http://www.twomiceandastrawberry.com/blog/5/vodes-better-component-for-joomla-15-legacy#comments</comments>
		<pubDate>Tue, 21 Apr 2009 20:09:31 +0000</pubDate>
		<dc:creator>Allen Shaw</dc:creator>
		
		<category><![CDATA[Software Releases]]></category>

		<category><![CDATA[Joomla]]></category>

		<category><![CDATA[vodes]]></category>

		<guid isPermaLink="false">http://www.twomiceandastrawberry.com/blog/?p=5</guid>
		<description><![CDATA[Emir Sakic&#8217;s &#8220;Vodes&#8221; component for Joomla! was just what I needed &#8212; almost.  My client needs configurable options without editing code files. I&#8217;ve extended Emir&#8217;s work into Vodez-better, which adds configurable options for currencies, price packages, and gift credits. GPL 3.0 [Download]
]]></description>
			<content:encoded><![CDATA[<p>Emir Sakic&#8217;s &#8220;Vodes&#8221; component for Joomla! was just what I needed &#8212; almost.  My client needs configurable options without editing code files. I&#8217;ve extended Emir&#8217;s work into Vodez-better, which adds configurable options for currencies, price packages, and gift credits. GPL 3.0 [<a title="Vodez-better.zip" href="http://twomiceandastrawberry.com/media/Vodez-better.zip">Download</a>]</p>
]]></content:encoded>
			<wfw:commentRss>http://www.twomiceandastrawberry.com/blog/5/vodes-better-component-for-joomla-15-legacy/feed</wfw:commentRss>
		</item>
	</channel>
</rss>

