generator-craftskeleton
Version:
Starterkit for Craft CMS 2.x (Multi-Environment Configs with HeartyConfig, Gulp, and Bower for Dependencie-Management) made by interpunkt. ag
816 lines (658 loc) • 27.9 kB
JavaScript
(function($){
//
// Modification of default Craft.MatrixConfigurator that properly finds the required matrix dom element
// This is especially an issue when using inside a table.
//
// addBlockType()
// '<input class="hidden" name="types[Matrix][blockTypes]['+id+'][name]">' +
// '<input class="hidden" name="types[Matrix][blockTypes]['+id+'][handle]">' +
// to
// '<input class="hidden" name="'+this.inputNamePrefix+'[blockTypes]['+id+'][name]">' +
// '<input class="hidden" name="'+this.inputNamePrefix+'[blockTypes]['+id+'][handle]">' +
//
Craft.MatrixConfiguratorAlt = Garnish.Base.extend({
id: null,
idPrefix: null,
fieldTypeInfo: null,
inputNamePrefix: null,
inputIdPrefix: null,
$container: null,
$blockTypesColumnContainer: null,
$fieldsColumnContainer: null,
$fieldSettingsColumnContainer: null,
$blockTypeItemsOuterContainer: null,
$blockTypeItemsContainer: null,
$fieldItemsContainer: null,
$fieldSettingItemsContainer: null,
$newBlockTypeBtn: null,
$newFieldBtn: null,
blockTypes: null,
selectedBlockType: null,
blockTypeSort: null,
totalNewBlockTypes: 0,
init: function(fieldTypeInfo, inputNamePrefix) {
this.fieldTypeInfo = fieldTypeInfo;
this.inputNamePrefix = inputNamePrefix;
this.inputIdPrefix = Craft.formatInputId(this.inputNamePrefix);
// Change the class of this alternative Matrix configuration - its got this special JS
// But without this change, the native Matrix configuration JS will hook onto this, binding things twice
this.$container = $('#'+this.inputIdPrefix+'-matrix-configurator:first .input:first');
this.$blockTypesColumnContainer = this.$container.children('.block-types').children();
this.$fieldsColumnContainer = this.$container.children('.fields').children();
this.$fieldSettingsColumnContainer = this.$container.children('.field-settings').children();
this.$blockTypeItemsOuterContainer = this.$blockTypesColumnContainer.children('.items');
this.$blockTypeItemsContainer = this.$blockTypeItemsOuterContainer.children('.blocktypes');
this.$fieldItemsOuterContainer = this.$fieldsColumnContainer.children('.items');
this.$fieldSettingItemsContainer = this.$fieldSettingsColumnContainer.children('.items');
this.setContainerHeight();
this.$newBlockTypeBtn = this.$blockTypeItemsOuterContainer.children('.btn');
this.$newFieldBtn = this.$fieldItemsOuterContainer.children('.btn');
// Find the existing block types
this.blockTypes = {};
var $blockTypeItems = this.$blockTypeItemsContainer.children();
for (var i = 0; i < $blockTypeItems.length; i++)
{
var $item = $($blockTypeItems[i]),
id = $item.data('id');
this.blockTypes[id] = new BlockType(this, $item);
// Is this a new block type?
var newMatch = (typeof id == 'string' && id.match(/new(\d+)/));
if (newMatch && newMatch[1] > this.totalNewBlockTypes)
{
this.totalNewBlockTypes = parseInt(newMatch[1]);
}
}
this.blockTypeSort = new Garnish.DragSort($blockTypeItems, {
handle: '.move',
axis: 'y'
});
this.addListener(this.$newBlockTypeBtn, 'click', 'addBlockType');
this.addListener(this.$newFieldBtn, 'click', 'addFieldToSelectedBlockType');
this.addListener(this.$blockTypesColumnContainer, 'resize', 'setContainerHeight');
this.addListener(this.$fieldsColumnContainer, 'resize', 'setContainerHeight');
this.addListener(this.$fieldSettingsColumnContainer, 'resize', 'setContainerHeight');
},
setContainerHeight: function()
{
setTimeout($.proxy(function()
{
var maxColHeight = Math.max(this.$blockTypesColumnContainer.height(), this.$fieldsColumnContainer.height(), this.$fieldSettingsColumnContainer.height(), 400);
this.$container.height(maxColHeight);
}, this), 1);
},
getFieldTypeInfo: function(type)
{
for (var i = 0; i < this.fieldTypeInfo.length; i++)
{
if (this.fieldTypeInfo[i].type == type)
{
return this.fieldTypeInfo[i];
}
}
},
addBlockType: function()
{
var blockTypeSettingsModal = this.getBlockTypeSettingsModal();
this.blockTypeSettingsModal.show();
this.blockTypeSettingsModal.onSubmit = $.proxy(function(name, handle)
{
this.totalNewBlockTypes++;
var id = 'new'+this.totalNewBlockTypes;
var $item = $(
'<div class="matrixconfigitem mci-blocktype" data-id="'+id+'">' +
'<div class="name"></div>' +
'<div class="handle code"></div>' +
'<div class="actions">' +
'<a class="move icon" title="'+Craft.t('Reorder')+'"></a>' +
'<a class="settings icon" title="'+Craft.t('Settings')+'"></a>' +
'</div>' +
'<input class="hidden" name="'+this.inputNamePrefix+'[blockTypes]['+id+'][name]">' +
'<input class="hidden" name="'+this.inputNamePrefix+'[blockTypes]['+id+'][handle]">' +
'</div>'
).appendTo(this.$blockTypeItemsContainer);
this.blockTypes[id] = new BlockType(this, $item);
this.blockTypes[id].applySettings(name, handle);
this.blockTypes[id].select();
this.blockTypes[id].addField();
this.blockTypeSort.addItems($item);
}, this);
},
addFieldToSelectedBlockType: function()
{
if (this.selectedBlockType)
{
this.selectedBlockType.addField();
}
},
getBlockTypeSettingsModal: function()
{
if (!this.blockTypeSettingsModal)
{
this.blockTypeSettingsModal = new BlockTypeSettingsModal();
}
return this.blockTypeSettingsModal;
}
});
var BlockTypeSettingsModal = Garnish.Modal.extend(
{
init: function()
{
this.$form = $('<form class="modal fitted"/>').appendTo(Garnish.$bod);
this.$body = $('<div class="body"/>').appendTo(this.$form);
this.$nameField = $('<div class="field"/>').appendTo(this.$body);
this.$nameHeading = $('<div class="heading"/>').appendTo(this.$nameField);
this.$nameLabel = $('<label for="new-block-type-name">'+Craft.t('Name')+'</label>').appendTo(this.$nameHeading);
this.$nameInstructions = $('<div class="instructions"><p>'+Craft.t('What this block type will be called in the CP.')+'</p></div>').appendTo(this.$nameHeading);
this.$nameInputContainer = $('<div class="input"/>').appendTo(this.$nameField);
this.$nameInput = $('<input type="text" class="text fullwidth" id="new-block-type-name"/>').appendTo(this.$nameInputContainer);
this.$nameErrorList = $('<ul class="errors"/>').appendTo(this.$nameInputContainer).hide();
this.$handleField = $('<div class="field"/>').appendTo(this.$body);
this.$handleHeading = $('<div class="heading"/>').appendTo(this.$handleField);
this.$handleLabel = $('<label for="new-block-type-handle">'+Craft.t('Handle')+'</label>').appendTo(this.$handleHeading);
this.$handleInstructions = $('<div class="instructions"><p>'+Craft.t('How you’ll refer to this block type in the templates.')+'</p></div>').appendTo(this.$handleHeading);
this.$handleInputContainer = $('<div class="input"/>').appendTo(this.$handleField);
this.$handleInput = $('<input type="text" class="text fullwidth code" id="new-block-type-handle"/>').appendTo(this.$handleInputContainer);
this.$handleErrorList = $('<ul class="errors"/>').appendTo(this.$handleInputContainer).hide();
this.$deleteBtn = $('<a class="error left hidden" style="line-height: 30px;">'+Craft.t('Delete')+'</a>').appendTo(this.$body);
this.$buttons = $('<div class="buttons right" style="margin-top: 0;"/>').appendTo(this.$body);
this.$cancelBtn = $('<div class="btn">'+Craft.t('Cancel')+'</div>').appendTo(this.$buttons);
this.$submitBtn = $('<input type="submit" class="btn submit"/>').appendTo(this.$buttons);
this.handleGenerator = new Craft.HandleGenerator(this.$nameInput, this.$handleInput);
// By default, this will close all other Modals - nah man!
this.base(this.$form, {
closeOtherModals: false,
autoShow: false,
});
this.addListener(this.$cancelBtn, 'click', 'hide');
this.addListener(this.$form, 'submit', 'onFormSubmit');
this.addListener(this.$deleteBtn, 'click', 'onDeleteClick');
},
onFormSubmit: function(ev)
{
ev.preventDefault();
// Prevent multi form submits with the return key
if (!this.visible)
{
return;
}
if (this.handleGenerator.listening)
{
// Give the handle a chance to catch up with the input
this.handleGenerator.updateTarget();
}
// Basic validation
var name = Craft.trim(this.$nameInput.val()),
handle = Craft.trim(this.$handleInput.val());
if (!name || !handle)
{
Garnish.shake(this.$form);
}
else
{
this.hide();
this.onSubmit(name, handle);
}
},
onDeleteClick: function()
{
if (confirm(Craft.t('Are you sure you want to delete this block type?')))
{
this.hide();
this.onDelete();
}
},
show: function(name, handle, errors)
{
this.$nameInput.val(typeof name == 'string' ? name : '');
this.$handleInput.val(typeof handle == 'string' ? handle : '');
if (!handle)
{
this.handleGenerator.startListening();
}
else
{
this.handleGenerator.stopListening();
}
if (typeof name == 'undefined')
{
this.$deleteBtn.addClass('hidden');
this.$submitBtn.val(Craft.t('Create'));
}
else
{
this.$deleteBtn.removeClass('hidden');
this.$submitBtn.val(Craft.t('Save'));
}
this.displayErrors('name', (errors ? errors.name : null));
this.displayErrors('handle', (errors ? errors.handle : null));
if (!Garnish.isMobileBrowser())
{
setTimeout($.proxy(function() {
this.$nameInput.focus()
}, this), 100);
}
this.base();
},
displayErrors: function(attr, errors)
{
var $input = this['$'+attr+'Input'],
$errorList = this['$'+attr+'ErrorList'];
$errorList.children().remove();
if (errors)
{
$input.addClass('error');
$errorList.show();
for (var i = 0; i < errors.length; i++)
{
$('<li/>').text(errors[i]).appendTo($errorList);
}
}
else
{
$input.removeClass('error');
$errorList.hide();
}
}
});
//
// Untouched original functions - needed to be included as they aren't on the global Craft object...
//
/**
* Block type class
*/
var BlockType = Garnish.Base.extend(
{
configurator: null,
id: null,
errors: null,
inputNamePrefix: null,
inputIdPrefix: null,
$item: null,
$nameLabel: null,
$handleLabel: null,
$nameHiddenInput: null,
$handleHiddenInput: null,
$settingsBtn: null,
$fieldItemsContainer: null,
$fieldSettingsContainer: null,
fields: null,
selectedField: null,
fieldSort: null,
totalNewFields: 0,
fieldSettings: null,
init: function(configurator, $item)
{
this.configurator = configurator;
this.$item = $item;
this.id = this.$item.data('id');
this.errors = this.$item.data('errors');
this.inputNamePrefix = this.configurator.inputNamePrefix+'[blockTypes]['+this.id+']';
this.inputIdPrefix = this.configurator.inputIdPrefix+'-blockTypes-'+this.id;
this.$nameLabel = this.$item.children('.name');
this.$handleLabel = this.$item.children('.handle');
this.$nameHiddenInput = this.$item.find('input[name$="[name]"]:first');
this.$handleHiddenInput = this.$item.find('input[name$="[handle]"]:first');
this.$settingsBtn = this.$item.find('.settings');
// Find the field items container if it exists, otherwise create it
this.$fieldItemsContainer = this.configurator.$fieldItemsOuterContainer.children('[data-id="'+this.id+'"]:first');
if (!this.$fieldItemsContainer.length)
{
this.$fieldItemsContainer = $('<div data-id="'+this.id+'"/>').insertBefore(this.configurator.$newFieldBtn);
}
// Find the field settings container if it exists, otherwise create it
this.$fieldSettingsContainer = this.configurator.$fieldSettingItemsContainer.children('[data-id="'+this.id+'"]:first');
if (!this.$fieldSettingsContainer.length)
{
this.$fieldSettingsContainer = $('<div data-id="'+this.id+'"/>').appendTo(this.configurator.$fieldSettingItemsContainer);
}
// Find the existing fields
this.fields = {};
var $fieldItems = this.$fieldItemsContainer.children();
for (var i = 0; i < $fieldItems.length; i++)
{
var $fieldItem = $($fieldItems[i]),
id = $fieldItem.data('id');
this.fields[id] = new Field(this.configurator, this, $fieldItem);
// Is this a new field?
var newMatch = (typeof id == 'string' && id.match(/new(\d+)/));
if (newMatch && newMatch[1] > this.totalNewFields)
{
this.totalNewFields = parseInt(newMatch[1]);
}
}
this.addListener(this.$item, 'click', 'select');
this.addListener(this.$settingsBtn, 'click', 'showSettings');
this.fieldSort = new Garnish.DragSort($fieldItems, {
handle: '.move',
axis: 'y',
onSortChange: $.proxy(function() {
// Adjust the field setting containers to match the new sort order
for (var i = 0; i < this.fieldSort.$items.length; i++)
{
var $item = $(this.fieldSort.$items[i]),
id = $item.data('id'),
field = this.fields[id];
field.$fieldSettingsContainer.appendTo(this.$fieldSettingsContainer);
}
}, this)
});
},
select: function()
{
if (this.configurator.selectedBlockType == this)
{
return;
}
if (this.configurator.selectedBlockType)
{
this.configurator.selectedBlockType.deselect();
}
this.configurator.$fieldsColumnContainer.removeClass('hidden').trigger('resize');
this.$fieldItemsContainer.removeClass('hidden');
this.$item.addClass('sel');
this.configurator.selectedBlockType = this;
},
deselect: function()
{
this.$item.removeClass('sel');
this.configurator.$fieldsColumnContainer.addClass('hidden').trigger('resize');
this.$fieldItemsContainer.addClass('hidden');
this.$fieldSettingsContainer.addClass('hidden');
this.configurator.selectedBlockType = null;
if (this.selectedField)
{
this.selectedField.deselect();
}
},
showSettings: function()
{
var blockTypeSettingsModal = this.configurator.getBlockTypeSettingsModal();
blockTypeSettingsModal.show(this.$nameHiddenInput.val(), this.$handleHiddenInput.val(), this.errors);
blockTypeSettingsModal.onSubmit = $.proxy(this, 'applySettings');
blockTypeSettingsModal.onDelete = $.proxy(this, 'selfDestruct');
},
applySettings: function(name, handle)
{
if (this.errors)
{
this.errors = null;
this.$settingsBtn.removeClass('error');
}
this.$nameLabel.text(name);
this.$handleLabel.text(handle);
this.$nameHiddenInput.val(name);
this.$handleHiddenInput.val(handle);
},
addField: function()
{
this.totalNewFields++;
var id = 'new'+this.totalNewFields;
var $item = $(
'<div class="matrixconfigitem mci-field" data-id="'+id+'">' +
'<div class="name"><em class="light">'+Craft.t('(blank)')+'</em> </div>' +
'<div class="handle code"> </div>' +
'<div class="actions">' +
'<a class="move icon" title="'+Craft.t('Reorder')+'"></a>' +
'</div>' +
'</div>'
).appendTo(this.$fieldItemsContainer);
this.fields[id] = new Field(this.configurator, this, $item);
this.fields[id].select();
this.fieldSort.addItems($item);
},
selfDestruct: function()
{
this.deselect();
this.$item.remove();
this.$fieldItemsContainer.remove();
this.$fieldSettingsContainer.remove();
this.configurator.blockTypes[this.id] = null;
delete this.configurator.blockTypes[this.id];
}
});
var Field = Garnish.Base.extend(
{
configurator: null,
blockType: null,
id: null,
inputNamePrefix: null,
inputIdPrefix: null,
selectedFieldType: null,
initializedFieldTypeSettings: null,
$item: null,
$nameLabel: null,
$handleLabel: null,
$fieldSettingsContainer: null,
$nameInput: null,
$handleInput: null,
$requiredCheckbox: null,
$typeSelect: null,
$typeSettingsContainer: null,
$deleteBtn: null,
init: function(configurator, blockType, $item)
{
this.configurator = configurator;
this.blockType = blockType;
this.$item = $item;
this.id = this.$item.data('id');
this.inputNamePrefix = this.blockType.inputNamePrefix+'[fields]['+this.id+']';
this.inputIdPrefix = this.blockType.inputIdPrefix+'-fields-'+this.id;
this.initializedFieldTypeSettings = {};
this.$nameLabel = this.$item.children('.name');
this.$handleLabel = this.$item.children('.handle');
// Find the field settings container if it exists, otherwise create it
this.$fieldSettingsContainer = this.blockType.$fieldSettingsContainer.children('[data-id="'+this.id+'"]:first');
var isNew = (!this.$fieldSettingsContainer.length);
if (isNew)
{
this.$fieldSettingsContainer = $(this.getDefaultFieldSettingsHtml()).appendTo(this.blockType.$fieldSettingsContainer);
}
this.$nameInput = this.$fieldSettingsContainer.find('input[name$="[name]"]:first');
this.$handleInput = this.$fieldSettingsContainer.find('input[name$="[handle]"]:first');
this.$requiredCheckbox = this.$fieldSettingsContainer.find('input[type="checkbox"][name$="[required]"]:first');
this.$typeSelect = this.$fieldSettingsContainer.find('select[name$="[type]"]:first');
this.$typeSettingsContainer = this.$fieldSettingsContainer.children('.fieldtype-settings:first');
this.$deleteBtn = this.$fieldSettingsContainer.children('a.delete:first');
if (isNew)
{
this.setFieldType('PlainText');
}
else
{
this.selectedFieldType = this.$typeSelect.val();
this.initializedFieldTypeSettings[this.selectedFieldType] = this.$typeSettingsContainer.children();
this.setFieldType(this.selectedFieldType);
}
if (!this.$handleInput.val())
{
new Craft.HandleGenerator(this.$nameInput, this.$handleInput);
}
this.addListener(this.$item, 'click', 'select');
this.addListener(this.$nameInput, 'textchange', 'updateNameLabel');
this.addListener(this.$handleInput, 'textchange', 'updateHandleLabel');
this.addListener(this.$requiredCheckbox, 'change', 'updateRequiredIcon');
this.addListener(this.$typeSelect, 'change', 'onTypeSelectChange');
this.addListener(this.$deleteBtn, 'click', 'confirmDelete');
},
select: function()
{
if (this.blockType.selectedField == this)
{
return;
}
if (this.blockType.selectedField)
{
this.blockType.selectedField.deselect();
}
this.configurator.$fieldSettingsColumnContainer.removeClass('hidden').trigger('resize');
this.blockType.$fieldSettingsContainer.removeClass('hidden');
this.$fieldSettingsContainer.removeClass('hidden');
this.$item.addClass('sel');
this.blockType.selectedField = this;
if (!Garnish.isMobileBrowser())
{
setTimeout($.proxy(function() {
this.$nameInput.focus()
}, this), 100);
}
},
deselect: function()
{
this.$item.removeClass('sel');
this.configurator.$fieldSettingsColumnContainer.addClass('hidden').trigger('resize');
this.blockType.$fieldSettingsContainer.addClass('hidden');
this.$fieldSettingsContainer.addClass('hidden');
this.blockType.selectedField = null;
},
updateNameLabel: function()
{
var val = this.$nameInput.val();
this.$nameLabel.html((val ? Craft.escapeHtml(val) : '<em class="light">'+Craft.t('(blank)')+'</em>')+' ');
},
updateHandleLabel: function()
{
this.$handleLabel.html(Craft.escapeHtml(this.$handleInput.val())+' ');
},
updateRequiredIcon: function()
{
if (this.$requiredCheckbox.prop('checked'))
{
this.$nameLabel.addClass('required');
}
else
{
this.$nameLabel.removeClass('required');
}
},
onTypeSelectChange: function()
{
this.setFieldType(this.$typeSelect.val());
},
setFieldType: function(type)
{
if (this.selectedFieldType)
{
this.initializedFieldTypeSettings[this.selectedFieldType].detach();
}
this.selectedFieldType = type;
this.$typeSelect.val(type);
var firstTime = (typeof this.initializedFieldTypeSettings[type] == 'undefined');
var info = this.configurator.getFieldTypeInfo(type),
bodyHtml = this.getParsedFieldTypeHtml(info.settingsBodyHtml),
footHtml = this.getParsedFieldTypeHtml(info.settingsFootHtml);
if (firstTime)
{
var $body = $('<div>'+bodyHtml+'</div>');
this.initializedFieldTypeSettings[type] = $body;
}
else
{
var $body = this.initializedFieldTypeSettings[type];
}
$body.appendTo(this.$typeSettingsContainer);
Craft.initUiElements($body);
Garnish.$bod.append(footHtml);
},
getParsedFieldTypeHtml: function(html)
{
if (typeof html == 'string')
{
html = html.replace(/__BLOCK_TYPE__/g, this.blockType.id);
html = html.replace(/__FIELD__/g, this.id);
}
else
{
html = '';
}
return html;
},
getDefaultFieldSettingsHtml: function()
{
var html =
'<div data-id="'+this.id+'">' +
'<div class="field" id="'+this.inputIdPrefix+'-name-field">' +
'<div class="heading">' +
'<label for="'+this.inputIdPrefix+'-name">'+Craft.t('Name')+'</label>' +
'</div>' +
'<div class="input">' +
'<input class="text fullwidth" type="text" id="'+this.inputIdPrefix+'-name" name="'+this.inputNamePrefix+'[name]" autofocus="" autocomplete="off"/>' +
'</div>' +
'</div>' +
'<div class="field" id="'+this.inputIdPrefix+'-handle-field">' +
'<div class="heading">' +
'<label class="required" for="'+this.inputIdPrefix+'-handle">'+Craft.t('Handle')+'</label>' +
'</div>' +
'<div class="input">' +
'<input class="text fullwidth code" type="text" id="'+this.inputIdPrefix+'-handle" name="'+this.inputNamePrefix+'[handle]" autofocus="" autocomplete="off"/>' +
'</div>' +
'</div>' +
'<div class="field" id="'+this.inputIdPrefix+'-instructions-field">' +
'<div class="heading">' +
'<label for="'+this.inputIdPrefix+'-instructions">'+Craft.t('Instructions')+'</label>' +
'</div>' +
'<div class="input">' +
'<textarea class="text nicetext fullwidth" rows="2" cols="50" id="'+this.inputIdPrefix+'-instructions" name="'+this.inputNamePrefix+'[instructions]"></textarea>' +
'</div>' +
'</div>' +
'<div class="field checkboxfield">' +
'<label>' +
'<input type="hidden" name="'+this.inputNamePrefix+'[required]" value=""/>' +
'<input type="checkbox" value="1" name="'+this.inputNamePrefix+'[required]"/> ' +
Craft.t('This field is required') +
'</label>' +
'</div>';
if (Craft.isLocalized)
{
html +=
'<div class="field checkboxfield">' +
'<label>' +
'<input type="hidden" name="'+this.inputNamePrefix+'[translatable]" value=""/>' +
'<input type="checkbox" value="1" name="'+this.inputNamePrefix+'[translatable]"/> ' +
Craft.t('This field is translatable') +
'</label>' +
'</div>';
}
html +=
'<hr/>' +
'<div class="field" id="type-field">' +
'<div class="heading">' +
'<label for="type">'+Craft.t('Field Type')+'</label>' +
'</div>' +
'<div class="input">' +
'<div class="select">' +
'<select id="type" class="fieldtoggle" name="'+this.inputNamePrefix+'[type]">';
for (var i = 0; i < this.configurator.fieldTypeInfo.length; i++)
{
var info = this.configurator.fieldTypeInfo[i],
selected = (info.type == 'PlainText');
html +=
'<option value="'+info.type+'"'+(selected ? ' selected=""' : '')+'>'+info.name+'</option>';
}
html +=
'</select>' +
'</div>' +
'</div>' +
'</div>' +
'<div class="fieldtype-settings"/>' +
'<hr/>' +
'<a class="error delete">'+Craft.t('Delete')+'</a>' +
'</div>';
return html;
},
confirmDelete: function()
{
if (confirm(Craft.t('Are you sure you want to delete this field?')))
{
this.selfDestruct();
}
},
selfDestruct: function()
{
this.deselect();
this.$item.remove();
this.$fieldSettingsContainer.remove();
this.blockType.fields[this.id] = null;
delete this.blockType.fields[this.id];
}
});
})(jQuery);