Skip to content

Instantly share code, notes, and snippets.

@piotrjura
Created March 28, 2013 10:19
Show Gist options
  • Select an option

  • Save piotrjura/5262176 to your computer and use it in GitHub Desktop.

Select an option

Save piotrjura/5262176 to your computer and use it in GitHub Desktop.
(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