Ticket #4805: test-wplists.php

File test-wplists.php, 17.2 kB (added by mdawaffe, 1 year ago)

Plugin: Docs, Tests/Examples

Line 
1 <?php
2 /*
3 Plugin Name: Test wp-lists.js
4 Plugin URI: http://wordpress.org/#
5 Description: Try out the wp-lists javascript
6 Author: Michael Adams
7 Version: 0.1
8 */
9
10 function test_wp_list_admin_menu() {
11     $hook = add_menu_page( 'WPLists Tests', 'WPLists', 0, __FILE__, 'test_wp_list_instructions' );
12     add_submenu_page( __FILE__, 'WPLists Tests', 'Instructions', 0, __FILE__ );
13     add_action( "admin_print_scripts-$hook", 'test_wp_list_admin_page_js' );
14     add_action( "admin_head-$hook", 'test_wp_list_admin_page_head' );
15     $hook = add_submenu_page( __FILE__, 'WPLists Tests', 'Add Test 1', 0, 'test_wp_lists_1', create_function('', 'test_wp_list_admin_page(1);') );
16     add_action( "admin_print_scripts-$hook", 'test_wp_list_admin_page_js' );
17     add_action( "admin_head-$hook", 'test_wp_list_admin_page_head' );
18     $hook = add_submenu_page( __FILE__, 'WPLists Tests', 'Add Test 2', 0, 'test_wp_lists_2', create_function('', 'test_wp_list_admin_page(2);') );
19     add_action( "admin_print_scripts-$hook", 'test_wp_list_admin_page_js' );
20     add_action( "admin_head-$hook", 'test_wp_list_admin_page_head' );
21     $hook = add_submenu_page( __FILE__, 'WPLists Tests', 'Delete Test', 0, 'test_wp_lists_3', create_function('', 'test_wp_list_admin_page(3);') );
22     add_action( "admin_print_scripts-$hook", 'test_wp_list_admin_page_js' );
23     add_action( "admin_head-$hook", 'test_wp_list_admin_page_head' );
24     $hook = add_submenu_page( __FILE__, 'WPLists Tests', 'Dim Test', 0, 'test_wp_lists_4', create_function('', 'test_wp_list_admin_page(4);') );
25     add_action( "admin_print_scripts-$hook", 'test_wp_list_admin_page_js' );
26     add_action( "admin_head-$hook", 'test_wp_list_admin_page_head' );
27     $hook = add_submenu_page( __FILE__, 'WPLists Tests', 'Full Test', 0, 'test_wp_lists_5', create_function('', 'test_wp_list_admin_page(5);') );
28     add_action( "admin_print_scripts-$hook", 'test_wp_list_admin_page_js' );
29     add_action( "admin_head-$hook", 'test_wp_list_admin_page_head' );
30 }
31 add_action( 'admin_menu', 'test_wp_list_admin_menu' );
32
33 function test_wp_list_admin_page_js() {
34     wp_enqueue_script( 'wp-lists' );
35     wp_enqueue_script( 'jquery-form' );
36 }
37
38 function test_wp_list_admin_page_head() {
39 ?>
40
41 <script type="text/javascript">
42 /* <![CDATA[ */
43 jQuery(function($) {
44 $('#the-list').wpList( { response: 'bob' } );
45 } );
46 /* ]]> */
47 </script>
48
49 <style type="text/css">
50 .dim-class { background-color: #99F; color: #33F; font-style: italic; }
51 pre { background-color: #FFD; padding: 1em; }
52 .green { background-color: #0F6; }
53 #the-list { border: 1px solid #ccc; padding: 1em 2em; }
54 form { border: 1px solid #ccc; padding: 0; }
55 form div { float: left; margin: 0 2ex 1em; }
56 </style>
57
58 <?php
59 }
60
61
62 function test_wp_list_instructions() {
63 ?>
64
65 <div class="wrap">
66 <h2>WP jQuery Lists</h2>
67 <p>Information about <a href="#markup">Markup</a>, <a href="#javascript">JavaScript</a>, and <a href="#server">Server Responses</a>.</p>
68 <p>You'll find some tests/examples in the other tabs.</p>
69 </div>
70
71 <div id="markup" class="wrap">
72 <h2>The HTML Markup</h2>
73
74 <pre><code>
75 &lt;ul id="the-list" class="list:item"&gt;
76     &lt;li id="item-1"&gt;The first item&lt;/li&gt;
77     ...
78 &lt;/ul&gt;
79 </code></pre>
80
81 <p>All of the classes mentioned below <strong>must</strong> be the first class for that element.</p>
82 <p>Upper case "class parameters" are required.  Lower case parameters are optional.
83
84 <h3>Setting up the list</h3>
85 <p>CLASS: <code>list:TTTT</code></p>
86 <dl>
87     <dt><code>TTTT</code></dt>
88     <dd>The "type" of the item the list contains</dd>
89 </dl>
90 <h4>Notes</h4>
91 <ul>
92     <li>The list element must have an HTML id attribute.</li>
93     <li>The list can be any block level element: <code>UL</code>, <code>OL</code>, <code>DIV</code>....</li>
94     <li>If you want to use a table, you must make the list container a <code>TBODY</code> within that table.</li>
95     <li>
96         The items in the list much each have an id formatted like: <code>id="TTTT-ID"</code> where <code>TYPE</code>
97         is the "type" of item the list contains and <code>ID</code> is some unqique identifer (not necessarily a number).
98     </li>
99    
100 </ul>
101
102 <h3>Adding items to the list</h3>
103 <p>CLASS: <code>add:LLLL:FFFF:aaaa:qqqq</code></p>
104 <dl>
105     <dt><code>LLLL</code></dt>
106     <dd>The HTML id of the list to which you want to add the item.</dd>
107
108     <dt><code>FFFF</code></dt>
109     <dd>
110         The HTML id of the element containing the form elements you want to send in the AJAX call.
111         May be blang if the <code>add:</code> class is given to a <code>FORM</code> element, but
112         the colon after <code>LLLL</code> is <em>always required</em>: <code>&lt;form class="add:the-list:"&gt;</code>.
113     <dd>
114
115     <dt><code>aaaa</code></dt>
116     <dd>A six digit hex color that specifies the fade color of the item when it is added.  It can also be set to "<code>none</code>".</dd>
117
118     <dt><code>qqqq</code></dt>
119     <dd>A query string formatted string of extra data to send in the AJAX call: <code>add:the-list:::foo=bar&yo=mama<code>.</dd>
120 </dl>
121 <h4>Notes</h4>
122 <ul>
123     <li>The AJAX call is constructed from <code>FORM</code> elements.</li>
124     <li>
125         You can send all of the form to the server by giving the form the <code>add:LLLL:</code> class. The final colon is very important!
126         The AJAX call will be made whenever the form is submitted (type enter, click submit...).
127     </li>
128     <li>
129         You can send just a piece of the form by giving some element a <code>add:LLLL:FFFF</code> class.
130         The AJAX call will be made whenever that element is clicked or whenever a submit event comes from that piece of the form.
131     </li>
132     <li>Whatever you send, it must include a <code>_ajax_nonce</code> or <code>_wpnonce</code> element.</li>
133 </ul>
134
135 <h3>Removing items from the list</h3>
136 <p>CLASS: <code>delete:LLLL:IIII:dddd:qqqq</code></p>
137 <dl>
138     <dt><code>LLLL</code></dt>
139     <dd>The HTML id of the list from which you want to delete the item.</dd>
140
141     <dt><code>IIII</code></dt>
142     <dd>The HTML id of the item you want to delete.</dd>
143
144     <dt><code>dddd</code></dt>
145     <dd>A six digit hex color that specifies the fade color of the item when it is deleted.  It can also be set to "<code>none</code>".</dd>
146
147     <dt><code>qqqq</code></dt>
148     <dd>A query string formatted string of extra data to send in the AJAX call: <code>delete:the-list:item-1::foo=bar&yo=mama<code>.</dd>
149 </dl>
150 <h4>Note</h4>
151 <p>The nonce is drawn from the url of the link's href.  Use either a <code>_ajax_nonce</code> or <code>_wpnonce</code> parameter.</p>
152
153 <h3>Dimming items in the list (toggling a class)</h3>
154 <p>CLASS: <code>dim:LLLL:IIII:CCCC:aaaa:dddd:qqqq</code></p>
155 <dl>
156     <dt><code>LLLL</code></dt>
157     <dd>The HTML id of the list containing the item you want to dim</dd>
158
159     <dt><code>IIII</code></dt>
160     <dd>The HTML id of the item you want to dim</dd>
161
162     <dt><code>CCCC</code></dt>
163     <dd>The name of the class</dd>
164
165     <dt><code>aaaa</code></dt>
166     <dd>A six digit hex color that specifies the fade color of the item when the class is added.  It can also be set to "<code>none</code>".</dd>
167
168     <dt><code>dddd</code></dt>
169     <dd>A six digit hex color that specifies the fade color of the item when the class is deleted.  It can also be set to "<code>none</code>".</dd>
170
171     <dt><code>qqqq</code></dt>
172     <dd>A query string formatted string of extra data to send in the AJAX call: <code>dim:the-list:item-1:classname:::foo=bar&yo=mama<code>.</dd>
173 </dl>
174 <h4>Note</h4>
175 <p>The nonce is drawn from the url of the link's href.  Use either a <code>_ajax_nonce</code> or <code>_wpnonce</code> parameter.</p>
176
177 </div>
178
179 <div id="javascript" class="wrap">
180
181 <h2>The Javascript</h2>
182
183 <p>If your form has radio buttons or other complicated form elements, you should include the jQuery-Forms JS file so that the data is sent to the server in the correct format.</p>
184
185 <pre><code>
186 // Set up the list
187 $('#the-list').wpList(); // Basic Usage.
188 // or
189 $('#the-list').wpList( options ); // Advanced Usage.
190
191 options = {
192     url: '/admin-ajax.php',
193         // Where to submit the AJAX request,
194     response: 'ajax-response',
195         // the HTML id of an element whose innerHTML
196         // will be filled with error messages if needed
197
198     what: '',
199     alt: 'alternate',
200         // the class that will be added to alternate list items.
201         // Can be set to blank.
202     altOffset: 0, // 0 or 1
203         // 0 => odd items will be given alt class
204         // 1 => even items
205     addColor: null, delColor: null, dimAddColor: null, dimDelColor: null,
206         // Fade colors for various actions.
207         // Overridden by class parameters in <a href="#markup">Markup</a>
208
209     confirm: null,
210         // Callback function usefupl for Are You Sure?s
211         // Called from scope of list element
212         // 1st arg: element to delete or dim, or form to add from
213         // 2nd: options object
214         // 3rd: 'add', 'delete', 'dim' (what we're doing)
215         // 4th: original pre-highlight background color of element
216         //
217         // Return true => "I want to da that", false => "I didn't mean it. Stop."
218
219     addBefore: null, // options.data is a query string
220     delBefore: null, // options.data is a JS object
221     dimBefore: null, // options.data is a JS object
222         // Callback functions executed before AJAX call
223         // Accepts options object as first and only parameter
224         // options.data is the data that will be sent via AJAX
225         //
226         // Must return options object (like WP filters must)
227         // Can instead return false => AJAX will be aborted,
228         //   and "traditional" action will proceed (form submit,
229         //   link click...)
230
231     addAfter: null,
232     delAfter: null,
233     dimAfter: null,
234         // Callback function executed after AJAX call succeeds
235         // Accepts response(XML|Text) as 1st argument, options object as 2nd
236        
237
238 };
239
240 // Add alt class to appropriate elements
241 $("#the-list').wpList.recolor();
242
243 // Add HTML or element to list manually.  No AJAX involved.  The .get(0) is really important
244 $("#the-list').get(0).wpList.add( HTML or element );
245 </code></pre>
246
247 </div>
248
249 <div id="server" class="wrap">
250 <h2>Server Side</h2>
251
252 <p>The server should exit with one of the following.</p>
253
254 <dl>
255     <dt><code>(string) -1</code></dt>
256     <dd>
257         This response indicates that the user does not have permission to perform the requested action.
258         This could be because of the user lacks a capability you're checking for or because the nonce check failed.
259     </dd>
260
261     <dt><code>(string) 0</code></dt>
262     <dd>Indicates that something reall strange happened.  You should only return this when you have no idea what the error really is.</dd>
263
264     <dt><code>(string) 1</code></dt>
265     <dd>"All is well.  The requested action was performed with no problem."</dd>
266
267     <dt><code>(string)</code> Raw Text or HTML</dt>
268     <dd>"Something bad happened; the requested action did not complete.  Here is an error message."</dd>
269
270     <dt>XML generated by <code>(object) new WP_Ajax_Response</code></dt>
271     <dd>
272         The client side JS expects the XML to be formatted in a particular way.
273         The <code>WP_Ajax_Response</code> class should be used to generate that XML.
274         You will need to use this method when AJAX adding to a list.
275     </dd>
276 </dl>
277
278 <h3>The <code>WP_Ajax_Response</code> Class</h3>
279
280 <pre><code>
281 // Respond with single item
282 $x = new WP_Ajax_Response( array(
283     'what'  => 'object', // the item "type" of your list
284     'action' => false, // (optional) formatted like a nonce action
285     'id' => 0, // The unique identifier of the item (not the HTML id)
286     'oldId' => 0, // (optional) If you were updating an item, did it formerly have a different id?
287     'position' => 1,
288         // -1 => insert at beginning of list
289         // 0  => if oldId, insert where oldId item was
290         // 1  => insert at end of list
291         // HTML_ID  => insert after the item with that HTML id
292         // -HTML_ID => insert before the item with that HTML id
293     'data' => '', // The HTML of the item to be inserted into the list.
294     'supplemental' => array()
295         // an associative array af extra data to be passed with the XML response:
296         // 'supplemental' => array( 'foo' => 'bar' )
297         // yields
298         // &lt;foo&gt;&lt;![CDATA[bar]]&gt;&lt;/foo&gt;
299 );
300 $x->send();
301
302 // Respond with several items
303 $x = new WP_Ajax_Response;
304 $x->add( ... );
305 $x->add( ... );
306 $x->send();
307 </pre></code>
308
309 </div>
310 <?php
311 }
312
313
314
315 function test_wp_list_admin_page( $test ) {
316     $list_items = array( 1,2,3,4,5,6,7,8); //,9,10,11,12,13,14,15,16,17,18,19,20 );
317 ?>
318 <div class="wrap">
319
320 <div id="bob"></div>
321
322 <?php
323 $code = '';
324 switch ( $test ) :
325 case 1 :
326 echo "<h2>Send the whole form</h2>\n";
327 echo "<p>The add: class is given to the whole form.</p>\n\n";
328 $code = <<<CODE1
329 <form action='' method='post' id='ajax-add' class='%s'>
330     ...
331     <?php wp_nonce_field( 'add-item', '_ajax_nonce', false ); ?>
332 </form>
333 <ul id="the-list" class="list:item">
334     ...
335 </ul>
336 CODE1;
337 $code = sprintf( wp_specialchars( $code ), "<span class='green'>add:the-list:</span>" );
338 break;
339
340
341 case 2 :
342 echo "<h2>Send a piece of the form</h2>\n";
343 echo "<p>The add: class is given to a button (so the position radios shouldn't work in this test; it will always appear at the end of the list).</p>\n\n";
344 $code = <<<CODE2
345 <form action='' method='post' id='ajax-add'>
346     <div id="%s">
347         <input type='text' id='adder' name='adder' />
348         <?php wp_nonce_field( 'add-item', '_ajax_nonce', false ); ?>
349     </div>
350     ...
351     <input type="button" value="Add" id='add-button' class='%s'>
352 </form>
353 <ul id="the-list" class="list:item">
354     ...
355 </ul>
356 CODE2;
357 $code = sprintf( wp_specialchars( $code ), "<span class='green'>ajax-add-name</span>", "<span class='green'>add:the-list:ajax-add-name</span>" );
358 break;
359
360
361
362 case 3 :
363 echo "<h2>Delete an item from the list</h2>\n";
364 echo "<ul>\n";
365 echo "\t<li>The list must specify what kind of items it holds with the list: class.</li>\n";
366 echo "\t<li>The delete link should have the nonce in it.</li>\n";
367 echo "\t<li>The delete link must specify what item to delete and from what list to delete it with the delete: class.</li>\n";
368 echo "</ul>\n\n";
369 $code = <<<CODE3
370 <ul id="the-list" class="%s">
371     <li id="item-1">
372         Item 1
373         <a href="?_wpnonce=123456789a" class="%s">Delete</a>
374     </li>
375     ...
376 </ul>
377 CODE3;
378 $code = sprintf( wp_specialchars( $code ), "<span class='green'>list:item</span>", "<span class='green'>delete:the-list:item-1</span>" );
379 break;
380
381
382
383 case 4 :
384 echo "<h2>'Dim' an item: toggle it's class</h2>\n";
385 echo "<ul>\n";
386 echo "\t<li>The list must specify what kind of items it holds with the list: class.</li>\n";
387 echo "\t<li>The dim link should have the nonce in it.</li>\n";
388 echo "\t<li>The dim link must specify what item to dim, from what list to dim it, and what class to toggle  with the dim: class.</li>\n";
389 echo "</ul>\n\n";
390 $code = <<<CODE3
391 <ul id="the-list" class="%s">
392     <li id="item-1">
393         Item 1
394         <a href="?_wpnonce=123456789a" class="%s">Dim</a>
395     </li>
396     ...
397 </ul>
398 CODE3;
399 $code = sprintf( wp_specialchars( $code ), "<span class='green'>list:item</span>", "<span class='green'>dim:the-list:item-1:dim-class</span>" );
400 break;
401 endswitch;
402
403 if ( $code ) {
404     echo "\n<h3>Example:</h3>\n\n";
405     echo "\n\n<pre><code>$code</code></pre>\n\n";
406
407     echo "\n<h3>Test:</h3>\n\n";
408 }
409
410 if ( $test < 3 || 5 == $test ) : ?>
411
412 <form action='' method='post' id='ajax-add'<?php if ( 1 == $test || 5 == $test ) echo " class='add:the-list:'"; ?>>
413 <div id="ajax-add-name">
414     <h4>Name of item to add:</h4>
415     <input type='text' id='adder' name='adder' />
416     <?php wp_nonce_field( 'add-item', '_ajax_nonce', false ); ?>
417 </div>
418 <div>
419     <h4>Position:</h4>
420     <label for="pos--1"><input type='radio' name='pos' value='-1' checked='checked' id='pos--1' /> Beginning: -1</label><br />
421     <label for="pos--3"><input type='radio' name='pos' value='-3' id='pos--3' /> Before Item 3</label><br />
422     <label for="pos-3"><input type='radio' name='pos' value='3' id='pos-3' /> After Item 3</label><br />
423     <label for="pos-1"><input type='radio' name='pos' value='1' id='pos-1' /> End: 1</label><br />
424 </div>
425 <?php if ( 2 == $test ) : ?>
426 <div>
427     <h4>The "submit" button</h4>
428     <input type="button" value="Add" id='add-button' class='add:the-list:ajax-add-name button' />
429 </div>
430 <?php endif; ?>
431 <?php if ( 5 == $test ) : ?>
432 <input type="hidden" value="5" name="test" />
433 <?php endif; ?>
434 <br style="clear: both"/>
435 </form>
436
437 <?php endif; ?>
438
439 <ul id="the-list" class="list:item">
440 <?php foreach ( $list_items as $list_item ) : ?>
441
442     <li id="item-<?php echo $list_item; ?>">
443         Item <?php echo $list_item; ?>
444 <?php if ( 3 == $test || 5 == $test ) : ?>
445         <a href="<?php echo wp_nonce_url( '?', "delete-item_$list_item"); ?>" class="delete:the-list:item-<?php echo $list_item; ?>">Delete</a>
446 <?php endif; if ( 4 == $test || 5 == $test ) : ?>
447         <a href="<?php echo wp_nonce_url( '?', "dim-item_$list_item"); ?>" class="dim:the-list:item-<?php echo $list_item; ?>:dim-class">Dim</a>
448 <?php endif; ?>
449     </li>
450
451 <?php endforeach; ?>
452
453 </ul>
454
455 </div>
456
457 <?php
458 }
459
460 function test_wp_list_admin_ajax() {
461     $id = (int) $_POST['id'];
462     switch ( $_POST['action'] ) :
463     case 'add-item' :
464         check_ajax_referer( 'add-item' );
465         $text = $_POST['adder'];
466         $id = mt_rand();
467         $data  = "<li id='item-$id'>\n";
468         $data .= "\t$text\n";
469         if ( isset($_POST['test']) && 5 == $_POST['test'] ) {
470             $data .= "\t<a href='" . wp_nonce_url( add_query_arg( array( 'action' => 'delete', 'id' => $id ), '?' ), "delete-item_$id") . "' class='delete:the-list:item-$id'>Delete</a>\n";
471             $data .= "\t<a href='" . wp_nonce_url( add_query_arg( array( 'action' => 'dim', 'id' => $id ), '?' ), "dim-item_$id") . "' class='dim:the-list:item-$id:dim-class'>Dim</a>\n";
472         }
473         $data .= "</li>";
474         $pos = (int) $_POST['pos'];
475         if ( 3 == $pos )
476             $pos = 'item-3';
477         elseif ( -3 == $pos )
478             $pos = '-item-3';
479
480         $x = new WP_Ajax_Response( array( 'what' => 'item', 'id' => $id, 'data' => $data, 'position' => $pos ) );
481         $x->send();
482         break;
483     case 'delete-item' :
484     case 'dim-item' :
485         check_ajax_referer( "{$_POST['action']}_$id" );
486         die('1');
487         break;
488     endswitch;
489 }
490 add_action( 'wp_ajax_add-item', 'test_wp_list_admin_ajax' );
491 add_action( 'wp_ajax_delete-item', 'test_wp_list_admin_ajax' );
492 add_action( 'wp_ajax_dim-item', 'test_wp_list_admin_ajax' );
493
494 ?>
495