From 1ef2b82cf1e0d1e1d42b3cc805acce17f0881380 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 13 Jul 2019 12:26:54 +0000 Subject: [PATCH 01/17] Bump lodash from 4.17.11 to 4.17.14 Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.14. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.14) Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index aeb4aabbb..079c48c64 100644 --- a/yarn.lock +++ b/yarn.lock @@ -945,9 +945,9 @@ locate-path@^2.0.0: path-exists "^3.0.0" lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5: - version "4.17.11" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" - integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + version "4.17.14" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba" + integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw== lru-cache@2: version "2.7.3" From 494f4452ea100ca462e17b16acd3d29aab72ce2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2019 07:42:15 +0000 Subject: [PATCH 02/17] Bump bootstrap from 3.3.7 to 3.4.1 Bumps [bootstrap](https://github.com/twbs/bootstrap) from 3.3.7 to 3.4.1. - [Release notes](https://github.com/twbs/bootstrap/releases) - [Commits](https://github.com/twbs/bootstrap/compare/v3.3.7...v3.4.1) Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index aeb4aabbb..cb8cc6e19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -242,9 +242,9 @@ bootstrap-switch@3.3.2: jquery ">=1.9.0" bootstrap@^3.1.1: - version "3.3.7" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.3.7.tgz#5a389394549f23330875a3b150656574f8a9eb71" - integrity sha1-WjiTlFSfIzMIdaOxUGVldPip63E= + version "3.4.1" + resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.4.1.tgz#c3a347d419e289ad11f4033e3c4132b87c081d72" + integrity sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA== brace-expansion@^1.1.7: version "1.1.11" From d0fbba2ccf85e362219b67ead2ff00e377f900e9 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 17 Jul 2019 10:31:43 +0200 Subject: [PATCH 03/17] updated angular-xeditable to remove dependency to jquery 1.11.1 --- package.json | 2 +- yarn.lock | 30 ++++++------------------------ 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 6e0dad248..a866cda68 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "angular-ui-bootstrap": "0.14.3", "angular-ui-calendar": "https://github.com/angular-ui/ui-calendar.git#1.0.1", "angular-unsavedchanges": "0.2", - "angular-xeditable": "0.1", + "angular-xeditable": "0.10", "bootstrap-switch": "3.3.2", "checklist-model": "0.2", "d3": "3.5", diff --git a/yarn.lock b/yarn.lock index 079c48c64..ee542ee3f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -180,15 +180,12 @@ angular-unsavedchanges@0.2: resolved "https://registry.yarnpkg.com/angular-unsavedchanges/-/angular-unsavedchanges-0.2.5.tgz#34be961d547051f2c6d536c60a5b42f565c8858b" integrity sha1-NL6WHVRwUfLG1TbGCltC9WXIhYs= -angular-xeditable@0.1: - version "0.1.12" - resolved "https://registry.yarnpkg.com/angular-xeditable/-/angular-xeditable-0.1.12.tgz#482c377cce1db49876f8ae220cce4db8d79e63c5" - integrity sha1-SCw3fM4dtJh2+K4iDM5NuNeeY8U= +angular-xeditable@0.10: + version "0.10.0" + resolved "https://registry.yarnpkg.com/angular-xeditable/-/angular-xeditable-0.10.0.tgz#81f0e477d0bc046bf85d9972dd8af341cf18828a" + integrity sha512-XZcy29EQtq5/ZrLABbhUr3MLT+lfAHfFpkbHFxY/J8PAaiqa+3b7/U6rg+TUV0oIQ5QfeeXCjHwg3gIyU0uDdA== dependencies: angular "~1.x" - bootstrap "^3.1.1" - jquery "^1.11.1" - moment "^2.5.0" angular@1.6: version "1.6.10" @@ -241,11 +238,6 @@ bootstrap-switch@3.3.2: dependencies: jquery ">=1.9.0" -bootstrap@^3.1.1: - version "3.3.7" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.3.7.tgz#5a389394549f23330875a3b150656574f8a9eb71" - integrity sha1-WjiTlFSfIzMIdaOxUGVldPip63E= - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -880,21 +872,11 @@ jquery-minicolors@^2.1.10: version "1.10.4" resolved "https://github.com/devongovett/jqueryui-npm.git#51bc3549dd6530a18f43be45c3e8ae520805b9e4" -"jquery@>= 1.7.x", jquery@>=1.7.1, jquery@>=1.9.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca" - integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg== - -jquery@>=3.4.0: +"jquery@>= 1.7.x", jquery@>=1.7.1, jquery@>=1.9.0, jquery@>=3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== -jquery@^1.11.1: - version "1.12.4" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-1.12.4.tgz#01e1dfba290fe73deba77ceeacb0f9ba2fec9e0c" - integrity sha1-AeHfuikP5z3rp3zurLD5ui/sngw= - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1015,7 +997,7 @@ moment-timezone@0.5: dependencies: moment ">= 2.9.0" -moment@2.22, "moment@>= 2.9.0", moment@>=2.5.0, "moment@>=2.8.0 <3.0.0", moment@^2.5.0: +moment@2.22, "moment@>= 2.9.0", moment@>=2.5.0, "moment@>=2.8.0 <3.0.0": version "2.22.2" resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= From 48c68b29be8a726183a3ed0ad6a2cf30f7028855 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Wed, 17 Jul 2019 15:18:39 +0200 Subject: [PATCH 04/17] removed old fullcalendar artefact --- .../javascripts/fullcalendar/fullcalendar.js | 6112 ----------------- 1 file changed, 6112 deletions(-) delete mode 100644 lib/assets/javascripts/fullcalendar/fullcalendar.js diff --git a/lib/assets/javascripts/fullcalendar/fullcalendar.js b/lib/assets/javascripts/fullcalendar/fullcalendar.js deleted file mode 100644 index a4c60d652..000000000 --- a/lib/assets/javascripts/fullcalendar/fullcalendar.js +++ /dev/null @@ -1,6112 +0,0 @@ -/*! - * FullCalendar v1.6.4 - * Docs & License: http://arshaw.com/fullcalendar/ - * (c) 2013 Adam Shaw - */ - -/* - * Use fullcalendar.css for basic styling. - * For event drag & drop, requires jQuery UI draggable. - * For event resizing, requires jQuery UI resizable. - */ - -(function($, undefined) { - - -;; - -var defaults = { - - // display - defaultView: 'month', - aspectRatio: 1.35, - header: { - left: 'title', - center: '', - right: 'today prev,next' - }, - weekends: true, - weekNumbers: false, - weekNumberCalculation: 'iso', - weekNumberTitle: 'W', - - // editing - //editable: false, - //disableDragging: false, - //disableResizing: false, - - allDayDefault: true, - ignoreTimezone: true, - - // event ajax - lazyFetching: true, - startParam: 'start', - endParam: 'end', - - // time formats - titleFormat: { - month: 'MMMM yyyy', - week: "MMM d[ yyyy]{ '—'[ MMM] d yyyy}", - day: 'dddd, MMM d, yyyy' - }, - columnFormat: { - month: 'ddd', - week: 'ddd M/d', - day: 'dddd M/d' - }, - timeFormat: { // for event elements - '': 'h(:mm)t' // default - }, - - // locale - isRTL: false, - firstDay: 0, - monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'], - monthNamesShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'], - dayNames: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], - dayNamesShort: ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'], - buttonText: { - prev: "", - next: "", - prevYear: "«", - nextYear: "»", - today: 'today', - month: 'month', - week: 'week', - day: 'day' - }, - - // jquery-ui theming - theme: false, - buttonIcons: { - prev: 'circle-triangle-w', - next: 'circle-triangle-e' - }, - - //selectable: false, - unselectAuto: true, - - dropAccept: '*', - - handleWindowResize: true - -}; - -// right-to-left defaults -var rtlDefaults = { - header: { - left: 'next,prev today', - center: '', - right: 'title' - }, - buttonText: { - prev: "", - next: "", - prevYear: "»", - nextYear: "«" - }, - buttonIcons: { - prev: 'circle-triangle-e', - next: 'circle-triangle-w' - } -}; - - - -;; - -var fc = $.fullCalendar = { version: "1.6.4" }; -var fcViews = fc.views = {}; - - -$.fn.fullCalendar = function(options) { - - - // method calling - if (typeof options == 'string') { - var args = Array.prototype.slice.call(arguments, 1); - var res; - this.each(function() { - var calendar = $.data(this, 'fullCalendar'); - if (calendar && $.isFunction(calendar[options])) { - var r = calendar[options].apply(calendar, args); - if (res === undefined) { - res = r; - } - if (options == 'destroy') { - $.removeData(this, 'fullCalendar'); - } - } - }); - if (res !== undefined) { - return res; - } - return this; - } - - options = options || {}; - - // would like to have this logic in EventManager, but needs to happen before options are recursively extended - var eventSources = options.eventSources || []; - delete options.eventSources; - if (options.events) { - eventSources.push(options.events); - delete options.events; - } - - - options = $.extend(true, {}, - defaults, - (options.isRTL || options.isRTL===undefined && defaults.isRTL) ? rtlDefaults : {}, - options - ); - - - this.each(function(i, _element) { - var element = $(_element); - var calendar = new Calendar(element, options, eventSources); - element.data('fullCalendar', calendar); // TODO: look into memory leak implications - calendar.render(); - }); - - - return this; - -}; - - -// function for adding/overriding defaults -function setDefaults(d) { - $.extend(true, defaults, d); -} - - - -;; - - -function Calendar(element, options, eventSources) { - var t = this; - - - // exports - t.options = options; - t.render = render; - t.destroy = destroy; - t.refetchEvents = refetchEvents; - t.reportEvents = reportEvents; - t.reportEventChange = reportEventChange; - t.rerenderEvents = rerenderEvents; - t.changeView = changeView; - t.select = select; - t.unselect = unselect; - t.prev = prev; - t.next = next; - t.prevYear = prevYear; - t.nextYear = nextYear; - t.today = today; - t.gotoDate = gotoDate; - t.incrementDate = incrementDate; - t.formatDate = function(format, date) { return formatDate(format, date, options) }; - t.formatDates = function(format, date1, date2) { return formatDates(format, date1, date2, options) }; - t.getDate = getDate; - t.getView = getView; - t.option = option; - t.trigger = trigger; - - - // imports - EventManager.call(t, options, eventSources); - var isFetchNeeded = t.isFetchNeeded; - var fetchEvents = t.fetchEvents; - - - // locals - var _element = element[0]; - var header; - var headerElement; - var content; - var tm; // for making theme classes - var currentView; - var elementOuterWidth; - var suggestedViewHeight; - var resizeUID = 0; - var ignoreWindowResize = 0; - var date = new Date(); - var events = []; - var _dragElement; - - - - /* Main Rendering - -----------------------------------------------------------------------------*/ - - - setYMD(date, options.year, options.month, options.date); - - - function render(inc) { - if (!content) { - initialRender(); - } - else if (elementVisible()) { - // mainly for the public API - calcSize(); - _renderView(inc); - } - } - - - function initialRender() { - tm = options.theme ? 'ui' : 'fc'; - element.addClass('fc'); - if (options.isRTL) { - element.addClass('fc-rtl'); - } - else { - element.addClass('fc-ltr'); - } - if (options.theme) { - element.addClass('ui-widget'); - } - - content = $("
") - .prependTo(element); - - header = new Header(t, options); - headerElement = header.render(); - if (headerElement) { - element.prepend(headerElement); - } - - changeView(options.defaultView); - - if (options.handleWindowResize) { - $(window).resize(windowResize); - } - - // needed for IE in a 0x0 iframe, b/c when it is resized, never triggers a windowResize - if (!bodyVisible()) { - lateRender(); - } - } - - - // called when we know the calendar couldn't be rendered when it was initialized, - // but we think it's ready now - function lateRender() { - setTimeout(function() { // IE7 needs this so dimensions are calculated correctly - if (!currentView.start && bodyVisible()) { // !currentView.start makes sure this never happens more than once - renderView(); - } - },0); - } - - - function destroy() { - - if (currentView) { - trigger('viewDestroy', currentView, currentView, currentView.element); - currentView.triggerEventDestroy(); - } - - $(window).unbind('resize', windowResize); - - header.destroy(); - content.remove(); - element.removeClass('fc fc-rtl ui-widget'); - } - - - function elementVisible() { - return element.is(':visible'); - } - - - function bodyVisible() { - return $('body').is(':visible'); - } - - - - /* View Rendering - -----------------------------------------------------------------------------*/ - - - function changeView(newViewName) { - if (!currentView || newViewName != currentView.name) { - _changeView(newViewName); - } - } - - - function _changeView(newViewName) { - ignoreWindowResize++; - - if (currentView) { - trigger('viewDestroy', currentView, currentView, currentView.element); - unselect(); - currentView.triggerEventDestroy(); // trigger 'eventDestroy' for each event - freezeContentHeight(); - currentView.element.remove(); - header.deactivateButton(currentView.name); - } - - header.activateButton(newViewName); - - currentView = new fcViews[newViewName]( - $("
") - .appendTo(content), - t // the calendar object - ); - - renderView(); - unfreezeContentHeight(); - - ignoreWindowResize--; - } - - - function renderView(inc) { - if ( - !currentView.start || // never rendered before - inc || date < currentView.start || date >= currentView.end // or new date range - ) { - if (elementVisible()) { - _renderView(inc); - } - } - } - - - function _renderView(inc) { // assumes elementVisible - ignoreWindowResize++; - - if (currentView.start) { // already been rendered? - trigger('viewDestroy', currentView, currentView, currentView.element); - unselect(); - clearEvents(); - } - - freezeContentHeight(); - currentView.render(date, inc || 0); // the view's render method ONLY renders the skeleton, nothing else - setSize(); - unfreezeContentHeight(); - (currentView.afterRender || noop)(); - - updateTitle(); - updateTodayButton(); - - trigger('viewRender', currentView, currentView, currentView.element); - currentView.trigger('viewDisplay', _element); // deprecated - - ignoreWindowResize--; - - getAndRenderEvents(); - } - - - - /* Resizing - -----------------------------------------------------------------------------*/ - - - function updateSize() { - if (elementVisible()) { - unselect(); - clearEvents(); - calcSize(); - setSize(); - renderEvents(); - } - } - - - function calcSize() { // assumes elementVisible - if (options.contentHeight) { - suggestedViewHeight = options.contentHeight; - } - else if (options.height) { - suggestedViewHeight = options.height - (headerElement ? headerElement.height() : 0) - vsides(content); - } - else { - suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5)); - } - } - - - function setSize() { // assumes elementVisible - - if (suggestedViewHeight === undefined) { - calcSize(); // for first time - // NOTE: we don't want to recalculate on every renderView because - // it could result in oscillating heights due to scrollbars. - } - - ignoreWindowResize++; - currentView.setHeight(suggestedViewHeight); - currentView.setWidth(content.width()); - ignoreWindowResize--; - - elementOuterWidth = element.outerWidth(); - } - - - function windowResize() { - if (!ignoreWindowResize) { - if (currentView.start) { // view has already been rendered - var uid = ++resizeUID; - setTimeout(function() { // add a delay - if (uid == resizeUID && !ignoreWindowResize && elementVisible()) { - if (elementOuterWidth != (elementOuterWidth = element.outerWidth())) { - ignoreWindowResize++; // in case the windowResize callback changes the height - updateSize(); - currentView.trigger('windowResize', _element); - ignoreWindowResize--; - } - } - }, 200); - }else{ - // calendar must have been initialized in a 0x0 iframe that has just been resized - lateRender(); - } - } - } - - - - /* Event Fetching/Rendering - -----------------------------------------------------------------------------*/ - // TODO: going forward, most of this stuff should be directly handled by the view - - - function refetchEvents() { // can be called as an API method - clearEvents(); - fetchAndRenderEvents(); - } - - - function rerenderEvents(modifiedEventID) { // can be called as an API method - clearEvents(); - renderEvents(modifiedEventID); - } - - - function renderEvents(modifiedEventID) { // TODO: remove modifiedEventID hack - if (elementVisible()) { - currentView.setEventData(events); // for View.js, TODO: unify with renderEvents - currentView.renderEvents(events, modifiedEventID); // actually render the DOM elements - currentView.trigger('eventAfterAllRender'); - } - } - - - function clearEvents() { - currentView.triggerEventDestroy(); // trigger 'eventDestroy' for each event - currentView.clearEvents(); // actually remove the DOM elements - currentView.clearEventData(); // for View.js, TODO: unify with clearEvents - } - - - function getAndRenderEvents() { - if (!options.lazyFetching || isFetchNeeded(currentView.visStart, currentView.visEnd)) { - fetchAndRenderEvents(); - } - else { - renderEvents(); - } - } - - - function fetchAndRenderEvents() { - fetchEvents(currentView.visStart, currentView.visEnd); - // ... will call reportEvents - // ... which will call renderEvents - } - - - // called when event data arrives - function reportEvents(_events) { - events = _events; - renderEvents(); - } - - - // called when a single event's data has been changed - function reportEventChange(eventID) { - rerenderEvents(eventID); - } - - - - /* Header Updating - -----------------------------------------------------------------------------*/ - - - function updateTitle() { - header.updateTitle(currentView.title); - } - - - function updateTodayButton() { - var today = new Date(); - if (today >= currentView.start && today < currentView.end) { - header.disableButton('today'); - } - else { - header.enableButton('today'); - } - } - - - - /* Selection - -----------------------------------------------------------------------------*/ - - - function select(start, end, allDay) { - currentView.select(start, end, allDay===undefined ? true : allDay); - } - - - function unselect() { // safe to be called before renderView - if (currentView) { - currentView.unselect(); - } - } - - - - /* Date - -----------------------------------------------------------------------------*/ - - - function prev() { - renderView(-1); - } - - - function next() { - renderView(1); - } - - - function prevYear() { - addYears(date, -1); - renderView(); - } - - - function nextYear() { - addYears(date, 1); - renderView(); - } - - - function today() { - date = new Date(); - renderView(); - } - - - function gotoDate(year, month, dateOfMonth) { - if (year instanceof Date) { - date = cloneDate(year); // provided 1 argument, a Date - }else{ - setYMD(date, year, month, dateOfMonth); - } - renderView(); - } - - - function incrementDate(years, months, days) { - if (years !== undefined) { - addYears(date, years); - } - if (months !== undefined) { - addMonths(date, months); - } - if (days !== undefined) { - addDays(date, days); - } - renderView(); - } - - - function getDate() { - return cloneDate(date); - } - - - - /* Height "Freezing" - -----------------------------------------------------------------------------*/ - - - function freezeContentHeight() { - content.css({ - width: '100%', - height: content.height(), - overflow: 'hidden' - }); - } - - - function unfreezeContentHeight() { - content.css({ - width: '', - height: '', - overflow: '' - }); - } - - - - /* Misc - -----------------------------------------------------------------------------*/ - - - function getView() { - return currentView; - } - - - function option(name, value) { - if (value === undefined) { - return options[name]; - } - if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') { - options[name] = value; - updateSize(); - } - } - - - function trigger(name, thisObj) { - if (options[name]) { - return options[name].apply( - thisObj || _element, - Array.prototype.slice.call(arguments, 2) - ); - } - } - - - - /* External Dragging - ------------------------------------------------------------------------*/ - - if (options.droppable) { - $(document) - .bind('dragstart', function(ev, ui) { - var _e = ev.target; - var e = $(_e); - if (!e.parents('.fc').length) { // not already inside a calendar - var accept = options.dropAccept; - if ($.isFunction(accept) ? accept.call(_e, e) : e.is(accept)) { - _dragElement = _e; - currentView.dragStart(_dragElement, ev, ui); - } - } - }) - .bind('dragstop', function(ev, ui) { - if (_dragElement) { - currentView.dragStop(_dragElement, ev, ui); - _dragElement = null; - } - }); - } - - -} - -;; - -function Header(calendar, options) { - var t = this; - - - // exports - t.render = render; - t.destroy = destroy; - t.updateTitle = updateTitle; - t.activateButton = activateButton; - t.deactivateButton = deactivateButton; - t.disableButton = disableButton; - t.enableButton = enableButton; - - - // locals - var element = $([]); - var tm; - - - - function render() { - tm = options.theme ? 'ui' : 'fc'; - var sections = options.header; - if (sections) { - element = $("") - .append( - $("") - .append(renderSection('left')) - .append(renderSection('center')) - .append(renderSection('right')) - ); - return element; - } - } - - - function destroy() { - element.remove(); - } - - - function renderSection(position) { - var e = $(""; - - if (showWeekNumbers) { - html += - ""; - } - - for (col=0; col" + - htmlEscape(formatDate(date, colFormat)) + - ""; - } - - html += ""; - - return html; - } - - - function buildBodyHTML() { - var contentClass = tm + "-widget-content"; - var html = ''; - var row; - var col; - var date; - - html += ""; - - for (row=0; row" + - "
" + - htmlEscape(formatDate(date, weekNumberFormat)) + - "
" + - ""; - } - - for (col=0; col" + - "
"; - - if (showNumbers) { - html += "
" + date.getDate() + "
"; - } - - html += - "
" + - "
 
" + - "
" + - "
" + - ""; - - return html; - } - - - - /* Dimensions - -----------------------------------------------------------*/ - - - function setHeight(height) { - viewHeight = height; - - var bodyHeight = viewHeight - head.height(); - var rowHeight; - var rowHeightLast; - var cell; - - if (opt('weekMode') == 'variable') { - rowHeight = rowHeightLast = Math.floor(bodyHeight / (rowCnt==1 ? 2 : 6)); - }else{ - rowHeight = Math.floor(bodyHeight / rowCnt); - rowHeightLast = bodyHeight - rowHeight * (rowCnt-1); - } - - bodyFirstCells.each(function(i, _cell) { - if (i < rowCnt) { - cell = $(_cell); - cell.find('> div').css( - 'min-height', - (i==rowCnt-1 ? rowHeightLast : rowHeight) - vsides(cell) - ); - } - }); - - } - - - function setWidth(width) { - viewWidth = width; - colPositions.clear(); - colContentPositions.clear(); - - weekNumberWidth = 0; - if (showWeekNumbers) { - weekNumberWidth = head.find('th.fc-week-number').outerWidth(); - } - - colWidth = Math.floor((viewWidth - weekNumberWidth) / colCnt); - setOuterWidth(headCells.slice(0, -1), colWidth); - } - - - - /* Day clicking and binding - -----------------------------------------------------------*/ - - - function dayBind(days) { - days.click(dayClick) - .mousedown(daySelectionMousedown); - } - - - function dayClick(ev) { - if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick - var date = parseISO8601($(this).data('date')); - trigger('dayClick', this, date, true, ev); - } - } - - - - /* Semi-transparent Overlay Helpers - ------------------------------------------------------*/ - // TODO: should be consolidated with AgendaView's methods - - - function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive - - if (refreshCoordinateGrid) { - coordinateGrid.build(); - } - - var segments = rangeToSegments(overlayStart, overlayEnd); - - for (var i=0; i") - .appendTo(element); - - if (opt('allDaySlot')) { - - daySegmentContainer = - $("
") - .appendTo(slotLayer); - - s = - "
"); - var buttonStr = options.header[position]; - if (buttonStr) { - $.each(buttonStr.split(' '), function(i) { - if (i > 0) { - e.append(""); - } - var prevButton; - $.each(this.split(','), function(j, buttonName) { - if (buttonName == 'title') { - e.append("

 

"); - if (prevButton) { - prevButton.addClass(tm + '-corner-right'); - } - prevButton = null; - }else{ - var buttonClick; - if (calendar[buttonName]) { - buttonClick = calendar[buttonName]; // calendar method - } - else if (fcViews[buttonName]) { - buttonClick = function() { - button.removeClass(tm + '-state-hover'); // forget why - calendar.changeView(buttonName); - }; - } - if (buttonClick) { - var icon = options.theme ? smartProperty(options.buttonIcons, buttonName) : null; // why are we using smartProperty here? - var text = smartProperty(options.buttonText, buttonName); // why are we using smartProperty here? - var button = $( - "" + - (icon ? - "" + - "" + - "" : - text - ) + - "" - ) - .click(function() { - if (!button.hasClass(tm + '-state-disabled')) { - buttonClick(); - } - }) - .mousedown(function() { - button - .not('.' + tm + '-state-active') - .not('.' + tm + '-state-disabled') - .addClass(tm + '-state-down'); - }) - .mouseup(function() { - button.removeClass(tm + '-state-down'); - }) - .hover( - function() { - button - .not('.' + tm + '-state-active') - .not('.' + tm + '-state-disabled') - .addClass(tm + '-state-hover'); - }, - function() { - button - .removeClass(tm + '-state-hover') - .removeClass(tm + '-state-down'); - } - ) - .appendTo(e); - disableTextSelection(button); - if (!prevButton) { - button.addClass(tm + '-corner-left'); - } - prevButton = button; - } - } - }); - if (prevButton) { - prevButton.addClass(tm + '-corner-right'); - } - }); - } - return e; - } - - - function updateTitle(html) { - element.find('h2') - .html(html); - } - - - function activateButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .addClass(tm + '-state-active'); - } - - - function deactivateButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .removeClass(tm + '-state-active'); - } - - - function disableButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .addClass(tm + '-state-disabled'); - } - - - function enableButton(buttonName) { - element.find('span.fc-button-' + buttonName) - .removeClass(tm + '-state-disabled'); - } - - -} - -;; - -fc.sourceNormalizers = []; -fc.sourceFetchers = []; - -var ajaxDefaults = { - dataType: 'json', - cache: false -}; - -var eventGUID = 1; - - -function EventManager(options, _sources) { - var t = this; - - - // exports - t.isFetchNeeded = isFetchNeeded; - t.fetchEvents = fetchEvents; - t.addEventSource = addEventSource; - t.removeEventSource = removeEventSource; - t.updateEvent = updateEvent; - t.renderEvent = renderEvent; - t.removeEvents = removeEvents; - t.clientEvents = clientEvents; - t.normalizeEvent = normalizeEvent; - - - // imports - var trigger = t.trigger; - var getView = t.getView; - var reportEvents = t.reportEvents; - - - // locals - var stickySource = { events: [] }; - var sources = [ stickySource ]; - var rangeStart, rangeEnd; - var currentFetchID = 0; - var pendingSourceCnt = 0; - var loadingLevel = 0; - var cache = []; - - - for (var i=0; i<_sources.length; i++) { - _addEventSource(_sources[i]); - } - - - - /* Fetching - -----------------------------------------------------------------------------*/ - - - function isFetchNeeded(start, end) { - return !rangeStart || start < rangeStart || end > rangeEnd; - } - - - function fetchEvents(start, end) { - rangeStart = start; - rangeEnd = end; - cache = []; - var fetchID = ++currentFetchID; - var len = sources.length; - pendingSourceCnt = len; - for (var i=0; i)), return null instead - return null; -} - - -function parseISO8601(s, ignoreTimezone) { // ignoreTimezone defaults to false - // derived from http://delete.me.uk/2005/03/iso8601.html - // TODO: for a know glitch/feature, read tests/issue_206_parseDate_dst.html - var m = s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/); - if (!m) { - return null; - } - var date = new Date(m[1], 0, 1); - if (ignoreTimezone || !m[13]) { - var check = new Date(m[1], 0, 1, 9, 0); - if (m[3]) { - date.setMonth(m[3] - 1); - check.setMonth(m[3] - 1); - } - if (m[5]) { - date.setDate(m[5]); - check.setDate(m[5]); - } - fixDate(date, check); - if (m[7]) { - date.setHours(m[7]); - } - if (m[8]) { - date.setMinutes(m[8]); - } - if (m[10]) { - date.setSeconds(m[10]); - } - if (m[12]) { - date.setMilliseconds(Number("0." + m[12]) * 1000); - } - fixDate(date, check); - }else{ - date.setUTCFullYear( - m[1], - m[3] ? m[3] - 1 : 0, - m[5] || 1 - ); - date.setUTCHours( - m[7] || 0, - m[8] || 0, - m[10] || 0, - m[12] ? Number("0." + m[12]) * 1000 : 0 - ); - if (m[14]) { - var offset = Number(m[16]) * 60 + (m[18] ? Number(m[18]) : 0); - offset *= m[15] == '-' ? 1 : -1; - date = new Date(+date + (offset * 60 * 1000)); - } - } - return date; -} - - -function parseTime(s) { // returns minutes since start of day - if (typeof s == 'number') { // an hour - return s * 60; - } - if (typeof s == 'object') { // a Date object - return s.getHours() * 60 + s.getMinutes(); - } - var m = s.match(/(\d+)(?::(\d+))?\s*(\w+)?/); - if (m) { - var h = parseInt(m[1], 10); - if (m[3]) { - h %= 12; - if (m[3].toLowerCase().charAt(0) == 'p') { - h += 12; - } - } - return h * 60 + (m[2] ? parseInt(m[2], 10) : 0); - } -} - - - -/* Date Formatting ------------------------------------------------------------------------------*/ -// TODO: use same function formatDate(date, [date2], format, [options]) - - -function formatDate(date, format, options) { - return formatDates(date, null, format, options); -} - - -function formatDates(date1, date2, format, options) { - options = options || defaults; - var date = date1, - otherDate = date2, - i, len = format.length, c, - i2, formatter, - res = ''; - for (i=0; ii; i2--) { - if (formatter = dateFormatters[format.substring(i, i2)]) { - if (date) { - res += formatter(date, options); - } - i = i2 - 1; - break; - } - } - if (i2 == i) { - if (date) { - res += c; - } - } - } - } - return res; -}; - - -var dateFormatters = { - s : function(d) { return d.getSeconds() }, - ss : function(d) { return zeroPad(d.getSeconds()) }, - m : function(d) { return d.getMinutes() }, - mm : function(d) { return zeroPad(d.getMinutes()) }, - h : function(d) { return d.getHours() % 12 || 12 }, - hh : function(d) { return zeroPad(d.getHours() % 12 || 12) }, - H : function(d) { return d.getHours() }, - HH : function(d) { return zeroPad(d.getHours()) }, - d : function(d) { return d.getDate() }, - dd : function(d) { return zeroPad(d.getDate()) }, - ddd : function(d,o) { return o.dayNamesShort[d.getDay()] }, - dddd: function(d,o) { return o.dayNames[d.getDay()] }, - M : function(d) { return d.getMonth() + 1 }, - MM : function(d) { return zeroPad(d.getMonth() + 1) }, - MMM : function(d,o) { return o.monthNamesShort[d.getMonth()] }, - MMMM: function(d,o) { return o.monthNames[d.getMonth()] }, - yy : function(d) { return (d.getFullYear()+'').substring(2) }, - yyyy: function(d) { return d.getFullYear() }, - t : function(d) { return d.getHours() < 12 ? 'a' : 'p' }, - tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' }, - T : function(d) { return d.getHours() < 12 ? 'A' : 'P' }, - TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }, - u : function(d) { return formatDate(d, "yyyy-MM-dd'T'HH:mm:ss'Z'") }, - S : function(d) { - var date = d.getDate(); - if (date > 10 && date < 20) { - return 'th'; - } - return ['st', 'nd', 'rd'][date%10-1] || 'th'; - }, - w : function(d, o) { // local - return o.weekNumberCalculation(d); - }, - W : function(d) { // ISO - return iso8601Week(d); - } -}; -fc.dateFormatters = dateFormatters; - - -/* thanks jQuery UI (https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js) - * - * Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. - * `date` - the date to get the week for - * `number` - the number of the week within the year that contains this date - */ -function iso8601Week(date) { - var time; - var checkDate = new Date(date.getTime()); - - // Find Thursday of this week starting on Monday - checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); - - time = checkDate.getTime(); - checkDate.setMonth(0); // Compare with Jan 1 - checkDate.setDate(1); - return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; -} - - -;; - -fc.applyAll = applyAll; - - -/* Event Date Math ------------------------------------------------------------------------------*/ - - -function exclEndDay(event) { - if (event.end) { - return _exclEndDay(event.end, event.allDay); - }else{ - return addDays(cloneDate(event.start), 1); - } -} - - -function _exclEndDay(end, allDay) { - end = cloneDate(end); - return allDay || end.getHours() || end.getMinutes() ? addDays(end, 1) : clearTime(end); - // why don't we check for seconds/ms too? -} - - - -/* Event Element Binding ------------------------------------------------------------------------------*/ - - -function lazySegBind(container, segs, bindHandlers) { - container.unbind('mouseover').mouseover(function(ev) { - var parent=ev.target, e, - i, seg; - while (parent != this) { - e = parent; - parent = parent.parentNode; - } - if ((i = e._fci) !== undefined) { - e._fci = undefined; - seg = segs[i]; - bindHandlers(seg.event, seg.element, seg); - $(ev.target).trigger(ev); - } - ev.stopPropagation(); - }); -} - - - -/* Element Dimensions ------------------------------------------------------------------------------*/ - - -function setOuterWidth(element, width, includeMargins) { - for (var i=0, e; i=0; i--) { - res = obj[parts[i].toLowerCase()]; - if (res !== undefined) { - return res; - } - } - return obj['']; -} - - -function htmlEscape(s) { - return s.replace(/&/g, '&') - .replace(//g, '>') - .replace(/'/g, ''') - .replace(/"/g, '"') - .replace(/\n/g, '
'); -} - - -function disableTextSelection(element) { - element - .attr('unselectable', 'on') - .css('MozUserSelect', 'none') - .bind('selectstart.ui', function() { return false; }); -} - - -/* -function enableTextSelection(element) { - element - .attr('unselectable', 'off') - .css('MozUserSelect', '') - .unbind('selectstart.ui'); -} -*/ - - -function markFirstLast(e) { - e.children() - .removeClass('fc-first fc-last') - .filter(':first-child') - .addClass('fc-first') - .end() - .filter(':last-child') - .addClass('fc-last'); -} - - -function setDayID(cell, date) { - cell.each(function(i, _cell) { - _cell.className = _cell.className.replace(/^fc-\w*/, 'fc-' + dayIDs[date.getDay()]); - // TODO: make a way that doesn't rely on order of classes - }); -} - - -function getSkinCss(event, opt) { - var source = event.source || {}; - var eventColor = event.color; - var sourceColor = source.color; - var optionColor = opt('eventColor'); - var backgroundColor = - event.backgroundColor || - eventColor || - source.backgroundColor || - sourceColor || - opt('eventBackgroundColor') || - optionColor; - var borderColor = - event.borderColor || - eventColor || - source.borderColor || - sourceColor || - opt('eventBorderColor') || - optionColor; - var textColor = - event.textColor || - source.textColor || - opt('eventTextColor'); - var statements = []; - if (backgroundColor) { - statements.push('background-color:' + backgroundColor); - } - if (borderColor) { - statements.push('border-color:' + borderColor); - } - if (textColor) { - statements.push('color:' + textColor); - } - return statements.join(';'); -} - - -function applyAll(functions, thisObj, args) { - if ($.isFunction(functions)) { - functions = [ functions ]; - } - if (functions) { - var i; - var ret; - for (i=0; i") - .appendTo(element); - } - - - function buildTable() { - var html = buildTableHTML(); - - if (table) { - table.remove(); - } - table = $(html).appendTo(element); - - head = table.find('thead'); - headCells = head.find('.fc-day-header'); - body = table.find('tbody'); - bodyRows = body.find('tr'); - bodyCells = body.find('.fc-day'); - bodyFirstCells = bodyRows.find('td:first-child'); - - firstRowCellInners = bodyRows.eq(0).find('.fc-day > div'); - firstRowCellContentInners = bodyRows.eq(0).find('.fc-day-content > div'); - - markFirstLast(head.add(head.find('tr'))); // marks first+last tr/th's - markFirstLast(bodyRows); // marks first+last td's - bodyRows.eq(0).addClass('fc-first'); - bodyRows.filter(':last').addClass('fc-last'); - - bodyCells.each(function(i, _cell) { - var date = cellToDate( - Math.floor(i / colCnt), - i % colCnt - ); - trigger('dayRender', t, date, $(_cell)); - }); - - dayBind(bodyCells); - } - - - - /* HTML Building - -----------------------------------------------------------*/ - - - function buildTableHTML() { - var html = - "" + - buildHeadHTML() + - buildBodyHTML() + - "
"; - - return html; - } - - - function buildHeadHTML() { - var headerClass = tm + "-widget-header"; - var html = ''; - var col; - var date; - - html += "
" + - htmlEscape(weekNumberTitle) + - "
" + - "" + - "" + - "" + - "" + - "" + - "
" + opt('allDayText') + "" + - "
" + - "
 
"; - allDayTable = $(s).appendTo(slotLayer); - allDayRow = allDayTable.find('tr'); - - dayBind(allDayRow.find('td')); - - slotLayer.append( - "
" + - "
" + - "
" - ); - - }else{ - - daySegmentContainer = $([]); // in jQuery 1.4, we can just do $() - - } - - slotScroller = - $("
") - .appendTo(slotLayer); - - slotContainer = - $("
") - .appendTo(slotScroller); - - slotSegmentContainer = - $("
") - .appendTo(slotContainer); - - s = - "" + - ""; - d = zeroDate(); - maxd = addMinutes(cloneDate(d), maxMinute); - addMinutes(d, minMinute); - slotCnt = 0; - for (i=0; d < maxd; i++) { - minutes = d.getMinutes(); - s += - "" + - "" + - "" + - ""; - addMinutes(d, opt('slotMinutes')); - slotCnt++; - } - s += - "" + - "
" + - ((!slotNormal || !minutes) ? formatDate(d, opt('axisFormat')) : ' ') + - "" + - "
 
" + - "
"; - slotTable = $(s).appendTo(slotContainer); - - slotBind(slotTable.find('td')); - } - - - - /* Build Day Table - -----------------------------------------------------------------------*/ - - - function buildDayTable() { - var html = buildDayTableHTML(); - - if (dayTable) { - dayTable.remove(); - } - dayTable = $(html).appendTo(element); - - dayHead = dayTable.find('thead'); - dayHeadCells = dayHead.find('th').slice(1, -1); // exclude gutter - dayBody = dayTable.find('tbody'); - dayBodyCells = dayBody.find('td').slice(0, -1); // exclude gutter - dayBodyCellInners = dayBodyCells.find('> div'); - dayBodyCellContentInners = dayBodyCells.find('.fc-day-content > div'); - - dayBodyFirstCell = dayBodyCells.eq(0); - dayBodyFirstCellStretcher = dayBodyCellInners.eq(0); - - markFirstLast(dayHead.add(dayHead.find('tr'))); - markFirstLast(dayBody.add(dayBody.find('tr'))); - - // TODO: now that we rebuild the cells every time, we should call dayRender - } - - - function buildDayTableHTML() { - var html = - "" + - buildDayTableHeadHTML() + - buildDayTableBodyHTML() + - "
"; - - return html; - } - - - function buildDayTableHeadHTML() { - var headerClass = tm + "-widget-header"; - var date; - var html = ''; - var weekText; - var col; - - html += - "" + - ""; - - if (showWeekNumbers) { - date = cellToDate(0, 0); - weekText = formatDate(date, weekNumberFormat); - if (rtl) { - weekText += weekNumberTitle; - } - else { - weekText = weekNumberTitle + weekText; - } - html += - "" + - htmlEscape(weekText) + - ""; - } - else { - html += " "; - } - - for (col=0; col" + - htmlEscape(formatDate(date, colFormat)) + - ""; - } - - html += - " " + - "" + - ""; - - return html; - } - - - function buildDayTableBodyHTML() { - var headerClass = tm + "-widget-header"; // TODO: make these when updateOptions() called - var contentClass = tm + "-widget-content"; - var date; - var today = clearTime(new Date()); - var col; - var cellsHTML; - var cellHTML; - var classNames; - var html = ''; - - html += - "" + - "" + - " "; - - cellsHTML = ''; - - for (col=0; col" + - "
" + - "
" + - "
 
" + - "
" + - "
" + - ""; - - cellsHTML += cellHTML; - } - - html += cellsHTML; - html += - " " + - "" + - ""; - - return html; - } - - - // TODO: data-date on the cells - - - - /* Dimensions - -----------------------------------------------------------------------*/ - - - function setHeight(height) { - if (height === undefined) { - height = viewHeight; - } - viewHeight = height; - slotTopCache = {}; - - var headHeight = dayBody.position().top; - var allDayHeight = slotScroller.position().top; // including divider - var bodyHeight = Math.min( // total body height, including borders - height - headHeight, // when scrollbars - slotTable.height() + allDayHeight + 1 // when no scrollbars. +1 for bottom border - ); - - dayBodyFirstCellStretcher - .height(bodyHeight - vsides(dayBodyFirstCell)); - - slotLayer.css('top', headHeight); - - slotScroller.height(bodyHeight - allDayHeight - 1); - - // the stylesheet guarantees that the first row has no border. - // this allows .height() to work well cross-browser. - slotHeight = slotTable.find('tr:first').height() + 1; // +1 for bottom border - - snapRatio = opt('slotMinutes') / snapMinutes; - snapHeight = slotHeight / snapRatio; - } - - - function setWidth(width) { - viewWidth = width; - colPositions.clear(); - colContentPositions.clear(); - - var axisFirstCells = dayHead.find('th:first'); - if (allDayTable) { - axisFirstCells = axisFirstCells.add(allDayTable.find('th:first')); - } - axisFirstCells = axisFirstCells.add(slotTable.find('th:first')); - - axisWidth = 0; - setOuterWidth( - axisFirstCells - .width('') - .each(function(i, _cell) { - axisWidth = Math.max(axisWidth, $(_cell).outerWidth()); - }), - axisWidth - ); - - var gutterCells = dayTable.find('.fc-agenda-gutter'); - if (allDayTable) { - gutterCells = gutterCells.add(allDayTable.find('th.fc-agenda-gutter')); - } - - var slotTableWidth = slotScroller[0].clientWidth; // needs to be done after axisWidth (for IE7) - - gutterWidth = slotScroller.width() - slotTableWidth; - if (gutterWidth) { - setOuterWidth(gutterCells, gutterWidth); - gutterCells - .show() - .prev() - .removeClass('fc-last'); - }else{ - gutterCells - .hide() - .prev() - .addClass('fc-last'); - } - - colWidth = Math.floor((slotTableWidth - axisWidth) / colCnt); - setOuterWidth(dayHeadCells.slice(0, -1), colWidth); - } - - - - /* Scrolling - -----------------------------------------------------------------------*/ - - - function resetScroll() { - var d0 = zeroDate(); - var scrollDate = cloneDate(d0); - scrollDate.setHours(opt('firstHour')); - var top = timePosition(d0, scrollDate) + 1; // +1 for the border - function scroll() { - slotScroller.scrollTop(top); - } - scroll(); - setTimeout(scroll, 0); // overrides any previous scroll state made by the browser - } - - - function afterRender() { // after the view has been freshly rendered and sized - resetScroll(); - } - - - - /* Slot/Day clicking and binding - -----------------------------------------------------------------------*/ - - - function dayBind(cells) { - cells.click(slotClick) - .mousedown(daySelectionMousedown); - } - - - function slotBind(cells) { - cells.click(slotClick) - .mousedown(slotSelectionMousedown); - } - - - function slotClick(ev) { - if (!opt('selectable')) { // if selectable, SelectionManager will worry about dayClick - var col = Math.min(colCnt-1, Math.floor((ev.pageX - dayTable.offset().left - axisWidth) / colWidth)); - var date = cellToDate(0, col); - var rowMatch = this.parentNode.className.match(/fc-slot(\d+)/); // TODO: maybe use data - if (rowMatch) { - var mins = parseInt(rowMatch[1]) * opt('slotMinutes'); - var hours = Math.floor(mins/60); - date.setHours(hours); - date.setMinutes(mins%60 + minMinute); - trigger('dayClick', dayBodyCells[col], date, false, ev); - }else{ - trigger('dayClick', dayBodyCells[col], date, true, ev); - } - } - } - - - - /* Semi-transparent Overlay Helpers - -----------------------------------------------------*/ - // TODO: should be consolidated with BasicView's methods - - - function renderDayOverlay(overlayStart, overlayEnd, refreshCoordinateGrid) { // overlayEnd is exclusive - - if (refreshCoordinateGrid) { - coordinateGrid.build(); - } - - var segments = rangeToSegments(overlayStart, overlayEnd); - - for (var i=0; i= 0) { - addMinutes(d, minMinute + slotIndex * snapMinutes); - } - return d; - } - - - // get the Y coordinate of the given time on the given day (both Date objects) - function timePosition(day, time) { // both date objects. day holds 00:00 of current day - day = cloneDate(day, true); - if (time < addMinutes(cloneDate(day), minMinute)) { - return 0; - } - if (time >= addMinutes(cloneDate(day), maxMinute)) { - return slotTable.height(); - } - var slotMinutes = opt('slotMinutes'), - minutes = time.getHours()*60 + time.getMinutes() - minMinute, - slotI = Math.floor(minutes / slotMinutes), - slotTop = slotTopCache[slotI]; - if (slotTop === undefined) { - slotTop = slotTopCache[slotI] = - slotTable.find('tr').eq(slotI).find('td div')[0].offsetTop; - // .eq() is faster than ":eq()" selector - // [0].offsetTop is faster than .position().top (do we really need this optimization?) - // a better optimization would be to cache all these divs - } - return Math.max(0, Math.round( - slotTop - 1 + slotHeight * ((minutes % slotMinutes) / slotMinutes) - )); - } - - - function getAllDayRow(index) { - return allDayRow; - } - - - function defaultEventEnd(event) { - var start = cloneDate(event.start); - if (event.allDay) { - return start; - } - return addMinutes(start, opt('defaultEventMinutes')); - } - - - - /* Selection - ---------------------------------------------------------------------------------*/ - - - function defaultSelectionEnd(startDate, allDay) { - if (allDay) { - return cloneDate(startDate); - } - return addMinutes(cloneDate(startDate), opt('slotMinutes')); - } - - - function renderSelection(startDate, endDate, allDay) { // only for all-day - if (allDay) { - if (opt('allDaySlot')) { - renderDayOverlay(startDate, addDays(cloneDate(endDate), 1), true); - } - }else{ - renderSlotSelection(startDate, endDate); - } - } - - - function renderSlotSelection(startDate, endDate) { - var helperOption = opt('selectHelper'); - coordinateGrid.build(); - if (helperOption) { - var col = dateToCell(startDate).col; - if (col >= 0 && col < colCnt) { // only works when times are on same day - var rect = coordinateGrid.rect(0, col, 0, col, slotContainer); // only for horizontal coords - var top = timePosition(startDate, startDate); - var bottom = timePosition(startDate, endDate); - if (bottom > top) { // protect against selections that are entirely before or after visible range - rect.top = top; - rect.height = bottom - top; - rect.left += 2; - rect.width -= 5; - if ($.isFunction(helperOption)) { - var helperRes = helperOption(startDate, endDate); - if (helperRes) { - rect.position = 'absolute'; - selectionHelper = $(helperRes) - .css(rect) - .appendTo(slotContainer); - } - }else{ - rect.isStart = true; // conside rect a "seg" now - rect.isEnd = true; // - selectionHelper = $(slotSegHtml( - { - title: '', - start: startDate, - end: endDate, - className: ['fc-select-helper'], - editable: false - }, - rect - )); - selectionHelper.css('opacity', opt('dragOpacity')); - } - if (selectionHelper) { - slotBind(selectionHelper); - slotContainer.append(selectionHelper); - setOuterWidth(selectionHelper, rect.width, true); // needs to be after appended - setOuterHeight(selectionHelper, rect.height, true); - } - } - } - }else{ - renderSlotOverlay(startDate, endDate); - } - } - - - function clearSelection() { - clearOverlays(); - if (selectionHelper) { - selectionHelper.remove(); - selectionHelper = null; - } - } - - - function slotSelectionMousedown(ev) { - if (ev.which == 1 && opt('selectable')) { // ev.which==1 means left mouse button - unselect(ev); - var dates; - hoverListener.start(function(cell, origCell) { - clearSelection(); - if (cell && cell.col == origCell.col && !getIsCellAllDay(cell)) { - var d1 = realCellToDate(origCell); - var d2 = realCellToDate(cell); - dates = [ - d1, - addMinutes(cloneDate(d1), snapMinutes), // calculate minutes depending on selection slot minutes - d2, - addMinutes(cloneDate(d2), snapMinutes) - ].sort(dateCompare); - renderSlotSelection(dates[0], dates[3]); - }else{ - dates = null; - } - }, ev); - $(document).one('mouseup', function(ev) { - hoverListener.stop(); - if (dates) { - if (+dates[0] == +dates[1]) { - reportDayClick(dates[0], false, ev); - } - reportSelection(dates[0], dates[3], false, ev); - } - }); - } - } - - - function reportDayClick(date, allDay, ev) { - trigger('dayClick', dayBodyCells[dateToCell(date).col], date, allDay, ev); - } - - - - /* External Dragging - --------------------------------------------------------------------------------*/ - - - function dragStart(_dragElement, ev, ui) { - hoverListener.start(function(cell) { - clearOverlays(); - if (cell) { - if (getIsCellAllDay(cell)) { - renderCellOverlay(cell.row, cell.col, cell.row, cell.col); - }else{ - var d1 = realCellToDate(cell); - var d2 = addMinutes(cloneDate(d1), opt('defaultEventMinutes')); - renderSlotOverlay(d1, d2); - } - } - }, ev); - } - - - function dragStop(_dragElement, ev, ui) { - var cell = hoverListener.stop(); - clearOverlays(); - if (cell) { - trigger('drop', _dragElement, realCellToDate(cell), getIsCellAllDay(cell), ev, ui); - } - } - - -} - -;; - -function AgendaEventRenderer() { - var t = this; - - - // exports - t.renderEvents = renderEvents; - t.clearEvents = clearEvents; - t.slotSegHtml = slotSegHtml; - - - // imports - DayEventRenderer.call(t); - var opt = t.opt; - var trigger = t.trigger; - var isEventDraggable = t.isEventDraggable; - var isEventResizable = t.isEventResizable; - var eventEnd = t.eventEnd; - var eventElementHandlers = t.eventElementHandlers; - var setHeight = t.setHeight; - var getDaySegmentContainer = t.getDaySegmentContainer; - var getSlotSegmentContainer = t.getSlotSegmentContainer; - var getHoverListener = t.getHoverListener; - var getMaxMinute = t.getMaxMinute; - var getMinMinute = t.getMinMinute; - var timePosition = t.timePosition; - var getIsCellAllDay = t.getIsCellAllDay; - var colContentLeft = t.colContentLeft; - var colContentRight = t.colContentRight; - var cellToDate = t.cellToDate; - var getColCnt = t.getColCnt; - var getColWidth = t.getColWidth; - var getSnapHeight = t.getSnapHeight; - var getSnapMinutes = t.getSnapMinutes; - var getSlotContainer = t.getSlotContainer; - var reportEventElement = t.reportEventElement; - var showEvents = t.showEvents; - var hideEvents = t.hideEvents; - var eventDrop = t.eventDrop; - var eventResize = t.eventResize; - var renderDayOverlay = t.renderDayOverlay; - var clearOverlays = t.clearOverlays; - var renderDayEvents = t.renderDayEvents; - var calendar = t.calendar; - var formatDate = calendar.formatDate; - var formatDates = calendar.formatDates; - - - // overrides - t.draggableDayEvent = draggableDayEvent; - - - - /* Rendering - ----------------------------------------------------------------------------*/ - - - function renderEvents(events, modifiedEventId) { - var i, len=events.length, - dayEvents=[], - slotEvents=[]; - for (i=0; i start && eventStart < end) { - if (eventStart < start) { - segStart = cloneDate(start); - isStart = false; - }else{ - segStart = eventStart; - isStart = true; - } - if (eventEnd > end) { - segEnd = cloneDate(end); - isEnd = false; - }else{ - segEnd = eventEnd; - isEnd = true; - } - segs.push({ - event: event, - start: segStart, - end: segEnd, - isStart: isStart, - isEnd: isEnd - }); - } - } - return segs.sort(compareSlotSegs); - } - - - function slotEventEnd(event) { - if (event.end) { - return cloneDate(event.end); - }else{ - return addMinutes(cloneDate(event.start), opt('defaultEventMinutes')); - } - } - - - // renders events in the 'time slots' at the bottom - // TODO: when we refactor this, when user returns `false` eventRender, don't have empty space - // TODO: refactor will include using pixels to detect collisions instead of dates (handy for seg cmp) - - function renderSlotSegs(segs, modifiedEventId) { - - var i, segCnt=segs.length, seg, - event, - top, - bottom, - columnLeft, - columnRight, - columnWidth, - width, - left, - right, - html = '', - eventElements, - eventElement, - triggerRes, - titleElement, - height, - slotSegmentContainer = getSlotSegmentContainer(), - isRTL = opt('isRTL'); - - // calculate position/dimensions, create html - for (i=0; i" + - // modified sleede peng - '' + - "
" + - "
" + - htmlEscape(formatDates(event.start, event.end, opt('timeFormat'))) + - "
" + - "
" + - htmlEscape(event.title || '') + - "
" + - "
" + - "
"; - if (seg.isEnd && isEventResizable(event)) { - html += - "
=
"; - } - html += - ""; - return html; - } - - - function bindSlotSeg(event, eventElement, seg) { - var timeElement = eventElement.find('div.fc-event-time'); - if (isEventDraggable(event)) { - draggableSlotEvent(event, eventElement, timeElement); - } - if (seg.isEnd && isEventResizable(event)) { - resizableSlotEvent(event, eventElement, timeElement); - } - eventElementHandlers(event, eventElement); - } - - - - /* Dragging - -----------------------------------------------------------------------------------*/ - - - // when event starts out FULL-DAY - // overrides DayEventRenderer's version because it needs to account for dragging elements - // to and from the slot area. - - function draggableDayEvent(event, eventElement, seg) { - var isStart = seg.isStart; - var origWidth; - var revert; - var allDay = true; - var dayDelta; - var hoverListener = getHoverListener(); - var colWidth = getColWidth(); - var snapHeight = getSnapHeight(); - var snapMinutes = getSnapMinutes(); - var minMinute = getMinMinute(); - eventElement.draggable({ - opacity: opt('dragOpacity', 'month'), // use whatever the month view was using - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - origWidth = eventElement.width(); - hoverListener.start(function(cell, origCell) { - clearOverlays(); - if (cell) { - revert = false; - var origDate = cellToDate(0, origCell.col); - var date = cellToDate(0, cell.col); - dayDelta = dayDiff(date, origDate); - if (!cell.row) { - // on full-days - renderDayOverlay( - addDays(cloneDate(event.start), dayDelta), - addDays(exclEndDay(event), dayDelta) - ); - resetElement(); - }else{ - // mouse is over bottom slots - if (isStart) { - if (allDay) { - // convert event to temporary slot-event - eventElement.width(colWidth - 10); // don't use entire width - setOuterHeight( - eventElement, - snapHeight * Math.round( - (event.end ? ((event.end - event.start) / MINUTE_MS) : opt('defaultEventMinutes')) / - snapMinutes - ) - ); - eventElement.draggable('option', 'grid', [colWidth, 1]); - allDay = false; - } - }else{ - revert = true; - } - } - revert = revert || (allDay && !dayDelta); - }else{ - resetElement(); - revert = true; - } - eventElement.draggable('option', 'revert', revert); - }, ev, 'drag'); - }, - stop: function(ev, ui) { - hoverListener.stop(); - clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - if (revert) { - // hasn't moved or is out of bounds (draggable has already reverted) - resetElement(); - eventElement.css('filter', ''); // clear IE opacity side-effects - showEvents(event, eventElement); - }else{ - // changed! - var minuteDelta = 0; - if (!allDay) { - minuteDelta = Math.round((eventElement.offset().top - getSlotContainer().offset().top) / snapHeight) - * snapMinutes - + minMinute - - (event.start.getHours() * 60 + event.start.getMinutes()); - } - eventDrop(this, event, dayDelta, minuteDelta, allDay, ev, ui); - } - } - }); - function resetElement() { - if (!allDay) { - eventElement - .width(origWidth) - .height('') - .draggable('option', 'grid', null); - allDay = true; - } - } - } - - - // when event starts out IN TIMESLOTS - - function draggableSlotEvent(event, eventElement, timeElement) { - var coordinateGrid = t.getCoordinateGrid(); - var colCnt = getColCnt(); - var colWidth = getColWidth(); - var snapHeight = getSnapHeight(); - var snapMinutes = getSnapMinutes(); - - // states - var origPosition; // original position of the element, not the mouse - var origCell; - var isInBounds, prevIsInBounds; - var isAllDay, prevIsAllDay; - var colDelta, prevColDelta; - var dayDelta; // derived from colDelta - var minuteDelta, prevMinuteDelta; - - eventElement.draggable({ - scroll: false, - grid: [ colWidth, snapHeight ], - axis: colCnt==1 ? 'y' : false, - opacity: opt('dragOpacity'), - revertDuration: opt('dragRevertDuration'), - start: function(ev, ui) { - - trigger('eventDragStart', eventElement, event, ev, ui); - hideEvents(event, eventElement); - - coordinateGrid.build(); - - // initialize states - origPosition = eventElement.position(); - origCell = coordinateGrid.cell(ev.pageX, ev.pageY); - isInBounds = prevIsInBounds = true; - isAllDay = prevIsAllDay = getIsCellAllDay(origCell); - colDelta = prevColDelta = 0; - dayDelta = 0; - minuteDelta = prevMinuteDelta = 0; - - }, - drag: function(ev, ui) { - - // NOTE: this `cell` value is only useful for determining in-bounds and all-day. - // Bad for anything else due to the discrepancy between the mouse position and the - // element position while snapping. (problem revealed in PR #55) - // - // PS- the problem exists for draggableDayEvent() when dragging an all-day event to a slot event. - // We should overhaul the dragging system and stop relying on jQuery UI. - var cell = coordinateGrid.cell(ev.pageX, ev.pageY); - - // update states - isInBounds = !!cell; - if (isInBounds) { - isAllDay = getIsCellAllDay(cell); - - // calculate column delta - colDelta = Math.round((ui.position.left - origPosition.left) / colWidth); - if (colDelta != prevColDelta) { - // calculate the day delta based off of the original clicked column and the column delta - var origDate = cellToDate(0, origCell.col); - var col = origCell.col + colDelta; - col = Math.max(0, col); - col = Math.min(colCnt-1, col); - var date = cellToDate(0, col); - dayDelta = dayDiff(date, origDate); - } - - // calculate minute delta (only if over slots) - if (!isAllDay) { - minuteDelta = Math.round((ui.position.top - origPosition.top) / snapHeight) * snapMinutes; - } - } - - // any state changes? - if ( - isInBounds != prevIsInBounds || - isAllDay != prevIsAllDay || - colDelta != prevColDelta || - minuteDelta != prevMinuteDelta - ) { - - updateUI(); - - // update previous states for next time - prevIsInBounds = isInBounds; - prevIsAllDay = isAllDay; - prevColDelta = colDelta; - prevMinuteDelta = minuteDelta; - } - - // if out-of-bounds, revert when done, and vice versa. - eventElement.draggable('option', 'revert', !isInBounds); - - }, - stop: function(ev, ui) { - - clearOverlays(); - trigger('eventDragStop', eventElement, event, ev, ui); - - if (isInBounds && (isAllDay || dayDelta || minuteDelta)) { // changed! - eventDrop(this, event, dayDelta, isAllDay ? 0 : minuteDelta, isAllDay, ev, ui); - } - else { // either no change or out-of-bounds (draggable has already reverted) - - // reset states for next time, and for updateUI() - isInBounds = true; - isAllDay = false; - colDelta = 0; - dayDelta = 0; - minuteDelta = 0; - - updateUI(); - eventElement.css('filter', ''); // clear IE opacity side-effects - - // sometimes fast drags make event revert to wrong position, so reset. - // also, if we dragged the element out of the area because of snapping, - // but the *mouse* is still in bounds, we need to reset the position. - eventElement.css(origPosition); - - showEvents(event, eventElement); - } - } - }); - - function updateUI() { - clearOverlays(); - if (isInBounds) { - if (isAllDay) { - timeElement.hide(); - eventElement.draggable('option', 'grid', null); // disable grid snapping - renderDayOverlay( - addDays(cloneDate(event.start), dayDelta), - addDays(exclEndDay(event), dayDelta) - ); - } - else { - updateTimeText(minuteDelta); - timeElement.css('display', ''); // show() was causing display=inline - eventElement.draggable('option', 'grid', [colWidth, snapHeight]); // re-enable grid snapping - } - } - } - - function updateTimeText(minuteDelta) { - var newStart = addMinutes(cloneDate(event.start), minuteDelta); - var newEnd; - if (event.end) { - newEnd = addMinutes(cloneDate(event.end), minuteDelta); - } - timeElement.text(formatDates(newStart, newEnd, opt('timeFormat'))); - } - - } - - - - /* Resizing - --------------------------------------------------------------------------------------*/ - - - function resizableSlotEvent(event, eventElement, timeElement) { - var snapDelta, prevSnapDelta; - var snapHeight = getSnapHeight(); - var snapMinutes = getSnapMinutes(); - eventElement.resizable({ - handles: { - s: '.ui-resizable-handle' - }, - grid: snapHeight, - start: function(ev, ui) { - snapDelta = prevSnapDelta = 0; - hideEvents(event, eventElement); - trigger('eventResizeStart', this, event, ev, ui); - }, - resize: function(ev, ui) { - // don't rely on ui.size.height, doesn't take grid into account - snapDelta = Math.round((Math.max(snapHeight, eventElement.height()) - ui.originalSize.height) / snapHeight); - if (snapDelta != prevSnapDelta) { - timeElement.text( - formatDates( - event.start, - (!snapDelta && !event.end) ? null : // no change, so don't display time range - addMinutes(eventEnd(event), snapMinutes*snapDelta), - opt('timeFormat') - ) - ); - prevSnapDelta = snapDelta; - } - }, - stop: function(ev, ui) { - trigger('eventResizeStop', this, event, ev, ui); - if (snapDelta) { - eventResize(this, event, 0, snapMinutes*snapDelta, ev, ui); - }else{ - showEvents(event, eventElement); - // BUG: if event was really short, need to put title back in span - } - } - }); - } - - -} - - - -/* Agenda Event Segment Utilities ------------------------------------------------------------------------------*/ - - -// Sets the seg.backwardCoord and seg.forwardCoord on each segment and returns a new -// list in the order they should be placed into the DOM (an implicit z-index). -function placeSlotSegs(segs) { - var levels = buildSlotSegLevels(segs); - var level0 = levels[0]; - var i; - - computeForwardSlotSegs(levels); - - if (level0) { - - for (i=0; i seg2.start && seg1.start < seg2.end; -} - - -// A cmp function for determining which forward segment to rely on more when computing coordinates. -function compareForwardSlotSegs(seg1, seg2) { - // put higher-pressure first - return seg2.forwardPressure - seg1.forwardPressure || - // put segments that are closer to initial edge first (and favor ones with no coords yet) - (seg1.backwardCoord || 0) - (seg2.backwardCoord || 0) || - // do normal sorting... - compareSlotSegs(seg1, seg2); -} - - -// A cmp function for determining which segment should be closer to the initial edge -// (the left edge on a left-to-right calendar). -function compareSlotSegs(seg1, seg2) { - return seg1.start - seg2.start || // earlier start time goes first - (seg2.end - seg2.start) - (seg1.end - seg1.start) || // tie? longer-duration goes first - (seg1.event.title || '').localeCompare(seg2.event.title); // tie? alphabetically by title -} - - -;; - - -function View(element, calendar, viewName) { - var t = this; - - - // exports - t.element = element; - t.calendar = calendar; - t.name = viewName; - t.opt = opt; - t.trigger = trigger; - t.isEventDraggable = isEventDraggable; - t.isEventResizable = isEventResizable; - t.setEventData = setEventData; - t.clearEventData = clearEventData; - t.eventEnd = eventEnd; - t.reportEventElement = reportEventElement; - t.triggerEventDestroy = triggerEventDestroy; - t.eventElementHandlers = eventElementHandlers; - t.showEvents = showEvents; - t.hideEvents = hideEvents; - t.eventDrop = eventDrop; - t.eventResize = eventResize; - // t.title - // t.start, t.end - // t.visStart, t.visEnd - - - // imports - var defaultEventEnd = t.defaultEventEnd; - var normalizeEvent = calendar.normalizeEvent; // in EventManager - var reportEventChange = calendar.reportEventChange; - - - // locals - var eventsByID = {}; // eventID mapped to array of events (there can be multiple b/c of repeating events) - var eventElementsByID = {}; // eventID mapped to array of jQuery elements - var eventElementCouples = []; // array of objects, { event, element } // TODO: unify with segment system - var options = calendar.options; - - - - function opt(name, viewNameOverride) { - var v = options[name]; - if ($.isPlainObject(v)) { - return smartProperty(v, viewNameOverride || viewName); - } - return v; - } - - - function trigger(name, thisObj) { - return calendar.trigger.apply( - calendar, - [name, thisObj || t].concat(Array.prototype.slice.call(arguments, 2), [t]) - ); - } - - - - /* Event Editable Boolean Calculations - ------------------------------------------------------------------------------*/ - - - function isEventDraggable(event) { - var source = event.source || {}; - return firstDefined( - event.startEditable, - source.startEditable, - opt('eventStartEditable'), - event.editable, - source.editable, - opt('editable') - ) - && !opt('disableDragging'); // deprecated - } - - - function isEventResizable(event) { // but also need to make sure the seg.isEnd == true - var source = event.source || {}; - return firstDefined( - event.durationEditable, - source.durationEditable, - opt('eventDurationEditable'), - event.editable, - source.editable, - opt('editable') - ) - && !opt('disableResizing'); // deprecated - } - - - - /* Event Data - ------------------------------------------------------------------------------*/ - - - function setEventData(events) { // events are already normalized at this point - eventsByID = {}; - var i, len=events.length, event; - for (i=0; i