Composite in Javascript

    本文从简的演示利用Composite Pattern来动态创建form,它支持保存和还原上次输入的数据。

    第一步,定义接口:

var Composite =  new Interface("Composite", ["add", "remove", "getChild"]);
var FormItem =  new Interface("FormItem", ["save", "restore", "getElement"]);

你懂的,这里是基于single responsibility rule将接口分为2个。


    然后,分别来实现2个接口了: 

var CompositeForm =  function (id, method, action) {
     this.formComponents = [];

     this.element = document.createElement("form");
     this.element.id = id;
     this.element.method = method || "post";
     this.element.action = action || "#";
};
CompositeForm.prototype = {
    add:  function (child) {
        Interface.ensureImplements(child, [Composite, FormItem]);
         this.formComponents.push(child);
         this.element.appendChild(child.getElement());
    },
    remove:  function (child) {
         for ( var i = 0; i <  this.formComponents.length; i++) {
             if ( this.formComponents[i] == child) {
                 this.formComponents.splice(i, 1);
                 this.element.removeChild(child.getElement());
                 break;
            }
        }
    },
    getChild:  function (i) {
         if (i >=  this.formComponents.length) {
             throw  new Error("i is out of range.");
        }
         return  this.fromComponents[i];
    },
    save:  function () {
         for (index  in formComponents) {
             this.formComponents[index].save();
        }
    },
    restore:  function () {
         for (index  in formComponents) {
             this.formComponents[index].resotre();
        }
    },
    getElement:  function () {
         return  this.element;
    }
};
CompositeForm.prototype.constructor = CompositeForm;

//  composite fieldset
var CompositeFieldset =  function (id, legendText) {
     this.components = {};

     this.element = document.createElement("fieldset");
     this.element.id = id;
     if (legendText) {
         this.legend = document.createElement("legend");
         this.legend.appendChild(document.createTextNode(legendText));
         this.element.appendChild( this.legend);
    }
};
CompositeFieldset.prototype = {
    add:  function (child) {
        Interface.ensureImplements(child, [Composite, FormItem]);
         this.components[child.getElement().id] = child;
         this.element.appendChild(child.getElement());
    },
    remove:  function (child) {
         delete  this.components[child.getElement().id];
         this.element.removeChild(child.getElement());
    },
    getChild:  function (id) {
         return  this.components[id];
    },
    save:  function () {
         for (index  in components) {
             if (components.hasOwnProperty(index)) {
                 this.fieldset[index].save();
            }
        }
    },
    restore:  function () {
         for (index  in components) {
             if (components.hasOwnProperty(index)) {
                 this.fieldset[index].resotre();
            }
        }
    },
    getElement:  function () {
         return  this.element;
    }
};
CompositeFieldset.prototype.constructor = CompositeFieldset;


//  field abstract class
var Field =  function (id) {
     this.element = document.createElement('div');
     this.element.id = id;
     this.element.className = 'input-field';
};
Field.prototype = {
    add:  function (child) {
    },
    remove:  function (i) {
    },
    getChild:  function (i) {
    },
    save:  function () {
        setCookie( this.id,  this.getValue());
    },
    resotre:  function () {
         var value = getCookie( this.id);
        setValue(value);
    },
    getElement:  function () {
         return  this.element;
    },
    getValue:  function () {
         throw  new Error("Unimplemented on the class Field.");
    },
    setValue:  function () {
         throw  new Error("Unimplemented on the class Field.");
    }
};
Field.prototype.constructor = Field;

//  input field class
var InputField =  function (id, label) {
     this.superClass.constructor.call( this, id);

     this.input = document.createElement('input');
     this.input.id = id + "_input";
     this.label = document.createElement('label');
     this.label.id = id + "_label";
     var labelTextNode = document.createTextNode(label);
     this.label.appendChild(labelTextNode);

     this.element.appendChild( this.label);
     this.element.appendChild( this.input);
};
extend(InputField, Field);
InputField.prototype.getValue =  function () {
     return  this.input.value;
};
InputField.prototype.getValue =  function (value) {
     this.input.value = value;
};

//  textarea field class
var TextAreaField =  function (id, label) {
     this.superClass.constructor.call( this, id);

     this.textArea = document.createElement('textarea');
     this.textArea.id = id + "_textarea";
     this.label = document.createElement('label');
     this.label.id = id + "_label";
     var labelTextNode = document.createTextNode(label);
     this.label.appendChild(labelTextNode);

     this.element.appendChild( this.label);
     this.element.appendChild( this.textArea);
};
extend(TextAreaField, Field);
TextAreaField.prototype.getValue =  function () {
     return  this.textArea.value;
};
TextAreaField.prototype.getValue =  function (value) {
     this.textArea.value = value;
};

//  select field class
var SelectField =  function (id, label, options) {
     this.superClass.constructor.call( this, id);

     this.select = document.createElement('select');
     this.select.id = id + "_select";
     for( var i = 0;i<options.length;i++){
         var option = document.createElement("option");
        option.text = options[i].text;
        option.value = options[i].value;
         try{
             this.select.add(option,  this.select.options[ null]);
        }
         catch(e){
             this.select.add(option,  null);
        }
    }
     this.label = document.createElement('label');
     this.label.id = id + "_label";
     var labelTextNode = document.createTextNode(label);
     this.label.appendChild(labelTextNode);

     this.element.appendChild( this.label);
     this.element.appendChild( this.select);
};
extend(SelectField, Field);
SelectField.prototype.getValue =  function () {
     return  this.select.options[ this.select.selectedIndex].value;
};
SelectField.prototype.getValue =  function (value) {
     for (index  in  this.select.options) {
         if ( this.select.options[index].value == value) {
             this.select.selectedIndex = index;
             break;
        }
    }
};

 

测试代码如下: 

     var  contactForm =  new  CompositeForm("contactForm", "post", "contact.php"); 
     var nameFieldset =  new CompositeFieldset('nameFieldset', "Name");
    nameFieldset.add( new InputField("firstName", "First Name"));
    nameFieldset.add( new InputField("lastName", "Last Name"));
    contactForm.add(nameFieldset);

     var addressFieldset =  new CompositeFieldset('addressFieldset', "Address");
    addressFieldset.add( new InputField("address", "Address"));
    addressFieldset.add( new SelectField("state", "State", [{"text": "Alabama", "value": "Alabama"}, {"text": "Seattle", "value": "Seattle"}]));
    addressFieldset.add( new InputField('zip', 'Zip'));    
    contactForm.add(addressFieldset);

    contactForm.add( new TextAreaField('comments', 'Comments'));

    body.appendChild(contactForm.getElement());
    addEvent(window, "load", contactForm.restore);
    addEvent(window, "unload", contactForm.save);

这里不再详细解释了,注意Field类是abstract的即可。 download

你可能感兴趣的:(JavaScript)