Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Aug 6th, 2012  |  syntax: None  |  size: 48.06 KB  |  hits: 9  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. if (!Array.prototype.filter)
  2. {
  3.   Array.prototype.filter = function(fun /*, thisp */)
  4.   {
  5.     "use strict";
  6.  
  7.     if (this === void 0 || this === null)
  8.       throw new TypeError();
  9.  
  10.     var t = Object(this);
  11.     var len = t.length >>> 0;
  12.     if (typeof fun !== "function")
  13.       throw new TypeError();
  14.  
  15.     var res = [];
  16.     var thisp = arguments[1];
  17.     for (var i = 0; i < len; i++)
  18.     {
  19.       if (i in t)
  20.       {
  21.         var val = t[i]; // in case fun mutates this
  22.         if (fun.call(thisp, val, i, t))
  23.           res.push(val);
  24.       }
  25.     }
  26.  
  27.     return res;
  28.   };
  29. }
  30.  
  31. // read support for HTML5 data Attributes
  32. Element.addMethods({
  33.     getDataset: function(element) {
  34.         if (element.dataset) return element.dataset;
  35.         var match, attr, dataset = {},
  36.             attributes = element.attributes,
  37.             index = attributes.length;
  38.         while (index--) {
  39.             attr = attributes[index];
  40.             if (attr.localName.startsWith('data-'))
  41.             dataset[attr.localName.substring(5)] = attr.nodeValue;
  42.         }
  43.         return element.dataset = dataset;
  44.     }
  45. });
  46.  
  47.  
  48. // Like perl ;)
  49. "use strict";
  50.  
  51.  
  52. // a single node
  53. var FormEditorNode = Class.create( {
  54.  
  55.     // Initalize new Element
  56.     initialize: function(raw, htm, pt) {
  57.    
  58.         var these = this;
  59.        
  60.         these.raw  = raw;
  61.  
  62.         // get a describtive title
  63.         var title = these.raw.label ? these.raw.label : these.raw.name;
  64.  
  65.         // is root?
  66.         these.pt = pt ? pt.raw.name : false;
  67.  
  68.         if ( these.root && !these.raw.name ) {
  69.  
  70.             // Special name for the root/form-Element
  71.             these.id = "element_root";
  72.  
  73.         } else {
  74.  
  75.             these.id = "element_" + these.raw.name;
  76.         }
  77.     },
  78.    
  79.     // update a node
  80.     update: function(raw) {
  81.  
  82.         var these = this;
  83.         Object.extend(these.raw, raw);
  84.  
  85.         // special cases, which could not be simple merged
  86.         these.raw.attributes = raw.attributes ? raw.attributes : undefined;
  87.         these.raw.options    = raw.options    ? raw.options    : undefined;
  88.         these.raw.restraints = raw.restraints ? raw.restraints : undefined;
  89.  
  90.     },
  91.  
  92. });
  93.  
  94. // FormEditor for FormFu-templates
  95. var FormEditor = Class.create({
  96.  
  97.     // List of elements which are selectable and there possible attributes
  98.     types: {
  99.  
  100.         'Text' : { type: 'Text', description: 'Text input field', 'attributes': ['size','width','title'] },
  101.         'Checkbox' : { type: 'Text', description: 'Single Checkbox', 'attributes': ['size','width','title'] },
  102.         'Password' : { type: 'Password', description: 'Password field', 'attributes': ['size','width','title'] },
  103.         'Textarea' : { type: 'Textarea', description: 'Textarea', 'attributes': ['size','width','title'] },
  104.         'Submit': { type: 'Submit', description: 'Submit Button', 'attributes': ['size','width','title'], 'removes': ['constraints'] },
  105.         'Block':  { type: 'Block',  description: 'Text paragraph', 'content': true, 'attributes': ['size','width','title'], 'removes': ['constraints','value','label']  },
  106.         'Hr': { type: 'Hr',     description: 'Horizontal ruler', 'removes': ['constraints','label','value','name'], 'attributes': ['width'] },
  107.         'Select': { type: 'Select', description: 'Select field', 'label': false,  'options': true, 'attributes': ['size','width','title'] },
  108.         'Webdisk': { type: 'Webdisk', description: 'Webdisk-Dialog', 'kind': true, 'attributes': ['size','width','title']  }
  109.      },
  110.  
  111.     // List of constraints which are selectable
  112.     constraints: {
  113.         'Required' : { type: 'Required',  description: 'Input required', 'configs': ['message'] },
  114.         'Number'   : { type: 'Number',    description: 'Number required', 'configs': ['message'] },
  115.         'Regex'    : { type: 'Regex',     description: 'Regex validation', 'configs': ['regex','message'] },
  116.         'MinLength': { type: 'MinLength', description: 'Minimal length', 'configs': ['min', 'message' ] },
  117.         'Length'   : { type: 'Length',    description: 'Min/Max length', 'configs': ['min', 'max', 'message' ] },
  118.         'Equal'    : { type: 'Equal',     description: 'Equal required', 'configs': ['others','message'] },
  119.         'Range'    : { type: 'Range',     description: 'Number in Range', 'configs': [ 'min','max','message'] }
  120.     },
  121.  
  122.     // Initialize and render tree
  123.     initialize: function(form, options) {
  124.  
  125.         var these = this;
  126.        
  127.         these.form = form;
  128.  
  129.         // initalize options
  130.         these.container = options.container;
  131.         these.saver     = options.saver;
  132.         these.previewer = options.previewer;
  133.         these.renderer  = options.renderer;
  134.         these.elements  = $H();
  135.         these.nodelist  = $H();
  136.         these.token     = options.token;
  137.         these.formfile  = options.formfile;
  138.  
  139.         these.y2j       = options.y2j;
  140.         these.j2y       = options.j2y;
  141.  
  142.         these.tree = options.inittree;
  143.  
  144.         these.form.observe('submit', function(e) { Event.stop(e); these.preview() } );
  145.  
  146.         if (options.undo_button) {
  147.             these.undo_button = options.undo_button;
  148.             these.undo_button.disabled = true;
  149.             these.undo_button.observe('click', function(e) { these.undo() } );
  150.        
  151.         }
  152.  
  153.         if (options.redo_button ) {
  154.             these.redo_button = options.redo_button;
  155.             these.redo_button.disabled = true;
  156.             these.redo_button.observe('click', function(e) { these.redo() } );
  157.         }
  158.  
  159.         // render the tree
  160.         these.rendertree();
  161.  
  162.         // history
  163.         these.history_redo = [ ];
  164.         these.history_undo = [ ];
  165.     },
  166.  
  167.     preview: function() {
  168.  
  169.         var these = this;
  170.  
  171.         var parameters = {
  172.             __json: Object.toJSON(these.serialize()),
  173.             __form: these.formfile
  174.         };
  175.  
  176.         parameters = $H(parameters).merge( these.form.serialize(true) );
  177.  
  178.         new Ajax.Request( these.previewer,
  179.             {
  180.                 method:'post',
  181.                 parameters: parameters,
  182.                 onSuccess: function(transport){
  183.  
  184.                     errormsg();
  185.                     infomsg("PReview successfull");
  186.                     these.form.replace(transport.responseText );                    
  187.                     these.form = $('previewForm');
  188.                     these.form.observe('submit', function(e) { Event.stop(e); these.preview()  } );                                
  189.                     these.rendertree();    
  190.                 },
  191.  
  192.                 onFailure: function(transport){
  193.            
  194.                     infomsg();                
  195.                     errormsg(transport.responseText);                                                
  196.                 }
  197.             }          
  198.         );
  199.  
  200.     },
  201.        
  202.     parseform: function(element) {
  203.    
  204.         var these = this;
  205.        
  206.         return these.traverseform(element, function(keyname,ele) {
  207.                
  208.             these.elements.set( keyname, ele );
  209.  
  210.         });
  211.     },
  212.  
  213.     // Traverseform and execute callback for every element found
  214.     traverseform: function(element,cb) {
  215.  
  216.         var these = this;
  217.  
  218.         var childs = element.childElements();
  219.    
  220.         var dataset =  element.getDataset();
  221.  
  222.         if (dataset.feName || dataset['fe-name'] ) {
  223.            
  224.             var fename = dataset.feName || dataset['fe-name'] ;
  225.  
  226.             // Exec Callback
  227.             cb(fename, element);
  228.         }
  229.  
  230.         childs.each( function(ele, idx) {
  231.  
  232.             these.traverseform(ele,cb);
  233.  
  234.         });
  235.     },
  236.  
  237.     store: function() {
  238.        
  239.         var these = this;
  240.        
  241.         new Ajax.Request(these.saver, {
  242.  
  243.             'method': 'post',
  244.             'asynchronous': false,    
  245.             'parameters': { '__form': these.formfile, '__json': Object.toJSON(these.serialize()), '_token': these.token },
  246.  
  247.             'onSuccess': function(transport) {
  248.  
  249.                 errormsg();
  250.                 infomsg(transport.responseText);
  251.  
  252.             },
  253.             'onFailure': function(transport){
  254.                
  255.                 infomsg();
  256.                 errormsg(transport.responseText);
  257.             }
  258.         });
  259.     },
  260.    
  261.     // Create json
  262.     serialize: function() {
  263.  
  264.         var these = this;
  265.        
  266.         var ds      = { elements: [] };
  267.         var eles    = {};
  268.         var parents = {};
  269.  
  270.         these.traverseform(these.form, function(keyname,ele) {
  271.                
  272.             var node = ele.retrieve('object');
  273.    
  274.             if ( node ) {
  275.  
  276.                 parents[node.raw.name] = node.raw;
  277.    
  278.                 if ( node.pt == false ) {
  279.  
  280.                     ds = node.raw;
  281.                     ds.elements = [];
  282.  
  283.                 } else {
  284.        
  285.                     var par = parents[node.pt];
  286.                     if (!par.elements) { par.elements = [] };
  287.                     par.elements.push(node.raw);
  288.  
  289.                 }
  290.                
  291.             }
  292.  
  293.         });
  294.  
  295.         return ds;
  296.     },
  297.  
  298.     // Toolbar, Add, remove and sort elements
  299.     showtoolbar: function(ele) {
  300.  
  301.         var these = this;
  302.    
  303.         ele.setStyle( { 'position':'relative' });
  304.        
  305.         var old = ele.down('.form_editor_toolbar');
  306.         if ( old ) { old.remove() };
  307.  
  308.         var node = ele.retrieve('object');
  309.    
  310.         // build fresh
  311.         var toolbar = new Element('div', { 'class': 'form_editor_toolbar' });
  312.         var a_add    = new Element('a', { 'class': 'form_editor_toolbar_add' }).update('add');
  313.         var a_delete = new Element('a', { 'class': 'form_editor_toolbar_delete' }).update('delete');
  314.         var a_edit   = new Element('a', { 'class': 'form_editor_toolbar_edit' }).update('edit');
  315.         var a_up     = new Element('a', { 'class': 'form_editor_toolbar_up' }).update('up');
  316.         var a_down   = new Element('a', { 'class': 'form_editor_toolbar_down'}).update('down');
  317.  
  318.         toolbar.insert(a_add);
  319.         if ( node.pt ) {
  320.             toolbar.insert(a_edit);
  321.             toolbar.insert(a_up);
  322.             toolbar.insert(a_down);
  323.             toolbar.insert(a_delete)
  324.         }
  325.  
  326.         ele.insert(toolbar);
  327.  
  328.         a_edit.observe('click', function(event,element) { these.edit_element(ele) });
  329.         a_add.observe('click', function(event,element) { these.add_element(ele) });
  330.         a_delete.observe('click', function(event,element) { these.delete_element(ele); });
  331.         a_up.observe('click', function(event,element) { these.up_element(ele) });
  332.         a_down.observe('click', function(event,element) { these.down_element(ele); });
  333.      },
  334.  
  335.     // edit element dialog
  336.     edit_element: function(ele) {
  337.  
  338.         var these = this;
  339.  
  340.         var cb = function(ele,node,raw) {
  341.  
  342.             these.undopoint();
  343.  
  344.             node.update( raw );
  345.      
  346.             // Render HTML on the serverside
  347.             new Ajax.Request(these.renderer, {
  348.  
  349.                 'method': 'post',
  350.                 'asynchronous': false,    
  351.                 'parameters': { 'json': Object.toJSON(node.raw) },
  352.  
  353.                 'onSuccess': function(response) {
  354.                
  355.                     var ans = response.responseJSON;
  356.                     var htmlcode = ans.container;
  357.                     ele.replace( htmlcode);
  358.                     these.rendertree();
  359.                  },
  360.                 'onFailure': function() {
  361.                     alert("Could not convert");
  362.                 }
  363.             });
  364.  
  365.            these.rendertree();
  366.         };
  367.  
  368.         var node = ele.retrieve('object');
  369.  
  370.         return this._dialog_element('edit', node.html,node, "Configure field", "Update", cb )
  371.  
  372.     },
  373.  
  374.     // private dialog window
  375.     _dialog_element: function(mode, ele, node, dialog_title, button_title, callback, newtype) {
  376.  
  377.         var these = this;
  378.  
  379.         var current = (mode == 'edit') ? node : { raw : {}};
  380.         var type    = (mode == 'edit') ? node.raw.type : newtype ;
  381.      
  382.         var stype = these.types[type];
  383.  
  384.         if ( stype ) {
  385.  
  386.                
  387.             // Ask for Config
  388.             var editbox = new Element('ul', { 'class': 'form_editor_dialog' });
  389.  
  390.             var title = new Element('li', { 'class': 'boxheader'}).update(dialog_title);
  391.             editbox.insert(title);
  392.    
  393.             var removes = these.types[type].removes || [];
  394.  
  395.             if (removes.indexOf('name') == -1 ) {
  396.  
  397.                 var li_name = new Element('li');
  398.                 var label_name = new Element('label').update('Name (Variable)');
  399.                 var block_name = new Element('div', { 'class': 'block' });
  400.                 var error_name = new Element('span', { 'class': 'fielderror' }) ;
  401.                 var field_name = new Element('input', { 'type': 'text', 'name': 'base_name', 'value': ( current.raw.name || "" ) });
  402.  
  403.                 li_name.insert(label_name);
  404.                 block_name.insert(error_name);
  405.                 block_name.insert(field_name);
  406.                 li_name.insert(block_name);
  407.                 editbox.insert(li_name);
  408.                
  409.             }
  410.  
  411.             if ( removes.indexOf('label') == -1 ) {
  412.  
  413.                 var li_label = new Element('li');
  414.                 var label_label = new Element('label').update("Label");
  415.                 var block_label = new Element('div', { 'class': 'block' });
  416.                 var error_label = new Element('span', { 'class': 'fielderror' });
  417.                 var field_label = new Element('input', { 'type': 'text', 'name': 'base_label', 'value': ( current.raw.label || "" ) });
  418.                 var xml_label   = new Element('input', { 'type': 'checkbox', 'name': 'check_xml_label'  });
  419.                 var xml_extra   = new Element('small', { }).update('XML');
  420.  
  421.                 // Handle XML content
  422.                 if ( current.raw.label_xml && !current.raw.label ) {
  423.  
  424.                     xml_label.checked = true;
  425.                     var label_value = current.raw.label_xml;
  426.                     label_value.replace(/"/,"\"");                  
  427.                     field_label.value = label_value;
  428.                 }
  429.  
  430.                 li_label.insert(label_label);
  431.                 block_label.insert(error_label);
  432.                 block_label.insert(field_label);
  433.                 block_label.insert(xml_label);
  434.                 block_label.insert(xml_extra);
  435.                 li_label.insert(block_label);
  436.                 editbox.insert(li_label);
  437.  
  438.             }
  439.  
  440.  
  441.             if ( type == 'Block' ) {
  442.                
  443.                 var li_content = new Element('li');
  444.                 var content_content = new Element('label').update("Content");
  445.                 var block_content = new Element('div', { 'class': 'block' });
  446.                 var error_content = new Element('span', { 'class': 'fielderror' });
  447.                 var field_content = new Element('textarea', { 'type': 'text', 'name': 'base_content' });
  448.  
  449.                 var xml_content   = new Element('input', { 'type': 'checkbox', 'name': 'check_xml_content'  });
  450.                 var xml_extra   = new Element('small', { }).update('XML');
  451.  
  452.                 // Handle XML content
  453.                 if ( current.raw.content_xml && !current.raw.content ) {
  454.  
  455.                     xml_content.checked = true;
  456.                     var content_value = current.raw.content_xml;
  457.                     content_value.replace(/"/,"\"");                  
  458.                     field_content.value = content_value;
  459.                
  460.                 } else {
  461.  
  462.                     field_content.value = content_value;
  463.    
  464.                 }
  465.  
  466.                 li_content.insert(content_content);
  467.                 block_content.insert(error_content);
  468.                 block_content.insert(field_content);
  469.                 block_content.insert(xml_content);
  470.                 block_content.insert(xml_extra);
  471.                 li_content.insert(block_content);
  472.                 editbox.insert(li_content);
  473.  
  474.             }        
  475.  
  476.  
  477.             if ( removes.indexOf('value') == -1 ) {
  478.  
  479.                 var li_value = new Element('li');
  480.                 var label_value = new Element('label').update("Value (Default)");
  481.                 var block_value = new Element('div', { 'class': 'block' });
  482.                 var error_value = new Element('span', { 'class': 'fielderror' });
  483.                 var field_value = new Element('input', { 'type': 'text', 'name': 'base_value', 'value': ( current.raw.value || "" ) });
  484.  
  485.                 li_value.insert(label_value);
  486.                 block_value.insert(error_value);
  487.                 block_value.insert(field_value);
  488.                 li_value.insert(block_value);
  489.                 editbox.insert(li_value);
  490.  
  491.             }
  492.  
  493.             var options_blocks = [];  
  494.            
  495.             if ( these.types[type] && these.types[type].options ) {
  496.  
  497.                 var li_option = new Element('li');
  498.                 var label_option = new Element('label').update("Options");
  499.                 var block_option = new Element('div', { 'class': 'block' });
  500.                 var error_option = new Element('span', { 'class': 'fielderror' });
  501.  
  502.                 var add_option_cb = function(item,container) {
  503.  
  504.                     var options_key   = new Element('input', { 'type': 'text', 'value':  ( item[0] || "" ) });
  505.                     var options_option = new Element('input', { 'type': 'text', 'value': ( item[1] || "" ) });
  506.                     var options_drop   = new Element('a').update("☒ ");
  507.  
  508.                     var options_set =  [ options_key, options_option ];
  509.  
  510.                     options_blocks.push(options_set);
  511.                     container.insert(options_key);
  512.                     container.insert(options_option);
  513.                     container.insert(options_drop);
  514.  
  515.                     options_drop.on('click', function() {
  516.  
  517.                         options_key.remove();
  518.                         options_option.remove();
  519.                         options_drop.remove();
  520.                         options_set = [];
  521.                    
  522.                     });
  523.    
  524.                 };
  525.  
  526.                 if ( current.raw && current.raw.options) {
  527.                 // Loop over every option
  528.                 current.raw.options.each( function(item,idx) {
  529.                         add_option_cb(item,block_option);
  530.                 });
  531.                 }
  532.  
  533.                 li_option.insert(label_option);
  534.                 block_option.insert(error_option);
  535.                 li_option.insert(block_option);
  536.            
  537.                 var add_option = new Element('a').update("Add option");
  538.  
  539.                 add_option.on('click', function() {
  540.  
  541.                     add_option.remove();
  542.                     add_option_cb([],block_option);
  543.                     block_option.insert(add_option);
  544.                 });
  545.  
  546.                 block_option.insert(add_option);
  547.                 editbox.insert(li_option);
  548.  
  549.             }
  550.  
  551.             var attribute_sets = [];
  552.            
  553.  
  554.             if (these.types[type] && these.types[type].attributes && these.types[type].attributes.length > 0) {
  555.  
  556.                 var li_attribute = new Element('li');
  557.                 var label_attribute = new Element('label').update("Attributes");
  558.                 var block_attribute = new Element('div', { 'class': 'block' });
  559.                 var error_attribute = new Element('span', { 'class': 'fielderror' });
  560.  
  561.                 var attributes = current.raw.attributes;
  562.            
  563.                 var add_attribute_cb = function(key,item,container, before) {
  564.  
  565.                     var attribute_key   = new Element('span', { 'class': 'attribute_title' } ).update(key);
  566.                     var attribute_value = new Element('input', { 'type': 'text', 'value': item });
  567.                     var attribute_drop  = new Element('a').update("☒ ");
  568.                     var attribute_next  = new Element('br');
  569.                    
  570.                     var attribute_set = [attribute_key, attribute_value, key];
  571.  
  572.                     attribute_sets.push(attribute_set);
  573.                    
  574.                     if ( before ) {
  575.  
  576.                         before.insert( { 'before': attribute_key });
  577.                         before.insert( { 'before': attribute_value });
  578.                         before.insert( { 'before': attribute_drop });
  579.                         before.insert( { 'before': attribute_next });
  580.    
  581.                     } else {
  582.  
  583.                         container.insert(attribute_key);
  584.                         container.insert(attribute_value);
  585.                         container.insert(attribute_drop);
  586.                         container.insert(attribute_next);
  587.                     }
  588.  
  589.                     attribute_drop.on('click', function() {
  590.                         attribute_key.remove();
  591.                         attribute_value.remove();
  592.                         attribute_drop.remove();
  593.                         attribute_next.remove();
  594.                         attribute_sets = attribute_sets.filter( function(it) { it[2] != key } );
  595.                     });
  596.    
  597.                 };
  598.  
  599.                 // Loop over every option
  600.                 for ( var key in attributes ) {
  601.                     var item = attributes[key];
  602.                     add_attribute_cb(key,item,block_attribute);
  603.                 };
  604.            
  605.                 var add_select = new Element('select', { 'name': 'attribute_select', 'id': 'attribute_select' } );
  606.  
  607.                 these.types[type].attributes.each( function(item,idx) {
  608.                     var add_option = new Element('option', { 'value': item }).update(item);
  609.                     add_select.insert(add_option);
  610.                 });
  611.            
  612.                 var add_attribute = new Element('a').update(" Add attribute");
  613.  
  614.                 add_attribute.on('click', function() {
  615.                     var attribute_type = add_select.getValue();
  616.                     add_attribute_cb(attribute_type,false, block_attribute, add_select );
  617.                 });
  618.  
  619.                 block_attribute.insert(add_select);
  620.                 block_attribute.insert(add_attribute);
  621.                 li_attribute.insert(label_attribute);
  622.                 block_attribute.insert(error_attribute);
  623.                 li_attribute.insert(block_attribute);
  624.                 editbox.insert(li_attribute);
  625.             }
  626.  
  627.             var attribute_xml_sets = [];
  628.  
  629.             if (these.types[type] && these.types[type].attributes && these.types[type].attributes.length > 0) {
  630.  
  631.                 var li_attribute_xml = new Element('li');
  632.                 var label_attribute_xml = new Element('label').update("Attributes XML");
  633.                 var block_attribute_xml = new Element('div', { 'class': 'block' });
  634.                 var error_attribute_xml = new Element('span', { 'class': 'fielderror' });
  635.  
  636.                 var attribute_xmls = current.raw.attributes_xml;
  637.            
  638.                 var add_attribute_xml_cb = function(key,item,container, before) {
  639.  
  640.                     if ( item ) {  item.replace(/"/, "\""); }
  641.  
  642.                     var attribute_xml_key   = new Element('span', { 'class': 'attribute_title' } ).update(key);
  643.                     var attribute_xml_value = new Element('input', { 'type': 'text', 'value': item });
  644.                     var attribute_xml_drop  = new Element('a').update("☒ ");
  645.                     var attribute_xml_next  = new Element('br');
  646.                    
  647.                     var attribute_xml_set = [attribute_xml_key, attribute_xml_value, key];
  648.  
  649.                     attribute_xml_sets.push(attribute_xml_set);
  650.                    
  651.                     if ( before ) {
  652.  
  653.                         before.insert( { 'before': attribute_xml_key });
  654.                         before.insert( { 'before': attribute_xml_value });
  655.                         before.insert( { 'before': attribute_xml_drop });
  656.                         before.insert( { 'before': attribute_xml_next });
  657.    
  658.                     } else {
  659.  
  660.                         container.insert(attribute_xml_key);
  661.                         container.insert(attribute_xml_value);
  662.                         container.insert(attribute_xml_drop);
  663.                         container.insert(attribute_xml_next);
  664.                     }
  665.  
  666.                     attribute_xml_drop.on('click', function() {
  667.                         attribute_xml_key.remove();
  668.                         attribute_xml_value.remove();
  669.                         attribute_xml_drop.remove();
  670.                         attribute_xml_next.remove();
  671.                         attribute_xml_sets = attribute_xml_sets.filter( function(it) { it[2] != key } );
  672.                     });
  673.    
  674.                 };
  675.  
  676.                 // Loop over every option
  677.                 for ( var key in attribute_xmls ) {
  678.                     var item = attribute_xmls[key];
  679.                     add_attribute_xml_cb(key,item,block_attribute_xml);
  680.                 };
  681.            
  682.                 var add_select_xml = new Element('select', { 'name': 'attribute_xml_select', 'id': 'attribute_xml_select' } );
  683.  
  684.                 these.types[type].attributes.each( function(item,idx) {
  685.                     var add_option = new Element('option', { 'value': item }).update(item);
  686.                     add_select_xml.insert(add_option);
  687.                 });
  688.            
  689.                 var add_attribute_xml = new Element('a').update(" Add attribute (XML, no escaping)");
  690.  
  691.                 add_attribute_xml.on('click', function() {
  692.                     var attribute_xml_type = add_select_xml.getValue();
  693.                     add_attribute_xml_cb(attribute_xml_type,false, block_attribute_xml, add_select_xml );
  694.                 });
  695.  
  696.                 block_attribute_xml.insert(add_select_xml);
  697.                 block_attribute_xml.insert(add_attribute_xml);
  698.                 li_attribute_xml.insert(label_attribute_xml);
  699.                 block_attribute_xml.insert(error_attribute_xml);
  700.                 li_attribute_xml.insert(block_attribute_xml);
  701.                 editbox.insert(li_attribute_xml);
  702.             }
  703.    
  704.        
  705.             if ( removes.indexOf('constraints') == -1 ) {
  706.    
  707.                 var constraint_sets = [];
  708.  
  709.                 var li_constraint = new Element('li');
  710.                 var label_constraint = new Element('label').update("Constraints");
  711.                 var block_constraint = new Element('div', { 'class': 'block' });
  712.                 var error_constraint = new Element('span', { 'class': 'fielderror' });
  713.  
  714.                 var constraints = current.raw.constraints;
  715.            
  716.                 var add_constraint_cb = function(key,item,container, before) {
  717.  
  718.                     var build = these.constraints[key];
  719.  
  720.                     if (!build) {
  721.  
  722.                         alert("Error please add " + key + "to the list of constraints");
  723.  
  724.                     }
  725.  
  726.                     var constraint_key   = new Element('span',{'class': 'contraint_type' } ).update(key);
  727.                
  728.                     var constraint_config_input = {};
  729.  
  730.                     $A(build.configs).each( function(citem,idx) {
  731.            
  732.                         var clabel = new Element('span', { 'class':'constraint_title' }).update(citem);
  733.                         var cinput = new Element('input', { 'type': 'text', 'value': (item[citem] || "" ) });
  734.                         var cnext  = new Element('br');
  735.                         constraint_config_input[citem] = [ clabel, cinput, cnext ] ;
  736.                     });
  737.            
  738.                     var constraint_drop  = new Element('a').update("☒ ");
  739.                     var constraint_next  = new Element('br');
  740.                    
  741.                     constraint_sets.push([constraint_key, constraint_config_input,key]);
  742.                    
  743.                     if ( before ) {
  744.  
  745.                         before.insert( { 'before': constraint_key });
  746.                         $H(constraint_config_input).each( function(item) {
  747.                             before.insert( { 'before': item.value[2] });
  748.                             before.insert( { 'before': item.value[0] });
  749.                             before.insert( { 'before': item.value[1] });
  750.                         });
  751.  
  752.                         before.insert( { 'before': constraint_drop });
  753.                         before.insert( { 'before': constraint_next });
  754.  
  755.                     } else {
  756.  
  757.  
  758.                         container.insert(constraint_key);
  759.                         $H(constraint_config_input).each( function(item) {
  760.                             container.insert(item.value[2]);
  761.                             container.insert(item.value[0]);
  762.                             container.insert(item.value[1]);
  763.                         });
  764.  
  765.                         container.insert(constraint_drop);
  766.                         container.insert(constraint_next);
  767.                     }
  768.  
  769.                     constraint_drop.on('click', function() {
  770.                         constraint_key.remove();
  771.                         constraint_drop.remove();
  772.                         constraint_next.remove();
  773.                            
  774.                         $H(constraint_config_input).each( function(item) {
  775.                             item.value[0].remove();
  776.                             item.value[1].remove();
  777.                             item.value[2].remove();
  778.                         });
  779.  
  780.                         constraint_sets = constraint_sets.filter( function(it) { it[3] != item.key } );
  781.                     });
  782.  
  783.                 };
  784.  
  785.                 // Loop over every constraint
  786.                 $A(constraints).each( function(item,idx) {
  787.  
  788.                     if (Object.isString(item)) {
  789.                         var type = item;
  790.                         add_constraint_cb(type,item,block_constraint);
  791.                     } else {
  792.                         add_constraint_cb(item.type,item,block_constraint);
  793.                     }
  794.                 });
  795.        
  796.                 var add_c_select = new Element('select', { 'name': 'constraint_select', 'id': 'constraint_select' } );
  797.  
  798.                 $H(these.constraints).each( function(item,idx) {
  799.                     var add_option = new Element('option', { 'value': item.key }).update(item.key);
  800.                     add_c_select.insert(add_option);
  801.                 });
  802.                
  803.                 var add_constraint = new Element('a').update("Add constraint");
  804.  
  805.                 add_constraint.on('click', function() {
  806.                     var constraint_type = add_c_select.getValue();
  807.                     add_constraint_cb(constraint_type,false, block_constraint, add_c_select );
  808.                 });
  809.  
  810.                 block_constraint.insert(add_c_select);
  811.                 block_constraint.insert(add_constraint);
  812.                 li_constraint.insert(label_constraint);
  813.                 block_constraint.insert(error_constraint);
  814.                 li_constraint.insert(block_constraint);
  815.                 editbox.insert(li_constraint);
  816.        
  817.             }
  818.  
  819.             var last = new Element('div');
  820.             var submit = new Element('button', { 'type': 'button' }).update(button_title);
  821.             var cancel = new Element('a', { 'style': 'color: #900' }).update("cancel");
  822.             cancel.on('click', function(event) { editbox.remove() });
  823.             last.insert(submit);
  824.             last.insert(cancel);
  825.  
  826.             var error_block = false;
  827.  
  828.             submit.on('click', function(event) {
  829.            
  830.                 var errors = 0;
  831.                 if ( error_block ) { error_block.remove(); }
  832.                
  833.                
  834.                 var raw = {};
  835.  
  836.            
  837.  
  838.                 if (removes.indexOf('name') == -1 ) {
  839.  
  840.                     error_name.update("");
  841.                     var value_name  = field_name.getValue();
  842.                     raw.name    = value_name;
  843.                     if (!value_name)  { error_name.update("Please add a unique variable name"); errors++; };
  844.                     if ( these.checkexistname( value_name, node.raw.name ) ) { error_name.update("Please choose a other name, name exists"); errors++ };
  845.                 }
  846.            
  847.                 if (removes.indexOf('label') == -1 ) {
  848.  
  849.                     error_label.update("");
  850.                     var value_label = field_label.getValue();
  851.  
  852.                     if ( xml_label.checked == true ) {
  853.                    
  854.                         raw.label_xml   = value_label;
  855.                         raw.label       = undefined;
  856.  
  857.                     } else {
  858.  
  859.                         raw.label  = value_label;
  860.                         raw.label_xml  = undefined;
  861.  
  862.                     }
  863.                    
  864.                     if (!value_label) { error_label.update("Pease add a label"); errors++ };
  865.                 }            
  866.  
  867.  
  868.                 if ( type == 'Block' ) {
  869.  
  870.                     error_content.update("");
  871.                     var value_label = field_content.getValue();
  872.  
  873.                     if ( xml_content.checked == true ) {
  874.                    
  875.                         raw.content_xml   = value_label;
  876.                         raw.content       = undefined;
  877.  
  878.                     } else {
  879.  
  880.                         raw.content  = value_label;
  881.                         raw.content_xml  = undefined;
  882.  
  883.                     }
  884.                    
  885.                 }  
  886.    
  887.                 if (removes.indexOf('value') == -1 ) {
  888.  
  889.                     error_value.update("");
  890.                     var value_value = field_value.getValue();
  891.                     raw.value   = value_value;
  892.                 }          
  893.  
  894.            
  895.                 // options for select
  896.                 options_blocks.each( function(item,idx) {
  897.  
  898.                     if ( idx == 0) {
  899.                         // Initialize options      
  900.                         raw.options = $A([]);
  901.                     }
  902.  
  903.                     if ( item.length == 2 ) {
  904.  
  905.                         var option_key   = item[0];
  906.                         var option_value = item[1];
  907.                            
  908.                         var option_key_value   = option_key.getValue();
  909.                         var option_value_value = option_value.getValue();
  910.  
  911.                         if ( idx == 0 || ( option_key_value && option_value_value)) {
  912.                             raw.options.push( [ option_key_value, option_value_value ] ) ;
  913.                         }
  914.                     }
  915.                 });
  916.  
  917.            
  918.                 if ( removes.indexOf('constraints') == -1 ) {
  919.  
  920.                     raw.constraints = [];
  921.  
  922.                     constraint_sets.each( function(item,idx) {
  923.  
  924.                         var constraint = { };
  925.  
  926.                         if ( $H(item[1]).keys().length ) {
  927.  
  928.                             constraint.type = item[2];
  929.  
  930.                             $H(item[1]).each(function(config) {
  931.                                 constraint[config.key] = config.value[1].getValue();
  932.                             });
  933.                         } else {
  934.  
  935.                             constraint = item[2];
  936.                         }
  937.  
  938.                         raw.constraints.push( constraint );
  939.                     });
  940.                 }
  941.  
  942.                 attribute_sets.each( function(item,idx) {
  943.            
  944.                     if ( idx == 0 ) {
  945.                         raw.attributes = {};
  946.                     }
  947.    
  948.                     if ( item.length == 3) {
  949.                            
  950.                         var attribute_key_field   = item[0];
  951.                         var attribute_value_field = item[1];
  952.                         var attribute_key   = attribute_key_field.innerHTML;
  953.                         var attribute_value = attribute_value_field.value;                
  954.  
  955.                         raw.attributes[attribute_key] =  attribute_value;
  956.                     }
  957.                 });
  958.  
  959.                 attribute_xml_sets.each( function(item,idx) {
  960.            
  961.                     if ( idx == 0 ) {
  962.                         raw.attributes_xml = {};
  963.                     }
  964.    
  965.                     if ( item.length == 3) {
  966.                            
  967.                         var attribute_key_field   = item[0];
  968.                         var attribute_value_field = item[1];
  969.                         var attribute_key   = attribute_key_field.innerHTML;
  970.                         var attribute_value = attribute_value_field.value;                
  971.  
  972.                         raw.attributes_xml[attribute_key] =  attribute_value;
  973.                     }
  974.                 });
  975.  
  976.  
  977.                 if ( errors  ) {
  978.  
  979.                     error_block = new Element('li', {  'style': 'color: #900; font-weight: bold' }).update('Please fill in as described');
  980.                     title.insert( { 'after': error_block });
  981.  
  982.                 } else {
  983.  
  984.                
  985.                     callback(ele,node,raw);
  986.                     editbox.remove();
  987.                 }
  988.                
  989.             });
  990.  
  991.             editbox.insert(last);
  992.    
  993.             ele.insert(editbox);
  994.        
  995.         } else {
  996.  
  997.             // unknown Type
  998.              // Ask for Config
  999.             var editbox = new Element('ul', { 'class': 'form_editor_dialog' });
  1000.  
  1001.             var title = new Element('li', { 'class': 'boxheader'}).update("Edit unknown type " + type);
  1002.             editbox.insert(title);
  1003.            
  1004.  
  1005.             ele.insert(editbox);
  1006.  
  1007.             var rawc = new Element('li');
  1008.  
  1009.             var rawbox = new Element('textarea', { 'style': 'width: 430px; height: 300px' });
  1010.  
  1011.             var jsonraw = Object.toJSON(node.raw);
  1012.            
  1013.             these.convert_j2y(jsonraw, function(yamlraw) {
  1014.  
  1015.                 rawbox.value = yamlraw;
  1016.                
  1017.                 rawc.insert(rawbox);
  1018.  
  1019.                 editbox.insert(rawc);
  1020.  
  1021.                 var last = new Element('li');
  1022.                 var submit = new Element('button', { 'type': 'button' }).update("Update");
  1023.                 var cancel = new Element('a', { 'style': 'color: #900' }).update("cancel");
  1024.                 cancel.on('click', function(event) { editbox.remove() });
  1025.                 last.insert(submit);
  1026.                 last.insert(cancel);
  1027.                 submit.on('click', function(event) {
  1028.  
  1029.                     var rawcode = rawbox.value;
  1030.  
  1031.                     these.convert_y2j(rawcode, function(raw) {
  1032.  
  1033.                         callback(ele,node,raw.evalJSON());
  1034.                         editbox.remove();
  1035.                     });
  1036.  
  1037.                 });
  1038.  
  1039.                 editbox.insert(last);
  1040.  
  1041.  
  1042.             });
  1043.  
  1044.         }
  1045.  
  1046.     },
  1047.  
  1048.     // add an element, select field type
  1049.     add_element: function(ele) {
  1050.  
  1051.         var these = this;      
  1052.        
  1053.         // Show possible types
  1054.         var selectbox = new Element('ul', { 'class': 'form_editor_dialog' });
  1055.  
  1056.         var title = new Element('li', { 'class': 'boxheader'}).update('1/2 Select field type');
  1057.        
  1058.         selectbox.insert(title);
  1059.  
  1060.         $H(these.types).each( function(pair) {
  1061.             var item = new Element('li', { 'class': 'type' }).update(pair.value.description);
  1062.             item.store(pair.value);
  1063.             selectbox.insert(item);
  1064.             item.on('click', function(event) { selectbox.remove(); these.askadd_element( ele, pair.value.type ) });
  1065.         });
  1066.  
  1067.         var cancel = new Element('li', { 'style': 'color: #900' }).update("cancel");
  1068.         cancel.on('click', function(event) { selectbox.remove() });
  1069.         selectbox.insert(cancel);
  1070.        
  1071.         ele.insert(selectbox);
  1072.     },
  1073.  
  1074.     // configure dialog for add a new field
  1075.     askadd_element: function(ele,type) {
  1076.  
  1077.         var these = this;
  1078.  
  1079.         var cb = function(ele,node,raw) {
  1080.            
  1081.             these.doadd_element(ele, Object.extend( raw, { type: type } ));
  1082.             these.rendertree();
  1083.         };
  1084.  
  1085.         return this._dialog_element('add', ele, { raw: {}}, "2/2 Configure field", "Add", cb, type )
  1086.  
  1087.     },
  1088.  
  1089.     // add the new Element
  1090.     doadd_element: function(ele, raw) {
  1091.  
  1092.         var these = this;
  1093.  
  1094.         // History
  1095.         these.undopoint();
  1096.  
  1097.         // Render HTML on the serverside
  1098.         new Ajax.Request(these.renderer, {
  1099.  
  1100.             'method': 'post',
  1101.             'asynchronous': false,    
  1102.             'parameters': { 'json': Object.toJSON(raw) },
  1103.  
  1104.             'onSuccess': function(response) {
  1105.                
  1106.                 var ans = response.responseJSON;
  1107.                 var htmlcode = ans.container;
  1108.  
  1109.                 var node = ele.retrieve('object')              
  1110.  
  1111.                 if ( node && node.pt ) {
  1112.                    
  1113.                     var newnode = new FormEditorNode(raw, htmlcode, these.nodelist.get(node.pt) );
  1114.                     these.nodelist.set(raw.name,newnode);
  1115.                     ele.insert( { after: htmlcode  } );
  1116.  
  1117.                 } else if ( node && !node.pt ) {
  1118.  
  1119.                     var fs = ele.select('fieldset');
  1120.                     var fsf = fs.reverse()[0];
  1121.                     fsf.insert( { 'top': htmlcode });
  1122.                     var newnode = new FormEditorNode(raw, htmlcode,node );
  1123.                     these.nodelist.set(raw.name,newnode);
  1124.  
  1125.                 } else {
  1126.  
  1127.                     ele.insert( htmlcode );
  1128.                     var newnode = new FormEditorNode(raw, htmlcode );
  1129.                     these.nodelist.set(raw.name,newnode);
  1130.                 }
  1131.  
  1132.                 these.rendertree();
  1133.              },
  1134.             'onFailure': function() {
  1135.                 alert("Could not convert");
  1136.             }
  1137.         });
  1138.  
  1139.    },
  1140.  
  1141.     _current: function() {
  1142.  
  1143.         var these = this;
  1144.         return  [ Object.toJSON(these.serialize()), these.form.innerHTML  ];
  1145.     },
  1146.  
  1147.  
  1148.     // Undo the last action
  1149.     undo: function() {
  1150.  
  1151.         var these = this;
  1152.  
  1153.         var set =  these.history_undo.pop();
  1154.  
  1155.         if ( set ) {
  1156.  
  1157.             these.history_redo.push(these._current());
  1158.             these.tree = set[0].evalJSON();
  1159.             these.form.update( set[1] );
  1160.             these.form.select('.form_editor_toolbar').map(Element.remove);
  1161.             these.form.select('.form_editor_dialog').map(Element.remove);
  1162.             these.rendertree();
  1163.         }
  1164.  
  1165.         if ( these.undo_button) {
  1166.             these.undo_button.disabled = these.history_undo.length ? false : true;
  1167.         }
  1168.  
  1169.         if ( these.redo_button) {
  1170.             these.redo_button.disabled = these.history_redo.length ? false : true;
  1171.         }
  1172.  
  1173.     },
  1174.     // create an undo point    
  1175.     undopoint: function() {
  1176.  
  1177.         var these = this;
  1178.  
  1179.         these.history_undo.push(these._current());
  1180.        
  1181.         if ( these.undo_button) {
  1182.             these.undo_button.disabled = these.history_undo.length ? false : true;
  1183.         }
  1184.  
  1185.         if ( these.redo_button) {
  1186.             these.redo_button.disabled = these.history_redo.length ? false : true;
  1187.         }
  1188.       },
  1189.  
  1190.     // redo the last action
  1191.     redo: function() {
  1192.  
  1193.         var these = this;
  1194.                
  1195.         var set =  these.history_redo.pop();
  1196.  
  1197.         if ( set ) {
  1198.  
  1199.             these.history_undo.push(these._current());
  1200.             these.tree = set[0].evalJSON();
  1201.             these.form.update( set[1] );
  1202.             these.form.select('.form_editor_toolbar').map(Element.remove);
  1203.             these.form.select('.form_editor_dialog').map(Element.remove);
  1204.             these.rendertree();
  1205.         }
  1206.  
  1207.         if ( this.undo_button) {
  1208.             this.undo_button.disabled = these.history_undo.length ? false : true;
  1209.         }
  1210.  
  1211.         if ( this.redo_button) {
  1212.             this.redo_button.disabled = these.history_redo.length ? false : true;
  1213.         }
  1214.    
  1215.     },
  1216.  
  1217.  
  1218.     // Validate name, check if there no other field with the same name
  1219.     checkexistname: function(name, old) {
  1220.  
  1221.         var these = this;
  1222.  
  1223.         var match = false;
  1224.  
  1225.         if ( name && old && name === old ) {
  1226.        
  1227.             return false;
  1228.         }
  1229.  
  1230.         return match;
  1231.     },
  1232.  
  1233.  
  1234.     // sort up, unless the ele is the first
  1235.     up_element: function(ele) {
  1236.  
  1237.         var these = this;
  1238.        
  1239.        // find previous element
  1240.         var prev_eles = ele.previousSiblings();
  1241.  
  1242.         if ( prev_eles.length > 0 ) {
  1243.  
  1244.             these.undopoint();
  1245.  
  1246.             var prev = prev_eles[0].remove();
  1247.             ele.insert( { after: prev });
  1248.         }
  1249.      },
  1250.  
  1251.     // sort down, unless the ele is the last
  1252.     down_element: function(ele) {
  1253.  
  1254.         var these = this;
  1255.  
  1256.         // find previous element
  1257.         var next_eles = ele.nextSiblings();
  1258.    
  1259.  
  1260.         if ( next_eles.length > 0 ) {
  1261.  
  1262.             these.undopoint();
  1263.  
  1264.             var next = next_eles[0].remove();
  1265.             ele.insert( { before: next });
  1266.         }
  1267.        
  1268.     },
  1269.  
  1270.     // delete the element
  1271.     delete_element: function(ele) {
  1272.  
  1273.         var these = this;
  1274.  
  1275.         // make History
  1276.         these.undopoint();
  1277.  
  1278.         // retrieve object from element
  1279.         var node = ele.retrieve('object');
  1280.  
  1281.         var key = node.raw.name;
  1282.  
  1283.         // Remove from list of elements
  1284.         these.elements.unset(key);
  1285.  
  1286.         // Remove form nodes  
  1287.         these.nodelist.unset(key);
  1288.  
  1289.         // Remove form html
  1290.         node.html.remove();
  1291.  
  1292.         // Remove node
  1293.  
  1294.         these.rendertree();
  1295.  
  1296.      },
  1297.  
  1298.     elementsselect: function() {
  1299.        
  1300.         var these = this;
  1301.         var elementselect = new Element('div', { 'class': 'form_editor_select_elements' });
  1302.     },
  1303.  
  1304.  
  1305.     // render the whole tree, cleanup the container
  1306.     rendertree: function() {
  1307.  
  1308.         var these = this;
  1309.        
  1310.         // Parse recursive
  1311.         these.parseform(these.form);
  1312.  
  1313.         if ( these.elements && these.elements.size() == 0 ) {
  1314.        
  1315.             // no elements given, inital add-button
  1316.             var toolbar = new Element('div', { 'class': 'form_editor_toolbar' });
  1317.             var a_add = new Element('a', { 'class': 'form_editor_toolbar_add' }).update('add');
  1318.  
  1319.  
  1320.             toolbar.insert(a_add);
  1321.  
  1322.             these.form.down('fieldset').setStyle({ 'position':'relative' });
  1323.             these.form.down('fieldset').insert(toolbar);
  1324.  
  1325.             a_add.observe('click', function(e) {
  1326.  
  1327.                 these.add_element(these.form.down('fieldset'));
  1328.  
  1329.             });
  1330.  
  1331.         }
  1332.  
  1333.         // start recursive build
  1334.         these.build(these.tree);  
  1335.  
  1336.         // combine HTML with nodes
  1337.         these.elements.each( function(item) {
  1338.  
  1339.             var ele     = item.value;
  1340.             var dataset = ele.getDataset();
  1341.             var fename = dataset['fe-name'] || dataset.feName;
  1342.             var node = these.nodelist.get(fename);
  1343.  
  1344.             if ( node ) {
  1345.            
  1346.                 ele.store('object', node );
  1347.                 node.html = ele;
  1348.                 these.showtoolbar(ele);
  1349.             }
  1350.  
  1351.         });
  1352.  
  1353.     },
  1354.  
  1355.     // build a node and subnodes
  1356.     build: function(raw,parentnode) {
  1357.    
  1358.         var these = this;
  1359.        
  1360.         var node = new FormEditorNode( raw, undefined, parentnode );
  1361.  
  1362.         // Set as root node    
  1363.         if (!parentnode) {
  1364.             these.root = node;
  1365.         }
  1366.  
  1367.         // Store nodes
  1368.         these.nodelist.set(node.raw.name, node);
  1369.  
  1370.         if ( raw.elements) {
  1371.             raw.elements.each( function(ele) { these.build(ele,node) });
  1372.         }
  1373.     },
  1374.  
  1375.     convert_y2j : function(yaml,cb) {
  1376.  
  1377.          var these = this;
  1378.  
  1379.          new Ajax.Request(these.y2j, {
  1380.  
  1381.             'method': 'post',
  1382.             'parameters': { 'yaml': yaml },
  1383.  
  1384.             'onSuccess': function(transport) {
  1385.  
  1386.                 errormsg();
  1387.                 cb( transport.responseText);
  1388.  
  1389.             },
  1390.             'onFailure': function(transport){
  1391.                
  1392.                 infomsg();
  1393.                 errormsg(transport.responseText);
  1394.                 return;
  1395.             }
  1396.         });
  1397.     },
  1398.    
  1399.     convert_j2y : function(json,cb) {
  1400.  
  1401.         var these = this;
  1402.  
  1403.          new Ajax.Request(these.j2y, {
  1404.  
  1405.             'method': 'post',
  1406.             'parameters': { 'json': json },
  1407.  
  1408.             'onSuccess': function(transport) {
  1409.  
  1410.                 errormsg();
  1411.                 cb( transport.responseText);
  1412.  
  1413.             },
  1414.             'onFailure': function(transport){
  1415.                
  1416.                 infomsg("Error");
  1417.                 errormsg(transport.responseText);
  1418.                 return;
  1419.             }
  1420.  
  1421.         });    
  1422.     }
  1423.  
  1424.    
  1425. });