diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7715e64 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "qunit"] + path = qunit + url = git://github.com/jquery/qunit.git diff --git a/Task/Scripts/BaseEvent.js b/Task/Scripts/BaseEvent.js new file mode 100644 index 0000000..4c1e784 --- /dev/null +++ b/Task/Scripts/BaseEvent.js @@ -0,0 +1,224 @@ +/*global Collection: true*/ +(function (toExport) { + "use strict"; +/** + * Создает оболочку над массивом событий, предоставляющую "sql" подобные операции + * + * @class Оболочка над массивом событий. + * @augments Collection + */ + var BaseEvent = function BaseEvent(events) { + "use strict"; + Collection.call(this, events); + } + + toExport.BaseEvent = BaseEvent; + + BaseEvent.prototype = Object.create(Collection.prototype, { + constructor: { + value: BaseEvent, + enumerable: false, + writable: true, + configurable: true + } + }); +/** + * + *@field {BaseEvent} - ссылка на "родной" конструктор +*/ + BaseEvent.prototype.constructor = BaseEvent; +/** + *@function Возвращает новую оболочку, но уже только с прошедшими событиями + * + *@return {BaseEvent} +*/ + BaseEvent.prototype.pastEventBase = function () { + var currentDate = new Date(); + return this.filter(function (event) { + return event.end.getTime() < currentDate.getTime(); + }); + }; +/** + * @function Возвращает новую оболочку, но уже только с ненаступившими событиями + * + * @return {BaseEvent} +*/ + BaseEvent.prototype.nextEventBase = function () { + var currentDate = new Date(); + return this.filter(function (event) { + return event.start.getTime() > currentDate.getTime(); + }); + }; +/** + * @function Возвращает новую оболочку, но уже с событиями, которые идут в данный момент + * + * @return +*/ + BaseEvent.prototype.nowEventBase = function () { + var currentDate = new Date(); + return this.filter(function (event) { + return (event.start.getTime() <= currentDate.getTime() && event.end.getTime() >= currentDate.getTime()); + }); + }; + +/** + * @function Возвращает новую оболочку, но уже с событиями, в которых участвует определенный человек + * + * @return + */ + BaseEvent.prototype.withFriend = function (myFriend) { + return this.filter(function (event) { + return event.parties.some(function (party) { + return party.name === myFriend.name; + }); + }); + }; +/** + * @function Увеличивает дату на день + * @private + * + * @field {Date} currentDate дата, которую будем увеличивать + * + * @return {Date} + */ + var addDay = function (currentDate) { + return new Date(new Date().getTime() + 24 * 60 * 60 * 1000); + } + +/** + * @function Возвращает новую оболочку, но уже с событиями, которые будут через день + * + * @return {BaseEvent} +*/ + BaseEvent.prototype.getEventAfterDay = function () { + var currentDate = addDay(new Date()); + return this.filter(function (event) { + return event.start.getTime() > currentDate.getTime(); + }); + }; + +/** + * @function Увеличивает дату на неделю + * @private + * + * @field {Date} currentDate дата, которую будем увеличивать + * + * @return {Date} + */ + var addWeek = function (currentDate) { + return new Date(currentDate.getTime() + 7 * 24 * 60 * 60 * 1000); + } + +/** + * @function Возвращает новую оболочку, но уже с событиями, которые будут через неделю + * + * @return {BaseEvent} +*/ + BaseEvent.prototype.getEventAfterWeek = function () { + var currentDate = addWeek(new Date()); + return this.filter(function (event) { + return event.start.getTime() > currentDate.getTime(); + }); + }; + +/** + * @function Увеличивает дату на месяц + * @private + * + * @field {Date} currentDate дата, которую будем увеличивать + * + * @return {Date} + */ + var addMonth = function (currentDate) { + if (currentDate.getMonth() === 11) { + currentDate = new Date(currentDate.getFullYear() + 1, 0, currentDate.getDay()); + } else { + currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, currentDate.getDay()); + } + return currentDate; + } + +/** + * @function Возвращает новую оболочку, но уже с событиями, которые будут через месяц + * + * @return {BaseEvent} +*/ + BaseEvent.prototype.getEventAfterMonth = function () { + var currentDate = addMonth(new Date()); + return this.filter(function (event) { + return event.start.getTime() > currentDate.getTime(); + }); + }; + +/** + * @function Возвращает новую оболочку, но уже с событиями, которые будут в определенный период + * + * @param {Date} fromDate - начала периода + * @param {Date} toDate - конец периода + * + * @return +*/ + BaseEvent.prototype.getEventFromPeriod = function (fromDate, toDate) { + return this.filter(function (event) { + return (event.start.getTime() > fromDate.getTime() && event.end.getTime() < toDate.getTime()); + }); + }; + +/** + * @function Компаратор рейтинга по убыванию + * @private + * + * @field {Date} a + * @field {Date} b + * + * @return {Numeric} + */ + var starsComparer = function compare(a, b) { + if (a.stars > b.stars) { + return -1; + } + if (a.stars < b.stars) { + return 1; + } + return 0; + }; + +/** + * @function Возвращает новую оболочку c теми же событиями, но отсортированными по уменьшению количества звезд + * + * @return {BaseEvent} +*/ + BaseEvent.prototype.sortByStars = function (ascending) { + + return this.sortBy(starsComparer, ascending); + }; + +/** + * @function Компаратор дат по возрастанию + * @private + * + * @field {Date} a + * @field {Date} b + * + * @return {Numeric} + */ + var dateComparer = function (a, b) { + if (a.start.getTime() < b.start.getTime()) { + return -1; + } + if (a.start.getTime() > b.start.getTime()) { + return 1; + } + return 0; + }; + +/** + * @function Возвращает новую оболочку c теми же событиями, но отсортированными по дате + * + * @return {BaseEvent} + */ + BaseEvent.prototype.sortByDate = function (ascending) { + + return this.sortBy(dateComparer, ascending); + }; +}(window)); \ No newline at end of file diff --git a/Task/Scripts/CalendaryErrorManager.js b/Task/Scripts/CalendaryErrorManager.js new file mode 100644 index 0000000..6c9ee6d --- /dev/null +++ b/Task/Scripts/CalendaryErrorManager.js @@ -0,0 +1,71 @@ +(function (toExport) { +/** + * @class Класс содержит обработчики ошибок при изменении элементов DOM связанных с календорем + * @augments DOMErrorManager + */ + + var CalendaryErrorManager = function (errorClassName) { + DOMErrorManager.call(this, errorClassName); + } + + toExport.CalendaryErrorManager = CalendaryErrorManager; + + CalendaryErrorManager.prototype = Object.create(DOMErrorManager.prototype, { + constructor: { + value: Event, + enumerable: false, + writable: true, + configurable: true + } + }); + +/** + * @function Обработчик ошибок объекта, содержащий начальное и конечное время + * + * @param {DOMdivElement} хранилище, содержащее таймер. + */ + CalendaryErrorManager.prototype.changeTime = function (timer) { + var textError = DOMValidator.isTimeInterval(timer); + this.changeTextError(timer, textError); + } + +/** + * @function Обработчик ошибок объекта, содержащий координаты + * + * @param {DOMdivElement} хранилище, содержащее координаты. + */ + CalendaryErrorManager.prototype.changeCoordinate = function (coordinates) { + var textError = DOMValidator.isCoordinate(coordinates); + this.changeTextError(coordinates, textError); + } + +/** + * @function Обработчик ошибок объекта, содержащий важныее данные + * + * @param {DOMdivElement} хранилище, содержащее важное поле. +*/ + CalendaryErrorManager.prototype.changeImportantStringField = function (importantStringField) { + var textError = DOMValidator.isImportantStringField(importantStringField, 5, 20); + this.changeTextError(importantStringField, textError); + } + +/** + * @function Обработчик ошибок объекта, содержащий поле с положительным числом + * + * @param {DOMdivElement} хранилище, содержащее поле с положительным числом. +*/ + CalendaryErrorManager.prototype.changePositiveNumber = function (positiveNumber) { + var textError = DOMValidator.isPositiveNumber(positiveNumber); + this.changeTextError(positiveNumber, textError); + } + +/** + * @function Обработчик ошибок объекта, содержащий поле с рейтингом + * + * @param {DOMdivElement} хранилище, содержащее поле с положительным числом. +*/ + CalendaryErrorManager.prototype.changeStars = function (stars) { + var textError = DOMValidator.isStars(stars); + this.changeTextError(stars, textError); + } +}(window)); \ No newline at end of file diff --git a/Task/Scripts/Collection.js b/Task/Scripts/Collection.js new file mode 100644 index 0000000..aed5a7c --- /dev/null +++ b/Task/Scripts/Collection.js @@ -0,0 +1,71 @@ +/*global Collection: true*/ +(function(toExport) { + "use strict"; +/** + * Создает оболочка для хранения массива объектов с операциями по извлечению более конкретных элементов + * @class Оболочка для храения массива объектов + * + * @param {Array} элементы коллекции +*/ + var Collection = function (otherItems) { + "use strict"; + var item; + this.items = []; + for (item in otherItems) { + if (otherItems.hasOwnProperty(item)) { + this.items.push(otherItems[item]); + } + } + }; + toExport.Collection = Collection; +/** + * @field {Collection} хранит ссылку на родной конструктор +*/ + Collection.prototype.constructor = Collection +/** + * @function создает новую коллекцию элементов с теме же элементами + с новым элементом obj + * + * @return {instanceof this.constructor} +*/ + Collection.prototype.add = function (obj) { + var newEvents = this.items.concat([obj]); + return new this.constructor(newEvents); + }; +/** + * @function создает новую коллекцию элементов с отфильтрованными элементами + * + * @param {Function} - делегат + * + * @return {instanceof this.constructor} +*/ + Collection.prototype.filter = function (selector) { + var newItems = this.items.filter(selector); + return new this.constructor(newItems); + }; +/** +* @function создает новую коллекцию элементов с теме же элементами + с новым элементом obj + * + * @param {Function} - компаратор + * @param {Function} - инвертировать, ли результат + * + * @return {instanceof this.constructor} +*/ + Collection.prototype.sortBy = function (comparator, isInvert) { + var newItems = [].concat(this.items); + if (newItems.length === 0) { + return []; + } + if (comparator) { + if (isInvert) { + newItems.sort(function (a, b) { + return -1 * comparator(a, b); + }); + } else { + newItems.sort(comparator); + } + } else { + newItems.sort(); + } + return new this.constructor(newItems); + }; +}(window)); \ No newline at end of file diff --git a/Task/Scripts/DOMErrorManager.js b/Task/Scripts/DOMErrorManager.js new file mode 100644 index 0000000..b06d7bd --- /dev/null +++ b/Task/Scripts/DOMErrorManager.js @@ -0,0 +1,72 @@ +(function (toExport) { + "use strict"; +/** + * @class * Класс содержит обработчики ошибок при изменении элементов DOM +*/ + var DOMErrorManager = function (errorClassName) { + this.errorClassName = errorClassName; + } + toExport.DOMErrorManager = DOMErrorManager; +/** + * @function Обработчик ошибок объекта, содержащий начальное и конечное время + * @param {DOMdivElement} хранилище, содержащее таймер. +*/ + DOMErrorManager.prototype.isFieldWithError = function (element) { + var lastElement = element.querySelector("."+this.errorClassName); + return !!lastElement; + } +/** + * @function Устанавливает в передаваемый элемент ошибку + * + * @param {DOMdivElement} element на что устанавливаем ошибку. + * @param {String} text текст ошибки. +*/ + DOMErrorManager.prototype.setTextError = function (element, text) { + var newError = document.createElement("span"), + newTextError = document.createTextNode(text); + newError.className = this.errorClassName; + newError.appendChild(newTextError); + element.appendChild(newError); + } +/** + * @function Стереть ошибку + * + * @param {DOMdivElement} element на что устанавливаем ошибку. +*/ + DOMErrorManager.prototype.removeTextError = function (element) { + var error = element.querySelector("."+this.errorClassName); + element.removeChild(error); + } +/** +* @function Изменить или стереть ошибку в зависимости от того есть она или нет +* +* @param {DOMdivElement} element хранилище элемента +* @param {DOMdivElement} element текст сообщения с ошибкой +*/ + DOMErrorManager.prototype.changeTextError = function (element, errorText) { + var currentErrorState = this.isFieldWithError(element); + if (errorText === "") { + if (currentErrorState) { + this.removeTextError(element); + } + } + else + { + if (currentErrorState) { + this.removeTextError(element); + } + this.setTextError(element, errorText); + } + } +/** +* @function Удалить всех детей элемента +* +* @param {DOMdivElement} хранилище детей +*/ + DOMErrorManager.prototype.removeAllChildren = function(element) { + var children = element.childNodes; + while(children.length) { + element.removeChild(children[0]) + } + } +}(window)); \ No newline at end of file diff --git a/Task/Scripts/DOMValidator.js b/Task/Scripts/DOMValidator.js new file mode 100644 index 0000000..7d42bbe --- /dev/null +++ b/Task/Scripts/DOMValidator.js @@ -0,0 +1,139 @@ +(function (toExport) { + "use strict"; +/** +* @function - проверяет является ли передаваемый объект Датой +* @private +* +* @param {Object} element - проверяемый объект +* +* @return {Boolean} +*/ + var isDate = function (element) { + return Event.prototype.dateValidator(element); + }; + +/** +* @function - проверяет является ли передаваемый объект числом +* @private +* +* @param {Object} element - проверяемый объект +* +* @return {Boolean} +*/ + var isNumeric = function(element) { + return !isNaN(parseFloat(element)); + }; + +/** +* @function - проверяет является ли передаваемый объект числом +* @private +* +* @param {Object} element - проверяемый объект +* +* @return {Boolean} +*/ + var isNumeric = function(element) { + return !isNaN(parseFloat(element)); + }; + +/** +* @namespace Пространство имен для DOM обработчиков ошибок +*/ + var DOMValidator = {}; + toExport.DOMValidator = DOMValidator; + +/** +* @field {Function} isTimeInterval - проверяет валидно ли поле содержащее промежуток времени +*/ + DOMValidator.isTimeInterval = function (divWithTimeInterval) { + var startDate = new Date(divWithTimeInterval.querySelector(".StartDate").value); + var finishDate = new Date(divWithTimeInterval.querySelector(".FinishDate").value); + + if (!isDate(startDate) && !isDate(finishDate)) + return "Обе даты некорректны"; + if (!isDate(startDate)) + return "Дата начала события некорректна"; + if (!isDate(finishDate)) + return "Дата конца события некорректна"; + if (startDate.getTime()> finishDate.getTime()) { + return "Даты перепутаны местами"; + } + return ""; + }; + +/** +@field {Function} isCoordinate - проверяет валидно ли поле содержащая координаты двух мерного пространства +*/ + DOMValidator.isCoordinate = function (divWithCoordinates) { + var xCoordinate = divWithCoordinates.querySelector(".XCoordinate").value; + var yCoordinate = divWithCoordinates.querySelector(".YCoordinate").value; + + if (!isNumeric(xCoordinate) && !isNumeric(yCoordinate)) { + return "Обе координаты некорректны"; + } + if (!isNumeric(xCoordinate)) { + return "Координата X - некорректна"; + } + if (!isNumeric(yCoordinate)) { + return "Координата Y - некорректна"; + } + return ""; + }; + +/** +* @field {Function} isTimeInterval - проверяет валидно ли поле содержащее промежуток времени +*/ + DOMValidator.isImportantStringField = function (divWithImportantStringField, minSize, maxSize) { + minSize = minSize || 0; + maxSize = maxSize || -1; + if (minSize < 0) { + minSize = 0; + } + if (minSize > maxSize) { + maxSize = -1; + } + var importantStringField = divWithImportantStringField.querySelector(".ImportantStringField").value; + if (maxSize != -1) { + if (minSize > importantStringField.length || maxSize < importantStringField.length) { + return "Поле должно содержать от " + minSize + " до " + maxSize + "символов"; + } + } + else { + if (minSize > importantStringField.length) { + return "Поле должно содержать как минимум " + minSize + " символов"; + } + } + return ""; + }; + +/** +* @field {Function} isStars - проверяет валидно ли поле содержащее рейтинг +*/ + DOMValidator.isStars = function (divWithStarField) { + var starsField = parseFloat(divWithStarField.querySelector(".StarsField").value); + if (isNaN(starsField)) { + return "В поле введено не число"; + } + if (starsField < 0 || starsField > 5) { + return "Количество звезд 0-5"; + } + if (parseInt(starsField) !== starsField) { + return "Количество звезд целое число"; + } + return ""; + }; + +/** +* @field {Function} isPositiveNumber - проверяет валидно ли поле содержащее целое положительное число +*/ + DOMValidator.isPositiveNumber = function (divWithPositiveNumberField) { + var positiveNumberField = divWithPositiveNumberField.querySelector(" .PositiveNumber").value; + if (!isNumeric(positiveNumberField)) { + return "В поле введено не число"; + } + if (parseFloat(positiveNumberField) < 0) { + return "В поле введено отрицательное число"; + } + return ""; + }; +}(window)); \ No newline at end of file diff --git a/Task/Scripts/Event.js b/Task/Scripts/Event.js new file mode 100644 index 0000000..d5d10b7 --- /dev/null +++ b/Task/Scripts/Event.js @@ -0,0 +1,142 @@ +/*global Model: true*/ +(function (toExport) { + "use strict"; +/** + * Создает новое событие в календаре + * @class Событие в календаре + * @augments Model + * + * @field {Number} - id Индификационный номер объекта по идее тут должен быть GUID + * @field {Object} - location объект содержащий локационные данные о событии + название события + * @field {Number} - реитинг + * @field {Number} - Цена посещения +*/ + var Event = function Event(data) { + "use strict"; + this.id = Math.random(); + this.location = { + "gps": {x: 0, y: 0}, + "nameLocation": "Earth" + }; + this.stars = 0; + this.cost = 0; + this.parties = []; + Model.call(this, data); + this.validate(this); + this.setLocation(this.location.gps, this.location.nameLocation); + this.stars = this.leaveMark(this.stars); + } + toExport.Event = Event; + Event.prototype = Object.create(Model.prototype, { + constructor: { + value: Event, + enumerable: false, + writable: true, + configurable: true + } + }); +/** + * @function Функция, проверяющая корректность даты + * + * @return {bool} +*/ + Event.prototype.dateValidator = function (date) { + "use strict"; + if (Object.prototype.toString.call(date) === "[object Date]") { + if (!isNaN(date.getTime())) { + return true; + } + } + return false; + }; +/** + * @function Проверяет на корректность координаты + * @private + * + * @field coordinate координаты в дву мерном пространстве + * @field name название события + * @filed {Boolean} +*/ + var isCorrectedCoordinate = function (coordinate, name) { + var isType = typeof coordinate !== "undefined" && typeof name === "string"; + if (!isType) { + return false; + } + var isX = typeof coordinate.x === "number"; + var isY = typeof coordinate.y === "number"; + return isX && isY; + } +/** + * @function set-ер установления локации события + * + * @field gps координаты в дву мерном пространстве + * @field название события +*/ + Event.prototype.setLocation = function (gps, name) { + + if (isCorrectedCoordinate(gps, name)) { + this.location.gps = gps; + this.location.nameLocation = name; + } else { + this.location = { + "gps" : {"x" : 0, "y" : 0}, + "nameLocation" : "Earth" + }; + } + }; +/** + * @function Коррекция значения рейтинга + * + * @return {Number} 0,1,2,3,4,5 +*/ + Event.prototype.leaveMark = function (stars) { + if (isNaN(parseFloat(stars)) || + !isFinite(stars) || + stars < 0) { + stars = 0; + } + if (stars > 5) { + stars = 5; + } + stars = Math.floor(stars); + return stars; + }; +/** + * @function Проверяет объект на корректность + * + * @field {Event} event - то что проверяем +*/ + Event.prototype.validate = function (event) { + if (event.cost < 0) { + throw new Error("Цена за вход не может быть отрицательной"); + } + if (!Array.isArray(event.parties)) { + throw new Error("Участники - это массив"); + } + var existsSomePartyWithoutNameField = event.parties.some(function (party) { + return !party.name; + }); + if (existsSomePartyWithoutNameField) { + throw new Error("У одного из участников нет поля <ИМЯ>"); + } + if (event.end < event.start) { + throw new Error("Даты начала и конца перепутаны"); + } + }; +/** + * @function Функция, печатающие значение локационных данных объекта + * + * @return {String} [location], (x, y) +*/ + Event.prototype.locationToString = function() { + return this.location.nameLocation + ", (" + this.location.gps.x + ";" + this.location.gps.y + ")"; + } +/** + * @function Функция, печатающие значение рейтинга в звездочках + * + * @return {String} ,*,**,***,****,***** +*/ + Event.prototype.starsToString= function() { + return new Array(this.stars + 1).join('*');; + } +}(window)); \ No newline at end of file diff --git a/Task/Scripts/Model.js b/Task/Scripts/Model.js new file mode 100644 index 0000000..4a8f174 --- /dev/null +++ b/Task/Scripts/Model.js @@ -0,0 +1,53 @@ +(function (toExport) { + "use strict"; +/** + * @class Абстрактный класс объектов ООП + * + * @param {data} - копируемый объект +*/ + var Model = function (data) { + var nameField; + for (nameField in data) { + this[nameField] = data[nameField]; + } + }; + toExport.Model = Model; + +/** + * @function setter + * + * @param {Object} - присваиваемый объект +*/ + Model.prototype.set = function (attributes) { + var nameAttr; + for (nameAttr in attributes) { + if (attributes.hasOwnProperty(nameAttr)) { + if (typeof this[nameAttr] !== "undefined") { + this[nameAttr] = attributes[nameAttr]; + } + } + } + }; + +/** + * @function getter + * + * @param {String} имя поля + * + * @return {Object} +*/ + Model.prototype.get = function (attribute) { + if (typeof attribute !== 'string' || typeof this[attribute] === "undefined") { + return; + } + return this[attribute]; + }; + +/** + * @function Проверяющая коррекцию объекта +*/ + Model.prototype.validate = function () { + "use strict"; + throw new Error('this is Abstract method'); + }; +}(window)); \ No newline at end of file diff --git a/Task/Scripts/calendary.js b/Task/Scripts/calendary.js new file mode 100644 index 0000000..1e7e1af --- /dev/null +++ b/Task/Scripts/calendary.js @@ -0,0 +1,254 @@ +/*global document: true*/ +/*global initTestBase: true*/ +/*global CalendaryErrorManager: true*/ +(function (toExport) { + "use strict"; +/** + * @namespace Пространство имен для календаря + * + * @field {EventFactory} объект, хранящий ссылки на inputы необходимые для создания нового события + * @field eventList ссылка на дом объект, хранящий список событий + * @field eventBase все события пользователя + * @field errorManager объект хранящий функции для валидации полей в дом и хранящий в себе некоторые тривиальные операции + * @field currentFilters фильтры наложенные на текущие события + */ + var Calendary = function () { + this.whois = "Alex.Mangin"; + this.EventFactory = { + "timer" : document.getElementById("NewEventTimeInterval"), + "nameLocation" : document.getElementById("NewEventNameLocation"), + "coordinate" : document.getElementById("NewEventCoordinate"), + "stars" : document.getElementById("NewEventStars"), + "cost" : document.getElementById("NewEventCost"), + "parties" : document.querySelector("#NewEventPartiesList ol") + }; + this.eventList = document.getElementById("eventList"); + this.eventBase = initTestBase(); + this.errorManager = new CalendaryErrorManager("Error"); + this.currentFilters = []; + } + toExport.Calendary = Calendary; +/** + * @function - функция, возвращающая текущую базу событий, но с наложенными фильтрами + * + * @param {[Function]} фильтры в виде функции + * + * @return {BaseEvent} +*/ + Calendary.prototype.ApplyFilter = function (filters) { + var base = this.eventBase, + i; + for (i = 0; i < filters.length; i = i + 1) { + base = filters[i].call(base); + } + return base; + } +/** + * @function - функция пытается создать событие из данных с формы +*/ + Calendary.prototype.CreateEvent = function () { + var parties = [], + partyList, + i, + eventDate, + inputs, + errors, + docfrag, + io, + input; + if (!this.isCorrecteNeedFields()) { + this.changeNeed(); + this.changeAddition(); + return + } + if (!this.isCorrecteAdditionFields()) { + if (!confirm('Некоторые незначительные поля некорректны, продолжить?')) { + this.changeAddition(); + return; + } + } + partyList = this.EventFactory.parties.querySelectorAll(" input"); + for ( i = 0; i < partyList.length; i = i + 1) { + if (partyList[i].value && partyList[i].value !== "") { + parties.push({"name" : partyList[i].value}); + } + } + eventDate = { + "id" : Math.random(), + "location" : { + "gps": { + "x": parseFloat(this.EventFactory.coordinate.querySelector(" .XCoordinate").value), + "y": parseFloat(this.EventFactory.coordinate.querySelector(" .YCoordinate").value) + }, + "nameLocation": this.EventFactory.nameLocation.querySelector("input").value, + }, + "stars" : parseFloat(this.EventFactory.stars.querySelector("input").value), + "cost" : parseFloat(this.EventFactory.cost.querySelector("input").value), + "start": new Date(this.EventFactory.timer.querySelector(".StartDate").value), + "end": new Date(this.EventFactory.timer.querySelector(".FinishDate").value), + "parties" : parties + } + if (DOMValidator.isCoordinate(this.EventFactory.coordinate)) { + eventDate.location.gps.x = 0; + eventDate.location.gps.y = 0; + } + if (DOMValidator.isStars(this.EventFactory.stars)) { + eventDate.stars = 0; + } + if (DOMValidator.isPositiveNumber(this.EventFactory.cost)) { + eventDate.cost = 0; + } + this.eventBase = this.eventBase.add(new Event(eventDate)); + inputs = document.querySelectorAll('#eventFactory input'); + for (i = 0; i < inputs.length; i = i + 1) { + if (inputs[i].type === "text" || inputs[i].type === "date") { + inputs[i].value = ""; + } + } + errors = document.querySelectorAll('#eventFactory .Error'); + for (i = 0; i < errors.length; i = i + 1) { + errors[i].parentElement.removeChild(errors[i]); + } + this.errorManager.removeAllChildren(this.EventFactory.parties); + docfrag = document.createDocumentFragment() + io = document.createElement("li"); + input = document.createElement("input"); + input.type = "text"; + io.appendChild(input); + for (i = 0; i < 3; i = i + 1) { + docfrag.appendChild(io.cloneNode(true)); + } + this.EventFactory.parties.appendChild(docfrag); + } +/** + * @function - функция обновляет отфильтрованный список со всеми наложенными фильтрами +*/ + Calendary.prototype.UpdateShowList = function () { + var createEventRow = function (number, event) { + var row = (function createRow() { + var rowTable = document.createElement("tr"), + cellTable = document.createElement("td"), + i; + for (i = 0; i < 7; i = i + 1) { + rowTable.appendChild(cellTable.cloneNode(false)); + } + return rowTable; + }()), + listParty, + n, + aDOMParty, + i; + row.children[0].appendChild(document.createTextNode(number)); + row.children[1].appendChild(document.createTextNode(event.locationToString())); + row.children[2].appendChild(document.createTextNode(event.starsToString())); + row.children[3].appendChild(document.createTextNode(event.start.toDateString())); + row.children[4].appendChild(document.createTextNode(event.end.toDateString())); + row.children[5].appendChild(document.createTextNode(event.cost + " $")); + listParty = document.createElement("select"); + for (i = 0; i < event.parties.length; i += 1) { + aDOMParty = document.createElement("option"); + aDOMParty.appendChild(document.createTextNode(event.parties[i].name)); + listParty.appendChild(aDOMParty); + } + if (event.parties.length) { + row.children[6].appendChild(listParty); + } + return row; + }, + newEventList, + currentBase, + i, + event; + this.errorManager.removeAllChildren(this.eventList); + newEventList = document.createDocumentFragment(); + currentBase = this.ApplyFilter(this.currentFilters); + for (i = 0; i < currentBase.items.length; i = i + 1) { + event = currentBase.items[i]; + newEventList.appendChild(createEventRow(i + 1, event)); + } + this.eventList.appendChild(newEventList); + } +/** + * @function функция вызывает обработчики ошибок необходимых полей +*/ + Calendary.prototype.changeNeed = function () { + this.errorManager.changeTime(this.EventFactory.timer); + this.errorManager.changeImportantStringField(this.EventFactory.nameLocation); + } +/** + * @function функция вызывает обработчики ошибок необязательных полей +*/ + Calendary.prototype.changeAddition = function () { + this.errorManager.changeCoordinate(this.EventFactory.coordinate); + this.errorManager.changePositiveNumber(this.EventFactory.cost); + this.errorManager.changeStars(this.EventFactory.stars); + } +/** + * @function функция проверяет корректность необходимых полей +*/ + Calendary.prototype.isCorrecteNeedFields = function () { + return DOMValidator.isTimeInterval(this.EventFactory.timer) === "" && + DOMValidator.isImportantStringField(this.EventFactory.nameLocation) === ""; + } +/** + * @function функция проверяет корректность дополнительных полей +*/ + Calendary.prototype.isCorrecteAdditionFields = function () { + return DOMValidator.isCoordinate(this.EventFactory.coordinate) === "" && + DOMValidator.isStars(this.EventFactory.stars) === "" && + DOMValidator.isPositiveNumber(this.EventFactory.cost) === ""; + } +/** + * @function функция добавляет дополнительное поле в коллекцию друзей + * @param {DIVdomElement} хранилище коллекции друзей +*/ + Calendary.prototype.addFriend = function (li) { + var newParty = document.createElement("li"), + input = document.createElement("input"); + input.type = "text"; + newParty.appendChild(input); + li.appendChild(newParty); + } +/** + * @function функция, обновляющая данные фильтра из DOM +*/ + Calendary.prototype.updateFilter = function () { + var filterRadios = document.querySelectorAll("#FilterEventList input[type = radio]"), + oldFilters = this.currentFilters, + newFilters = [], + i, + radioButton, + partys, + nonEmptyParty, + partyFilter; + for (i = 0; i < filterRadios.length; i = i + 1) { + radioButton = filterRadios[i]; + if (radioButton.checked && + radioButton.checked === true && + radioButton.value != "None") { + var nameFunc = radioButton.value.toString(); + newFilters.push(function() { + return this[nameFunc](); + }); + } + } + partys = document.querySelectorAll("#FilterFriens input"); + nonEmptyParty = []; + for (i = 0; i < partys.length; i = i + 1) { + if (partys[i].value != "") { + nonEmptyParty.push(partys[i].value); + } + } + partyFilter = function() { + var base = this, i + for (i = 0; i < nonEmptyParty.length; i = i + 1) { + base = base.withFriend({ + "name": nonEmptyParty[i] + }); + } + return base; + } + newFilters.push(partyFilter); + this.currentFilters = newFilters; + } +}(window)); \ No newline at end of file diff --git a/Task/Scripts/run.js b/Task/Scripts/run.js new file mode 100644 index 0000000..b5b85c7 --- /dev/null +++ b/Task/Scripts/run.js @@ -0,0 +1,42 @@ +/** + * + * + * @author Alex.Mangin + */ +(function (){ + var calendary = new Calendary(); + calendary.UpdateShowList(); + calendary.EventFactory.timer.addEventListener('blur', function() { + calendary.errorManager.changeTime(this); + }, true); + calendary.EventFactory.nameLocation.addEventListener('blur', function() { + calendary.errorManager.changeImportantStringField(this); + }, true); + calendary.EventFactory.coordinate.addEventListener('blur', function() { + calendary.errorManager.changeCoordinate(this); + }, true); + calendary.EventFactory.stars.addEventListener('blur', function() { + calendary.errorManager.changeStars(this); + }, true); + calendary.EventFactory.cost.addEventListener('blur', function() { + calendary.errorManager.changePositiveNumber(this); + }, true); + document.getElementById("SubmitNewEventButton").addEventListener('click', function() { + calendary.CreateEvent(); + calendary.UpdateShowList(); + }, false); + document.getElementById("AddFriend").addEventListener('click', function() { + calendary.addFriend(calendary.EventFactory.parties); + }, false); + var filterRadios =document.querySelectorAll("#FilterEventList input[type = radio]"); + for(var i = 0; i < filterRadios.length; i = i + 1) { + filterRadios[i].addEventListener('click', function() { + calendary.updateFilter(); + calendary.UpdateShowList(); + }) + } + document.getElementById("FIlterFreshPeopleList").addEventListener('blur', function() { + calendary.updateFilter(); + calendary.UpdateShowList(); + }, true); +}()); \ No newline at end of file diff --git a/Task/Scripts/test/BaseEventTest.html b/Task/Scripts/test/BaseEventTest.html new file mode 100644 index 0000000..be489e2 --- /dev/null +++ b/Task/Scripts/test/BaseEventTest.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + +

