[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/devel_themer/ -> devel_themer.module (source)

   1  <?php
   2  
   3  /**
   4   * Implementation of hook_menu().
   5   */
   6  function devel_themer_menu() {
   7    $items = array();
   8  
   9    $items['admin/settings/devel_themer'] = array(
  10      'title' => 'Theme Developer',
  11      'description' => 'Display or hide the textual template log',
  12      'page callback' => 'drupal_get_form',
  13      'page arguments' => array('devel_themer_admin_settings'),
  14      'access arguments' => array('administer site configuration'),
  15      'type' => MENU_NORMAL_ITEM,
  16    );
  17    $items['devel_themer/variables'] = array(
  18      'title' => 'Theme Development AJAX variables',
  19      'page callback' => 'devel_themer_ajax_variables',
  20      'access callback' => 'devel_themer_user_access',
  21      'type' => MENU_CALLBACK,
  22    );
  23    $items['devel/devel_themer'] = array(
  24      'title callback' => 'devel_themer_set_menu_text',
  25      'description' => 'Quickly enable or disable theme developer module.',
  26      'page callback' => 'devel_themer_toggle',
  27      'access arguments' => array('access devel information'),
  28      'menu_name' => 'devel',
  29      // Have a weight other than zero here, so that the item does not flip around
  30      // position depending on the text of the link. Most of the other links are weight zero.
  31      // The link can easily be moved to another position via admin -> menu
  32      'weight' => 5,
  33    );
  34    return $items;
  35  }
  36  
  37  /**
  38   * Helper function to set the menu link text.
  39   */
  40  function devel_themer_set_menu_text() {
  41    return devel_themer_enabled() ? t('Disable Theme Developer') : t('Enable Theme Developer');
  42  }
  43  
  44  /**
  45   * Implementation of hook_menu_link_alter().
  46   * Flag this link as needing alter at display time. This is more robust than setting
  47   * alter in hook_menu(). See devel_themer_translated_menu_link_alter().
  48   *
  49   */
  50  function devel_themer_menu_link_alter(&$item, $menu) {
  51    if ($item['link_path'] == 'devel/devel_themer') {
  52      $item['options']['alter'] = TRUE;
  53    }
  54  }
  55  
  56  /**
  57   * Implementation of hook_translated_menu_item_alter().
  58   * Append dynamic querystring 'destination' to our own menu item.
  59   *
  60   */
  61  function devel_themer_translated_menu_link_alter(&$item) {
  62    if ($item['href'] == 'devel/devel_themer') {
  63      $item['localized_options']['query'] = drupal_get_destination();
  64    }
  65  }
  66  
  67  /**
  68   * A menu callback used by popup to retrieve variables from cache for a recent page.
  69   * 
  70   * @param $request_id
  71   *   A unique key that is sent to the browser in Drupal.Settings.devel_themer_request_id
  72   * @param $call
  73   *   The theme call for which you wish to retrieve variables.
  74   * @return string
  75   * A chunk of HTML with the devel_print_object() rendering of the variables.
  76   */
  77  function devel_themer_ajax_variables($request_id, $call) {
  78    $file = file_directory_temp(). "/devel_themer_$request_id";
  79    if ($data = unserialize(file_get_contents($file))) {
  80      $variables = $data[$call]['variables'];
  81      if (has_krumo()) {      
  82        print krumo_ob($variables);      
  83      } 
  84      elseif ($data[$call]['type'] == 'func') {      
  85        print devel_print_object($variables, NULL, FALSE);      
  86      }
  87      else {
  88        print devel_print_object($variables, '$', FALSE);
  89      }
  90    }
  91    else {
  92      print 'Ajax variables file not found. -'. check_plain($file);
  93    }
  94    $GLOBALS['devel_shutdown'] = FALSE;
  95    return;
  96  }
  97  
  98  /**
  99   * Toggle the Devel Themer.
 100   * This is called from the Devel menu link.
 101   * 
 102   * @return void
 103   */
 104  function devel_themer_toggle() {
 105    if (devel_themer_enabled()) {
 106      devel_themer_enabled(FALSE);
 107      drupal_set_message(t('Devel Themer module is now disabled.'));
 108    }
 109    else {
 110      devel_themer_enabled(TRUE);
 111      drupal_set_message(t('Devel Themer module is now enabled. Tick the "themer info" box to display theme information.'));
 112    }
 113    drupal_goto();
 114  }
 115  
 116  /**
 117   * Set and/or return the status of Devel Themer.
 118   * @param
 119   *   $enable - TRUE to enable the themer.
 120   *             FALSE to disable the themer.
 121   *             NULL to leave it unchanged.
 122   *
 123   * @return
 124   *   TRUE if themer is enabled, FALSE if not.
 125   */
 126  function devel_themer_enabled($enable = NULL) {
 127    if (!is_null($enable)) {
 128      variable_set('devel_themer_enabled', (bool)$enable);
 129    }
 130    return variable_get('devel_themer_enabled', TRUE);
 131  }
 132  
 133  function devel_themer_admin_settings() {
 134    $form['devel_themer_log'] = array('#type' => 'checkbox',
 135      '#title' => t('Display theme log'),
 136      '#default_value' => variable_get('devel_themer_log', FALSE),
 137      '#description' => t('Display the list of theme templates and theme functions which could have been be used for a given page. The one that was actually used is bolded. This is the same data as the represented in the popup, but all calls are listed in chronological order and can alternately be sorted by time.'),
 138    );
 139    return system_settings_form($form);
 140  }
 141  
 142  /**
 143   * Implementation of hook_perm().
 144   */
 145  function devel_themer_perm() {
 146    return array('access devel theme information');
 147  }
 148  
 149  function devel_themer_init() {
 150    if (devel_themer_enabled() && devel_themer_user_access()) {
 151      $path = drupal_get_path('module', 'devel_themer');
 152      $path_to_devel = drupal_get_path('module', 'devel');
 153      // we inject our HTML after page has loaded we have to add this manually.
 154      if (has_krumo()) {
 155        drupal_add_js($path_to_devel. '/krumo/krumo.js');
 156        drupal_add_css($path_to_devel. '/krumo/skins/default/skin.css');
 157      }
 158      drupal_add_css($path .'/devel_themer.css');
 159      drupal_add_js($path .'/devel_themer.js');
 160      
 161      // The order these last two are loaded is important.
 162      if (module_exists('jquery_ui'))
 163      {
 164        jquery_ui_add('ui.core');
 165        // Early versions of jquery_ui still need ui.mouse included.
 166        $jquery_version = explode(".",jquery_ui_get_version());
 167        if ($jquery_version[0] < 1 || ($jquery_version[0] == 1 && $jquery_version[1] < 5)) {
 168          jquery_ui_add('ui.mouse');
 169        }
 170        jquery_ui_add('ui.draggable');
 171      }
 172      else
 173      {
 174        drupal_add_js($path_to_devel .'/ui.mouse.js');
 175        drupal_add_js($path_to_devel .'/ui.draggable.js');
 176      }
 177      
 178      // This needs to happen after all the other CSS.
 179      drupal_set_html_head('<!--[if IE]>
 180      <link href="' . base_path() . $path .'/devel_themer_ie_fix.css" rel="stylesheet" type="text/css" media="screen" />
 181  <![endif]-->');
 182      devel_themer_popup();
 183  
 184      if (!devel_silent() && variable_get('devel_themer_log', FALSE)) {
 185        register_shutdown_function('devel_themer_shutdown');
 186      }
 187    }
 188  }
 189  
 190  function devel_themer_shutdown() {
 191    print devel_themer_log();
 192  }
 193  
 194  /**
 195   * An implementation of hook_theme_registry_alter()
 196   * Iterate over theme registry, injecting our catch function into every theme call, including template calls.
 197   * The catch function logs theme calls and performs divine nastiness.
 198   *
 199   * @return void
 200   **/
 201  function devel_themer_theme_registry_alter($theme_registry) {
 202    foreach ($theme_registry as $hook => $data) {
 203      if (isset($theme_registry[$hook]['function'])) {
 204        // If the hook is a function, store it so it can be run after it has been intercepted.
 205        // This does not apply to template calls.
 206        $theme_registry[$hook]['devel_function_intercept'] = $theme_registry[$hook]['function'];
 207      }
 208      // Add  our catch function to intercept functions as well as templates.
 209      $theme_registry[$hook]['function'] = 'devel_themer_catch_function';
 210    }
 211  }
 212  
 213  /**
 214   * Show all theme templates and functions that could have been used on this page.
 215   **/
 216  function devel_themer_log() {
 217    if (isset($GLOBALS['devel_theme_calls'])) {
 218      foreach ($GLOBALS['devel_theme_calls'] as $counter => $call) {
 219        // Sometimes $call is a string.  Not sure why.
 220        if (is_array($call)) {
 221          $id = "devel_theme_log_link_$counter";
 222          $marker = "<div id=\"$id\" class=\"devel_theme_log_link\"></div>\n";
 223  
 224          $used = $call['used'];
 225          if ($call['type'] == 'func') {
 226            $name = $call['name']. '()';
 227            foreach ($call['candidates'] as $item) {
 228              if ($item == $used) {
 229                $items[] = "<strong>$used</strong>";
 230              }
 231              else {
 232                $items[] = $item;
 233              }
 234            }
 235          }
 236          else {
 237            $name = $call['name'];
 238            foreach ($call['candidates'] as $item) {
 239              if ($item == basename($used)) {
 240                $items[] = "<strong>$used</strong>";
 241              }
 242              else {
 243                $items[] = $item;
 244              }
 245            }
 246          }
 247          $rows[] = array($call['duration'], $marker. $name, implode(', ', $items));
 248          unset($items);
 249        }
 250      }
 251      $header = array('Duration (ms)', 'Template/Function', "Candidate template files or function names");
 252      $output = theme('table', $header, $rows);
 253      return $output;
 254    }
 255  }
 256  
 257  // Would be nice if theme() broke this into separate function so we don't copy logic here. this one is better - has cache
 258  function devel_themer_get_extension() {
 259    global $theme_engine;
 260    static $extension = NULL;
 261  
 262    if (!$extension) {
 263      $extension_function = $theme_engine .'_extension';
 264      if (function_exists($extension_function)) {
 265        $extension = $extension_function();
 266      }
 267      else {
 268        $extension = '.tpl.php';
 269      }
 270    }
 271    return $extension;
 272  }
 273  
 274  /**
 275   * Intercepts all theme calls (including templates), adds to template log, and dispatches to original theme function.
 276   * This function gets injected into theme registry in devel_themer_theme_registry_alter().
 277   */
 278  function devel_themer_catch_function() {
 279    $args = func_get_args();
 280  
 281    // Get the hook argument passed to theme() by stepping through the backtrace
 282    // to the closest entry of theme() being called, and get its first argument.
 283    $trace = debug_backtrace();
 284    foreach ($trace as $trace_entry) {
 285      if ($trace_entry['function'] == 'theme') {
 286        $hook = $trace_entry['args'][0];
 287        break;
 288      }
 289    }
 290    array_unshift($args, $hook);
 291  
 292    $counter = devel_counter();
 293    $timer_name = "thmr_$counter";
 294    timer_start($timer_name);
 295  
 296    // The twin of theme(). All rendering done through here.
 297    list($return, $meta) = call_user_func_array('devel_themer_theme_twin', $args);
 298    $time = timer_stop($timer_name);
 299  
 300    $skip_calls = array('hidden', 'form_element', 'placeholder');
 301    if (devel_themer_enabled() && !empty($return) && !is_array($return) && !is_object($return) && devel_themer_user_access()) {
 302      list($prefix, $suffix) = devel_theme_call_marker($hook, $counter, 'func');
 303      $start_return = substr($return, 0, 31);
 304      $start_prefix = substr($prefix, 0, 31);
 305  
 306      if ($start_return != $start_prefix && !in_array($hook, $skip_calls) && empty($GLOBALS['devel_themer_stop'])) {
 307        if ($hook == 'page') {
 308          $GLOBALS['devel_theme_calls']['page_id'] = $counter;
 309          // Stop logging theme calls after we see theme('page'). This prevents
 310          // needless logging of devel module's query log, for example. Other modules may set this global as needed.
 311          $GLOBALS['devel_themer_stop'] = TRUE;
 312        }
 313        else {
 314          $output = variable_get('devel_themer_no_whitespace', FALSE) ? ($prefix . $return . $suffix) : ($prefix. "\n  ". $return. $suffix. "\n");
 315        }
 316  
 317        if ($meta['type'] == 'func') {
 318          $name = $meta['used'];
 319          $used = $meta['used'];
 320          if (empty($meta['wildcards'])) {
 321            $meta['wildcards'][$hook] = '';
 322          }  
 323          $candidates = devel_themer_ancestry(array_reverse(array_keys($meta['wildcards'])));
 324          if (empty($meta['variables'])) {
 325            $variables = array();
 326          }
 327        }
 328        else {
 329          $name = $hook; 
 330          if (empty($suggestions)) {
 331            array_unshift($meta['suggestions'], $meta['used']);
 332          }
 333          $candidates = array_reverse(array_map('devel_themer_append_extension', $meta['suggestions']));
 334          $used = $meta['template_file'];
 335        }
 336  
 337        $key = "thmr_$counter";
 338        // This variable gets sent to the browser in Drupal.settings.
 339        $GLOBALS['devel_theme_calls'][$key] = array(
 340          'name' => $name,
 341          'type' => $meta['type'],
 342          'duration' => $time['time'],
 343          'used' => $used,
 344          'candidates' => $candidates,
 345          'preprocessors' => isset($meta['preprocessors']) ? $meta['preprocessors'] : array(),
 346        );
 347        
 348        // This variable gets serialized and cached on the server.
 349        $GLOBALS['devel_themer_server'][$key] = array(
 350          'variables' => $meta['variables'],
 351          'type' => $meta['type'],
 352        );
 353      }
 354      else {
 355        $output = $return;
 356      }
 357    }
 358  
 359    return isset($output) ? $output : $return;
 360  }
 361  
 362  function devel_themer_append_extension($string) {
 363    return $string. devel_themer_get_extension();
 364  }
 365  
 366  /**
 367   * For  given theme *function* call, return the ancestry of function names which could have handled the call.
 368   * This mimics the way the theme registry is built.
 369   *
 370   * @param array
 371   *  A list of theme calls.
 372   * @return array()
 373   *   An array of function names.
 374   **/
 375  function devel_themer_ancestry($calls) {
 376    global $theme, $theme_engine, $base_theme_info;
 377    static $prefixes;
 378    if (!isset($prefixes)) {
 379      $prefixes[] = 'theme';
 380      if (isset($base_theme_info)) {
 381        foreach ($base_theme_info as $base) {
 382          $prefixes[] = $base->name;
 383        }
 384      }
 385      $prefixes[] = $theme_engine;
 386      $prefixes[] = $theme;
 387      $prefixes = array_filter($prefixes);
 388    }
 389  
 390    foreach ($calls as $call) {
 391      foreach ($prefixes as $prefix) {
 392        $candidates[] = $prefix. '_'. $call;
 393      }
 394    }
 395    return array_reverse($candidates);
 396  }
 397  
 398  /**
 399   * An unfortunate copy/paste of theme(). This one is called by the devel_themer_catch_function()
 400   * and processes all theme calls but gives us info about the candidates, timings, etc. Without this twin,
 401   * it was impossible to capture calls to module owned templates (e.g. user_profile) and awkward to determine
 402   * which template was finally called and how long it took.
 403   *
 404   * @return array
 405   *   A two element array. First element contains the HTML from the theme call. The second contains 
 406   *   a metadata array about the call. 
 407   *
 408   **/
 409  function devel_themer_theme_twin() {
 410    $args = func_get_args();
 411    $hook = array_shift($args);
 412  
 413    static $hooks = NULL;
 414    if (!isset($hooks)) {
 415      init_theme();
 416      $hooks = theme_get_registry();
 417    }
 418  
 419    // Gather all possible wildcard functions.
 420    $meta['wildcards'] = array();
 421    if (is_array($hook)) {
 422      foreach ($hook as $candidate) {
 423        $meta['wildcards'][$candidate] = FALSE;
 424        if (isset($hooks[$candidate])) {
 425          $meta['wildcards'][$candidate] = TRUE;
 426          break;
 427        }
 428      }
 429      $hook = $candidate;
 430    }
 431  
 432    // This should not be needed but some users are getting errors. See http://drupal.org/node/209929
 433    if (!isset($hooks[$hook])) {
 434      return array('', $meta);
 435    }
 436  
 437    $info = $hooks[$hook];
 438    $meta['hook'] = $hook;
 439    $meta['path'] = $info['theme path'];
 440  
 441    // Include a file if the theme function or preprocess function is held elsewhere.
 442    if (!empty($info['include files'])) {
 443      foreach ($info['include files'] as $include_file) {
 444        include_once($include_file);
 445      }
 446    }
 447  
 448    // Handle compatibility with theme_registry_alters to prevent failures.
 449    if (!empty($info['file'])) {
 450      static $included_files = array();
 451      $include_file = $info['file'];
 452      if (!empty($info['path'])) {
 453        $include_file = $info['path'] .'/'. $include_file;
 454      }
 455  
 456      if (empty($included_files[$include_file])) {
 457        // Statically cache files we've already tried to include so we don't
 458        // run unnecessary file_exists calls.
 459        $included_files[$include_file] = TRUE;
 460        if (file_exists('./'. $include_file)) {
 461          include_once('./'. $include_file);
 462        }
 463      }
 464    }
 465  
 466    if (isset($info['devel_function_intercept'])) {
 467      // The theme call is a function.
 468      $output = call_user_func_array($info['devel_function_intercept'], $args);
 469      $meta['type'] = 'func';
 470      $meta['used'] = $info['devel_function_intercept'];
 471      // Try to populate the keys of $args with variable names. Works on PHP5+.
 472      if (!empty($args) && class_exists('ReflectionFunction')) {
 473        $reflect = new ReflectionFunction($info['devel_function_intercept']);
 474        $params = $reflect->getParameters();
 475        for ($i=0; $i < count($args); $i++) {
 476          // The implementation of the theme function may recieve less parameters than were passed to it.
 477          if ($i < count($params)) {
 478            $meta['variables'][$params[$i]->getName()] = $args[$i];
 479          }
 480          else {
 481            // @TODO:  Consider informing theme developers of theme functions that accept less parameters
 482            //         than are passed to them. This could be disabled by default, with an option to 
 483            //         enable at admin/settings/devel_themer.  Given this is a theme developer module 
 484            //         used by implementors of theme override functions, it would probably be a useful
 485            //         default feature.
 486            $meta['variables'][] = $args[$i];
 487          }
 488        }
 489      }
 490      else {
 491        $meta['variables'] = $args;
 492      }
 493    }
 494    else {
 495      // The theme call is a template.
 496      $meta['type'] = 'tpl';
 497      $meta['used'] = str_replace($info['theme path'] .'/', '', $info['template']);
 498      $variables = array(
 499        'template_files' => array()
 500      );
 501      if (!empty($info['arguments'])) {
 502        $count = 0;
 503        foreach ($info['arguments'] as $name => $default) {
 504          $variables[$name] = isset($args[$count]) ? $args[$count] : $default;
 505          $count++;
 506        }
 507      }
 508  
 509      // default render function and extension.
 510      $render_function = 'theme_render_template';
 511      $extension = '.tpl.php';
 512  
 513      // Run through the theme engine variables, if necessary
 514      global $theme_engine;
 515      if (isset($theme_engine)) {
 516        // If theme or theme engine is implementing this, it may have
 517        // a different extension and a different renderer.
 518        if ($info['type'] != 'module') {
 519          if (function_exists($theme_engine .'_render_template')) {
 520            $render_function = $theme_engine .'_render_template';
 521          }
 522          $extension_function = $theme_engine .'_extension';
 523          if (function_exists($extension_function)) {
 524            $extension = $extension_function();
 525          }
 526        }
 527      }
 528  
 529      if (isset($info['preprocess functions']) && is_array($info['preprocess functions'])) {
 530        // This construct ensures that we can keep a reference through
 531        // call_user_func_array.
 532        $args = array(&$variables, $hook);
 533        foreach ($info['preprocess functions'] as $preprocess_function) {
 534          if (function_exists($preprocess_function)) {
 535            call_user_func_array($preprocess_function, $args);
 536          }
 537        }
 538      }
 539  
 540      // Get suggestions for alternate templates out of the variables
 541      // that were set. This lets us dynamically choose a template
 542      // from a list. The order is FILO, so this array is ordered from
 543      // least appropriate first to most appropriate last.
 544      $suggestions = array();
 545  
 546      if (isset($variables['template_files'])) {
 547        $suggestions = $variables['template_files'];
 548      }
 549      if (isset($variables['template_file'])) {
 550        $suggestions[] = $variables['template_file'];
 551      }
 552  
 553      if ($suggestions) {
 554        $template_file = drupal_discover_template($info['theme paths'], $suggestions, $extension);
 555      }
 556  
 557      if (empty($template_file)) {
 558        $template_file = $info['template'] . $extension;
 559        if (isset($info['path'])) {
 560          $template_file = $info['path'] .'/'. $template_file;
 561        }
 562      }
 563      $output = $render_function($template_file, $variables);
 564      $meta['suggestions'] = $suggestions;
 565      $meta['template_file'] = $template_file;
 566      $meta['variables'] = $variables;
 567      $meta['preprocessors'] = $info['preprocess functions'];
 568    }
 569  
 570    return array($output, $meta);
 571  }
 572  
 573  // We save the huge js array here instead of hook_footer so we can catch theme('page')
 574  function devel_themer_exit($destination = NULL) {
 575    if (!isset($destination) && !empty($GLOBALS['devel_theme_calls']) && $_SERVER['REQUEST_METHOD'] != 'POST') {
 576      // A random string that is sent to the browser. It enables the popup to retrieve params/variables from this request.
 577      $request_id = uniqid(rand());
 578      // Write the variables information to the a file. It will be retrieved on demand via AJAX.
 579      // We used to write this to DB but was getting 'Warning: Got a packet bigger than 'max_allowed_packet' bytes'
 580      // Writing to temp dir means we don't worry about folder existence/perms and cleanup is free.
 581      devel_put_contents(file_directory_temp(). "/devel_themer_$request_id", serialize($GLOBALS['devel_themer_server']));
 582  
 583      $GLOBALS['devel_theme_calls']['request_id'] = $request_id;
 584      $GLOBALS['devel_theme_calls']['devel_themer_uri'] = url("devel_themer/variables/$request_id");
 585      print '<script type="text/javascript">jQuery.extend(Drupal.settings, '.  drupal_to_js($GLOBALS['devel_theme_calls']) .");</script>\n";
 586    }
 587  }
 588  
 589  function devel_theme_call_marker($name, $counter, $type) {
 590    $id = "thmr_". $counter;
 591    return array("<span id=\"$id\" class=\"thmr_call\">", "</span>\n");
 592  }
 593  
 594  // just hand out next counter, or return current value
 595  function devel_counter($increment = TRUE) {
 596    static $counter = 0;
 597    if ($increment) {
 598      $counter++;
 599    }
 600    return $counter;
 601  }
 602  
 603  /**
 604   * Return the popup template
 605   * placed here for easy editing
 606   */
 607  function devel_themer_popup() {
 608    $majorver = substr(VERSION, 0, strpos(VERSION, '.'));
 609  
 610    // add translatable strings
 611    drupal_add_js(array('thmrStrings' =>
 612      array(
 613        'themer_info' => t('Themer info'),
 614        'toggle_throbber' => ' <img src="'. base_path() . drupal_get_path('module', 'devel'). '/loader-little.gif' .'" alt="'. t('loading') .'" class="throbber" width="16" height="16" style="display:none" />',
 615        'parents' => t('Parents: '),
 616        'function_called' => t('Function called: '),
 617        'template_called' => t('Theme hook called: '),
 618        'candidate_files' => t('Candidate template files: '),
 619        'preprocessors' => t('Preprocess functions: '),
 620        'candidate_functions' => t('Candidate function names: '),
 621        'drupal_api_docs' => t('link to Drupal API documentation'),
 622        'source_link_title' => t('link to source code'),
 623        'function_arguments' => t('Function Arguments'),
 624        'template_variables' => t('Template Variables'),
 625        'file_used' => t('File used: '),
 626        'duration' => t('Duration: '),
 627        'api_site' => variable_get('devel_api_site', 'http://api.drupal.org/'),
 628        'drupal_version' => $majorver,
 629        'source_link' => url('devel/source', array('query' => array('file' => ''))),
 630      ))
 631      , 'setting');
 632  
 633    $title = t('Drupal Themer Information');
 634    $intro = t('Click on any element to see information about the Drupal theme function or template that created it.');
 635  
 636    $popup = <<<EOT
 637    <div id="themer-fixeder">
 638    <div id="themer-relativer">
 639    <div id="themer-popup">
 640        <div class="topper">
 641          <span class="close">X</span> $title
 642        </div>
 643        <div id="parents" class="row">
 644  
 645        </div>
 646        <div class="info row">
 647          <div class="starter">$intro</div>
 648          <dl>
 649            <dt class="key-type">
 650  
 651            </dt>
 652            <dd class="key">
 653  
 654            </dd>
 655            <div class="used">
 656            </div>
 657            <dt class="candidates-type">
 658  
 659            </dt>
 660            <dd class="candidates">
 661  
 662            </dd>
 663            
 664            <dt class="preprocessors-type">
 665  
 666            </dt>
 667            <dd class="preprocessors">
 668  
 669            </dd>
 670            
 671            <div class="duration"></div>
 672          </dl>
 673        </div><!-- /info -->
 674        <div class="attributes row">
 675  
 676        </div><!-- /attributes -->
 677      </div><!-- /themer-popup -->
 678      </div>
 679      </div>
 680  EOT;
 681  
 682    drupal_add_js(array('thmr_popup' => $popup), 'setting');
 683  }
 684  
 685  // Temporary - for D6 only since we support PHP4
 686  function devel_put_contents($n, $d, $flag = false) {
 687      if (function_exists('file_put_contents')){
 688          file_put_contents($n, $d, $flag);
 689      } else {
 690          $mode = ($flag == FILE_APPEND || strtoupper($flag) == 'FILE_APPEND') ? 'a' : 'w';
 691          $f = @fopen($n, $mode);
 692          if ($f === false) {
 693              return 0;
 694          } else {
 695              if (is_array($d)) $d = implode($d);
 696              fwrite($f, $d);
 697              fclose($f);
 698          }
 699      }
 700  }
 701  
 702  /**
 703   * Clean up the files we dropped in the temp dir in devel_themer_exit().
 704   *
 705   * Limitation: one more devel_themer_exit() will run after this function is
 706   * called and drop one more file, since hook_exit() is called after the normal
 707   * page cycle.
 708   *
 709   * @return
 710   *   void.
 711   */
 712  function devel_themer_cleanup() {
 713    foreach (array_keys(file_scan_directory(file_directory_temp(), 'devel_themer_*', array('.', '..', 'CVS'), 0, FALSE)) as $file) {
 714      file_delete($file);
 715    }
 716  }
 717  
 718  /**
 719   * Implement hook_cron() for periodic cleanup.
 720   * 
 721   * @return
 722   *   void.
 723   */
 724  function devel_themer_cron() {
 725    devel_themer_cleanup();
 726  }
 727  
 728  /**
 729   * Determine whether the user has permission to access the information provided by this module.
 730   *
 731   * @param $account
 732   *   (optional) The account to check, if not given use currently logged in user.
 733   *
 734   * @return
 735   *   Boolean TRUE if the user has permission to access the information provided
 736   *   by this module.
 737   *
 738   * @see user_access()
 739   */
 740  function devel_themer_user_access($account = NULL) {
 741    // Users with access to devel information from the devel module should
 742    // automatically get access to the theme information as well.
 743    return (user_access('access devel information', $account) || user_access('access devel theme information', $account));
 744  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7