4 * Add JavaScript behaviors for the "options" form element type.
9 Drupal
.optionElements
= Drupal
.optionElements
|| {};
10 Drupal
.behaviors
.optionsElement
= Drupal
.behaviors
.optionsElement
|| {};
12 // We need to check/set HTML properties frequently, such as the disabled and
13 // checked state of elements. In jQuery 1.6+, the "prop" method was added for
14 // this purpose, but in earlier versions you had to use "attr".
15 $.fn
.oeProp
= $.fn
.prop
? $.fn
.prop
: $.fn
.attr
;
17 Drupal
.behaviors
.optionsElement
.attach = function(context
) {
18 $('div.form-options:not(.options-element-processed)', context
).each(function() {
19 $(this).addClass('options-element-processed');
20 var optionsElement
= new Drupal
.optionsElement(this);
21 Drupal
.optionElements
[optionsElement
.identifier
] = optionsElement
;
26 * Constructor for an options element.
28 Drupal
.optionsElement = function(element
) {
31 // Find the original "manual" fields.
32 this.element
= element
;
33 this.manualElement
= $(element
).find('div.options').get(0);
34 this.manualOptionsElement
= $(element
).find('textarea').get(0);
35 this.manualDefaultValueElement
= $(element
).find('input.form-text').get(0);
36 this.keyTypeToggle
= $(element
).find('input.key-type-toggle').get(0);
37 this.multipleToggle
= $(element
).find('input.multiple-toggle').get(0);
39 // Setup variables containing the current status of the widget.
40 this.optgroups
= $(element
).is('.options-optgroups');
41 this.multiple
= $(element
).is('.options-multiple');
42 this.keyType
= element
.className
.replace(/^.*?options-key-type-([a-z]+).*?$/, '$1');
43 this.customKeys
= Boolean(element
.className
.match(/options-key-custom/));
44 this.identifier
= this.manualOptionsElement
.id
+ '-widget';
45 this.enabled
= !$(this.manualOptionsElement
).oeProp('readonly');
46 this.defaultValuePattern
= $(element
).find('input.default-value-pattern').val();
48 if (this.defaultValuePattern
) {
49 this.defaultValuePattern
= new RegExp(this.defaultValuePattern
);
53 this.keyChangeWarning
= Drupal
.t('Custom keys have been specified in this list. Removing these custom keys may change way data is stored. Are you sure you wish to remove these custom keys?');
55 // Setup new DOM elements containing the actual options widget.
56 this.optionsElement
= $('<div></div>').get(0); // Temporary DOM object.
57 this.optionsToggleElement
= $(Drupal
.theme('optionsElementToggle')).get(0);
58 this.optionAddElement
= $(Drupal
.theme('optionsElementAdd')).get(0);
59 this.removeDefaultElement
= $(Drupal
.theme('optionsElementRemoveDefault')).get(0);
61 // Add the options widget and toggle elements to the page.
62 $(this.manualElement
).css('display', 'none').before(this.optionsElement
).after(this.optionsToggleElement
).after(this.optionAddElement
);
63 if (this.manualDefaultValueElement
) {
64 $(this.manualElement
).after(this.removeDefaultElement
);
67 // Enable add item link.
68 $(this.optionAddElement
).find('a').click(function() {
69 var newOption
= self
.addOption($('table tr:last', self
.optionsElement
).get(0));
70 $(newOption
).find('input[type=text]:visible:first').focus();
74 // Enable the toggle action for manual entry of options.
75 $(this.optionsToggleElement
).find('a').click(function() {
80 // Enable the remove default link.
81 $(this.removeDefaultElement
).find('a').click(function() {
82 $(self
.element
).find('input.option-default').oeProp('checked', false).trigger('change');
86 // Add a handler for key type changes.
87 if (this.keyTypeToggle
) {
88 $(this.keyTypeToggle
).click(function() {
89 var checked
= $(this).oeProp('checked');
90 // Before switching the key type, ensure we're not destroying user keys.
92 var options
= self
.optionsFromText();
94 if (self
.keyType
== 'associative') {
95 for (var n
= 0; n
< options
.length
; n
++) {
96 if (options
[n
].key
!= options
[n
].value
) {
103 if (window
.confirm(self
.keyChangeWarning
)) {
104 self
.setCustomKeys(false);
108 self
.setCustomKeys(false);
112 self
.setCustomKeys(true);
117 // Add a handler for multiple value changes.
118 if (this.multipleToggle
) {
119 $(this.multipleToggle
).click(function(){
120 self
.setMultiple($(this).oeProp('checked'));
124 // Be sure to show the custom keys if we have any errors.
125 if (Drupal
.settings
.optionsElement
&& Drupal
.settings
.optionsElement
.errors
) {
126 this.customKeys
= true;
129 // Update the options widget with the current state of the textarea.
130 this.updateWidgetElements();
132 // Highlight errors that may have occurred during Drupal validation.
133 if (Drupal
.settings
.optionsElement
&& Drupal
.settings
.optionsElement
.errors
) {
134 this.checkKeys(Drupal
.settings
.optionsElement
.errors
, 'error');
139 * Update the widget element based on the current values of the manual elements.
141 Drupal
.optionsElement
.prototype.updateWidgetElements = function() {
144 // Create a new options element and replace the existing one.
145 var newElement
= $(Drupal
.theme('optionsElement', this)).get(0);
146 if ($(this.optionsElement
).css('display') == 'none') {
147 $(newElement
).css('display', 'none');
149 $(this.optionsElement
).replaceWith(newElement
);
150 this.optionsElement
= newElement
;
152 // Manually set up table drag for the created table.
153 Drupal
.settings
.tableDrag
= Drupal
.settings
.tableDrag
|| {};
154 Drupal
.settings
.tableDrag
[this.identifier
] = {
160 relationship
: 'self',
161 source
: 'option-depth',
162 target
: 'option-depth'
167 // Allow indentation of elements if optgroups are supported.
168 if (this.optgroups
) {
169 Drupal
.settings
.tableDrag
[this.identifier
]['option-parent'] = {
174 relationship
: 'parent',
175 source
: 'option-value',
176 target
: 'option-parent'
181 // Enable button for adding options.
182 $('a.add', this.optionsElement
).click(function() {
183 var newOption
= self
.addOption($(this).parents('tr:first').get(0));
184 $(newOption
).find('input[type=text]:visible:first').focus();
188 // Enable button for removing options.
189 $('a.remove', this.optionsElement
).click(function() {
190 self
.removeOption($(this).parents('tr:first').get(0));
194 // Add the same update action to all textfields and radios.
195 $('input', this.optionsElement
).change(function() {
196 self
.updateOptionElements();
197 self
.updateManualElements();
200 // Add a delayed update to textfields.
201 $('input.option-value', this.optionsElement
).keyup(function(e
) {
202 self
.pendingUpdate(e
);
205 // Attach behaviors as normal to the new widget.
206 Drupal
.attachBehaviors(this.optionsElement
);
208 // Remove the "Show row weights" link
209 $(".tabledrag-toggle-weight-wrapper").remove();
211 // Add an onDrop action to the table drag instance.
212 Drupal
.tableDrag
[this.identifier
].onDrop = function() {
213 // Update the checkbox/radio buttons for selecting default values.
214 if (self
.optgroups
) {
215 self
.updateOptionElements();
217 // Update the options within the hidden text area.
218 self
.updateManualElements();
221 // Add an onIndent action to the table drag row instances.
222 Drupal
.tableDrag
[this.identifier
].row
.prototype.onIndent = function() {
224 $(this.element
).addClass('indented');
227 $(this.element
).removeClass('indented');
231 // Update the default value and optgroups.
232 this.updateOptionElements();
236 * Update the original form element based on the current state of the widget.
238 Drupal
.optionsElement
.prototype.updateManualElements = function() {
241 // Build a list of current options.
242 var previousOption
= false;
243 $(this.optionsElement
).find('input.option-value').each(function() {
244 var $row
= $(this).is('tr') ? $(this) : $(this).parents('tr:first');
245 var depth
= $row
.find('input.option-depth').val();
246 if (depth
== 1 && previousOption
) {
247 if (typeof(options
[previousOption
]) != 'object') {
248 options
[previousOption
] = {};
250 options
[previousOption
][this.value
] = this.value
;
253 options
[this.value
] = this.value
;
254 previousOption
= this.value
;
257 this.options
= options
;
259 // Update the default value.
260 var defaultValue
= this.multiple
? [] : '';
261 var multiple
= this.multiple
;
262 $(this.optionsElement
).find('input.option-default').each(function() {
263 if (this.checked
&& this.value
) {
265 defaultValue
.push(this.value
);
268 defaultValue
= this.value
;
272 this.defaultValue
= defaultValue
;
274 // Update with the new text and trigger the change action on the field.
275 this.optionsToText();
277 if (this.manualDefaultValueElement
) {
278 // Don't wipe out custom pattern-matched default values.
279 defaultValue
= multiple
? defaultValue
.join(', ') : defaultValue
;
280 if (defaultValue
|| !(this.defaultValuePattern
&& this.defaultValuePattern
.test(this.manualDefaultValueElement
.value
))) {
281 this.manualDefaultValueElement
.value
= defaultValue
;
282 $('.default-value-pattern-match', this.element
).remove();
286 $(this.manualOptionsElement
).change();
290 * Several maintenance routines to update all rows of the options element.
292 * - Disable options for optgroups if indented.
293 * - Disable add and delete links if indented.
294 * - Match the default value radio button value to the key of the text element.
296 Drupal
.optionsElement
.prototype.updateOptionElements = function() {
298 var previousRow
= false;
299 var previousElement
= false;
300 var $rows
= $(this.optionsElement
).find('tbody tr');
302 $rows
.each(function(index
) {
303 var optionValue
= $(this).find('input.option-value').val();
304 var optionKey
= $(this).find('input.option-key').val();
306 // Update the elements key if matching the key and value.
307 if (self
.keyType
== 'associative') {
308 $(this).find('input.option-key').val(optionValue
);
311 // Match the default value checkbox/radio button to the option's key.
312 $(this).find('input.option-default').val(optionKey
? optionKey
: optionValue
);
314 // Hide the add/remove links the row if indented.
315 var depth
= $(this).find('input.option-depth').val();
316 var defaultInput
= $(this).find('input.option-default').get(0);
319 // Affect the parent row, adjusting properties for optgroup items.
320 $(previousElement
).oeProp('disabled', true).oeProp('checked', false);
321 $(previousRow
).addClass('optgroup').find('a.add, a.remove').css('display', 'none');
322 $(this).find('a.add, a.remove').css('display', '');
323 $(defaultInput
).oeProp('disabled', false);
325 // Hide the key column for the optgroup.
326 if (self
.customKeys
) {
327 $(previousRow
).find('td.option-key-cell').css('display', 'none');
328 $(previousRow
).find('td.option-value-cell').attr('colspan', 2);
332 // Set properties for normal options that are not optgroups.
333 $(defaultInput
).oeProp('disabled', false);
334 $(this).removeClass('optgroup').find('a.add, a.remove').css('display', '');
336 // Hide the key column.
337 if (self
.customKeys
) {
338 $(this).find('td.option-key-cell').css('display', '');
339 $(this).find('td.option-value-cell').attr('colspan', '');
341 previousElement
= defaultInput
;
346 // Do not allow the last item to be removed.
347 if ($rows
.size() == 1) {
348 $rows
.find('a.remove').css('display', 'none')
351 // Disable items if needed.
352 if (this.enabled
== false) {
358 * Add a new option below the current row.
360 Drupal
.optionsElement
.prototype.addOption = function(currentOption
) {
362 var windowHieght
= $(document
).height();
363 var newOption
= $(currentOption
).clone()
364 .find('input.option-key').val(self
.keyType
== 'numeric' ? self
.nextNumericKey() : '').end()
365 .find('input.option-value').val('').end()
366 .find('input.option-default').oeProp('checked', false).end()
367 .find('a.tabledrag-handle').remove().end()
368 .removeClass('drag-previous')
369 .insertAfter(currentOption
)
372 // Scroll down to accomidate the new option.
373 $(window
).scrollTop($(window
).scrollTop() + $(document
).height() - windowHieght
);
375 // Make the new option draggable.
376 Drupal
.tableDrag
[this.identifier
].makeDraggable(newOption
);
378 // Enable button for adding options.
379 $('a.add', newOption
).click(function() {
380 var newOption
= self
.addOption($(this).parents('tr:first').get(0));
381 $(newOption
).find('input[type=text]:visible:first').focus();
385 // Enable buttons for removing options.
386 $('a.remove', newOption
).click(function() {
387 self
.removeOption(newOption
);
391 // Add the update action to all textfields and radios.
392 $('input', newOption
).change(function() {
393 self
.updateOptionElements();
394 self
.updateManualElements();
397 // Add a delayed update to textfields.
398 $('input.option-value', newOption
).keyup(function(e
) {
399 self
.pendingUpdate(e
);
402 this.updateOptionElements();
403 this.updateManualElements();
409 * Remove the current row.
411 Drupal
.optionsElement
.prototype.removeOption = function(currentOption
) {
412 $(currentOption
).remove();
414 this.updateOptionElements();
415 this.updateManualElements();
419 * Toggle link for switching between the JavaScript and manual entry.
421 Drupal
.optionsElement
.prototype.toggleMode = function() {
422 if ($(this.optionsElement
).is(':visible')) {
423 var height
= $(this.optionsElement
).height();
424 $(this.optionsElement
).css('display', 'none');
425 $(this.optionAddElement
).css('display', 'none');
426 $(this.manualElement
).css('display', '').find('textarea').height(height
);
427 $(this.optionsToggleElement
).find('a').text(Drupal
.t('Normal entry'));
430 this.updateWidgetElements();
431 $(this.optionsElement
).css('display', '');
432 $(this.optionAddElement
).css('display', '');
433 $(this.manualElement
).css('display', 'none');
434 $(this.optionsToggleElement
).find('a').text(Drupal
.t('Manual entry'));
439 * Enable the changing of options.
441 Drupal
.optionsElement
.prototype.enable = function() {
443 $(this.manualOptionsElement
).oeProp('readonly', false);
444 $(this.element
).removeClass('options-disabled');
446 $('a.add, a.remove, a.tabledrag-handle, div.form-option-add a', this.element
).css('display', '');
447 $('input.form-text', this.optionsElement
).oeProp('disabled', false);
451 * Disable the changing of options.
453 Drupal
.optionsElement
.prototype.disable = function() {
454 this.enabled
= false;
455 $(this.manualOptionsElement
).oeProp('readonly', true);
456 $(this.element
).addClass('options-disabled');
458 $('a.add, a.remove, a.tabledrag-handle, div.form-option-add a', this.element
).css('display', 'none');
459 $('input.form-text', this.optionsElement
).oeProp('disabled', true);
463 * Enable entering of custom key values.
465 Drupal
.optionsElement
.prototype.setCustomKeys = function(enabled
) {
467 $(this.element
).addClass('options-key-custom');
470 $(this.element
).removeClass('options-key-custom');
473 this.customKeys
= enabled
;
474 // Rebuild the options widget.
475 this.updateManualElements();
476 this.updateWidgetElements();
480 * Change the current key type (associative, custom, numeric, none).
482 Drupal
.optionsElement
.prototype.setKeyType = function(type
) {
484 .removeClass('options-key-type-' + this.keyType
)
485 .addClass('options-key-type-' + type
);
487 // Rebuild the options widget.
488 this.updateManualElements();
489 this.updateWidgetElements();
493 * Set the element's #multiple property. Boolean TRUE or FALSE.
495 Drupal
.optionsElement
.prototype.setMultiple = function(multiple
) {
497 $(this.element
).addClass('options-multiple');
500 // Unselect all default options except the first.
501 $(this.optionsElement
).find('input.option-default:checked:not(:first)').oeProp('checked', false);
502 this.updateManualElements();
503 $(this.element
).removeClass('options-multiple');
505 this.multiple
= multiple
;
506 // Rebuild the options widget.
507 this.updateWidgetElements();
511 * Highlight duplicate keys.
513 Drupal
.optionsElement
.prototype.checkKeys = function(duplicateKeys
, cssClass
){
514 $(this.optionsElement
).find('input.option-key').each(function() {
515 if (duplicateKeys
[this.value
]) {
516 $(this).addClass(cssClass
);
522 * Update a field after a delay.
524 * Similar to immediately changing a field, this field as pending changes that
525 * will be updated after a delay. This includes textareas and textfields in
526 * which updating continuously would be a strain the server and actually slow
527 * down responsiveness.
529 Drupal
.optionsElement
.prototype.pendingUpdate = function(e
) {
532 // Only operate on "normal" keys, excluding special function keys.
533 // http://protocolsofmatrix.blogspot.com/2007/09/javascript-keycode-reference-table-for.html
535 e
.keyCode
>= 48 && e
.keyCode
<= 90 || // 0-9, A-Z.
536 e
.keyCode
>= 93 && e
.keyCode
<= 111 || // Number pad.
537 e
.keyCode
>= 186 && e
.keyCode
<= 222 || // Symbols.
538 e
.keyCode
== 8) // Backspace.
543 if (this.updateDelay
) {
544 clearTimeout(this.updateDelay
);
547 this.updateDelay
= setTimeout(function(){
548 self
.updateOptionElements();
549 self
.updateManualElements();
554 * Given an object of options, convert it to a text string.
556 Drupal
.optionsElement
.prototype.optionsToText = function() {
557 var $rows
= $('tbody tr', this.optionsElement
);
560 var rowCount
= $rows
.size();
561 var defaultValues
= [];
563 for (var rowIndex
= 0; rowIndex
< rowCount
; rowIndex
++) {
564 var isOptgroup
= $rows
.eq(rowIndex
).is('.optgroup');
565 var isChild
= $rows
.eq(rowIndex
).is('.indented');
566 var key
= $rows
.eq(rowIndex
).find('input.option-key').val();
567 var value
= $rows
.eq(rowIndex
).find('input.option-value').val();
570 if (this.optgroups
&& value
!== '' && isOptgroup
) {
571 output
+= '<' + ((key
!== '') ? (key
+ '|') : '') + value
+ '>' + "\n";
574 // Typical key|value pairs.
576 // Exit out of any groups.
577 if (this.optgroups
&& inGroup
&& !isChild
) {
582 // Add the row for the option.
583 if (this.keyType
== 'none' || this.keyType
== 'associative') {
584 output
+= value
+ "\n";
586 else if (value
== '') {
590 output
+= ((key
!== '') ? (key
+ '|') : '') + value
+ "\n";
595 this.manualOptionsElement
.value
= output
;
599 * Given a text string, convert it to an object.
601 Drupal
.optionsElement
.prototype.optionsFromText = function() {
602 // Use jQuery val() instead of value because it fixes Windows line breaks.
603 var rows
= $(this.manualOptionsElement
).val().match(/^.*$/mg);
606 var defaultValues
= {};
608 // Drop the last row if empty.
609 if (rows
.length
&& rows
[rows
.length
- 1] == '') {
613 if (this.manualDefaultValueElement
) {
615 var defaults
= this.manualDefaultValueElement
.value
.split(',');
616 for (var n
= 0; n
< defaults
.length
; n
++) {
617 var defaultValue
= defaults
[n
].replace(/^[ ]*(.*?)[ ]*$/, '$1'); // trim().
618 defaultValues
[defaultValue
] = defaultValue
;
622 var defaultValue
= this.manualDefaultValueElement
.value
.replace(/^[ ]*(.*?)[ ]*$/, '$1'); // trim().
623 defaultValues
[defaultValue
] = defaultValue
;
627 for (var n
= 0; n
< rows
.length
; n
++) {
628 var row
= rows
[n
].replace(/^[ \r\n]*(.*?)[ \r\n]*$/, '$1'); // trim().
632 var hasChildren
= false;
633 var groupClear
= false;
637 if (this.optgroups
&& (matches
= row
.match(/^\<((([^>|]*)\|)?([^>]*))\>$/))) {
638 if (matches
[0] == '<>') {
643 key
= matches
[3] ? matches
[3] : '';
644 parent
= value
= matches
[4];
648 // Check if this row is a key|value pair.
649 else if ((this.keyType
== 'mixed' || this.keyType
== 'numeric' || this.keyType
== 'custom') && (matches
= row
.match(/^([^|]+)\|(.*)$/))) {
652 checked
= defaultValues
[key
];
654 // Row is a straight value.
656 key
= (this.keyType
== 'mixed' || this.keyType
== 'numeric') ? '' : row
;
658 if (!key
&& this.keyType
== 'mixed') {
659 checked
= defaultValues
[value
];
662 checked
= defaultValues
[key
];
670 parent
: (value
!== parent
? parent
: ''),
671 hasChildren
: hasChildren
,
672 checked
: (checked
? 'checked' : false)
677 // Convert options to numeric if no key is specified.
678 if (this.keyType
== 'numeric') {
679 var nextKey
= this.nextNumericKey();
680 for (var n
= 0; n
< options
.length
; n
++) {
681 if (options
[n
].key
== '') {
682 options
[n
].key
= nextKey
;
692 * Utility method to get the next numeric option in a list of options.
694 Drupal
.optionsElement
.prototype.nextNumericKey = function(options
) {
695 this.keyType
= 'custom';
696 options
= this.optionsFromText();
697 this.keyType
= 'numeric';
700 for (var n
= 0; n
< options
.length
; n
++) {
701 if (options
[n
].key
.match(/^[0-9]+$/)) {
702 maxKey
= Math
.max(maxKey
, options
[n
].key
);
709 * Theme function for creating a new options element.
711 * @param optionsElement
712 * An options element object.
714 Drupal
.theme
.prototype.optionsElement = function(optionsElement
) {
716 var options
= optionsElement
.optionsFromText();
717 var hasDefault
= optionsElement
.manualDefaultValueElement
;
718 var defaultType
= optionsElement
.multiple
? 'checkbox' : 'radio';
719 var keyType
= optionsElement
.customKeys
? 'textfield' : 'hidden';
721 // Helper function to print out a single draggable option row.
722 function tableDragRow(key
, value
, parent
, indent
, status
) {
724 output
+= '<tr class="draggable' + (indent
> 0 ? ' indented' : '') + '">'
725 output
+= '<td class="' + (hasDefault
? 'option-default-cell' : 'option-order-cell') + '">';
726 for (var n
= 0; n
< indent
; n
++) {
727 output
+= Drupal
.theme('tableDragIndentation');
729 output
+= '<input type="hidden" class="option-parent" value="' + parent
.replace(/"/g, '"') + '" />';
730 output += '<input type
="hidden" class="option-depth" value
="' + indent + '" />';
732 output += '<input type
="' + defaultType + '" name
="' + optionsElement.identifier + '-default" class="form-radio option-default" value
="' + key.replace(/"/g
, '"') + '"' + (status
== 'checked' ? ' checked="checked"' : '') + (status
== 'disabled' ? ' disabled="disabled"' : '') + ' />';
734 output
+= '</td><td class="' + (keyType
== 'textfield' ? 'option-key-cell' : 'option-value-cell') +'">';
735 output
+= '<input type="' + keyType
+ '" class="' + (keyType
== 'textfield' ? 'form-text ' : '') + 'option-key" value="' + key
.replace(/"/g, '"') + '" />';
736 output += keyType == 'textfield
' ? '</td
><td
class="option-value-cell">' : '';
737 output += '<input
class="form-text option-value" type
="text" value
="' + value.replace(/"/g
, '"') + '" />';
738 output
+= '</td><td class="option-actions-cell">'
739 output
+= '<a class="add" title="' + Drupal
.t('Add new option') + '" href="#"' + (status
== 'disabled' ? ' style="display: none"' : '') + '><span class="add">' + Drupal
.t('Add') + '</span></a>';
740 output
+= '<a class="remove" title="' + Drupal
.t('Remove option') + '" href="#"' + (status
== 'disabled' ? ' style="display: none"' : '') + '><span class="remove">' + Drupal
.t('Remove') + '</span></a>';
746 output
+= '<div class="options-widget">';
747 output
+= '<table id="' + optionsElement
.identifier
+ '">';
749 output
+= '<thead><tr>';
750 output
+= '<th>' + (hasDefault
? Drupal
.t('Default') : ' ') + '</th>';
751 output
+= keyType
== 'textfield' ? '<th>' + Drupal
.t('Key') + '</th>' : '';
752 output
+= '<th>' + Drupal
.t('Value') + '</th>';
753 output
+= '<th> </th>';
754 output
+= '</tr></thead>';
758 // Make sure that at least a few options exist if empty.
759 if (!options
.length
) {
767 options
.push(newOption
);
768 options
.push(newOption
);
769 options
.push(newOption
);
772 for (var n
= 0; n
< options
.length
; n
++) {
773 var option
= options
[n
];
774 var depth
= option
.parent
=== '' ? 0 : 1;
775 var checked
= !option
.hasChildren
&& option
.checked
;
776 output
+= tableDragRow(option
.key
, option
.value
, option
.parent
, depth
, checked
);
779 output
+= '</tbody>';
780 output
+= '</table>';
782 if (optionsElement
.defaultValuePattern
&& optionsElement
.manualDefaultValueElement
&& optionsElement
.defaultValuePattern
.test(optionsElement
.manualDefaultValueElement
.value
)) {
783 output
+= Drupal
.theme('optionsElementPatternMatch', optionsElement
.manualDefaultValueElement
.value
);
791 Drupal
.theme
.prototype.optionsElementPatternMatch = function(matchedValue
) {
792 return '<div class="default-value-pattern-match"><span>' + Drupal
.t('Manual default value') + '</span>: ' + matchedValue
+ '</div>';
795 Drupal
.theme
.prototype.optionsElementAdd = function() {
796 return '<div class="form-option-add"><a href="#">' + Drupal
.t('Add item') + '</a></div>';
799 Drupal
.theme
.prototype.optionsElementRemoveDefault = function() {
800 return '<div class="remove-default"><a href="#">' + Drupal
.t('No default') + '</a></div>';
803 Drupal
.theme
.prototype.optionsElementToggle = function() {
804 return '<div class="form-options-manual"><a href="#">' + Drupal
.t('Manual entry') + '</a></div>';
807 Drupal
.theme
.tableDragChangedMarker = function () {
811 Drupal
.theme
.tableDragChangedWarning = function() {
812 return '<span></span>';
816 * Field module support for Options widgets.
818 Drupal
.behaviors
.optionsElementFieldUI
= {};
819 Drupal
.behaviors
.optionsElementFieldUI
.attach = function(context
) {
820 var $cardinalityField
= $(context
).find('#edit-field-cardinality');
821 if ($cardinalityField
.length
) {
822 $cardinalityField
.change(function() {
823 var optionsElementId
= $(this).parents('fieldset:first').find('.form-type-options table').attr('id');
824 if (Drupal
.optionElements
[optionsElementId
]) {
825 Drupal
.optionElements
[optionsElementId
].setMultiple(this.value
!= 1);
827 }).trigger('change');