2135 lines
73 KiB
XML
2135 lines
73 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<javascript app="calendar">
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.main.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000250"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.browse.main.js - Calendar main browsing controller
|
|
*
|
|
* Author: Rikki Tissier
|
|
*/
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.browse.main', {
|
|
|
|
_ajaxObj: null,
|
|
|
|
initialize: function () {
|
|
this.on( 'click', '[data-action="changeView"]', this.changeView );
|
|
this.on( window, 'historychange:calendarView', this.stateChange );
|
|
this.setup();
|
|
},
|
|
|
|
/**
|
|
* Controller setup method
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setup () {
|
|
ips.utils.history.replaceState( { controller: 'calendarView' }, 'calendarView', window.location.href );
|
|
},
|
|
|
|
/**
|
|
* Changes the calendar view dynamically
|
|
*
|
|
* @param {Event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
changeView(e) {
|
|
e.preventDefault();
|
|
|
|
// Load the url via ajax instead
|
|
const title = $( e.currentTarget ).attr('title');
|
|
const url = $( e.currentTarget ).attr('href');
|
|
|
|
|
|
ips.utils.history.pushState( { controller: 'calendarView' }, 'calendarView', url );
|
|
document.title = title
|
|
},
|
|
|
|
/**
|
|
* Event handler for history state changes
|
|
*
|
|
* @param {event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
stateChange () {
|
|
const data = ips.utils.history.getState('calendarView') || {}, url = window.location.href
|
|
|
|
if (data.controller !== 'calendarView') {
|
|
return;
|
|
}
|
|
|
|
// Track page view
|
|
ips.utils.analytics.trackPageView( url );
|
|
|
|
this._updateView( url )
|
|
},
|
|
|
|
/**
|
|
* Loads a new view
|
|
*
|
|
* @param {string} url URL to load
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
_updateView (url) {
|
|
if( this._ajaxObj && _.isFunction( this._ajaxObj.abort ) ){
|
|
this._ajaxObj.abort();
|
|
}
|
|
|
|
this._setLoading( true );
|
|
|
|
this._ajaxObj = ips.getAjax()(
|
|
url, {
|
|
showLoading: true
|
|
})
|
|
.done(response => {
|
|
this.scope.html( response );
|
|
|
|
$( document ).trigger( 'contentChange', [ this.scope ] );
|
|
})
|
|
.always(() => {
|
|
this._setLoading( false );
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Toggles the loading state on the view
|
|
*
|
|
* @param {boolean} state Enable the loading state?
|
|
* @returns {void}
|
|
*/
|
|
_setLoading(state) {
|
|
if( state ){
|
|
this.scope.animate( { opacity: "0.6" }, 'fast' );
|
|
} else {
|
|
this.scope.animate( { opacity: "1" }, 'fast' );
|
|
}
|
|
}
|
|
});
|
|
}(jQuery, _));]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/browse" javascript_name="ips.browse.monthView.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000250"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.browse.monthView.js - Month view controller
|
|
*
|
|
* Author: Rikki Tissier
|
|
*/
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.browse.monthView', {
|
|
|
|
_emptyEvent: "<li class='cEvents_event cEvents_empty' data-eventid='0'><span></span></a></li>",
|
|
|
|
initialize: function () {
|
|
this.setup();
|
|
},
|
|
|
|
/**
|
|
* Setup method
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setup: function () {
|
|
this._alignEvents();
|
|
},
|
|
|
|
|
|
_alignEvents: function () {
|
|
// Lets start by getting all active days in the current calendar
|
|
var days = this.scope.find('.cCalendar_date');
|
|
var currentPositions = [];
|
|
var self = this;
|
|
|
|
_.each( days, function (day) {
|
|
var day = $( day );
|
|
var dayNumber = day.find('.cCalendar_dayNumber').text();
|
|
var weekStart = false;
|
|
|
|
if( day.closest('td').is('tr > td:first-child') ){
|
|
weekStart = true;
|
|
}
|
|
|
|
// Get events for this day
|
|
var events = day.find('.cEvents_ranged [data-eventID]');
|
|
|
|
// If there's no events, we can skip this day
|
|
if( !events.length ){
|
|
currentPositions = [];
|
|
return;
|
|
}
|
|
|
|
// Build a wrapper into which we'll move our events
|
|
var wrapper = $("<ul/>").addClass('cEvents');
|
|
var spaces = 0;
|
|
|
|
// Now we loop over currentPositions (from the previous day), and try and arrange today's events
|
|
// in the same order
|
|
if( currentPositions.length ){
|
|
var doneEvent = false;
|
|
|
|
for( var i = 0; i < currentPositions.length; i++ ){
|
|
if( events.filter('[data-eventID="' + currentPositions[i] + '"]').length ){
|
|
wrapper.append( events.filter('[data-eventID="' + currentPositions[i] + '"]') );
|
|
doneEvent = true;
|
|
} else {
|
|
|
|
// If this is the first day of the week, we won't bother adding spacers unless we've already done an event today
|
|
// This prevents lots of unnecessary spacers carrying over from the previous row
|
|
if( !weekStart || doneEvent ){
|
|
wrapper.append( self._emptyEvent );
|
|
spaces++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var remainingEvents = day.find('.cEvents_ranged [data-eventID]');
|
|
|
|
// If we have any remaining events, and there's gaps available, we can move those events into the gaps rather than
|
|
// just putting them at the end
|
|
if( spaces && remainingEvents.length ){
|
|
var availableSpaces = wrapper.find('[data-eventID="0"]');
|
|
|
|
// If we have a space and an event, move the event into that space
|
|
for( var i = 0; i <= spaces; i++ ){
|
|
if( remainingEvents[ i ] && availableSpaces[ i ] ){
|
|
$( availableSpaces[ i ] ).replaceWith( $( remainingEvents[ i ] ) );
|
|
}
|
|
}
|
|
|
|
// Update remaining events again
|
|
remainingEvents = day.find('.cEvents_ranged [data-eventID]');
|
|
}
|
|
|
|
// Add in remaining events
|
|
wrapper.append( remainingEvents );
|
|
|
|
// Replace the existing wrapper with the new, correctly-ordered one
|
|
day.find('.cEvents_ranged > .cEvents').replaceWith( wrapper );
|
|
|
|
// Now we need to build a new currentPositions array for this day, so that the following
|
|
// day can use it to do its thing
|
|
currentPositions = [];
|
|
|
|
_.each( day.find('.cEvents_ranged [data-eventID]'), function (event) {
|
|
var eventID = parseInt( $( event ).attr('data-eventID') );
|
|
|
|
if( eventID === 0 ){
|
|
currentPositions.push('-');
|
|
} else if( _.isNumber( eventID ) && !_.isNaN( eventID ) ){
|
|
currentPositions.push( eventID );
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}(jQuery, _));]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/overview" javascript_name="ips.overview.eventList.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000300"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.overview.eventList.js - Controller for event listing
|
|
*
|
|
* Author: Rikki Tissier
|
|
*/
|
|
var PER_PAGE = 16;
|
|
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.overview.eventList', {
|
|
initialize: function () {
|
|
this.on( 'click', '[data-action="loadMore"]', this.loadMore );
|
|
this.on( 'click', '[data-action="changeMonth"]', this.changeMonth );
|
|
this.setup();
|
|
},
|
|
|
|
/**
|
|
* Setup method
|
|
* Hides categories the user has already hidden
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setup: function () {
|
|
this._eventList = this.scope.find('[data-role="eventList"]');
|
|
this._loadMore = this.scope.find('[data-action="loadMore"]');
|
|
this._monthNav = this.scope.find('[data-role="monthNav"]');
|
|
},
|
|
|
|
loadMore: function (e) {
|
|
e.preventDefault();
|
|
|
|
var placeholders = this.getPlaceholders();
|
|
this._eventList.append( placeholders );
|
|
this._loadMore.prop('disabled', true);
|
|
|
|
// Get the current month/year
|
|
var self = this;
|
|
var current = this.getCurrentDate();
|
|
var total = this.scope.find('[data-eventID]').length;
|
|
var url = ips.getSetting('baseURL') + '?app=calendar&module=calendar&controller=view&view=overview&get=byMonth&m=' + current.month + '&y=' + current.year + '&offset=' + total;
|
|
|
|
ips.getAjax()( url )
|
|
.done( function (response) {
|
|
self._eventList.append( response.html );
|
|
self.removePlaceholders();
|
|
self.checkMoreButton( response.count );
|
|
self._loadMore.prop('disabled', false);
|
|
$( document ).trigger('contentChange', [ self.scope ]);
|
|
});
|
|
},
|
|
|
|
changeMonth: function (e) {
|
|
e.preventDefault();
|
|
|
|
var placeholders = this.getPlaceholders(4);
|
|
this._eventList.html( placeholders );
|
|
this._loadMore.prop('disabled', true);
|
|
|
|
// Toggle the correct month
|
|
this._monthNav.find('[data-action="changeMonth"]').removeClass('cEvents__monthNav__monthItem--active');
|
|
$( e.currentTarget ).addClass('cEvents__monthNav__monthItem--active');
|
|
|
|
// Now fetch results
|
|
var self = this;
|
|
var current = this.getCurrentDate();
|
|
var url = ips.getSetting('baseURL') + '?app=calendar&module=calendar&controller=view&view=overview&get=byMonth&m=' + current.month + '&y=' + current.year + '&offset=0';
|
|
|
|
ips.getAjax()( url )
|
|
.done( function (response) {
|
|
self._eventList.html( response.html );
|
|
self.checkMoreButton( response.count );
|
|
self._loadMore.prop('disabled', false);
|
|
$( document ).trigger('contentChange', [ self.scope ]);
|
|
});
|
|
},
|
|
|
|
getPlaceholders: function (count) { //@todo get actual count
|
|
var events = [];
|
|
|
|
if( _.isUndefined( count ) ){
|
|
count = 4;
|
|
}
|
|
|
|
for( var i = 0; i < count; i++ ){
|
|
events.push( ips.templates.render('eventLoading') );
|
|
}
|
|
|
|
return events.join('');
|
|
},
|
|
|
|
removePlaceholders: function () {
|
|
this.scope.find('.ipsData__item--loading').remove();
|
|
},
|
|
|
|
checkMoreButton: function (count) {
|
|
if( _.isNumber( count ) && count < PER_PAGE ){
|
|
this.scope.find('[data-action="loadMore"]').attr('hidden', true);
|
|
this.scope.find('[data-role="noMoreResults"]').removeAttr('hidden');
|
|
} else {
|
|
this.scope.find('[data-action="loadMore"]').removeAttr('hidden');
|
|
this.scope.find('[data-role="noMoreResults"]').attr('hidden', true);
|
|
}
|
|
},
|
|
|
|
getCurrentDate: function () {
|
|
var current = this.scope.find('[data-role="monthNav"] .cEvents__monthNav__monthItem--active');
|
|
|
|
return {
|
|
month: current.attr('data-month'),
|
|
year: current.attr('data-year')
|
|
};
|
|
}
|
|
});
|
|
}(jQuery, _));]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/overview" javascript_name="ips.overview.nearMe.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000300"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.overview.nearMe.js - Controller for near me
|
|
*
|
|
* Author: Rikki Tissier
|
|
*/
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.overview.nearMe', {
|
|
useGoogleMaps: false,
|
|
events: {},
|
|
useGeolocation: false,
|
|
|
|
initialize: function () {
|
|
this.setup();
|
|
|
|
this.on( 'change', 'input#useCurrentLocation', this.useCurrentLocation );
|
|
},
|
|
|
|
/**
|
|
* Setup method
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setup() {
|
|
if ( ips.utils.geolocation.getGeolocationIsAllowed() ) {
|
|
this.scope.find('input[type="checkbox"]').attr('checked', true);
|
|
this.useGeolocation = true;
|
|
}
|
|
|
|
// Are we using Mapbox or Google Maps?
|
|
if ('nearmeUseGoogle' in this.scope.data()) {
|
|
let apiKey = this.scope.data()['googlemapsApiKey'];
|
|
if ( !apiKey ) {
|
|
// handle failure
|
|
}
|
|
|
|
this.useGoogleMaps = true;
|
|
ips.ui.map.afterGoogleMapsLoaded(() => this.setupGoogleMaps())
|
|
}
|
|
else {
|
|
// Pull in the CSS
|
|
$('head').append(
|
|
`<link rel='stylesheet' type='text/css' media='all' href='https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.css'>
|
|
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/MarkerCluster.css' rel='stylesheet' />
|
|
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/MarkerCluster.Default.css' rel='stylesheet' />
|
|
<link rel='stylesheet' type='text/css' media='all' href='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/leaflet.fullscreen.css' />`
|
|
);
|
|
|
|
|
|
// Now the JS
|
|
window.ips.loader.get( [ 'https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.js' ] )
|
|
.then(
|
|
() => ips.loader.get([
|
|
'https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/leaflet.markercluster.js',
|
|
'https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/Leaflet.fullscreen.min.js'
|
|
])
|
|
)
|
|
.then( () => {
|
|
|
|
if ( this.useGeolocation ) {
|
|
this.getEventsByLocation();
|
|
} else {
|
|
this.fetchEvents();
|
|
}
|
|
|
|
this._mapReady = true;
|
|
});
|
|
}
|
|
},
|
|
|
|
googleMap: undefined,
|
|
|
|
/**
|
|
* setup the map for google maps; really just a callback for the google maps api response
|
|
*/
|
|
setupGoogleMaps: function() {
|
|
// just enter the fetch event flow; the response will be handled on return
|
|
if ( this.useGeolocation ) {
|
|
this.getEventsByLocation();
|
|
} else {
|
|
this.fetchEvents();
|
|
}
|
|
|
|
window.ipsGoogleMapsCallback = undefined;
|
|
|
|
this._mapReady = true;
|
|
},
|
|
|
|
/**
|
|
* Handles use current location checkbox
|
|
*/
|
|
useCurrentLocation: function() {
|
|
|
|
// Not the best way to go about this but we clear the map with fetchEvents response
|
|
if ( this.useGoogleMaps ) {
|
|
this.googleMap = false;
|
|
}
|
|
|
|
if( this.scope.find('#useCurrentLocation').is(':checked') ) {
|
|
this.getEventsByLocation();
|
|
} else {
|
|
ips.utils.geolocation.setGeolocationIsAllowed( ips.utils.geolocation.permissions.DENIED );
|
|
this.fetchEvents();
|
|
}
|
|
},
|
|
/**
|
|
* Uses the browser's geolocation to set the lat and long of the map; those are then sent to community to get a listing of nearby events
|
|
*/
|
|
getEventsByLocation: function () {
|
|
// Save the contents just in case we need it again
|
|
this.showPlaceholders();
|
|
ips.utils.geolocation.getCurrentPosition().then( coords => {
|
|
var lat = coords.latitude;
|
|
var long = coords.longitude;
|
|
|
|
// Update the near me link
|
|
this.scope.find('[data-role="nearMeLink"]')
|
|
.attr('href', ips.getSetting('baseURL') + '?app=calendar&do=search&form_submitted=1&lat=' + lat + '&lon=' + long )
|
|
.attr('data-lat', lat)
|
|
.attr('data-long', long);
|
|
|
|
this.fetchEvents(lat, long);
|
|
|
|
}).catch( () => {
|
|
ips.ui.alert.show( {
|
|
type: 'alert',
|
|
message: ips.getString('event_your_current_location_sorry'),
|
|
icon: 'warn'
|
|
});
|
|
this.scope.find('#useCurrentLocation').closest('li').remove();
|
|
this.fetchEvents();
|
|
});
|
|
},
|
|
|
|
fetchEvents: function (lat, long) {
|
|
var self = this;
|
|
|
|
this.showPlaceholders();
|
|
|
|
ips.getAjax()( ips.getSetting('baseURL') + '?app=calendar&module=calendar&controller=view&view=overview&get=nearMe' + ( lat && long ? '&lat=' + lat + '&lon=' + long : '' ) )
|
|
.done( function (response) {
|
|
self.scope.find('[data-role="locationEvents"]').html(response.content);
|
|
self.setUpMap(response.lat, response.long);
|
|
$(document).trigger('contentChange', [self.scope]);
|
|
});
|
|
},
|
|
|
|
setUpMap: function (lat, long) {
|
|
var self = this;
|
|
var mapDiv = this.scope.find('#map');
|
|
|
|
if (!mapDiv.length) {
|
|
Debug.log("No map container");
|
|
return;
|
|
}
|
|
|
|
if ( this.useGoogleMaps ) {
|
|
// Make sure these are numbers. They might come in as string encoded Floats
|
|
lat = Number(lat);
|
|
long = Number(long);
|
|
|
|
if ( !this.googleMap ) {
|
|
const mapContainer = mapDiv.get(0);
|
|
mapContainer.style.width = '100%';
|
|
mapContainer.style.height = '400px';
|
|
this.googleMap = new window.google.maps.Map(mapContainer, {zoom: 4, center: {lat, lng: long}});
|
|
} else {
|
|
this.googleMap.setCenter({ lat, lng: long });
|
|
}
|
|
|
|
|
|
// Update the near me link
|
|
self.scope.find('[data-role="nearMeLink"]')
|
|
.attr('href', ips.getSetting('baseURL') + '?app=calendar&do=search&form_submitted=1&lat=' + lat + '&lon=' + long )
|
|
.attr('data-lat', lat)
|
|
.attr('data-long', long);
|
|
|
|
// If we have the map now, set its contents
|
|
if ( this.googleMap ) {
|
|
let markers;
|
|
try {
|
|
|
|
// We first copy the JSON and make sure lat an long are all numeric
|
|
let _markers = JSON.parse(mapDiv.attr('data-markers'));
|
|
let markers = [];
|
|
for ( let marker of Object.values(_markers) ) {
|
|
markers.push({
|
|
...marker,
|
|
lat: Number(marker.lat),
|
|
long: Number(marker.long)
|
|
});
|
|
}
|
|
|
|
for ( let marker of Object.values(markers) ) {
|
|
let mapMarker = new window.google.maps.Marker({
|
|
position: {lat: marker.lat, lng: marker.long},
|
|
map: this.googleMap,
|
|
title: marker.title
|
|
});
|
|
}
|
|
|
|
if ( Object.values(markers).length ) {
|
|
const cb = (() => {
|
|
let bounds = this.googleMap.getBounds();
|
|
if ( !bounds ) {
|
|
return window.setTimeout( cb, 200 );
|
|
}
|
|
let firstMarker = null;
|
|
let markerVisible = false;
|
|
let markerBounds = {latMax: null, latMin: null, lngMax: null, lngMin: null};
|
|
for (let marker of Object.values(markers)) {
|
|
markerBounds.latMax = markerBounds.latMax === null ? marker.lat : Math.max(markerBounds.latMax, marker.lat);
|
|
markerBounds.latMin = markerBounds.latMin === null ? marker.lat : Math.min(markerBounds.latMin, marker.lat);
|
|
markerBounds.lngMax = markerBounds.lngMax === null ? marker.long : Math.max(markerBounds.lngMax, marker.long);
|
|
markerBounds.lngMin = markerBounds.lngMin === null ? marker.long : Math.min(markerBounds.lngMin, marker.long);
|
|
firstMarker = firstMarker || marker;
|
|
if ( bounds.contains({lat: marker.lat, lng: marker.long}) ) {
|
|
markerVisible = true;
|
|
}
|
|
}
|
|
if (!markerVisible && firstMarker) {
|
|
// find the centermost event
|
|
let evtMidpoint = {
|
|
lat: ((markerBounds.latMax + markerBounds.latMin) / 2),
|
|
lng: ((markerBounds.lngMax + markerBounds.lngMin) / 2)
|
|
};
|
|
|
|
let minDistance = null;
|
|
let mostMiddleMarker = null;
|
|
if ( Object.values(markers).length > 1 ) {
|
|
for (let marker of Object.values(markers)) {
|
|
// we need to use the haversine formula to get he distance
|
|
let distance = this.getDistance(evtMidpoint.lat, marker.lat, evtMidpoint.lng, marker.long);
|
|
if (minDistance === null || distance < minDistance) {
|
|
minDistance = distance;
|
|
mostMiddleMarker = {lat: marker.lat, lng: marker.long};
|
|
}
|
|
}
|
|
} else {
|
|
mostMiddleMarker = {lat: firstMarker.lat, lng: firstMarker.long};
|
|
}
|
|
|
|
this.googleMap.panTo(mostMiddleMarker);
|
|
}
|
|
}).bind(this);
|
|
window.setTimeout(cb, 0);
|
|
}
|
|
|
|
} catch (e) {}
|
|
}
|
|
} else {
|
|
|
|
L.mapbox.accessToken = ips.getSetting('mapApiKey');
|
|
this._map = L.mapbox
|
|
.map(mapDiv.get(0))
|
|
.addLayer(L.mapbox.styleLayer('mapbox://styles/mapbox/streets-v11'));
|
|
|
|
// Map prefs
|
|
this._map.zoomControl = false;
|
|
this._map.minZoom = 2;
|
|
this._map.dragging = false;
|
|
this._map.zoomControl = false;
|
|
|
|
// Reposition zoom control
|
|
/*L.control.zoom({
|
|
position: 'bottomright'
|
|
}).addTo(this._map);*/
|
|
|
|
// Add and position fullscreen control
|
|
/*this._map.addControl(new L.Control.Fullscreen({
|
|
position: 'bottomleft'
|
|
}));*/
|
|
|
|
var markersGroup = new L.featureGroup([]);
|
|
var markers = $.parseJSON(mapDiv.attr('data-markers'));
|
|
|
|
for (var id in markers) {
|
|
var marker = L.marker([Number(markers[id].lat), Number(markers[id].long)], {
|
|
title: markers[id].title,
|
|
draggable: false,
|
|
eventId: parseInt(id)
|
|
});
|
|
|
|
//self._map.addLayer( marker );
|
|
markersGroup.addLayer(marker);
|
|
|
|
// Build info popup for this marker
|
|
marker.on('mouseover', _.bind(this._markerMouseOver, this));
|
|
marker.on('mouseout', _.bind(this._markerMouseOut, this));
|
|
}
|
|
|
|
markersGroup.addTo(this._map);
|
|
this._map.fitBounds(markersGroup.getBounds(), {maxZoom: 5});
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Use the haversine formula to get a COOEFFICIENT of the distance between two points. This coefficient must be multiplied by 2*3956 to get the miles and by 2*6371 to get the kilometers
|
|
*
|
|
* @param lat1
|
|
* @param lat2
|
|
* @param lng1
|
|
* @param lng2
|
|
*
|
|
*
|
|
* @return {number}
|
|
*/
|
|
getDistance: function (lat1, lat2, lng1, lng2) {
|
|
// The math module contains a function
|
|
// named toRadians which converts from
|
|
// degrees to radians.
|
|
lng1 = lng1 * Math.PI / 180;
|
|
lng2 = lng2 * Math.PI / 180;
|
|
lat1 = lat1 * Math.PI / 180;
|
|
lat2 = lat2 * Math.PI / 180;
|
|
|
|
// Haversine formula
|
|
let dlng = lng2 - lng1;
|
|
let dlat = lat2 - lat1;
|
|
let a = Math.pow(Math.sin(dlat / 2), 2)
|
|
+ Math.cos(lat1) * Math.cos(lat2)
|
|
* Math.pow(Math.sin(dlng / 2),2);
|
|
|
|
let c = Math.asin(Math.sqrt(a));
|
|
|
|
// Radius of earth in kilometers. Use 3956
|
|
// for miles
|
|
//let r = 6371;
|
|
|
|
// calculate the result; multiply by 2*6371 for kilometers and 2*3956 for miles; at the time of writing this, the distance is only being compared so no need to factor in all these constants
|
|
return c;
|
|
},
|
|
|
|
_markerMouseOver: function (e) {
|
|
var eventId = e.target.options.eventId;
|
|
|
|
// Fade out all events except this one
|
|
this.scope.find('[data-eventid]').stop(false, true);
|
|
this.scope.find('[data-eventid]:not([data-eventid="' + eventId + '"])').animate({ opacity: 0.4 }, 'fast');
|
|
},
|
|
|
|
_markerMouseOut: function (e) {
|
|
this.scope.find('[data-eventid]').stop(false, true);
|
|
this.scope.find('[data-eventid]').animate({ opacity: 1 }, 'fast');
|
|
},
|
|
|
|
showPlaceholders: function (count) {
|
|
var events = [];
|
|
|
|
for( var i = 0; i < 6; i++ ){
|
|
events.push( ips.templates.render('eventLoading') );
|
|
}
|
|
|
|
this.scope
|
|
.find('[data-role="locationEvents"]')
|
|
.removeClass('ipsJS_hide')
|
|
.html( ips.templates.render('nearMe', { events: events.join('') }) );
|
|
}
|
|
});
|
|
}(jQuery, _));]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/overview" javascript_name="ips.overview.search.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000300"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.overview.search.js - Controller for event search
|
|
*
|
|
* Author: Rikki Tissier
|
|
*/
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.overview.search', {
|
|
initialize() {
|
|
this.on('click', '[data-action="useMyLocation"]', this.useMyLocation);
|
|
this.on('click', '[data-action="cancelLocation"]', this.cancelLocation);
|
|
this.on('submit', this.doSearch);
|
|
this.on( document, 'click', '[data-action="backToOverview"]', this.backToOverview);
|
|
this.on( document, 'click', '[data-action="loadMoreSearch"]', this.loadMore);
|
|
this.on( document, 'menuItemSelected', '#elSortMenu', this.changeSort);
|
|
this.on( document, 'click', '[data-action="moreNearMe"]', this.moreNearMe);
|
|
this.on( document, 'click', '[data-action="moreExhibitions"]', this.moreExhibitions);
|
|
this.on( window, 'historychange:calendarSearch', this.stateChange );
|
|
this.setup();
|
|
},
|
|
|
|
/**
|
|
* Setup method
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setup() {
|
|
|
|
// Other setup
|
|
this._gotCoords = false;
|
|
this._offset = 0;
|
|
this._limit = 20;
|
|
this._currentSort = $('body').find('#elSortMenu_menu [aria-selected="true"]').attr('data-ipsMenuValue');
|
|
this._baseURL = this.scope.attr('action');
|
|
this._initialURL = window.location.href;
|
|
this._cancelledLookup = false;
|
|
this._searchBox = this.scope.find('input[name="location"]');
|
|
this._previousValue = this._searchBox.val();
|
|
this._originalPlaceholder = this.scope.attr('data-placeholder');
|
|
this._locationLink = this.scope.find('[data-action="useMyLocation"]');
|
|
this._cancelLocationLink = this.scope.find('[data-action="cancelLocation"]');
|
|
this._page = this.scope.closest('[data-role="eventsPage"]');
|
|
this._resultsContainer = $('body').find('[data-role="searchResults"]');
|
|
this._noResults = $('body').find('[data-role="noSearchResults"]');
|
|
this._loadMore = $('body').find('[data-action="loadMoreSearch"]');
|
|
this._noMore = $('body').find('[data-role="noMoreSearchResults"]');
|
|
this._map = null;
|
|
this._mapContainer = $('body').find('[data-role="searchResultsMap"]');
|
|
this._markers = {};
|
|
|
|
|
|
this.getInitialLocation();
|
|
|
|
|
|
// Get map ready to show
|
|
if( ips.getSetting( 'mapProvider' ) === 'google' ){
|
|
this.setupGoogle();
|
|
} else if( ips.getSetting( 'mapProvider' ) === 'mapbox' ){
|
|
this.setupMapbox();
|
|
} else {
|
|
this._mapContainer.hide(); // hide map container if no map
|
|
}
|
|
},
|
|
|
|
setupGoogle(){
|
|
this._mapReady = true;
|
|
Debug.log( this._resultsContainer.find('[data-eventid]') );
|
|
Debug.log( this._mapContainer.attr('data-markers') );
|
|
|
|
if( this._resultsContainer.find('[data-eventid]').length && this._mapContainer.attr('data-markers') ){
|
|
Debug.log('here');
|
|
try {
|
|
var markers = JSON.parse( this._mapContainer.attr('data-markers') );
|
|
Debug.log( markers );
|
|
this._updateGoogleMap( markers );
|
|
} catch (err) {
|
|
Debug.log("Invalid marker JSON");
|
|
Debug.log(err);
|
|
}
|
|
}
|
|
},
|
|
|
|
setupMapbox() {
|
|
$('head').append`
|
|
<link rel='stylesheet' type='text/css' media='all' href='https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.css'>
|
|
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/MarkerCluster.css' rel='stylesheet' />
|
|
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/MarkerCluster.Default.css' rel='stylesheet' />
|
|
<link rel='stylesheet' type='text/css' media='all' href='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/leaflet.fullscreen.css' />`;
|
|
|
|
ips.loader.get( [ 'https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.js' ] ).then(() => {
|
|
ips.loader.get( [ 'https://api.mapbox.com/mapbox.js/plugins/leaflet-markercluster/v1.0.0/leaflet.markercluster.js',
|
|
'https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/Leaflet.fullscreen.min.js' ] ).then(() => {
|
|
|
|
this._mapReady = true;
|
|
|
|
if( this._resultsContainer.find('[data-eventid]').length && this._mapContainer.attr('data-markers') ){
|
|
|
|
try {
|
|
const markers = JSON.parse( this._mapContainer.attr('data-markers') );
|
|
this._updateMapboxMap( markers );
|
|
} catch (err) {
|
|
Debug.log("Invalid marker JSON");
|
|
Debug.log(err);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
},
|
|
|
|
getInitialLocation() {
|
|
if ( ips.utils.geolocation.getGeolocationIsAllowed() ) {
|
|
|
|
ips.utils.geolocation.getCurrentPosition()
|
|
.then( coords => {
|
|
this.setCoords( coords.latitude, coords.longitude );
|
|
})
|
|
|
|
// Update useMyLocation link
|
|
this.setSearchToLocation();
|
|
this._locationLink.attr('hidden', true);
|
|
this._cancelLocationLink.removeAttr('hidden');
|
|
}
|
|
},
|
|
|
|
setCoords(lat, long) {
|
|
this.scope.prepend("<input type='hidden' name='lat' value='" + lat + "'>");
|
|
this.scope.prepend("<input type='hidden' name='lon' value='" + long + "'>");
|
|
this._gotCoords = true;
|
|
},
|
|
|
|
clearCoords() {
|
|
this.scope.find( 'input[name="lat"]' ).remove();
|
|
this.scope.find( 'input[name="lon"]' ).remove();
|
|
this._gotCoords = false;
|
|
},
|
|
|
|
moreNearMe(e) {
|
|
e.preventDefault();
|
|
|
|
// Get the lat/long from the link
|
|
var lat = $( e.currentTarget ).attr('data-lat');
|
|
var long = $( e.currentTarget ).attr('data-long');
|
|
var self = this;
|
|
|
|
this.setSearchToLocation();
|
|
this.scope.find('[name="date[start]"]').val('');
|
|
this.scope.find('[name="date[end]"]').val('');
|
|
this.scope.find('[name="show"]').val('regular');
|
|
|
|
$("html, body").animate({ scrollTop: "300px" }, function () {
|
|
self.doSearch();
|
|
});
|
|
},
|
|
|
|
moreExhibitions(e) {
|
|
e.preventDefault();
|
|
|
|
this.cancelLocation();
|
|
this.scope.find('[name="date[start]"]').val('');
|
|
this.scope.find('[name="date[end]"]').val('');
|
|
this.scope.find('[name="show"]').val('exhibitions');
|
|
|
|
$("html, body").animate({ scrollTop: "300px" }, () => {
|
|
this.doSearch();
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Submit handler for the search form
|
|
*
|
|
* @param {Event} [e] Event object
|
|
* @returns {void}
|
|
*/
|
|
doSearch (e) {
|
|
e?.preventDefault()
|
|
const url = this._getUrlFromData();
|
|
|
|
ips.utils.history.replaceState( {
|
|
controller: 'calendar.front.overview.search',
|
|
url
|
|
}, 'calendarSearch', url );
|
|
},
|
|
|
|
/**
|
|
* Build placeholder elements from a template
|
|
*
|
|
* @param {number} [count] Number to build (10 default)
|
|
* @returns {string}
|
|
*/
|
|
getPlaceholders(count) {
|
|
let events = '';
|
|
count = typeof count === 'number' ? 10 : count;
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
events += ips.templates.render('eventLoading');
|
|
}
|
|
|
|
return events;
|
|
},
|
|
|
|
/**
|
|
* Main state change event handler that responds to URL changes
|
|
*
|
|
* @param {event} e Event object
|
|
* @param {object} data Event data object
|
|
* @returns {void}
|
|
*/
|
|
stateChange() {
|
|
if (!('calendarSearch' in ips.utils.history.getState()) && this._initialURL !== window.location.href) {
|
|
return;
|
|
}
|
|
|
|
const state = ips.utils.history.getState('calendarSearch')
|
|
|
|
if (this._initialURL === state?.url) {
|
|
// If our URLs match but we have no state data, we can assume we've gone back to the initial search form, so let's reset
|
|
this.hideResults();
|
|
} else if (this._initialURL === window.location.href && state?.url === undefined) {
|
|
// If we don't have a URL, get it from our initial data
|
|
this._loadResults( this._getUrlFromData( this._initialData ) );
|
|
} else {
|
|
// Otherwise use the state url
|
|
this._loadResults( state?.url );
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Builds a search URL based on on the form values
|
|
*
|
|
* @param {Event} e Event object
|
|
* @param {object} data Event data object
|
|
* @returns {string}
|
|
*/
|
|
changeSort(e, data = e.detail) {
|
|
e.preventDefault();
|
|
this._currentSort = data.selectedItemID;
|
|
const title = $(data.menuElem).find('[data-ipsMenuValue="' + this._currentSort + '"]').text();
|
|
$('body').find('[data-role="searchOrder"]').text( title );
|
|
this.doSearch();
|
|
},
|
|
|
|
/**
|
|
* Builds a search URL based on on the form values
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
_getUrlFromData() {
|
|
const formData = this.scope.serializeArray();
|
|
const params = [];
|
|
|
|
_.each( formData, function (item){
|
|
if( $.trim( item.value ) !== '' ){
|
|
params.push( item.name + "=" + encodeURIComponent( item.value ) );
|
|
}
|
|
});
|
|
|
|
params.push("sortBy=" + this._currentSort);
|
|
|
|
if (this._baseURL.match(/\?/)) {
|
|
if (!this._baseURL.endsWith('?')) {
|
|
this._baseURL += '&';
|
|
}
|
|
} else {
|
|
this._baseURL += '?';
|
|
}
|
|
|
|
return this._baseURL + params.join('&');
|
|
},
|
|
|
|
/**
|
|
* Handles performing a new search
|
|
*
|
|
* @param {string} url URL to request
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async _loadResults(url) {
|
|
// Do we need to hide the overview stuff?
|
|
if (this._page.length) {
|
|
this._page.find('[data-role="eventsOverview"]').hide();
|
|
this._page.find('[data-role="searchResultsWrapper"]').show();
|
|
}
|
|
|
|
this._resultsContainer.removeClass('ipsHide').html( this.getPlaceholders(6) );
|
|
if (ips.getSetting('mapProvider') !== 'none') {
|
|
this._mapContainer.addClass('cEvents__searchMap--loading').show();
|
|
}
|
|
this._currentUrl = url;
|
|
|
|
const response = await ips.fetch( url );
|
|
if (response.count) {
|
|
this._resultsContainer.html( response.content );
|
|
this._noResults.addClass('ipsHide');
|
|
this._updateMap( _.extend( {}, this._markers, response.markers ) );
|
|
|
|
if( response.totalCount > ( response.count + this._offset ) ){
|
|
this._loadMore.show();
|
|
this._noMore.hide();
|
|
} else {
|
|
this._loadMore.hide();
|
|
this._noMore.hide();
|
|
}
|
|
} else {
|
|
this._resultsContainer.html('').addClass('ipsHide');
|
|
this._noResults.removeClass('ipsHide');
|
|
this._loadMore.hide();
|
|
this._noMore.hide();
|
|
this._mapContainer.hide();
|
|
}
|
|
|
|
if (response.virtual || !response.markerCount) {
|
|
this._mapContainer.hide();
|
|
}
|
|
|
|
$( document ).trigger('contentChange', [ this._resultsContainer ]);
|
|
},
|
|
|
|
_updateMap(markers){
|
|
if (ips.getSetting( 'mapProvider' ) === 'google') {
|
|
this._updateGoogleMap( markers );
|
|
} else if (ips.getSetting( 'mapProvider' ) === 'mapbox') {
|
|
this._updateMapboxMap( markers );
|
|
} else {
|
|
this._mapContainer.hide(); // we really don't need it.
|
|
}
|
|
},
|
|
|
|
_updateGoogleMap(markers){
|
|
|
|
if( !this._map ){
|
|
this._map = new window.google.maps.Map( document.querySelector( '[data-role="searchResultsMap"]' ) );
|
|
this._mapMarkers = [];
|
|
}
|
|
|
|
this._mapContainer.removeClass('cEvents__searchMap--loading');
|
|
|
|
/* Clear existing markers before we rebuild */
|
|
if( this._mapMarkers.length ){
|
|
for ( let marker of Object.values(this._mapMarkers) ) {
|
|
marker.setMap(null);
|
|
}
|
|
this._mapMarkers = [];
|
|
}
|
|
|
|
const bounds = new google.maps.LatLngBounds();
|
|
for ( let marker of Object.values(markers) ) {
|
|
let mapMarker = new window.google.maps.Marker({
|
|
position: {lat: marker.lat, lng: marker.long},
|
|
map: this._map,
|
|
title: marker.title
|
|
});
|
|
this._mapMarkers.push( mapMarker );
|
|
|
|
const coords = new google.maps.LatLng(marker.lat, marker.long);
|
|
if( !( bounds.contains( coords ) ) ){
|
|
bounds.extend( coords );
|
|
}
|
|
}
|
|
|
|
/* If we have only one marker in here, fitting to the bounds zooms in way too much */
|
|
if( this._mapMarkers.length === 1 ){
|
|
this._map.setZoom(15);
|
|
this._map.setCenter(bounds.getCenter());
|
|
} else {
|
|
this._map.fitBounds( bounds );
|
|
}
|
|
this._mapContainer.show();
|
|
},
|
|
|
|
_updateMapboxMap(markers) {
|
|
if (!this._map) {
|
|
L.mapbox.accessToken = ips.getSetting('mapApiKey');
|
|
this._map = L.mapbox
|
|
.map( this._mapContainer.get(0) )
|
|
.addLayer(L.mapbox.styleLayer('mapbox://styles/mapbox/streets-v11'));
|
|
|
|
// Map prefs
|
|
this._map.zoomControl = false;
|
|
this._map.minZoom = 2;
|
|
this._map.dragging = false;
|
|
this._map.zoomControl = false;
|
|
|
|
this._markersGroup = new L.featureGroup([]);
|
|
this._markersGroup.addTo( this._map );
|
|
}
|
|
|
|
this._mapContainer.removeClass('cEvents__searchMap--loading');
|
|
this._markersGroup.clearLayers(); // Remove all existing markers
|
|
|
|
for (let id in markers) {
|
|
const marker = L.marker([markers[id].lat, markers[id].long], {
|
|
title: markers[id].title,
|
|
draggable: false,
|
|
eventId: parseInt(id)
|
|
});
|
|
|
|
this._markersGroup.addLayer( marker );
|
|
|
|
// Build info popup for this marker
|
|
marker.on('click', _.bind( this._markerClick, this ) );
|
|
}
|
|
|
|
this._mapContainer.show();
|
|
this._map.fitBounds(this._markersGroup.getBounds(), { maxZoom: 5 });
|
|
},
|
|
|
|
_markerClick(e) {
|
|
const targetEvent = e.target.options.eventId;
|
|
|
|
// Find that event in our listing
|
|
const eventBlock = this._resultsContainer.find('[data-eventId="' + targetEvent + '"]');
|
|
|
|
// Get position
|
|
const topPos = eventBlock.offset().top;
|
|
|
|
// Scroll to it
|
|
$('html, body').animate({ scrollTop: topPos }, function () {
|
|
eventBlock.css({ transform: 'scale(1.1)' });
|
|
|
|
setTimeout( function () {
|
|
eventBlock.css({ transform: 'scale(1)' });
|
|
}, 2000);
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Handles loading more results into the current search
|
|
*
|
|
* @param {Event} e Event object
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async loadMore(e) {
|
|
e.preventDefault();
|
|
|
|
const placeholders = this.getPlaceholders(2);
|
|
this._resultsContainer.append( placeholders );
|
|
this._loadMore.prop('disabled', true);
|
|
|
|
const currentCount = this._resultsContainer.find('[data-eventid]').length;
|
|
|
|
const response = await ips.fetch( this._currentUrl + "&offset=" + currentCount + "&limit=" + this._limit);
|
|
|
|
this._resultsContainer.find('.ipsData__item--loading').remove();
|
|
this._resultsContainer.append( response.content );
|
|
this._updateMap( response.markers );
|
|
this._loadMore.prop('disabled', false);
|
|
|
|
if (this._resultsContainer.find('[data-eventid]').length >= response.totalCount) {
|
|
this._loadMore.hide();
|
|
this._noMore.show();
|
|
} else {
|
|
this._loadMore.show();
|
|
this._noMore.hide();
|
|
}
|
|
|
|
$( document ).trigger('contentChange', [ this._resultsContainer ]);
|
|
},
|
|
|
|
/**
|
|
* Remove current location as the search term
|
|
*
|
|
* @param {Event} [e] Event object
|
|
* @returns {void}
|
|
*/
|
|
cancelLocation(e) {
|
|
e?.preventDefault()
|
|
ips.utils.geolocation.setGeolocationIsAllowed(ips.utils.geolocation.permissions.DENIED);
|
|
|
|
this._cancelledLookup = true;
|
|
this._searchBox.val( this._previousValue ).attr('placeholder', this._originalPlaceholder).prop('disabled', false).removeClass('ipsField_loading');
|
|
this._locationLink.removeAttr('hidden');
|
|
this._cancelLocationLink.attr('hidden', true);
|
|
|
|
this.scope.find('[name="searchNearLocation"]').remove();
|
|
},
|
|
|
|
/**
|
|
* Fetch current location and use it as the current search param
|
|
*
|
|
* @param {Event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
useMyLocation(e) {
|
|
e.preventDefault();
|
|
|
|
this._cancelledLookup = false;
|
|
this._searchBox.val('').attr('placeholder', ips.getString('event_finding_location')).prop('disabled', true).addClass('ipsField_loading');
|
|
this._locationLink.attr('hidden', true);
|
|
this._cancelLocationLink.removeAttr('hidden');
|
|
|
|
const afterCoords = () => {
|
|
if( this._cancelledLookup ){
|
|
this._cancelledLookup = false;
|
|
return;
|
|
}
|
|
|
|
this.setSearchToLocation();
|
|
this._cancelledLookup = false;
|
|
};
|
|
|
|
if( this._gotCoords ){
|
|
afterCoords()
|
|
} else {
|
|
ips.utils.geolocation.getCurrentPosition()
|
|
.then(coords => {
|
|
this.setCoords(coords.latitude, coords.longitude);
|
|
this.setSearchToLocation();
|
|
});
|
|
}
|
|
},
|
|
|
|
setSearchToLocation() {
|
|
this._searchBox.val('').attr('placeholder', ips.getString('event_your_current_location')).prop('disabled', true).removeClass('ipsField_loading');
|
|
this.scope.prepend("<input type='hidden' name='searchNearLocation' value='1'>");
|
|
},
|
|
|
|
/**
|
|
* Cancel searching and show the overview page again
|
|
*
|
|
* @param {Event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
backToOverview(e) {
|
|
if (!this._page.length) {
|
|
return;
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
ips.utils.history.replaceState(
|
|
{
|
|
controller: 'calendar.front.overview.search',
|
|
url: this._initialURL
|
|
},
|
|
'calendarSearch',
|
|
this._initialURL
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Hide the search results panel
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
hideResults() {
|
|
this._page.find('[data-role="eventsOverview"]').show();
|
|
this._page.find('[data-role="searchResultsWrapper"]').hide();
|
|
}
|
|
});
|
|
}(jQuery, _));
|
|
]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/submit" javascript_name="ips.submit.dates.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000100"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.submit.dates.js - Helper for date selection enhancements
|
|
*
|
|
* Author: Rikki Tissier
|
|
*/
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.submit.dates', {
|
|
|
|
initialize: function () {
|
|
this._hasFocusedEventEnd = false;
|
|
|
|
this.on( 'click', '[data-action="updateTimezone"]', this.updateTimezone );
|
|
|
|
// Monitor focus in recurring event input fields and select appropriate radio button
|
|
this.on( 'focus', 'input[name="repeat_end_occurrences"]', function(){ $('#event_repeat_end_afterx').prop('checked', true); } );
|
|
this.on( 'focus', 'input[name="repeat_end_date"]', function(){ $('#event_repeat_end_ondate').prop('checked', true); } );
|
|
|
|
this.on( 'change', 'input, select', this.checkForSummaryChange );
|
|
this.on( 'change', '#check_single_day, #check_all_day', this.toggleFields );
|
|
this.on( 'change', '#check_no_end_time', this.toggleEndtimeFields );
|
|
this.on( 'click', '#elRecurRemove', this.disableRecurring );
|
|
this.on( 'change', 'input[name="event_dates[start_date]"]', this.setEndDateOnStartChange );
|
|
this.on( 'change', '#event_end_date', this.setHasFocusedEventOnEndChange );
|
|
|
|
this.on( 'click', '[data-action="updateRepeat"]', this.finishRepeat );
|
|
|
|
this._checkAndSetEventEndState();
|
|
this.evaluateRecurringOptions();
|
|
|
|
this.setup();
|
|
},
|
|
|
|
/**
|
|
* On page load check to see what the current state of the end date is. If its set lets just go ahead and ignore any start date changes
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
_checkAndSetEventEndState: function() {
|
|
var eventEndDate = $("#event_end_date");
|
|
var date = eventEndDate.val();
|
|
|
|
if (!this._hasFocusedEventEnd && this._isValidEndDate(date)) {
|
|
this._hasFocusedEventEnd = true;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Is the date passed in a valid date?
|
|
*
|
|
* @param {date} date Date to check
|
|
* @returns {boolean}
|
|
*/
|
|
_isValidEndDate: function(date) {
|
|
|
|
var tempDate = new Date(date);
|
|
|
|
if(!isNaN(tempDate.getDate())) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* If the end field has changed from input go ahead and ignore any start date changes
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setHasFocusedEventOnEndChange: function() {
|
|
this._hasFocusedEventEnd = true;
|
|
|
|
this.evaluateRecurringOptions();
|
|
},
|
|
|
|
/**
|
|
* Event handler, handles changes to the start date
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setEndDateOnStartChange: function() {
|
|
var isSameDay = $("#check_single_day").is(":checked");
|
|
var eventStartDate = $('input[name="event_dates[start_date]');
|
|
var eventEndDate = $("#event_end_date");
|
|
|
|
if(!isSameDay && !this._hasFocusedEventEnd) {
|
|
if( ips.utils.time.supportsHTMLDate() ) {
|
|
eventEndDate.val(eventStartDate.val());
|
|
}
|
|
}
|
|
},
|
|
|
|
/**
|
|
* When an end date is set, adjust the available recurrence options
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
evaluateRecurringOptions: function() {
|
|
var startDate = $("#event_start_date").val();
|
|
var endDate = $("#event_end_date").val();
|
|
|
|
if (!this._isValidEndDate(endDate) || $('#check_single_day').prop('checked') ) {
|
|
// If the summary isn't visible, make sure the checkbox row is
|
|
if( !$('#elRepeatRow_shown').is(':visible') )
|
|
{
|
|
$('#elRepeatRow_hidden').show();
|
|
}
|
|
|
|
$('#elSelect_event_repeats').find('option').prop( 'disabled', false );
|
|
|
|
if( $('#elRepeatOn_back').length )
|
|
{
|
|
$('#elRepeatOn_back').attr( 'id', 'elRepeatOn' );
|
|
}
|
|
|
|
if( $('#elSelect_event_repeats').val() == 'weekly' )
|
|
{
|
|
$('#elRepeatOn').show();
|
|
}
|
|
|
|
this._updateSummary();
|
|
|
|
return;
|
|
}
|
|
|
|
startDate = new Date( startDate );
|
|
endDate = new Date( endDate );
|
|
|
|
var dayDifference = parseInt( ( endDate.getTime() - startDate.getTime() ) / ( 24 * 3600 * 1000 ) );
|
|
|
|
var currentlySelected = $('#elSelect_event_repeats').val();
|
|
|
|
// If the event spans more than one day, remove "daily" as a recurrence option and hide the "day of the week" options for monthly
|
|
if( dayDifference > 1 ) {
|
|
$('#elSelect_event_repeats').find('option[value="daily"]').prop( 'disabled', true );
|
|
$('#elRepeatOn').hide();
|
|
$('#elRepeatOn').attr( 'id', 'elRepeatOn_back' );
|
|
|
|
if( !currentlySelected || currentlySelected == 'daily' )
|
|
{
|
|
$('#elSelect_event_repeats').find('option[value="daily"]').prop( 'selected', false );
|
|
$('#elSelect_event_repeats').find('option[value="weekly"]').prop( 'selected', true );
|
|
currentlySelected = 'weekly';
|
|
}
|
|
} else {
|
|
$('#elSelect_event_repeats').find('option[value="daily"]').prop( 'disabled', false );
|
|
|
|
if( $('#elRepeatOn_back').length )
|
|
{
|
|
$('#elRepeatOn_back').attr( 'id', 'elRepeatOn' );
|
|
}
|
|
|
|
if( $('#elSelect_event_repeats').val() == 'weekly' )
|
|
{
|
|
$('#elRepeatOn').show();
|
|
}
|
|
}
|
|
|
|
// If the event spans more than one week, remove "daily" and "weekly" as recurrence options
|
|
if( dayDifference > 7 ) {
|
|
$('#elSelect_event_repeats').find('option[value="weekly"]').prop( 'disabled', true );
|
|
|
|
if( !currentlySelected || currentlySelected == 'weekly' )
|
|
{
|
|
$('#elSelect_event_repeats').find('option[value="weekly"]').prop( 'selected', false );
|
|
$('#elSelect_event_repeats').find('option[value="monthly"]').prop( 'selected', true );
|
|
currentlySelected = 'monthly';
|
|
}
|
|
} else {
|
|
$('#elSelect_event_repeats').find('option[value="weekly"]').prop( 'disabled', false );
|
|
}
|
|
|
|
// If the event spans more than one month, remove "daily", "weekly" and "monthly" recurrence options
|
|
if(
|
|
// If there's more than one month between the dates, then we block
|
|
( endDate.getMonth() - startDate.getMonth() + ( 12 * ( endDate.getFullYear() - startDate.getFullYear() ) ) > 1 )
|
|
||
|
|
// Else if there is one month between the dates, then we check the end date is greater than the start date
|
|
(
|
|
endDate.getMonth() - startDate.getMonth() + ( 12 * ( endDate.getFullYear() - startDate.getFullYear() ) ) == 1 && endDate.getDate() > startDate.getDate()
|
|
)
|
|
) {
|
|
$('#elSelect_event_repeats').find('option[value="monthly"]').prop( 'disabled', true );
|
|
|
|
if( !currentlySelected || currentlySelected == 'monthly' )
|
|
{
|
|
$('#elSelect_event_repeats').find('option[value="monthly"]').prop( 'selected', false );
|
|
$('#elSelect_event_repeats').find('option[value="yearly"]').prop( 'selected', true );
|
|
currentlySelected = 'yearly';
|
|
}
|
|
} else {
|
|
$('#elSelect_event_repeats').find('option[value="monthly"]').prop( 'disabled', false );
|
|
}
|
|
|
|
// If the event spans more than one year, remove ability for event to repeat entirely
|
|
if( dayDifference > 365 )
|
|
{
|
|
$('#elSelect_event_repeats').find('option[value="yearly"]').prop( 'selected', false );
|
|
this.disableRecurring();
|
|
$('#elRepeatRow_hidden').hide();
|
|
}
|
|
else
|
|
{
|
|
$('#elRepeatRow_hidden').show();
|
|
}
|
|
|
|
// And update the summary in case anything changed
|
|
this._updateSummary();
|
|
},
|
|
|
|
/**
|
|
* Finish setting the options
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
finishRepeat: function () {
|
|
this._updateSummary();
|
|
},
|
|
|
|
/**
|
|
* Setup method
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setup: function () {
|
|
this._updateSummary();
|
|
this.toggleFields();
|
|
this.updateTimezone();
|
|
},
|
|
|
|
/**
|
|
* Toggle the end time enabled/disabled status
|
|
*
|
|
* @param {event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
toggleEndtimeFields: function(e) {
|
|
if( this.scope.find('#check_no_end_time').is(':checked') )
|
|
{
|
|
this.scope.find('#end_time').prop('disabled', true);
|
|
}
|
|
else
|
|
{
|
|
this.scope.find('#end_time').prop('disabled', false);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Manual toggle functionality for the Single/All Day checkboxes
|
|
*
|
|
* @param {event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
toggleFields: function (e) {
|
|
this.toggleEndtimeFields();
|
|
|
|
var singleDay = this.scope.find('#check_single_day');
|
|
var allDay = this.scope.find('#check_all_day');
|
|
var self = this;
|
|
|
|
var toggles = {
|
|
start_time_wrap: true,
|
|
end_time_wrap: true,
|
|
event_end_date_wrap: true,
|
|
elDateGrid_arrow: true,
|
|
elDateGrid_end: true,
|
|
end_date_controls: true
|
|
};
|
|
|
|
// Single day, not all day
|
|
if( singleDay.is(':checked') && !allDay.is(':checked') ){
|
|
toggles.event_end_date_wrap = false;
|
|
// Single day, all day
|
|
} else if( singleDay.is(':checked') && allDay.is(':checked') ){
|
|
toggles.elDateGrid_arrow = false;
|
|
toggles.elDateGrid_end = false;
|
|
toggles.start_time_wrap = false;
|
|
// Multiple days, all day
|
|
} else if( !singleDay.is(':checked') && allDay.is(':checked') ){
|
|
toggles.start_time_wrap = false;
|
|
toggles.end_time_wrap = false;
|
|
toggles.end_date_controls = false;
|
|
}
|
|
// Multiple days, not all day
|
|
else
|
|
{
|
|
toggles.end_date_controls = false;
|
|
this.scope.find('#end_time').prop('disabled', false);
|
|
}
|
|
|
|
// Hide appropriate elements
|
|
_.each( toggles, function (val, key) {
|
|
self.scope.find( '#' + key ).toggle( val );
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Monitor changes to the repeat options and update the summary
|
|
*
|
|
* @param {event} e Event object
|
|
* @param {object} data Event data object
|
|
* @returns {void}
|
|
*/
|
|
checkForSummaryChange: function (e) {
|
|
if( $( e.currentTarget ).attr('name').startsWith('event_dates[') ){
|
|
this._updateSummary();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Updates the timezone value both in the hidden field and in the display to the end user
|
|
*
|
|
* @param {event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
updateTimezone: function (e) {
|
|
// Update displayed timezone
|
|
this.scope.find('[data-role="timezone_display"]').text( $('#event_timezone option:selected').data('abbreviated') );
|
|
},
|
|
|
|
/**
|
|
* Removes the Repeat summary and unchecks the Repeat checkbox
|
|
*
|
|
* @param {event} e Event object
|
|
* @param {object} data Event data object
|
|
* @returns {void}
|
|
*/
|
|
disableRecurring: function (e) {
|
|
this._updateSummary();
|
|
},
|
|
|
|
/**
|
|
* Update the recurring string
|
|
*
|
|
* @param {event} e Event object
|
|
* @param {object} data Event data object
|
|
* @returns {void}
|
|
*/
|
|
_updateSummary: function () {
|
|
var summary = this.scope.find('[data-role="recurringSummary"]');
|
|
|
|
// Update repeating text
|
|
if( this.scope.find('#elRepeatCb').is(':checked') ){
|
|
summary.text( this._getSummary() );
|
|
this.scope.find('#elRepeatRow_hidden').hide();
|
|
this.scope.find('#elRepeatRow_shown').show();
|
|
} else {
|
|
summary.html( "<em class='i-color_soft'>" + ips.getString('doesnt_repeat') + "</em>" );
|
|
this.scope.find('#elRepeatRow_hidden').show();
|
|
this.scope.find('#elRepeatRow_shown').hide();
|
|
}
|
|
|
|
// Update the dates
|
|
this.scope.find('[data-role="dateSummary"]').html( this._dateSummary() );
|
|
},
|
|
|
|
/**
|
|
* Builds a summary of the selected dates/times
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
_dateSummary: function () {
|
|
// Build start date
|
|
var startDate = ips.utils.time.getDateFromInput( this.scope.find('input[name="event_dates[start_date]"]') );
|
|
var singleDay = this.scope.find('#check_single_day');
|
|
var allDay = this.scope.find('#check_all_day');
|
|
|
|
// If there's no start time, then abandon showing any summary for now
|
|
if( !ips.utils.time.isValidDateObj( startDate ) || startDate.getFullYear() < 1900 ) {
|
|
return '';
|
|
}
|
|
|
|
ips.utils.time.removeTimezone( startDate );
|
|
|
|
var startDateString = ips.utils.time.localeDateString( startDate, { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' } );
|
|
var startTime = this._getTime( this.scope.find('input[name="event_dates[start_time]"]').val() );
|
|
var endTime = this._getTime( this.scope.find('input[name="event_dates[end_time]"]').val() );
|
|
var endDate = ips.utils.time.getDateFromInput( this.scope.find('input[name="event_dates[end_date]"]') );
|
|
var endDateString = '';
|
|
|
|
// If we have a valid end date...
|
|
if( !singleDay.is(':checked') && ips.utils.time.isValidDateObj( endDate ) ){
|
|
ips.utils.time.removeTimezone( endDate );
|
|
endDateString = ips.utils.time.localeDateString( endDate, { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric', timeZone: 'UTC' } );
|
|
}
|
|
|
|
// Now build strings
|
|
var finalString = '';
|
|
|
|
if( singleDay.is(':checked') && !allDay.is(':checked') ){
|
|
if( this.scope.find('#check_no_end_time').is(':checked') )
|
|
{
|
|
finalString = ips.getString( 'single_not_allday_noendtime', { startDate: startDateString, startTime: startTime } );
|
|
}
|
|
else
|
|
{
|
|
finalString = ips.getString( 'single_not_allday', { startDate: startDateString, startTime: startTime, endTime: endTime } );
|
|
}
|
|
} else if ( ( !singleDay.is(':checked') && !allDay.is(':checked') ) && endDateString && startTime && endTime ) {
|
|
finalString = ips.getString( 'not_single_not_allday', { startDate: startDateString, endDate: endDateString, startTime: startTime, endTime: endTime } );
|
|
} else if( !singleDay.is(':checked') && allDay.is(':checked') && endDateString ) {
|
|
finalString = ips.getString( 'not_single_allday', { startDate: startDateString, endDate: endDateString } );
|
|
} else {
|
|
finalString = ips.getString( 'single_allday', { startDate: startDateString } );
|
|
}
|
|
|
|
return finalString;
|
|
},
|
|
|
|
/**
|
|
* Returns the given time, or a placeholder string if empty
|
|
*
|
|
* @param {string} time Time string
|
|
* @returns {string}
|
|
*/
|
|
_getTime: function (time) {
|
|
if( !time ){
|
|
return "<em class='i-color_soft i-font-weight_normal i-opacity_4'>" + ips.getString('select_time') + "</em>";
|
|
}
|
|
|
|
var date = new Date('1970-01-01T' + time + 'Z');
|
|
var time = date.toLocaleTimeString( $('html').attr('lang'), { hour: '2-digit', minute: '2-digit', timeZone: 'UTC' } );
|
|
|
|
return time;
|
|
},
|
|
|
|
/**
|
|
* Returns the summary string for recurring events
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
_getSummary: function () {
|
|
var type = this.scope.find('#elSelect_event_repeats').val();
|
|
var intervalString = '';
|
|
var endString = '';
|
|
|
|
// Build the 'interval' string
|
|
switch( type ){
|
|
case 'daily':
|
|
case 'monthly':
|
|
case 'yearly':
|
|
intervalString = this._buildString( type );
|
|
break;
|
|
case 'weekly':
|
|
intervalString = this._buildWeekly();
|
|
break;
|
|
}
|
|
|
|
// Build the 'end after' string
|
|
if( this.scope.find('#event_repeat_end_afterx').is(':checked') ){
|
|
var occurrences = parseInt( this.scope.find('input[name="event_dates[repeat_end_occurrences]"]').val() );
|
|
|
|
if( _.isNumber( occurrences ) && !_.isNaN( occurrences ) ){
|
|
endString = ips.pluralize( ips.getString( 'x_times' ), occurrences );
|
|
}
|
|
} else if( this.scope.find('#event_repeat_end_ondate').is(':checked') ){
|
|
var dateObj = ips.utils.time.getDateFromInput( this.scope.find('input[name="event_dates[repeat_end_date]"]') );
|
|
|
|
if( ips.utils.time.isValidDateObj( dateObj ) && dateObj.getFullYear() > 1900 ){ // > 1900 just so it doesn't start updating on year 19 etc.
|
|
ips.utils.time.removeTimezone( dateObj );
|
|
endString = ips.getString('until', { date: ips.utils.time.localeDateString( dateObj, { weekday: 'short', month: 'short', day: 'numeric', year: 'numeric' } ) } );
|
|
}
|
|
}
|
|
|
|
// Put it together
|
|
if( endString ){
|
|
return ips.getString( 'with_end', { interval: intervalString, endAfter: endString } );
|
|
} else {
|
|
return intervalString;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Builds a summary string for daily, monthly and yearly repeats
|
|
*
|
|
* @param {string} type The type of repeat
|
|
* @returns {string}
|
|
*/
|
|
_buildString: function ( type ) {
|
|
var val = parseInt( this.scope.find('#elSelect_event_repeat_freq').val() ) || 1;
|
|
return ips.pluralize( ips.getString( 'every_x', { period: ips.pluralize( ips.getString( 'x_' + type ), val ) } ), val );
|
|
},
|
|
|
|
/**
|
|
* Builds a summary string for weekly repeats
|
|
*
|
|
* @returns {string}
|
|
*/
|
|
_buildWeekly: function () {
|
|
var selectedDays = this.scope.find('[data-iCal]:checked');
|
|
var val = parseInt( this.scope.find('#elSelect_event_repeat_freq').val() ) || 1;
|
|
var weekString = '';
|
|
|
|
weekString = ips.pluralize( ips.getString( 'x_weekly' ), val );
|
|
|
|
// If no days are selected, we can bypass and finish now
|
|
if( !selectedDays.length ){
|
|
return weekString;
|
|
}
|
|
|
|
// Get full days
|
|
var fullDays = _.map( selectedDays, function (day, key) {
|
|
return ips.getString( $( day ).attr('data-iCal') );
|
|
});
|
|
|
|
// Build string
|
|
var dayString = '';
|
|
|
|
if( fullDays.length === 1 ){
|
|
dayString = ips.getString( 'one_day', { first: fullDays[0] } );
|
|
} else {
|
|
dayString = ips.getString( 'multiple_day', { days: fullDays.slice(0, -1).join(', '), last: fullDays[ fullDays.length - 1 ] });
|
|
}
|
|
|
|
return ips.getString( 'week_string', { week: weekString, days: dayString } );
|
|
}
|
|
});
|
|
}(jQuery, _));]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/venue" javascript_name="ips.venue.main.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000200"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.venue.main.js - Venue main browsing controller
|
|
*
|
|
*/
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.venue.main', {
|
|
|
|
_ajaxObj: null,
|
|
|
|
initialize() {
|
|
this.on( 'click', '[data-action="changeView"]', this.changeView );
|
|
this.on( window, 'historychange:venueView', this.stateChange );
|
|
this.setup();
|
|
},
|
|
|
|
/**
|
|
* Controller setup method
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setup() {
|
|
ips.utils.history.pushState( { controller: 'venueView' }, 'venueView', window.location.href );
|
|
},
|
|
|
|
/**
|
|
* Changes the calendar view dynamically
|
|
*
|
|
* @param {Event} e Event object
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
changeView(e) {
|
|
e.preventDefault();
|
|
|
|
// Load the url via ajax instead
|
|
ips.utils.history.pushState({ controller: 'venueView' }, 'venueView', $( e.currentTarget ).attr('href'));
|
|
document.title = $( e.currentTarget ).attr('title');
|
|
},
|
|
|
|
/**
|
|
* Event handler for history state changes
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
stateChange() {
|
|
const data = ips.utils.history.getState('venueView') || {},
|
|
url = window.location.href
|
|
|
|
if (data.controller !== 'venueView') {
|
|
return;
|
|
}
|
|
|
|
// Track page view
|
|
ips.utils.analytics.trackPageView(url);
|
|
|
|
this._updateView(url)
|
|
},
|
|
|
|
/**
|
|
* Loads a new view
|
|
*
|
|
* @param {string} url URL to load
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
_updateView(url) {
|
|
if (this._ajaxObj && _.isFunction( this._ajaxObj.abort ) ){
|
|
this._ajaxObj.abort();
|
|
}
|
|
|
|
this._setLoading( true );
|
|
|
|
this._ajaxObj = ips.getAjax()( url, {
|
|
showLoading: true
|
|
} )
|
|
.done(response => {
|
|
console.log( response );
|
|
this.scope.html( response );
|
|
$( document ).trigger( 'contentChange', [ self.scope ] );
|
|
})
|
|
.always(() => {
|
|
this._setLoading( false );
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Toggles the loading state on the view
|
|
*
|
|
* @param {boolean} state Enable the loading state?
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
_setLoading(state) {
|
|
this.scope.animate(
|
|
{
|
|
opacity: state ? "0.6" : "1"
|
|
},
|
|
"fast"
|
|
);
|
|
}
|
|
});
|
|
}(jQuery, _));]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/view" javascript_name="ips.view.reminderButton.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000150"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.calendar.reminderButton.js - Controller for event reminder button
|
|
*
|
|
* Author: Andrew Millne
|
|
*/
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.view.reminderButton', {
|
|
|
|
initialize: function () {
|
|
this.setup();
|
|
this.on( document, 'reminderItem', this.reminderItemChange );
|
|
},
|
|
|
|
setup: function () {
|
|
this._id = this.scope.attr('data-reminderID');
|
|
this._button = this.scope.find('[data-role="reminderButton"]');
|
|
},
|
|
|
|
/**
|
|
* Responds to events indicating the reminder status has changed
|
|
*
|
|
* @param {event} e Event object
|
|
* @param {object} data Event data object
|
|
* @returns {void}
|
|
*/
|
|
reminderItemChange: function (e, data) {
|
|
this._reloadButton();
|
|
},
|
|
|
|
/**
|
|
* Gets a new reminder button from the server and replaces the current one with the response
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
_reloadButton: function () {
|
|
// Show button as loading
|
|
this._button.addClass('i-opacity_3');
|
|
|
|
var self = this;
|
|
var pos = ips.utils.position.getElemPosition( this._button );
|
|
var dims = ips.utils.position.getElemDims( this._button );
|
|
|
|
this.scope.append( ips.templates.render('calendar.reminder.loading') );
|
|
|
|
// Adjust sizing
|
|
this.scope
|
|
.css({
|
|
position: 'relative'
|
|
})
|
|
.find('.ipsLoading')
|
|
.css({
|
|
width: dims.outerWidth + 'px',
|
|
height: dims.outerHeight + 'px',
|
|
top: "0",
|
|
left: "0",
|
|
position: 'absolute',
|
|
zIndex: ips.ui.zIndex()
|
|
});
|
|
|
|
// Load new contents
|
|
ips.getAjax()( ips.getSetting('baseURL') + 'index.php?app=calendar&module=calendar&controller=event&do=reminderButton', {
|
|
data: _.extend({
|
|
id: this._id
|
|
}, ( this.scope.attr('data-buttonType') ) ? { button_type: this.scope.attr('data-buttonType') } : {} )
|
|
})
|
|
.done( function (response) {
|
|
self.scope.html( response );
|
|
$( document ).trigger( 'contentChange', [ self.scope ] );
|
|
})
|
|
.fail( function () {
|
|
self._button.removeClass('i-opacity_3');
|
|
})
|
|
.always( function () {
|
|
self.scope.find('.ipsLoading').remove();
|
|
});
|
|
}
|
|
});
|
|
}(jQuery, _));]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="controllers/view" javascript_name="ips.view.reminderForm.js" javascript_type="controller" javascript_version="5001403" javascript_position="1000150">/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*
|
|
* ips.calendar.reminderButton.js - Controller for reminder button
|
|
*
|
|
* Author: Andrew Millne
|
|
*/
|
|
;( function($, _, undefined){
|
|
"use strict";
|
|
|
|
ips.controller.register('calendar.front.view.reminderForm', {
|
|
|
|
initialize: function () {
|
|
this.on( 'submit', this.submitForm );
|
|
this.on( 'click', '[data-action="removereminder"]', this.removereminder );
|
|
this.setup();
|
|
},
|
|
|
|
/**
|
|
* Setup method
|
|
*
|
|
* @returns {void}
|
|
*/
|
|
setup: function () {
|
|
},
|
|
|
|
/**
|
|
* Event handler for removing reminder
|
|
*
|
|
* @param {event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
removereminder: function (e) {
|
|
e.preventDefault();
|
|
this._doRemindAction( $( e.currentTarget ).attr('href'), {}, true );
|
|
},
|
|
|
|
/**
|
|
* Event handler for submitting the reminder form
|
|
*
|
|
* @param {event} e Event object
|
|
* @returns {void}
|
|
*/
|
|
submitForm: function (e) {
|
|
e.preventDefault();
|
|
this._doRemindAction( this.scope.attr('action'), this.scope.serialize(), false );
|
|
},
|
|
|
|
/**
|
|
* Performs an ajax action.
|
|
*
|
|
* @param {string} url URL to call
|
|
* @param {object} data Object of data to include in the request
|
|
* @returns {void}
|
|
*/
|
|
_doRemindAction: function (url, data, removereminder ) {
|
|
var self = this;
|
|
var dims = ips.utils.position.getElemDims( this.scope.parent('div') );
|
|
|
|
// Set it to loading
|
|
this.scope
|
|
.hide()
|
|
.parent('div')
|
|
.css({
|
|
width: dims.outerWidth + 'px',
|
|
height: dims.outerHeight + 'px'
|
|
})
|
|
.addClass('ipsLoading');
|
|
|
|
// Update reminder preference via ajax
|
|
ips.getAjax()( url, {
|
|
data: data,
|
|
type: 'post'
|
|
})
|
|
.done( function (response, status, jqXHR) {
|
|
|
|
if( jqXHR.getAllResponseHeaders().indexOf('X-IPS-FormError: true') !== -1 || jqXHR.getAllResponseHeaders().indexOf('X-IPS-FormNoSubmit: true') !== -1 || jqXHR.getAllResponseHeaders().indexOf('x-ips-formerror: true') !== -1 || jqXHR.getAllResponseHeaders().indexOf('x-ips-formnosubmit: true') !== -1 ){
|
|
self.scope
|
|
.show()
|
|
.html( response )
|
|
.parent('div')
|
|
.removeClass('ipsLoading')
|
|
.css({
|
|
width: 'auto',
|
|
height: 'auto'
|
|
});
|
|
} else {
|
|
// Success, so trigger event to update button
|
|
self.trigger('reminderItem');
|
|
if( removereminder ) {
|
|
ips.ui.flashMsg.show(ips.getString('event_reminder_removed'));
|
|
}
|
|
else {
|
|
ips.ui.flashMsg.show(ips.getString('event_reminder_added'));
|
|
}
|
|
|
|
self.scope.parents('.ipsHovercard').remove();
|
|
}
|
|
})
|
|
.fail( function (jqXHR, textStatus, errorThrown) {
|
|
window.location = url;
|
|
})
|
|
.always( function () {
|
|
// If we're in a hovercard, remove it
|
|
});
|
|
}
|
|
});
|
|
}(jQuery, _));
|
|
</file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="templates" javascript_name="ips.calendar.templates.js" javascript_type="framework" javascript_version="5001403" javascript_position="1000050"><![CDATA[/**
|
|
* Invision Community
|
|
* (c) Invision Power Services, Inc. - https://www.invisioncommunity.com
|
|
*/
|
|
|
|
/* REMINDER BUTTON LOADING */
|
|
ips.templates.set('calendar.reminder.loading', " \
|
|
<div class='ipsLoading ipsLoading--tiny'></div>\
|
|
");]]></file>
|
|
<file javascript_app="calendar" javascript_location="front" javascript_path="templates" javascript_name="ips.templates.overview.js" javascript_type="template" javascript_version="5001403" javascript_position="1000050"><![CDATA[ips.templates.set("eventLoading", `
|
|
<li class='ipsData__item ipsData__item--loading'>
|
|
<div class="ipsData__image" aria-hidden="true"></div>
|
|
<div class="ipsData__content">
|
|
<div class="ipsData__main">
|
|
<div class="ipsData__title"></div>
|
|
<div class="ipsData__desc"></div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
`);
|
|
|
|
ips.templates.set("nearMe", `
|
|
<i-data>
|
|
<ul class='ipsData ipsData--grid ipsData--events-list ipsEventList ipsEventList--nearMe'>
|
|
<li class="ipsData__item ipsEventsNearMe__map"><div class='cEvents__skeleton cEvents__skeleton--map' id='map'></div></li>
|
|
{{{events}}}
|
|
</ul>
|
|
</i-data>
|
|
`);]]></file>
|
|
<order app="global" path="/dev/js//framework/">templates
|
|
common/ips.loader.js
|
|
common/ui
|
|
common/utils
|
|
common
|
|
controllers</order>
|
|
<order app="global" path="/dev/js//library/">underscore
|
|
jquery
|
|
mustache
|
|
Debug.js
|
|
app.js</order>
|
|
<order app="global" path="/dev/js//library//jquery">jquery.js
|
|
jquery-migrate.js</order>
|
|
<order app="global" path="/dev/js//library//linkify">linkify.min.js
|
|
linkify-jquery.min.js</order>
|
|
</javascript>
|