QUnit test env

+

+

+
    + + \ No newline at end of file diff --git a/Task/Scripts/test/BaseEventTest.js b/Task/Scripts/test/BaseEventTest.js new file mode 100644 index 0000000..08a2f05 --- /dev/null +++ b/Task/Scripts/test/BaseEventTest.js @@ -0,0 +1,272 @@ +/*global module: true*/ +/*global test: true*/ +/*global ok: true*/ +/*global equal: true*/ +/*global initTestBase: true*/ +/*global Event: true*/ +module("test simple SQL"); +test('add()', function () { + "use strict"; + var testBase = new BaseEvent([]), RealDate = Date, pastEventbase; + Date = function () { + return new RealDate("September 13, 2012 12:00:00"); + }; + testBase = testBase.add(new Event({"start": new Date(1),"end": new Date(2), "location":{"nameLocation":"123", "gps":{"x":1,"y":2}}})); + equal(testBase.items.length, 1); + ok(testBase instanceof BaseEvent); + ok(testBase instanceof Collection); + ok(true, true); +}); +test('pastEventBase()', function () { + "use strict"; + var testBase = initTestBase(), RealDate = Date, pastEventbase; + Date = function () { + return new RealDate("September 13, 2012 12:00:00"); + }; + pastEventbase = testBase.pastEventBase(); + equal(pastEventbase.items.length, 2); + ok(pastEventbase.items.some(function (event) { + return event.id === 15; + })); + ok(pastEventbase.items.some(function (event) { + return event.id === 17; + })); + Date = RealDate; +}); +test('nextEventBase()', function () { + "use strict"; + var testBase = initTestBase(), RealDate = Date, nextEventBase; + Date = function () { + return new RealDate("November 1, 2012 12:00:00"); + }; + nextEventBase = testBase.nextEventBase(); + equal(nextEventBase.items.length, 2); + ok(nextEventBase.items.some(function (event) { + return event.id === 19; + })); + ok(nextEventBase.items.some(function (event) { + return event.id === 20; + })); + Date = RealDate; +}); +test('nowEventBase()', function () { + "use strict"; + var testBase = initTestBase(), RealDate = Date, nowEventbase; + Date = function () { + return new RealDate("September 13, 2012 12:00:00"); + }; + nowEventbase = testBase.nowEventBase(); + equal(nowEventbase.items.length, 1); + ok(nowEventbase.items.some(function (event) { + return event.id === 16; + })); + Date = RealDate; +}); +test('withFriend("Alexander.Mangin")', function () { + "use strict"; + var testBase = initTestBase(), eventWithFriendBase = testBase.withFriend({name: "Alexander.Mangin"}); + equal(eventWithFriendBase.items.length, 1); + ok(eventWithFriendBase.items.some(function (event) { + return event.id === 16; + })); +}); +test('getEventAfterMonth()', function () { + "use strict"; + var testBase = initTestBase(), RealDate = Date, eventAfterMonthbase; + Date = function (param1, param2, param3) { + if (param1 && param2 && param3) { + return new RealDate(param1, param2, param3); + } + return new RealDate("October 1, 2012 12:00:00"); + }; + eventAfterMonthbase = testBase.getEventAfterMonth(); + equal(eventAfterMonthbase.items.length, 2); + ok(eventAfterMonthbase.items.some(function (event) { + return event.id === 19; + })); + ok(eventAfterMonthbase.items.some(function (event) { + return event.id === 20; + })); + Date = RealDate; +}); +test('getEventAfterDay()', function () { + "use strict"; + var testBase = initTestBase(), RealDate = Date, eventAfterDaybase; + Date = function (param1, param2, param3) { + if (param1 && param2 && param3) { + return new RealDate(param1, param2, param3); + } + return new RealDate("November 1, 2012 12:00:00"); + }; + eventAfterDaybase = testBase.getEventAfterDay(); + equal(eventAfterDaybase.items.length, 2); + ok(eventAfterDaybase.items.some(function (event) { + return event.id === 19; + })); + ok(eventAfterDaybase.items.some(function (event) { + return event.id === 20; + })); + Date = RealDate; +}); +test('getEventAfterWeek()', function () { + "use strict"; + var testBase = initTestBase(), RealDate = Date, eventAfterWeekbase; + Date = function (param1) { + if (param1) { + return new RealDate(param1); + } + return new RealDate("October 28, 2012 12:00:00"); + }; + eventAfterWeekbase = testBase.getEventAfterWeek(); + equal(eventAfterWeekbase.items.length, 1); + ok(eventAfterWeekbase.items.some(function (event) { + return event.id === 19; + })); + Date = RealDate; +}); +test('getEventFromPeriod(from,to)', function () { + "use strict"; + var testBase = initTestBase(), result; + result = testBase.getEventFromPeriod(new Date("September 12 2012 00:00:00"), new Date("September 14 2012 00:00:00")); + equal(result.items.length, 1); + ok(result.items.some(function (event) { + return event.id === 16; + })); +}); +test('sortByStar()', function () { + "use strict"; + var testBase = initTestBase(), sortByStarsEventbase = testBase.sortByStars(); + equal(testBase.items.length, sortByStarsEventbase.items.length); + ok(sortByStarsEventbase.items[0].id === 18); + ok(sortByStarsEventbase.items[1].id === 19); + ok(sortByStarsEventbase.items[2].id === 17); +}); +test('sortByDate()', function () { + "use strict"; + var testBase = initTestBase(), sortByDateEventbase = testBase.sortByDate(); + equal(testBase.items.length, sortByDateEventbase.items.length); + ok(sortByDateEventbase.items[0].id === 15); + ok(sortByDateEventbase.items[1].id === 17); +}); +function initTestBase() { + "use strict"; + var bestOfSweetsDateStart = new Date("October 10, 2012 00:00:00"), + bestOfSweetsDateFinish = new Date("October 14, 2012 23:59:59"), + bestOfSweets = new Event({"start": bestOfSweetsDateStart, "end": bestOfSweetsDateFinish, "name": "BestOfSweets", "id": 1}), + сirioDeNazareDateStart = new Date("October 8, 2012 00:00:00"), + сirioDeNazareDateFinish = new Date("October 15, 2012 23:59:59"), + сirioDeNazare = new Event({"start": сirioDeNazareDateStart, "end": сirioDeNazareDateFinish, "name": "Cirio De Nazare", "id": 2}), + vinesDayDateStart = new Date("October 4, 2012 00:00:00"), + vinesDayDateFinish = new Date("October 6, 2012 23:59:59"), + vinesDay = new Event({"start": vinesDayDateStart, "end": vinesDayDateFinish, "name": "День вина", "id": 3}), + theBlackCountryDateStart = new Date("October 31, 2012 00:00:00"), + theBlackCountryDateFinish = new Date("November 1, 2012 23:59:59"), + theBlackCountry = new Event({"start": theBlackCountryDateStart, "end": theBlackCountryDateFinish, "name": 'Вкус "Черной страны"', "id": 4}), + oktoberFestDateStart = new Date("September 24, 2012 00:00:00"), + oktoberFestDateFinish = new Date("October 8, 2012 23:59:59"), + oktoberFest = new Event({"start": oktoberFestDateStart, "end": oktoberFestDateFinish, "name": 'OktoberFest', "id": 5}), + francfurtBookDateStart = new Date("October 15, 2012 00:00:00"), + francfurtBookDateFinish = new Date("October 20, 2012 23:59:59"), + francfurtBook = new Event({"start": francfurtBookDateStart, "end": francfurtBookDateFinish, "name": 'Франкфуртская международная книжная ярмарка', "id": 6}), + aidaDateStart = new Date("October 12, 2012 00:00:00"), + aidaDateFinish = new Date("October 27, 2012 23:59:59"), + aida = new Event({"start": aidaDateStart, "end": aidaDateFinish, "name": '"Аида" у великих пирамид, Гиза', "id": 7}), + paradeOfLoveDateStart = new Date("October 3, 2012 14:00:00"), + paradeOfLoveDateFinish = new Date("October 3, 2012 22:00:00"), + paradeOfLove = new Event({"start": paradeOfLoveDateStart, "end": paradeOfLoveDateFinish, "name": 'Парад любви', "id": 8}), + sukkotDateStart = new Date("October 3, 2012 00:00:00"), + sukkotDateFinish = new Date("October 3, 2012 23:59:59"), + sukkot = new Event({"start": sukkotDateStart, "end": sukkotDateFinish, "name": 'Парад любви', "id": 9}), + fishFestivalDateStart = new Date("October 15, 2012 00:00:00"), + fishFestivalDateFinish = new Date("October 15, 2012 23:59:59"), + fishFestival = new Event({"start": fishFestivalDateStart, "end": fishFestivalDateFinish, "name": 'Фестиваль рыбы', "id": 10}), + chocolateFestivalDateStart = new Date("October 19, 2012 00:00:00"), + chocolateFestivalDateFinish = new Date("October 28, 2012 23:59:59"), + chocolateFestival = new Event({"start": chocolateFestivalDateStart, "end": chocolateFestivalDateFinish, "name": 'Фестиваль "Еврошоколад"', "id": 11}), + digitalArtFestivalDateStart = new Date("September 19, 2012 00:00:00"), + digitalArtFestivalDateFinish = new Date("September 28, 2012 23:59:59"), + digitalArtFestival = new Event({"start": digitalArtFestivalDateStart, "end": digitalArtFestivalDateFinish, "name": 'Фестиваль цифрового исскуства', "id": 12}), + fatherDaysDateStart = new Date("September 18, 2012 00:00:00"), + fatherDaysDateFinish = new Date("September 19, 2012 23:59:59"), + fatherDays = new Event({"start": fatherDaysDateStart, "end": fatherDaysDateFinish, "name": 'Дни наследия', "id": 13}), + bearWeekendDateStart = new Date("September 18, 2012 00:00:00"), + bearWeekendDateFinish = new Date("September 19, 2012 23:59:59"), + bearWeekend = new Event({"start": bearWeekendDateStart, "end": bearWeekendDateFinish, "name": 'Bear Weekends', "id": 14}), + teaFestivalDateStart = new Date("September 1, 2012 00:00:00"), + teaFestivalDateFinish = new Date("September 1, 2012 23:59:59"), + teaFestival = new Event({"start": teaFestivalDateStart, "end": teaFestivalDateFinish, "name": 'Фестиваль Чая', "id": 15}), + programmerDayDateStart = new Date("September 13, 2012 00:00:00"), + programmerDayDateFinish = new Date("September 13, 2012 23:59:59"), + programmerDay = new Event({"start": programmerDayDateStart, "end": programmerDayDateFinish, "name": 'День программмиста', "id": 16}), + knowDayDateStart = new Date("September 1, 2012 00:00:01"), + knowDayDateDateFinish = new Date("September 1, 2012 23:59:59"), + knowDayDate = new Event({"start": knowDayDateStart, "end": knowDayDateDateFinish, "name": 'День знаний', "id": 17, "stars": 1}), + teacherDayDateStart = new Date("October 5, 2012 00:00:00"), + teacherDayDateFinish = new Date("October 5, 2012 23:59:59"), + teacherDay = new Event({"start": teacherDayDateStart, "end": teacherDayDateFinish, "name": 'День учителя', "id": 18, "stars": 5}), + securiteDayDateStart = new Date("November 5, 2012 00:00:00"), + securiteDayDateFinish = new Date("November 5, 2012 23:59:59"), + securiteDay = new Event({"start": securiteDayDateStart, "end": securiteDayDateFinish, "name": 'День защиты информации', "id": 19, "stars": 3}), + nationUnitionDateStart = new Date("November 4, 2012 00:00:00"), + nationUnitionDateDateFinish = new Date("November 4, 2012 23:59:59"), + nationUnition = new Event({"start": nationUnitionDateStart, "end": nationUnitionDateDateFinish, "name": 'День нароного единства', "id": 20}); + bestOfSweets.setLocation({"gps": { + "x": 15, "y": 189}, "name": "Австрия, Бургенланд - Айзенштадте, Фестиваль сладких вин"}); + + сirioDeNazare.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Бразилия, Белен, Фестиваль Cirio De Nazare"}); + + vinesDay.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Венгрия, Мор, День вина"}); + + theBlackCountry.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Великобритания, Дадли, Вкус 'Черной страны'"}); + + oktoberFest.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Германия, Мюнхен, OktoberFest"}); + + programmerDay.parties = [{name: "Pupkin"}, {"name": "Alex.IDontKnow"}]; + francfurtBook.setLocation({"gps": { + x : 45, y : 133}, "name" : "Германия, Frankfurt, Франкфуртская международная книжная ярмарка"}); + + aida.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Египет, ?, Аида у великих пирамид, Гиза"}); + + paradeOfLove.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Израль, Тель-Авиве, Парад любви"}); + + sukkot.setLocation({"gps": { + "x": 45, y : 133}, "name": "Израль, Иерусалиме, праздник Суккот"}); + + fishFestival.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Испания, О Грове, Фестиваль рыбы"}); + + chocolateFestival.setLocation({"gps": { + "x": 45, "y": 133}, "name": 'Италия, Перуджа, Фестиваль "Еврошоколад"'}); + + digitalArtFestival.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Австрия, Линц, Фестиваль Цифрового Исскуства"}); + + fatherDays.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Бельгия, Антверпене, Дни наследия"}); + + bearWeekend.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Бельгия, Брюссель, Bear Weekends"}); + + teaFestival.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Россия, Москва, Фестиваль чая"}); + programmerDay.setLocation({"gps" :{ + "x": 45, "y": 133}, "name": "Вселенная, Земля, День программиста"}); + programmerDay.parties = [{name: "Alexander.Mangin"}, {"name": "Alex.IDontKnow"}]; + knowDayDate.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Вселенная, Земля, День знаний"}); + teacherDay.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Вселенная, Земля, День учителя"}); + securiteDay.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Вселенная, Земля, День защиты информации"}); + nationUnition.setLocation({"gps": { + "x": 45, "y": 133}, "name": "Вселенная, Земля, День народного единства"}); +return new BaseEvent([bestOfSweets, сirioDeNazare, vinesDay, theBlackCountry, oktoberFest, francfurtBook + , aida, paradeOfLove, sukkot, fishFestival, chocolateFestival, digitalArtFestival, fatherDays, + bearWeekend, teaFestival, programmerDay, knowDayDate, teacherDay, securiteDay, nationUnition]); +} \ No newline at end of file diff --git a/Task/Scripts/test/CollectionTest.html b/Task/Scripts/test/CollectionTest.html new file mode 100644 index 0000000..92d77b3 --- /dev/null +++ b/Task/Scripts/test/CollectionTest.html @@ -0,0 +1,15 @@ + + + + + + + + + +

    QUnit test env

    +

    +

    +
      + + \ No newline at end of file diff --git a/Task/Scripts/test/CollectionTest.js b/Task/Scripts/test/CollectionTest.js new file mode 100644 index 0000000..6e7b14c --- /dev/null +++ b/Task/Scripts/test/CollectionTest.js @@ -0,0 +1,76 @@ +/*global module: true*/ +/*global test: true*/ +/*global ok: true*/ +/*global equal: true*/ +/*global deepEqual: true*/ +/*global initTestBase: true*/ +/*global Event: true*/ +/*global Collection: true*/ +module("Конструктор"); +test("Конструктор", function () { + "use strict"; + var newCollection = new Collection([1, 2, 3, 4]); + deepEqual(newCollection.items, [1, 2, 3, 4]); +}); +module("Add(model)"); +test("Добавление элемента в пустую коллекцию", function () { + "use strict"; + var newCollection = new Collection(); + newCollection = newCollection.add(1); + deepEqual(newCollection.items, [1]); +}); +test("Добавление элемента в не пустую коллекцию", function () { + "use strict"; + var newCollection = new Collection([2]); + newCollection = newCollection.add(1); + deepEqual(newCollection.items, [2, 1]); +}); +module("filter(function)"); +test("Пример использование filter", function () { + "use strict"; + var newCollection = new Collection([1, 2, 3, 4, 5, 6]); + newCollection = newCollection.filter(function (element) {return (element % 2 === 0); }); + + deepEqual(newCollection.items, [2, 4, 6]); +}); +module("sortBy(function)"); +test("С использование своего компаратора, без инвертирования результата", function () { + "use strict"; + var newCollection = new Collection([{"id": 8}, {"id": 2}, {"id": 3}, + {"id": 4}, {"id": 14}, {"id": 9}]), + comparator = function (a, b) { + if (a.id > b.id) { + return 1; + } + if (a.id < b.id) { + return -1; + } + return 0; + }; + newCollection = newCollection.sortBy(comparator); + deepEqual(newCollection.items, [{"id": 2}, {"id": 3}, {"id": 4}, + {"id": 8}, {"id": 9}, {"id": 14}]); +}); +test("С использование своего компаратора, c инвертированием результата", function () { + "use strict"; + var newCollection = new Collection([{"id": 8}, {"id": 2}, {"id": 3}, + {"id": 4}, {"id": 14}, {"id": 9}]), + comparator = function (a, b) { + if (a.id > b.id) { + return 1; + } + if (a.id < b.id) { + return -1; + } + return 0; + }; + newCollection = newCollection.sortBy(comparator, true); + deepEqual(newCollection.items, [{"id": 14}, {"id": 9}, {"id": 8}, + {"id": 4}, {"id": 3}, {"id": 2}]); +}); +test("Сортировка по default", function () { + "use strict"; + var newCollection = new Collection([3, 2, 1]); + newCollection = newCollection.sortBy(); + deepEqual(newCollection.items, [1, 2, 3]); +}); \ No newline at end of file diff --git a/Task/Scripts/test/EventTest.html b/Task/Scripts/test/EventTest.html new file mode 100644 index 0000000..8fb416e --- /dev/null +++ b/Task/Scripts/test/EventTest.html @@ -0,0 +1,16 @@ + + + + + + + + + + +

      QUnit test env

      +

      +

      +
        + + \ No newline at end of file diff --git a/Task/Scripts/test/EventTest.js b/Task/Scripts/test/EventTest.js new file mode 100644 index 0000000..681b30e --- /dev/null +++ b/Task/Scripts/test/EventTest.js @@ -0,0 +1,124 @@ +/*global module: true*/ +/*global test: true*/ +/*global ok: true*/ +/*global equal: true*/ +/*global deepEqual: true*/ +/*global initTestBase: true*/ +/*global Event: true*/ +/*global Collection: true*/ +/*global throws: true*/ +module("Tests of Event's constructor"); +test('Create event', function () { + "use strict"; + var dateToString = function (currentTime) { + var month = currentTime.getMonth() + 1, day = currentTime.getDate(), year = currentTime.getFullYear(); + return month + "/" + day + "/" + year; + }, currentTime = new Date(), testEvent = new Event({"start": currentTime}); + equal(dateToString(testEvent.start), dateToString(currentTime)); + testEvent = new Event({"start": new Date(1), "end": new Date(2)}); + ok(testEvent.start.getTime() < testEvent.end.getTime()); + throws(function () { + new Event({"start": new Date(2), "end": new Date(1)}); + }, + 'Error("Даты начала и конца перепутаны")' + ); + throws(function () { + new Event({"cost": -1}); + }, + 'Error("Цена за вход не может быть отрицательной")' + ); + throws(function () { + new Event({"parties": "NoArray"}); + }, + 'Error("Участники - это массив")' + ); + throws(function () { + new Event({"parties": ["sds"]}); + }, + 'Error("У одного из участников нет поля <ИМЯ>")' + ); + equal(new Event({"stars": 2}).stars, 2, "При присваивании звезд произошла ошибка"); + equal(new Event({"stars": 2.1}).stars, 2, "Функция устанавливающая звездочки не сработала"); +}); + +module("LeaveMark(number)"); +test('Передача не числа', function () { + "use strict"; + var testEvent = new Event({}); + equal(testEvent.leaveMark("не число"), 0, 'Если звездочку передали в виде не числа, то 0'); +}); +test('Запуск без параметра', function () { + "use strict"; + var testEvent = new Event({}); + + equal(testEvent.leaveMark(), 0, 'Если звездочку забыли объявить, то 0'); +}); +test('Передача отрицательного числа', function () { + "use strict"; + var testEvent = new Event({}); + equal(testEvent.leaveMark(-1), 0, 'Звездочка не может быть меньше 0'); +}); +test('Передача числа болешьшего 5', function () { + "use strict"; + var testEvent = new Event({}); + + equal(testEvent.leaveMark(6), 5, 'Звездочка не может быть больше 5'); +}); +test('Передача корректного числа', function () { + "use strict"; + var testEvent = new Event({}); + + equal(testEvent.leaveMark(3), 3, '0-5 звездочка не изменяется, если целая'); +}); +test('Передача дробного числа', function () { + "use strict"; + var testEvent = new Event({}); + equal(testEvent.leaveMark(3.124), 3, 'Звездочки - Int'); +}); + +module("SetLocation(location)"); +test('Gps - undef', function () { + "use strict"; + var testEvent = new Event({}), gps; + testEvent.setLocation(gps, ""); + deepEqual(testEvent.location, { + "gps": {"x": 0, "y": 0}, + "nameLocation": "Earth" + }, "GPS - некорректный => установить значения по умолчанию"); +}); +test('Передача числа болешьшего 5', function () { + "use strict"; + var testEvent = new Event({}), gps; + testEvent.setLocation(gps, ""); + deepEqual(testEvent.location, { + "gps": {"x": 0, "y": 0}, + "nameLocation": "Earth" + }, "GPS - некорректный => установить значения по умолчанию"); +}); +test('Передача объекта не являющимся gps', function () { + "use strict"; + var testEvent = new Event({}); + testEvent.setLocation("Not gps", ""); + deepEqual(testEvent.location, { + "gps": {"x": 0, "y": 0}, + "nameLocation": "Earth" + }, "GPS - не содержит X или Y => установить значения по умолчанию"); +}); +test('Имя места - не строка', function () { + "use strict"; + var testEvent = new Event({}); + testEvent.setLocation({"x": 0, "y": 0}, []); + deepEqual(testEvent.location, { + "gps": {"x": 0, "y": 0}, + "nameLocation": "Earth" + }, "Название места не строка => установить значения по умолчанию"); +}); +test('Корректный тест', function () { + "use strict"; + var testEvent = new Event({}); + testEvent.setLocation({"x": 1, "y": 2}, "Moon"); + deepEqual(testEvent.location, { + "gps": {"x": 1, "y": 2}, + "nameLocation": "Moon" + }, "GPS - не содержит X или Y => установить значения по умолчанию"); +}); \ No newline at end of file diff --git a/Task/Scripts/test/ModelTest.html b/Task/Scripts/test/ModelTest.html new file mode 100644 index 0000000..5111961 --- /dev/null +++ b/Task/Scripts/test/ModelTest.html @@ -0,0 +1,15 @@ + + + + + + + + + +

        QUnit test env

        +

        +

        +
          + + \ No newline at end of file diff --git a/Task/Scripts/test/ModelTest.js b/Task/Scripts/test/ModelTest.js new file mode 100644 index 0000000..81fa2b9 --- /dev/null +++ b/Task/Scripts/test/ModelTest.js @@ -0,0 +1,43 @@ +/*global module: true*/ +/*global test: true*/ +/*global ok: true*/ +/*global equal: true*/ +/*global deepEqual: true*/ +/*global initTestBase: true*/ +/*global Event: true*/ +/*global Collection: true*/ +/*global Model: true*/ +/*global TestObject: true*/ +module("Create model"); +test('Проверка конструктора клонирования', function () { + "use strict"; + var model = new Model(new TestObject(1)); + equal(typeof model["myNumber"], "number", "Личный объект не скопировался"); + equal(typeof model["commonNumber"], "number", "Объекты прототипа не скопировались"); +}); +test('Проверка метода get()', function () { + "use strict"; + var model = new Model(new TestObject(1)); + equal(model.get("commonNumber"), 20, "Нет доступа к полям прототипа"); + equal(model.get("myNumber"), 1, "Нет доступа к личным полям"); + equal(typeof model.get({}), "undefined", "Объект не исполняет интерфейс"); + equal(typeof model.get("ТакогоПоляТочноНет"), "undefined", "несуществующее поле определено"); +}); +test('Проверка метода set()', function () { + "use strict"; + var model = new Model(new TestObject(1)); + model.set({"myNumber": 2}); + equal(typeof model.get("myNumber"), "number", "Присваение произошло с ошибкой"); + equal(model.get("myNumber"), 2, "Присвоение произошло с ошибкой"); + model.set({"commonNumber": 2}); + equal(TestObject.prototype.commonNumber, 20, "Присвоение испортило прототип"); + equal(model.get("commonNumber"), 2, "Ошибка при присвоении наследуемому полю через прототип"); +}); + +function TestObject (number) { + "use strict"; + this.myNumber = number; +} +TestObject.prototype.commonNumber = 20; + + diff --git a/Task/Scripts/testData.js b/Task/Scripts/testData.js new file mode 100644 index 0000000..69f33a5 --- /dev/null +++ b/Task/Scripts/testData.js @@ -0,0 +1,104 @@ +//Это "мясо" T_T +(function (toExport) { + "use strict"; + var initTestBase = function () { + var bestOfSweetsDateStart = new Date("December 10, 2012 00:00:00"), + bestOfSweetsDateFinish = new Date("December 14, 2012 23:59:59"), + bestOfSweets = new Event({"start": bestOfSweetsDateStart, "end": bestOfSweetsDateFinish, "name": "BestOfSweets", "id": 1}), + сirioDeNazareDateStart = new Date("December 8, 2012 00:00:00"), + сirioDeNazareDateFinish = new Date("December 15, 2012 23:59:59"), + сirioDeNazare = new Event({"start": сirioDeNazareDateStart, "end": сirioDeNazareDateFinish, "name": "Cirio De Nazare", "id": 2}), + vinesDayDateStart = new Date("November 10, 2012 00:00:00"), + vinesDayDateFinish = new Date("November 15, 2012 23:59:59"), + vinesDay = new Event({"start": vinesDayDateStart, "end": vinesDayDateFinish, "name": "День вина", "id": 3}), + theBlackCountryDateStart = new Date("November 15, 2012 00:00:00"), + theBlackCountryDateFinish = new Date("December 1, 2012 23:59:59"), + theBlackCountry = new Event({"start": theBlackCountryDateStart, "end": theBlackCountryDateFinish, "name": 'Вкус "Черной страны"', "id": 4}), + oktoberFestDateStart = new Date("September 24, 2012 00:00:00"), + oktoberFestDateFinish = new Date("October 8, 2012 23:59:59"), + oktoberFest = new Event({"start": oktoberFestDateStart, "end": oktoberFestDateFinish, "name": 'OktoberFest', "id": 5}), + francfurtBookDateStart = new Date("October 15, 2012 00:00:00"), + francfurtBookDateFinish = new Date("October 20, 2012 23:59:59"), + francfurtBook = new Event({"start": francfurtBookDateStart, "end": francfurtBookDateFinish, "name": 'Франкфуртская международная книжная ярмарка', "id": 6}), + aidaDateStart = new Date("October 12, 2012 00:00:00"), + aidaDateFinish = new Date("October 27, 2012 23:59:59"), + aida = new Event({"start": aidaDateStart, "end": aidaDateFinish, "name": '"Аида" у великих пирамид, Гиза', "id": 7}), + paradeOfLoveDateStart = new Date("October 3, 2012 14:00:00"), + paradeOfLoveDateFinish = new Date("October 3, 2012 22:00:00"), + paradeOfLove = new Event({"start": paradeOfLoveDateStart, "end": paradeOfLoveDateFinish, "name": 'Парад любви', "id": 8}), + sukkotDateStart = new Date("October 3, 2012 00:00:00"), + sukkotDateFinish = new Date("October 3, 2012 23:59:59"), + sukkot = new Event({"start": sukkotDateStart, "end": sukkotDateFinish, "name": 'Парад любви', "id": 9}), + fishFestivalDateStart = new Date("October 15, 2012 00:00:00"), + fishFestivalDateFinish = new Date("October 15, 2012 23:59:59"), + fishFestival = new Event({"start": fishFestivalDateStart, "end": fishFestivalDateFinish, "name": 'Фестиваль рыбы', "id": 10}), + chocolateFestivalDateStart = new Date("October 19, 2012 00:00:00"), + chocolateFestivalDateFinish = new Date("October 28, 2012 23:59:59"), + chocolateFestival = new Event({"start": chocolateFestivalDateStart, "end": chocolateFestivalDateFinish, "name": 'Фестиваль "Еврошоколад"', "id": 11}), + digitalArtFestivalDateStart = new Date("September 19, 2012 00:00:00"), + digitalArtFestivalDateFinish = new Date("September 28, 2012 23:59:59"), + digitalArtFestival = new Event({"start": digitalArtFestivalDateStart, "end": digitalArtFestivalDateFinish, "name": 'Фестиваль цифрового исскуства', "id": 12}), + fatherDaysDateStart = new Date("September 18, 2012 00:00:00"), + fatherDaysDateFinish = new Date("September 19, 2012 23:59:59"), + fatherDays = new Event({"start": fatherDaysDateStart, "end": fatherDaysDateFinish, "name": 'Дни наследия', "id": 13}), + bearWeekendDateStart = new Date("September 18, 2012 00:00:00"), + bearWeekendDateFinish = new Date("September 19, 2012 23:59:59"), + bearWeekend = new Event({"start": bearWeekendDateStart, "end": bearWeekendDateFinish, "name": 'Bear Weekends', "id": 14}), + teaFestivalDateStart = new Date("September 1, 2012 00:00:00"), + teaFestivalDateFinish = new Date("September 1, 2012 23:59:59"), + teaFestival = new Event({"start": teaFestivalDateStart, "end": teaFestivalDateFinish, "name": 'Фестиваль Чая', "id": 15}), + programmerDayDateStart = new Date("September 13, 2012 00:00:00"), + programmerDayDateFinish = new Date("September 13, 2012 23:59:59"), + programmerDay = new Event({"start": programmerDayDateStart, "end": programmerDayDateFinish, "name": 'День программмиста', "id": 16}), + knowDayDateStart = new Date("September 1, 2012 00:00:01"), + knowDayDateDateFinish = new Date("September 1, 2012 23:59:59"), + knowDayDate = new Event({"start": knowDayDateStart, "end": knowDayDateDateFinish, "name": 'День знаний', "id": 17, "stars": 1}), + teacherDayDateStart = new Date("October 5, 2012 00:00:00"), + teacherDayDateFinish = new Date("October 5, 2012 23:59:59"), + teacherDay = new Event({"start": teacherDayDateStart, "end": teacherDayDateFinish, "name": 'День учителя', "id": 18, "stars": 5}), + securiteDayDateStart = new Date("November 5, 2012 00:00:00"), + securiteDayDateFinish = new Date("November 5, 2012 23:59:59"), + securiteDay = new Event({"start": securiteDayDateStart, "end": securiteDayDateFinish, "name": 'День защиты информации', "id": 19, "stars": 3}), + nationUnitionDateStart = new Date("November 4, 2012 00:00:00"), + nationUnitionDateDateFinish = new Date("November 4, 2012 23:59:59"), + nationUnition = new Event({"start": nationUnitionDateStart, "end": nationUnitionDateDateFinish, "name": 'День нароного единства', "id": 20}); + bestOfSweets.setLocation({"x": 15, "y": 189}, "Австрия, Бургенланд - Айзенштадте, Фестиваль сладких вин"); + + сirioDeNazare.setLocation({"x": 45, "y": 133}, "Бразилия, Белен, Фестиваль Cirio De Nazare"); + + vinesDay.setLocation({"x": 45, "y": 133}, "Венгрия, Мор, День вина"); + + theBlackCountry.setLocation({"x": 45, "y": 133}, "Великобритания, Дадли, Вкус 'Черной страны'"); + + oktoberFest.setLocation({"x": 45, "y": 133}, "Германия, Мюнхен, OktoberFest"); + + programmerDay.parties = [{"name": "Pupkin"}, {"name": "Alex.IDontKnow"}]; + francfurtBook.setLocation({x : 45, y : 133}, "Германия, Frankfurt, Франкфуртская международная книжная ярмарка"); + aida.setLocation({"x": 45, "y": 133}, "Египет, ?, Аида у великих пирамид, Гиза"); + paradeOfLove.setLocation({"x": 45, "y": 133}, "Израль, Тель-Авиве, Парад любви"); + + sukkot.setLocation({"x": 45, y : 133}, "Израль, Иерусалиме, праздник Суккот"); + + fishFestival.setLocation({"x": 45, "y": 133}, "Испания, О Грове, Фестиваль рыбы"); + + chocolateFestival.setLocation({"x": 45, "y": 133}, 'Италия, Перуджа, Фестиваль "Еврошоколад"'); + + digitalArtFestival.setLocation({"x": 45, "y": 133}, "Австрия, Линц, Фестиваль Цифрового Исскуства"); + + fatherDays.setLocation({"x": 45, "y": 133}, "Бельгия, Антверпене, Дни наследия"); + + bearWeekend.setLocation({"x": 45, "y": 133}, "Бельгия, Брюссель, Bear Weekends"); + + teaFestival.setLocation({"x": 45, "y": 133}, "Россия, Москва, Фестиваль чая"); + programmerDay.setLocation({"x": 45, "y": 133}, "Вселенная, Земля, День программиста"); + programmerDay.parties = [{"name": "Alexander.Mangin"}, {"name": "Alex.IDontKnow"}]; + knowDayDate.setLocation({"x": 45, "y": 133}, "Вселенная, Земля, День знаний"); + teacherDay.setLocation({"x": 45, "y": 133}, "Вселенная, Земля, День учителя"); + securiteDay.setLocation({"x": 45, "y": 133}, "Вселенная, Земля, День защиты информации"); + nationUnition.setLocation({"x": 45, "y": 133}, "Вселенная, Земля, День народного единства"); + return new BaseEvent([bestOfSweets, сirioDeNazare, vinesDay, theBlackCountry, oktoberFest, francfurtBook + , aida, paradeOfLove, sukkot, fishFestival, chocolateFestival, digitalArtFestival, fatherDays, + bearWeekend, teaFestival, programmerDay, knowDayDate, teacherDay, securiteDay, nationUnition]); + } + toExport.initTestBase = initTestBase; +}(window)); \ No newline at end of file diff --git a/Task/index.html b/Task/index.html new file mode 100644 index 0000000..9fb1361 --- /dev/null +++ b/Task/index.html @@ -0,0 +1,170 @@ + + + + + +
          +
          +
          +
          +
          +
          + Начало + +
          +
          + Конец + +
          +
          +
          + Что + +
          +
          +
          + Где? ( + + ; + + ) +
          +
          + Важность + +
          +
          + Цена посещения + +
          +
          +
          Список участников:
          +
            +
          1. +
          2. +
          3. +
          +
          + +
          +
          +
          + +
          +
          +
          + +
          +
          + Показать события, которые ... +
          +
          + Вообще есть + +
          +
          + Будут завтра + +
          +
          + Будут через неделю + +
          +
          + Будут через месяц + +
          +
          +
          +
          + Показать события, которые .. +
          +
          + Вообще есть + +
          +
          + Уже прошли + +
          +
          + Идут в данный момент + +
          +
          + Будут идти + +
          +
          +
          +
          + Какую сортировочку изволите? +
          +
          + Ни какую пожалуйста + +
          +
          + По звездам ^^ + +
          +
          + По дате + +
          +
          +
          +
          + Показать события, в которых .. +
          +
          +
          Участвуют мои друзья
          +
            +
          1. +
          2. +
          3. +
          +
          + +
          +
          +
          +
          +
          + + + + + + + + + + + + + + + + + + + + + + + +
          ЧтоЗвездочки ^^НачалоКонецСтоимостьУчастники
          sdfkjsjdfЧтоЗвездочки ^^НачалоКонецСУчастники
          +
          + + + + + + + + + + + + \ No newline at end of file diff --git a/Task/style.css b/Task/style.css new file mode 100644 index 0000000..94d0f42 --- /dev/null +++ b/Task/style.css @@ -0,0 +1,35 @@ +*{ +} +#ActionWithEventList { + float: left; + border:4px double black; +} +#eventList { + color: red; + overflow: hidden; + border:4px double black; +} +#AddInputs { + float: left; +} + +#messageErrorAddInputs { + overflow: hidden; +} + +.ErrorActivateOff { + visibility:hidden +} + +.ErrorActivateOn { + color: red; + visibility:show +} + +.TitleAddEvent { + color: blue; +} +.ColonTable { + float: left; + overflow: hidden; +} \ No newline at end of file