diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..74cee9f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +/node_modules +/Server script/node_modules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b8ea4f6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "qunit"] + path = qunit + url = git://github.com/jquery/qunit.git +[submodule "jquery"] + path = jquery + url = git://github.com/jquery/jquery.git +[submodule "es5-shim"] + path = es5-shim + url = git://github.com/kriskowal/es5-shim.git diff --git a/Server script/GUID.js b/Server script/GUID.js new file mode 100644 index 0000000..bcf7a1d --- /dev/null +++ b/Server script/GUID.js @@ -0,0 +1,33 @@ +(function () { + "use strict"; + var randomHex4, + GUID; + /** + * @function генерирует случайный hex из четырех символов + * @private + * @return {String} + */ + randomHex4 = function () { + return Math.floor( + Math.random() * 0x10000 /* 65536 */ + ).toString(16); + }; + /** + * @namespaсe , содержащий инструменты для работы с GUID + */ + GUID = function () {}; + exports.GUID = GUID; + /** + * function генерирует guid в виде строки + * @return {String} + */ + GUID.createGUID = function () { + return ( + randomHex4() + randomHex4() + "-" + + randomHex4() + "-" + + randomHex4() + "-" + + randomHex4() + "-" + + randomHex4() + randomHex4() + randomHex4() + ); + }; +}()); diff --git a/Server script/ValidateEvent.js b/Server script/ValidateEvent.js new file mode 100644 index 0000000..a2b6002 --- /dev/null +++ b/Server script/ValidateEvent.js @@ -0,0 +1,16 @@ +(function () { + "use strict"; + var validate = function (event) { + //это можно сказать копи паст... + return !(typeof event.start === "undefined" || + typeof event.end === "undefined" || + typeof event.name === "undefined" || + typeof event.gps === "undefined" || + typeof event.gps.x === "undefined" || + typeof event.gps.y === "undefined" || + typeof event.stars === "undefined" || + typeof event.cost === "undefined" || + typeof event.parties === "undefined"); + }; + exports.validate = validate; +}()); diff --git a/Server script/main.js b/Server script/main.js new file mode 100644 index 0000000..f386ee7 --- /dev/null +++ b/Server script/main.js @@ -0,0 +1,74 @@ +(function () { + "use strict"; + var express = require('express'), + optimist = require('optimist').default('port', 8080).default('host', '127.0.0.1'), + color = require('colors'), + fs = require('fs'), + eventValidator = require('./validateEvent.js'), + guidModule = require('./guid.js'), + cfg, + app = express(), + printDate = function (date) { + return date.getFullYear() + "/" + date.getMonth() + "/" + date.getDate(); + }; + app.use(express.static("../WebSite")); + app.use(express.bodyParser()); + + app.post("/saveNewEvent", function (req, res) { + console.log("Обработка запроса на добавления нового события в Бд....".green); + var newEventRequest = JSON.parse(req.param('request')), + newEvent; + if (!eventValidator.validate(newEventRequest)) { + console.log("Событие не валидное".red); + res.send({"request": false}); + console.log("Обработка закончена".green); + return; + } + console.log("Событие прошло валидацию"); + newEvent = { + "start": printDate(new Date(newEventRequest.start)), + "end": printDate(new Date(newEventRequest.end)), + "gps": { + "x": parseFloat(newEventRequest.gps.x), + "y": parseFloat(newEventRequest.gps.x) + }, + "name": newEventRequest.name, + "stars": newEventRequest.stars, + "cost": newEventRequest.cost, + "parties": newEventRequest.parties, + "id": guidModule.GUID.createGUID() + }; + console.log("Начинаем обновлять БД"); + console.log("Открываем бд"); + fs.readFile("../WebSite/base.json", "utf8", function (err, date) { + if (err) { + res.send({"request": false}); + console.log("Открыть бд не удалось".red); + console.log("Обработка закончена".red); + return; + } + console.log("Файл прочитался"); + + var eventList = JSON.parse(date); + console.log("Файл преобразовали в json"); + eventList.items.push(newEvent); + console.log("Сохраняем изменение в бд"); + fs.writeFile("../WebSite/base.json", JSON.stringify(eventList), "utf8", function (error) { + if (error) { + res.send({"request": false}); + console.log("Сохранить Бд не удалось".red); + console.log("Обработка закончена".red); + return; + } + console.log("Все удачно сохранилось"); + console.log("Обработка закончена".green); + res.send({"request": true, "id": newEvent.id}); + }); + }); + + }); + + cfg = optimist.argv; + app.listen(cfg.port, cfg.host); + console.log("Server up: ".green + cfg.host + ":" + cfg.port); +}()); \ No newline at end of file diff --git a/Server script/package.json b/Server script/package.json new file mode 100644 index 0000000..906b1a0 --- /dev/null +++ b/Server script/package.json @@ -0,0 +1,14 @@ +{ + "dependencies": { + "optimist": "*", + "express": "*", + "colors": "*" + }, + "name": "CalendarServer", + "version": "1.0.0", + "description": "Задание на dz8-nodejs", + "author": { + "name": "Mangin.Alex", + "email": "mywork.koder@gmail.com" + } +} \ No newline at end of file diff --git a/WebSite/Scripts/BaseEvent.js b/WebSite/Scripts/BaseEvent.js new file mode 100644 index 0000000..98b80b9 --- /dev/null +++ b/WebSite/Scripts/BaseEvent.js @@ -0,0 +1,162 @@ +/*global + Collection: false + */ +(function (toExport) { + "use strict"; + /** + * Создает оболочку над массивом событий, предоставляющую "sql" подобные операции + * + * @class Оболочка над массивом событий. + * @augments Collection + */ + var BaseEvent = function BaseEvent(events) { + Collection.call(this, events); + }, + starsComparer, + dateComparer; + + 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 Возвращает новую оболочку, но уже с событиями, которые будут в определенный период + * + * @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 Возвращает новую оболочку, но уже с событиями, которые стоят не меньше min и не больше max + * + * @param {Number} min - начала периода + * @param {Number} max - начала периода + * + * @return {BaseEvent} + */ + BaseEvent.prototype.getEventWithCost = function (min, max) { + return this.filter(function (event) { + return (event.cost >= min && event.cost <= max); + }); + }; + + /** + * @function Компаратор рейтинга по убыванию + * @private + * + * @field {Date} a + * @field {Date} b + * + * @return {Number} + */ + 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 {Number} + */ + 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/WebSite/Scripts/Calendar.js b/WebSite/Scripts/Calendar.js new file mode 100644 index 0000000..7009f7e --- /dev/null +++ b/WebSite/Scripts/Calendar.js @@ -0,0 +1,138 @@ +/*global + FactoryEvent: false, + FilterEventBase:false, + TableEventBase: false, + Event: false, + confirm:false, + alert:false, + Model:false, + $:false, + BaseEvent:false, + console:false + */ +(function (toExport) { + "use strict"; + /** + * + * @param {jQuery} $factory объект, содержащий фабрику событий + * @param {jQuery} $filter объект, содержащий различные фильтры + * @param {jQuery} $table + * @param {String} baseUrl + * @constructor контроллер каландаря + */ + var Calendar = function ($factory, $filter, $table, baseUrl) { + var cloneCalendar = this; + this.factory = new FactoryEvent($factory); + this.filter = new FilterEventBase($filter); + this.table = new TableEventBase($table); + + this.loadBase(baseUrl); + this.factory.WriteDefaultEvent(); + + this.factory.$container.find("input[type = text], input[type = date]").on("blur", function () { + cloneCalendar.factory.eventValidation(); + }); + + this.factory.$container.find("#SubmitNewEventButton").on("click", function () { + var eventObj = cloneCalendar.factory.readEvent(), + errors = Event.isValidate(eventObj), + isCritical = errors.some(function (element) { + return element.isCritical; + }); + cloneCalendar.factory.eventValidation(); + if (!isCritical) { + if (errors.length !== 0) { + if (confirm('Некоторые незначительные поля некорректны, продолжить?')) { + var defaultObj = new Event(), + field; + for(field in errors) { + if (errors.hasOwnProperty(field)) { + eventObj[field] = defaultObj[field]; + } + } + cloneCalendar.saveNewEvent("/saveNewEvent", eventObj); + } + } else { + cloneCalendar.saveNewEvent("/saveNewEvent", eventObj); + } + } + }); + //todo это гомосятина ! но почему то у input type = radio, нет события blur + this.filter.$container.find("input").on("click", function () { + var newBaseEvent = cloneCalendar.filter.apply(cloneCalendar.baseEvent); + cloneCalendar.table.updateTable(newBaseEvent); + }); + this.filter.$container.find("input").on("blur", function () { + var newBaseEvent = cloneCalendar.filter.apply(cloneCalendar.baseEvent); + cloneCalendar.table.updateTable(newBaseEvent); + }); + }; + toExport.Calendar = Calendar; + Calendar.prototype = Object.create(Model.prototype, { + constructor: { + value: Event, + enumerable: false, + writable: true, + configurable: true + } + }); + /** + * @function Загрузить по url базу событий + * @param baseUrl {String} url + * + */ + Calendar.prototype.loadBase = function (baseUrl) { + var calendar = this, + i, + events; + $.getJSON(baseUrl, function (date) { + events = []; + for (i = 0; i < date.items.length; i += 1) { + var item = date.items[i]; + events.push(new Event({ + "start": new Date(item.start), + "end": new Date(item.end), + "name": item.name, + "gps": { + "x": parseFloat(item.gps.x), + "y": parseFloat(item.gps.y) + }, + "cost": parseFloat(item.cost), + "stars": parseInt(item.stars, 10), + "parties": item.parties, + id: item.id + })); + } + calendar.baseEvent = new BaseEvent(events); + calendar.table.updateTable(calendar.baseEvent); + }); + }; + /** + * + * @param {String} saveUrl url + * @param {Object} newEvent новое событие похожий на Event. + * @function отправляет json с новым событием на сервер + */ + Calendar.prototype.saveNewEvent = function (saveUrl, newEvent) { + var cloneCalendar = this, + newBaseEvent; + $.post(saveUrl, {"request":JSON.stringify(newEvent)}) + .done(function (req, data) { + console.log(req); + if (req.request === true) { + newEvent.id = req.id; + cloneCalendar.baseEvent.items.push(new Event(newEvent)); + var newBaseEvent = cloneCalendar.filter.apply(cloneCalendar.baseEvent); + cloneCalendar.table.updateTable(newBaseEvent); + cloneCalendar.factory.WriteDefaultEvent(); + } else { + alert("Вы ввели не валидные данные... как вам это удалось. Позвоните в тех поддержку") + } + + }) + .fail(function () { + alert("Данные не сохранились. Позвоните в тех поддержку"); + console.log("Данные не сохранились"); + }); + }; +}(window)); \ No newline at end of file diff --git a/WebSite/Scripts/Collection.js b/WebSite/Scripts/Collection.js new file mode 100644 index 0000000..40e5e64 --- /dev/null +++ b/WebSite/Scripts/Collection.js @@ -0,0 +1,69 @@ +(function (toExport) { + "use strict"; +/** + * Создает оболочка для хранения массива объектов с операциями по извлечению более конкретных элементов + * @class Оболочка для храения массива объектов + * + * @param {Array} otherItems элементы коллекции +*/ + var Collection = function (otherItems) { + 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 {Object} instanceof this.constructor +*/ + Collection.prototype.add = function (obj) { + var newEvents = this.items.concat([obj]); + return new this.constructor(newEvents); + }; +/** + * @function создает новую коллекцию элементов с отфильтрованными элементами + * + * @param {Function} selector делегат + * + * @return {Object} instanceof this.constructor +*/ + Collection.prototype.filter = function (selector) { + var newItems = this.items.filter(selector); + return new this.constructor(newItems); + }; +/** +* @function создает новую коллекцию элементов с теме же элементами + с новым элементом obj + * + * @param {Function} comparator компаратор + * @param {Boolean} isInvert инвертировать, ли результат + * + * @return {Object} 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/WebSite/Scripts/Event.js b/WebSite/Scripts/Event.js new file mode 100644 index 0000000..1f4059c --- /dev/null +++ b/WebSite/Scripts/Event.js @@ -0,0 +1,192 @@ +/*global Model: false, +GUID:false, + FieldsError:false, + $:false, + window:false +*/ + +(function (toExport) { + "use strict"; + +/** + * Создает новое событие в календаре + * @class Событие в календаре + * @augments Model + * + * @field {String} - id в виде GUID + * @field {Object} - location объект содержащий локационные данные о событии + название события + * @field {Number} - реитинг + * @field {Number} - Цена посещения +*/ + var Event = function Event(data) { + if (typeof data === "undefined") { + toExport.Model.call(this, { + "start": new Date(), + "end" : new Date(), + "gps" : { + "x": 0, + "y": 0 + }, + "name" : "Что-то", + "stars" : 0, + "cost" : 0, + "parties" : [], + "id": "Empty" + }); + return this; + } + var eventDefaultVal = new Event(), + newEvent = this; + toExport.Model.call(this, eventDefaultVal); + toExport.Model.call(this, data); + Event.isValidate(data).forEach(function (error) { + newEvent[error.who] = eventDefaultVal[error.who]; + }); + return this; + }, + dateValidator, + isValidateTimeInterval, + isValidateGps, + isValidateName, + isValidateStars, + isValidateCost; + + toExport.Event = Event; + + Event.prototype = Object.create(toExport.Model.prototype, { + constructor: { + value: Event, + enumerable: false, + writable: true, + configurable: true + } + }); + +/** + * @function Функция, проверяющая корректность даты + * + * @return {Boolean} +*/ + dateValidator = function (date) { + if (Object.prototype.toString.call(date) === "[object Date]") { + if (!isNaN(date.getTime())) { + return true; + } + } + return false; + }; +/** + * + * @function проверяет корректный ли параметр интервала времени события + * @param {Object} event + * @return {Array} сообщения с ошибками + */ + isValidateTimeInterval = function (event) { + var errors = []; + if (!event.start || !dateValidator(event.start)) { + errors.push(new FieldsError("start", "Дата начала события задана не корректно", true)); + } + if (!event.end || !dateValidator(event.end)) { + errors.push(new FieldsError("end", "Дата конца событий задана не корректно", true)); + } + if (errors.length === 0) { + if (event.start.getTime() > event.end.getTime()) { + errors.push(new FieldsError("start", "Дата начала и конца события перепутаны местами", true)); + errors.push(new FieldsError("end", "Дата начала и конца события перепутаны местами", true)); + } + } + + return errors; + }; +/** + * + * @function проверяет корректный ли параметры содержащие координаты события + * @param {Object} event + * @return {Array} сообщения с ошибками + */ + isValidateGps = function (event) { + var errors = []; + + if (typeof event.gps === "undefined" || !$.isNumeric(event.gps.x)) { + errors.push(new FieldsError("gps.x", "Координата X - не число")); + } + if (typeof event.gps === "undefined" || !$.isNumeric(event.gps.y)) { + errors.push(new FieldsError("gps.y", "Координата Y - не число")); + } + return errors; + }; +/** + * + * @function проверяет корректный ли параметр названия события + * @param {Object} event + * @return {Array} сообщения с ошибками + */ + isValidateName = function (event) { + var errors = []; + if (event.name === "undefined" || event.name.length === 0 || event.name.length > 100) { + errors.push(new FieldsError("name", "Название события должно содержать имя от 1 до 100 символов", true)); + } + return errors; + }; +/** + * + * @function проверяет корректный ли параметр рейтинга события + * @param {Object} event + * @return {Array} сообщения с ошибками + */ + isValidateStars = function (event) { + var errors = []; + if (typeof event.stars === "undefined" || !$.isNumeric(event.stars)) { + errors.push(new FieldsError("stars", "В поле должно быть введено число")); + } else { + if (event.stars < 0 || event.stars > 5) { + errors.push(new FieldsError("stars", "Количество звезд от 0 до 5")); + } else { + if (Math.floor(event.stars) !== event.stars) { + errors.push(new FieldsError("stars", "Количество звезд целое число")); + } + } + } + return errors; + }; +/** + * + * @function проверяет корректный ли параметр стоимости посещения + * @param {Object} event + * @return {Array} сообщения с ошибками + */ + isValidateCost = function (event) { + var errors = []; + if (typeof event.cost === "undefined" || !$.isNumeric(event.cost)) { + errors.push(new FieldsError("cost", "В этом поле должно быть число")); + } else { + if (event.cost < 0) { + errors.push(new FieldsError("cost", "Цена за участие не может быть отрицательной")); + } + } + return errors; + }; +/** + * @function Проверяет объект на корректность + * + * @field {Object} event - то что проверяемый + * @return {Array} сообщение с ошибками. +*/ + Event.isValidate = function (event) { + return [].concat( + isValidateTimeInterval(event), + isValidateName(event), + isValidateGps(event), + isValidateCost(event), + isValidateStars(event) + ); + }; +/** + * @function Функция, печатающие значение рейтинга в звездочках + * + * @return {String} ,*,**,***,****,***** +*/ + Event.prototype.starsToString = function () { + return new Array(this.stars + 1).join('*'); + }; +}(window)); \ No newline at end of file diff --git a/WebSite/Scripts/FactoryEvent.js b/WebSite/Scripts/FactoryEvent.js new file mode 100644 index 0000000..df3317c --- /dev/null +++ b/WebSite/Scripts/FactoryEvent.js @@ -0,0 +1,112 @@ +/*global +$: false, +Event: false, + Model: false + */ +(function (toExport) { + "use strict"; + /** + * + * @param $container + * @constructor создать объект работающий с фабрикой событий расположенных на странице + */ + var FactoryEvent = function ($container) { + this.$container = $container; + this.$startEvent = this.$container.find(".EventsStartDate").eq(0); + this.$endEvent = this.$container.find(".EventsEndDate").eq(0); + this.$name = this.$container.find(".EventsName").eq(0); + this.$x = this.$container.find(".EventsX").eq(0); + this.$y = this.$container.find(".EventsY").eq(0); + this.$stars = this.$container.find(".EventsStars").eq(0); + this.$cost = this.$container.find(".EventsCost").eq(0); + }; + + toExport.FactoryEvent = FactoryEvent; + + /** + * @function - функция читает {Event} элемент из фибричных полей + * @return {Object} + */ + FactoryEvent.prototype.readEvent = function () { + var parties = []; + this.$container.find(".EventsParty").each(function () { + var party = $.trim($(this).val()); + if (party !== "") { + parties.push(party); + } + }); + return { + "start": new Date(this.$startEvent.val()), + "end": new Date(this.$endEvent.val()), + "name": this.$name.val(), + "gps": { + "x": parseFloat(this.$x.val()), + "y": parseFloat(this.$y.val()) + }, + "stars": parseFloat(this.$stars.val()), + "cost": parseInt(this.$cost.val(), 10), + "parties": parties + }; + }; + + /** + * @function - функция пишет в поля фабрики Default поля + */ + FactoryEvent.prototype.WriteDefaultEvent = function () { + var defaultEvent = new Event(); + this.$container.each(function () { + $(this).attr("value", ""); + }); + + this.$startEvent.val(Model.printDate(defaultEvent.start)); + this.$endEvent.val(Model.printDate(defaultEvent.end)); + this.$name.val(defaultEvent.name); + this.$x.val(defaultEvent.gps.x); + this.$y.val(defaultEvent.gps.y); + this.$stars.val(defaultEvent.stars); + this.$cost.val(defaultEvent.cost); + }; + /** + * @function проверяет объект созданный фабрикой, активизирует валидаторы + */ + FactoryEvent.prototype.eventValidation = function () { + var eventObj = this.readEvent(), + errors = Event.isValidate(eventObj), + fieldToDomElementHash = { + "start": this.$startEvent, + "end": this.$endEvent, + "name": this.$name, + "gps.x": this.$x, + "gps.y": this.$y, + "stars": this.$stars, + "cost": this.$cost + }, + fieldToDOM, + $validator; + for (fieldToDOM in fieldToDomElementHash) { + if (fieldToDomElementHash.hasOwnProperty(fieldToDOM)) { + $validator = fieldToDomElementHash[fieldToDOM].parents().eq(0).next(); + $validator.empty(); + $validator.removeClass("CriticalError"); + $validator.removeClass("Error"); + $validator.addClass("Valid"); + } + } + + $.each(errors, function (index, erorr) { + var $DOMObject = fieldToDomElementHash[erorr.nameField], + $validator = $DOMObject.parents().eq(0).next(); + if ($validator.children().length === 0) { + $validator.removeClass("Valid"); + if (erorr.isCritical === true) { + $validator.addClass("CriticalError"); + } else { + $validator.addClass("Error"); + } + $("", { + "text": erorr.message + }).appendTo($validator); + } + }); + }; +}(window)); \ No newline at end of file diff --git a/WebSite/Scripts/FieldError.js b/WebSite/Scripts/FieldError.js new file mode 100644 index 0000000..bc73f7e --- /dev/null +++ b/WebSite/Scripts/FieldError.js @@ -0,0 +1,23 @@ +/** + * Created with JetBrains WebStorm. + * User: painandfear + * Date: 11/27/12 + * Time: 9:53 PM + * To change this template use File | Settings | File Templates. + */ +(function (toExport) { + "use strict"; + /** + * + * @constructor {FieldError} - объект с сообщение о том что поле содержит не корректную информацию + * @field {nameField} - имя поля в котором возникла ошибка + * @field {isCritical} - критично ли поле или можно заполнить default значением + * @field {message} - дружелюбное сообщение для пользователя + */ + + toExport.FieldsError = function (nameField, message, isCritical) { + this.nameField = nameField || "errorField"; + this.message = message || ""; + this.isCritical = isCritical || false; + }; +}(window)); \ No newline at end of file diff --git a/WebSite/Scripts/FilterEvent.js b/WebSite/Scripts/FilterEvent.js new file mode 100644 index 0000000..50db1e9 --- /dev/null +++ b/WebSite/Scripts/FilterEvent.js @@ -0,0 +1,122 @@ +/*global +$:false, +console:false + */ +(function (toExport) { + "use strict"; + var FilterEventBase = function ($container) { + this.$container = $container; + }, + readFilter = function ($container) { + var timeStatusFilter = $container.find('[name = "TimeStatusFilter"]').filter("input:checked").val(), + costFilter = $container.find('[name = "CostFilter"]').filter("input:checked").val(), + sortFilter = $container.find('[name = "Sort"]').filter("input:checked").val(); + return [timeStatusFilter, + costFilter, + sortFilter + ]; + }; + /** + * + * @function применить группу фильтров к базе base, содержащей события календаря + * @param {BaseEvent} base база к которой применится группа фильтров + * @return {BaseEvent} база с примененными фильтрами + */ + FilterEventBase.prototype.apply = function (base) { + var filters = readFilter(this.$container), + newBase = base, + filterModule = this; + $.each(filters, function (i, filter) { + if (filterModule[filter]) { + newBase = filterModule[filter](newBase); + } else { + console.log("Фильтр не обнаружен: " + filter); + } + }); + return newBase; + }; + /** + * + * @function фильтр пустышка + * @param {BaseEvent} base база к которой применится фильтр + * @return {BaseEvent} + */ + FilterEventBase.prototype.none = function (base) { + return base; + }; + /** + * + * @function фильтр, возрвщающий прощедщие события + * @param {BaseEvent} base база к которой применится фильтр + * @return {BaseEvent} + */ + FilterEventBase.prototype.past = function (base) { + return base.pastEventBase(); + }; + /** + * + * @function фильтр, возрвщающий текущие события + * @param {BaseEvent} base база к которой применится фильтр + * @return {BaseEvent} + */ + FilterEventBase.prototype.now = function (base) { + return base.nowEventBase(); + }; + /** + * + * @function фильтр, возрвщающий грядущие события + * @param {BaseEvent} base база к которой применится фильтр + * @return {BaseEvent} + */ + FilterEventBase.prototype.next = function (base) { + return base.nextEventBase(); + }; + /** + * + * @function фильтр, возрвщающий события в определенный период + * @param {BaseEvent} base база к которой применится фильтр + * @return {BaseEvent} + */ + FilterEventBase.prototype.period = function (base) { + var startDate = new Date(this.$container.find(".StartDate").eq(0).val()), + finishDate = new Date(this.$container.find(".EndDate").eq(0).val()); + if (startDate.getTime() <= finishDate.getTime()) { + return base.getEventFromPeriod(startDate, finishDate); + } + return base; + }; + /** + * + * @function фильтр, возрвщающий события определенной стоимости + * @param base + * @return {BaseEvent} + */ + FilterEventBase.prototype.minMaxCost = function (base) { + var minCost = parseFloat(this.$container.find(".MinCost").eq(0).val()), + maxCost = parseFloat(this.$container.find(".MaxCost").eq(0).val()); + if (minCost <= maxCost) { + return base.getEventWithCost(minCost, maxCost); + } + return base; + }; + /** + * + * @function фильтр, сортирует по звездам + * @param base + * @return {BaseEvent} + */ + FilterEventBase.prototype.stars = function (base) { + return base.sortByStars(false); + }; + /** + * + * @function фильтр, сортирует по дате + * @param base + * @return {BaseEvent} + */ + FilterEventBase.prototype.date = function (base) { + return base.sortByDate(false); + }; + + toExport.FilterEventBase = FilterEventBase; +}(window)); \ No newline at end of file diff --git a/WebSite/Scripts/Model.js b/WebSite/Scripts/Model.js new file mode 100644 index 0000000..d290db5 --- /dev/null +++ b/WebSite/Scripts/Model.js @@ -0,0 +1,71 @@ +/*global +$: false, + window: false + */ +(function (toExport) { + "use strict"; +/** + * @class Абстрактный класс объектов ООП + * + * @param {Object} data копируемый объект +*/ + var Model = function (data) { + var nameField; + for (nameField in data) { + if (data.hasOwnProperty(nameField)) { + this[nameField] = data[nameField]; + } + } + }, + printDate; + toExport.Model = Model; + +/** + * @function setter + * + * @param {Object} attributes присваиваемый объект +*/ + 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} attribute имя поля + * + * @return {Object} +*/ + Model.prototype.get = function (attribute) { + if (typeof attribute !== 'string' || typeof this[attribute] === "undefined") { + return undefined; + } + return this[attribute]; + }; + + /** + * @function записать даты в нормальном виде + * @param {Date} date + */ + if (toExport.$.browser.msie) { + printDate = function (date) { + return date.getFullYear().toString() + "/" + date.getMonth().toString() + "/" + date.getDate().toString(); + }; + } else { + printDate = function (date) { + var month = date.getMonth(), + day = date.getDate(); + month = (month < 10) ? "0" + month.toString() : month.toString(); + day = (day < 10) ? "0" + day.toString() : day.toString(); + return date.getFullYear() + "-" + month + "-" + day; + }; + } + Model.printDate = printDate; +}(window)); \ No newline at end of file diff --git a/WebSite/Scripts/Polyfill.js b/WebSite/Scripts/Polyfill.js new file mode 100644 index 0000000..746a654 --- /dev/null +++ b/WebSite/Scripts/Polyfill.js @@ -0,0 +1,107 @@ +(function () { + "use strict"; + /** + * Полифил Object.create + * @source https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create + */ + if (typeof Object.create !== 'function') { + Object.create = function (o, props) { + var prop; + function F() {} + F.prototype = o; + if (typeof props === "object") { + for (prop in props) { + if (props.hasOwnProperty((prop))) { + F[prop] = props[prop]; + } + } + } + return new F(); + }; + } + /** + * Полифил Array.forEach + * @source https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach + */ + if (!Array.prototype.forEach) { + Array.prototype.forEach = function forEach( callback, thisArg) { + var T, k, O, len; + if (this === null) { + throw new TypeError("this is null or not defined"); + } + O = Object(this); + len = O.length >>> 0; + if ({}.toString.call(callback) !== "[object Function]") { + throw new TypeError(callback + " is not a function"); + } + if (thisArg) { + T = thisArg; + } + k = 0; + while (k < len) { + var kValue; + if (Object.prototype.hasOwnProperty.call(O, k)) { + kValue = O[k]; + callback.call(T, kValue, k, O); + } + k += 1; + } + }; + } + /** + * Полифил Array.some + * @source https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some + */ + if (!Array.prototype.some) { + Array.prototype.some = function (fun) { + if (this === null) { + throw new TypeError(); + } + var t = Object(this), + len = t.length >>> 0, + thisp, + i; + if (typeof fun !== "function") { + throw new TypeError(); + } + thisp = arguments[1]; + for (i = 0; i < len; i += 1) { + if (i in t && fun.call(thisp, t[i], i, t)) { + return true; + } + } + return false; + }; + } + /** + * Полифил Array.some + * @source https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter + */ + if (!Array.prototype.filter) { + Array.prototype.filter = function (fun) { + if (this === null) { + throw new TypeError(); + } + var t = Object(this), + len = t.length >>> 0, + res, + thisp, + i, + val; + if (typeof fun !== "function") { + throw new TypeError(); + } + res = []; + thisp = arguments[1]; + for (i = 0; i < len; i += 1) { + if (i in t) { + val = t[i]; // in case fun mutates this + if (fun.call(thisp, val, i, t)) { + res.push(val); + } + } + } + return res; + }; + } +}()); \ No newline at end of file diff --git a/WebSite/Scripts/Run.js b/WebSite/Scripts/Run.js new file mode 100644 index 0000000..fa1a286 --- /dev/null +++ b/WebSite/Scripts/Run.js @@ -0,0 +1,6 @@ +$(function (){ + var $eventFactory = $("#EventFactory"); + var $eventFilter = $("#EventFilter"); + var $eventTable = $("#eventList"); + var calendar = new Calendar($eventFactory, $eventFilter, $eventTable, "./base.json"); + }); \ No newline at end of file diff --git a/WebSite/Scripts/TableEventBase.js b/WebSite/Scripts/TableEventBase.js new file mode 100644 index 0000000..e1b1ad4 --- /dev/null +++ b/WebSite/Scripts/TableEventBase.js @@ -0,0 +1,61 @@ +/*global + tmpl: false, + Model: false, + $: false +*/ +(function (toExport) { + "use strict"; + var TableEventBase = function ($container) { + this.$container = $container; + }, + rowTable = '' + + "<%= number %>" + + "<%= start %>" + + "<%= end %>" + + "<%= name %>" + + "<%= x %>" + + "<%= y %>" + + "<%= stars %>" + + "<%= cost %>" + + "<%= parties %>" + + "", + templateRowParty = ''; + toExport.TableEventBase = TableEventBase; + /** + * @function Функция отображет {BaseEvent} + * @param {BaseEvent} base + */ + TableEventBase.prototype.updateTable = function (base) { + var tableHtml = "", + item, + i, + j, + partiesHtml; + this.$container.children().remove(); + + for (i = 0; i < base.items.length; i += 1) { + item = base.items[i]; + partiesHtml = ""; + for (j = 0; j < item.parties.length; j += 1) { + partiesHtml += tmpl(templateRowParty, {"party": item.parties[j]}); + } + if (partiesHtml.length !== 0) { + partiesHtml = ""; + } + tableHtml += tmpl(rowTable, { + "number": i, + "start": Model.printDate(item.start), + "end": Model.printDate(item.end), + "name": item.name, + "x": item.gps.x, + "y": item.gps.y, + "stars": item.starsToString(), + "cost": item.cost, + "parties": partiesHtml + }); + } + $(tableHtml).appendTo(this.$container); + }; +}(window)); \ No newline at end of file diff --git a/WebSite/Scripts/Templating.js b/WebSite/Scripts/Templating.js new file mode 100644 index 0000000..4a5eaed --- /dev/null +++ b/WebSite/Scripts/Templating.js @@ -0,0 +1,36 @@ +// Simple JavaScript Templating +// John Resig - http://ejohn.org/ - MIT Licensed +(function (exports) { + "use strict"; + var cache = {}; + + exports.tmpl = function tmpl(str, data) { + // Figure out if we're getting a template, or if we need to + // load the template - and be sure to cache the result. + var fn = !/\W/.test(str) ? + cache[str] = cache[str] || + tmpl(document.getElementById(str).innerHTML) : + + // Generate a reusable function that will serve as a template + // generator (and which will be cached). + new Function("obj", + "var p=[],print=function(){p.push.apply(p,arguments);};" + + + // Introduce the data as local variables using with(){} + "with(obj){p.push('" + + + // Convert the template into pure JavaScript + str + .replace(/[\r\t\n]/g, " ") + .split("<%").join("\t") + .replace(/((^|%>)[^\t]*)'/g, "$1\r") + .replace(/\t=(.*?)%>/g, "',$1,'") + .split("\t").join("');") + .split("%>").join("p.push('") + .split("\r").join("\\'") + + "');}return p.join('');"); + + // Provide some basic currying to the user + return data ? fn(data) : fn; + }; +}(window)); \ No newline at end of file diff --git a/WebSite/Scripts/test/BaseEventTest.html b/WebSite/Scripts/test/BaseEventTest.html new file mode 100644 index 0000000..3b44dd4 --- /dev/null +++ b/WebSite/Scripts/test/BaseEventTest.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + +

