diff --git a/collection.js b/collection.js new file mode 100644 index 0000000..5792d4d --- /dev/null +++ b/collection.js @@ -0,0 +1,81 @@ +(function (exports) { + "use strict"; + +var Collection = function (items) { + + this.items = []; + var key; + + for (key in items) { + if (items.hasOwnProperty(key)) { + this.items.push(items[key]); + } + } +}; + +exports.Collection = Collection; + +Collection.prototype.constructor = Collection; + +/** + * Добавляет в коллекцию объект + * + * @param {object} model + * + * @return {Collection} * @example + * + */ +Collection.prototype.add = function (model) { + + var temp = new this.constructor(this.items); + temp.items.push(model); + return temp; +}; + +/** + * @param {Function} selector + * + * @see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter + * + * @example + * new Collection().filter(function (item) { + * return item.get('attendee').indexOf("me") !== -1; + * }); + * @return {Collection} + */ +Collection.prototype.filter = function (selector) { + + if (typeof selector !== "function") { + throw new Error('Argument must be function'); + } + + return new this.constructor(this.items.filter(selector)); +}; + +/** + * Принимает функцию сортировки и сортирует на основе ее + * + * @param {function} selector + * + * @return {Collection} * @example + * + */ +Collection.prototype.sort = function (selector) { + + if (typeof selector !== "function") { + throw new Error('Argument must be function'); + } + + return new this.constructor(this.items.sort(selector)); +}; + +Collection.prototype.reverse = function () { + + return new this.constructor(this.items.reverse()); +}; + +Collection.prototype.length = function (selector) { + + return this.items.length; +}; +}(window)); \ No newline at end of file diff --git a/documentAction.js b/documentAction.js new file mode 100644 index 0000000..1abadf8 --- /dev/null +++ b/documentAction.js @@ -0,0 +1,191 @@ +(function (exports) { + "use strict"; + + var ListOfEvents = new Events(); + var sortedList = new Events(); + + var filterOption = "all"; + var sortOption = "without"; + +/** + * Добавляет новое событие в список. Если установлены опции фильтрации и сортировки + * - то располагает элменты на странице, в с-ии с ними + * +*/ + function preventDefault() { + + var name = document.querySelector("#title").value, + start = document.querySelector("#from").value, + end = document.querySelector("#to").value, + location = document.querySelector("#location").value, + raiting = document.querySelector("#raiting").value, + description = document.querySelector("#description").value, + remindTime = document.querySelector("#remindTime").value; + + if (!validateTitle(name, document.querySelector('#title_help'))) { alert("Событие не было добавлено. Ошибка"); return; }; + if (!validateDate(start, document.querySelector('#from_help'))) { alert("Событие не было добавлено. Ошибка"); return; }; + if (!validateNumber(remindTime, document.querySelector('#remindTime_help'))) { alert("Событие не было добавлено. Ошибка"); return; }; + + var element = new Event({ + name: name, + start: new Date(start), + end: new Date(end), + location: location, + raiting: raiting, + description: description, + remindTime: remindTime + }).validate(); + + ListOfEvents = ListOfEvents.add(element); + + changeDocument("sort"); + document.forms["form"].reset(); +}; + + function filterEvents(listEvents) { + switch (filterOption) { + case "future": + return listEvents.coming(); + case "past": + return listEvents.past(); + default: + return listEvents; + } + } + + function sortEvents(listEvents) { + switch (sortOption) { + case "byName": + return ListOfEvents.sortByName(); + case "byStart": + return ListOfEvents.sortByTime(); + case "byRaiting": + return ListOfEvents.sortByRaiting(); + default: + return ListOfEvents; + } + } + +/** + * Сортирует и фильтрует события в соответствии с указанными опциями. + * + * @param {string} changeType - если указана строка "sort", то события также будут отсортированы, + * инчае - только отфильтрованы + * @return коллекция объектов типа event +*/ + + function changeDocument(changeType) { + var parent = document.querySelector(".collection"), + removeList = document.querySelector(".events"); + parent.removeChild(removeList); + + var addList = document.createElement('ul'); + addList.className = "events"; + + var fragment = document.createDocumentFragment(); + if (changeType === "sort") { + sortedList = sortEvents(ListOfEvents); + } + var filterList = filterEvents(sortedList); + + var length = filterList.length(); + + for (var i = 0; i < length; i++) + { + var element = filterList.items[i]; + var el = addLiElement(element); + addList.appendChild(el); + } + + var parent = document.querySelector(".collection"); + fragment.appendChild(addList); + parent.appendChild(fragment); +} + +/** + * Создает DOM-элемент типа li, заполняется полями из объекта + * + * @param {Event} element - объект типа Element + * + * @return Возвращает созданный дом-элемент типа li +*/ + + function addLiElement (element) { + var el = document.createElement('li'); + el.className = 'event_item'; + + var name = document.createElement('div'); + name.textContent = "Название: " + element.name; + + var start = document.createElement('div'); + start.textContent = "Начало: " + element.start; + + var end = document.createElement('div'); + end.textContent = "Окончание: " + element.end; + + var location = document.createElement('div'); + location.textContent = "Местоположение: " + element.location; + + var remindTime = document.createElement('div'); + remindTime.textContent = "Напомнить за: " + element.remindTime + "минут"; + + var description = document.createElement('div'); + description.textContent = "Описание: " + element.description; + + var raiting = document.createElement('div'); + raiting.textContent = "Рейтинг: " + element.raiting; + + el.appendChild(name); + el.appendChild(start); + el.appendChild(end); + el.appendChild(location); + el.appendChild(remindTime); + el.appendChild(description); + el.appendChild(raiting); + + return el; + }; + +/** + * Навешивает обработчики событий на страницу +*/ + exports.addListener = function() { + var name = document.querySelector("#title"); + var start = document.querySelector("#from"); + var remindTime = document.querySelector("#remindTime"); + var filters = document.querySelectorAll('.filter'); + var sort = document.querySelectorAll('.sort'); + var button = document.querySelector("#addButton"); + + name.addEventListener('blur', function(event) { + var cur = event.currentTarget; + validateTitle(cur.value, document.querySelector('#title_help')); + }); + + start.addEventListener('blur', function (event) { + var cur = event.currentTarget; + validateDate(cur.value, document.querySelector('#from_help')); + }); + + remindTime.addEventListener('blur', function (event) { + var cur = event.currentTarget; + validateNumber(remindTime.value, document.querySelector('#remindTime_help')); + }); + + for (var i=0; i < filters.length; i++) { + filters[i].addEventListener('change', function (event) { + filterOption = document.querySelector('input[name="filter"]:checked').value; + changeDocument("filter"); + }); + } + + for (var i=0; i < sort.length; i++) { + sort[i].addEventListener('change', function(event) { + sortOption = document.querySelector('input[name="sort"]:checked').value; + changeDocument("sort"); + }); + } + + button.addEventListener('click', preventDefault); + } +}(window)); \ No newline at end of file diff --git a/event.js b/event.js new file mode 100644 index 0000000..ca9101b --- /dev/null +++ b/event.js @@ -0,0 +1,86 @@ +(function (exports) { + "use strict"; + + exports.isDate = function (date) { + + if (typeof date === 'undefined') { + return false; + } + if (typeof date.getMonth !== 'function') { + return false; + } + if (isNaN(date.getMonth())) { + return false; + } + return true; + }; + + exports.inherits = function (constructor, superconstructor) { + + var Func = function () { }; + + Func.prototype = superconstructor.prototype; + constructor.prototype = new Func(); + }; + + exports.Event = function (data) { + + Model.apply(this, arguments); + }; + + inherits(Event, Model); + +/** + * Валидирует объект event, либо undefined, если в объекте отсутвуют обязательные поля + * eventObject{ + * name - название события + * start - начало + * end - окончание + * location - место + * remindTime - за сколько минут до события напомнить + * description - описание + * raiting - важность события + * } + + * @param {object} obj Объект + * @example + * Event({ + * name: "Пара по веб-технологиям", + * start: new Date("2012-10-20 10:00:00"), + * end: new Date("2012-10-20 12:50:00"), + * location: "5 этаж", + * remindTime: 10, + * raiting:5, + * description: "Взять бумагу и ручку, не брать бук!" + * }) + * + * @return {Object} + */ + Event.prototype.validate = function () { + + var remindTime = this.remindTime || 0; + this.raiting = this.raiting || 0; + + if (!isDate(this.get("start"))) { + throw new Error('Field "start" must be Date format'); + } + + if (!isDate(this.end)) { + this.end = this.start; + } + + if (this.end < this.start) { + this.end = this.start; + } + + return { + "name": this.name || "(Нет темы)", + "start": this.start, + "end": this.end, + "location": this.location || "", + "remindTime": remindTime, + "description": this.description || "(отсутствует)", + "raiting": this.raiting + }; + }; +}(window)); \ No newline at end of file diff --git a/events.js b/events.js new file mode 100644 index 0000000..89b3d76 --- /dev/null +++ b/events.js @@ -0,0 +1,152 @@ +(function (exports) { + "use strict"; + +exports.Events = function (data) { + + Collection.apply(this, arguments); +}; + +inherits(Events, Collection); + +Events.prototype.constructor = exports.Events; + +/** + * Возвращает прошедшие события, из items отсортированной по дате начала + * + * @param {events} - коллекция объектов типа event + * @return {Collection} - коллекция объектов типа event +*/ +Events.prototype.past = function () { + + return this.filter(function (events) { + return events.start < new Date(); + }); +}; + +/** + * Возвращает предстоящие события, + * из items, отсортированной по дате начала + * + * @return {Collection} - коллекция объектов типа event +*/ +Events.prototype.coming = function () { + + return this.filter(function (events) { + return events.start > new Date(); + }); +}; + +/** + * Возвращает события, которые произойдут через опр период времени, + * из items, отсортированной по дате начала + * + * @param {number} days - период (в днях) времени + * + * @return коллекция объектов типа event +*/ +Events.prototype.comeThrough = function (days) { + + var now = new Date(); + now.setDate(now.getDate() + days); + + var result = this.coming() + .filter(function (events) { + return events.start < now; + }); + + return result; +}; + +Events.prototype.byEndTime = function () { + + return this.sort(function (a, b) { + return a.end - b.end; + }); +}; + +Events.prototype.byRaiting = function () { + + return this.sort(function (a, b) { + return a.raiting - b.raiting; + }); +}; + +Events.prototype.byStartTime = function () { + + return this.sort(function (a, b) { + return a.start - b.start; + }); +}; + +Events.prototype.byName = function () { + + return this.sort(function (a, b) { + return a.name - b.name; + }); +}; + +/** + * Возвращает события,из items отсортированной по дате начала по возр/убыв + * от старых обытий к новым / наоборот. + * По умолчанию сортирует в порядке возрастания + * + * @param {bool} isAscending - необязательный параметр - указывает порядок сортировки. + * при отсутсвии сортируется по возрастанию. + * + * @return {Collection} - Новый объект типа Collection +*/ +Events.prototype.sortByName = function (isAscending) { + + isAscending = isAscending || false; + + if (isAscending) { + return this.byName(); + } + return this.byName() + .reverse(); +}; + +/** + * Возвращает события,из items отсортированной по названию по возр/убыв + * По умолчанию сортирует в порядке возрастания + * + * @param {bool} isAscending - необязательный параметр - указывает порядок сортировки. + * при отсутсвии сортируется по возрастанию. + * + * @return {Collection} - Новый объект типа Collection +*/ +Events.prototype.sortByTime = function (isAscending) { + + isAscending = isAscending || false; + + if (isAscending) { + return this + .byStartTime().reverse(); + } + return this.byStartTime(); + +}; + +/** + * Возвращает события, из items, отсортированной по рейтингу по убыв/возрастанию + * от событий с более высоким рейтингом к самому низко приоритетному / наоборот. + * По умолчанию сортирует в порядке убывания + * + * @param {bool} isAscending - необязательный параметр - указывает порядок сортировки. + * при отсутствии сортируется по убыванию. + * + * @return {COllection} - Новый объект типа Collection +*/ +Events.prototype.sortByRaiting = function (isAscending) { + + isAscending = isAscending || false; + + if (isAscending) { + return this + .byRaiting() + .reverse(); + } + return this + .byRaiting(); +}; +}(window)); \ No newline at end of file diff --git a/examples.js b/examples.js new file mode 100644 index 0000000..8aa58ae --- /dev/null +++ b/examples.js @@ -0,0 +1,23 @@ +var examples = [ + { name: "Пара по веб-технологиям", start: new Date("2012-10-20 10:00:00"), end: new Date("2012-10-20 12:50:00"), location: "5 этаж", remindTime: 10, description: "Взять бумагу и ручку, не брать бук!" }, + { name: "День зимы", start: new Date("2012-10-27 06:00:00"), end: new Date("2012-10-27 12:00:00"), location: "Скандинавия", description: "Кататься ^_^" }, + { name: "День инженера механика", start: new Date("2012-10-29 10:00:00"), end: new Date("2012-10-29 15:00:00"), location: "9 этаж", remindTime: 10 }, + { name: "День вегана", start: new Date("2012-11-1 10:00:00"), end: new Date("2012-10-1 23:00"), location: "Дома", description: "Be vegan =)" }, + { name: "День журналисты", start: new Date("2012-11-8 10:00:00"), location: "Китай", remindTime: 10, description: "Поздравить Олежу" }, + { name: "Всемирный день борьбы с диабетом", start: new Date("2012-11-14 12:00") }, + { name: "Международный день отказа от курения", start: new Date("2012-11-15 12:00"), description: "Поздравить Сашку)" }, + { name: "День защиты черных котов", start: new Date("2012-11-17 14:00:00"), location: "Италия", remindTime: 50, description: "Котэ" }, + { name: "Всемирный день туалетов", start: new Date("2012-11-19 15:00:00"), location: "МИр", description: "о_О" }, + { name: "День революции", start: new Date("2012-11-20 12:00:00"), location: "Мексика"}, + { name: "День сладостей", start: new Date("2012-10-20 15:00:00"), location: "США", remindTime: 10, description: "Приготовить вкусняшки" }, + { name: "Ерофеев день", start: new Date("2012-10-17 16:00:00"), location: "Россия", description: "Лисики" }, + { name: "Утиный фестиваль", start: new Date("2012-10-13 12:00:00"), location: "Италия", description: "Все в Италию!" }, + { name: "Дент ребенка", start: new Date("2012-10-12 14:00:00"), location: "Бразилия" }, + { name: "День физкультуры", start: new Date("2012-10-8 12:00:00"), location: "Япония"}, + { name: "Всемирный день животных", start: new Date("2012-10-4 12:00:00 ")}, + { name: "День сакэ в Японии", start: new Date("2012-10-1 14:00:00") }, + { name: "День моря", start: new Date("2012-09-27 15:00:00") }, + { name: "День комиксов", start: new Date("2012-09-25 15:00:00"), location: "США"}, + { name: "День почитания пожилых людей", start: new Date("2012-09-17 16:00:00")}, + { name: "Международный жень демократии", start: new Date("2012-09-15 17:00:00")} +]; \ No newline at end of file diff --git a/index.css b/index.css new file mode 100644 index 0000000..e19eec3 --- /dev/null +++ b/index.css @@ -0,0 +1,24 @@ +body{ text-align: left;} +#frame { + display: inline-block; + float: left; + text-align: right; +} +.help { + color: red; + visibility : hidden; + min-height: 25px; +} +.event_item{ +} +.collection{ + float: left; + text-align: left; + margin-left: 50px; +} +.select{ + text-align: left; +} +.selecter{ + color: blue; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..b145959 --- /dev/null +++ b/index.html @@ -0,0 +1,69 @@ + + +
+ +