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 @@ + + + + + Календарь событий + + + +
+
+
Название: +
+
С:
+
По:
+
Место:
+
Важность события: + +
+
Описание: + +
+
Напомнить за: минут +
+ + +
+
+
Выбрать
+
+
+ +
Отсортировать по
+
+
+
+ +
+
+
+
Введите название события
+
Введите корректную дату
+
Введите корректную дату
+
D
+
D
+
D
+
D
+
Введите корректное число
+
+ +
+ +
+ + + + + + + + + \ No newline at end of file diff --git a/model.js b/model.js new file mode 100644 index 0000000..963a925 --- /dev/null +++ b/model.js @@ -0,0 +1,62 @@ +(function (exports) { + "use strict"; + +/** + * Абстрактный конструктор, принимает объект и создает абстрактный объект для работы + * + * @param {Object} attributes + * + * @example + * item.set({title: "March 20", content: "In his eyes she eclipses..."}); + */ +exports.Model = function (data) { + + var key; + + for (key in data) { + if (data.hasOwnProperty(key)) { + this[key] = data[key]; + } + } +}; + + +/** + * Сеттер - устанавливает аттрибуты и значения атрибутов, в соответсвии с принятым в качестве параметра объектом + * + * @param {Object} attributes + * + * @example + * item.set({title: "March 20", content: "In his eyes she eclipses..."}); + */ +Model.prototype.set = function (attributes) { + + var key; + + for (key in attributes) { + if (attributes.hasOwnProperty(key)) { + this[key] = attributes[key]; + } + } +}; + +/** + * Геттер - возвращает запрашиваемое свойство у объекта + * + * @param {Object} attributes + */ +Model.prototype.get = function (attribute) { + + if (this.hasOwnProperty(attribute)) { + return this[attribute]; + } + + return undefined; +}; +/** + * @param {Object} attributes + */ +Model.prototype.validate = function (attributes) { + throw new Error('this is Abstract method'); +}; +}(window)); \ No newline at end of file diff --git a/tests/EventsTest.html b/tests/EventsTest.html new file mode 100644 index 0000000..dbafb9e --- /dev/null +++ b/tests/EventsTest.html @@ -0,0 +1,18 @@ + + + + + Тестирование класса Events (Collection) + + + + + + + + + + +
+ + diff --git a/tests/EventsTest.js b/tests/EventsTest.js new file mode 100644 index 0000000..9549c6c --- /dev/null +++ b/tests/EventsTest.js @@ -0,0 +1,78 @@ +function getString(event) { + "use strict"; + + return "\n" + event.name + "\n" + " начало: " + event.start + "\n" + + " конец: " + event.end + "\n" + + " место события: " + event.location + " напомнить за " + event.remindTime + " минут" + "\n" + + " описание: " + event.description + "\n"; +} + +test("Testing inherits Events from Collection", function () { + "use strict"; + + var collection = new Events(examples), + element = {title: "March 20", content: "In his eyes she eclipses..."}, + result = collection.add(element); + + examples.push(element); + + deepEqual(result.items, examples, "Two objects can be the same in value"); +}); + +test("Testing past in Events", function () { + "use strict"; + + var collection = new Events(examples), + result = collection.past(); + + console.log("Result: " + result.items.map(function (event) { + return getString(event); + })); + + console.log("--------------\n"); + ok("1" === "1", "Two objects can be the same in value"); +}); + +test("Testing coming in Events", function () { + "use strict"; + + var collection = new Events(examples), + result = collection.coming(); + + console.log("Result: " + result.items.map(function(event) { + return getString(event); + })); + + console.log("--------------\n"); + ok("1" === "1", "Two objects can be the same in value"); +}); + +test("Testing comeThrough in Events", function () { + "use strict"; + + var collection = new Events(examples), + result = collection.comeThrough(10); + + console.log("Result: " + result.items.map(function (event) { + return getString(event); + })); + + console.log("--------------\n"); + ok("1" === "1", "Two objects can be the same in value"); +}); + +test("Testing sortBytime in Events", function () { + "use strict"; + + var collection = new Events(examples), + result = collection.byStartTime(); + + console.log("Result: " + result.items.map(function (event) { + return getString(event); + })); + + console.log("--------------\n"); + ok("1" === "1", "Two objects can be the same in value"); +}); + + diff --git a/tests/collectionTest.html b/tests/collectionTest.html new file mode 100644 index 0000000..1ae6ec6 --- /dev/null +++ b/tests/collectionTest.html @@ -0,0 +1,17 @@ + + + + + Тестирование класса Collection + + + + + + + + + +
+ + diff --git a/tests/collectionTest.js b/tests/collectionTest.js new file mode 100644 index 0000000..131b6c1 --- /dev/null +++ b/tests/collectionTest.js @@ -0,0 +1,49 @@ +test("Create object Collection", function () { + "use strict"; + + var result = new Collection(examples); + + ok(result.items[0].name == examples[0].name, "Passed!"); +}); + +test("Testing for creating new Collection in constructor", function () { + "use strict"; + + var result = new Collection(examples); + result.items.pop(); + + ok(result.items.length !== examples.length, "Passed!"); +}); + +test("Add func in Collection", function () { + "use strict"; + + var collection = new Collection(examples), + element = {title: "March 20", content: "In his eyes she eclipses..."}, + result = collection.add(element); + + examples.push(element); + + deepEqual(result.items, examples, "Two objects can be the same in value"); +}); + +test("Test Collection", function () { + "use strict"; + + var collection = new Collection(), + element = {title: "March 20", content: "In his eyes she eclipses..."}, + result = collection.add(element); + + deepEqual(result.items, [element], "Two objects can be the same in value"); +}); + +test("Filter func in Collection", function () { + "use strict"; + + var collection = new Collection(examples), + result = collection.filter(function (item) { + return item.name === "День зимы"; + }); + + ok(result.items.length !== examples.length, "Passed"); +}); diff --git a/tests/eventTest.html b/tests/eventTest.html new file mode 100644 index 0000000..d8284b1 --- /dev/null +++ b/tests/eventTest.html @@ -0,0 +1,16 @@ + + + + + Тестирование класса Event и наследования от класса Model + + + + + + + + +
+ + diff --git a/tests/eventTest.js b/tests/eventTest.js new file mode 100644 index 0000000..0787a89 --- /dev/null +++ b/tests/eventTest.js @@ -0,0 +1,24 @@ +test("Create object Event using Model constructor", function () { + "use strict"; + + var item = new Event({title: "March 20", content: "In his eyes she eclipses..."}); + + ok(item.title === "March 20", "Passed!"); +}); + +test("Testing inherits Event from Model", function () { + "use strict"; + + var item = new Event({title: "March 20", content: "In his eyes she eclipses..."}); + + ok(item.get("title") === "March 20", "Passed!"); +}); + +test("Test for validate method", function () { + "use strict"; + + var item = new Event({name: "hello", start: new Date("2012-10-20 10:00:00")}), + valide = item.validate(); + + ok(valide.name === "hello", "Passed!"); +}); diff --git a/tests/modelTest.html b/tests/modelTest.html new file mode 100644 index 0000000..978bab0 --- /dev/null +++ b/tests/modelTest.html @@ -0,0 +1,16 @@ + + + + + Тестирование класса Model + + + + + + + + +
+ + diff --git a/tests/modelTest.js b/tests/modelTest.js new file mode 100644 index 0000000..c322f9e --- /dev/null +++ b/tests/modelTest.js @@ -0,0 +1,30 @@ +test("Testing qunit", function () { + "use strict"; + + ok( "1" == "1", "Passed!"); +}); + +test("Creating absract object Model", function () { + "use strict"; + + var item = new Model({title: "March 20", content: "In his eyes she eclipses..."}); + ok(item.title === "March 20", "Passed!"); +}); + + +test("Testing setter for Model", function () { + "use strict"; + + var item = new Model(); + item.set({title: "March 20", content: "In his eyes she eclipses..."}); + ok(item.title === "March 20", "Passed!"); +}); + +test("Testing getter for Model", function () { + "use strict"; + + var item = new Model(); + item.set({title: "March 20", content: "In his eyes she eclipses..."}); + + ok(item.get("title") === "March 20", "Passed!"); +}); \ No newline at end of file diff --git a/tests/runner.js b/tests/runner.js new file mode 100644 index 0000000..cea3719 --- /dev/null +++ b/tests/runner.js @@ -0,0 +1,98 @@ +/* + * Qt+WebKit powered headless test runner using Phantomjs + * + * Phantomjs installation: http://code.google.com/p/phantomjs/wiki/BuildInstructions + * + * Run with: + * phantomjs runner.js [url-of-your-qunit-testsuite] + * + * E.g. + * phantomjs runner.js http://localhost/qunit/test + */ + +/*jshint latedef:false */ +/*global phantom:true require:true console:true */ +var url = phantom.args[0], + page = require('webpage').create(); + +// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") +page.onConsoleMessage = function(msg) { + console.log(msg); +}; + +page.onInitialized = function() { + page.evaluate(addLogging); +}; +page.open(url, function(status){ + if (status !== "success") { + console.log("Unable to access network: " + status); + phantom.exit(1); + } else { + // page.evaluate(addLogging); + var interval = setInterval(function() { + if (finished()) { + clearInterval(interval); + onfinishedTests(); + } + }, 500); + } +}); + +function finished() { + return page.evaluate(function(){ + return !!window.qunitDone; + }); +} + +function onfinishedTests() { + var output = page.evaluate(function() { + return JSON.stringify(window.qunitDone); + }); + phantom.exit(JSON.parse(output).failed > 0 ? 1 : 0); +} + +function addLogging() { + window.document.addEventListener( "DOMContentLoaded", function() { + var current_test_assertions = []; + + QUnit.testDone(function(result) { + var i, + name = result.module + ': ' + result.name; + + if (result.failed) { + console.log('Assertion Failed: ' + name); + + for (i = 0; i < current_test_assertions.length; i++) { + console.log(' ' + current_test_assertions[i]); + } + } + + current_test_assertions = []; + }); + + QUnit.log(function(details) { + var response; + + if (details.result) { + return; + } + + response = details.message || ''; + + if (typeof details.expected !== 'undefined') { + if (response) { + response += ', '; + } + + response += 'expected: ' + details.expected + ', but was: ' + details.actual; + } + + current_test_assertions.push('Failed assertion: ' + response); + }); + + QUnit.done(function(result){ + console.log('Took ' + result.runtime + 'ms to run ' + result.total + ' tests. ' + result.passed + ' passed, ' + result.failed + ' failed.'); + window.qunitDone = result; + }); + }, false ); +} diff --git a/validation.js b/validation.js new file mode 100644 index 0000000..fd8464c --- /dev/null +++ b/validation.js @@ -0,0 +1,59 @@ +(function (exports) { + "use strict"; + + exports.ListOfEvents = new Events(); + + exports.showError = function (isError, helpText) { + + if (isError) { + if (helpText.style.visibility !== 'visible') { + helpText.style.visibility = 'visible'; + } + return; + } + + if (helpText.style.visibility !== 'hidden') { + helpText.style.visibility = 'hidden'; + } + }; + + exports.validateTitle = function (input, helpText) { + + if (input.length === 0) { + showError(true, helpText); + return false; + } + + showError(false, helpText); + return true; + }; + + exports.validateDate = function (input, helpText) { + + if (!isDate(new Date(input))) { + showError(true, helpText); + return false; + } + + showError(false, helpText); + return true; + }; + + exports.validateNumber = function (input, helpText) { + + if (typeof +input !== "number") { + if (typeof input !== "undefined") { + showError(true, helpText); + return false; + } + } + + if (+input < 0) { + showError(true, helpText); + return false; + } + + showError(false, helpText); + return true; + }; +}(window)); \ No newline at end of file