1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354 |
- /*
- formBuilder - git@github.com:kevinchappell/formBuilder.git
- Version: 1.6.2
- Author: Kevin Chappell <kevin.b.chappell@gmail.com>
- */
- 'use strict';
- (function($) {
- 'use strict';
- var Toggle = function Toggle(element, options) {
- var defaults = {
- theme: 'fresh',
- labels: {
- off: 'Off',
- on: 'On'
- }
- };
- var opts = $.extend(defaults, options),
- $kcToggle = $('<div class="kc-toggle"/>').insertAfter(element).append(element);
- $kcToggle.toggleClass('on', element.is(':checked'));
- var kctOn = '<div class="kct-on">' + opts.labels.on + '</div>',
- kctOff = '<div class="kct-off">' + opts.labels.off + '</div>',
- kctHandle = '<div class="kct-handle"></div>',
- kctInner = '<div class="kct-inner">' + kctOn + kctHandle + kctOff + '</div>';
- $kcToggle.append(kctInner);
- $kcToggle.click(function() {
- element.attr('checked', !element.attr('checked'));
- $(this).toggleClass('on');
- });
- };
- $.fn.kcToggle = function(options) {
- var toggle = this;
- return toggle.each(function() {
- var element = $(this);
- if (element.data('kcToggle')) {
- return;
- }
- var kcToggle = new Toggle(element, options);
- element.data('kcToggle', kcToggle);
- });
- };
- })(jQuery);
- 'use strict';
- (function($) {
- 'use strict';
- var FormBuilder = function FormBuilder(element, options) {
- var defaults = {
- // Uneditable fields or other content you would like to
- // appear before and after regular fields.
- disableFields: {
- // before: '<h2>Header</h2>',
- // after: '<h3>Footer</h3>'
- },
- // array of objects with fields values
- // ex:
- // defaultFields: [{
- // label: 'First Name',
- // name: 'first-name',
- // required: 'true',
- // description: 'Your first name',
- // type: 'text'
- // }, {
- // label: 'Phone',
- // name: 'phone',
- // description: 'How can we reach you?',
- // type: 'text'
- // }],
- defaultFields: [],
- roles: {
- 1 : 'Administrator'
- },
- showWarning: false,
- serializePrefix: 'frmb',
- messages: {
- add: 'Add Item',
- allowSelect: 'Allow Select',
- autocomplete: 'Autocomplete',
- cannotBeEmpty: 'This field cannot be empty',
- checkboxGroup: 'Checkbox Group',
- checkbox: 'Checkbox',
- checkboxes: 'Checkboxes',
- clearAllMessage: 'Are you sure you want to remove all items?',
- clearAll: 'Clear All',
- close: 'Close',
- copy: 'Copy To Clipboard',
- dateField: 'Date Field',
- description: 'Help Text',
- descriptionField: 'Description',
- devMode: 'Developer Mode',
- disableFields: 'These fields cannot be moved.',
- editNames: 'Edit Names',
- editorTitle: 'Form Elements',
- editXML: 'Edit XML',
- fieldVars: 'Field Variables',
- fieldRemoveWarning: 'Are you sure you want to remove this field?',
- getStarted: 'Drag a field from the right to this area',
- hide: 'Edit',
- hidden: 'Hidden Input',
- label: 'Label',
- labelEmpty: 'Field Label cannot be empty',
- limitRole: 'Limit access to one or more of the following roles:',
- mandatory: 'Mandatory',
- maxLength: 'Max Length',
- minOptionMessage: 'This field requires a minimum of 2 options',
- name: 'Name',
- no: 'No',
- off: 'Off',
- on: 'On',
- optional: 'optional',
- optionLabelPlaceholder: 'Label',
- optionValuePlaceholder: 'Value',
- optionEmpty: 'Option value required',
- paragraph: 'Paragraph',
- preview: 'Preview',
- radioGroup: 'Radio Group',
- radio: 'Radio',
- removeMessage: 'Remove Element',
- remove: '×',
- required: 'Required',
- richText: 'Rich Text Editor',
- roles: 'Access',
- save: 'Save Template',
- selectOptions: 'Select Items',
- select: 'Select',
- selectionsMessage: 'Allow Multiple Selections',
- text: 'Text Field',
- textLabel: 'Title',
- textIntroduce: 'Description',
- toggle: 'Toggle',
- warning: 'Warning!',
- viewXML: 'View XML',
- yes: 'Yes',
- defaultValue : 'Default Value',
- }
- };
- var startIndex, doCancel, _helpers = {};
- /**
- * Callback for when a drag begins
- * @param {object} event
- * @param {object} ui
- */
- _helpers.startMoving = function(event, ui) {
- event = event;
- ui.item.addClass('moving');
- startIndex = $('li', this).index(ui.item);
- };
- /**
- * Callback for when a drag ends
- * @param {object} event
- * @param {object} ui
- */
- _helpers.stopMoving = function(event, ui) {
- event = event;
- ui.item.removeClass('moving');
- if (doCancel) {
- $(ui.sender).sortable('cancel');
- $(this).sortable('cancel');
- }
- };
- /**
- * Make strings safe to be used as classes
- * @param {string} str string to be converted
- * @return {string} converter string
- */
- _helpers.safename = function(str) {
- return str.replace(/\s/g, '-').replace(/[^a-zA-Z0-9\-\_]/g, '').toLowerCase();
- };
- /**
- * Strips non-numbers from a number only input
- * @param {string} str string with possible number
- * @return {string} string without numbers
- */
- _helpers.forceNumber = function(str) {
- return str.replace(/[^0-9]/g, '');
- };
- /**
- * hide and show mouse tracking tooltips, only used for disabled
- * fields in the editor.
- * @todo remove or refactor to make better use
- * @param {object} tt jQuery option with nexted tooltip
- * @return {void}
- */
- _helpers.initTooltip = function(tt) {
- var tooltip = tt.find('.tooltip');
- tt.mouseenter(function() {
- if (tooltip.outerWidth() > 200) {
- tooltip.addClass('max-width');
- }
- tooltip.css('left', tt.width() + 14);
- tooltip.stop(true, true).fadeIn('fast');
- }).mouseleave(function() {
- tt.find('.tooltip').stop(true, true).fadeOut('fast');
- });
- tooltip.hide();
- };
- // saves the field data to our canvas (elem)
- _helpers.save = function() {
- $sortableFields.children('li').not('.disabled').each(function() {
- _helpers.updatePreview($(this));
- });
- elem.val($sortableFields.toXML());
- };
- // updatePreview will generate the preview for radio and checkbox groups
- _helpers.updatePreview = function(field) {
- var fieldClass = field.attr('class'),
- $prevHolder = $('.prev-holder', field);
- if (fieldClass.indexOf('ui-sortable-handle') !== -1) {
- return;
- }
- fieldClass = fieldClass.replace(' form-field', '');
- var preview, previewData = {
- type: fieldClass,
- label: $('.fld-label', field).val()
- };
- if (fieldClass === 'checkbox') {
- previewData.toggle = $('.checkbox-toggle', field).is(':checked');
- }
- if (fieldClass.match(/(select|checkbox-group|radio-group)/)) {
- previewData.values = [];
- $('.sortable-options li', field).each(function() {
- var option = {};
- option.selected = $('.select-option', $(this)).is(':checked');
- option.value = $('.option-value', $(this)).val();
- option.label = $('.option-label', $(this)).val();
- previewData.values.push(option);
- });
- }
- preview = fieldPreview(previewData);
- $prevHolder.html(preview);
- $('input[toggle]', $prevHolder).kcToggle();
- };
- // update preview to label
- _helpers.updateMultipleSelect = function() {
- $sortableFields.delegate('input[name="multiple"]', 'change',
- function() {
- var options = $(this).parents('.fields:eq(0)').find('.sortable-options input.select-option');
- if (this.checked) {
- options.each(function() {
- $(this).prop('type', 'checkbox');
- });
- } else {
- options.each(function() {
- $(this).removeAttr('checked').prop('type', 'radio');
- });
- }
- });
- };
- _helpers.htmlEncode = function(value) {
- return $('<div/>').text(value).html();
- };
- _helpers.htmlDecode = function(value) {
- return $('<div/>').html(value).text();
- };
- _helpers.validateForm = function() {
- var errors = [];
- // check for empty field labels
- $('input[name="label"], input[type="text"].option', $sortableFields).each(function() {
- if ($(this).val() === '') {
- var field = $(this).parents('li.form-field'),
- fieldAttr = $(this);
- errors.push({
- field: field,
- error: opts.messages.labelEmpty,
- attribute: fieldAttr
- });
- }
- });
- // @todo add error = { noVal: opts.messages.labelEmpty }
- if (errors.length) {
- alert('Error: ' + errors[0].error);
- $('html, body').animate({
- scrollTop: errors[0].field.offset().top
- },
- 1000,
- function() {
- var targetID = $('.toggle-form', errors[0].field).attr('id');
- $('.toggle-form', errors[0].field).addClass('open').parent().next('.prev-holder').slideUp(250);
- $('#' + targetID + '-fld').slideDown(250,
- function() {
- errors[0].attribute.addClass('error');
- });
- });
- }
- };
- _helpers.disabledTT = function(field) {
- var title = field.attr('data-tooltip');
- if (title) {
- field.removeAttr('title').data('tip_text', title);
- var tt = $('<p/>', {
- 'class': 'frmb-tt'
- }).html(title);
- field.append(tt);
- tt.css({
- top: -tt.outerHeight(),
- left: -15
- });
- field.mouseleave(function() {
- $(this).attr('data-tooltip', field.data('tip_text'));
- $('.frmb-tt').remove();
- });
- }
- };
- var opts = $.extend(defaults, options),
- elem = $(element),
- frmbID = 'frmb-' + $('ul[id^=frmb-]').length++;
- var field = '',
- lastID = 1,
- boxID = frmbID + '-control-box';
- // create array of field objects to cycle through
- var frmbFields = [{
- label: opts.messages.text,
- attrs: {
- type: 'text',
- className: 'text-input',
- name: 'text-input'
- }
- },
- {
- label: opts.messages.select,
- attrs: {
- type: 'select',
- className: 'select',
- name: 'select'
- }
- },
- {
- label: opts.messages.richText,
- attrs: {
- type: 'rich-text',
- className: 'rich-text',
- name: 'rich-text'
- }
- },
- {
- label: opts.messages.radioGroup,
- attrs: {
- type: 'radio-group',
- className: 'radio-group',
- name: 'radio-group'
- }
- },
- {
- label: opts.messages.hidden,
- attrs: {
- type: 'hidden',
- className: 'hidden-input',
- name: 'hidden-input'
- }
- },
- {
- label: opts.messages.dateField,
- attrs: {
- type: 'date',
- className: 'calendar',
- name: 'date-input'
- }
- },
- {
- label: opts.messages.checkboxGroup,
- attrs: {
- type: 'checkbox-group',
- className: 'checkbox-group',
- name: 'checkbox-group'
- }
- },
- {
- label: opts.messages.checkbox,
- attrs: {
- type: 'checkbox',
- className: 'checkbox',
- name: 'checkbox'
- }
- },
- {
- label: opts.messages.autocomplete,
- attrs: {
- type: 'autocomplete',
- className: 'autocomplete',
- name: 'autocomplete'
- }
- },
- {
- label: opts.messages.textLabel,
- attrs: {
- type: 'text-label',
- className: 'text-label',
- name: 'text'
- }
- }];
- // Create draggable fields for formBuilder
- var cbUL = $('<ul/>', {
- id: boxID,
- 'class': 'frmb-control'
- });
- // Loop through
- for (var i = frmbFields.length - 1; i >= 0; i--) {
- var $field = $('<li/>', {
- 'class': 'icon-' + frmbFields[i].attrs.className,
- 'type': frmbFields[i].type,
- 'name': frmbFields[i].className,
- 'label': frmbFields[i].label
- });
- for (var attr in frmbFields[i]) {
- if (frmbFields[i].hasOwnProperty(attr)) {
- $field.data(attr, frmbFields[i][attr]);
- }
- }
- $field.html(frmbFields[i].label).appendTo(cbUL);
- }
- // Build our headers and action links
- var cbHeader = $('<h4/>').html(opts.messages.editorTitle),
- viewXML = $('<a/>', {
- id: frmbID + '-export-xml',
- text: opts.messages.viewXML,
- href: '#',
- 'class': 'view-xml'
- }),
- allowSelect = $('<a/>', {
- id: frmbID + '-allow-select',
- text: opts.messages.allowSelect,
- href: '#',
- 'class': 'allow-select'
- }).prop('checked', 'checked'),
- editXML = $('<a/>', {
- id: frmbID + '-edit-xml',
- text: opts.messages.editXML,
- href: '#',
- 'class': 'edit-xml'
- }),
- editNames = $('<a/>', {
- id: frmbID + '-edit-names',
- text: opts.messages.editNames,
- href: '#',
- 'class': 'edit-names'
- }),
- clearAll = $('<a/>', {
- id: frmbID + '-clear-all',
- text: opts.messages.clearAll,
- href: '#',
- 'class': 'clear-all'
- }),
- saveAll = $('<div/>', {
- id: frmbID + '-save',
- href: '#',
- 'class': 'save-btn-wrap',
- title: opts.messages.save
- }).html('<a class="save fb-button primary"><span>' + opts.messages.save + '</span></a>'),
- actionLinksInner = $('<div/>', {
- id: frmbID + '-action-links-inner',
- 'class': 'action-links-inner'
- }).append(editXML, ' | ', editNames, ' | ', allowSelect, ' | ', clearAll, ' | '),
- devMode = $('<span/>', {
- 'class': 'dev-mode-link'
- }).html(opts.messages.devMode + ' ' + opts.messages.off),
- actionLinks = $('<div/>', {
- id: frmbID + '-action-links',
- 'class': 'action-links'
- }).append(actionLinksInner, devMode);
- // Sortable fields
- var $sortableFields = $('<ul/>').attr('id', frmbID).addClass('frmb').sortable({
- cursor: 'move',
- opacity: 0.9,
- beforeStop: function beforeStop(event, ui) {
- var lastIndex = $('> li', $sortableFields).length - 1,
- curIndex = ui.placeholder.index();
- doCancel = curIndex <= 1 || curIndex === lastIndex;
- },
- start: _helpers.startMoving,
- stop: _helpers.stopMoving,
- cancel: 'input, .disabled, .sortable-options, .add, .btn, .no-drag',
- // items: 'li:not(.no-fields)',
- receive: function receive(event, ui) {
- // if (doCancel) {
- // $('li:nth-child(' + curIndex + ')', $(this)).remove();
- // }
- },
- placeholder: 'frmb-placeholder'
- });
- // ControlBox with different fields
- cbUL.sortable({
- helper: 'clone',
- opacity: 0.9,
- connectWith: $sortableFields,
- cursor: 'move',
- placeholder: 'ui-state-highlight',
- start: _helpers.startMoving,
- stop: _helpers.stopMoving,
- revert: 150,
- change: function change(event, ui) {
- //fix the logic on this to only hide placeholder for disabledFields.before and after
- // if (ui.placeholder.index() === 0 || ui.placeholder.index() === $('> li', $sortableFields).last().index()) {
- // $(ui.placeholder).hide();
- // } else {
- // $(ui.placeholder).show();
- // }
- },
- remove: function remove(event, ui) {
- if (startIndex === 0) {
- cbUL.prepend(ui.item);
- } else {
- $('li:nth-child(' + startIndex + ')', cbUL).after(ui.item);
- }
- },
- beforeStop: function beforeStop(event, ui) {
- var lastIndex = $('> li', $sortableFields).length - 1,
- curIndex = ui.placeholder.index();
- doCancel = curIndex <= 1 || curIndex === lastIndex ? true: false;
- if (ui.placeholder.parent().hasClass('frmb-control')) {
- doCancel = true;
- }
- },
- update: function update(event, ui) {
- // _helpers.stopMoving;
- elem.stopIndex = $('li', $sortableFields).index(ui.item) === 0 ? '0': $('li', $sortableFields).index(ui.item);
- if ($('li', $sortableFields).index(ui.item) < 0) {
- $(this).sortable('cancel');
- } else {
- prepFieldVars($(ui.item[0]), true);
- }
- },
- receive: function receive(event, ui) {
- if (ui.sender.hasClass('frmb') || ui.sender.hasClass('frmb-control')) {
- $(ui.sender).sortable('cancel');
- }
- }
- });
- var $stageWrap = $('<div/>', {
- id: frmbID + '-stage-wrap',
- 'class': 'stage-wrap'
- });
- var $formWrap = $('<div/>', {
- id: frmbID + '-form-wrap',
- 'class': 'form-wrap'
- });
- elem.before($stageWrap).appendTo($stageWrap);
- // Replace the textarea with sortable list.
- //elem.before($sortableFields).parent().prepend(frmbHeader).addClass('frmb-wrap').append(actionLinks, viewXML, saveAll);
- var cbWrap = $('<div/>', {
- id: frmbID + '-cb-wrap',
- 'class': 'cb-wrap'
- }).append(cbHeader, cbUL);
- $stageWrap.append($sortableFields, cbWrap, actionLinks, viewXML, saveAll);
- $stageWrap.before($formWrap);
- $formWrap.append($stageWrap, cbWrap);
- var doSave = function doSave() {
- if ($(this).parents('li.disabled').length === 0) {
- if ($(this).name === 'label' && $(this).val() === '') {
- return alert('Error: ' + opts.messages.labelEmpty);
- }
- _helpers.save();
- }
- };
- // Not pretty but we need to save a lot so users don't have to keep clicking a save button
- $('input, select', $sortableFields).on('change', doSave);
- $('input, select', $sortableFields).on('blur', doSave);
- // Parse saved XML template data
- elem.getTemplate = function() {
- var xml = elem.val() !== '' ? $.parseXML(elem.val()) : false,
- fields = $(xml).find('field');
- if (fields.length > 0) {
- fields.each(function() {
- prepFieldVars($(this));
- });
- } else if (!xml) {
- // Load default fields if none are set
- if (opts.defaultFields.length) {
- for (var i = opts.defaultFields.length - 1; i >= 0; i--) {
- appendNewField(opts.defaultFields[i]);
- }
- } else {
- $stageWrap.addClass('empty').attr('data-content', opts.messages.getStarted);
- }
- disabledBeforeAfter();
- }
- };
- var disabledBeforeAfter = function disabledBeforeAfter() {
- var li = '<li class="disabled __POSITION__">__CONTENT__</li>';
- if (opts.disableFields.before && !$('.disabled.before', $sortableFields).length) {
- $sortableFields.prepend(li.replace('__POSITION__', 'before').replace('__CONTENT__', opts.disableFields.before));
- }
- if (opts.disableFields.after && !$('.disabled.after', $sortableFields).length) {
- $sortableFields.append(li.replace('__POSITION__', 'after').replace('__CONTENT__', opts.disableFields.after));
- }
- };
- var nameAttr = function nameAttr(field) {
- var epoch = new Date().getTime();
- return field.data('attrs').name + '-' + epoch;
- };
- var prepFieldVars = function prepFieldVars($field, isNew) {
- isNew = isNew || false;
- var fieldAttrs = $field.data('attrs') || {},
- fType = fieldAttrs.type || $field.attr('type'),
- isMultiple = fType.match(/(select|checkbox-group|radio-group)/),
- values = {};
- values.label = _helpers.htmlEncode($field.attr('label'));
- values.name = isNew ? nameAttr($field) : fieldAttrs.name || $field.attr('name');
- values.name = typeof values.name == 'undefined' ? '' : values.name;
- values.defaultVal = $field.attr('defaultVal') !== undefined ? _helpers.htmlEncode($field.attr('defaultVal')) : '';
- values.role = $field.attr('role');
- values.required = $field.attr('required');
- values.maxLength = $field.attr('max-length');
- values.toggle = $field.attr('toggle');
- values.type = fType;
- values.description = $field.attr('description') !== undefined ? _helpers.htmlEncode($field.attr('description')) : '';
- values.introduce = $field.attr('introduce') !== undefined ? _helpers.htmlEncode($field.attr('introduce')) : '';
- if (isMultiple) {
- values.multiple = true;
- values.values = [];
- $field.children().each(function(i) {
- var value = {
- label: $(this).text(),
- value: $(this).attr('value'),
- selected: $field.attr('default') === i ? true: false
- };
- values.values.push(value);
- });
- }
- appendNewField(values);
- $stageWrap.removeClass('empty');
- disabledBeforeAfter();
- };
- // multi-line textarea
- var appendTextarea = function appendTextarea(values) {
- appendFieldLi(opts.messages.richText, advFields(values), values);
- };
- var appendInput = function appendInput(values) {
- var type = values.type || 'text';
- appendFieldLi(opts.messages[type], advFields(values), values);
- };
- var textLabel = function textLabel(values) {
- var type = values.type || 'text';
- values.introduce = values.introduce || opts.messages.textIntroduce;
- appendFieldLi(opts.messages[type], advFields(values), values);
- }
- // add select dropdown
- var appendSelectList = function appendSelectList(values) {
- if (!values.values || !values.values.length) {
- values.values = [{
- selected: 'false',
- label: 'Option 1',
- value: 'option-1'
- },
- {
- selected: 'false',
- label: 'Option 2',
- value: 'option-2'
- }];
- }
- var field = '',
- name = _helpers.safename(values.name),
- multiDisplay = values.type === 'checkbox-group' ? 'none': 'none';
- field += advFields(values);
- field += '<div class="false-label">' + opts.messages.selectOptions + '</div>';
- field += '<div class="fields">';
- field += '<div class="allow-multi" style="display:' + multiDisplay + '">';
- field += '<input type="checkbox" id="multiple_' + lastID + '" name="multiple"' + (values.multiple ? 'checked="checked"': '') + '>';
- field += '<label class="multiple" for="multiple_' + lastID + '">' + opts.messages.selectionsMessage + '</label>';
- field += '</div>';
- field += '<ol class="sortable-options">';
- for (i = 0; i < values.values.length; i++) {
- field += selectFieldOptions(values.values[i], name, values.values[i].selected, values.multiple);
- }
- field += '</ol>';
- field += '<div class="field_actions"><a href="#" class="add add_opt"><strong>' + opts.messages.add + '</strong></a> | <a href="#" class="close_field">' + opts.messages.close + '</a></div>';
- field += '</div>';
- appendFieldLi(opts.messages.select, field, values);
- $('.sortable-options').sortable(); // making the dynamically added option fields sortable.
- };
- var appendNewField = function appendNewField(values) {
- if (values === undefined) {
- values = '';
- }
- // TODO: refactor to move functions into this object
- var appendFieldType = {
- // 'text': appendTextInput(values),
- // 'checkbox': appendCheckbox(values),
- // 'select': appendSelectList(values),
- // 'textarea': appendTextarea(values),
- 'text-label': textLabel,
- '2': appendInput,
- 'date': appendInput,
- 'autocomplete': appendInput,
- 'checkbox': appendInput,
- 'select': appendSelectList,
- 'rich-text': appendTextarea,
- 'textarea': appendTextarea,
- 'radio-group': appendSelectList,
- 'checkbox-group': appendSelectList,
- 'text': appendInput,
- 'hidden': appendInput
- };
- if (typeof appendFieldType[values.type] === 'function') {
- appendFieldType[values.type](values);
- }
- };
- /**
- * Build the editable properties for the field
- * @param {object} values configuration object for advanced fields
- * @return {string} markup for advanced fields
- */
- var advFields = function advFields(values) {
- var advFields = '',
- key, roles = values.role !== undefined ? values.role.split(',') : [];
- var fieldLabel = $('<div>', {
- 'class': 'frm-fld label-wrap'
- });
- $('<label/>').html(opts.messages.label + ' *').appendTo(fieldLabel);
- $('<input>', {
- type: 'text',
- name: 'label',
- value: values.label,
- 'class': 'fld-label'
- }).appendTo(fieldLabel);
- advFields += fieldLabel[0].outerHTML;
- var fieldDesc = $('<div>', {
- 'class': 'frm-fld description-wrap'
- });
- $('<label/>').html(opts.messages.description + ' *').appendTo(fieldDesc);
- if (values.type == 'text-label') { //text-label
- advFields += '<div class="frm-fld description-wrap"><label>' + opts.messages.textIntroduce + '</label>';
- advFields += '<input type="text" name="introduce" value="' + values.introduce + '" class="fld-introduce" id="introduce-' + lastID + '" /></div>';
- }
- if (values.type != 'text-label') {
- advFields += '<div class="frm-fld description-wrap"><label>' + opts.messages.description + '</label>';
- advFields += '<input type="text" name="description" value="' + values.description + '" class="fld-description" id="description-' + lastID + '" /></div>';
- advFields += '<div class="frm-fld name-wrap"><label>' + opts.messages.name + ' <span class="required">*</span></label>';
- advFields += '<input type="text" name="name" value="' + values.name + '" class="fld-name" id="title-' + lastID + '" /></div>';
- }
- advFields += '<div class="frm-fld access-wrap"><label>' + opts.messages.roles + '</label>';
- advFields += '<input type="checkbox" name="enable_roles" value="" ' + (values.role !== undefined ? 'checked': '') + ' id="enable_roles-' + lastID + '"/> <label for="enable_roles-' + lastID + '" class="roles_label">' + opts.messages.limitRole + '</label>';
- advFields += '<div class="frm-fld available-roles" ' + (values.role !== undefined ? 'style="display:block"': '') + '>';
- for (key in opts.roles) {
- if ($.inArray(key, ['date', '4']) === -1) {
- advFields += '<input type="checkbox" name="roles[]" value="' + key + '" id="fld-' + lastID + '-roles-' + key + '" ' + ($.inArray(key, roles) !== -1 ? 'checked': '') + ' class="roles-field" /><label for="fld-' + lastID + '-roles-' + key + '">' + opts.roles[key] + '</label><br/>';
- }
- }
- advFields += '</div></div>';
- // if field type is not checkbox, checkbox/radio group or select list, add max length
- if ($.inArray(values.type, ['checkbox', 'select', 'checkbox-group', 'date', 'autocomplete', 'radio-group', 'text-label']) < 0) {
- advFields += '<div class="frm-fld"><label class="max-length-label">' + opts.messages.maxLength + '</label>';
- advFields += '<input type="text" name="max-length" max-length="4" value="' + (values.maxLength !== undefined ? values.maxLength: '') + '" class="fld-max-length" id="max-length-' + lastID + '" /></div>';
- }
- return advFields;
- };
- // Append the new field to the editor
- var appendFieldLi = function appendFieldLi(title, field, values) {
- var label = $(field).find('input[name="label"]').val() !== '' ? $(field).find('input[name="label"]').val() : title;
- var defaultVal = typeof values.defaultVal != 'undefined' ? values.defaultVal : '';
- var introduce = $(field).find('input[name="introduce"]').val() !== '' ? $(field).find('input[name="introduce"]').val() : '';
- var li = '',
- delBtn = '<a id="del_' + lastID + '" class="del-button btn delete-confirm" href="#" title="' + opts.messages.removeMessage + '">' + opts.messages.remove + '</a>',
- toggleBtn = '<a id="frm-' + lastID + '" class="toggle-form btn icon-pencil" href="#" title="' + opts.messages.hide + '"></a> ',
- required = values.required,
- toggle = values.toggle || undefined,
- tooltip = values.description !== '' ? '<span class="tooltip-element" tooltip="' + values.description + '">?</span>': '';
- li += '<li id="frm-' + lastID + '-item" class="' + values.type + ' form-field">';
- li += '<div class="legend">';
- li += delBtn;
- li += '<span id="txt-title-' + lastID + '" class="field-label">' + label + '</span>' + tooltip + '<span class="required-asterisk" ' + (required === 'true' ? 'style="display:inline"': '') + '> *</span>' + toggleBtn;
- li += '</div>';
- if (values.type == 'text-label') {
- li += '<div class="frm-fld">';
- li += '<label class="field-introduce">' + introduce + '</label>';
- li += '</div>';
- }
- li += '<div class="prev-holder">' + fieldPreview(values) + '</div>';
- li += '<div id="frm-' + lastID + '-fld" class="frm-holder">';
- li += '<div class="form-elements">';
- if (values.type != 'text-label') {
- li += '<div class="frm-fld">';
- li += '<label> </label>';
- li += '<input class="required" type="checkbox" value="1" name="required-' + lastID + '" id="required-' + lastID + '"' + (required === 'true' ? ' checked="checked"': '') + ' /><label class="required_label" for="required-' + lastID + '">' + opts.messages.required + '</label>';
- if (values.type === 'checkbox') {
- li += '<div class="frm-fld">';
- li += '<label> </label>';
- li += '<input class="checkbox-toggle" type="checkbox" value="1" name="toggle-' + lastID + '" id="toggle-' + lastID + '"' + (toggle === 'true' ? ' checked="checked"': '') + ' /><label class="toggle-label" for="toggle-' + lastID + '">' + opts.messages.toggle + '</label>';
- li += '</div>';
- }
- li += '</div>';
- }
- if (values.type == 'hidden') {
- li += '<div class="frm-fld">';
- li += '<label class="field-defaultVal">'+opts.messages.defaultValue+'</label>';
- li += '<input type="text" class="fld-defaultVal" name="defaultVal" id="defaultVal-'+lastID+'" value="'+ defaultVal +'" />';
- li += '</div>';
- }
- li += field;
- li += '</div>';
- li += '</div>';
- li += '</li>';
- if (elem.stopIndex) {
- $('li', $sortableFields).eq(elem.stopIndex).after(li);
- } else {
- $sortableFields.append(li);
- }
- $(document.getElementById('frm-' + lastID + '-item')).hide().slideDown(250);
- lastID++;
- _helpers.save();
- };
- /**
- * Generate preview markup
- * @param {object} attrs
- * @return {string} preview markup for field
- */
- var fieldPreview = function fieldPreview(attrs) {
- var i, preview = '',
- epoch = new Date().getTime();
- switch (attrs.type) {
- case 'textarea':
- preview = '<' + attrs.type + '></' + attrs.type + '>';
- break;
- case 'select':
- var options;
- attrs.values.reverse();
- for (i = attrs.values.length - 1; i >= 0; i--) {
- options += '<option value="' + attrs.values[i].value + '">' + attrs.values[i].label + '</option>';
- }
- preview = '<' + attrs.type + ' class="no-drag">' + options + '</' + attrs.type + '>';
- break;
- case 'checkbox-group':
- case 'radio-group':
- var type = attrs.type.replace('-group', '');
- attrs.values.reverse();
- for (i = attrs.values.length - 1; i >= 0; i--) {
- preview += '<div class="inner-checkbox"><input type="' + type + '" id="' + type + '-' + epoch + '-' + i + '" value="' + attrs.values[i].value + '" /><label for="' + type + '-' + epoch + '-' + i + '">' + attrs.values[i].label + '</label></div>';
- }
- break;
- case 'text':
- case 'password':
- case 'hidden':
- case 'email':
- case 'date':
- case 'checkbox':
- var toggle = attrs.toggle ? 'toggle': '';
- preview = '<input type="' + attrs.type + '" ' + toggle + ' placeholder="">';
- break;
- case 'autocomplete':
- preview = '<input class="ui-autocomplete-input" autocomplete="on" placeholder="">';
- break;
- default:
- preview = '<' + attrs.type + '></' + attrs.type + '>';
- }
- return preview;
- };
- // Select field html, since there may be multiple
- var selectFieldOptions = function selectFieldOptions(values, name, selected, multipleSelect) {
- var selectedType = multipleSelect ? 'checkbox': 'radio';
- if (typeof values !== 'object') {
- values = {
- label: '',
- value: ''
- };
- } else {
- values.label = values.label || '';
- values.value = values.value || '';
- }
- field = '<li>';
- field += '<input type="' + selectedType + '" ' + selected + ' class="select-option" name="' + name + '" />';
- field += '<input type="text" class="option-label" placeholder="' + opts.messages.optionLabelPlaceholder + '" value="' + values.label + '" />';
- field += '<input type="text" class="option-value" placeholder="' + opts.messages.optionValuePlaceholder + '" value="' + values.value + '" />';
- field += '<a href="#" class="remove btn" title="' + opts.messages.removeMessage + '">' + opts.messages.remove + '</a>';
- field += '</li>';
- return field;
- };
- // ---------------------- UTILITIES ---------------------- //
- // delete options
- $sortableFields.delegate('.remove', 'click',
- function(e) {
- e.preventDefault();
- var optionsCount = $(this).parents('.sortable-options:eq(0)').children('li').length;
- if (optionsCount <= 2) {
- alert('Error: ' + opts.messages.minOptionMessage);
- } else {
- $(this).parent('li').slideUp('250',
- function() {
- $(this).remove();
- });
- }
- });
- // toggle fields
- $sortableFields.on('click', '.toggle-form',
- function(e) {
- e.preventDefault();
- var targetID = $(this).attr('id');
- $(this).toggleClass('open').parent().next('.prev-holder').slideToggle(250);
- $(document.getElementById(targetID + '-fld')).slideToggle(250,
- function() {
- _helpers.save();
- });
- });
- // update preview to label
- $sortableFields.delegate('input[name="label"]', 'keyup',
- function() {
- $('.field-label', $(this).closest('li')).text($(this).val());
- });
- $sortableFields.delegate('input[name="introduce"]', 'keyup',
- function() {
- $('.field-introduce', $(this).closest('li')).text($(this).val());
- });
- $sortableFields.delegate('input[name="defaultVal"]', 'keyup',
- function() {
- _helpers.save();
- });
- // remove error styling when users tries to correct mistake
- $sortableFields.delegate('input.error', 'keyup',
- function() {
- $(this).removeClass('error');
- });
- // update preview for description
- $sortableFields.delegate('input[name="description"]', 'keyup',
- function() {
- var closestToolTip = $('.tooltip-element', $(this).closest('li'));
- if ($(this).val() !== '') {
- if (!closestToolTip.length) {
- var tt = '<span class="tooltip-element" tooltip="' + $(this).val() + '">?</span>';
- $('.toggle-form', $(this).closest('li')).before(tt);
- // _helpers.initTooltip(tt);
- } else {
- closestToolTip.attr('tooltip', $(this).val()).css('display', 'inline-block');
- }
- } else {
- if (closestToolTip.length) {
- closestToolTip.css('display', 'none');
- }
- }
- });
- _helpers.updateMultipleSelect();
- // format name attribute
- $sortableFields.delegate('input[name="name"]', 'keyup',
- function() {
- $(this).val(_helpers.safename($(this).val()));
- if ($(this).val() === '') {
- $(this).addClass('field_error').attr('placeholder', opts.messages.cannotBeEmpty);
- } else {
- $(this).removeClass('field_error');
- }
- });
- $sortableFields.delegate('input.fld-max-length', 'keyup',
- function() {
- $(this).val(_helpers.forceNumber($(this).val()));
- });
- // Delete field
- $sortableFields.delegate('.delete-confirm', 'click',
- function(e) {
- e.preventDefault();
- // lets see if the user really wants to remove this field... FOREVER
- var fieldWarnH3 = $('<h3/>').html('<span></span>' + opts.messages.warning),
- deleteID = $(this).attr('id').replace(/del_/, ''),
- delBtn = $(this),
- $field = $(document.getElementById('frm-' + deleteID + '-item')),
- toolTipPageX = delBtn.offset().left - $(window).scrollLeft(),
- toolTipPageY = delBtn.offset().top - $(window).scrollTop();
- if (opts.showWarning) {
- jQuery('<div />').append(fieldWarnH3, opts.messages.fieldRemoveWarning).dialog({
- modal: true,
- resizable: false,
- width: 300,
- dialogClass: 'ite-warning',
- open: function open() {
- $('.ui-widget-overlay').css({
- 'opacity': 0.0
- });
- },
- position: [toolTipPageX - 282, toolTipPageY - 178],
- buttons: [{
- text: opts.messages.yes,
- click: function click() {
- $field.slideUp(250,
- function() {
- $(this).remove();
- _helpers.save();
- });
- $(this).dialog('close');
- }
- },
- {
- text: opts.messages.no,
- 'class': 'cancel',
- click: function click() {
- $(this).dialog('close');
- }
- }]
- });
- } else {
- $field.slideUp(250,
- function() {
- $(this).remove();
- _helpers.save();
- });
- }
- if ($('.form-field', $sortableFields).length === 1) {
- $stageWrap.addClass('empty');
- }
- });
- // Attach a callback to toggle required asterisk
- $sortableFields.delegate('input.required', 'click',
- function() {
- var requiredAsterisk = $(this).parents('li.form-field').find('.required-asterisk');
- requiredAsterisk.toggle();
- });
- // Attach a callback to toggle roles visibility
- $sortableFields.delegate('input[name="enable_roles"]', 'click',
- function() {
- var roles = $(this).siblings('div.available-roles'),
- enableRolesCB = $(this);
- roles.slideToggle(250,
- function() {
- if (!enableRolesCB.is(':checked')) {
- $('input[type="checkbox"]', roles).removeAttr('checked');
- }
- });
- });
- // Attach a callback to add new checkboxes
- $sortableFields.delegate('.add_ck', 'click',
- function() {
- $(this).parent().before(selectFieldOptions());
- return false;
- });
- $sortableFields.delegate('li.disabled .form-element', 'mouseenter',
- function() {
- _helpers.disabledTT($(this));
- });
- // Attach a callback to add new options
- $sortableFields.delegate('.add_opt', 'click',
- function(e) {
- e.preventDefault();
- var isMultiple = $(this).parents('.fields').first().find('input[name="multiple"]')[0].checked,
- name = $(this).parents('.fields').find('.select-option:eq(0)').attr('name');
- $(this).parents('.fields').first().find('.sortable-options').append(selectFieldOptions(false, name, false, isMultiple));
- _helpers.updateMultipleSelect();
- });
- // Attach a callback to close link
- $sortableFields.delegate('.close_field', 'click',
- function(e) {
- e.preventDefault();
- $(this).parents('li.form-field').find('.toggle-form').trigger('click');
- });
- // Attach a callback to add new radio fields
- $sortableFields.delegate('.add_rd', 'click',
- function(e) {
- e.preventDefault();
- $(this).parent().before(selectFieldOptions(false, $(this).parents('.frm-holder').attr('id')));
- });
- $('.form-elements .fields .remove, .frmb .del-button').on('hover',
- function() {
- $(this).parents('li.form-field').toggleClass('delete');
- });
- // View XML
- $(document.getElementById(frmbID + '-export-xml')).click(function(e) {
- e.preventDefault();
- var xml = elem.val(),
- $pre = $('<pre />').text(xml);
- $pre.dialog({
- resizable: false,
- modal: true,
- width: 720,
- dialogClass: 'frmb-xml',
- overlay: {
- color: '#333333'
- }
- });
- });
- // Clear all fields in form editor
- $(document.getElementById(frmbID + '-clear-all')).click(function(e) {
- e.preventDefault();
- if (window.confirm(opts.messages.clearAllMessage)) {
- $sortableFields.empty();
- elem.val('');
- _helpers.save();
- var values = {
- label: [opts.messages.descriptionField],
- name: ['content'],
- required: 'true',
- description: opts.messages.mandatory
- };
- appendNewField(values);
- $sortableFields.prepend(opts.disableFields.before);
- $sortableFields.append(opts.disableFields.after);
- }
- });
- // Save Idea Template
- $(document.getElementById(frmbID + '-save')).click(function(e) {
- if ($(this).find('.ldkInlineEdit').length === 0) {
- e.preventDefault();
- if (!$stageWrap.hasClass('edit-xml')) {
- _helpers.save();
- }
- _helpers.validateForm(e);
- }
- });
- var triggerDevMode = false,
- keys = [],
- devCode = '68,69,86';
- // Super secret Developer Tools
- $('.save.fb-button').mouseover(function() {
- triggerDevMode = true;
- }).mouseout(function() {
- triggerDevMode = false;
- });
- $(document.documentElement).keydown(function(e) {
- keys.push(e.keyCode);
- if (keys.toString().indexOf(devCode) >= 0) {
- $('.action-links').toggle();
- $('.view-xml').toggle();
- keys = [];
- }
- });
- // Toggle Developer Mode
- $('.dev-mode-link').click(function(e) {
- e.preventDefault();
- var dml = $(this);
- $stageWrap.toggleClass('dev-mode');
- dml.parent().css('opacity', 1);
- if ($stageWrap.hasClass('dev-mode')) {
- dml.siblings('.action-links-inner').css('width', '100%');
- dml.html(opts.messages.devMode + ' ' + opts.messages.on).css('color', '#8CC63F');
- } else {
- dml.siblings('.action-links-inner').css('width', 0);
- dml.html(opts.messages.devMode + ' ' + opts.messages.off).css('color', '#666666');
- triggerDevMode = false;
- $('.action-links').toggle();
- $('.view-xml').toggle();
- }
- });
- // Toggle Edit Names
- $(document.getElementById(frmbID + '-edit-names')).click(function(e) {
- e.preventDefault();
- $(this).toggleClass('active');
- $('.name-wrap', $sortableFields).slideToggle(250,
- function() {
- $stageWrap.toggleClass('edit-names');
- });
- });
- // Toggle Allow Select
- $(document.getElementById(frmbID + '-allow-select')).click(function(e) {
- e.preventDefault();
- $(this).toggleClass('active');
- $('.allow-multi, .select-option', $sortableFields).slideToggle(250,
- function() {
- $stageWrap.toggleClass('allow-select');
- });
- });
- // Toggle Edit XML
- $(document.getElementById(frmbID + '-edit-xml')).click(function(e) {
- e.preventDefault();
- $(this).toggleClass('active');
- $('textarea.idea-template').show();
- $('.template-textarea-wrap').slideToggle(250);
- $stageWrap.toggleClass('edit-xml');
- });
- elem.parent().find('p[id*="ideaTemplate"]').remove();
- elem.wrap('<div class="template-textarea-wrap"/>');
- elem.getTemplate();
- };
- $.fn.formBuilder = function(options) {
- var form = this;
- return form.each(function() {
- var element = $(this);
- if (element.data('formBuilder')) {
- return;
- }
- var formBuilder = new FormBuilder(this, options);
- element.data('formBuilder', formBuilder);
- });
- };
- })(jQuery);
- // toXML is a jQuery plugin that turns our form editor into XML
- (function($) {
- 'use strict';
- $.fn.toXML = function(options) {
- var defaults = {
- prepend: '',
- attributes: ['class']
- };
- var opts = $.extend(defaults, options);
- var serialStr = '';
- // Begin the core plugin
- this.each(function() {
- var liCount = 0;
- var c = 1;
- if ($(this).children().length >= 1) {
- serialStr += '<form-template>\n\t<fields>';
- // build new xml
- $(this).children().each(function() {
- var $field = $(this);
- if (! ($field.hasClass('moving') || $field.hasClass('disabled'))) {
- for (var att = 0; att < opts.attributes.length; att++) {
- var required = $('input.required', $field).is(':checked') ? 'required="true" ': 'required="false" ',
- multipleChecked = $('input[name="multiple"]', $field).is(':checked'),
- multiple = multipleChecked ? 'style="multiple" ': '',
- t = $field.attr(opts.attributes[att]).replace(' form-field', ''),
- // field type
- multipleField = t.match(/(select|checkbox-group|radio-group)/),
- type = 'type="' + t + '" ',
- fName = $('input.fld-name', $field).length > 0 ? ('name="' + $('input.fld-name', $field).val() + '" ') : '',
- fLabel = 'label="' + $('input.fld-label', $field).val() + '" ',
- roleVals = $.map($('input.roles-field:checked', $field),
- function(n) {
- return n.value;
- }).join(','),
- roles = roleVals !== '' ? 'role="' + roleVals + '" ': '',
- desc = $('input.fld-description', $field).length > 0 ? ('description="' + $('input.fld-description', $field).val() + '" ') : '',
- introduce = $('input.fld-introduce', $field).length > 0 ? ('introduce="' + $('input.fld-introduce', $field).val() + '" ') : '',
- defaultVal = $('input.fld-defaultVal', $field).length > 0 ? ('defaultVal="' + $('input.fld-defaultVal', $field).val() + '" ') : '',
- maxLengthVal = $('input.fld-max-length', $field).val(),
- maxLength = 'max-length="' + (maxLengthVal !== undefined ? maxLengthVal: '') + '" ',
- fSlash = !multipleField ? '/': '';
- var fToggle = $('.checkbox-toggle', $field).is(':checked') ? 'toggle="true" ': '';
- serialStr += '\n\t\t<field ' + fName + fLabel + defaultVal + fToggle + multiple + roles + desc + introduce + (maxLengthVal !== '' ? maxLengthVal !== undefined ? maxLength: '': '') + required + type + fSlash +'>';
- if (multipleField) {
- c = 1;
- $('.sortable-options li', $field).each(function() {
- var $option = $(this),
- optionValue = 'value="' + $('.option-value', $option).val() + '"',
- optionLabel = $('.option-label', $option).val(),
- selected = $('.select-option', $option).is(':checked') ? ' selected="true"': '';
- serialStr += '\n\t\t\t<option' + selected + ' ' + optionValue + '>' + optionLabel + '</option>';
- c++;
- });
- serialStr += '\n\t\t</field>';
- }
- }
- }
- liCount++;
- });
- serialStr += '\n\t</fields>\n</form-template>';
- } // if "$(this).children().length >= 1"
- });
- return serialStr;
- };
- })(jQuery);
|