AI-in-Healthcare / Developer Meetup in Boston Generative AI Use Cases in Healthcare _files /js__PxKuGXQ7t1kgFAt01KambNhC5Tl2ewy_HHNT5A4YbHo__na_sM4tP0YCd.js
nmitchko's picture
Upload 77 files
1e4c25f
raw
history blame contribute delete
No virus
34.9 kB
(function($) {
// Check if this file has already been loaded.
if (typeof Drupal.wysiwygAttach !== 'undefined') {
return;
}
// Keeps track of editor status during AJAX operations, active format and more.
// Always use getFieldInfo() to get a valid reference to the correct data.
var _fieldInfoStorage = {};
// Keeps track of information relevant to each format, such as editor settings.
// Always use getFormatInfo() to get a reference to a format's data.
var _formatInfoStorage = {};
// Keeps track of global and per format plugin configurations.
// Always use getPluginInfo() tog get a valid reference to the correct data.
var _pluginInfoStorage = {'global': {'drupal': {}, 'native': {}}};
// Keeps track of private instance information.
var _internalInstances = {};
// Keeps track of initialized editor libraries.
var _initializedLibraries = {};
// Keeps a map between format selectboxes and fields.
var _selectToField = {};
/**
* Returns field specific editor data.
*
* @throws Error
* Exception thrown if data for an unknown field is requested.
* Summary fields are expected to use the same data as the main field.
*
* If a field id contains the delimiter '--', anything after that is dropped and
* the remainder is assumed to be the id of an original field replaced by an
* AJAX operation, due to how Drupal generates unique ids.
* @see drupal_html_id()
*
* Do not modify the returned object unless you really know what you're doing.
* No external code should need access to this, and it may likely change in the
* future.
*
* @param fieldId
* The id of the field to get data for.
*
* @returns
* A reference to an object with the following properties:
* - activeFormat: A string with the active format id.
* - enabled: A boolean, true if the editor is attached.
* - formats: An object with one sub-object for each available format, holding
* format specific state data for this field.
* - summary: An optional string with the id of a corresponding summary field.
* - trigger: A string with the id of the format selector for the field.
* - getFormatInfo: Shortcut method to getFormatInfo(fieldInfo.activeFormat).
*/
function getFieldInfo(fieldId) {
if (_fieldInfoStorage[fieldId]) {
return _fieldInfoStorage[fieldId];
}
var baseFieldId = (fieldId.indexOf('--') === -1 ? fieldId : fieldId.substr(0, fieldId.indexOf('--')));
if (_fieldInfoStorage[baseFieldId]) {
return _fieldInfoStorage[baseFieldId];
}
throw new Error('Wysiwyg module has no information about field "' + fieldId + '"');
}
/**
* Returns format specific editor data.
*
* Do not modify the returned object unless you really know what you're doing.
* No external code should need access to this, and it may likely change in the
* future.
*
* @param formatId
* The id of a format to get data for.
*
* @returns
* A reference to an object with the following properties:
* - editor: A string with the id of the editor attached to the format.
* 'none' if no editor profile is associated with the format.
* - enabled: True if the editor is active.
* - toggle: True if the editor can be toggled on/off by the user.
* - editorSettings: A structure holding editor settings for this format.
* - getPluginInfo: Shortcut method to get plugin config for the this format.
*/
function getFormatInfo(formatId) {
if (_formatInfoStorage[formatId]) {
return _formatInfoStorage[formatId];
}
return {
editor: 'none',
getPluginInfo: function () {
return getPluginInfo(formatId);
}
};
}
/**
* Returns plugin configuration for a specific format, or the global values.
*
* @param formatId
* The id of a format to get data for, or 'global' to get data common to all
* formats and editors. Use 'global:editorname' to limit it to one editor.
*
* @return
* The returned object will have the sub-objects 'drupal' and 'native', each
* with properties matching names of plugins.
* Global data for Drupal (cross-editor) plugins will have the following keys:
* - title: A human readable name for the button.
* - internalName: The unique name of a native plugin wrapper, used in editor
* profiles and when registering the plugin with the editor API to avoid
* possible id conflicts with native plugins.
* - css: A stylesheet needed by the plugin.
* - icon path: The path where button icons are stored.
* - path: The path to the plugin's main folder.
* - buttons: An object with button data, keyed by name with the properties:
* - description: A human readable string describing the button's function.
* - title: A human readable string with the name of the button.
* - icon: An object with one or more of the following properties:
* - src: An absolute (begins with '/') or relative path to the icon.
* - path: An absolute path to a folder containing the button.
*
* When formatId matched a format with an assigned editor, values for plugins
* match the return value of the editor integration's [proxy] plugin settings
* callbacks.
*
* @see Drupal.wysiwyg.utilities.getPluginInfo()
* @see Drupal.wyswiyg.utilities.extractButtonSettings()
*/
function getPluginInfo(formatId) {
var match, editor;
if ((match = formatId.match(/^global:(\w+)$/))) {
formatId = 'global';
editor = match[1];
}
if (!_pluginInfoStorage[formatId]) {
return {};
}
if (formatId === 'global' && typeof editor !== 'undefined') {
return { 'drupal': _pluginInfoStorage.global.drupal, 'native': (_pluginInfoStorage.global['native'][editor]) };
}
return _pluginInfoStorage[formatId];
}
/**
* Attach editors to input formats and target elements (f.e. textareas).
*
* This behavior searches for input format selectors and formatting guidelines
* that have been preprocessed by Wysiwyg API. All CSS classes of those elements
* with the prefix 'wysiwyg-' are parsed into input format parameters, defining
* the input format, configured editor, target element id, and variable other
* properties, which are passed to the attach/detach hooks of the corresponding
* editor.
*
* Furthermore, an "enable/disable rich-text" toggle link is added after the
* target element to allow users to alter its contents in plain text.
*
* This is executed once, while editor attach/detach hooks can be invoked
* multiple times.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
*/
Drupal.behaviors.attachWysiwyg = {
attach: function (context, settings) {
// This breaks in Konqueror. Prevent it from running.
if (/KDE/.test(navigator.vendor)) {
return;
}
var wysiwygs = $('.wysiwyg:input', context);
if (!wysiwygs.length) {
// No new fields, nothing to update.
return;
}
updateInternalState(settings.wysiwyg, context);
wysiwygs.once('wysiwyg', function () {
// Skip processing if the element is unknown or does not exist in this
// document. Can happen after a form was removed but Drupal.ajax keeps a
// lingering reference to the form and calls Drupal.attachBehaviors().
var $this = $('#' + this.id, document);
if (!$this.length) {
return;
}
// Directly attach this editor, if the input format is enabled or there is
// only one input format at all.
Drupal.wysiwygAttach(context, this.id);
})
.closest('form').submit(function (event) {
// Detach any editor when the containing form is submitted.
// Do not detach if the event was cancelled.
if (event.isDefaultPrevented()) {
return;
}
var form = this;
$('.wysiwyg:input', this).each(function () {
Drupal.wysiwygDetach(form, this.id, 'serialize');
});
});
},
detach: function (context, settings, trigger) {
var wysiwygs;
// The 'serialize' trigger indicates that we should simply update the
// underlying element with the new text, without destroying the editor.
if (trigger == 'serialize') {
// Removing the wysiwyg-processed class guarantees that the editor will
// be reattached. Only do this if we're planning to destroy the editor.
wysiwygs = $('.wysiwyg-processed:input', context);
}
else {
wysiwygs = $('.wysiwyg:input', context).removeOnce('wysiwyg');
}
wysiwygs.each(function () {
Drupal.wysiwygDetach(context, this.id, trigger);
if (trigger === 'unload') {
// Delete the instance in case the field is removed. This is safe since
// detaching with the unload trigger is reverts to the 'none' "editor".
delete _internalInstances[this.id];
delete Drupal.wysiwyg.instances[this.id];
}
});
}
};
/**
* Attach an editor to a target element.
*
* Detaches any existing instance for the field before attaching a new instance
* based on the current state of the field. Editor settings and state
* information is fetched based on the element id and get cloned first, so they
* cannot be overridden. After attaching the editor, the toggle link is shown
* again, except in case we are attaching no editor.
*
* Also attaches editors to the summary field, if available.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param fieldId
* The id of an element to attach an editor to.
*/
Drupal.wysiwygAttach = function(context, fieldId) {
var fieldInfo = getFieldInfo(fieldId),
doSummary = (fieldInfo.summary && (!fieldInfo.formats[fieldInfo.activeFormat] || !fieldInfo.formats[fieldInfo.activeFormat].skip_summary));
// Detach any previous editor instance if enabled, else remove the grippie.
detachFromField(fieldId, context, 'unload');
var wasSummary = !!_internalInstances[fieldInfo.summary];
if (doSummary || wasSummary) {
detachFromField(fieldId, context, 'unload', {summary: true});
}
// Store this field id, so (external) plugins can use it.
// @todo Wrong point in time. Probably can only supported by editors which
// support an onFocus() or similar event.
Drupal.wysiwyg.activeId = fieldId;
// Attach or update toggle link, if enabled.
Drupal.wysiwygAttachToggleLink(context, fieldId);
// Attach to main field.
attachToField(fieldId, context);
// Attach to summary field.
if (doSummary || wasSummary) {
// If the summary wrapper is visible, attach immediately.
if ($('#' + fieldInfo.summary).parents('.text-summary-wrapper').is(':visible')) {
attachToField(fieldId, context, {summary: true, forceDisabled: !doSummary});
}
else {
// Attach an instance of the 'none' editor to have consistency while the
// summary is hidden, then switch to a real editor instance when shown.
attachToField(fieldId, context, {summary: true, forceDisabled: true});
// Unbind any existing click handler to avoid double toggling.
$('#' + fieldId).parents('.text-format-wrapper').find('.link-edit-summary').closest('.field-edit-link').unbind('click.wysiwyg').bind('click.wysiwyg', function () {
detachFromField(fieldId, context, 'unload', {summary: true});
attachToField(fieldId, context, {summary: true, forceDisabled: !doSummary});
$(this).unbind('click.wysiwyg');
});
}
}
};
/**
* The public API exposed for an editor-enabled field.
*
* Properties should be treated as read-only state and changing them will not
* have any effect on how the instance behaves.
*
* Note: The attach() and detach() methods are not part of the public API and
* should not be called directly to avoid synchronization issues.
* Use Drupal.wysiwygAttach() and Drupal.wysiwygDetach() to activate or
* deactivate editor instances. Externally switching the active editor is not
* supported other than changing the format using the select element.
*/
function WysiwygInstance(internalInstance) {
// The id of the field the instance manipulates.
this.field = internalInstance.field;
// The internal name of the attached editor.
this.editor = internalInstance.editor;
// If the editor is currently enabled or not.
this['status'] = internalInstance['status'];
// The id of the text format the editor is attached to.
this.format = internalInstance.format;
// If the field is resizable without an editor attached.
this.resizable = internalInstance.resizable;
// Methods below here redirect to the 'none' editor which handles plain text
// fields when the editor is disabled.
/**
* Insert content at the cursor position.
*
* @param content
* An HTML markup string.
*/
this.insert = function (content) {
return internalInstance['status'] ? internalInstance.insert(content) : Drupal.wysiwyg.editor.instance.none.insert.call(internalInstance, content);
}
/**
* Get all content from the editor.
*
* @return
* An HTML markup string.
*/
this.getContent = function () {
return internalInstance['status'] ? internalInstance.getContent() : Drupal.wysiwyg.editor.instance.none.getContent.call(internalInstance);
}
/**
* Replace all content in the editor.
*
* @param content
* An HTML markup string.
*/
this.setContent = function (content) {
return internalInstance['status'] ? internalInstance.setContent(content) : Drupal.wysiwyg.editor.instance.none.setContent.call(internalInstance, content);
}
/**
* Check if the editor is in fullscreen mode.
*
* @return bool
* True if the editor is considered to be in fullscreen mode.
*/
this.isFullscreen = function (content) {
return internalInstance['status'] && $.isFunction(internalInstance.isFullscreen) ? internalInstance.isFullscreen() : false;
}
// @todo The methods below only work for TinyMCE, deprecate?
/**
* Open a native editor dialog.
*
* Use of this method i not recommended due to limited editor support.
*
* @param dialog
* An object with dialog settings. Keys used:
* - url: The url of the dialog template.
* - width: Width in pixels.
* - height: Height in pixels.
*/
this.openDialog = function (dialog, params) {
if ($.isFunction(internalInstance.openDialog)) {
return internalInstance.openDialog(dialog, params)
}
}
/**
* Close an opened dialog.
*
* @param dialog
* Same options as for opening a dialog.
*/
this.closeDialog = function (dialog) {
if ($.isFunction(internalInstance.closeDialog)) {
return internalInstance.closeDialog(dialog)
}
}
}
/**
* The private base for editor instances.
*
* An instance of this object is used as the context for all calls into the
* editor instances (including attach() and detach() when only one instance is
* asked to detach).
*
* Anything added to Drupal.wysiwyg.editor.instance[editorName] is cloned into
* an instance of this function.
*
* Editor state parameters are cloned into the instance after that.
*/
function WysiwygInternalInstance(params) {
$.extend(true, this, Drupal.wysiwyg.editor.instance[params.editor]);
$.extend(true, this, params);
this.pluginInfo = {
'global': getPluginInfo('global:' + params.editor),
'instances': getPluginInfo(params.format)
};
// Keep track of the public face to keep it synced.
this.publicInstance = new WysiwygInstance(this);
}
/**
* Updates internal settings and state caches with new information.
*
* Attaches selection change handler to format selector to track state changes.
*
* @param settings
* A structure like Drupal.settigns.wysiwyg.
* @param context
* The context given from Drupal.attachBehaviors().
*/
function updateInternalState(settings, context) {
var pluginData = settings.plugins;
for (var plugin in pluginData.drupal) {
if (!(plugin in _pluginInfoStorage.global.drupal)) {
_pluginInfoStorage.global.drupal[plugin] = pluginData.drupal[plugin];
}
}
// To make sure we don't rely on Drupal.settings, uncomment these for testing.
//pluginData.drupal = {};
for (var editorId in pluginData['native']) {
for (var plugin in pluginData['native'][editorId]) {
_pluginInfoStorage.global['native'][editorId] = (_pluginInfoStorage.global['native'][editorId] || {});
if (!(plugin in _pluginInfoStorage.global['native'][editorId])) {
_pluginInfoStorage.global['native'][editorId][plugin] = pluginData['native'][editorId][plugin];
}
}
}
//pluginData['native'] = {};
for (var fmatId in pluginData) {
if (fmatId.substr(0, 6) !== 'format') {
continue;
}
_pluginInfoStorage[fmatId] = (_pluginInfoStorage[fmatId] || {'drupal': {}, 'native': {}});
for (var plugin in pluginData[fmatId].drupal) {
if (!(plugin in _pluginInfoStorage[fmatId].drupal)) {
_pluginInfoStorage[fmatId].drupal[plugin] = pluginData[fmatId].drupal[plugin];
}
}
for (var plugin in pluginData[fmatId]['native']) {
if (!(plugin in _pluginInfoStorage[fmatId]['native'])) {
_pluginInfoStorage[fmatId]['native'][plugin] = pluginData[fmatId]['native'][plugin];
}
}
delete pluginData[fmatId];
}
// Build the cache of format/profile settings.
for (var editor in settings.configs) {
if (!settings.configs.hasOwnProperty(editor)) {
continue;
}
for (var format in settings.configs[editor]) {
if (_formatInfoStorage[format] || !settings.configs[editor].hasOwnProperty(format)) {
continue;
}
_formatInfoStorage[format] = {
editor: editor,
toggle: true, // Overridden by triggers.
editorSettings: processObjectTypes(settings.configs[editor][format])
};
}
// Initialize editor libraries if not already done.
if (!_initializedLibraries[editor] && typeof Drupal.wysiwyg.editor.init[editor] === 'function') {
// Clone, so original settings are not overwritten.
Drupal.wysiwyg.editor.init[editor](jQuery.extend(true, {}, settings.configs[editor]), getPluginInfo('global:' + editor));
_initializedLibraries[editor] = true;
}
// Update libraries, in case new plugins etc have not been initialized yet.
else if (typeof Drupal.wysiwyg.editor.update[editor] === 'function') {
Drupal.wysiwyg.editor.update[editor](jQuery.extend(true, {}, settings.configs[editor]), getPluginInfo('global:' + editor));
}
}
//settings.configs = {};
for (var triggerId in settings.triggers) {
var trigger = settings.triggers[triggerId];
var fieldId = trigger.field;
var baseFieldId = (fieldId.indexOf('--') === -1 ? fieldId : fieldId.substr(0, fieldId.indexOf('--')));
var fieldInfo = null;
if ($('#' + triggerId, context).length === 0) {
// Skip fields which may have been removed or are not in this context.
continue;
}
if (!(fieldInfo = _fieldInfoStorage[baseFieldId])) {
fieldInfo = _fieldInfoStorage[baseFieldId] = {
formats: {},
select: trigger.select,
resizable: trigger.resizable,
summary: trigger.summary,
getFormatInfo: function () {
if (this.select) {
this.activeFormat = 'format' + $('#' + this.select + ':input').val();
}
return getFormatInfo(this.activeFormat);
}
// 'activeFormat' and 'enabled' added below.
};
}
for (var format in trigger) {
if (format.indexOf('format') != 0 || fieldInfo.formats[format]) {
continue;
}
fieldInfo.formats[format] = {
'enabled': trigger[format].status
};
if (!_formatInfoStorage[format]) {
_formatInfoStorage[format] = {
editor: trigger[format].editor,
editorSettings: {},
getPluginInfo: function () {
return getPluginInfo(formatId);
}
};
}
// Always update these since they are stored as state.
_formatInfoStorage[format].toggle = trigger[format].toggle;
if (trigger[format].skip_summary) {
fieldInfo.formats[format].skip_summary = true;
}
}
var $selectbox = null;
// Always update these since Drupal generates new ids on AJAX calls.
fieldInfo.summary = trigger.summary;
if (trigger.select) {
_selectToField[trigger.select.replace(/--\d+$/,'')] = trigger.field;
fieldInfo.select = trigger.select;
// Specifically target input elements in case selectbox wrappers have
// hidden the real element and cloned its attributes.
$selectbox = $('#' + trigger.select + ':input', context).filter('select');
// Attach onChange handlers to input format selector elements.
$selectbox.unbind('change.wysiwyg').bind('change.wysiwyg', formatChanged);
}
// Always update the active format to ensure the righ profile is used if a
// field was removed and gets re-added and the instance was left behind.
fieldInfo.activeFormat = 'format' + ($selectbox ? $selectbox.val() : trigger.activeFormat);
fieldInfo.enabled = fieldInfo.formats[fieldInfo.activeFormat] && fieldInfo.formats[fieldInfo.activeFormat].enabled;
}
//settings.triggers = {};
}
/**
* Helper to prepare and attach an editor for a single field.
*
* Creates the 'instance' object under Drupal.wysiwyg.instances[fieldId].
*
* @param mainFieldId
* The id of the field's main element, for fetching field info.
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param params
* An optional object for overriding state information for the editor with the
* following properties:
* - 'summary': Set to true to indicate to attach to the summary instead of
* the main element. Defaults to false.
* - 'forceDisabled': Set to true to override the current state of the field
* and assume it is disabled. Useful for hidden summary instances.
*
* @see Drupal.wysiwygAttach()
*/
function attachToField(mainFieldId, context, params) {
params = params || {};
var fieldInfo = getFieldInfo(mainFieldId);
var fieldId = (params.summary ? fieldInfo.summary : mainFieldId);
var formatInfo = fieldInfo.getFormatInfo();
// If the editor isn't active, attach default behaviors instead.
var enabled = (fieldInfo.enabled && !params.forceDisabled);
var editor = (enabled ? formatInfo.editor : 'none');
// Settings are deep merged (cloned) to prevent editor implementations from
// permanently modifying them while attaching.
var clonedSettings = (enabled ? jQuery.extend(true, {}, formatInfo.editorSettings) : {});
// (Re-)initialize field instance.
var stateParams = {
field: fieldId,
editor: formatInfo.editor,
'status': enabled,
format: fieldInfo.activeFormat,
resizable: fieldInfo.resizable
};
var internalInstance = new WysiwygInternalInstance(stateParams);
_internalInstances[fieldId] = internalInstance;
Drupal.wysiwyg.instances[fieldId] = internalInstance.publicInstance;
// Attach editor, if enabled by default or last state was enabled.
Drupal.wysiwyg.editor.attach[editor].call(internalInstance, context, stateParams, clonedSettings);
}
/**
* Detach all editors from a target element.
*
* Ensures Drupal's original textfield resize functionality is restored if
* enabled and the triggering reason is 'unload'.
*
* Also detaches editors from the summary field, if available.
*
* @param context
* A DOM element, supplied by Drupal.detachBehaviors().
* @param fieldId
* The id of an element to attach an editor to.
* @param trigger
* A string describing what is causing the editor to be detached.
* - 'serialize': The editor normally just syncs its contents to the original
* textarea for value serialization before an AJAX request.
* - 'unload': The editor is to be removed completely and the original
* textarea restored.
*
* @see Drupal.detachBehaviors()
*/
Drupal.wysiwygDetach = function (context, fieldId, trigger) {
var fieldInfo = getFieldInfo(fieldId),
trigger = trigger || 'unload';
// Detach from main field.
detachFromField(fieldId, context, trigger);
if (trigger == 'unload') {
// Attach the resize behavior by forcing status to false. Other values are
// intentionally kept the same to show which editor is normally attached.
attachToField(fieldId, context, {forceDisabled: true});
Drupal.wysiwygAttachToggleLink(context, fieldId);
}
// Detach from summary field.
if (fieldInfo.summary && _internalInstances[fieldInfo.summary]) {
// The "Edit summary" click handler could re-enable the editor by mistake.
$('#' + fieldId).parents('.text-format-wrapper').find('.link-edit-summary').unbind('click.wysiwyg');
detachFromField(fieldId, context, trigger, {summary: true});
if (trigger == 'unload') {
attachToField(fieldId, context, {summary: true});
}
}
};
/**
* Helper to detach and clean up after an editor for a single field.
*
* Removes the 'instance' object under Drupal.wysiwyg.instances[fieldId].
*
* @param mainFieldId
* The id of the field's main element, for fetching field info.
* @param context
* A DOM element, supplied by Drupal.detachBehaviors().
* @param trigger
* A string describing what is causing the editor to be detached.
* - 'serialize': The editor normally just syncs its contents to the original
* textarea for value serialization before an AJAX request.
* - 'unload': The editor is to be removed completely and the original
* textarea restored.
* @param params
* An optional object for overriding state information for the editor with the
* following properties:
* - 'summary': Set to true to indicate to detach from the summary instead of
* the main element. Defaults to false.
*
* @see Drupal.wysiwygDetach()
*/
function detachFromField(mainFieldId, context, trigger, params) {
params = params || {};
var fieldInfo = getFieldInfo(mainFieldId);
var fieldId = (params.summary ? fieldInfo.summary : mainFieldId);
var enabled = false;
var editor = 'none';
if (_internalInstances[fieldId]) {
enabled = _internalInstances[fieldId]['status'];
editor = (enabled ? _internalInstances[fieldId].editor : 'none');
}
var stateParams = {
field: fieldId,
'status': enabled,
editor: fieldInfo.editor,
format: fieldInfo.activeFormat,
resizable: fieldInfo.resizable
};
if (jQuery.isFunction(Drupal.wysiwyg.editor.detach[editor])) {
Drupal.wysiwyg.editor.detach[editor].call(_internalInstances[fieldId], context, stateParams, trigger);
}
if (trigger == 'unload') {
delete Drupal.wysiwyg.instances[fieldId];
delete _internalInstances[fieldId];
}
}
/**
* Append or update an editor toggle link to a target element.
*
* @param context
* A DOM element, supplied by Drupal.attachBehaviors().
* @param fieldId
* The id of an element to attach an editor to.
*/
Drupal.wysiwygAttachToggleLink = function(context, fieldId) {
var fieldInfo = getFieldInfo(fieldId),
editor = fieldInfo.getFormatInfo().editor;
if (!fieldInfo.getFormatInfo().toggle) {
// Otherwise, ensure that toggle link is hidden.
$('#wysiwyg-toggle-' + fieldId).hide();
return;
}
if (!$('#wysiwyg-toggle-' + fieldId, context).length) {
var text = document.createTextNode(fieldInfo.enabled ? Drupal.settings.wysiwyg.disable : Drupal.settings.wysiwyg.enable),
a = document.createElement('a'),
div = document.createElement('div');
$(a).attr({ id: 'wysiwyg-toggle-' + fieldId, href: 'javascript:void(0);' }).append(text);
$(div).addClass('wysiwyg-toggle-wrapper').append(a);
if ($('#' + fieldInfo.select).closest('.fieldset-wrapper').prepend(div).length == 0) {
// Fall back to inserting the link right after the field.
$('#' + fieldId).after(div);
};
}
$('#wysiwyg-toggle-' + fieldId, context)
.html(fieldInfo.enabled ? Drupal.settings.wysiwyg.disable : Drupal.settings.wysiwyg.enable).show()
.unbind('click.wysiwyg')
.bind('click.wysiwyg', { 'fieldId': fieldId, 'context': context }, Drupal.wysiwyg.toggleWysiwyg);
// Hide toggle link in case no editor is attached.
if (editor == 'none') {
$('#wysiwyg-toggle-' + fieldId).hide();
}
};
/**
* Callback for the Enable/Disable rich editor link.
*/
Drupal.wysiwyg.toggleWysiwyg = function (event) {
var context = event.data.context,
fieldId = event.data.fieldId,
fieldInfo = getFieldInfo(fieldId);
// Toggling the enabled state indirectly toggles use of the 'none' editor.
if (fieldInfo.enabled) {
fieldInfo.enabled = false;
Drupal.wysiwygDetach(context, fieldId, 'unload');
}
else {
fieldInfo.enabled = true;
Drupal.wysiwygAttach(context, fieldId);
}
fieldInfo.formats[fieldInfo.activeFormat].enabled = fieldInfo.enabled;
}
/**
* Event handler for when the selected format is changed.
*/
function formatChanged(event) {
var fieldId = _selectToField[this.id.replace(/--\d+$/, '')];
var context = $(this).closest('form');
var newFormat = 'format' + $(this).val();
// Field state is fetched by reference.
var currentField = getFieldInfo(fieldId);
// Prevent double-attaching if change event is triggered manually.
if (newFormat === currentField.activeFormat) {
return;
}
// Save the state of the current format.
if (currentField.formats[currentField.activeFormat]) {
currentField.formats[currentField.activeFormat].enabled = currentField.enabled;
}
// Switch format/profile.
currentField.activeFormat = newFormat;
// Load the state from the new format.
if (currentField.formats[currentField.activeFormat]) {
currentField.enabled = currentField.formats[currentField.activeFormat].enabled;
}
else {
currentField.enabled = false;
}
// Attaching again will use the changed field state.
Drupal.wysiwygAttach(context, fieldId);
}
/**
* Convert JSON type placeholders into the actual types.
*
* Recognizes function references (callbacks) and Regular Expressions.
*
* To create a callback, pass in an object with the following properties:
* - 'drupalWysiwygType': Must be set to 'callback'.
* - 'name': A string with the name of the callback, use
* 'object.subobject.method' syntax for methods in nested objects.
* - 'context': An optional string with the name of an object for overriding
* 'this' inside the function. Use 'object.subobject' syntax for nested
* objects. Defaults to the window object.
*
* To create a RegExp, pass in an object with the following properties:
* - 'drupalWysiwygType: Must be set to 'regexp'.
* - 'regexp': The Regular Expression as a string, without / wrappers.
* - 'modifiers': An optional string with modifiers to set on the RegExp object.
*
* @param json
* The json argument with all recognized type placeholders replaced by the real
* types.
*
* @return The JSON object with placeholder types replaced.
*/
function processObjectTypes(json) {
var out = null;
if (typeof json != 'object') {
return json;
}
out = new json.constructor();
if (json.drupalWysiwygType) {
switch (json.drupalWysiwygType) {
case 'callback':
out = callbackWrapper(json.name, json.context);
break;
case 'regexp':
out = new RegExp(json.regexp, json.modifiers ? json.modifiers : undefined);
break;
default:
out.drupalWysiwygType = json.drupalWysiwygType;
}
}
else {
for (var i in json) {
if (json.hasOwnProperty(i) && json[i] && typeof json[i] == 'object') {
out[i] = processObjectTypes(json[i]);
}
else {
out[i] = json[i];
}
}
}
return out;
}
/**
* Convert function names into function references.
*
* @param name
* The name of a function to use as callback. Use the 'object.subobject.method'
* syntax for methods in nested objects.
* @param context
* An optional string with the name of an object for overriding 'this' inside
* the function. Use 'object.subobject' syntax for nested objects. Defaults to
* the window object.
*
* @return
* A function which will call the named function or method in the proper
* context, passing through arguments and return values.
*/
function callbackWrapper(name, context) {
var namespaces = name.split('.'), func = namespaces.pop(), obj = window;
for (var i = 0; obj && i < namespaces.length; i++) {
obj = obj[namespaces[i]];
}
if (!obj) {
throw "Wysiwyg: Unable to locate callback " + namespaces.join('.') + "." + func + "()";
}
if (!context) {
context = obj;
}
else if (typeof context == 'string'){
namespaces = context.split('.');
context = window;
for (i = 0; context && i < namespaces.length; i++) {
context = context[namespaces[i]];
}
if (!context) {
throw "Wysiwyg: Unable to locate context object " + namespaces.join('.');
}
}
if (typeof obj[func] != 'function') {
throw "Wysiwyg: " + func + " is not a callback function";
}
return function () {
return obj[func].apply(context, arguments);
}
}
var oldBeforeSerialize = (Drupal.ajax ? Drupal.ajax.prototype.beforeSerialize : false);
if (oldBeforeSerialize) {
/**
* Filter the ajax_html_ids list sent in AJAX requests.
*
* This overrides part of the form serializer to not include ids we know will
* not collide because editors are removed before those ids are reused.
*
* This avoids hitting like max_input_vars, which defaults to 1000,
* even with just a few active editor instances.
*/
Drupal.ajax.prototype.beforeSerialize = function (element, options) {
var ret = oldBeforeSerialize.call(this, element, options);
var excludeSelectors = [];
$.each(Drupal.wysiwyg.excludeIdSelectors, function () {
if ($.isArray(this)) {
excludeSelectors = excludeSelectors.concat(this);
}
});
if (excludeSelectors.length > 0) {
var ajaxHtmlIdsArray = options.data['ajax_html_ids[]'];
if (!ajaxHtmlIdsArray || ajaxHtmlIdsArray.length === 0) {
return ret;
}
options.data['ajax_html_ids[]'] = [];
$('[id]:not(' + excludeSelectors.join(',') + ')').each(function () {
if ($.inArray(this.id, ajaxHtmlIdsArray) !== -1) {
options.data['ajax_html_ids[]'].push(this.id);
}
});
}
return ret;
};
}
// Respond to CTools detach behaviors event.
$(document).unbind('CToolsDetachBehaviors.wysiwyg').bind('CToolsDetachBehaviors.wysiwyg', function(event, context) {
$('.wysiwyg:input', context).removeOnce('wysiwyg').each(function () {
Drupal.wysiwygDetach(context, this.id, 'unload');
// The 'none' instances are destroyed with the dialog.
delete Drupal.wysiwyg.instances[this.id];
delete _internalInstances[this.id];
var baseFieldId = (this.id.indexOf('--') === -1 ? this.id : this.id.substr(0, this.id.indexOf('--')));
delete _fieldInfoStorage[baseFieldId];
});
});
})(jQuery);
;/*})'"*/
;/*})'"*/