Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

forum_fn.js

Zuletzt modifiziert: 09.10.2024, 12:54 - Dateigröße: 23.48 KiB


 001  /* global phpbb */
 002   
 003  /**
 004  * phpBB3 forum functions
 005  */
 006   
 007  /**
 008  * Find a member
 009  */
 010  function find_username(url) {
 011      'use strict';
 012   
 013      popup(url, 760, 570, '_usersearch');
 014      return false;
 015  }
 016   
 017  /**
 018  * Window popup
 019  */
 020  function popup(url, width, height, name) {
 021      'use strict';
 022   
 023      if (!name) {
 024          name = '_popup';
 025      }
 026   
 027      window.open(url.replace(/&/g, '&'), name, 'height=' + height + ',resizable=yes,scrollbars=yes, width=' + width);
 028      return false;
 029  }
 030   
 031  /**
 032  * Jump to page
 033  */
 034  function pageJump(item) {
 035      'use strict';
 036   
 037      var page = parseInt(item.val(), 10),
 038          perPage = item.attr('data-per-page'),
 039          baseUrl = item.attr('data-base-url'),
 040          startName = item.attr('data-start-name');
 041   
 042      if (page !== null && !isNaN(page) && page === Math.floor(page) && page > 0) {
 043          if (baseUrl.indexOf('?') === -1) {
 044              document.location.href = baseUrl + '?' + startName + '=' + ((page - 1) * perPage);
 045          } else {
 046              document.location.href = baseUrl.replace(/&/g, '&') + '&' + startName + '=' + ((page - 1) * perPage);
 047          }
 048      }
 049  }
 050   
 051  /**
 052  * Mark/unmark checklist
 053  * id = ID of parent container, name = name prefix, state = state [true/false]
 054  */
 055  function marklist(id, name, state) {
 056      'use strict';
 057   
 058      jQuery('#' + id + ' input[type=checkbox][name]').each(function() {
 059          var $this = jQuery(this);
 060          if ($this.attr('name').substr(0, name.length) === name) {
 061              $this.prop('checked', state);
 062          }
 063      });
 064  }
 065   
 066  /**
 067  * Resize viewable area for attached image or topic review panel (possibly others to come)
 068  * e = element
 069  */
 070  function viewableArea(e, itself) {
 071      'use strict';
 072   
 073      if (!e) {
 074          return;
 075      }
 076   
 077      if (!itself) {
 078          e = e.parentNode;
 079      }
 080   
 081      if (!e.vaHeight) {
 082          // Store viewable area height before changing style to auto
 083          e.vaHeight = e.offsetHeight;
 084          e.vaMaxHeight = e.style.maxHeight;
 085          e.style.height = 'auto';
 086          e.style.maxHeight = 'none';
 087          e.style.overflow = 'visible';
 088      } else {
 089          // Restore viewable area height to the default
 090          e.style.height = e.vaHeight + 'px';
 091          e.style.overflow = 'auto';
 092          e.style.maxHeight = e.vaMaxHeight;
 093          e.vaHeight = false;
 094      }
 095  }
 096   
 097  /**
 098  * Alternate display of subPanels
 099  */
 100  jQuery(function($) {
 101      'use strict';
 102   
 103      $('.sub-panels').each(function() {
 104   
 105          var $childNodes = $('a[data-subpanel]', this),
 106              panels = $childNodes.map(function () {
 107                  return this.getAttribute('data-subpanel');
 108              }),
 109              showPanel = this.getAttribute('data-show-panel');
 110   
 111          if (panels.length) {
 112              activateSubPanel(showPanel, panels);
 113              $childNodes.click(function () {
 114                  activateSubPanel(this.getAttribute('data-subpanel'), panels);
 115                  return false;
 116              });
 117          }
 118      });
 119  });
 120   
 121  /**
 122  * Activate specific subPanel
 123  */
 124  function activateSubPanel(p, panels) {
 125      'use strict';
 126   
 127      var i, showPanel;
 128   
 129      if (typeof p === 'string') {
 130          showPanel = p;
 131      }
 132      $('input[name="show_panel"]').val(showPanel);
 133   
 134      if (typeof panels === 'undefined') {
 135          panels = jQuery('.sub-panels a[data-subpanel]').map(function() {
 136              return this.getAttribute('data-subpanel');
 137          });
 138      }
 139   
 140      for (i = 0; i < panels.length; i++) {
 141          jQuery('#' + panels[i]).css('display', panels[i] === showPanel ? 'block' : 'none');
 142          jQuery('#' + panels[i] + '-tab').toggleClass('activetab', panels[i] === showPanel);
 143      }
 144  }
 145   
 146  function selectCode(a) {
 147      'use strict';
 148   
 149      // Get ID of code block
 150      var e = a.parentNode.parentNode.getElementsByTagName('CODE')[0];
 151      var s, r;
 152   
 153      // Not IE and IE9+
 154      if (window.getSelection) {
 155          s = window.getSelection();
 156          // Safari and Chrome
 157          if (s.setBaseAndExtent) {
 158              var l = (e.innerText.length > 1) ? e.innerText.length - 1 : 1;
 159              try {
 160                  s.setBaseAndExtent(e, 0, e, l);
 161              } catch (error) {
 162                  r = document.createRange();
 163                  r.selectNodeContents(e);
 164                  s.removeAllRanges();
 165                  s.addRange(r);
 166              }
 167          }
 168          // Firefox and Opera
 169          else {
 170              // workaround for bug # 42885
 171              if (window.opera && e.innerHTML.substring(e.innerHTML.length - 4) === '<BR>') {
 172                  e.innerHTML = e.innerHTML + '&nbsp;';
 173              }
 174   
 175              r = document.createRange();
 176              r.selectNodeContents(e);
 177              s.removeAllRanges();
 178              s.addRange(r);
 179          }
 180      }
 181      // Some older browsers
 182      else if (document.getSelection) {
 183          s = document.getSelection();
 184          r = document.createRange();
 185          r.selectNodeContents(e);
 186          s.removeAllRanges();
 187          s.addRange(r);
 188      }
 189      // IE
 190      else if (document.selection) {
 191          r = document.body.createTextRange();
 192          r.moveToElementText(e);
 193          r.select();
 194      }
 195  }
 196   
 197  /**
 198  * Play quicktime file by determining it's width/height
 199  * from the displayed rectangle area
 200  */
 201  function play_qt_file(obj) {
 202      'use strict';
 203   
 204      var rectangle = obj.GetRectangle();
 205      var width, height;
 206   
 207      if (rectangle) {
 208          rectangle = rectangle.split(',');
 209          var x1 = parseInt(rectangle[0], 10);
 210          var x2 = parseInt(rectangle[2], 10);
 211          var y1 = parseInt(rectangle[1], 10);
 212          var y2 = parseInt(rectangle[3], 10);
 213   
 214          width = (x1 < 0) ? (x1 * -1) + x2 : x2 - x1;
 215          height = (y1 < 0) ? (y1 * -1) + y2 : y2 - y1;
 216      } else {
 217          width = 200;
 218          height = 0;
 219      }
 220   
 221      obj.width = width;
 222      obj.height = height + 16;
 223   
 224      obj.SetControllerVisible(true);
 225      obj.Play();
 226  }
 227   
 228  var inAutocomplete = false;
 229  var lastKeyEntered = '';
 230   
 231  /**
 232  * Check event key
 233  */
 234  function phpbbCheckKey(event) {
 235      'use strict';
 236   
 237      // Keycode is array down or up?
 238      if (event.keyCode && (event.keyCode === 40 || event.keyCode === 38)) {
 239          inAutocomplete = true;
 240      }
 241   
 242      // Make sure we are not within an "autocompletion" field
 243      if (inAutocomplete) {
 244          // If return pressed and key changed we reset the autocompletion
 245          if (!lastKeyEntered || lastKeyEntered === event.which) {
 246              inAutocomplete = false;
 247              return true;
 248          }
 249      }
 250   
 251      // Keycode is not return, then return. ;)
 252      if (event.which !== 13) {
 253          lastKeyEntered = event.which;
 254          return true;
 255      }
 256   
 257      return false;
 258  }
 259   
 260  /**
 261  * Apply onkeypress event for forcing default submit button on ENTER key press
 262  */
 263  jQuery(function($) {
 264      'use strict';
 265   
 266      $('form input[type=text], form input[type=password]').on('keypress', function (e) {
 267          var defaultButton = $(this).parents('form').find('input[type=submit].default-submit-action');
 268   
 269          if (!defaultButton || defaultButton.length <= 0) {
 270              return true;
 271          }
 272   
 273          if (phpbbCheckKey(e)) {
 274              return true;
 275          }
 276   
 277          if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) {
 278              defaultButton.click();
 279              return false;
 280          }
 281   
 282          return true;
 283      });
 284  });
 285   
 286  /**
 287  * Functions for user search popup
 288  */
 289  function insertUser(formId, value) {
 290      'use strict';
 291   
 292      var $form = jQuery(formId),
 293          formName = $form.attr('data-form-name'),
 294          fieldName = $form.attr('data-field-name'),
 295          item = opener.document.forms[formName][fieldName];
 296   
 297      if (item.value.length && item.type === 'textarea') {
 298          value = item.value + '\n' + value;
 299      }
 300   
 301      item.value = value;
 302  }
 303   
 304  function insert_marked_users(formId, users) {
 305      'use strict';
 306   
 307      for (var i = 0; i < users.length; i++) {
 308          if (users[i].checked) {
 309              insertUser(formId, users[i].value);
 310          }
 311      }
 312   
 313      window.close();
 314  }
 315   
 316  function insert_single_user(formId, user) {
 317      'use strict';
 318   
 319      insertUser(formId, user);
 320      window.close();
 321  }
 322   
 323  /**
 324  * Parse document block
 325  */
 326  function parseDocument($container) {
 327      'use strict';
 328   
 329      var test = document.createElement('div'),
 330          oldBrowser = (typeof test.style.borderRadius === 'undefined'),
 331          $body = $('body');
 332   
 333      /**
 334      * Reset avatar dimensions when changing URL or EMAIL
 335      */
 336      $container.find('input[data-reset-on-edit]').on('keyup', function() {
 337          $(this.getAttribute('data-reset-on-edit')).val('');
 338      });
 339   
 340      /**
 341      * Pagination
 342      */
 343      $container.find('.pagination .page-jump-form :button').click(function() {
 344          var $input = $(this).siblings('input.inputbox');
 345          pageJump($input);
 346      });
 347   
 348      $container.find('.pagination .page-jump-form input.inputbox').on('keypress', function(event) {
 349          if (event.which === 13 || event.keyCode === 13) {
 350              event.preventDefault();
 351              pageJump($(this));
 352          }
 353      });
 354   
 355      $container.find('.pagination .dropdown-trigger').click(function() {
 356          var $dropdownContainer = $(this).parent();
 357          // Wait a little bit to make sure the dropdown has activated
 358          setTimeout(function() {
 359              if ($dropdownContainer.hasClass('dropdown-visible')) {
 360                  $dropdownContainer.find('input.inputbox').focus();
 361              }
 362          }, 100);
 363      });
 364   
 365      /**
 366      * Adjust HTML code for IE8 and older versions
 367      */
 368      // if (oldBrowser) {
 369      //     // Fix .linklist.bulletin lists
 370      //     $container
 371      //         .find('ul.linklist.bulletin > li')
 372      //         .filter(':first-child, .rightside:last-child')
 373      //         .addClass('no-bulletin');
 374      // }
 375   
 376      /**
 377      * Resize navigation (breadcrumbs) block to keep all links on same line
 378      */
 379      $container.find('.navlinks').each(function() {
 380          var $this = $(this),
 381              $left = $this.children().not('.rightside'),
 382              $right = $this.children('.rightside');
 383   
 384          if ($left.length !== 1 || !$right.length) {
 385              return;
 386          }
 387   
 388          function resize() {
 389              var width = 0,
 390                  diff = $left.outerWidth(true) - $left.width(),
 391                  minWidth = Math.max($this.width() / 3, 240),
 392                  maxWidth;
 393   
 394              $right.each(function() {
 395                  var $this = $(this);
 396                  if ($this.is(':visible')) {
 397                      width += $this.outerWidth(true);
 398                  }
 399              });
 400   
 401              maxWidth = $this.width() - width - diff;
 402              $left.css('max-width', Math.floor(Math.max(maxWidth, minWidth)) + 'px');
 403          }
 404   
 405          resize();
 406          $(window).resize(resize);
 407      });
 408   
 409      /**
 410      * Makes breadcrumbs responsive
 411      */
 412      $container.find('.breadcrumbs:not([data-skip-responsive])').each(function() {
 413          var $this = $(this),
 414              $links = $this.find('.crumb'),
 415              length = $links.length,
 416              classes = ['wrapped-max', 'wrapped-wide', 'wrapped-medium', 'wrapped-small', 'wrapped-tiny'],
 417              classesLength = classes.length,
 418              maxHeight = 0,
 419              lastWidth = false,
 420              wrapped = false;
 421   
 422          // Set tooltips
 423          $this.find('a').each(function() {
 424              var $link = $(this);
 425              $link.attr('title', $link.text());
 426          });
 427   
 428          // Function that checks breadcrumbs
 429          function check() {
 430              var height = $this.height(),
 431                  width;
 432   
 433              // Test max-width set in code for .navlinks above
 434              width = parseInt($this.css('max-width'), 10);
 435              if (!width) {
 436                  width = $body.width();
 437              }
 438   
 439              maxHeight = parseInt($this.css('line-height'), 10);
 440              $links.each(function() {
 441                  if ($(this).height() > 0) {
 442                      maxHeight = Math.max(maxHeight, $(this).outerHeight(true));
 443                  }
 444              });
 445   
 446              if (height <= maxHeight) {
 447                  if (!wrapped || lastWidth === false || lastWidth >= width) {
 448                      return;
 449                  }
 450              }
 451              lastWidth = width;
 452   
 453              if (wrapped) {
 454                  $this.removeClass('wrapped').find('.crumb.wrapped').removeClass('wrapped ' + classes.join(' '));
 455                  if ($this.height() <= maxHeight) {
 456                      return;
 457                  }
 458              }
 459   
 460              wrapped = true;
 461              $this.addClass('wrapped');
 462              if ($this.height() <= maxHeight) {
 463                  return;
 464              }
 465   
 466              for (var i = 0; i < classesLength; i++) {
 467                  for (var j = length - 1; j >= 0; j--) {
 468                      $links.eq(j).addClass('wrapped ' + classes[i]);
 469                      if ($this.height() <= maxHeight) {
 470                          return;
 471                      }
 472                  }
 473              }
 474          }
 475   
 476          // Run function and set event
 477          check();
 478          $(window).resize(check);
 479      });
 480   
 481      /**
 482      * Responsive link lists
 483      */
 484      var selector = '.linklist:not(.navlinks, [data-skip-responsive]),' +
 485          '.postbody .post-buttons:not([data-skip-responsive])';
 486      $container.find(selector).each(function() {
 487          var $this = $(this),
 488              filterSkip = '.breadcrumbs, [data-skip-responsive]',
 489              filterLast = '.edit-icon, .quote-icon, [data-last-responsive]',
 490              $linksAll = $this.children(),
 491              $linksNotSkip = $linksAll.not(filterSkip), // All items that can potentially be hidden
 492              $linksFirst = $linksNotSkip.not(filterLast), // The items that will be hidden first
 493              $linksLast = $linksNotSkip.filter(filterLast), // The items that will be hidden last
 494              persistent = $this.attr('id') === 'nav-main', // Does this list already have a menu (such as quick-links)?
 495              html = '<li class="responsive-menu hidden"><a href="javascript:void(0);" class="js-responsive-menu-link responsive-menu-link"><i class="icon fa-bars fa-fw" aria-hidden="true"></i></a><div class="dropdown"><div class="pointer"><div class="pointer-inner" /></div><ul class="dropdown-contents" /></div></li>',
 496              slack = 3; // Vertical slack space (in pixels). Determines how sensitive the script is in determining whether a line-break has occured.
 497   
 498          // Add a hidden drop-down menu to each links list (except those that already have one)
 499          if (!persistent) {
 500              if ($linksNotSkip.is('.rightside')) {
 501                  $linksNotSkip.filter('.rightside:first').before(html);
 502                  $this.children('.responsive-menu').addClass('rightside');
 503              } else {
 504                  $this.append(html);
 505              }
 506          }
 507   
 508          // Set some object references and initial states
 509          var $menu = $this.children('.responsive-menu'),
 510              $menuContents = $menu.find('.dropdown-contents'),
 511              persistentContent = $menuContents.find('li:not(.separator)').length,
 512              lastWidth = false,
 513              compact = false,
 514              responsive1 = false,
 515              responsive2 = false,
 516              copied1 = false,
 517              copied2 = false,
 518              maxHeight = 0;
 519   
 520          // Find the tallest element in the list (we assume that all elements are roughly the same height)
 521          $linksAll.each(function() {
 522              if (!$(this).height()) {
 523                  return;
 524              }
 525              maxHeight = Math.max(maxHeight, $(this).outerHeight(true));
 526          });
 527          if (maxHeight < 1) {
 528              return; // Shouldn't be possible, but just in case, abort
 529          } else {
 530              maxHeight = maxHeight + slack;
 531          }
 532   
 533          function check() {
 534              var width = $body.width();
 535              // We can't make it any smaller than this, so just skip
 536              if (responsive2 && compact && (width <= lastWidth)) {
 537                  return;
 538              }
 539              lastWidth = width;
 540   
 541              // Reset responsive and compact layout
 542              if (responsive1 || responsive2) {
 543                  $linksNotSkip.removeClass('hidden');
 544                  $menuContents.children('.clone').addClass('hidden');
 545                  responsive1 = responsive2 = false;
 546              }
 547              if (compact) {
 548                  $this.removeClass('compact');
 549                  compact = false;
 550              }
 551   
 552              // Unhide the quick-links menu if it has "persistent" content
 553              if (persistent && persistentContent) {
 554                  $menu.removeClass('hidden');
 555              } else {
 556                  $menu.addClass('hidden');
 557              }
 558   
 559              // Nothing to resize if block's height is not bigger than tallest element's height
 560              if ($this.height() <= maxHeight) {
 561                  return;
 562              }
 563   
 564              // STEP 1: Compact
 565              if (!compact) {
 566                  $this.addClass('compact');
 567                  compact = true;
 568              }
 569              if ($this.height() <= maxHeight) {
 570                  return;
 571              }
 572   
 573              // STEP 2: First responsive set - compact
 574              if (compact) {
 575                  $this.removeClass('compact');
 576                  compact = false;
 577              }
 578              // Copy the list items to the dropdown
 579              if (!copied1) {
 580                  var $clones1 = $linksFirst.clone();
 581                  $menuContents.prepend($clones1.addClass('clone clone-first').removeClass('leftside rightside'));
 582   
 583                  if ($this.hasClass('post-buttons')) {
 584                      $('.button', $menuContents).removeClass('button');
 585                      $('.sr-only', $menuContents).removeClass('sr-only');
 586                      $('.js-responsive-menu-link').addClass('button').addClass('button-icon-only');
 587                      $('.js-responsive-menu-link .icon').removeClass('fa-bars').addClass('fa-ellipsis-h');
 588                  }
 589                  copied1 = true;
 590              }
 591              if (!responsive1) {
 592                  $linksFirst.addClass('hidden');
 593                  responsive1 = true;
 594                  $menuContents.children('.clone-first').removeClass('hidden');
 595                  $menu.removeClass('hidden');
 596              }
 597              if ($this.height() <= maxHeight) {
 598                  return;
 599              }
 600   
 601              // STEP 3: First responsive set + compact
 602              if (!compact) {
 603                  $this.addClass('compact');
 604                  compact = true;
 605              }
 606              if ($this.height() <= maxHeight) {
 607                  return;
 608              }
 609   
 610              // STEP 4: Last responsive set - compact
 611              if (!$linksLast.length) {
 612                  return; // No other links to hide, can't do more
 613              }
 614              if (compact) {
 615                  $this.removeClass('compact');
 616                  compact = false;
 617              }
 618              // Copy the list items to the dropdown
 619              if (!copied2) {
 620                  var $clones2 = $linksLast.clone();
 621                  $menuContents.prepend($clones2.addClass('clone clone-last').removeClass('leftside rightside'));
 622                  copied2 = true;
 623              }
 624              if (!responsive2) {
 625                  $linksLast.addClass('hidden');
 626                  responsive2 = true;
 627                  $menuContents.children('.clone-last').removeClass('hidden');
 628              }
 629              if ($this.height() <= maxHeight) {
 630                  return;
 631              }
 632   
 633              // STEP 5: Last responsive set + compact
 634              if (!compact) {
 635                  $this.addClass('compact');
 636                  compact = true;
 637              }
 638          }
 639   
 640          if (!persistent) {
 641              phpbb.registerDropdown($menu.find('a.js-responsive-menu-link'), $menu.find('.dropdown'), false);
 642          }
 643   
 644          // If there are any images in the links list, run the check again after they have loaded
 645          $linksAll.find('img').each(function() {
 646              $(this).load(function() {
 647                  check();
 648              });
 649          });
 650   
 651          check();
 652          $(window).resize(check);
 653      });
 654   
 655      /**
 656      * Do not run functions below for old browsers
 657      */
 658      if (oldBrowser) {
 659          return;
 660      }
 661   
 662      /**
 663      * Adjust topiclist lists with check boxes
 664      */
 665      $container.find('ul.topiclist dd.mark').siblings('dt').children('.list-inner').addClass('with-mark');
 666   
 667      /**
 668      * Appends contents of all extra columns to first column in
 669      * .topiclist lists for mobile devices. Copies contents as is.
 670      *
 671      * To add that functionality to .topiclist list simply add
 672      * responsive-show-all to list of classes
 673      */
 674      $container.find('.topiclist.responsive-show-all > li > dl').each(function() {
 675          var $this = $(this),
 676              $block = $this.find('dt .responsive-show:last-child'),
 677              first = true;
 678   
 679          // Create block that is visible only on mobile devices
 680          if (!$block.length) {
 681              $this.find('dt > .list-inner').append('<div class="responsive-show" style="display:none;" />');
 682              $block = $this.find('dt .responsive-show:last-child');
 683          } else {
 684              first = ($.trim($block.text()).length === 0);
 685          }
 686   
 687          // Copy contents of each column
 688          $this.find('dd').not('.mark').each(function() {
 689              var column = $(this),
 690                  $children = column.children(),
 691                  html = column.html();
 692   
 693              if ($children.length === 1 && $children.text() === column.text()) {
 694                  html = $children.html();
 695              }
 696   
 697              $block.append((first ? '' : '<br />') + html);
 698   
 699              first = false;
 700          });
 701      });
 702   
 703      /**
 704      * Same as above, but prepends text from header to each
 705      * column before contents of that column.
 706      *
 707      * To add that functionality to .topiclist list simply add
 708      * responsive-show-columns to list of classes
 709      */
 710      $container.find('.topiclist.responsive-show-columns').each(function() {
 711          var $list = $(this),
 712              headers = [],
 713              headersLength = 0;
 714   
 715          // Find all headers, get contents
 716          $list.prev('.topiclist').find('li.header dd').not('.mark').each(function() {
 717              headers.push($(this).text());
 718              headersLength++;
 719          });
 720   
 721          if (!headersLength) {
 722              return;
 723          }
 724   
 725          // Parse each row
 726          $list.find('dl').each(function() {
 727              var $this = $(this),
 728                  $block = $this.find('dt .responsive-show:last-child'),
 729                  first = true;
 730   
 731              // Create block that is visible only on mobile devices
 732              if (!$block.length) {
 733                  $this.find('dt > .list-inner').append('<div class="responsive-show" style="display:none;" />');
 734                  $block = $this.find('dt .responsive-show:last-child');
 735              } else {
 736                  first = ($.trim($block.text()).length === 0);
 737              }
 738   
 739              // Copy contents of each column
 740              $this.find('dd').not('.mark').each(function(i) {
 741                  var column = $(this),
 742                      children = column.children(),
 743                      html = column.html();
 744   
 745                  if (children.length === 1 && children.text() === column.text()) {
 746                      html = children.html();
 747                  }
 748   
 749                  // Prepend contents of matching header before contents of column
 750                  if (i < headersLength) {
 751                      html = headers[i] + ': <strong>' + html + '</strong>';
 752                  }
 753   
 754                  $block.append((first ? '' : '<br />') + html);
 755   
 756                  first = false;
 757              });
 758          });
 759      });
 760   
 761      /**
 762      * Responsive tables
 763      */
 764      $container.find('table.table1').not('.not-responsive').each(function() {
 765          var $this = $(this),
 766              $th = $this.find('thead > tr > th'),
 767              headers = [],
 768              totalHeaders = 0,
 769              i, headersLength;
 770   
 771          // Find each header
 772          $th.each(function(column) {
 773              var cell = $(this),
 774                  colspan = parseInt(cell.attr('colspan'), 10),
 775                  dfn = cell.attr('data-dfn'),
 776                  text = dfn ? dfn : cell.text();
 777   
 778              colspan = isNaN(colspan) || colspan < 1 ? 1 : colspan;
 779   
 780              for (i = 0; i < colspan; i++) {
 781                  headers.push(text);
 782              }
 783              totalHeaders++;
 784   
 785              if (dfn && !column) {
 786                  $this.addClass('show-header');
 787              }
 788          });
 789   
 790          headersLength = headers.length;
 791   
 792          // Add header text to each cell as <dfn>
 793          $this.addClass('responsive');
 794   
 795          if (totalHeaders < 2) {
 796              $this.addClass('show-header');
 797              return;
 798          }
 799   
 800          $this.find('tbody > tr').each(function() {
 801              var row = $(this),
 802                  cells = row.children('td'),
 803                  column = 0;
 804   
 805              if (cells.length === 1) {
 806                  row.addClass('big-column');
 807                  return;
 808              }
 809   
 810              cells.each(function() {
 811                  var cell = $(this),
 812                      colspan = parseInt(cell.attr('colspan'), 10),
 813                      text = $.trim(cell.text());
 814   
 815                  if (headersLength <= column) {
 816                      return;
 817                  }
 818   
 819                  if ((text.length && text !== '-') || cell.children().length) {
 820                      cell.prepend('<dfn style="display: none;">' + headers[column] + '</dfn>');
 821                  } else {
 822                      cell.addClass('empty');
 823                  }
 824   
 825                  colspan = isNaN(colspan) || colspan < 1 ? 1 : colspan;
 826                  column += colspan;
 827              });
 828          });
 829      });
 830   
 831      /**
 832      * Hide empty responsive tables
 833      */
 834      $container.find('table.responsive > tbody').not('.responsive-skip-empty').each(function() {
 835          var $items = $(this).children('tr');
 836          if (!$items.length) {
 837              $(this).parent('table:first').addClass('responsive-hide');
 838          }
 839      });
 840   
 841      /**
 842      * Responsive tabs
 843      */
 844      $container.find('#tabs, #minitabs').not('[data-skip-responsive]').each(function() {
 845          var $this = $(this),
 846              $ul = $this.children(),
 847              $tabs = $ul.children().not('[data-skip-responsive]'),
 848              $links = $tabs.children('a'),
 849              $item = $ul.append('<li class="tab responsive-tab" style="display:none;"><a href="javascript:void(0);" class="responsive-tab-link">&nbsp;</a><div class="dropdown tab-dropdown" style="display: none;"><div class="pointer"><div class="pointer-inner" /></div><ul class="dropdown-contents" /></div></li>').find('li.responsive-tab'),
 850              $menu = $item.find('.dropdown-contents'),
 851              maxHeight = 0,
 852              lastWidth = false,
 853              responsive = false;
 854   
 855          $links.each(function() {
 856              var $this = $(this);
 857              maxHeight = Math.max(maxHeight, Math.max($this.outerHeight(true), $this.parent().outerHeight(true)));
 858          });
 859   
 860          function check() {
 861              var width = $body.width(),
 862                  height = $this.height();
 863   
 864              if (!arguments.length && (!responsive || width <= lastWidth) && height <= maxHeight) {
 865                  return;
 866              }
 867   
 868              $tabs.show();
 869              $item.hide();
 870   
 871              lastWidth = width;
 872              height = $this.height();
 873              if (height <= maxHeight) {
 874                  if ($item.hasClass('dropdown-visible')) {
 875                      phpbb.toggleDropdown.call($item.find('a.responsive-tab-link').get(0));
 876                  }
 877                  return;
 878              }
 879   
 880              responsive = true;
 881              $item.show();
 882              $menu.html('');
 883   
 884              var $availableTabs = $tabs.filter(':not(.activetab, .responsive-tab)'),
 885                  total = $availableTabs.length,
 886                  i, $tab;
 887   
 888              for (i = total - 1; i >= 0; i--) {
 889                  $tab = $availableTabs.eq(i);
 890                  $menu.prepend($tab.clone(true).removeClass('tab'));
 891                  $tab.hide();
 892                  if ($this.height() <= maxHeight) {
 893                      $menu.find('a').click(function() {
 894                          check(true);
 895                      });
 896                      return;
 897                  }
 898              }
 899              $menu.find('a').click(function() {
 900                  check(true);
 901              });
 902          }
 903   
 904          var $tabLink = $item.find('a.responsive-tab-link');
 905          phpbb.registerDropdown($tabLink, $item.find('.dropdown'), {
 906              visibleClass: 'activetab'
 907          });
 908   
 909          check(true);
 910          $(window).resize(check);
 911      });
 912   
 913      /**
 914       * Hide UCP/MCP navigation if there is only 1 item
 915       */
 916      $container.find('#navigation').each(function() {
 917          var $items = $(this).children('ol, ul').children('li');
 918          if ($items.length === 1) {
 919              $(this).addClass('responsive-hide');
 920          }
 921      });
 922   
 923      /**
 924      * Replace responsive text
 925      */
 926      $container.find('[data-responsive-text]').each(function() {
 927          var $this = $(this),
 928              fullText = $this.text(),
 929              responsiveText = $this.attr('data-responsive-text'),
 930              responsive = false;
 931   
 932          function check() {
 933              if ($(window).width() > 700) {
 934                  if (!responsive) {
 935                      return;
 936                  }
 937                  $this.text(fullText);
 938                  responsive = false;
 939                  return;
 940              }
 941              if (responsive) {
 942                  return;
 943              }
 944              $this.text(responsiveText);
 945              responsive = true;
 946          }
 947   
 948          check();
 949          $(window).resize(check);
 950      });
 951  }
 952   
 953  /**
 954  * Run onload functions
 955  */
 956  jQuery(function($) {
 957      'use strict';
 958   
 959      // Swap .nojs and .hasjs
 960      $('#phpbb.nojs').toggleClass('nojs hasjs');
 961      $('#phpbb').toggleClass('hastouch', phpbb.isTouch);
 962      $('#phpbb.hastouch').removeClass('notouch');
 963   
 964      // Focus forms
 965      $('form[data-focus]:first').each(function() {
 966          $('#' + this.getAttribute('data-focus')).focus();
 967      });
 968   
 969      parseDocument($('body'));
 970  });
 971