You are here

function wysiwyg_profile_form in Wysiwyg 7.2

Same name and namespace in other branches
  1. 5.2 wysiwyg.admin.inc \wysiwyg_profile_form()
  2. 5 wysiwyg.admin.inc \wysiwyg_profile_form()
  3. 6.2 wysiwyg.admin.inc \wysiwyg_profile_form()
  4. 6 wysiwyg.admin.inc \wysiwyg_profile_form()

Form builder for Wysiwyg profile form.

1 string reference to 'wysiwyg_profile_form'
wysiwyg_menu in ./wysiwyg.module
Implementation of hook_menu().

File

./wysiwyg.admin.inc, line 11
Integrate Wysiwyg editors into Drupal.

Code

function wysiwyg_profile_form($form, &$form_state, $profile) {

  // Merge in defaults.
  $editor = wysiwyg_get_editor($profile->editor);
  if (!$editor) {

    // A missing library or unrecognized version, no edit link is shown so users
    // should not get here.
    drupal_goto('admin/config/content/wysiwyg');
  }
  if (!$profile->settings) {
    $profile->settings = array();
  }

  // Editor settings.
  $settings =& $profile->settings;
  $settings += array(
    'theme' => '',
    'language' => 'en',
    'buttons' => array(),
    'css_setting' => 'theme',
    'css_theme' => variable_get('node_admin_theme') ? variable_get('admin_theme') : variable_get('theme_default', 'bartik'),
    'css_path' => NULL,
  );
  if (!isset($profile->preferences)) {
    $profile->preferences = array();
  }

  // Wysiwyg profile preferences, not used directly by the editor.
  $preferences =& $profile->preferences;
  $preferences += array(
    'add_to_summaries' => TRUE,
    'default' => TRUE,
    'show_toggle' => TRUE,
    'user_choose' => FALSE,
    'version' => NULL,
  );
  $installed_version = $editor['installed version'];
  $profile_version = $preferences['version'];
  $formats = filter_formats();
  drupal_set_title(t('%editor profile for %format', array(
    '%editor' => $editor['title'],
    '%format' => $formats[$profile->format]->name,
  )), PASS_THROUGH);
  $form['basic'] = array(
    '#type' => 'fieldset',
    '#title' => t('Basic setup'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#group' => 'advanced',
  );
  $form['basic']['info'] = array(
    'editor_version' => array(
      '#markup' => t('Installed editor library version: @installed_version', array(
        '@installed_version' => !empty($installed_version) ? $installed_version : t('Unknown'),
      )),
    ),
    'profile_version' => array(
      '#prefix' => '<br />',
      '#markup' => t('Version expected by profile: @profile_version', array(
        '@profile_version' => !empty($profile_version) ? $profile_version : t('Unknown'),
      )),
    ),
  );
  if (!empty($editor['deprecation message'])) {
    $form['basic']['info']['deprecated'] = array(
      '#prefix' => '<div class="messages warning">',
      '#markup' => $editor['deprecation message'],
      '#suffix' => '</div>',
    );
  }
  $version_verified = $editor['installed version verified'];
  $migrate_message = '';
  $migrate_status = 'status';
  if (!empty($editor['verified version range'])) {
    $verified_range = $editor['verified version range'];
    $form['basic']['info']['verified_range'] = array(
      '#prefix' => '<br />',
      '#markup' => t('<a href="!url" target="_blank" title="Supported editor versions">Verified version range: @min_version to @max_version</a>', array(
        '@min_version' => $verified_range[0],
        '@max_version' => $verified_range[1],
        '!url' => url('https://www.drupal.org/node/596966'),
      )),
    );
    if (!$version_verified) {
      $migrate_status = 'warning';
      $form['basic']['info']['editor_version']['#markup'] .= ' <span class="warning">' . t('Untested!') . '</span>';
    }
    $version_diff = version_compare(empty($profile_version) ? $installed_version : $profile_version, $installed_version);
    if ($version_diff !== 0) {
      $migrate_message = t('The installed editor library version was changed from @profile_version to @installed_version since this profile was last saved.', array(
        '@profile_version' => $profile_version,
        '@installed_version' => $installed_version,
      ));

      // If the editor integration supports migration between versions, attempt
      // it before widgets for settings are rendered.
      if (isset($editor['migrate settings callback']) && function_exists($editor['migrate settings callback'])) {

        // Get the version migrated to. MUST be in the verified version range,
        // FALSE if no migration was possible, or TRUE if no change needed.
        $migrated_version = $editor['migrate settings callback']($settings, $editor, $profile_version, $installed_version);
        $profile->changed = $migrated_version !== TRUE && $migrated_version != $profile_version;
        if ($migrated_version === FALSE) {
          $migrate_message .= ' ' . t('Wysiwyg is not able to automatically adapt the profile to the installed editor version. It is recommended to start over with a new profile.');
          $migrate_status = 'error';
        }
        elseif ($version_verified) {
          $migrate_message .= ' ' . ($profile->changed ? t('The profile was automatically adapted to better match the installed editor version, but please check all settings before proceeding.') : t('No known changes to the profile were needed, but please check all settings before proceeding'));
        }
        else {
          $closest_version = $version_diff === 1 ? $verified_range[0] : $verified_range[1];
          $migrate_message .= ' ' . t('Wysiwyg was only able to adapt the profile to editor version %version, any additional differences to the installed version will not be accounted for and the editor may not work as expected.', array(
            '%version' => $closest_version,
          ));
          $migrate_status = 'warning';
        }
      }
    }
  }
  if (!$version_verified) {
    $migrate_message .= (empty($migrate_message) ? '' : ' ') . t('The installed version has not been tested, the editor may not work as expected.');
    $migrate_status = 'warning';
  }
  if (!empty($migrate_message)) {
    $form['basic']['info'][''] = array(
      '#prefix' => '<div class="messages ' . $migrate_status . '">',
      '#markup' => $migrate_message . ' ' . t('This message is shown until the profile is saved while a verified version is installed.'),
      '#suffix' => '</div>',
    );
  }
  if (empty($profile->new) && !empty($profile->changed)) {
    drupal_set_message(t('All changes are stored temporarily. Click Save to make your changes permanent. Click Cancel to discard any changes.'), 'warning');
  }
  if (isset($profile->locked) && is_object($profile->locked)) {
    $form['locked'] = array(
      '#theme_wrappers' => array(
        'container',
      ),
      '#attributes' => array(
        'class' => array(
          'profile-locked',
          'messages',
          'warning',
        ),
      ),
      '#markup' => t('This profile is being edited by user !user, and is therefore locked from editing by others. This lock is !age old. Click here to <a href="!break">break this lock</a>.', array(
        '!user' => theme('username', array(
          'account' => user_load($profile->locked->uid),
        )),
        '!age' => format_interval(REQUEST_TIME - $profile->locked->updated),
        '!break' => url('admin/config/content/wysiwyg/profile/' . $profile->format . '/break-lock'),
      )),
    );
  }
  $form['basic']['default'] = array(
    '#type' => 'checkbox',
    '#title' => t('Enabled by default'),
    '#default_value' => $preferences['default'],
    '#return_value' => 1,
    '#description' => t('The default editor state for users having access to this profile. Users are able to override this state if the next option is enabled.'),
    '#parents' => array(
      'preferences',
      'default',
    ),
  );
  $form['basic']['user_choose'] = array(
    '#type' => 'checkbox',
    '#title' => t('Allow users to choose default'),
    '#default_value' => $preferences['user_choose'],
    '#return_value' => 1,
    '#description' => t('If allowed, users will be able to choose their own editor default state in their user account settings.'),
    '#parents' => array(
      'preferences',
      'user_choose',
    ),
  );
  $form['basic']['show_toggle'] = array(
    '#type' => 'checkbox',
    '#title' => t('Show <em>enable/disable rich text</em> toggle link'),
    '#default_value' => $preferences['show_toggle'],
    '#return_value' => 1,
    '#description' => t('Whether or not to show the <em>enable/disable rich text</em> toggle link below a textarea. If disabled, the user setting or global default is used (see above).'),
    '#parents' => array(
      'preferences',
      'show_toggle',
    ),
  );
  $form['basic']['add_to_summaries'] = array(
    '#type' => 'checkbox',
    '#title' => t('Enable on summary fields'),
    '#default_value' => $preferences['add_to_summaries'],
    '#return_value' => 1,
    '#description' => t('Attach the editor to summary fields of textareas.'),
    '#parents' => array(
      'preferences',
      'add_to_summaries',
    ),
  );
  $form['buttons'] = array(
    '#type' => 'fieldset',
    '#title' => t('Buttons and plugins'),
    '#collapsible' => FALSE,
    '#tree' => TRUE,
    '#theme' => 'wysiwyg_admin_button_table',
  );
  $plugins = wysiwyg_get_plugins($profile->editor);

  // Generate the button list.
  foreach ($plugins as $name => $meta) {
    if (isset($meta['buttons']) && is_array($meta['buttons'])) {
      foreach ($meta['buttons'] as $button => $title) {
        $icon = '';
        if (!empty($meta['path'])) {

          // @todo Button icon locations are different in editors, editor versions,
          // and contrib/custom plugins (like Image Assist, f.e.).
          $img_src = $meta['path'] . "/images/{$name}.gif";

          // Handle plugins that have more than one button.
          if (!file_exists($img_src)) {
            $img_src = $meta['path'] . "/images/{$button}.gif";
          }
          $icon = file_exists($img_src) ? '<img src="' . base_path() . $img_src . '" title="' . $button . '" style="border: 1px solid grey; vertical-align: middle;" />' : '';
        }
        $title = !empty($icon) ? $icon . ' ' . check_plain($title) : check_plain($title);
        $form['buttons'][$name][$button] = array(
          '#type' => 'checkbox',
          '#title' => $title,
          '#default_value' => !empty($settings['buttons'][$name][$button]) ? $settings['buttons'][$name][$button] : FALSE,
          '#description' => isset($meta['url']) ? l($meta['url'], $meta['url']) : NULL,
        );
      }
    }
    elseif (isset($meta['extensions']) && is_array($meta['extensions'])) {
      foreach ($meta['extensions'] as $extension => $title) {
        $form['buttons'][$name][$extension] = array(
          '#type' => 'checkbox',
          '#title' => check_plain($title),
          '#default_value' => !empty($settings['buttons'][$name][$extension]) ? $settings['buttons'][$name][$extension] : FALSE,
          '#description' => isset($meta['url']) ? l($meta['url'], $meta['url']) : NULL,
        );
      }
    }
  }
  $form['appearance'] = array(
    '#type' => 'fieldset',
    '#title' => t('Editor appearance'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#group' => 'advanced',
  );
  $form['appearance']['theme'] = array(
    '#type' => 'hidden',
    '#value' => $settings['theme'],
  );
  $form['appearance']['language'] = array(
    '#type' => 'select',
    '#title' => t('Interface language'),
    '#default_value' => $settings['language'],
  );

  // @see _locale_prepare_predefined_list()
  require_once DRUPAL_ROOT . '/includes/iso.inc';
  $predefined = _locale_get_predefined_list();
  foreach ($predefined as $key => $value) {

    // Include native name in output, if possible.
    if (count($value) > 1) {
      $tname = t($value[0]);
      $predefined[$key] = $tname == $value[1] ? $tname : "{$tname} ({$value[1]})";
    }
    else {
      $predefined[$key] = t($value[0]);
    }
  }
  asort($predefined);
  $form['appearance']['language']['#options'] = $predefined;
  $form['output'] = array(
    '#type' => 'fieldset',
    '#title' => t('Cleanup and output'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#group' => 'advanced',
  );
  $form['css'] = array(
    '#type' => 'fieldset',
    '#title' => t('CSS'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#group' => 'advanced',
  );
  $form['css']['css_setting'] = array(
    '#type' => 'select',
    '#title' => t('Editor CSS'),
    '#default_value' => $settings['css_setting'],
    '#options' => array(
      'theme' => t('Use theme CSS'),
      'self' => t('Define CSS'),
      'none' => t('Editor default CSS'),
    ),
    '#description' => t('Defines the CSS to be used in the editor area.<br />Use theme CSS - loads stylesheets from current site theme.<br/>Define CSS - enter path for stylesheet files below.<br />Editor default CSS - uses default stylesheets from editor.'),
  );
  $themes = list_themes();
  $theme_list = array(
    '' => t('Active theme'),
    'wysiwyg_theme_admin' => t('Admin theme'),
    'wyiswyg_theme_default' => t('Default theme'),
    // Set an optgroup 'Other'.
    t('Other') => array(),
  );
  foreach ($themes as $theme) {
    if ($theme->status) {
      $theme_list[t('Other')][$theme->name] = $theme->info['name'];
    }
  }
  $form['css']['css_theme'] = array(
    '#type' => 'select',
    '#title' => t('Theme'),
    '#default_value' => $profile->settings['css_theme'],
    '#description' => t("Select which theme's CSS to apply to the content while in the editor.<br />Beware that most theme styling may not apply well without all wrapping elements in place. Users may see different themes depending on their permissions.<br />Note: This is only applied when the 'Editor CSS' field above is set to 'Use theme CSS'."),
    '#options' => $theme_list,
    '#states' => array(
      'visible' => array(
        'select[name="css_setting"]' => array(
          'value' => 'theme',
        ),
      ),
    ),
  );
  $form['css']['css_path'] = array(
    '#type' => 'textfield',
    '#title' => t('CSS path'),
    '#default_value' => $settings['css_path'],
    '#size' => 40,
    '#maxlength' => 255,
    '#description' => t('If "Define CSS" was selected above, enter path to a CSS file or a list of CSS files separated by a comma.') . '<br />' . t('Available tokens: <code>%b</code> (base path, eg: <code>/</code>), <code>%t</code> (path to theme, eg: <code>themes/garland</code>), <code>%q</code> (<code>css_js_query_string</code> variable, used for cache-busting)') . '<br />' . t('Example:') . ' css/editor.css,/themes/garland/style.css,%b%t/style.css?%q,http://example.com/external.css',
    '#states' => array(
      'visible' => array(
        'select[name="css_setting"]' => array(
          'value' => 'self',
        ),
      ),
    ),
  );
  $form['advanced'] = array(
    '#type' => 'vertical_tabs',
    '#weight' => 50,
  );
  $form['advanced']['settings_notes'] = array(
    '#type' => 'fieldset',
    '#weight' => 55,
    '#title' => '&star;&nbsp;' . t('Settings notes'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['advanced']['settings_notes']['json']['#markup'] = t('Some settings use <a href="!json_url" title="JavaScript Object Notation">JSON</a> syntax to allow complex data structures. Compared to the JSON specification, Wysiwyg module is a bit more flexible with which syntax it accepts to make it easier to copy sample configurations from editor documentation. JSON requires properties and String values to be enclosed in double quotes. Wysiwyg will try to add missing double quotes and replace single quotes, but it only handles simple cases. JSON syntax only allows Objects, Arrays, Strings, Numbers, and Booleans as values, but Wysiwyg can recognize and convert some objects with a specific structures to native JavaScript types otherwise not accepted by JSON.', array(
    '!json_url' => url('https://en.wikipedia.org/wiki/JSON'),
  ));
  $form['advanced']['settings_notes']['json_examples'] = array(
    '#type' => 'fieldset',
    '#title' => t('Serializing native types'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['advanced']['settings_notes']['json_examples']['function']['#markup'] = t('Function reference') . ':<br /><pre>{' . "\n  " . '"drupalWysiwygType" : "callback",' . "\n  " . '"name" : "name_of_callback_or_method",' . "\n  " . '"context" : "global.context.object"' . "\n}</pre>";
  $form['advanced']['settings_notes']['json_examples']['regexp']['#markup'] = t('RegExp') . ':<br /><pre>{' . "\n  " . '"drupalWysiwygType" : "regexp",' . "\n  " . '"regexp" : "\\w+\\d$",' . "\n  " . '"modifiers" : "gi"' . "\n}</pre>";
  $form['advanced']['settings_notes']['json_examples']['modules']['#markup'] = t('Modules implementing hooks may use the helper functions starting with <em>wysiwyg_wrap_js_*</em> to create these objects, see the file <em>wysiwyg.api.php</em>.');
  $form['actions'] = array(
    '#type' => 'actions',
  );
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  $form['actions']['cancel'] = array(
    '#type' => 'submit',
    '#value' => t('Cancel'),
    '#submit' => array(
      'wysiwyg_profile_form_cancel_submit',
    ),
  );

  // Supply contextual information for other callbacks and handlers.
  // @todo Modernize this form for D7+ and declare these earlier.
  // $profile is the primary object of this form, and as an entity, usually
  // expected to live in $form_state[$entity_type].
  $form_state['wysiwyg_profile'] = $profile;
  $form_state['wysiwyg']['editor'] = $editor;
  $form_state['wysiwyg']['plugins'] = $plugins;

  // Allow editor library specific changes to be made to the form.
  if (isset($editor['settings form callback'])) {
    $editor['settings form callback']($form, $form_state);
  }
  foreach (array(
    'appearance',
    'output',
  ) as $fieldset) {
    if (count(element_children($form[$fieldset])) == 0) {
      $form[$fieldset]['#access'] = FALSE;
    }
  }
  return $form;
}