[JavaScript] Prototype Erweiterungen + Ajax.Upload

Dieses Thema im Forum "Webentwicklung" wurde erstellt von Murdoc, 24. Juli 2011 .

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen
?

Findet Ihr diese Erweiterungen nützlich?

  1. Ja, nutze das Script auch in meinen Projekt(en)

    3 Stimme(n)
    30,0%
  2. Ja, nutze das Script aber nicht sondern schau mir nur Sachen daraus ab

    1 Stimme(n)
    10,0%
  3. Nützlich ja, nutze aber ein anderes Framework

    4 Stimme(n)
    40,0%
  4. Javascript? Ich programmiere nur mit jQuery (PLONK)

    2 Stimme(n)
    20,0%
  5. Nein

    0 Stimme(n)
    0,0%
  1. #1 24. Juli 2011
    Prototype Erweiterungen + Ajax.Upload

    Ich hab eine Sammlung an Funktionen und Erweiterungen für Prototype erstellt, die ich die letzten Jahre immer wieder eingesetzt hab und nützlich finde.

    Folgendes wurde hinzugefügt:

    dom:loaded Support für die Funktion $()

    Man kann nun über die Funktion $() direkt einen Callback für den Event "dom:loaded" hinzufügen.

    Deklaration:
    Code:
    $(function callback) -> Event.Handler
    Beispiel:
    Code:
    $(function() { ... });
    Führt die Funktion im dom:loaded event aus.

    vergleichbar mit:
    Code:
    document.observe("dom:loaded", function() { ... });
    ----

    HTML Interpretation

    Die Funktion $() kann nun HTML interpretieren und gibt die erstellten Elemente zurück.

    Deklaration:
    Code:
    $(string html) -> Element
    Beispiel:
    Code:
    var em = $('<em>hallo welt</em>');
    interpretiert den übergebenen string als html-element und gib dieses zurück

    vergleichbar mit:
    Code:
    var em = new Element('em').insert('hallo welt');
    Info: leere tags sind auch möglich:
    Code:
    var em = $('<em />');
    Analog dazu ist es auch möglich Elemente zu erstellen:
    Code:
    var em = $('em', {});
    ----

    Elemente direkt an document.body anhängen

    Deklaration:
    Code:
    $.insert(string content) -> void
    $.insert(Element element) -> void
    Beispiel:
    Code:
    $.insert('<em>hallo welt</em>');
    Fügt <em>hallo welt</em> an das Ende von <body> hinzu. Sollte der Quelltext beim Aufruf der Funktion noch nicht komplett geladen sein, werden alle Elemente in einem Array gesammelt und erst bei dom:loaded hinzugefügt.

    vergleichbar mit:
    Code:
    $(document.body).insert('<em>hallo welt</em>');
    ----

    Skripte nachladen include/require

    Deklaration:
    Code:
    $.include(string src) -> void
    $.require(string src) -> void
    Code:
    $.include('beispiel.js');
    läd das "beispiel.js" nach

    Code:
    $.require('beispiel.js');
    läd ebenfalls "beispiel.js" nach, prüft aber zuvor ob es schon nachgeladen wurde

    ----

    Die bekannte Funktionalität bleibt erhalten.
    Code:
    var foo = $("foo"); // element mit der id "foo"
    var bar = $("foo", "bar"); // elemente mit der id "foo" und "bar"
    ----

    $$ gibt nun einen Wrapper zurück anstelle einer NodeList

    Es ist nun möglich ohne den Umweg über .invoke(...) Methoden der gefundenen Elemente auszuführen.

    Ohne Erweiterung:
    Code:
    $$('a.alert').invoke('observe', 'click', function(event) {
     event.stop();
     alert('geklickt!');
    });
    
    $$('div.hide-me').invoke('hide');
    Mit Erweiterung:
    Code:
    $$('a.alert').observe('click', function(event) {
     event.stop();
     alert('geklickt!');
    });
    
    $$('div.hide-me').hide();
    Achtung: Damit lassen sich nur Methoden die in Element.Methods definiert wurden aufrufen.

    $$("...").getAttribute() z.b. geht nicht! macht auch keinen sinn, weil keine werte zurückgegeben werden können.

    Bitte nicht verwechseln mit $$.first().

    ----

    $$.first Erweiterung

    Mit dieser Funktion ist es möglich nur den ersten Fund eines CSS-Selektors zu ermitteln.

    Deklaration:
    Code:
    $$.first(string selector) -> Element
    Beispiel:
    Code:
    var div = $$.first('div.content');
    sucht nach allen div's mit der Klasse "content" und gibt den ersten Fund zurück

    vergleichbar mit:
    Code:
    var div = $$('div.content')[0];
    ----

    Ajax.Upload Klasse

    Mit dieser Klasse ist es möglich Dateien über XMLHttpRequest2 hochzuladen.
    Im Grunde entspricht diese Klasse der Altbekannten Ajax.Request Klasse, führt aber zwei neue Callbacks ein:

    - onProgress()
    Wird gefeuert wenn eine Datei hochgeladen wird und es Daten zu verarbeiten gibt.

    - onUploaded()
    Wird gefeuert wenn der Upload abgeschlossen wurde.

    Beispiel:
    Code:
    var input = $$.first('#form input[type="file"]');
    
    new Ajax.Upload("upload.php", {
     method: "POST",
     upload: input.files[0],
    
     onProgress: function(data) {
     console.log("Fortschritt: " + ((data.loaded / data.total) * 100) + " %");
     },
    
     onUploaded: function() {
     console.log("Upload komplett");
     },
    
     onSuccess: function(res) {
     console.log("Abfrage erledigt");
     }
    });
    Ob man diese Funktion vorhanden ist kann man mittels der Eigenschaft
    Ajax.UPLOAD_SUPPORTED prüfen.

    Bzw.:
    Prototype.BrowserFeatures.XMLHttpRequest2
    Prototype.BrowserFeatures.FileAPI

    ----

    download:

    quelltext http://murdoc.eu/protoext/protoext.js
    minified: http://murdoc.eu/protoext/protoext.min.js
    minified + gzip: http://murdoc.eu/protoext/protoext.min.js.gz


    Weitere Vorschläge immer gern gesehen!

    Viel Spaß :)
     

  2. Anzeige
    Dealz: stark reduzierte Angebote finden.
  3. #2 13. August 2011
    AW: Prototype: Erweiterung der Funktionen $ und $$

    kleines update:

    - $$() gibt nun einen wrapper zurück anstelle einer nodelist.
    - Ajax.Upload support

    weiters dazu hab ich im startpost aktualisiert.
     
  4. #3 15. August 2011
    AW: Prototype: Erweiterung der Funktionen $ und $$

    Da keiner irgendwie Feedback gab mal ne Frage an euch:
    Interessiert das eigl. überhaupt jemanden?

    Oder denkt Ihr euch sowas wie "Jaja, der will doch nur Angeben pfft." :D

    Also nutzt jemand das Script oder blockier ich damit nur die erste Seite der Webmaster Forums? ^^

    Geplant war im übrigen noch Support für Websockets, Server Events und andere neue Sachen die bisher in Prototype noch fehlen, da seit nem guten Jahr kein Update mehr kam - und bis Prototype2 wird vermutlich auch kein neues Minor-Release mehr kommen.
     
  5. #4 15. August 2011
    AW: Prototype Erweiterungen + Ajax.Upload

    Interesse: Ja.

    Hab den Thread eben erst bemerkt. Liest sich sehr gut alles.Aber um es wirklich zu bewerten, muss man es halt testen. Werde das die Woche versuchen.
     
  6. #5 18. August 2011
    AW: Prototype Erweiterungen + Ajax.Upload

    Habe nun alles getestet.

    Funktioniert alles wie versprochen. Besonders der Ajax Upload ist elegant gelöst. Gefällt mir sehr gut. Besonders onProcess ist nützlich.

    Tolle Arbeit.
     
  7. #6 7. Oktober 2011
    AW: Prototype Erweiterungen + Ajax.Upload

    arbeite derzeit an einem form-validator mit benutzerdefinierten fehlermeldungen (HTML5 + fallback).

    Spoiler
    Code:
    Form.Validator = Class.create((function() {
     
     var USE_NATIVE_VALIDATOR = (function() {
     var form = document.createElement('form'),
     check = (typeof form.checkValidity == 'function');
     
     form = null;
     return check;
     })();
     
     var NO_PATTERN_ELEMENTS = ['select', 'check', 'radio', 'submit', 'button', 'image'],
     FORM_ELEMENT_SELECTOR = 'input:not([type="button"]):not([type="image"]):not([type="submit"]), select, textarea';
     
     /**
     * constructor
     *
     */
     function initialize(form, options) {
     this.form = form;
     
     // just references
     this.types = Form.Validator.Types;
     this.flags = Form.Validator.Flags;
     this.cntrs = Form.Validator.Constraints;
     
     this.options = Object.extend({
     // called when a field is invalid
     onInvalid: function() {},
     // called when validation is done and the form seems to be invalid
     onFailure: function() {},
     // called when the form seems to be valid
     onSuccess: function(form) { form.submit(); }
     }, options || {});
     
     if (USE_NATIVE_VALIDATOR) {
     // prepares the form and let the browser validate its values
     this.prepare();
     } else {
     // validates the the form on submit
     this.form.on("submit", this.validate.bind(this));
     }
     } 
     
     // private
     function _type(field) {
     var type = field.getAttribute('type');
     
     if (!type) {
     type = field.nodeName.toLowerCase();
     if (type === 'textarea')
     type = 'text';
     }
     
     switch (type) {
     case 'url':
     case 'email':
     case 'tel':
     case 'search':
     case 'password':
     case 'number':
     return 'text';
     
     case 'checkbox':
     return 'check';
     }
     
     return type;
     }
     
     function _value(field) {
     switch (_type(field)) {
     case 'text':
     return field.value.empty() ? false : field.value;
     
     case 'radio':
     case 'check':
     return field.checked;
     
     case 'select':
     if (field.selectedIndex === -1)
     return false;
     
     return field.options[field.selectedIndex].value;
     }
     
     return false;
     }
     
     /**
     * checks a field
     *
     * @param Element field
     * @param String type
     * @return Boolean
     */
     function check(field, type) {
     // grab pattern and test it
     return new RegExp(field.getAttribute("pattern") || this.types.get(type)).test(field.value);
     }
     
     /**
     * fetches an error-message
     *
     * @param Element field
     * @param String type
     * @param String format
     * @return String|undefined
     */
     function notice(field, type, format) {
     var message = this.cntrs.get(type)[format] || "undefined";
     
     if (USE_NATIVE_VALIDATOR)
     return message;
     
     // display an error-bubble :-)
     if (this.errors === 1)
     console.log("first error", field);
     
     console.log(message);
     }
     
     /**
     * prepares the form to be validated by the browser
     *
     * @void
     */
     function prepare() {
     // handle first-invalid event
     var handler = (function(event) {
     this.form.removeEventListener("invalid", handler, true);
     this.options.onFailure(this.form);
     }).bind(this);
     
     // handle invalid event for elements
     var invalid = (function(event) {
     var element = event.element();
     
     // handle element
     var name = element.nodeName.toLowerCase(),
     type = _type(element);
     
     var error;
     
     if (element.hasAttribute("required") && _value(element) === false) {
     // looks like "required" triggered this error
     error = 'required';
     } else if (NO_PATTERN_ELEMENTS.indexOf(type) == -1) {
     // must be an input element
     error = element.getAttribute("type");
     } else {
     // remove custom message
     element.setCustomValidity("");
     event.preventDefault();
     return; // done
     }
     
     ++this.errors;
     this.options.onInvalid(element, error, this.form);
     
     // add message
     element.setCustomValidity(this.notice(element, error, type));
     }).bind(this);
     
     this.form.addEventListener("invalid", handler, true);
     this.form.addEventListener("invalid", invalid, true);
     
     // submit -> valid
     this.form.observe("submit", function(event) { 
     event.stop();
     this.options.onSuccess();
     }.bind(this));
     }
     
     /**
     * validates the form
     *
     * @param Event event
     * @void
     */
     function validate(event) {
     event.stop();
     
     var trigger = event.element(), radios = [];
     
     if (trigger && ["input", "button"].indexOf(trigger.nodeName.toLowerCase())
     && trigger.hasAttribute("formnovalidate")) {
     this.options.onSuccess(this.form);
     return; // done
     }
     
     trigger = null;
     
     this.errors = 0;
     
     this.form.select(FORM_ELEMENT_SELECTOR).each(function(field) { 
     // fetch internal-type
     var internal_type = _type(field);
     
     // handle flags
     this.flags.each(function(flag) {
     // special case: radio
     if (internal_type === 'radio') {
     var name = field.getAttribute('name');
     if (radios.indexOf(name) > -1)
     return;
     
     radios.push(name);
     }
     
     if (field.hasAttribute(flag.key) && !flag.value(field, this.form)) {
     ++this.errors;
     this.notice(field, flag.key, internal_type, this.form);
     this.options.onInvalid(field, flag.key, this.form);
     throw $break;
     }
     }, this);
     
     // select-, check-, radio-fields and textareas are done at this point
     if (field.nodeName.toLowerCase() === 'textarea'
     || NO_PATTERN_ELEMENTS.indexOf(internal_type) > -1)
     return;
     
     // handle field-specific type/pattern attributes
     var type = field.getAttribute('type');
     
     if (!this.check(field, type)) {
     ++this.errors;
     this.notice(field, type, internal_type, this.form);
     this.options.onInvalid(field, type, this.form);
     throw $break;
     }
     }, this);
     
     // submitable?
     if (this.errors !== 0) {
     this.options.onFailure(this.form);
     return this;
     }
     
     this.options.onSuccess(this.form);
     return this;
     }
     
     return {
     initialize: initialize,
     validate: validate,
     check: check,
     notice: notice,
     prepare: prepare
     };
    })());
    
    // predefined types 
    Form.Validator.Types = $H({
     email: /^\w+@(?:(?:\w+\.)+[a-z]{2,}|\w+)$/i,
     tel: /^[\d\/\.\-\s]+$/,
     url: /^[a-z]+[a-z0-9\-]*:\/\/(?:\w+(?::\w+)?@)?(?:(?:\w+\.)+[a-z]{2,}|\w+)(?::[0-9]+)?(?:\/[^?#]*(?:\?[^#]*)?(?:#.*)?)?$/i
    });
    
    // predefined constraits
    Form.Validator.Constraints = $H({
     email: { text: 'Bitte geben Sie eine korrekte E-Mail an.' },
     tel: { text: 'Bitte geben Sie eine Telefonnummer an.' },
     url: { text: 'Bitte geben Sie eine korrekte URL an.' },
     
     required: { 
     text: 'Bitte füllen Sie dieses Feld aus.',
     check: 'Bitte Klicken Sie dieses Feld an.',
     radio: 'Bitte Klicken Sie eines der Felder an.',
     select: 'Bitte wählen Sie eine Option aus.'
     },
     
     // maxlength is silent
     
     // todo: add messages
     date: { },
     month: { },
     week: { },
     range: { },
     number: { },
     time: { },
     datetime: { },
     "datetime-local": { }
    });
    
    // predefined flags
    Form.Validator.Flags = $H({
     // todo: add validators for min and max
     
     maxlength: function(element, form) {
     var len = element.value.length,
     max = parseInt(element.getAttribute("maxlength"));
     
     if (len > max)
     element.value = element.value.substr(0, max);
     
     return true;
     },
     
     required: function(element, form) { 
     switch (element.nodeName.toLowerCase()) {
     case 'input':
     switch (element.getAttribute('type')) {
     case 'checkbox':
     return (element.checked === true);
     
     case 'radio':
     var name = element.getAttribute('name'),
     found = false;
     
     if (!name) return (element.checked === true);
     
     form.select('input[type="radio"][name="' + name + '"]').each(
     function(box) {
     if (box.checked === true) {
     found = true;
     throw $break;
     }
     }
     );
     
     return found;
     
     default:
     return !element.value.blank();
     }
     
     case 'textarea':
     return !element.value.blank();
     
     case 'select':
     return (element.selectedIndex > -1);
     }
     }
    });
    
    Element.addMethods('FORM', { 
     validate: function(element, options) {
     element = $(element);
     
     if (Object.isUndefined(options))
     return element.retrieve("validator") || null;
     
     var validator = new Form.Validator(element, options);
     element.store("validator", validator);
     
     return validator;
     }
    });
    
    

    HTML:
    <!DOCTYPE html>
    <html lang="de">
     <head>
     <title>Form.Validator</title>
     <meta http-equiv="Content-Type" content="text/html; Charset=UTF-8" />
     </head>
     <body>
     <form id="test-form" >
     <input type="url" required="1" />
     <select name="test123" required="1" size="2">
     <option value="1">Something</option>
     </select>
     <input type="radio" name="test-radio" value="1" required="1" />
     <input type="radio" name="test-radio" value="2" />
     <input type="checkbox" name="test" required="1" />
     <textarea required="1"></textarea>
     <input type="submit" />
     </form>
     
     <script type="text/javascript" src="prototype.js"></script>
     <script type="text/javascript" src="validation.js"></script>
     <script type="text/javascript">
     // <![CDATA[
     $("test-form").validate({
     onSuccess: function(form) { alert("okay"); },
     onFailure: function(form) { alert("fehler"); },
     onInvalid: function(das_fehlerhafte_feld, der_fehler, form) { /* mach was */ }
     });
     // ]]>
     </script>
     </body>
    </html>
    anpassbar über:
    Code:
    Form.Validator.Types // -> reguläre ausdrücke für input-typen z.b. email, url, tel ...
    Form.Validator.Constraints // -> entsprechende fehlermeldungen
    Form.Validator.Flags // -> validator-funktionen für required="1" oder maxlength="123" usw...
    beispiel:
    Code:
    Form.Validator.Constraints.set("email", { 
     text: "Hier muss eine E-Mail rein Junge!" 
    });
    live: http://murdoc.eu/rr/valid.html

    bekannte fehler:
    felder werden mit dem script nicht mehr resetet, ohne schon
     

  8. Videos zum Thema
Die Seite wird geladen...
Similar Threads - JavaScript Prototype Erweiterungen
  1. Antworten:
    0
    Aufrufe:
    3.677
  2. Antworten:
    6
    Aufrufe:
    2.931
  3. Antworten:
    6
    Aufrufe:
    649
  4. Antworten:
    2
    Aufrufe:
    359
  5. Antworten:
    2
    Aufrufe:
    278
  • Annonce

  • Annonce