QUnit test env

+

+

+
    + + \ No newline at end of file diff --git a/WebSite/Scripts/test/BaseEventTest.js b/WebSite/Scripts/test/BaseEventTest.js new file mode 100644 index 0000000..1bef350 --- /dev/null +++ b/WebSite/Scripts/test/BaseEventTest.js @@ -0,0 +1,115 @@ +/*global + module: false, + test: false, + equal: false, + ok: false, + BaseEvent: false, + Event: false, + Collection: false +*/ +module("test simple SQL"); +test('add()', function () { + "use strict"; + var testBase = new BaseEvent([]); + testBase = testBase.add(new Event({"start": new Date(1), "end": new Date(2)})); + equal(testBase.items.length, 1); + ok(testBase instanceof BaseEvent); + ok(testBase instanceof Collection); + ok(true, true); +}); +test('Фильтры времени', function () { + "use strict"; + var testBase, + pastEventBase, + nextEventBase, + nowEventBase, + periodEventBase, + pastEvent, + nextEvent, + nowEvent, + currentDate; + currentDate = new Date(); + nowEvent = new Event({ + "start": new Date(currentDate.getTime() - 100000), + "end": new Date(currentDate.getTime() + 100000), + "id": "now" + }); + pastEvent = new Event({ + "start": new Date(currentDate.getTime() - 100000001), + "end": new Date(currentDate.getTime() - 100000001), + "id": "past" + }); + nextEvent = new Event({ + "start": new Date(currentDate.getTime() + 100000000), + "end": new Date(currentDate.getTime() + 100000100), + "id": "next" + }); + testBase = new BaseEvent([pastEvent, nextEvent, nowEvent]); + pastEventBase = testBase.pastEventBase(); + nextEventBase = testBase.nextEventBase(); + nowEventBase = testBase.nowEventBase(); + periodEventBase = testBase.getEventFromPeriod(new Date(currentDate.getTime() - 200000), new Date(currentDate.getTime() + 200000)); + equal(pastEventBase.items.length, 1); + ok(pastEventBase.items[0].id === "past"); + equal(nextEventBase.items.length, 1); + ok(nextEventBase.items[0].id === "next"); + equal(nowEventBase.items.length, 1); + ok(nowEventBase.items[0].id === "now"); + equal(periodEventBase.items.length, 1); + ok(periodEventBase.items[0].id === "now"); + +}); +test('Фильтр по другу', function () { + "use strict"; + var testBase, + eventWithFriendBase, + withFriend, + withoutFriend; + withFriend = new Event({ + "parties": ["Mangin.Alexander"], + "id": "ok" + }); + withoutFriend = new Event(); + testBase = new BaseEvent([withFriend, withoutFriend]); + eventWithFriendBase = testBase.withFriend("Mangin.Alexander"); + equal(eventWithFriendBase.items.length, 1); + ok(eventWithFriendBase.items[0].id === "ok"); +}); +test('Фильтр цены', function () { + "use strict"; + var testBase, result, less, bigger, free; + free = new Event(); + less = new Event(); + less.cost = 100; + less.id = 1; + bigger = new Event(); + bigger.cost = 999; + bigger.id = 2; + testBase = new BaseEvent([less, bigger, free]); + + result = testBase.getEventWithCost(10, 101); + equal(result.items.length, 1); + ok(result.items.some(function (event) { + return event.id === 1; + })); +}); +test('Сортировка по звездам)))', function () { + "use strict"; + var testBase = new BaseEvent([new Event({"stars": 3}), new Event({"stars": 2}), new Event({"stars": 5})]), + sortByStarsEventBase = testBase.sortByStars(); + equal(testBase.items.length, sortByStarsEventBase.items.length); + ok(sortByStarsEventBase.items[0].stars === 5); + ok(sortByStarsEventBase.items[1].stars === 3); + ok(sortByStarsEventBase.items[2].stars === 2); +}); +test('Сортировка по дате', function () { + "use strict"; + var testBase = new BaseEvent([new Event({"start": new Date(1), "finish": new Date(2), "id": 2}), + new Event({"start": new Date(0), "finish": new Date(1), "id": 1}), + new Event({"start": new Date(2), "finish": new Date(3), "id": 3})]), + sortByDateEventBase = testBase.sortByDate(); + equal(testBase.items.length, sortByDateEventBase.items.length); + ok(sortByDateEventBase.items[0].id === 1); + ok(sortByDateEventBase.items[1].id === 2); + ok(sortByDateEventBase.items[2].id === 3); +}); \ No newline at end of file diff --git a/WebSite/Scripts/test/CollectionTest.html b/WebSite/Scripts/test/CollectionTest.html new file mode 100644 index 0000000..c155a06 --- /dev/null +++ b/WebSite/Scripts/test/CollectionTest.html @@ -0,0 +1,15 @@ + + + + + + + + + +

    QUnit test env

    +

    +

    +
      + + \ No newline at end of file diff --git a/WebSite/Scripts/test/CollectionTest.js b/WebSite/Scripts/test/CollectionTest.js new file mode 100644 index 0000000..4f12c90 --- /dev/null +++ b/WebSite/Scripts/test/CollectionTest.js @@ -0,0 +1,78 @@ +/*global + module: false, + test: false, + equal: false, + ok: false, + deepEqual: false, + BaseEvent: false, + Event: false, + Collection: false + */ +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/WebSite/Scripts/test/EventTest.html b/WebSite/Scripts/test/EventTest.html new file mode 100644 index 0000000..e73cb10 --- /dev/null +++ b/WebSite/Scripts/test/EventTest.html @@ -0,0 +1,18 @@ + + + + + + + + + + + + +

      QUnit test env

      +

      +

      +
        + + \ No newline at end of file diff --git a/WebSite/Scripts/test/EventTest.js b/WebSite/Scripts/test/EventTest.js new file mode 100644 index 0000000..bda9137 --- /dev/null +++ b/WebSite/Scripts/test/EventTest.js @@ -0,0 +1,137 @@ +/*global + module: false, + test: false, + equal: false, + ok: false, + deepEqual: false, + BaseEvent: false, + Event: false, + Collection: false + */ +module("Tests of Event's constructor"); +test('Проверка пустого конструктора Event', function () { + "use strict"; + var event = new Event(); + ok(event instanceof Event); +}); +test('Проверка не пустого конструктора Event', function () { + "use strict"; + var event = new Event(new Event()); + ok(event instanceof Event); +}); +test('Начальное время не валидно', function () { + "use strict"; + var event = new Event(), + error; + event.start = "Ой не время"; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше, чем должно было быть"); + equal(error[0].nameField, "start", "Ошибка возникла в другом поле"); +}); +test('Дата конца события не валидна', function () { + "use strict"; + var event = new Event(), + error; + event.end = "Ой не время"; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше, чем должно было быть"); + equal(error[0].nameField, "end", "Ошибка возникла в другом поле"); +}); +test('Даты перепутаны местами', function () { + "use strict"; + var event = new Event(), + error; + event.start = new Date(100); + event.end = new Date(1); + error = Event.isValidate(event); + equal(error.length, 2, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "start", "Ошибка возникла в другом поле"); + equal(error[1].nameField, "end", "Ошибка возникла в другом поле"); + + event.start = new Date(1); + event.end = new Date(100); + error = Event.isValidate(event); + equal(error.length, 0, "Данные корректны!!! ошибки быть не должно"); +}); +test('Цена посещения положителеное число', function () { + "use strict"; + var event = new Event(), + error; + event.cost = "Ой не число"; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "cost", "Ошибка возникла в другом поле"); + + event.cost = -123; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "cost", "Ошибка возникла в другом поле"); + + event.cost = 100; + error = Event.isValidate(event); + equal(error.length, 0, "Данные корректны!!! ошибки быть не должно"); +}); +test('Название события от 1 до 18 символов', function () { + "use strict"; + var event = new Event(), + error; + event.name = ""; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "name", "Ошибка возникла в другом поле"); + + event.name = "1234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910123456789101234567891012345678910"; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "name", "Ошибка возникла в другом поле"); + + event.name = "Что-то важное"; + error = Event.isValidate(event); + equal(error.length, 0, "Данные корректны!!! ошибки быть не должно"); +}); + +test('GPS - два числа', function () { + "use strict"; + var event = new Event(), + error; + event.gps.x = event.gps.y = "Ой не число"; + error = Event.isValidate(event); + equal(error.length, 2, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "gps.x", "Ошибка возникла в другом поле"); + equal(error[1].nameField, "gps.y", "Ошибка возникла в другом поле"); + + event.gps.x = event.gps.y = 123; + error = Event.isValidate(event); + equal(error.length, 0, "Данные корректны!!! ошибки быть не должно"); +}); +test('Stars - рейтинг = 0,1,2,3,4,5', function () { + "use strict"; + var event = new Event(), + error, + i; + event.stars = "Ой не число"; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "stars", "Ошибка возникла в другом поле"); + + event.stars = 1.1; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "stars", "Ошибка возникла в другом поле"); + + event.stars = 6; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "stars", "Ошибка возникла в другом поле"); + + event.stars = -1; + error = Event.isValidate(event); + equal(error.length, 1, "Ошибок больше или меньше, чем должно было быть"); + equal(error[0].nameField, "stars", "Ошибка возникла в другом поле"); + + for (i = 0; i < 5; i += 1) { + event.stars = i; + error = Event.isValidate(event); + equal(error.length, 0, "Данные корректны!!! ошибки быть не должно"); + } +}); \ No newline at end of file diff --git a/WebSite/Scripts/test/ModelTest.html b/WebSite/Scripts/test/ModelTest.html new file mode 100644 index 0000000..15e15bf --- /dev/null +++ b/WebSite/Scripts/test/ModelTest.html @@ -0,0 +1,15 @@ + + + + + + + + + +

        QUnit test env

        +

        +

        +
          + + \ No newline at end of file diff --git a/WebSite/Scripts/test/ModelTest.js b/WebSite/Scripts/test/ModelTest.js new file mode 100644 index 0000000..548e29a --- /dev/null +++ b/WebSite/Scripts/test/ModelTest.js @@ -0,0 +1,38 @@ +/*global + module: false, + test: false, + equal: false, + ok: false, + Model: false, + */ +(function () { + "use strict"; + var TestObject = function (number) { + this.myNumber = number; + }; + TestObject.prototype.commonNumber = 20; + module("Create model"); + test('Проверка конструктора клонирования', function () { + var model = new Model(new TestObject(1)); + equal(typeof model.myNumber, "number", "Личный объект не скопировался"); + equal(typeof model.commonNumber, "number", "Объекты прототипа не скопировались"); + }); + test('Проверка метода get()', function () { + 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 () { + 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, "Ошибка при присвоении наследуемому полю через прототип"); + }); +}()); + + diff --git a/WebSite/base.json b/WebSite/base.json new file mode 100644 index 0000000..cf7321a --- /dev/null +++ b/WebSite/base.json @@ -0,0 +1 @@ +{"items":[{"start":"2012/1/1","end":"2012/1/10","gps":{"x":0,"y":0},"name":"Новый год 2012","stars":3,"cost":100,"parties":["Я"],"id":"9aсe6fe2-e064-2e79-fe5b-2626c868caaa"},{"start":"2013/1/1","end":"2013/1/10","gps":{"x":234,"y":0},"name":"Новый год 2013","stars":1,"cost":200,"parties":["Я","Друг"],"id":"20ed3df2-c390-3726-3ade-2b34a59666fa"},{"start":"2014/1/1","end":"2014/1/10","gps":{"x":123,"y":23},"name":"Новый год 2014","stars":5,"cost":0,"parties":["Я","Друг","Еще один друг"],"id":"20ed3df2-c390-3726-3ade-2b34a59777fa"},{"start":"2012/9/1","end":"2013/1/1","gps":{"x":34,"y":545},"name":"Подготовка к новому году","stars":0,"cost":0,"parties":["Друг","Еще один друг"],"id":"20ed3df2-c390-3726-4bde-2b34a59777fa"},{"start":"2012/10/2","end":"2012/10/2","gps":{"x":0,"y":0},"name":"Что-то","cost":0,"stars":0,"parties":[],"id":"264af7b5-7148-48c1-fde3-6a75f9fde854"},{"start":"2012/10/2","end":"2012/10/2","gps":{"x":0,"y":0},"name":"Что-то","stars":0,"cost":0,"parties":[],"id":"32cec906-ca37-feab-f91d-31b4bf4aee4d"},{"start":"2012/10/2","end":"2012/10/2","gps":{"x":0,"y":0},"name":"EBBB","stars":3,"cost":0,"parties":[],"id":"7aeab6d3-9716-8f68-f08e-72e250bba170"},{"start":"2012/10/2","end":"2012/10/2","gps":{"x":0,"y":0},"name":"Что-то","stars":0,"cost":0,"parties":[],"id":"9ee11c5a-51a7-56bd-b452-c148d06ef7c1"},{"start":"2012/10/2","end":"2012/10/2","gps":{"x":0,"y":0},"name":"Что-то","stars":0,"cost":0,"parties":[],"id":"ae29f88-bf68-1cbd-e361-689eb0fbba86"},{"start":"2012/10/2","end":"2012/10/2","gps":{"x":0,"y":0},"name":"Что-то","stars":0,"cost":0,"parties":[],"id":"93e9c587-b894-95a2-4201-b630d8be44cd"},{"start":"2012/10/2","end":"2012/10/2","gps":{"x":0,"y":0},"name":"Что-то","stars":0,"cost":0,"parties":[],"id":"96da5ca6-920e-eb2a-5382-ba03dbc18c8c"},{"start":"2012/10/2","end":"2012/10/2","gps":{"x":0,"y":0},"name":"Что-то","stars":0,"cost":0,"parties":[],"id":"a3be4e67-ec51-5dba-c225-c219c141bceb"}]} \ No newline at end of file diff --git a/WebSite/newIndex.html b/WebSite/newIndex.html new file mode 100644 index 0000000..9d5069f --- /dev/null +++ b/WebSite/newIndex.html @@ -0,0 +1,159 @@ + + + + + +
          +
          +
          +
          + Когда: + + - + +
          +
          +
          + Что + +
          +
          +
          + Где? ( + + ; + + ) +
          +
          +
          + Важность + +
          +
          +
          + Цена посещения + +
          +
          +
          +
          Список участников:
          +
            +
          1. +
          2. +
          3. +
          +
          +
          + +
          +
          +
          +
          +
          + Показать события, которые +
          +
          + Вообще есть + +
          +
          + Прошли + +
          +
          + Идут + +
          +
          + Будут идти + +
          +
          + В период + + + + - + +
          +
          + Показать события, которые стоят +
          +
          + Без разницы сколько + +
          +
          + Стоят не меньше X и не больше Y + + + - + +
          +
          + Отсортировать события.. +
          +
          + Никак + +
          +
          + По звездам + +
          +
          + По дате + +
          +
          +
          +
          +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          НачалоКонецЧтоXYЗвездочкиЦенаУчастники
          НачалоКонецЧтоXYЗвездочкиЦенаУчастники
          +
          +
          + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WebSite/style.css b/WebSite/style.css new file mode 100644 index 0000000..13d768d --- /dev/null +++ b/WebSite/style.css @@ -0,0 +1,34 @@ +*{ +} +#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 +} + +.Error { + color: orange; +} + +.CriticalError { + color: red; +} +.ColonTable { + float: left; + overflow: hidden; +} \ No newline at end of file diff --git a/es5-shim b/es5-shim new file mode 160000 index 0000000..12adafe --- /dev/null +++ b/es5-shim @@ -0,0 +1 @@ +Subproject commit 12adafe3552d3a3d69a8216314614140569387e2 diff --git a/jquery b/jquery new file mode 160000 index 0000000..b382af6 --- /dev/null +++ b/jquery @@ -0,0 +1 @@ +Subproject commit b382af685a3f590d03be7a9dc790a657c7b33f99 diff --git a/qunit b/qunit new file mode 160000 index 0000000..cce90d3 --- /dev/null +++ b/qunit @@ -0,0 +1 @@ +Subproject commit cce90d380284d4ca79a66420564d5bc198c4fa53 diff --git a/server.js b/server.js new file mode 100644 index 0000000..03a3d0e --- /dev/null +++ b/server.js @@ -0,0 +1,4 @@ +var connect = require('connect'); +connect.createServer( +connect.static(__dirname) +).listen(3000, "192.168.56.102"); \ No newline at end of file