[ Index ]

PHP Cross Reference of MyBB 1.8.38

title

Body

[close]

/admin/inc/ -> functions_themes.php (source)

   1  <?php
   2  /**
   3   * MyBB 1.8
   4   * Copyright 2014 MyBB Group, All Rights Reserved
   5   *
   6   * Website: http://www.mybb.com
   7   * License: http://www.mybb.com/about/license
   8   *
   9   */
  10  
  11  /**
  12   * Import an entire theme (stylesheets, properties & templates) from an XML file.
  13   *
  14   * @param string $xml The contents of the XML file
  15   * @param array $options Optional array of options or overrides
  16   * @return boolean True on success, false on failure
  17   */
  18  function import_theme_xml($xml, $options=array())
  19  {
  20      global $mybb, $db;
  21  
  22      $parser = create_xml_parser($xml);
  23      $tree = $parser->get_tree();
  24  
  25      if(!is_array($tree) || !is_array($tree['theme']))
  26      {
  27          return -1;
  28      }
  29  
  30      $theme = $tree['theme'];
  31  
  32      // Do we have MyBB 1.2 template's we're importing?
  33      $css_120 = "";
  34  
  35      if(isset($theme['cssbits']) && is_array($theme['cssbits']))
  36      {
  37          $cssbits = kill_tags($theme['cssbits']);
  38  
  39          foreach($cssbits as $name => $values)
  40          {
  41              $css_120 .= "{$name} {\n";
  42              foreach($values as $property => $value)
  43              {
  44                  if(is_array($value))
  45                  {
  46                      $property = str_replace('_', ':', $property);
  47  
  48                      $css_120 .= "}\n{$name} {$property} {\n";
  49                      foreach($value as $property2 => $value2)
  50                      {
  51                          $css_120 .= "\t{$property2}: {$value2}\n";
  52                      }
  53                  }
  54                  else
  55                  {
  56                      $css_120 .= "\t{$property}: {$value}\n";
  57                  }
  58              }
  59              $css_120 .= "}\n";
  60          }
  61      }
  62  
  63      if(isset($theme['themebits']) && is_array($theme['themebits']))
  64      {
  65          $themebits = kill_tags($theme['themebits']);
  66  
  67          $theme['properties']['tag'] = 'properties';
  68  
  69          foreach($themebits as $name => $value)
  70          {
  71              if($name == "extracss")
  72              {
  73                  $css_120 .= $value;
  74                  continue;
  75              }
  76  
  77              $theme['properties'][$name] = $value;
  78          }
  79      }
  80  
  81      if($css_120)
  82      {
  83          $css_120 = upgrade_css_120_to_140($css_120);
  84          $theme['stylesheets']['tag'] = 'stylesheets';
  85          $theme['stylesheets']['stylesheet'][0]['tag'] = 'stylesheet';
  86          $theme['stylesheets']['stylesheet'][0]['attributes'] = array('name' => 'global.css', 'version' => $mybb->version_code);
  87          $theme['stylesheets']['stylesheet'][0]['value'] = $css_120;
  88  
  89          unset($theme['cssbits']);
  90          unset($theme['themebits']);
  91      }
  92  
  93      if(is_array($theme['properties']))
  94      {
  95          foreach($theme['properties'] as $property => $value)
  96          {
  97              if($property == "tag" || $property == "value")
  98              {
  99                  continue;
 100              }
 101  
 102              if($property == 'colors' || $property == 'disporder')
 103              {
 104                  $data = my_unserialize($value['value']);
 105  
 106                  if(!is_array($data))
 107                  {
 108                      // Bad data?
 109                      continue;
 110                  }
 111  
 112                  $value['value'] = $data;
 113              }
 114  
 115              $properties[$property] = $value['value'];
 116          }
 117      }
 118  
 119      if(empty($mybb->input['name']))
 120      {
 121          $name = $theme['attributes']['name'];
 122      }
 123      else
 124      {
 125          $name = $mybb->input['name'];
 126      }
 127      $version = $theme['attributes']['version'];
 128  
 129      $query = $db->simple_select("themes", "tid", "name='".$db->escape_string($name)."'", array("limit" => 1));
 130      $existingtheme = $db->fetch_array($query);
 131      if(!empty($options['force_name_check']) && $existingtheme)
 132      {
 133          return -3;
 134      }
 135      else if($existingtheme)
 136      {
 137          $options['tid'] = $existingtheme['tid'];
 138      }
 139  
 140      if($mybb->version_code != $version && $options['version_compat'] != 1)
 141      {
 142          return -2;
 143      }
 144  
 145      // Do we have any templates to insert?
 146      if(!empty($theme['templates']['template']) && empty($options['no_templates']))
 147      {    
 148          $templates = $theme['templates']['template'];
 149          if(is_array($templates))
 150          {
 151              // Theme only has one custom template
 152              if(array_key_exists("attributes", $templates))
 153              {
 154                  $templates = array($templates);
 155              }
 156          }
 157  
 158          // Security check
 159          $security_check = false;
 160          foreach($templates as $template)
 161          {
 162              if(check_template($template['value']))
 163              {
 164                  $security_check = true;
 165                  break;
 166              }
 167          }
 168  
 169          if($security_check == true)
 170          {
 171              return -4;
 172          }
 173  
 174          if(!empty($options['templateset']))
 175          {
 176              $sid = (int)$options['templateset'];
 177          }
 178          else
 179          {
 180              $sid = $db->insert_query("templatesets", array('title' => $db->escape_string($name)." Templates"));
 181          }
 182  
 183          $templatecache = array();
 184          foreach($templates as $template)
 185          {
 186              $templatecache[] = array(
 187                  "title" => $db->escape_string($template['attributes']['name']),
 188                  "template" => $db->escape_string($template['value']),
 189                  "sid" => $db->escape_string($sid),
 190                  "version" => $db->escape_string($template['attributes']['version']),
 191                  "dateline" => TIME_NOW
 192              );
 193          }
 194  
 195          foreach($templatecache as $template)
 196          {
 197              // PostgreSQL causes apache to stop sending content sometimes and
 198              // causes the page to stop loading during many queries all at one time
 199              if($db->engine == "pgsql")
 200              {
 201                  echo " ";
 202                  flush();
 203              }
 204  
 205              $db->insert_query("templates", $template);
 206          }
 207  
 208          $properties['templateset'] = $sid;
 209      }
 210  
 211      // Not overriding an existing theme
 212      if(empty($options['tid']))
 213      {
 214          // Insert the theme
 215          if(!isset($options['parent']))
 216          {
 217              $options['parent'] = 0;
 218          }
 219          $theme_id = build_new_theme($name, $properties, $options['parent']);
 220      }
 221      // Overriding an existing - delete refs.
 222      else
 223      {
 224          $db->delete_query("themestylesheets", "tid='{$options['tid']}'");
 225          $db->update_query("themes", array("properties" => $db->escape_string(my_serialize($properties))), "tid='{$options['tid']}'");
 226          $theme_id = $options['tid'];
 227      }
 228  
 229      // If we have any stylesheets, process them
 230      if(!empty($theme['stylesheets']['stylesheet']) && empty($options['no_stylesheets']))
 231      {
 232          // Are we dealing with a single stylesheet?
 233          if(isset($theme['stylesheets']['stylesheet']['tag']))
 234          {
 235              // Trick the system into thinking we have a good array =P
 236              $theme['stylesheets']['stylesheet'] = array($theme['stylesheets']['stylesheet']);
 237          }
 238  
 239          // Retrieve a list of inherited stylesheets
 240          $query = $db->simple_select("themes", "stylesheets", "tid = '{$theme_id}'");
 241          if($db->num_rows($query))
 242          {
 243              $inherited_stylesheets = my_unserialize($db->fetch_field($query, "stylesheets"));
 244  
 245              if(isset($inherited_stylesheets['inherited']) && is_array($inherited_stylesheets['inherited']))
 246              {
 247                  $loop = 1;
 248                  foreach($inherited_stylesheets['inherited'] as $action => $stylesheets)
 249                  {
 250                      foreach($stylesheets as $filename => $stylesheet)
 251                      {
 252                          if($properties['disporder'][basename($filename)])
 253                          {
 254                              continue;
 255                          }
 256  
 257                          $properties['disporder'][basename($filename)] = $loop;
 258                          ++$loop;
 259                      }
 260                  }
 261              }
 262          }
 263  
 264          $loop = 1;
 265          foreach($theme['stylesheets']['stylesheet'] as $stylesheet)
 266          {
 267              $stylesheet['attributes']['name'] = my_substr($stylesheet['attributes']['name'], 0, 30);
 268  
 269              if(substr($stylesheet['attributes']['name'], -4) != ".css")
 270              {
 271                  continue;
 272              }
 273  
 274              if(empty($stylesheet['attributes']['lastmodified']))
 275              {
 276                  $stylesheet['attributes']['lastmodified'] = TIME_NOW;
 277              }
 278  
 279              if(empty($stylesheet['attributes']['disporder']))
 280              {
 281                  $stylesheet['attributes']['disporder'] = $loop;
 282              }
 283  
 284              if(empty($stylesheet['attributes']['attachedto']))
 285              {
 286                  $stylesheet['attributes']['attachedto'] = '';
 287              }
 288  
 289              $properties['disporder'][$stylesheet['attributes']['name']] = $stylesheet['attributes']['disporder'];
 290  
 291              $new_stylesheet = array(
 292                  "name" => $db->escape_string($stylesheet['attributes']['name']),
 293                  "tid" => $theme_id,
 294                  "attachedto" => $db->escape_string($stylesheet['attributes']['attachedto']),
 295                  "stylesheet" => $db->escape_string($stylesheet['value']),
 296                  "lastmodified" => (int)$stylesheet['attributes']['lastmodified'],
 297                  "cachefile" => $db->escape_string($stylesheet['attributes']['name'])
 298              );
 299              $sid = $db->insert_query("themestylesheets", $new_stylesheet);
 300              $css_url = "css.php?stylesheet={$sid}";
 301              $cached = cache_stylesheet($theme_id, $stylesheet['attributes']['name'], $stylesheet['value']);
 302              if($cached)
 303              {
 304                  $css_url = $cached;
 305              }
 306  
 307              $attachedto = $stylesheet['attributes']['attachedto'];
 308              if(!$attachedto)
 309              {
 310                  $attachedto = "global";
 311              }
 312  
 313              // private.php?compose,folders|usercp.php,global|global
 314              $attachedto = explode("|", $attachedto);
 315              foreach($attachedto as $attached_file)
 316              {
 317                  $attached_actions = explode(",", $attached_file);
 318                  $attached_file = array_shift($attached_actions);
 319                  if(count($attached_actions) == 0)
 320                  {
 321                      $attached_actions = array("global");
 322                  }
 323  
 324                  foreach($attached_actions as $action)
 325                  {
 326                      $theme_stylesheets[$attached_file][$action][] = $css_url;
 327                  }
 328              }
 329  
 330              ++$loop;
 331          }
 332          // Now we have our list of built stylesheets, save them
 333          $updated_theme = array(
 334              "stylesheets" => $db->escape_string(my_serialize($theme_stylesheets))
 335          );
 336  
 337          $db->update_query("themes", $updated_theme, "tid='{$theme_id}'");
 338      }
 339  
 340      update_theme_stylesheet_list($theme_id);
 341  
 342      // And done?
 343      return $theme_id;
 344  }
 345  
 346  /**
 347   * Parse theme variables in a specific string.
 348   *
 349   * @param string $string The string to parse variables for
 350   * @param array $variables Array of variables
 351   * @return string Parsed string with variables replaced
 352   */
 353  function parse_theme_variables($string, $variables=array())
 354  {
 355      $find = array();
 356      $replace = array();
 357      foreach(array_keys($variables) as $variable)
 358      {
 359          $find[] = "{{$variable}}";
 360          $replace[] = $variables[$variable];
 361      }
 362      return str_replace($find, $replace, $string);
 363  }
 364  
 365  /**
 366   * Caches a stylesheet to the file system.
 367   *
 368   * @param string $tid The theme ID this stylesheet belongs to.
 369   * @param string $filename The name of the stylesheet.
 370   * @param string $stylesheet The contents of the stylesheet.
 371   *
 372   * @return string The cache file path.
 373   */
 374  function cache_stylesheet($tid, $filename, $stylesheet)
 375  {
 376      global $mybb;
 377  
 378      $filename = basename($filename);
 379      $tid = (int) $tid;
 380      $theme_directory = "cache/themes/theme{$tid}";
 381  
 382      if(substr($filename, -4) != ".css")
 383      {
 384          return false;
 385      }
 386  
 387      // If we're in safe mode save to the main theme folder by default
 388      if($mybb->safemode)
 389      {
 390          $theme_directory = "cache/themes";
 391          $filename = $tid."_".$filename;
 392      }
 393      // Does our theme directory exist? Try and create it.
 394      elseif(!is_dir(MYBB_ROOT . $theme_directory))
 395      {
 396          if(!@mkdir(MYBB_ROOT . $theme_directory))
 397          {
 398              $theme_directory = "cache/themes";
 399              $filename        = $tid."_".$filename;
 400          }
 401          else
 402          {
 403              // Add in empty index.html!
 404              $fp = @fopen(MYBB_ROOT . $theme_directory."/index.html", "w");
 405              @fwrite($fp, "");
 406              @fclose($fp);
 407  
 408          }
 409      }
 410  
 411      $theme_vars = array(
 412          "theme" => $theme_directory
 413      );
 414      $stylesheet = parse_theme_variables($stylesheet, $theme_vars);
 415      $stylesheet = preg_replace_callback("#url\((\"|'|)([^\"'\s]*?)\\1\)#", 'fix_css_urls_callback', $stylesheet);
 416  
 417      $fp = @fopen(MYBB_ROOT . "{$theme_directory}/{$filename}", "wb");
 418      if(!$fp)
 419      {
 420          return false;
 421      }
 422  
 423      @fwrite($fp, $stylesheet);
 424      @fclose($fp);
 425  
 426      $stylesheet_min = minify_stylesheet($stylesheet);
 427      $filename_min = str_replace('.css', '.min.css', $filename);
 428      $fp_min = @fopen(MYBB_ROOT . "{$theme_directory}/{$filename_min}", "wb");
 429      if(!$fp_min)
 430      {
 431          return false;
 432      }
 433      @fwrite($fp_min, $stylesheet_min);
 434      @fclose($fp_min);
 435  
 436      copy_file_to_cdn(MYBB_ROOT . "{$theme_directory}/{$filename}");
 437      copy_file_to_cdn(MYBB_ROOT . "{$theme_directory}/{$filename_min}");
 438  
 439      return "{$theme_directory}/{$filename}";
 440  }
 441  
 442  /**
 443   * Minify a stylesheet to remove comments, linebreaks, whitespace,
 444   * unnecessary semicolons, and prefers #rgb over #rrggbb.
 445   *
 446   * @param $stylesheet string The stylesheet in it's untouched form.
 447   * @return string The minified stylesheet
 448   */
 449  function minify_stylesheet($stylesheet)
 450  {
 451      // Remove comments.
 452      $stylesheet = preg_replace('@/\*.*?\*/@s', '', $stylesheet);
 453      // Remove whitespace around symbols.
 454      $stylesheet = preg_replace('@\s*([{}:;,])\s*@', '\1', $stylesheet);
 455      // Remove unnecessary semicolons.
 456      $stylesheet = preg_replace('@;}@', '}', $stylesheet);
 457      // Replace #rrggbb with #rgb when possible.
 458      $stylesheet = preg_replace('@#([a-f0-9])\1([a-f0-9])\2([a-f0-9])\3@i','#\1\2\3',$stylesheet);
 459      $stylesheet = trim($stylesheet);
 460      return $stylesheet;
 461  }
 462  
 463  /**
 464   * @param array $stylesheet
 465   *
 466   * @return bool
 467   */
 468  function resync_stylesheet($stylesheet)
 469  {
 470      global $db;
 471  
 472      // Try and fix any missing cache file names
 473      if(!$stylesheet['cachefile'] && $stylesheet['name'])
 474      {
 475          $stylesheet['cachefile'] = $stylesheet['name'];
 476          $db->update_query("themestylesheets", array('cachefile' => $db->escape_string($stylesheet['name'])), "sid='{$stylesheet['sid']}'");
 477      }
 478  
 479      // Still don't have the cache file name or is it not a flat file? Return false
 480      if(!$stylesheet['cachefile'] || strpos($stylesheet['cachefile'], 'css.php') !== false)
 481      {
 482          return false;
 483      }
 484  
 485      if(!file_exists(MYBB_ROOT."cache/themes/theme{$stylesheet['tid']}/{$stylesheet['name']}") && !file_exists(MYBB_ROOT."cache/themes/{$stylesheet['tid']}_{$stylesheet['name']}"))
 486      {
 487          if(cache_stylesheet($stylesheet['tid'], $stylesheet['cachefile'], $stylesheet['stylesheet']) !== false)
 488          {
 489              $db->update_query("themestylesheets", array('cachefile' => $db->escape_string($stylesheet['name'])), "sid='{$stylesheet['sid']}'");
 490  
 491              update_theme_stylesheet_list($stylesheet['tid']);
 492  
 493              if($stylesheet['sid'] != 1)
 494              {
 495                  $db->update_query("themestylesheets", array('lastmodified' => TIME_NOW), "sid='{$stylesheet['sid']}'");
 496              }
 497          }
 498  
 499          return true;
 500      }
 501  
 502      return false;
 503  }
 504  
 505  /**
 506   * @deprecated
 507   * @param string $url
 508   *
 509   * @return string
 510   */
 511  function fix_css_urls($url)
 512  {
 513      if(!preg_match("#^([a-z0-9]+\:|/)#i", $url) && strpos($url, "../../../") === false)
 514      {
 515          return "url(../../../{$url})";
 516      }
 517      else
 518      {
 519          return "url({$url})";
 520      }
 521  }
 522  
 523  /**
 524   * @param array $matches Matches.
 525   *
 526   * @return string
 527   */
 528  function fix_css_urls_callback($matches)
 529  {
 530      return fix_css_urls($matches[2]);
 531  }
 532  
 533  /**
 534   * @deprecated
 535   * @param string $url
 536   *
 537   * @return string
 538   */
 539  function unfix_css_urls($url)
 540  {
 541      return str_replace("../../../", "", $url);
 542  }
 543  
 544  /**
 545   * Build a theme based on the specified parameters.
 546   *
 547   * @param string $name The name of the theme
 548   * @param array $properties Array of theme properties (if blank, inherits from parent)
 549   * @param int $parent The parent ID for this theme (defaults to Master)
 550   * @return int The new theme ID
 551   */
 552  function build_new_theme($name, $properties=null, $parent=1)
 553  {
 554      global $db;
 555  
 556      $new_theme = array(
 557          "name" => $db->escape_string($name),
 558          "pid" => (int)$parent,
 559          "def" => 0,
 560          "allowedgroups" => "all",
 561          "properties" => "",
 562          "stylesheets" => ""
 563      );
 564      $tid = $db->insert_query("themes", $new_theme);
 565  
 566      $inherited_properties = false;
 567      $stylesheets = array();
 568      if($parent > 0)
 569      {
 570          $query = $db->simple_select("themes", "*", "tid='".(int)$parent."'");
 571          $parent_theme = $db->fetch_array($query);
 572          if(!is_array($properties) || count($properties) == 0)
 573          {
 574              $parent_properties = my_unserialize($parent_theme['properties']);
 575              if(!empty($parent_properties))
 576              {
 577                  foreach($parent_properties as $property => $value)
 578                  {
 579                      if($property == "inherited")
 580                      {
 581                          continue;
 582                      }
 583  
 584                      $properties[$property] = $value;
 585                      if(!empty($parent_properties['inherited'][$property]))
 586                      {
 587                          $properties['inherited'][$property] = $parent_properties['inherited'][$property];
 588                      }
 589                      else
 590                      {
 591                          $properties['inherited'][$property] = $parent;
 592                      }
 593                  }
 594                  $inherited_properties = true;
 595              }
 596          }
 597  
 598          $parent_stylesheets = my_unserialize($parent_theme['stylesheets']);
 599          if(!empty($parent_stylesheets))
 600          {
 601              foreach($parent_stylesheets as $location => $value)
 602              {
 603                  if($location == "inherited")
 604                  {
 605                      continue;
 606                  }
 607  
 608                  foreach($value as $action => $sheets)
 609                  {
 610                      foreach($sheets as $stylesheet)
 611                      {
 612                          $stylesheets[$location][$action][] = $stylesheet;
 613                          $inherited_check = "{$location}_{$action}";
 614                          if(!empty($parent_stylesheets['inherited'][$inherited_check][$stylesheet]))
 615                          {
 616                              $stylesheets['inherited'][$inherited_check][$stylesheet] = $parent_stylesheets['inherited'][$inherited_check][$stylesheet];
 617                          }
 618                          else
 619                          {
 620                              $stylesheets['inherited'][$inherited_check][$stylesheet] = $parent;
 621                          }
 622                      }
 623                  }
 624              }
 625          }
 626      }
 627  
 628      if(!$inherited_properties)
 629      {
 630          $theme_vars = array(
 631              "theme" => "cache/themes/theme{$tid}"
 632          );
 633          $properties['logo'] = parse_theme_variables($properties['logo'], $theme_vars);
 634      }
 635  
 636      $updated_theme = array();
 637      if(!empty($stylesheets))
 638      {
 639          $updated_theme['stylesheets'] = $db->escape_string(my_serialize($stylesheets));
 640      }
 641      $updated_theme['properties'] = $db->escape_string(my_serialize($properties));
 642  
 643      if(count($updated_theme) > 0)
 644      {
 645          $db->update_query("themes", $updated_theme, "tid='{$tid}'");
 646      }
 647  
 648      return $tid;
 649  }
 650  
 651  /**
 652   * Generates an array from an incoming CSS file.
 653   *
 654   * @param string $css The incoming CSS
 655   * @return array Parsed CSS file as array, false on failure
 656   */
 657  function css_to_array($css)
 658  {
 659      // Normalise line breaks
 660      $css = str_replace(array("\r\n", "\n", "\r"), "\n", $css);
 661  
 662      /**
 663       * Play with the css a  little - just to ensure we can parse it
 664       *
 665       * This essentially adds line breaks before and after each } not inside a string
 666       * so it's parsed correctly below
 667       */
 668      $stripped_css = preg_replace('#(?<!\\")\}#', "\n}\n", $css);
 669  
 670      // Fetch out classes and comments
 671      preg_match_all('#(\/\*(.|[\r\n])*?\*\/)?([a-z0-9a+\\\[\]\-\"=_:>\*\.\#\,\s\(\)\|~|@\^]+)(\s*)\{(.*?)\}\n#msi', $stripped_css, $matches, PREG_PATTERN_ORDER);
 672      $total = count($matches[1]);
 673  
 674      $parsed_css = array();
 675  
 676      for($i=0; $i < $total; $i++)
 677      {
 678          $name = $description = '';
 679          $class_name = $matches[3][$i];
 680          $class_name = trim($class_name);
 681          $comments = $matches[1][$i];
 682          preg_match_all("#Name:(.*)#i", $comments, $name_match);
 683          if(isset($name_match[count($name_match)-1][0]))
 684          {
 685              $name = trim($name_match[count($name_match)-1][0]);
 686          }
 687          preg_match_all("#Description:(.*)#i", $comments, $description_match);
 688          if(isset($description_match[count($description_match)-1][0]))
 689          {
 690              $description = trim($description_match[count($description_match)-1][0]);
 691          }
 692          $class_id = md5($class_name);
 693          if(isset($already_parsed[$class_id]))
 694          {
 695              $already_parsed[$class_id]++;
 696              $class_id .= "_".$already_parsed[$class_id];
 697          }
 698          else
 699          {
 700              $already_parsed[$class_id] = 1;
 701          }
 702          $values = trim($matches[5][$i]);
 703          $values = preg_replace("#/\*(.*?)\*/#s", "", $values);
 704          $parsed_css[$class_id] = array("class_name" => $class_name, "name" => $name, "description" => $description, "values" => $values);
 705      }
 706  
 707      return $parsed_css;
 708  }
 709  
 710  /**
 711   * @param array|string $css
 712   * @param int $selected_item
 713   *
 714   * @return string
 715   */
 716  function get_selectors_as_options($css, $selected_item=null)
 717  {
 718      $select = "";
 719  
 720      if(!is_array($css))
 721      {
 722          $css = css_to_array($css);
 723      }
 724  
 725      $selected = false;
 726  
 727      if(is_array($css))
 728      {
 729          uasort($css, "css_selectors_sort_cmp");
 730  
 731          foreach($css as $id => $css_array)
 732          {
 733              if(!$css_array['name'])
 734              {
 735                  $css_array['name'] = $css_array['class_name'];
 736              }
 737  
 738              if($selected_item == $id || (!$selected_item && !$selected))
 739              {
 740                  $select .= "<option value=\"{$id}\" selected=\"selected\">{$css_array['name']}</option>\n";
 741                  $selected = true;
 742              }
 743              else
 744              {
 745                  $select .= "<option value=\"{$id}\">{$css_array['name']}</option>\n";
 746              }
 747          }
 748      }
 749      return $select;
 750  }
 751  
 752  /**
 753   * @param array $a
 754   * @param array $b
 755   *
 756   * @return int
 757   */
 758  function css_selectors_sort_cmp($a, $b)
 759  {
 760      if(!$a['name'])
 761      {
 762          $a['name'] = $a['class_name'];
 763      }
 764  
 765      if(!$b['name'])
 766      {
 767          $b['name'] = $b['class_name'];
 768      }
 769      return strcmp($a['name'], $b['name']);
 770  }
 771  
 772  /**
 773   * @param array|string $css
 774   * @param string $id
 775   *
 776   * @return array|bool
 777   */
 778  function get_css_properties($css, $id)
 779  {
 780      if(!is_array($css))
 781      {
 782          $css = css_to_array($css);
 783      }
 784  
 785      if(!isset($css[$id]))
 786      {
 787          return false;
 788      }
 789      return parse_css_properties($css[$id]['values']);
 790  }
 791  
 792  /**
 793   * Parses CSS supported properties and returns them as an array.
 794   *
 795   * @param string $values Value of CSS properties from within class or selector
 796   * @return array Array of CSS properties
 797   */
 798  function parse_css_properties($values)
 799  {
 800      $css_bits = array(
 801          'extra' => null,
 802      );
 803  
 804      if(!$values)
 805      {
 806          return null;
 807      }
 808  
 809      $values = explode(";", $values);
 810      foreach($values as $value)
 811      {
 812          $value = trim($value);
 813          if(!$value) continue;
 814          list($property, $css_value) = explode(":", $value, 2);
 815          $property = trim($property);
 816          switch(strtolower($property))
 817          {
 818              case "background":
 819              case "color":
 820              case "width":
 821              case "font-family":
 822              case "font-size":
 823              case "font-weight":
 824              case "font-style":
 825              case "text-decoration":
 826                  $css_bits[$property] = trim($css_value);
 827                  break;
 828              default:
 829                  $css_bits['extra'] .= "{$property}: ".trim($css_value).";\n";
 830  
 831          }
 832      }
 833      return $css_bits;
 834  }
 835  
 836  /**
 837   * Inserts an incoming string of CSS in to an already defined document. If the class ID is not found, the CSS is appended to the file.
 838   *
 839   * @param string $new_css CSS we wish to insert at this location.
 840   * @param string $selector The selector for this piece of CSS.
 841   * @param string $css The existing CSS if we have any.
 842   * @param string $class_id (Optional) The optional friendly class id value just incase the CSS is not found in the file.
 843   *
 844   * @return string The altered CSS.
 845   */
 846  function insert_into_css($new_css, $selector="", $css="", $class_id="")
 847  {
 848      $new_css = str_replace(array("\r\n", "\n", "\r"), "\n", $new_css);
 849  
 850      $generated_css = '';
 851  
 852      // Build the new CSS properties list
 853      $new_css = explode("\n", $new_css);
 854      foreach($new_css as $css_line)
 855      {
 856          $generated_css .= "\t".trim($css_line)."\n";
 857      }
 858  
 859      $parsed_css = array();
 860  
 861      // Parse out the CSS
 862      if($css)
 863      {
 864          $parsed_css = css_to_array($css);
 865      }
 866  
 867      if(!$class_id)
 868      {
 869          $class_id = $parsed_css[$selector]['class_name'];
 870      }
 871  
 872      // The specified class ID cannot be found, add CSS to end of file
 873      if(!$css || !$parsed_css[$selector])
 874      {
 875          return $css."{$class_id}\n{\n{$generated_css}\n}\n\n";
 876      }
 877      // Valid CSS, swap out old, swap in new
 878      else
 879      {
 880          $css = str_replace(array("\r\n", "\n", "\r"), "\n", $css);
 881          $css = preg_replace('#(?<!\\")\}#', "}\n", $css);
 882          $css = preg_replace("#^(?!@)\s*([a-z0-9a+\\\[\]\-\"=_:>\*\.\#\,\s\(\)\|~\^]+)(\s*)\{(\n*)#isu", "\n$1 {\n", $css);
 883          $css = preg_replace("#\s{1,}\{#", " {", $css);
 884          $existing_block = $parsed_css[$selector];
 885  
 886          $break = strrpos($selector, "_");
 887          $actual_occurance = 0;
 888          if($break !== false)
 889          {
 890              $actual_occurance = (int)substr($selector, ($break+1));
 891          }
 892  
 893          if(!$actual_occurance)
 894          {
 895              $actual_occurance = 1;
 896          }
 897  
 898          $occurance = 1;
 899          $pos = 0;
 900          do
 901          {
 902              $pos = strpos($css, "\n".$existing_block['class_name']." {", $pos);
 903              if($pos === false)
 904              {
 905                  break;
 906              }
 907              if($occurance == $actual_occurance)
 908              {
 909                  // This is the part we want to replace, now we need to fetch the opening & closing braces
 910                  $opening = strpos($css, "{", $pos);
 911                  $closing = strpos($css, "}", $pos);
 912                  $css = substr_replace($css, "\n".$generated_css."\n", $opening+1, $closing-$opening-1);
 913                  break;
 914              }
 915              ++$occurance;
 916              ++$pos;
 917          } while($occurance <= $actual_occurance);
 918      }
 919      $css = preg_replace("#{\n*#s", "{\n", $css);
 920      $css = preg_replace("#\s*\}\s*#", "\n}\n\n", $css);
 921      return $css;
 922  }
 923  
 924  /**
 925   * @param array $stylesheet
 926   * @param int $tid
 927   *
 928   * @return bool|int
 929   */
 930  function copy_stylesheet_to_theme($stylesheet, $tid)
 931  {
 932      global $db;
 933  
 934      $stylesheet['tid'] = $tid;
 935      unset($stylesheet['sid']);
 936  
 937      $new_stylesheet = array();
 938      foreach($stylesheet as $key => $value)
 939      {
 940          if(!is_numeric($key))
 941          {
 942              $new_stylesheet[$db->escape_string($key)] = $db->escape_string($value);
 943          }
 944      }
 945  
 946      $sid = $db->insert_query("themestylesheets", $new_stylesheet);
 947  
 948      return $sid;
 949  }
 950  
 951  /**
 952   * @param int $tid
 953   * @param bool|array $theme
 954   * @param bool $update_disporders
 955   *
 956   * @return bool
 957   */
 958  function update_theme_stylesheet_list($tid, $theme = false, $update_disporders = true)
 959  {
 960      global $mybb, $db, $cache, $plugins;
 961  
 962      $stylesheets = array();
 963  
 964      $child_list = make_child_theme_list($tid);
 965      $parent_list = make_parent_theme_list($tid);
 966  
 967      if(!is_array($parent_list))
 968      {
 969          return false;
 970      }
 971  
 972      $tid_list = implode(',', $parent_list);
 973  
 974      // Get our list of stylesheets
 975      $query = $db->simple_select("themestylesheets", "*", "tid IN ({$tid_list})", array('order_by' => 'tid', 'order_dir' => 'desc'));
 976      while($stylesheet = $db->fetch_array($query))
 977      {
 978          if(empty($stylesheets[$stylesheet['name']]))
 979          {
 980              if($stylesheet['tid'] != $tid)
 981              {
 982                  $stylesheet['inherited'] = $stylesheet['tid'];
 983              }
 984  
 985              $stylesheets[$stylesheet['name']] = $stylesheet;
 986          }
 987      }
 988  
 989      $theme_stylesheets = array();
 990  
 991      foreach($stylesheets as $name => $stylesheet)
 992      {
 993          $sid = $stylesheet['sid'];
 994          $css_url = "css.php?stylesheet={$sid}";
 995  
 996          foreach($parent_list as $theme_id)
 997          {
 998              if(!empty($mybb->settings['usecdn']) && !empty($mybb->settings['cdnpath']))
 999              {
1000                  $cdnpath = rtrim($mybb->settings['cdnpath'], '/\\').'/';
1001                  if(file_exists($cdnpath."cache/themes/theme{$theme_id}/{$stylesheet['name']}") && filemtime(
1002                          $cdnpath."cache/themes/theme{$theme_id}/{$stylesheet['name']}"
1003                      ) >= $stylesheet['lastmodified']
1004                  )
1005                  {
1006                      $css_url = "cache/themes/theme{$theme_id}/{$stylesheet['name']}";
1007                      break;
1008                  }
1009              }
1010              else
1011              {
1012                  if(file_exists(MYBB_ROOT."cache/themes/theme{$theme_id}/{$stylesheet['name']}") && filemtime(
1013                          MYBB_ROOT."cache/themes/theme{$theme_id}/{$stylesheet['name']}"
1014                      ) >= $stylesheet['lastmodified']
1015                  )
1016                  {
1017                      $css_url = "cache/themes/theme{$theme_id}/{$stylesheet['name']}";
1018                      break;
1019                  }
1020              }
1021          }
1022  
1023          if(is_object($plugins))
1024          {
1025              $plugins->run_hooks('update_theme_stylesheet_list_set_css_url', $css_url);
1026          }
1027  
1028          $attachedto = $stylesheet['attachedto'];
1029          if(!$attachedto)
1030          {
1031              $attachedto = "global";
1032          }
1033          // private.php?compose,folders|usercp.php,global|global
1034          $attachedto = explode("|", $attachedto);
1035          foreach($attachedto as $attached_file)
1036          {
1037              $attached_actions = array();
1038              if(strpos($attached_file, '?') !== false)
1039              {
1040                  $attached_file = explode('?', $attached_file);
1041                  $attached_actions = explode(",", $attached_file[1]);
1042                  $attached_file = $attached_file[0];
1043              }
1044  
1045              if(count($attached_actions) == 0)
1046              {
1047                  $attached_actions = array("global");
1048              }
1049  
1050              foreach($attached_actions as $action)
1051              {
1052                  $theme_stylesheets[$attached_file][$action][] = $css_url;
1053  
1054                  if(!empty($stylesheet['inherited']))
1055                  {
1056                      $theme_stylesheets['inherited']["{$attached_file}_{$action}"][$css_url] = $stylesheet['inherited'];
1057                  }
1058              }
1059          }
1060      }
1061  
1062      // Now we have our list of built stylesheets, save them
1063      $updated_theme = array(
1064          "stylesheets" => $db->escape_string(my_serialize($theme_stylesheets))
1065      );
1066  
1067      // Do we have a theme present? If so, update the stylesheet display orders
1068      if($update_disporders)
1069      {
1070          if(!is_array($theme) || !$theme)
1071          {
1072              $theme_cache = cache_themes();
1073              $theme = $theme_cache[$tid];
1074          }
1075  
1076          $orders = $orphaned_stylesheets = array();
1077          $properties = $theme['properties'];
1078  
1079          if(!is_array($properties))
1080          {
1081              $properties = my_unserialize($theme['properties']);
1082          }
1083  
1084          $max_disporder = 0;
1085  
1086          foreach($stylesheets as $stylesheet)
1087          {
1088              if(!isset($properties['disporder'][$stylesheet['name']]))
1089              {
1090                  $orphaned_stylesheets[] = $stylesheet['name'];
1091                  continue;
1092              }
1093  
1094              if($properties['disporder'][$stylesheet['name']] > $max_disporder)
1095              {
1096                  $max_disporder = $properties['disporder'][$stylesheet['name']];
1097              }
1098  
1099              $orders[$stylesheet['name']] = $properties['disporder'][$stylesheet['name']];
1100          }
1101  
1102          if(!empty($orphaned_stylesheets))
1103          {
1104              $loop = $max_disporder + 1;
1105              $max_disporder = $loop;
1106              foreach($orphaned_stylesheets as $stylesheet)
1107              {
1108                  $orders[$stylesheet] = $loop;
1109                  ++$loop;
1110              }
1111          }
1112  
1113          asort($orders);
1114          $properties['disporder'] = $orders;
1115          $updated_theme['properties'] = $db->escape_string(my_serialize($properties));
1116      }
1117  
1118      $db->update_query("themes", $updated_theme, "tid = '{$tid}'");
1119  
1120      // Do we have any children themes that need updating too?
1121      if(is_array($child_list) && count($child_list) > 0)
1122      {
1123          foreach($child_list as $id)
1124          {
1125              update_theme_stylesheet_list($id, false, $update_disporders);
1126          }
1127      }
1128  
1129      $cache->update_default_theme();
1130  
1131      return true;
1132  }
1133  
1134  /**
1135   * @param int $tid
1136   *
1137   * @return array|bool
1138   */
1139  function make_parent_theme_list($tid)
1140  {
1141      static $themes_by_parent;
1142  
1143      $themes = array();
1144      if(!is_array($themes_by_parent))
1145      {
1146          $theme_cache = cache_themes();
1147          foreach($theme_cache as $key => $theme)
1148          {
1149              if($key == "default")
1150              {
1151                  continue;
1152              }
1153  
1154              $themes_by_parent[$theme['tid']][$theme['pid']] = $theme;
1155          }
1156      }
1157  
1158      if(!isset($themes_by_parent[$tid]) || !is_array($themes_by_parent[$tid]))
1159      {
1160          return false;
1161      }
1162  
1163      reset($themes_by_parent);
1164      reset($themes_by_parent[$tid]);
1165  
1166      $themes = array();
1167  
1168      foreach($themes_by_parent[$tid] as $key => $theme)
1169      {
1170          $themes[] = $theme['tid'];
1171          $parents = make_parent_theme_list($theme['pid']);
1172  
1173          if(is_array($parents))
1174          {
1175              $themes = array_merge($themes, $parents);
1176          }
1177      }
1178  
1179      return $themes;
1180  }
1181  
1182  /**
1183   * @param int $tid
1184   *
1185   * @return array|null
1186   */
1187  function make_child_theme_list($tid)
1188  {
1189      static $themes_by_child;
1190  
1191      $themes = array();
1192      if(!is_array($themes_by_child))
1193      {
1194          $theme_cache = cache_themes();
1195          foreach($theme_cache as $key => $theme)
1196          {
1197              if($key == "default")
1198              {
1199                  continue;
1200              }
1201  
1202              $themes_by_child[$theme['pid']][$theme['tid']] = $theme;
1203          }
1204      }
1205  
1206      if(!isset($themes_by_child[$tid]) || !is_array($themes_by_child[$tid]))
1207      {
1208          return null;
1209      }
1210  
1211      $themes = array();
1212  
1213      foreach($themes_by_child[$tid] as $theme)
1214      {
1215          $themes[] = $theme['tid'];
1216          $children = make_child_theme_list($theme['tid']);
1217  
1218          if(is_array($children))
1219          {
1220              $themes = array_merge($themes, $children);
1221          }
1222      }
1223  
1224      return $themes;
1225  }
1226  
1227  /**
1228   * @return array
1229   */
1230  function cache_themes()
1231  {
1232      global $db, $theme_cache;
1233  
1234      if(empty($theme_cache) || !is_array($theme_cache))
1235      {
1236          $query = $db->simple_select("themes", "*", "", array('order_by' => "pid, name"));
1237          while($theme = $db->fetch_array($query))
1238          {
1239              $theme['users'] = 0;
1240              $theme['properties'] = my_unserialize($theme['properties']);
1241              $theme['stylesheets'] = my_unserialize($theme['stylesheets']);
1242              $theme_cache[$theme['tid']] = $theme;
1243  
1244              if($theme['def'] == 1)
1245              {
1246                  $theme_cache['default'] = $theme['tid'];
1247              }
1248          }
1249      }
1250  
1251      // Do we have no themes assigned as default?
1252      if(empty($theme_cache['default']))
1253      {
1254          $theme_cache['default'] = 1;
1255      }
1256  
1257      return $theme_cache;
1258  }
1259  
1260  /**
1261   * @param int $parent
1262   * @param int $depth
1263   */
1264  function build_theme_list($parent=0, $depth=0)
1265  {
1266      global $mybb, $db, $table, $lang, $page; // Global $table is bad, but it will have to do for now
1267      static $theme_cache;
1268  
1269      $padding = $depth*20; // Padding
1270  
1271      if(!is_array($theme_cache))
1272      {
1273          $themes = cache_themes();
1274          $query = $db->simple_select("users", "style, COUNT(uid) AS users", "", array('group_by' => 'style'));
1275          while($user_themes = $db->fetch_array($query))
1276          {
1277              if($user_themes['style'] == 0)
1278              {
1279                  $user_themes['style'] = $themes['default'];
1280              }
1281  
1282              if(isset($themes[$user_themes['style']]['users']) && $themes[$user_themes['style']]['users'] > 0)
1283              {
1284                  $themes[$user_themes['style']]['users'] += (int)$user_themes['users'];
1285              }
1286              else
1287              {
1288                  $themes[$user_themes['style']]['users'] = (int)$user_themes['users'];
1289              }
1290          }
1291  
1292          // Restrucure the theme array to something we can "loop-de-loop" with
1293          foreach($themes as $key => $theme)
1294          {
1295              if($key == "default")
1296              {
1297                  continue;
1298              }
1299  
1300              $theme_cache[$theme['pid']][$theme['tid']] = $theme;
1301          }
1302          $theme_cache['num_themes'] = count($themes);
1303          unset($themes);
1304      }
1305  
1306      if(!isset($theme_cache[$parent]) || !is_array($theme_cache[$parent]))
1307      {
1308          return;
1309      }
1310  
1311      foreach($theme_cache[$parent] as $theme)
1312      {
1313          $popup = new PopupMenu("theme_{$theme['tid']}", $lang->options);
1314          $set_default = '';
1315          if($theme['tid'] > 1)
1316          {
1317              $popup->add_item($lang->edit_theme, "index.php?module=style-themes&amp;action=edit&amp;tid={$theme['tid']}");
1318              $theme['name'] = "<a href=\"index.php?module=style-themes&amp;action=edit&amp;tid={$theme['tid']}\">".htmlspecialchars_uni($theme['name'])."</a>";
1319  
1320              // We must have at least the master and 1 other active theme
1321              if($theme_cache['num_themes'] > 2)
1322              {
1323                  $popup->add_item($lang->delete_theme, "index.php?module=style-themes&amp;action=delete&amp;tid={$theme['tid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_theme_deletion}')");
1324              }
1325  
1326              if($theme['def'] != 1)
1327              {
1328                  $popup->add_item($lang->set_as_default, "index.php?module=style-themes&amp;action=set_default&amp;tid={$theme['tid']}&amp;my_post_key={$mybb->post_code}");
1329                  $set_default = "<a href=\"index.php?module=style-themes&amp;action=set_default&amp;tid={$theme['tid']}&amp;my_post_key={$mybb->post_code}\"><img src=\"styles/{$page->style}/images/icons/make_default.png\" alt=\"{$lang->set_as_default}\" style=\"vertical-align: middle;\" title=\"{$lang->set_as_default}\" /></a>";
1330              }
1331              else
1332              {
1333                  $set_default = "<img src=\"styles/{$page->style}/images/icons/default.png\" alt=\"{$lang->default_theme}\" style=\"vertical-align: middle;\" title=\"{$lang->default_theme}\" />";
1334              }
1335              $popup->add_item($lang->force_on_users, "index.php?module=style-themes&amp;action=force&amp;tid={$theme['tid']}&amp;my_post_key={$mybb->post_code}", "return AdminCP.deleteConfirmation(this, '{$lang->confirm_theme_forced}')");
1336              $set_default = "<div class=\"float_right\">{$set_default}</div>";
1337          }
1338          $popup->add_item($lang->export_theme, "index.php?module=style-themes&amp;action=export&amp;tid={$theme['tid']}");
1339          $popup->add_item($lang->duplicate_theme, "index.php?module=style-themes&amp;action=duplicate&amp;tid={$theme['tid']}");
1340          $table->construct_cell("{$set_default}<div style=\"margin-left: {$padding}px;\"><strong>{$theme['name']}</strong></div>");
1341          $table->construct_cell(my_number_format($theme['users']), array("class" => "align_center"));
1342          $table->construct_cell($popup->fetch(), array("class" => "align_center"));
1343          $table->construct_row();
1344  
1345          // Fetch & build any child themes
1346          build_theme_list($theme['tid'], ++$depth);
1347      }
1348  }
1349  
1350  /**
1351   * returns an array which can be sent to generate_select_box()
1352   *
1353   * @param int $ignoretid
1354   * @param int  $parent
1355   * @param int  $depth
1356   *
1357   * @return null|string
1358   */
1359  function build_theme_array($ignoretid = null, $parent=0, $depth=0)
1360  {
1361      global $list;
1362      static $theme_cache;
1363  
1364      if(!is_array($theme_cache))
1365      {
1366          $themes = cache_themes();
1367          // Restrucure the theme array to something we can "loop-de-loop" with
1368          foreach($themes as $key => $theme)
1369          {
1370              if($key == "default")
1371              {
1372                  continue;
1373              }
1374  
1375              $theme_cache[$theme['pid']][$theme['tid']] = $theme;
1376          }
1377          unset($theme);
1378      }
1379  
1380      if(!isset($theme_cache[$parent]) || !is_array($theme_cache[$parent]) || $ignoretid === $parent)
1381      {
1382          return null;
1383      }
1384  
1385      foreach($theme_cache[$parent] as $theme)
1386      {
1387          if($ignoretid === $theme['tid'])
1388          {
1389              continue;
1390          }
1391  
1392          $list[$theme['tid']] = str_repeat("--", $depth).$theme['name'];
1393          // Fetch & build any child themes
1394          build_theme_array($ignoretid, $theme['tid'], $depth+1);
1395      }
1396  
1397      if(!$parent)
1398      {
1399          return $list;
1400      }
1401  }
1402  
1403  /**
1404   * @param array $theme
1405   *
1406   * @return array|bool
1407   */
1408  function fetch_theme_stylesheets($theme)
1409  {
1410      // Fetch list of all of the stylesheets for this theme
1411      $file_stylesheets = my_unserialize($theme['stylesheets']);
1412  
1413      if(!is_array($file_stylesheets))
1414      {
1415          return false;
1416      }
1417  
1418      $stylesheets = array();
1419      $inherited_load = array();
1420  
1421      // Now we loop through the list of stylesheets for each file
1422      foreach($file_stylesheets as $file => $action_stylesheet)
1423      {
1424          if($file == 'inherited')
1425          {
1426              continue;
1427          }
1428  
1429          foreach($action_stylesheet as $action => $style)
1430          {
1431              foreach($style as $stylesheet2)
1432              {
1433                  $stylesheets[$stylesheet2]['applied_to'][$file][] = $action;
1434                  if(isset($file_stylesheets['inherited'][$file."_".$action]) && is_array($file_stylesheets['inherited'][$file."_".$action]) && in_array($stylesheet2, array_keys($file_stylesheets['inherited'][$file."_".$action])))
1435                  {
1436                      $stylesheets[$stylesheet2]['inherited'] = $file_stylesheets['inherited'][$file."_".$action];
1437                      foreach($file_stylesheets['inherited'][$file."_".$action] as $value)
1438                      {
1439                          $inherited_load[] = $value;
1440                      }
1441                  }
1442              }
1443          }
1444      }
1445  
1446      foreach($stylesheets as $file => $stylesheet2)
1447      {
1448          if(isset($stylesheet2['inherited']) && is_array($stylesheet2['inherited']))
1449          {
1450              foreach($stylesheet2['inherited'] as $inherited_file => $tid)
1451              {
1452                  $stylesheet2['inherited'][basename($inherited_file)] = $tid;
1453                  unset($stylesheet2['inherited'][$inherited_file]);
1454              }
1455          }
1456  
1457          $stylesheets[basename($file)] = $stylesheet2;
1458          unset($stylesheets[$file]);
1459      }
1460  
1461      return $stylesheets;
1462  }
1463  
1464  /**
1465   * @param string $css
1466   *
1467   * @return string
1468   */
1469  function upgrade_css_120_to_140($css)
1470  {
1471      global $mybb;
1472      // Update our CSS to the new stuff in 1.4
1473      $parsed_css = css_to_array($css);
1474  
1475      if(!is_array($parsed_css))
1476      {
1477          return "";
1478      }
1479  
1480      foreach($parsed_css as $class_id => $array)
1481      {
1482          $parsed_css[$class_id]['values'] = str_replace('#eea8a1', '#ffdde0', $array['values']);
1483          $parsed_css[$class_id]['values'] = str_replace('font-family: Verdana;', 'font-family: Verdana, Arial, Sans-Serif;', $array['values']);
1484  
1485          switch($array['class_name'])
1486          {
1487              case '.bottommenu':
1488                  $parsed_css[$class_id]['values'] = str_replace('padding: 6px;', 'padding: 10px;', $array['values']);
1489                  break;
1490              case '.expcolimage':
1491                  $parsed_css[$class_id]['values'] .= "\n\tmargin-top: 2px;";
1492                  break;
1493              case '.toolbar_normal':
1494              case '.toolbar_hover':
1495              case '.toolbar_clicked':
1496              case '.pagenav':
1497              case '.pagenavbit':
1498              case '.pagenavbit a':
1499              case '.pagenavcurrent':
1500              case '.quote_header':
1501              case '.quote_body':
1502              case '.code_header':
1503              case '.code_body':
1504              case '.usercpnav':
1505              case '.usercpnav li':
1506              case '.usercpnav .pmfolders':
1507                  unset($parsed_css[$class_id]);
1508                  break;
1509              default:
1510          }
1511      }
1512  
1513      $to_add = array(
1514          md5('.trow_selected td') => array("class_name" => '.trow_selected td', "values" => 'background: #FFFBD9;'),
1515          md5('blockquote') => array("class_name" => 'blockquote', "values" => "border: 1px solid #ccc;\n\tmargin: 0;\n\tbackground: #fff;\n\tpadding: 4px;"),
1516          md5('blockquote cite') => array("class_name" => 'blockquote cite', "values" => "font-weight: bold;\n\tborder-bottom: 1px solid #ccc;\n\tfont-style: normal;\n\tdisplay: block;\n\tmargin: 4px 0;"),
1517          md5('blockquote cite span') => array("class_name" => 'blockquote cite span', "values" => "float: right;\n\tfont-weight: normal;"),
1518          md5('.codeblock') => array("class_name" => '.codeblock', "values" => "background: #fff;\n\tborder: 1px solid #ccc;\n\tpadding: 4px;"),
1519          md5('.codeblock .title') => array("class_name" => '.codeblock .title', "values" => "border-bottom: 1px solid #ccc;\n\tfont-weight: bold;\n\tmargin: 4px 0;"),
1520          md5('.codeblock code') => array("class_name" => '.codeblock code', "values" => "overflow: auto;\n\theight: auto;\n\tmax-height: 200px;\n\tdisplay: block;\n\tfont-family: Monaco, Consolas, Courier, monospace;\n\tfont-size: 13px;"),
1521          md5('.subject_new') => array("class_name" => '.subject_new', "values" => "font-weight: bold;"),
1522          md5('.highlight') => array("class_name" => '.highlight', "values" => "background: #FFFFCC;\n\tpadding: 3px;"),
1523          md5('.pm_alert') => array("class_name" => '.pm_alert', "values" => "background: #FFF6BF;\n\tborder: 1px solid #FFD324;\n\ttext-align: center;\n\tpadding: 5px 20px;\n\tfont-size: 11px;"),
1524          md5('.red_alert') => array("class_name" => '.red_alert', "values" => "background: #FBE3E4;\n\tborder: 1px solid #A5161A;\n\tcolor: #A5161A;\n\ttext-align: center;\n\tpadding: 5px 20px;\n\tfont-size: 11px;"),
1525          md5('.high_warning') => array("class_name" => '.high_warning', "values" => "color: #CC0000;"),
1526          md5('.moderate_warning') => array("class_name" => '.moderate_warning', "values" => "color: #F3611B;"),
1527          md5('.low_warning') => array("class_name" => '.low_warning', "values" => "color: #AE5700;"),
1528          md5('div.error') => array("class_name" => 'div.error', "values" => "padding: 5px 10px;\n\tborder-top: 2px solid #FFD324;\n\tborder-bottom: 2px solid #FFD324;\n\tbackground: #FFF6BF\n\tfont-size: 12px;"),
1529          md5('.high_warning') => array("class_name" => '.high_warning', "values" => "color: #CC0000;"),
1530          md5('.moderate_warning') => array("class_name" => '.moderate_warning', "values" => "color: #F3611B;"),
1531          md5('.low_warning') => array("class_name" => '.low_warning', "values" => "color: #AE5700;"),
1532          md5('div.error') => array("class_name" => 'div.error', "values" => "padding: 5px 10px;\n\tborder-top: 2px solid #FFD324;\n\tborder-bottom: 2px solid #FFD324;\n\tbackground: #FFF6BF;\n\tfont-size: 12px;"),
1533          md5('div.error p') => array("class_name" => 'div.error p', "values" => "margin: 0;\n\tcolor: #000;\n\tfont-weight: normal;"),
1534          md5('div.error p em') => array("class_name" => 'div.error p em', "values" => "font-style: normal;\n\tfont-weight: bold;\n\tpadding-left: 24px;\n\tdisplay: block;\n\tcolor: #C00;\n\tbackground: url({$mybb->settings['bburl']}/images/error.png) no-repeat 0;"),
1535          md5('div.error.ul') => array("class_name" => 'div.error.ul', "values" => "margin-left: 24px;"),
1536          md5('.online') => array("class_name" => '.online', "values" => "color: #15A018;"),
1537          md5('.offline') => array("class_name" => '.offline', "values" => "color: #C7C7C7;"),
1538          md5('.pagination') => array("class_name" => '.pagination', "values" => "font-size: 11px;\n\tpadding-top: 10px;\n\tmargin-bottom: 5px;"),
1539          md5('.tfoot .pagination, .tcat .pagination') => array("class_name" => '.tfoot .pagination, .tcat .pagination', "values" => "padding-top: 0;"),
1540          md5('.pagination .pages') => array("class_name" => '.pagination .pages', "values" => "font-weight: bold;"),
1541          md5('.pagination .pagination_current, .pagination a') => array("class_name" => '.pagination .pagination_current, .pagination a', "values" => "padding: 2px 6px;\n\tmargin-bottom: 3px;"),
1542          md5('.pagination a') => array("class_name" => '.pagination a', "values" => "border: 1px solid #81A2C4;"),
1543          md5('.pagination .pagination_current') => array("class_name" => '.pagination .pagination_current', "values" => "background: #F5F5F5;\n\tborder: 1px solid #81A2C4;\n\tfont-weight: bold;"),
1544          md5('.pagination a:hover') => array("class_name" => '.pagination a:hover', "values" => "background: #F5F5F5;\n\ttext-decoration: none;"),
1545          md5('.thread_legend, .thread_legend dd') => array("class_name" => '.thread_legend, .thread_legend dd', "values" => "margin: 0;\n\tpadding: 0;"),
1546          md5('.thread_legend dd') => array("class_name" => '.thread_legend dd', "values" => "padding-bottom: 4px;\n\tmargin-right: 15px;"),
1547          md5('.thread_legend img') => array("class_name" => '.thread_legend img', "values" => "margin-right: 4px;\n\tvertical-align: bottom;"),
1548          md5('.forum_legend, .forum_legend dt, .forum_legend dd') => array("class_name" => '.forum_legend, .forum_legend dt, .forum_legend dd', "values" => "margin: 0;\n\tpadding: 0;"),
1549          md5('.forum_legend dd') => array("class_name" => '.forum_legend dd', "values" => "float: left;\n\tmargin-right: 10px;"),
1550          md5('.forum_legend dt') => array("class_name" => '.forum_legend dt', "values" => "margin-right: 10px;\n\tfloat: left;"),
1551          md5('.success_message') => array("class_name" => '.success_message', "values" => "color: #00b200;\n\tfont-weight: bold;\n\tfont-size: 10px;\n\tmargin-bottom: 10px;"),
1552          md5('.error_message') => array("class_name" => '.error_message', "values" => "color: #C00;\n\tfont-weight: bold;\n\tfont-size: 10px;\n\tmargin-bottom: 10px;"),
1553          md5('.post_body') => array("class_name" => '.post_body', "values" => "padding: 5px;"),
1554          md5('.post_content') => array("class_name" => '.post_content', "values" => "padding: 5px 10px;"),
1555          md5('.invalid_field') => array("class_name" => '.invalid_field', "values" => "border: 1px solid #f30;\n\tcolor: #f30;"),
1556          md5('.valid_field') => array("class_name" => '.valid_field', "values" => "border: 1px solid #0c0;"),
1557          md5('.validation_error') => array("class_name" => '.validation_error', "values" => "background: url(images/invalid.png) no-repeat center left;\n\tcolor: #f30;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"),
1558          md5('.validation_success') => array("class_name" => '.validation_success', "values" => "background: url(images/valid.png) no-repeat center left;\n\tcolor: #00b200;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"),
1559          md5('.validation_loading') => array("class_name" => '.validation_loading', "values" => "background: url(images/spinner.gif) no-repeat center left;\n\tcolor: #555;\n\tmargin: 5px 0;\n\tpadding: 5px;\n\tfont-weight: bold;\n\tfont-size: 11px;\n\tpadding-left: 22px;"),
1560      );
1561  
1562      $already_parsed = array();
1563  
1564      foreach($to_add as $class_id => $array)
1565      {
1566          if(isset($already_parsed[$class_id]))
1567          {
1568              $already_parsed[$class_id]++;
1569              $class_id .= "_".$already_parsed[$class_id];
1570          }
1571          else
1572          {
1573              $already_parsed[$class_id] = 1;
1574          }
1575  
1576          $array['name'] = "";
1577          $array['description'] = "";
1578  
1579          $parsed_css[$class_id] = $array;
1580      }
1581  
1582      $theme = array(
1583          'css' => '',
1584      );
1585  
1586      $css = "";
1587      foreach($parsed_css as $class_id => $array)
1588      {
1589          if($array['name'] || $array['description'])
1590          {
1591              $theme['css'] .= "/* ";
1592              if($array['name'])
1593              {
1594                  $array['css'] .= "Name: {$array['name']}";
1595  
1596                  if($array['description'])
1597                  {
1598                      $array['css'] .= "\n";
1599                  }
1600              }
1601  
1602              if($array['description'])
1603              {
1604                  $array['css'] .= "Description: {$array['description']}";
1605              }
1606  
1607              $array['css'] .= " */\n";
1608          }
1609  
1610          $css .= "{$array['class_name']} {\n\t{$array['values']}\n}\n";
1611      }
1612  
1613      return $css;
1614  }


2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup Cross-referenced by PHPXref