Subversion Repositories web.creative

Rev

Blame | Last modification | View Log | Download

<?php namespace ProcessWire;

/**
 * ProcessWire Language Field Tabs
 *
 * Organizes Language Fields into tabs for a cleaner easier to use interface
 *
 * By Adamspruijt and Ryan Cramer, Copyright 2013/2014
 * 
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer
 * https://processwire.com
 * 
 * @property string $tabField Name of field/property to use for tab labels.
 * 
 *
 */

class LanguageTabs extends WireData implements Module, ConfigurableModule {

  public static function getModuleInfo() {
    return array(
      'title' => 'Languages Support - Tabs',
      'version' => 114,
      'summary' => 'Organizes multi-language fields into tabs for a cleaner easier to use interface.',
      'author' => 'adamspruijt, ryan', 
      'singular' => true,
      'autoload' => "template=admin",
      'requires' => 'LanguageSupport'
    );
  }

  /**
   * Temporary storage of tabs created from addTab() method
   * 
   * @var array of strings
   * 
   */
  protected $tabs = array();
  
  protected $settings = array();
  
  public function __construct() {
    $this->set('tabField', 'title');
  }

  /**
   * Add hooks, setup JS config, and determine active tab
   * 
   */
  public function ready() {
    if($this->wire('page')->template != 'admin') return;
    $this->addHookAfter('InputfieldForm::render', $this, 'hookRenderInputfieldForm'); 
  }
  
  public function getSettings() {
    if(!empty($this->settings)) return $this->settings;
    $language = null;
    // allow for specifying language in your "edit" page link, from front-end
    // so if you want to focus on the Spanish tabs when the user clicks "edit"
    // from /es/path/to/page/, then you can by using a page edit link like:
    // <a href='{$config->urls->admin}page/edit/?id=$page->id&language=$user->language'>Edit</a>
    $id = (int) $this->input->get('language');
    if($id) $language = $this->languages->get($id);

    // if language is not specified as a GET variable, then use the user's language
    if(!$language || !$language->id) $language = $this->user->language;

    // determine the index of the tab for the user's language 
    $activeTab = 0;
    foreach($this->languages as $index => $lang) {
      if($lang->id == $language->id) $activeTab = $index;
    }

    $defaults = array(
      'jQueryUI' => true,  // use jQuery UI tabs?
      'labelOpen' => $this->_('Expand Language Tabs'),
      'labelClose' => $this->_('Collapse/Convert Back to Tabs'),
      'activeTab' => $activeTab,
      'ulClass' => '',
      'ulAttrs' => '',
      'liActiveClass' => '',
      'liDisabledClass' => '',
      'liEmptyClass' => '',
      'aClass' => '',
      'loadStyles' => true,
      'loadScripts' => true,
      'tabField' => $this->get('tabField'),
    );

    $settings = $this->wire('config')->get('LanguageTabs');
    if(is_array($settings)) {
      $this->settings = array_merge($defaults, $settings);
    } else {
      $this->settings = $defaults;
    }

    $this->wire('config')->js('LanguageTabs', $this->settings);
    
    return $this->settings;
  }

  /**
   * Init language tabs in form immediately after form render
   * 
   * @param HookEvent $e
   * 
   */
  public function hookRenderInputfieldForm(HookEvent $e) {
    
    $settings = $this->getSettings();
    $config = $this->wire('config');
    
    if($settings['jQueryUI']) {
      $adminTheme = $this->wire('adminTheme');
      if($adminTheme) $adminTheme->addBodyClass('LanguageTabsJqueryUI');
    }
    
    if($settings['loadStyles']) {
      $config->styles->add($config->urls->LanguageTabs . 'LanguageTabs.css');
    }
    if($settings['loadScripts']) {
      $config->scripts->add($config->urls->LanguageTabs . 'LanguageTabs.js');
    }
    
    // $this->wire('modules')->loadModuleFileAssets($this); 
    $this->wire('modules')->get('JqueryCore')->use('longclick');
    if(strpos($e->return, 'LanguageSupport') === false) return;
    /** @var InputfieldForm $form */
    $form = $e->object;
    $id = $form->attr('id'); 
    $e->return .= "<script>setupLanguageTabs($('#$id'));</script>";
  }

  /**
   * Clear any stored tabs
   * 
   */
  public function resetTabs() {
    $this->tabs = array();
  }

  /**
   * Add a new tab, to be later retrieved by renderTabs()
   * 
   * @param Inputfield $inputfield
   * @param Language $language
   * 
   */
  public function addTab(Inputfield $inputfield, Language $language) {
    $settings = $this->getSettings();
    $liClasses = array();
    $aClasses = array('langTab' . $language->id);
    $title = $language->get($this->tabField);
    if(empty($title)) $title = $language->get('name');
    $title = $this->wire('sanitizer')->entities1($title);
    if(!$this->wire('languages')->editable($language)) {
      $title = "<s>$title</s>";
      $liClasses[] = 'LanguageNotEditable'; 
      $liClasses[] = $settings['liDisabledClass'];
    }
    if($inputfield->isEmpty()) {
      $liClasses[] = 'langTabEmpty';
      $liClasses[] = $settings['liEmptyClass'];
    }
    $id = $inputfield->attr('id'); 
    $liClass = implode(' ', $liClasses);
    $aClass = implode(' ', $aClasses);
    /** @noinspection HtmlUnknownAnchorTarget */
    $this->tabs[] = "<li class='$liClass'><a data-lang='$language->id' class='$aClass' href='#langTab_$id'>$title</a></li>";
  }

  /**
   * Render output for all added tabs
   * 
   * Note that if only 1 tab has been added, tabs won't be displayed (no point in it).
   * This method automatically calls resetTabs() after rendering. 
   * 
   * @param Inputfield $inputfield
   * @param string $content Content that will have the tabs 
   * @return string Modified $content with tabs
   * 
   */
  public function renderTabs(Inputfield $inputfield, $content) {
    $settings = $this->getSettings();
    if(count($this->tabs) > 1) { 
      $inputfield->wrapClass .= " hasLangTabs";
      $inputfield->contentClass .= " langTabsContainer";
      $tabs = implode('', $this->tabs);
      $id = $inputfield->attr('id');
      $note = "<small class='langTabsNote detail'><i class='fa fa-fw fa-angle-double-left'></i>" . 
        $this->_('click twice to change all tabs') . "</small>";
      $attrs = $settings['ulAttrs']; 
      $attrs .= $settings['ulClass'] ? " class='$settings[ulClass]'" : "";
      $attrs = strlen($attrs) ? " " . trim($attrs) : "";
      $content = "<div class='langTabs' id='langTabs_$id'>$note<ul$attrs>$tabs</ul>$content</div>";
    } else {
      // do nothing, just return content because there was only 1 tab (no render necessary)
    }
    $this->resetTabs();
    return $content; 
  }
  
  public function getModuleConfigInputfields(InputfieldWrapper $inputfields) {
    $f = $this->wire('modules')->get('InputfieldSelect'); 
    $f->attr('name', 'tabField');
    $f->label = $this->_('Field to use for tab labels');
    $f->addOption('name');
    foreach($this->wire('templates')->get('language')->fieldgroup as $field) {
      if($field->type instanceof FieldtypeMulti) continue;
      $f->addOption($field->name);
    }
    $f->attr('value', $this->tabField);
    $f->required = true;
    $inputfields->add($f);
    return $inputfields;
  }

}