Created
March 28, 2013 10:19
-
-
Save piotrjura/5262176 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (function() { | |
| // Zapisujemy globalny obiekt `window` | |
| var root = this; | |
| // Definiujemy nadrzędny namespace `Futbolowo`, przypisany do `window` | |
| var Futbolowo = root.Futbolowo = {}; | |
| // Referencja do globalnego obiektu `jQuery` | |
| Futbolowo.$ = root.jQuery; | |
| // Referencja do underscore.js | |
| var _ = root._; | |
| var People = Futbolowo.People = {}; | |
| // Futbolowo.EventSubscriber | |
| // ------------- | |
| var EventSubscriber = Futbolowo.EventSubscriber = function(arguments) { | |
| }; | |
| _.extend(EventSubscriber, { | |
| bind: function(event, method, caller) { | |
| // FIXME | |
| // Tutaj potrzebne będzie jakieś bardziej PRO rejestrowanie zdarzeń, | |
| // żeby nie robić protezy | |
| if (event == 'uploadDone' && typeof uploader !== 'undefined') { | |
| uploader.bind('FileUploaded', function(up, file, data) { | |
| method(Futbolowo.$.parseJSON(data.response), caller); | |
| }); | |
| } | |
| } | |
| }); | |
| // Futbolowo.View | |
| // ------------- | |
| // Konstruktor widoku | |
| var View = Futbolowo.View = function(arguments) { | |
| // Zapamiętuje przekazane parametry w polu `options` | |
| this.options = arguments || {}; | |
| // Inicjujemy obiekt przechowujący dane | |
| this.data = {}; | |
| this._configure(this.options); | |
| // Upewnia się, że widok posiada przypisany element DOM. | |
| // Można go przekazać w parametrze jako `el`(selektor lub kod) | |
| // lub `$el`(obiekt jQuery). | |
| this._ensureElement(); | |
| // Przypina zdefiniowane zdarzenia do odpowiednich elementów DOM | |
| // a także do globalnych zdarzeń `Futbolowo` | |
| this._bindEvents(); | |
| // Przypina walidatory do odpowiednich pól formularzy | |
| this._bindValidators(); | |
| this.initialize.apply(this); | |
| }; | |
| // Walidatory w formie predefiniowanych wyrażeń regularnych które | |
| // należy objąc custom[] | |
| var customValidators = ['phone', 'url', 'email', 'date', 'number', 'integer', 'ipv4', 'onlyNumberSp', | |
| 'onlyLetterSp', 'onlyLetterNumber']; | |
| _.extend(View.prototype, { | |
| // Zawęrzenie `jQuery` do kontekstu elementu DOM widoku | |
| $: function(selector) { | |
| return this.$el.find(selector); | |
| }, | |
| // Metoda wywoływana automatycznie po utworzeniu obiektu, | |
| // (po rzeczywistym konstruktorze) | |
| initialize: function() {}, | |
| // Usuwa element DOM jeżeli jest przypisany | |
| destroy: function() { | |
| // Jeżeli widok posiada element DOM, usuwamy ten element | |
| if (this.$el && this.$el instanceof Futbolowo.$) { | |
| this.$el.remove(); | |
| } | |
| }, | |
| render: function() { | |
| return this; | |
| }, | |
| // Ustawia element DOM widoku na podstawie kodu HTML, selektora bądź obiektu `jQuery` | |
| setElement: function(element) { | |
| // Tworzy obiekt DOM (na podstawie przekazanego kodu HTML lub selektora) | |
| // albo przypisuje przekazany obiekt `jQuery` | |
| this.$el = element instanceof Futbolowo.$ ? element : Futbolowo.$(element); | |
| // Kopiuje dane z obiektu `jQuery` do pola `data` widoku | |
| if (this.$el) this.data = _.extend(this.$el.data(), this.data) || {}; | |
| // Wybiera pierwszy element odnaleziony przez selektor | |
| this.el = this.$el[0]; | |
| return this; | |
| }, | |
| // Pobiera szablon z atrybutu elementu DOM (`data-template*`), podmienia | |
| // placeholdery na wartość (atrybut - wartość obiektu data) | |
| template: function(name, data) { | |
| if (!_.isUndefined(this.data['template' + name])) { | |
| var template = this.data['template' + name]; | |
| _.each(data, function(item, index) { | |
| index = new RegExp(index, 'g'); | |
| template = template.replace(index, item); | |
| }); | |
| return template; | |
| } | |
| }, | |
| _configure: function(options) { | |
| _.extend(this, options); | |
| }, | |
| _ensureElement: function() { | |
| if (this.$el) { | |
| this.setElement(this.$el) | |
| } else if (this.el) { | |
| this.setElement(this.el); | |
| } else { | |
| this.setElement('<div></div>'); | |
| } | |
| }, | |
| // Przypina do elementów DOM widoku zdarzenia zdefiniowane | |
| // we właściwości `events' obiektu widoku | |
| _bindEvents: function() { | |
| var view = this; | |
| _.each(this.events, function(event, index, events) { | |
| if (index.charAt(0) == '@') { | |
| EventSubscriber.bind(index.slice(1), view[event], view); | |
| } else { | |
| var eventInfo = index.split(' '); | |
| var dom = view.$(eventInfo[0]); | |
| if (dom.length) dom.bind(eventInfo[1], function() { view[event](this, view); }); | |
| } | |
| }); | |
| }, | |
| // Dodaje do atrybutu `class` elementu DOM definicje dla walidacji `jQuery` | |
| // na podstawie pola `validators` obiektu widoku | |
| _bindValidators: function() { | |
| var view = this; | |
| _.each(this.validators, function(validator, index, validators) { | |
| // Wyszukujemy element o nazwie zawierającej name | |
| var dom = view.$('[name*=' + index + ']'); | |
| // Tworzymy tablicę nazw walidatorów | |
| var fieldValidators = validator.split(' '); | |
| var c = 'validate['; | |
| _.each(fieldValidators, function(validator) { | |
| if (!_.contains(customValidators, validator)) | |
| c += validator + ','; | |
| else | |
| c += 'custom[' + validator + '],'; | |
| }); | |
| c = c.slice(0, -1) + ']'; | |
| dom.addClass(c); | |
| }); | |
| } | |
| }); | |
| var extend = function(protoProps, staticProps) { | |
| var parent = this; | |
| var child; | |
| if (protoProps && _.has(protoProps, 'constructor')) { | |
| child = protoProps.constructor; | |
| } else { | |
| child = function(){ return parent.apply(this, arguments); }; | |
| } | |
| _.extend(child, parent, staticProps); | |
| var Surrogate = function(){ this.constructor = child; }; | |
| Surrogate.prototype = parent.prototype; | |
| child.prototype = new Surrogate; | |
| if (protoProps) _.extend(child.prototype, protoProps); | |
| child.__super__ = parent.prototype; | |
| return child; | |
| }; | |
| View.extend = extend; | |
| }).call(this); | |
| $(function(){ | |
| // MeasurementItemView | |
| // ------------- | |
| var MeasurementItemView = Futbolowo.View.extend({ | |
| events: { | |
| '.remove click': 'remove' | |
| }, | |
| // Walidatory dla elementów formularza w obrębie widoku, kluczem jest | |
| // przybliżona nazwa pola, wartości to walidatory oddzielone spacją | |
| validators: { | |
| 'height': 'required min[60] max[220]', | |
| 'weight': 'required min[20] max[250]', | |
| 'measurmentDate': 'required date' | |
| }, | |
| initialize: function() { | |
| this.$('.date').datepicker({dateFormat: 'yy-mm-dd'}); | |
| }, | |
| remove: function() { | |
| this.destroy(); | |
| } | |
| }); | |
| // MeasurementCollectionView | |
| // ------------- | |
| var MeasurementCollectionView = Futbolowo.View.extend({ | |
| // Istniejący element DOM | |
| el: '#view-measurements', | |
| // Tablica przechowująca kolekcję | |
| collection: [], | |
| // Definicja zdarzeń, jako klucz należy podać selektor i zdarzenie oddzielone | |
| // spacją, jako wartość nazwę metody w kontekście obecnego widoku | |
| events: { | |
| '#addMeasurement click': 'add' | |
| }, | |
| initialize: function() { | |
| // Pobiera aktualne elementy kolekcji z DOM | |
| var existingItems = this.$('li'); | |
| // Zapisujemy następny indeks elementu formularza | |
| this.data.index = existingItems.length; | |
| // Zapisujemy aktualny widok, ponieważ `this` w kontekście `_each()` to `window` | |
| var view = this; | |
| _.each(existingItems, function(item) { | |
| view.collection.push(new MeasurementItemView({$el: item})); | |
| }); | |
| }, | |
| // Funkcje zdarzeniowe (callback) są wywoływane z parametrem `object`, który | |
| // w przypadku `jQuery` jest obiektem który spowodował zdarzenie (a, input) | |
| // a w przypadku zdarzeń globalnych jest to obiekt zależny od zdarzenia. | |
| // Argument `_this` zawsze jest obiektem widoku, do którego przypisana jest | |
| // metoda zdarzenia | |
| add: function(object, _this) { | |
| // Funkcja `template` wyciąga szablon zdefiniowany jako atrybut głównego | |
| // elementu DOM widoku (`data-templateMeasurement`). Drugim parametrem | |
| // jest obiekt w którym atrybut określa placeholder w szablonie a wartość | |
| // to fragment na który należy zamienić placeholder | |
| var template = this.template('measurement', {__name__: _this.data.index}); | |
| // Tworzymy nowy widok pojedyńczego elementu kolekcji, przypisując do niego | |
| // od razu element DOM | |
| var item = new MeasurementItemView({$el: $(template)}); | |
| _this.collection.push(item); | |
| // Dopisujemy element kolekcji do listy | |
| _this.$('ul').append(item.$el); | |
| // Zwiększamy indeks następnego elementu kolekcji | |
| _this.data.index++; | |
| } | |
| }); | |
| // PictureCollectionView | |
| // ------------- | |
| var PictureCollectionView = Futbolowo.View.extend({ | |
| el: '#pictures', | |
| collection: [], | |
| events: { | |
| // Zdarzenia poprzedzone `@` są globalnymi zdarzeniami `Futbolowo`, | |
| // obsługiwanymi przez `EventSubscriber` | |
| '@uploadDone': 'add' | |
| }, | |
| initialize: function() { | |
| var existingItems = this.$('div.picture'); | |
| this.data.index = existingItems.length; | |
| var view = this; | |
| _.each(existingItems, function(item) { | |
| view.collection.push(new PictureItemView({$el: item})); | |
| }); | |
| }, | |
| add: function(object, _this) { | |
| var template = _this.template('picture', { | |
| __name__: _this.data.index, | |
| __source__: object.filename, | |
| }); | |
| var item = new PictureItemView({$el: $(template)}); | |
| item.$('[name*=dateTaken]').val(object.dateTaken); | |
| _this.collection.push(item); | |
| _this.$el.prepend(item.$el); | |
| _this.data.index++; | |
| } | |
| }); | |
| // PictureItemView | |
| // ------------- | |
| var PictureItemView = Futbolowo.View.extend({ | |
| events: { | |
| '.remove click': 'remove', | |
| 'input[type=radio] click': 'selectMe' | |
| }, | |
| validators: { | |
| 'dateTaken': 'required date' | |
| }, | |
| initialize: function() { | |
| this.$('.date').datepicker({dateFormat: 'yy-mm-dd'}); | |
| }, | |
| remove: function() { | |
| this.destroy(); | |
| }, | |
| selectMe: function(object, _this) { | |
| // Do refactoru. Pole `collection` zamiast tablicą, będzie obiektem. | |
| // Pozwoli to przypisywać do widoków widok nadrzędny i wykonywać | |
| // metody widoku nadrzędnego | |
| Futbolowo.$('[name*="person[pictures]"]').prop('checked', false); | |
| this.$(object).prop('checked', true); | |
| } | |
| }); | |
| // NotificationsView | |
| // ------------- | |
| var NotificationsView = Futbolowo.View.extend({ | |
| el: '#notifications', | |
| add: function(message, type) { | |
| var template = this.template('notification', { | |
| __message__: message, | |
| __type__: type | |
| }); | |
| this.$el.html($(template)); | |
| } | |
| }); | |
| // NotificationView | |
| // ------------- | |
| var NotificationView = Futbolowo.View.extend({ | |
| }); | |
| var notificationsView = new NotificationsView(); | |
| notificationsView.add('Test powiadomień!!!', 'success'); | |
| var measurementCollectionView = new MeasurementCollectionView(); | |
| var pictureCollectionView = new PictureCollectionView(); | |
| $("form").validationEngine(); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment