From 0af0cc7878daee0bae2436434b20872147c5c7c2 Mon Sep 17 00:00:00 2001 From: Peng DU Date: Wed, 13 Jul 2016 19:09:07 +0200 Subject: [PATCH] update angular-ui-calendar and ajax load availabilites --- .../controllers/admin/calendar.coffee.erb | 32 ++- .../controllers/machines.coffee.erb | 29 ++- .../controllers/trainings.coffee.erb | 35 ++-- app/assets/javascripts/router.coffee.erb | 3 - .../api/availabilities_controller.rb | 3 + .../api/availabilities/index.json.jbuilder | 4 + bower.json | 2 +- .../angular-ui-calendar/.bower.json | 28 +-- .../components/angular-ui-calendar/README.md | 71 ++++--- .../components/angular-ui-calendar/bower.json | 15 +- .../angular-ui-calendar/src/calendar.js | 184 +++++++++++------- 11 files changed, 235 insertions(+), 171 deletions(-) diff --git a/app/assets/javascripts/controllers/admin/calendar.coffee.erb b/app/assets/javascripts/controllers/admin/calendar.coffee.erb index 81e38b54f..414c5b1b2 100644 --- a/app/assets/javascripts/controllers/admin/calendar.coffee.erb +++ b/app/assets/javascripts/controllers/admin/calendar.coffee.erb @@ -4,8 +4,8 @@ # Controller used in the calendar management page ## -Application.Controllers.controller "AdminCalendarController", ["$scope", "$state", "$uibModal", "moment", "Availability", 'Slot', 'Setting', 'growl', 'dialogs', 'availabilitiesPromise', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', '_t' -($scope, $state, $uibModal, moment, Availability, Slot, Setting, growl, dialogs, availabilitiesPromise, bookingWindowStart, bookingWindowEnd, machinesPromise, _t) -> +Application.Controllers.controller "AdminCalendarController", ["$scope", "$state", "$uibModal", "moment", "Availability", 'Slot', 'Setting', 'growl', 'dialogs', 'bookingWindowStart', 'bookingWindowEnd', 'machinesPromise', '_t', 'uiCalendarConfig' +($scope, $state, $uibModal, moment, Availability, Slot, Setting, growl, dialogs, bookingWindowStart, bookingWindowEnd, machinesPromise, _t, uiCalendarConfig) -> @@ -36,12 +36,9 @@ Application.Controllers.controller "AdminCalendarController", ["$scope", "$state ## bind the availabilities slots with full-Calendar events $scope.eventSources = [] $scope.eventSources.push - events: availabilitiesPromise + url: '/api/availabilities' textColor: 'black' - ## after fullCalendar loads, provides access to its methods through $scope.calendar.fullCalendar() - $scope.calendar = null - ## fullCalendar (v2) configuration $scope.calendarConfig = timezone: Fablab.timezone @@ -141,7 +138,7 @@ Application.Controllers.controller "AdminCalendarController", ["$scope", "$state # update the machine_ids attribute $scope.availability.machine_ids = data.machine_ids $scope.availability.title = data.title - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' # notify the admin growl.success(_t('the_machine_was_successfully_removed_from_the_slot')) , (data, status) -> # failed @@ -180,7 +177,7 @@ Application.Controllers.controller "AdminCalendarController", ["$scope", "$state end: -> end # when the modal is closed, we send the slot to the server for saving modalInstance.result.then (availability) -> - $scope.calendar.fullCalendar 'renderEvent', + uiCalendarConfig.calendars.calendar.fullCalendar 'renderEvent', id: availability.id title: availability.title, start: availability.start_at @@ -189,12 +186,13 @@ Application.Controllers.controller "AdminCalendarController", ["$scope", "$state backgroundColor: availability.backgroundColor borderColor: availability.borderColor tag_ids: availability.tag_ids + tags: availability.tags machine_ids: availability.machine_ids , true , -> - $scope.calendar.fullCalendar('unselect') + uiCalendarConfig.calendars.calendar.fullCalendar('unselect') - $scope.calendar.fullCalendar('unselect') + uiCalendarConfig.calendars.calendar.fullCalendar('unselect') @@ -209,7 +207,7 @@ Application.Controllers.controller "AdminCalendarController", ["$scope", "$state # if the user has clicked on the delete event button, delete the event if ($(jsEvent.target).hasClass('remove-event')) Availability.delete id: event.id, -> - $scope.calendar.fullCalendar 'removeEvents', event.id + uiCalendarConfig.calendars.calendar.fullCalendar 'removeEvents', event.id for _event, i in $scope.eventSources[0].events if _event.id == event.id $scope.eventSources[0].events.splice(i,1) @@ -231,12 +229,12 @@ Application.Controllers.controller "AdminCalendarController", ["$scope", "$state # @see http://fullcalendar.io/docs/event_rendering/eventRender/ ## eventRenderCb = (event, element) -> - if event.tag_ids.length > 0 - Availability.get {id: event.id}, (avail) -> - html = '' - for tag in avail.tags - html += "#{tag.name} " - element.find('.fc-title').append("
"+html) + if event.tags.length > 0 + html = '' + for tag in event.tags + html += "#{tag.name} " + element.find('.fc-title').append("
"+html) + return ] diff --git a/app/assets/javascripts/controllers/machines.coffee.erb b/app/assets/javascripts/controllers/machines.coffee.erb index a5ee09123..99948d7d7 100644 --- a/app/assets/javascripts/controllers/machines.coffee.erb +++ b/app/assets/javascripts/controllers/machines.coffee.erb @@ -268,8 +268,8 @@ Application.Controllers.controller "ShowMachineController", ['$scope', '$state', # This controller workflow is pretty similar to the trainings reservation controller. ## -Application.Controllers.controller "ReserveMachineController", ["$scope", "$state", '$stateParams', "$uibModal", '_t', "moment", 'Machine', 'Auth', 'dialogs', '$timeout', 'Price', 'Member', 'Availability', 'Slot', 'Setting', 'CustomAsset', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', -($scope, $state, $stateParams, $uibModal, _t, moment, Machine, Auth, dialogs, $timeout, Price, Member, Availability, Slot, Setting, CustomAsset, plansPromise, groupsPromise, growl, settingsPromise) -> +Application.Controllers.controller "ReserveMachineController", ["$scope", "$state", '$stateParams', "$uibModal", '_t', "moment", 'Machine', 'Auth', 'dialogs', '$timeout', 'Price', 'Member', 'Availability', 'Slot', 'Setting', 'CustomAsset', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', 'uiCalendarConfig', +($scope, $state, $stateParams, $uibModal, _t, moment, Machine, Auth, dialogs, $timeout, Price, Member, Availability, Slot, Setting, CustomAsset, plansPromise, groupsPromise, growl, settingsPromise, uiCalendarConfig) -> @@ -297,9 +297,6 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat ### PUBLIC SCOPE ### - ## after fullCalendar loads, provides access to its methods through $scope.calendar.fullCalendar() - $scope.calendar = null - ## bind the machine availabilities with full-Calendar events $scope.eventSources = [] @@ -412,7 +409,7 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat $scope.slotToModify.title = if $scope.currentUser.role isnt 'admin' then _t('i_ve_reserved') else _t('not_available') $scope.slotToModify.backgroundColor = 'white' $scope.slotToModify = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' @@ -425,7 +422,7 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat $scope.slotToPlace.backgroundColor = 'white' $scope.slotToPlace.title = '' $scope.slotToPlace = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' @@ -458,7 +455,7 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat $scope.slotToModify.can_modify = false $scope.slotToModify = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' , (err) -> # failure growl.error(_t('unable_to_change_the_reservation')) console.error(err) @@ -476,7 +473,7 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat $scope.slotToModify.backgroundColor = 'white' $scope.slotToModify = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' @@ -532,8 +529,8 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat $scope.plansAreShown = false updateCartPrice() $timeout -> - $scope.calendar.fullCalendar 'refetchEvents' - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'refetchEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' @@ -732,7 +729,7 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat $scope.slotToModify = event event.backgroundColor = '#eee' event.title = _t('i_change') - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' else if type == 'cancel' dialogs.confirm resolve: @@ -750,7 +747,7 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat $scope.canceledSlot.is_reserved = false $scope.canceledSlot.can_modify = false $scope.canceledSlot = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' , -> # error while canceling growl.error _t('cancellation_failed') , -> @@ -758,7 +755,7 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat $scope.selectedPlan = null $scope.modifiedSlots = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' updateCartPrice() @@ -930,8 +927,8 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan) $scope.plansAreShown = false - $scope.calendar.fullCalendar 'refetchEvents' - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'refetchEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' diff --git a/app/assets/javascripts/controllers/trainings.coffee.erb b/app/assets/javascripts/controllers/trainings.coffee.erb index 028886969..3b54d80a1 100644 --- a/app/assets/javascripts/controllers/trainings.coffee.erb +++ b/app/assets/javascripts/controllers/trainings.coffee.erb @@ -51,8 +51,8 @@ Application.Controllers.controller "ShowTrainingController", ['$scope', '$state' # training can be reserved during the reservation process (the shopping cart may contains only one training and a subscription). ## -Application.Controllers.controller "ReserveTrainingController", ["$scope", "$state", '$stateParams', '$filter', '$compile', "$uibModal", 'Auth', 'dialogs', '$timeout', 'Price', 'Availability', 'Slot', 'Member', 'Setting', 'CustomAsset', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', 'trainingPromise', '_t' -, ($scope, $state, $stateParams, $filter, $compile, $uibModal, Auth, dialogs, $timeout, Price, Availability, Slot, Member, Setting, CustomAsset, availabilityTrainingsPromise, plansPromise, groupsPromise, growl, settingsPromise, trainingPromise, _t) -> +Application.Controllers.controller "ReserveTrainingController", ["$scope", "$state", '$stateParams', '$filter', '$compile', "$uibModal", 'Auth', 'dialogs', '$timeout', 'Price', 'Availability', 'Slot', 'Member', 'Setting', 'CustomAsset', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig' +($scope, $state, $stateParams, $filter, $compile, $uibModal, Auth, dialogs, $timeout, Price, Availability, Slot, Member, Setting, CustomAsset, availabilityTrainingsPromise, plansPromise, groupsPromise, growl, settingsPromise, trainingPromise, _t, uiCalendarConfig) -> @@ -77,9 +77,6 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta ### PUBLIC SCOPE ### - ## after fullCalendar loads, provides access to its methods through $scope.calendar.fullCalendar() - $scope.calendar = null - ## bind the trainings availabilities with full-Calendar events $scope.eventSources = [ { events: availabilityTrainingsPromise, textColor: 'black' } ] @@ -148,7 +145,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta eventClick: (event, jsEvent, view) -> calendarEventClickCb(event, jsEvent, view) eventAfterAllRender: (view)-> - $scope.events = $scope.calendar.fullCalendar 'clientEvents' + $scope.events = uiCalendarConfig.calendars.calendar.fullCalendar 'clientEvents' eventRender: (event, element, view) -> eventRenderCb(event, element, view) @@ -174,7 +171,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta Member.get {id: $scope.ctrl.member.id}, (member) -> $scope.ctrl.member = member Availability.trainings {trainingId: $stateParams.id, member_id: $scope.ctrl.member.id}, (trainings) -> - $scope.calendar.fullCalendar 'removeEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'removeEvents' $scope.eventSources.push events: trainings textColor: 'black' @@ -210,8 +207,8 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta $scope.selectedPlan = null $scope.trainingIsValid = false $timeout -> - $scope.calendar.fullCalendar 'refetchEvents' - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.fullCalendar 'refetchEvents' + uiCalendarConfig.calendars.fullCalendar 'rerenderEvents' @@ -283,7 +280,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta $scope.slotToModify.title = if $scope.currentUser.role isnt 'admin' then $scope.slotToModify.training.name + " - " + _t('i_ve_reserved') else $scope.slotToModify.training.name $scope.slotToModify.backgroundColor = 'white' $scope.slotToModify = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' @@ -296,7 +293,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta $scope.slotToPlace.backgroundColor = 'white' $scope.slotToPlace.title = $scope.slotToPlace.training.name $scope.slotToPlace = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' @@ -329,7 +326,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta $scope.slotToModify.can_modify = false $scope.slotToModify.is_completed = false if $scope.slotToModify.is_completed $scope.slotToModify = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' , -> # failure growl.error('an_error_occured_preventing_the_booked_slot_from_being_modified') @@ -345,7 +342,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta $scope.slotToModify.title = if $scope.currentUser.role isnt 'admin' then $scope.slotToModify.training.name + " - " + _t('i_ve_reserved') else $scope.slotToModify.training.name $scope.slotToModify.backgroundColor = 'white' $scope.slotToModify = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' @@ -426,7 +423,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta angular.forEach $scope.events, (e)-> if event.id != e.id e.backgroundColor = 'white' - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' # two if below for move training reserved # if training isnt reserved and have a training to modify and same training and not complete else if !event.is_reserved && $scope.slotToModify && slotCanBePlaced(event) @@ -436,7 +433,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta $scope.slotToPlace = event event.backgroundColor = '#bbb' event.title = event.training.name + ' - ' + _t('i_shift') - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' # if training reserved can modify else if event.is_reserved and (slotCanBeModified(event) or slotCanBeCanceled(event)) and !$scope.slotToModify and !$scope.selectedTraining event.movable = slotCanBeModified(event) @@ -454,7 +451,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta $scope.slotToModify = event event.backgroundColor = '#eee' event.title = event.training.name + ' - ' + _t('i_change') - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' else if type == 'cancel' dialogs.confirm resolve: @@ -473,7 +470,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta $scope.canceledSlot.can_modify = false $scope.canceledSlot.is_completed = false if event.is_completed $scope.canceledSlot = null - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' , -> # error while canceling growl.error _t('cancellation_failed') , -> # canceled @@ -635,8 +632,8 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta Auth._currentUser.training_credits = angular.copy(reservation.user.training_credits) Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits) - $scope.calendar.fullCalendar 'refetchEvents' - $scope.calendar.fullCalendar 'rerenderEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'refetchEvents' + uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents' diff --git a/app/assets/javascripts/router.coffee.erb b/app/assets/javascripts/router.coffee.erb index 16d42380e..9f84e5c03 100644 --- a/app/assets/javascripts/router.coffee.erb +++ b/app/assets/javascripts/router.coffee.erb @@ -506,9 +506,6 @@ angular.module('application.router', ['ui.router']). templateUrl: '<%= asset_path "admin/calendar/calendar.html" %>' controller: 'AdminCalendarController' resolve: - availabilitiesPromise: ['Availability', (Availability)-> - Availability.query().$promise - ] bookingWindowStart: ['Setting', (Setting)-> Setting.get(name: 'booking_window_start').$promise ] diff --git a/app/controllers/api/availabilities_controller.rb b/app/controllers/api/availabilities_controller.rb index f6529e6ba..c5e4b5cd8 100644 --- a/app/controllers/api/availabilities_controller.rb +++ b/app/controllers/api/availabilities_controller.rb @@ -8,7 +8,10 @@ class API::AvailabilitiesController < API::ApiController def index authorize Availability + start_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:start]) + end_date = ActiveSupport::TimeZone[params[:timezone]].parse(params[:end]).end_of_day @availabilities = Availability.includes(:machines,:tags,:trainings).where.not(available_type: 'event') + .where('start_at >= ? AND end_at <= ?', start_date, end_date) end def show diff --git a/app/views/api/availabilities/index.json.jbuilder b/app/views/api/availabilities/index.json.jbuilder index eaeda36e6..c51987e8d 100644 --- a/app/views/api/availabilities/index.json.jbuilder +++ b/app/views/api/availabilities/index.json.jbuilder @@ -9,4 +9,8 @@ json.array!(@availabilities) do |availability| json.backgroundColor 'white' json.borderColor availability.available_type == 'machines' ? '#e4cd78' : '#bd7ae9' json.tag_ids availability.tag_ids + json.tags availability.tags do |t| + json.id t.id + json.name t.name + end end diff --git a/bower.json b/bower.json index 4ba28caa6..2065c2514 100644 --- a/bower.json +++ b/bower.json @@ -18,7 +18,7 @@ "angular-bootstrap": "~0.14.3", "angular-ui-router": ">=0.2.15", "fullcalendar": "=2.3.1", - "angular-ui-calendar": "0.9.0-beta.1", + "angular-ui-calendar": "1.0.1", "moment": "=2.10.6", "angular-moment": ">=0.10.3", "ngUpload": ">=0.5.11", diff --git a/vendor/assets/components/angular-ui-calendar/.bower.json b/vendor/assets/components/angular-ui-calendar/.bower.json index 755c1f194..b01057744 100644 --- a/vendor/assets/components/angular-ui-calendar/.bower.json +++ b/vendor/assets/components/angular-ui-calendar/.bower.json @@ -1,6 +1,6 @@ { "name": "angular-ui-calendar", - "version": "0.9.0-beta.1", + "version": "1.0.1", "description": "A complete AngularJS directive for the Arshaw FullCalendar.", "author": "https://github.com/angular-ui/ui-calendar/graphs/contributors", "license": "MIT", @@ -16,21 +16,27 @@ "package.json" ], "dependencies": { - "angular": "~1.2.x", - "fullcalendar": "~2.x" + "angular": "1.3.15", + "jquery": "2.x", + "fullcalendar": "2.3.1", + "moment": "2.*" }, "devDependencies": { "angular-mocks": "~1.x", - "bootstrap-css": "2.3.1", - "jquery-ui": "~1.10.3" + "bootstrap-css": "2.3.1" }, - "_release": "0.9.0-beta.1", + "resolutions": { + "jquery": "~2.x", + "angular": "1.3.15" + }, + "_release": "1.0.1", "_resolution": { "type": "version", - "tag": "0.9.0-beta.1", - "commit": "80a32ee00a6a327ea1446451d725fdd30a4535e9" + "tag": "1.0.1", + "commit": "9c658bcf574be738bbe24258992da263eafc3095" }, - "_source": "git://github.com/angular-ui/ui-calendar.git", - "_target": "0.9.0-beta.1", - "_originalSource": "angular-ui-calendar" + "_source": "https://github.com/angular-ui/ui-calendar.git", + "_target": "1.0.1", + "_originalSource": "angular-ui-calendar", + "_direct": true } \ No newline at end of file diff --git a/vendor/assets/components/angular-ui-calendar/README.md b/vendor/assets/components/angular-ui-calendar/README.md index 916c18a5d..5e88a01e3 100644 --- a/vendor/assets/components/angular-ui-calendar/README.md +++ b/vendor/assets/components/angular-ui-calendar/README.md @@ -1,50 +1,54 @@ -# ui-calendar directive [![Build Status](https://travis-ci.org/angular-ui/ui-calendar.png?branch=master)](https://travis-ci.org/angular-ui/ui-calendar) +# ui-calendar directive [![Build Status](https://travis-ci.org/angular-ui/ui-calendar.svg?branch=master)](https://travis-ci.org/angular-ui/ui-calendar) + +[![Join the chat at https://gitter.im/angular-ui/ui-calendar](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular-ui/ui-calendar?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) A complete AngularJS directive for the Arshaw FullCalendar. # Requirements + - ([AngularJS](http://code.angularjs.org/1.2.1/angular.js)) - ([fullcalendar.js 2.0 and it's dependencies](http://arshaw.com/fullcalendar/download/)) - optional - ([gcal-plugin](http://arshaw.com/js/fullcalendar-1.5.3/fullcalendar/gcal.js)) -# Testing - -We use karma and grunt to ensure the quality of the code. - - npm install -g grunt-cli - npm install - bower install - grunt - # Usage -We use [bower](http://twitter.github.com/bower/) for dependency management. Add +Using [bower](http://bower.io) run: + + bower install --save angular-ui-calendar + +Alternatively you can add it to your `bower.json` like this: dependencies: { "angular-ui-calendar": "latest" } -To your `components.json` file. Then run +And then run bower install -This will copy the ui-calendar files into your `components` folder, along with its dependencies. Load the script files in your application: +This will copy the ui-calendar files into your `components` folder, along with its dependencies. Load the script and style files in your application: - - - + + + + + - - + + Add the calendar module as a dependency to your application module: - var myAppModule = angular.module('MyApp', ['ui.calendar']) + var app = angular.module('App', ['ui.calendar']) -Apply the directive to your div elements. The calendar must be supplied an array of decoumented event sources to render itself: +Apply the directive to your div elements. The calendar must be supplied an array of documented event sources to render itself:
+Define your model in a scope e.g. + + $scope.eventSources = []; + ## Options All the Arshaw Fullcalendar options can be passed through the directive. This even means function objects that are declared on the scope. @@ -73,20 +77,20 @@ All the Arshaw Fullcalendar options can be passed through the directive. This ev The ui-calendar directive plays nicely with ng-model. -An Event Sources objects needs to be created to pass into ng-model. This object will be watched for changes and update the calendar accordingly, giving the calendar some Angular Magic. +An Event Sources objects needs to be created to pass into ng-model. This object's values will be watched for changes. If a change occurs, then that specific calendar will call the appropriate fullCalendar method. The ui-calendar directive expects the eventSources object to be any type allowed in the documentation for the fullcalendar. [docs](http://arshaw.com/fullcalendar/docs/event_data/Event_Source_Object/) Note that all calendar options which are functions that are passed into the calendar are wrapped in an apply automatically. ## Accessing the calendar object -To avoid potential issues, by default the calendar object is not available in the parent scope. Access the object by declaring a calendar attribute name: +It is possible to access a specific calendar object by declaring a name for it on the uiCalendar directive. In this next line we are naming the calendar 'myCalendar'. This will be attached to the uiCalendarConfig constant object, that can be accessed via DI.
-Now the calendar object is available in the parent scope: +Now the calendar object is available in uiCalendarConfig.calendars: - $scope.myCalendar.fullCalendar + uiCalendarConfig.calendars.myCalendar This allows you to declare any number of calendar objects with distinct names. @@ -102,9 +106,13 @@ If you need to automatically re-render other event data, you can use `calendar-w returns "" + event.price; } - + // will now watch for price +### Adding new events issue + +When adding new events to the calendar they can disappear when switching months. To solve this add `stick: true` to the event object being added to the scope. + ## Watching the displayed date range of the calendar There is no mechanism to $watch the displayed date range on the calendar due to the JQuery nature of fullCalendar. If you want @@ -121,9 +129,22 @@ in a service, instead of letting fullCalendar pull them via AJAX), you can add t } }; +# Minify + + grunt minify + ## Documentation for the Calendar The calendar works alongside of all the documentation represented [here](http://arshaw.com/fullcalendar/docs) ## PR's R always Welcome Make sure that if a new feature is added, that the proper tests are created. + +# Testing + +We use karma and grunt to ensure the quality of the code. + + npm install -g grunt-cli + npm install + bower install + grunt diff --git a/vendor/assets/components/angular-ui-calendar/bower.json b/vendor/assets/components/angular-ui-calendar/bower.json index 21193eea2..292d38410 100644 --- a/vendor/assets/components/angular-ui-calendar/bower.json +++ b/vendor/assets/components/angular-ui-calendar/bower.json @@ -1,6 +1,6 @@ { "name": "angular-ui-calendar", - "version": "0.9.0-beta.1", + "version": "1.0.1", "description": "A complete AngularJS directive for the Arshaw FullCalendar.", "author": "https://github.com/angular-ui/ui-calendar/graphs/contributors", "license": "MIT", @@ -16,12 +16,17 @@ "package.json" ], "dependencies": { - "angular": "~1.2.x", - "fullcalendar": "~2.x" + "angular": "1.3.15", + "jquery": "2.x", + "fullcalendar": "2.3.1", + "moment": "2.*" }, "devDependencies": { "angular-mocks": "~1.x", - "bootstrap-css": "2.3.1", - "jquery-ui": "~1.10.3" + "bootstrap-css": "2.3.1" + }, + "resolutions": { + "jquery": "~2.x", + "angular": "1.3.15" } } diff --git a/vendor/assets/components/angular-ui-calendar/src/calendar.js b/vendor/assets/components/angular-ui-calendar/src/calendar.js index 80a02eaae..6b953f1b7 100644 --- a/vendor/assets/components/angular-ui-calendar/src/calendar.js +++ b/vendor/assets/components/angular-ui-calendar/src/calendar.js @@ -9,48 +9,56 @@ */ angular.module('ui.calendar', []) - .constant('uiCalendarConfig', {}) - .controller('uiCalendarCtrl', ['$scope', '$timeout', function($scope, $timeout){ + .constant('uiCalendarConfig', {calendars: {}}) + .controller('uiCalendarCtrl', ['$scope', + '$locale', function( + $scope, + $locale){ - var sourceSerialId = 1, - eventSerialId = 1, - sources = $scope.eventSources, + var sources = $scope.eventSources, extraEventSignature = $scope.calendarWatchEvent ? $scope.calendarWatchEvent : angular.noop, wrapFunctionWithScopeApply = function(functionToWrap){ - var wrapper; - - if (functionToWrap){ - wrapper = function(){ - // This happens outside of angular context so we need to wrap it in a timeout which has an implied apply. - // In this way the function will be safely executed on the next digest. + return function(){ + // This may happen outside of angular context, so create one if outside. + if ($scope.$root.$$phase) { + return functionToWrap.apply(this, arguments); + } else { var args = arguments; - var _this = this; - $timeout(function(){ - functionToWrap.apply(_this, args); + var self = this; + return $scope.$root.$apply(function(){ + return functionToWrap.apply(self, args); }); - }; - } - - return wrapper; + } + }; }; - this.eventsFingerprint = function(e) { + var eventSerialId = 1; + // @return {String} fingerprint of the event object and its properties + this.eventFingerprint = function(e) { if (!e._id) { e._id = eventSerialId++; } // This extracts all the information we need from the event. http://jsperf.com/angular-calendar-events-fingerprint/3 return "" + e._id + (e.id || '') + (e.title || '') + (e.url || '') + (+e.start || '') + (+e.end || '') + - (e.allDay || '') + (e.className || '') + extraEventSignature(e) || ''; + (e.allDay || '') + (e.className || '') + extraEventSignature({event: e}) || ''; }; - this.sourcesFingerprint = function(source) { - return source.__id || (source.__id = sourceSerialId++); + var sourceSerialId = 1, sourceEventsSerialId = 1; + // @return {String} fingerprint of the source object and its events array + this.sourceFingerprint = function(source) { + var fp = '' + (source.__id || (source.__id = sourceSerialId++)), + events = angular.isObject(source) && source.events; + if (events) { + fp = fp + '-' + (events.__id || (events.__id = sourceEventsSerialId++)); + } + return fp; }; + // @return {Array} all events from all sources this.allEvents = function() { - // return sources.flatten(); but we don't have flatten + // do sources.map(&:events).flatten(), but we don't have flatten var arraySources = []; for (var i = 0, srcLen = sources.length; i < srcLen; i++) { var source = sources[i]; @@ -61,7 +69,7 @@ angular.module('ui.calendar', []) // event source as object, ie extended form var extEvent = {}; for(var key in source){ - if(key !== '_uiCalId' && key !== 'events'){ + if(key !== '_id' && key !== 'events'){ extEvent[key] = source[key]; } } @@ -71,14 +79,17 @@ angular.module('ui.calendar', []) arraySources.push(source.events); } } - return Array.prototype.concat.apply([], arraySources); }; - // Track changes in array by assigning id tokens to each element and watching the scope for changes in those tokens - // arguments: - // arraySource array of function that returns array of objects to watch - // tokenFn function(object) that returns the token for a given object + // Track changes in array of objects by assigning id tokens to each element and watching the scope for changes in the tokens + // @param {Array|Function} arraySource array of objects to watch + // @param tokenFn {Function} that returns the token for a given object + // @return {Object} + // subscribe: function(scope, function(newTokens, oldTokens)) + // called when source has changed. return false to prevent individual callbacks from firing + // onAdded/Removed/Changed: + // when set to a callback, called each item where a respective change is detected this.changeWatcher = function(arraySource, tokenFn) { var self; var getTokens = function() { @@ -92,8 +103,12 @@ angular.module('ui.calendar', []) } return result; }; - // returns elements in that are in a but not in b - // subtractAsSets([4, 5, 6], [4, 5, 7]) => [6] + + // @param {Array} a + // @param {Array} b + // @return {Array} elements in that are in a but not in b + // @example + // subtractAsSets([6, 100, 4, 5], [4, 5, 7]) // [6, 100] var subtractAsSets = function(a, b) { var result = [], inB = {}, i, n; for (i = 0, n = b.length; i < n; i++) { @@ -110,6 +125,7 @@ angular.module('ui.calendar', []) // Map objects to tokens and vice-versa var map = {}; + // Compare newTokens to oldTokens and call onAdded, onRemoved, and onChanged handlers for each affected event respectively. var applyChanges = function(newTokens, oldTokens) { var i, n, el, token; var replacedTokens = {}; @@ -138,9 +154,10 @@ angular.module('ui.calendar', []) } }; return self = { - subscribe: function(scope, onChanged) { + subscribe: function(scope, onArrayChanged) { scope.$watch(getTokens, function(newTokens, oldTokens) { - if (!onChanged || onChanged(newTokens, oldTokens) !== false) { + var notify = !(onArrayChanged && onArrayChanged(newTokens, oldTokens) === false); + if (notify) { applyChanges(newTokens, oldTokens); } }, true); @@ -156,7 +173,7 @@ angular.module('ui.calendar', []) angular.extend(config, uiCalendarConfig); angular.extend(config, calendarSettings); - + angular.forEach(config, function(value,key){ if (typeof value === 'function'){ config[key] = wrapFunctionWithScopeApply(config[key]); @@ -165,26 +182,31 @@ angular.module('ui.calendar', []) return config; }; - }]) - .directive('uiCalendar', ['uiCalendarConfig', '$locale', function(uiCalendarConfig, $locale) { - // Configure to use locale names by default - var tValues = function(data) { - // convert {0: "Jan", 1: "Feb", ...} to ["Jan", "Feb", ...] - var r, k; - r = []; - for (k in data) { - r[k] = data[k]; - } - return r; - }; - var dtf = $locale.DATETIME_FORMATS; - uiCalendarConfig = angular.extend({ - monthNames: tValues(dtf.MONTH), - monthNamesShort: tValues(dtf.SHORTMONTH), - dayNames: tValues(dtf.DAY), - dayNamesShort: tValues(dtf.SHORTDAY) - }, uiCalendarConfig || {}); + this.getLocaleConfig = function(fullCalendarConfig) { + if (!fullCalendarConfig.lang || fullCalendarConfig.useNgLocale) { + // Configure to use locale names by default + var tValues = function(data) { + // convert {0: "Jan", 1: "Feb", ...} to ["Jan", "Feb", ...] + var r, k; + r = []; + for (k in data) { + r[k] = data[k]; + } + return r; + }; + var dtf = $locale.DATETIME_FORMATS; + return { + monthNames: tValues(dtf.MONTH), + monthNamesShort: tValues(dtf.SHORTMONTH), + dayNames: tValues(dtf.DAY), + dayNamesShort: tValues(dtf.SHORTDAY) + }; + } + return {}; + }; + }]) + .directive('uiCalendar', ['uiCalendarConfig', function(uiCalendarConfig) { return { restrict: 'A', scope: {eventSources:'=ngModel',calendarWatchEvent: '&'}, @@ -193,8 +215,9 @@ angular.module('ui.calendar', []) var sources = scope.eventSources, sourcesChanged = false, - eventSourcesWatcher = controller.changeWatcher(sources, controller.sourcesFingerprint), - eventsWatcher = controller.changeWatcher(controller.allEvents, controller.eventsFingerprint), + calendar, + eventSourcesWatcher = controller.changeWatcher(sources, controller.sourceFingerprint), + eventsWatcher = controller.changeWatcher(controller.allEvents, controller.eventFingerprint), options = null; function getOptions(){ @@ -203,8 +226,12 @@ angular.module('ui.calendar', []) fullCalendarConfig = controller.getFullCalendarConfig(calendarSettings, uiCalendarConfig); + var localeFullCalendarConfig = controller.getLocaleConfig(fullCalendarConfig); + angular.extend(localeFullCalendarConfig, fullCalendarConfig); options = { eventSources: sources }; - angular.extend(options, fullCalendarConfig); + angular.extend(options, localeFullCalendarConfig); + //remove calendars from options + options.calendars = null; var options2 = {}; for(var o in options){ @@ -216,51 +243,60 @@ angular.module('ui.calendar', []) } scope.destroy = function(){ - if(scope.calendar && scope.calendar.fullCalendar){ - scope.calendar.fullCalendar('destroy'); + if(calendar && calendar.fullCalendar){ + calendar.fullCalendar('destroy'); } if(attrs.calendar) { - scope.calendar = scope.$parent[attrs.calendar] = $(elm).html(''); + calendar = uiCalendarConfig.calendars[attrs.calendar] = $(elm).html(''); } else { - scope.calendar = $(elm).html(''); + calendar = $(elm).html(''); } }; scope.init = function(){ - scope.calendar.fullCalendar(options); + calendar.fullCalendar(options); + if(attrs.calendar) { + uiCalendarConfig.calendars[attrs.calendar] = calendar; + } }; eventSourcesWatcher.onAdded = function(source) { - scope.calendar.fullCalendar('addEventSource', source); - sourcesChanged = true; + calendar.fullCalendar('addEventSource', source); + sourcesChanged = true; }; eventSourcesWatcher.onRemoved = function(source) { - scope.calendar.fullCalendar('removeEventSource', source); + calendar.fullCalendar('removeEventSource', source); + sourcesChanged = true; + }; + + eventSourcesWatcher.onChanged = function(source) { + calendar.fullCalendar('refetchEvents'); sourcesChanged = true; }; eventsWatcher.onAdded = function(event) { - scope.calendar.fullCalendar('renderEvent', event); + calendar.fullCalendar('renderEvent', event, (event.stick ? true : false)); }; eventsWatcher.onRemoved = function(event) { - scope.calendar.fullCalendar('removeEvents', function(e) { - return e._id === event._id; - }); + calendar.fullCalendar('removeEvents', event._id); }; eventsWatcher.onChanged = function(event) { - event._start = $.fullCalendar.moment(event.start); - event._end = $.fullCalendar.moment(event.end); - scope.calendar.fullCalendar('updateEvent', event); + var clientEvents = calendar.fullCalendar('clientEvents', event._id); + for (var i = 0; i < clientEvents.length; i++) { + var clientEvent = clientEvents[i]; + clientEvent = angular.extend(clientEvent, event); + calendar.fullCalendar('updateEvent', clientEvent); + } }; eventSourcesWatcher.subscribe(scope); - eventsWatcher.subscribe(scope, function(newTokens, oldTokens) { + eventsWatcher.subscribe(scope, function() { if (sourcesChanged === true) { sourcesChanged = false; - // prevent incremental updates in this case + // return false to prevent onAdded/Removed/Changed handlers from firing in this case return false; } }); @@ -271,4 +307,4 @@ angular.module('ui.calendar', []) }); } }; -}]); \ No newline at end of file +}]);