/[drupal]/contributions/modules/interface_sortable/interface_sortable.module
ViewVC logotype

Contents of /contributions/modules/interface_sortable/interface_sortable.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (show annotations) (download) (as text)
Thu May 24 01:08:05 2007 UTC (2 years, 6 months ago) by marcp
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +2 -2 lines
File MIME type: text/x-php
FormAPI 3 compatibility changes.  Still not sure if $form_values and
$form are swapped in the _submit handler...
1 <?php
2 // $Id: interface_sortable.module,v 1.2 2007/05/15 00:32:45 marcp Exp $
3
4 /**
5 * Implementation of hook_elements
6 */
7 function interface_sortable_elements() {
8 $type['sortable'] = array(
9 '#input' => TRUE,
10 '#process' => array('interface_sortable_process'),
11 '#items' => array(),
12 '#outer_tag' => 'div',
13 '#inner_tag' => 'div',
14 '#options' => array(),
15 );
16
17 return $type;
18 }
19
20 /**
21 * Expansion function for 'interface_sortable' type form element
22 *
23 * extra arguments:
24 *
25 * #items => array()
26 * required - Keyed array of items to be sorted.
27 * Keys will be returned in sorted order.
28 * Values can be anything.
29 *
30 * #inner_tag => 'div'
31 * #outer_tag => 'div'
32 * type of tag to use for sortables (could also be 'ul' and 'li'... or anything)
33 *
34 * #inner_class => 'sortable-item'
35 * #outer_class => 'sortable-container'
36 * class to attach to the sortable items and container. #inner_class gets
37 * passed on to the Sortable as 'accept'...
38 *
39 * #options => array()
40 * options to modify the behaviour of the sorting
41 * see: http://interface.eyecon.ro/docs/sort
42 *
43 * @param array $element
44 * the array representing the sortable element
45 */
46 function interface_sortable_process($element) {
47 if (!is_array($element)) {
48 $element = array();
49 }
50
51 if (!array_key_exists('#options', $element)) {
52 $element['#options'] = array();
53 }
54
55 $innertag = array_key_exists('#inner_tag', $element) ? $element['#inner_tag'] : 'div';
56 $outertag = array_key_exists('#outer_tag', $element) ? $element['#outer_tag'] : 'div';
57 $outer_class = array_key_exists('#outer_class', $element) ? $element['#outer_class'] : 'sortable-container';
58 $inner_class = array_key_exists('#inner_class', $element) ? $element['#inner_class'] : 'sortable-item';
59
60 // If the user hasn't set the class of items to accept for drag and drop,
61 // set it to the inner class for them...
62 if (!array_key_exists('accept', $element['#options'])) {
63 $element['#options']['accept'] = $inner_class;
64 }
65
66 $outerid = $element['#parents'][0];
67
68 $sortables['#prefix'] = "<$outertag id='$outerid-wrapper' class='$outer_class'>\n";
69 $sortables['#suffix'] = "</$outertag>\n";
70
71 // if there's a #value, eval it and resort
72 if ($element['#value']) {
73 $keyorder = interface_get_sort($element['#value']);
74 $items = $element['#items'];
75 foreach ($keyorder as $key) {
76 $newitems[$key] = $items[$key];
77 }
78 $element['#items'] = $newitems;
79 unset($element['#value']);
80 }
81
82 foreach ($element['#items'] as $k => $v) {
83 $sortables[$k] = array(
84 '#type' => 'markup',
85 '#value' => $v,
86 '#prefix' => "<$innertag id='{$outerid}_{$k}' class='$inner_class'>",
87 '#suffix' => "</$innertag>\n"
88 );
89 $order[] = $k;
90 }
91
92 // If the user hasn't sent in an onchange handler, create a default
93 // one that sets the sortable element's value every time the order
94 // changes...
95 if (!array_key_exists('#onchange', $element['#options'])) {
96 $element['#options']['#onchange'] = <<<EOT
97 function (obj) {
98 serial = $.SortSerialize(obj[0].id);
99 document.getElementById('edit-$outerid').value = serial.hash;
100 }
101 EOT;
102 }
103
104 interface_sortable_element($outerid .'-wrapper', $element['#options']);
105 $value = $outerid .'[]='. implode('&'. $outerid .'[]=', $order);
106
107 $element['#type'] = 'markup';
108 $element[] = $sortables;
109 $element[$outerid] = array(
110 '#type' => 'hidden',
111 '#theme' => 'interface_sortable_hidden',
112 '#value' => $value
113 );
114
115 return $element;
116 }
117
118 /**
119 * Format the hidden sortable form field that holds the sort order.
120 * This differs from theme_hidden() only in the fact that we don't
121 * call check_plain($element['#value']) when printing the value out
122 * because it escapes the ampersands... Not even sure that would be
123 * a problem, so this might not even be necessary...
124 *
125 * @param $element
126 * An associative array containing the properties of the element.
127 * Properties used: value, edit
128 * @return
129 * A themed HTML string representing the hidden form field.
130 */
131 function theme_interface_sortable_hidden($element) {
132 return '<input type="hidden" name="'. $element['#name'] .'" id="'. $element['#id'] .'" value="'. $element['#value'] ."\" ". drupal_attributes($element['#attributes']) ." />\n";
133 }
134
135 /**
136 * Convert form output from interface_sortable_process into an array
137 *
138 * Interface's sortable output is designed as a GET argument (e.g. ?sort[]=second&sort[]=third&sort[]=first)
139 *
140 * This function converts the output of the hidden field into an array
141 *
142 * @param string $sort
143 * @return array
144 */
145 function interface_get_sort($sort) {
146 $return = array();
147 parse_str($sort, $result);
148 $elements = array_keys($result);
149 if (!empty($elements)) {
150 $element = $elements[0];
151 $len = strpos($element, '-wrapper');
152 $prefix = substr($element, 0, $len);
153 foreach ($result[$element] as $val) {
154 if (strpos($val, $prefix .'_') === 0) {
155 $val = substr($val, strlen($prefix) + 1);
156 }
157 $return[] = $val;
158 }
159 }
160 return $return;
161 }
162
163 /**
164 * Makes the element with the DOM ID specified by element_id sortable by
165 * drag-and-drop.
166 *
167 * This method requires the inclusion of the jQuery Interface JavaScript plug-in.
168 *
169 * @Example:
170 * interface_sortable_element("my_list", array('action' => 'order'))
171 *
172 * In the example, the action gets a "my_list" array parameter containing the values
173 * of the ids of elements the sortable consists of, in the current order.
174 *
175 * You can change the behaviour with various options, see script.aculo.us for more documentation.
176 *
177 * @param string $element_id
178 * @param array $options
179 */
180
181 function interface_sortable_element($element_id, $options = array()) {
182 jquery_interface_add();
183 $parms = interface_to_js($options);
184
185 drupal_add_js("$(document).ready( function () { $('#$element_id').Sortable($parms) } );", 'inline');
186 }
187
188 /******************** Core rewrites *************************/
189
190 /**
191 * Modification of drupal_to_js()
192 * adds support for anonymous arrays & function (non-quoted) strings
193 *
194 * prefix key with # to prevent quoting of value
195 *
196 * @example
197 * interface_to_js(
198 * array('containment' => array('element_1', 'element_2'), '#onUpdate' => 'function(){alert("hi");}'));
199 * returns:
200 * {containment: ['element_1', 'element_2'], onUpdate: function(){alert("hi");}}
201 *
202 * [[[^^^check that^^^]]]
203 *
204 * @param mixed $var
205 * any type of variable
206 *
207 * @param string $key
208 * used internally
209 *
210 * @return string
211 * a javascript representation of the variable
212 */
213 function interface_to_js($var, $key = NULL) {
214 switch (gettype($var)) {
215 case 'boolean':
216 return $var ? 'true' : 'false'; // Lowercase necessary!
217 case 'integer':
218 case 'double':
219 return $var;
220 case 'resource':
221 case 'string':
222 // if the key for this variable starts with a #, don't quote it
223 if ($key{0} == '#') {
224 $output = $var;
225 }
226 else {
227 $output = str_replace(array("\r", "\n"), array('\r', '\n'), addslashes($var));
228 $output = '"'. $output .'"';
229 }
230 return $output;
231 case 'array':
232 //check to see if there are non-numeric keys
233 $keys = false;
234 foreach (array_keys($var) as $key) {
235 if (!is_numeric($key)) {
236 $keys = true;
237 break;
238 }
239 }
240 if (!$keys) {
241 foreach ($var as $v) {
242 $output[] = interface_to_js($v);
243 }
244 return '[ '. implode(', ', $output) .' ]';
245 }
246 // if it's an array with keys, continue to object treatment
247 case 'object':
248 $output = array();
249 foreach ($var as $k => $v) {
250 if ($k{0} == '#') {
251 $ok = substr($k, 1);
252 }
253 else {
254 $ok = $k;
255 }
256 $output[] = $ok .': '. interface_to_js($v, $k);
257 }
258 return '{ '. implode(', ', $output) .' }';
259 default:
260 return 'null';
261 }
262 }
263
264 /**
265 * Implementation of hook_theme()...
266 */
267 function interface_sortable_theme() {
268 return array(
269 'interface_sortable_hidden' => array(
270 'arguments' => array('element')
271 )
272 );
273 }

  ViewVC Help
Powered by ViewVC 1.1.2