/[drupal]/contributions/modules/category/category.pages.inc
ViewVC logotype

Contents of /contributions/modules/category/category.pages.inc

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


Revision 1.6 - (show annotations) (download) (as text)
Wed Aug 5 04:52:53 2009 UTC (3 months, 3 weeks ago) by jaza
Branch: MAIN
CVS Tags: DRUPAL-6--2-0-RC1, HEAD
Changes since 1.5: +2 -2 lines
File MIME type: text/x-php
#158598 by JirkaRybka: a massive collection of bug fixes, D6 upgrades, and performance / usability improvements and other tasks for the category package. This commit includes patches from the following threads:
 - #370641: Port category_views to D6
 - #370633: Port category_breadcrumb to D6
 - #484624: Fix all broken category/container previews, and add category_display defaults
 - #481280: Generated menu items vs. menu administration and weights
 - #457688: Get rid of Menu wrapper, moving functionality to category_menu
 - #484084: Update README.txt and friends
 - #483978: Remove t() from database schema descriptions
 - #501378: PERFORMANCE! Central caching for category API functions
 - #521680: Missing argument error on category/### paths
 - #521714: Missing JavaScript file in Taxonomy wrapper
Lots and lots of thanks go to JirkaRybka for this monumental cleanup effort.
1 <?php
2 // $Id: category.pages.inc,v 1.5 2009/03/05 22:23:54 jaza Exp $
3
4 /**
5 * @file
6 * Page callbacks for the category module.
7 */
8
9 /**
10 * Menu callback; displays all nodes associated with a category.
11 */
12 function category_page($str_cids = '', $depth = 0, $op = 'page') {
13 $categories = category_categories_parse_string($str_cids);
14 if ($categories['operator'] != 'and' && $categories['operator'] != 'or') {
15 drupal_not_found();
16 }
17
18 if ($categories['cids']) {
19 $result = db_query(db_rewrite_sql('SELECT n.nid, n.title FROM {node} n WHERE n.nid IN ('. db_placeholders($categories['cids']) .')', 'n', 'nid'), $categories['cids']);
20 $cids = array(); // we rebuild the $cids-array so it only contains categories the user has access to.
21 $names = array();
22 while ($category = db_fetch_object($result)) {
23 $cids[] = $category->nid;
24 $names[] = $category->title;
25 }
26
27 if ($names) {
28 $title = check_plain(implode(', ', $names));
29 drupal_set_title($title);
30
31 switch ($op) {
32 case 'page':
33 // Build breadcrumb based on first hierarchy of first category:
34 $current->cid = $cids[0];
35 $breadcrumb = array();
36 while ($parents = category_get_parents($current->cid)) {
37 $current = array_shift($parents);
38 if (!empty($current->cid)) {
39 $breadcrumb[] = l($current->title, 'category/'. $current->cid);
40 }
41 }
42 $breadcrumb[] = l(t('Home'), NULL);
43 $breadcrumb = array_reverse($breadcrumb);
44 drupal_set_breadcrumb($breadcrumb);
45
46 $output = theme('category_page', $cids, category_select_nodes($cids, $categories['operator'], $depth, TRUE));
47 drupal_add_feed(url('category/'. $str_cids .'/'. $depth .'/feed'), 'RSS - '. $title);
48 return $output;
49 break;
50
51 case 'feed':
52 $channel['link'] = url('category/'. $str_cids .'/'. $depth, array('absolute' => TRUE));
53 $channel['title'] = variable_get('site_name', 'Drupal') .' - '. $title;
54 // Only display the description if we have a single category, to avoid clutter and confusion.
55 if (count($cids) == 1) {
56 $category = node_load($cids[0]);
57 // HTML will be removed from feed description, so no need to filter here.
58 $channel['description'] = $category->teaser;
59 }
60
61 $result = category_select_nodes($cids, $categories['operator'], $depth, FALSE);
62 $items = array();
63 while ($row = db_fetch_object($result)) {
64 $items[] = $row->nid;
65 }
66
67 node_feed($items, $channel);
68 break;
69
70 default:
71 drupal_not_found();
72 }
73 }
74 else {
75 drupal_not_found();
76 }
77 }
78 }
79
80 /**
81 * Render a category category page HTML output.
82 *
83 * @param $cids
84 * An array of category ids.
85 * @param $result
86 * A pager_query() result, such as that performed by category_select_nodes().
87 *
88 * @ingroup themeable
89 */
90 function theme_category_page($cids, $result) {
91 drupal_add_css(drupal_get_path('module', 'category') .'/category.css');
92
93 $output = '';
94
95 // Only display the description if we have a single category, to avoid clutter and confusion.
96 if (count($cids) == 1) {
97 $category = node_load($cids[0]);
98 $description = $category->teaser;
99
100 // Check that a description is set.
101 if (!empty($description)) {
102 $output .= '<div class="category-category-description">';
103 $output .= filter_xss_admin($description);
104 $output .= '</div>';
105 }
106 }
107
108 $output .= category_render_nodes($result);
109
110 return $output;
111 }
112
113 /**
114 * Menu callback; generates the RSS feed for all nodes associated with a
115 * category.
116 */
117 function category_feed($cid) {
118 if (is_numeric($cid)) {
119 $cat = node_load($cid);
120 if (!empty($cat) && !empty($cat->category)) {
121 $channel['link'] = url('node/'. $cid, array('absolute' => TRUE));
122 $channel['title'] = variable_get('site_name', 'drupal') .' - '. check_plain($cat->title);
123 $channel['description'] = $cat->teaser;
124
125 if ($cat->category['depth'] < 0) {
126 $cat->category['depth'] = 'all';
127 }
128 $result = category_select_nodes(array($cid), 'or', $cat->category['depth'], FALSE, TRUE);
129 $nids = array();
130 while ($node = db_fetch_object($result)) {
131 $nids[] = $node->nid;
132 }
133 node_feed($nids, $channel);
134 }
135 }
136 }
137
138 /**
139 * Helper function for autocompletion
140 */
141 function category_autocomplete($cnid, $string = '') {
142 // The user enters a comma-separated list of tags. We only autocomplete the last tag.
143 $array = drupal_explode_tags($string);
144
145 // Fetch last tag
146 $last_string = trim(array_pop($array));
147 $matches = array();
148 if ($last_string != '') {
149 $result = db_query_range(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n INNER JOIN {category} c ON n.nid = c.cid WHERE c.cnid = %d AND LOWER(n.title) LIKE LOWER('%%%s%%')", 'n', 'nid'), $cnid, $last_string, 0, 10);
150
151 $prefix = count($array) ? implode(', ', $array) .', ' : '';
152
153 while ($tag = db_fetch_object($result)) {
154 $n = $tag->title;
155 // Commas and quotes in terms are special cases, so encode 'em.
156 if (strpos($tag->title, ',') !== FALSE || strpos($tag->title, '"') !== FALSE) {
157 $n = '"'. str_replace('"', '""', $tag->title) .'"';
158 }
159 $matches[$prefix . $n] = check_plain($tag->title);
160 }
161 }
162
163 drupal_json($matches);
164 }
165
166 /**
167 * The category wrapper install / uninstall script.
168 *
169 * @param $type
170 * The wrapper being installed or uninstalled ('taxonomy' or 'book').
171 * @param $op
172 * The operation being performed ('install' or 'uninstall').
173 */
174 function category_wrapper($type, $op, $goto = NULL, $rebuild = TRUE) {
175 if (!isset($goto)) {
176 $goto = 'admin/content/category/wrappers';
177 }
178 $generic_error = ' '. t('Unable to perform the specified operation.');
179
180 // Various validation checks
181 if (!($type == 'taxonomy' || $type == 'book') || !($op == 'install' || $op == 'uninstall')) {
182 drupal_set_message(t('Invalid parameters supplied to wrapper install / uninstall script.') . $generic_error, 'error');
183 drupal_goto($goto);
184 }
185 if (!module_exists($type)) {
186 drupal_set_message(t('The %type module is not currently enabled. You must enable it before performing an install or uninstall.', array('%type' => $type)), 'error');
187 drupal_goto($goto);
188 }
189 $status = category_get_wrapper_status($type);
190 if (($status && $op == 'install') || (!$status && $op == 'uninstall')) {
191 drupal_set_message(t('The %type module is already @status.', array('%type' => $type, '@status' => ($status ? t('installed') : t('uninstalled')))) . $generic_error, 'error');
192 drupal_goto($goto);
193 }
194
195 $module_path = drupal_get_path('module', 'category') .'/wrappers/'. $type;
196 $module_file_old = $type .'.module'. ($op == 'install' ? '.php' : '');
197 $module_file_old_path = $module_path .'/'. $module_file_old;
198 if (!file_exists($module_file_old_path)) {
199 drupal_set_message(t('The file %filename could not be found.', array('%filename' => $module_file_old)) . $generic_error, 'error');
200 drupal_goto($goto);
201 }
202
203 $info_file_old = $type .'.info'. ($op == 'install' ? '.php' : '');
204 $info_file_old_path = $module_path .'/'. $info_file_old;
205 if (!file_exists($info_file_old_path)) {
206 drupal_set_message(t('The file %filename could not be found.', array('%filename' => $info_file_old)) . $generic_error, 'error');
207 drupal_goto($goto);
208 }
209
210 $install_file_old = $type .'.install'. ($op == 'install' ? '.php' : '');
211 $install_file_old_path = $module_path .'/'. $install_file_old;
212 if (!file_exists($install_file_old_path)) {
213 drupal_set_message(t('The file %filename could not be found.', array('%filename' => $install_file_old)) . $generic_error, 'error');
214 drupal_goto($goto);
215 }
216
217 $module_file_new = $type .'.module'. ($op == 'install' ? '' : '.php');
218 $module_file_new_path = $module_path .'/'. $module_file_new;
219
220 $info_file_new = $type .'.info'. ($op == 'install' ? '' : '.php');
221 $info_file_new_path = $module_path .'/'. $info_file_new;
222
223 $install_file_new = $type .'.install'. ($op == 'install' ? '' : '.php');
224 $install_file_new_path = $module_path .'/'. $install_file_new;
225
226 if (!@rename($module_file_old_path, $module_file_new_path)) {
227 drupal_set_message(t('The file %filename could not be renamed.', array('%filename' => $module_file_old)) . $generic_error, 'error');
228 drupal_goto($goto);
229 }
230
231 if (!@rename($info_file_old_path, $info_file_new_path)) {
232 drupal_set_message(t('The file %filename could not be renamed.', array('%filename' => $info_file_old)) . $generic_error, 'error');
233 drupal_goto($goto);
234 }
235
236 if (!@rename($install_file_old_path, $install_file_new_path)) {
237 drupal_set_message(t('The file %filename could not be renamed.', array('%filename' => $install_file_old)) . $generic_error, 'error');
238 drupal_goto($goto);
239 }
240
241 if ($type == 'taxonomy' || $type == 'book') {
242 if ($op == 'install') {
243 db_query("UPDATE {system} SET weight = 10 WHERE name = '%s' AND type = 'module'", $type);
244 }
245 else {
246 db_query("UPDATE {system} SET weight = 0 WHERE name = '%s' AND type = 'module'", $type);
247 }
248 }
249
250 drupal_set_message(t('The @type wrapper was @op successfully.', array('@type' => $type, '@op' => ($op == 'install' ? t('installed') : t('uninstalled')))));
251
252 if ($rebuild) {
253 drupal_flush_all_caches();
254 module_rebuild_cache();
255 }
256
257 drupal_goto($goto);
258 }
259
260 /**
261 * AJAX callback to replace the category parent select options.
262 *
263 * This function is called when the selected container is changed. It updates the
264 * cached form and returns rendered output to be used to replace the select
265 * containing the possible parent pages in the newly selected container.
266 *
267 * @param $build_id
268 * The form's build_id.
269 * @param $container
270 * A container from from among those in the form's container select.
271 * @return
272 * Prints the replacement HTML in JSON format.
273 */
274 function category_form_update() {
275 $container_nid = $_POST['category']['hierarchy']['container'];
276
277 if ($form = form_get_cache($_POST['form_build_id'], $form_state)) {
278 // Validate the container id.
279 if (isset($form['category']['hierarchy']['container']['#options'][$container_nid])) {
280 $category_link = $form['#node']->category;
281 $category_link['container'] = $container_nid;
282 if (isset($form['category']['allowed_parents_map']['#value'][$container_nid])) {
283 $category_link['allowed_parent'] = $form['category']['allowed_parents_map']['#value'][$container_nid];
284 }
285 if (isset($form['category']['tags_map']['#value'][$container_nid])) {
286 $category_link['tags'] = $form['category']['tags_map']['#value'][$container_nid];
287 }
288 // Get the new options and update the cache.
289 $form['category']['hierarchy']['parents'] = _category_parent_select($category_link);
290 form_set_cache($_POST['form_build_id'], $form, $form_state);
291
292 // Build and render the new select element, then return it in JSON format.
293 $form_state = array();
294 $form['#post'] = array();
295 $form = form_builder($form['form_id']['#value'] , $form, $form_state);
296 $output = drupal_render($form['category']['hierarchy']['parents']);
297 drupal_json(array('status' => TRUE, 'data' => $output));
298 }
299 else {
300 drupal_json(array('status' => FALSE, 'data' => ''));
301 }
302 }
303 else {
304 drupal_json(array('status' => FALSE, 'data' => ''));
305 }
306 exit();
307 }
308
309 /**
310 * AJAX callback to replace the category select list for distant children.
311 *
312 * This function is called when the parent container is changed. It updates the
313 * cached form and returns rendered output to be used to replace the select
314 * containing the categories of the child container.
315 *
316 * @param $parent_cnid
317 * The ID of the parent container.
318 * @param $child_cnid
319 * The ID of the child container.
320 * @return
321 * Prints the replacement HTML in JSON format.
322 */
323 function category_distant_update($parent_cnid, $child_cnid) {
324 $selection_cids = $_POST['categories'][$parent_cnid];
325
326 $parent_cids = array();
327 $parent_container = NULL;
328 $child_container = NULL;
329 $validates = TRUE;
330
331 if (!empty($selection_cids)) {
332 if (!is_array($selection_cids)) {
333 if (is_numeric($selection_cids)) {
334 $parent_cids[] = $selection_cids;
335 }
336 }
337 else {
338 $parent_cids = array_filter($selection_cids, 'is_numeric');
339 }
340 }
341
342 if (empty($parent_cnid) || empty($child_cnid) ||
343 !is_numeric($parent_cnid) || !is_numeric($child_cnid)) {
344 $validates = FALSE;
345 }
346 else {
347 $parent_container = category_get_container($parent_cnid);
348 $child_container = category_get_container($child_cnid);
349
350 if (empty($parent_container) || empty($child_container)) {
351 $validates = FALSE;
352 }
353 }
354
355 if ($form = form_get_cache($_POST['form_build_id'], $form_state)) {
356
357 foreach ($parent_cids as $parent_cid) {
358 if (!isset($form['categories'][$parent_cnid]['#options'][$parent_cid])) {
359 $validates = FALSE;
360 break;
361 }
362 }
363
364 // Validate the container id.
365 if ($validates) {
366 // Get the new options and update the cache.
367 $form['categories'][$child_cnid] = array_merge(
368 $form['categories'][$child_cnid], category_form($child_cnid, 0,
369 $child_container->help, 'category', $parent_cids));
370 form_set_cache($_POST['form_build_id'], $form, $form_state);
371
372 // Build and render the new select element, then return it in JSON format.
373 $form_state = array();
374 $form['#post'] = array();
375 $form = form_builder($form['form_id']['#value'] , $form, $form_state);
376 $output = drupal_render($form['categories'][$child_cnid]);
377 drupal_json(array('status' => TRUE, 'data' => $output));
378 }
379 else {
380 drupal_json(array('status' => FALSE, 'data' => ''));
381 }
382 }
383 else {
384 drupal_json(array('status' => FALSE, 'data' => ''));
385 }
386 exit();
387 }

  ViewVC Help
Powered by ViewVC 1.1.2