Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow creation of meeting details pages #418

Merged
merged 13 commits into from
Aug 12, 2023
45 changes: 41 additions & 4 deletions crouton.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Description: A tabbed based display for showing meeting information.
Author: bmlt-enabled
Author URI: https://bmlt.app
Version: 3.15.3
Version: 3.16.0
*/
/* Disallow direct access to the plugin file */
if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) {
Expand All @@ -21,6 +21,7 @@ class Crouton
public $options = array();
public $croutonBlockInitialized = false;
public static $HOUR_IN_SECONDS = 3600;
public $has_handlebars = false;
public $themes = [
"asheboro",
"florida-nights",
Expand Down Expand Up @@ -83,6 +84,9 @@ class Crouton
"show_map" => '0',
"max_zoom_level" => 15,
"language" => 'en-US',
'strict_datafields' => false,
'meeting_details_href' => '',
'virtual_meeting_details_href' => '',
"auto_tz_adjust" => '0',
"base_tz" => null,
"sort_keys" => 'start_time',
Expand Down Expand Up @@ -146,6 +150,10 @@ public function __construct()
&$this,
"serviceBodyNames"
));
add_shortcode('bmlt_handlebar', array(
&$this,
"bmlt_handlebar"
));
}
// Content filter
add_filter('the_content', array(
Expand Down Expand Up @@ -335,7 +343,14 @@ public function tabbedUi($atts, $content = null)
{
return sprintf('%s<div id="bmlt-tabs" class="bmlt-tabs hide">%s</div><script>document.getElementById("please-wait").style.display = "none";</script>', $this->sharedRender(), $this->renderTable($atts));
}

public function bmlt_handlebar($atts, $template = null)
{
if (!$this->has_handlebars) {
add_action("wp_footer", [$this,'handlebar_footer']);
}
$this->has_handlebars = true;
return sprintf('<bmlt-handlebar><div style="display:none;">%s</div>Fetching...</bmlt-handlebar>', htmlspecialchars($template));
}
public function croutonMap($atts, $content = null)
{
return sprintf('%s<div id="bmlt-tabs" class="bmlt-tabs hide">%s</div>', $this->sharedRender(), $this->renderMap($atts));
Expand Down Expand Up @@ -409,7 +424,26 @@ public function serviceBodyNames($atts)
$random_id = rand(10000, 99999);
return $this->getInitializeCroutonBlock($this->getCroutonJsConfig($atts)) . "<script type='text/javascript'>jQuery(document).ready(function() { crouton.serviceBodyNames(function(res) { document.getElementById('service-body-names-$random_id').innerHTML = res; }) })</script><span id='service-body-names-$random_id'></span>";
}

public function handlebar_footer()
{
if (!isset($_GET['meeting-id'])) {
return;
}
$meetingId = $_GET['meeting-id'];
$attr = ['custom_query' => '&meeting_ids[]='.$meetingId,
'strict_datafields' => false];
$config = $this->getCroutonJsConfig($attr);
?>
<script type='text/javascript'>
var crouton;

jQuery(document).ready(function() {
crouton = new Crouton(<?php echo $config; ?>);
crouton.doHandlebars();
});
</script>
<?php
}
/**
* @desc Adds the options sub-panel
*/
Expand Down Expand Up @@ -879,6 +913,9 @@ public function getCroutonJsConfig($atts)
}

$params['extra_meetings'] = $extra_meetings_array;

$params['force_rootserver_in_querystring'] = ($params['root_server'] !== $this->options['root_server']);
// TODO add default language and root_server
return json_encode($params);
}
}
Expand All @@ -889,4 +926,4 @@ public function getCroutonJsConfig($atts)
if (class_exists("Crouton")) {
$BMLTTabs_instance = new Crouton();
}
?>
?>
113 changes: 108 additions & 5 deletions croutonjs/src/js/crouton-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ function Crouton(config) {
service_body: [], // Array of service bodies to return data for.
formats: '', // Return only meetings with these formats (format shared-id, not key-string)
venue_types: '', // Return only meetings with this venue type (1, 2 or 3)
strict_datafields: true, // Only get the datafields that are mentioned in the templates
meeting_details_href: '', // Link to the meeting details page
virtual_meeting_details_href: '', // Link to the virtual meeting details page
exclude_zip_codes: [], // List of zip codes to exclude
extra_meetings: [], // List of id_bigint of meetings to include
native_lang: '', // The implied language of meetings with no explicit language specied. May be there as second language, but it still doesn't make sense to search for it.
Expand All @@ -66,11 +69,15 @@ function Crouton(config) {
int_start_day_id: 1, // Controls the first day of the week sequence. Sunday is 1.
view_by: "weekday", // TODO: replace with using the first choice in button_filters as the default view_by.
show_qrcode: false, // Determines whether or not to show the QR code for virtual / phone meetings if they exist.
force_rootserver_in_querystring: true, // Set to false to shorten generated meeting detail query strings
force_timeformat_in_querystring: true, // Set to false to shorten generated meeting detail query strings
force_language_in_querystring: true, // Set to false to shorten generated meeting detail query strings
theme: "jack", // Allows for setting pre-packaged themes. Choices are listed here: https://github.com/bmlt-enabled/crouton/blob/master/croutonjs/dist/templates/themes
meeting_data_template: croutonDefaultTemplates.meeting_data_template,
metadata_template: croutonDefaultTemplates.metadata_template,
observer_template: croutonDefaultTemplates.observer_template,
meeting_count_template: croutonDefaultTemplates.meeting_count_template
meeting_count_template: croutonDefaultTemplates.meeting_count_template,
meeting_link_template: croutonDefaultTemplates.meeting_link_template,
};

self.setConfig(config);
Expand Down Expand Up @@ -205,9 +212,12 @@ function Crouton(config) {
self.mutex = false;
});
};
self.mutex = true;

self.meetingSearch = function() {
self.addDatafieldsToQuery = function() {
if (!self.config.strict_datafields) {
self.all_data_keys = [];
self.queryable_data_keys = [];
return '';
}
var base_data_field_keys = [
'location_postal_code_1',
'duration_time',
Expand Down Expand Up @@ -278,8 +288,13 @@ function Crouton(config) {
self.collectDataKeys(self.config['observer_template']);

var unique_data_field_keys = arrayUnique(self.queryable_data_keys);
return '&data_field_key=' + unique_data_field_keys.join(',');
}
self.mutex = true;

self.meetingSearch = function() {
var url = '/client_interface/jsonp/?switcher=GetSearchResults&get_used_formats&lang_enum=' + self.config['short_language'] +
'&data_field_key=' + unique_data_field_keys.join(',');
self.addDatafieldsToQuery();

if (self.config['formats']) {
url += self.config['formats'].reduce(function(prev,id) {
Expand Down Expand Up @@ -554,6 +569,7 @@ function Crouton(config) {
crouton_Handlebars.registerPartial("metaDataTemplate", self.config['metadata_template']);
crouton_Handlebars.registerPartial("observerTemplate", self.config['observer_template']);
crouton_Handlebars.registerPartial("meetingCountTemplate", self.config['meeting_count_template']);
crouton_Handlebars.registerPartial("meetingLink", self.config['meeting_link_template']);

for (var m = 0; m < meetingData.length; m++) {
meetingData[m]['formatted_comments'] = meetingData[m]['comments'];
Expand Down Expand Up @@ -636,6 +652,19 @@ function Crouton(config) {
meetingData[m]['parentServiceBodyType'] = self.localization.getServiceBodyType(parentBodyInfo["type"]);
}

meetingData[m]['meeting_details_url'] = '';
if (self.config.meeting_details_href) {
meetingData[m]['meeting_details_url'] = self.config.meeting_details_href;
if (meetingData[m]['venue_type'] === 2 && self.config.virtual_meeting_details_href ) {
meetingData[m]['meeting_details_url'] = self.config.virtual_meeting_details_href;
}
meetingData[m]['meeting_details_url'] += '?meeting-id=' + meetingData[m]['id_bigint']
+ self.config.force_language_in_querystring ? '&language=' + self.config.language : ''
+ self.config.force_timeformat_in_querystring ? '&time_format=' + encodeURIComponent(self.config.time_format) : ''
+ self.config.force_rootserver_in_querystring ? '&root_server=' + encodeURIComponent(self.config.root_server) : ''
;
}

meetings.push(meetingData[m])
}

Expand Down Expand Up @@ -769,6 +798,80 @@ Crouton.prototype.getServiceBodyDetails = function(serviceBodyId) {
}
}

Crouton.prototype.doHandlebars = function() {
var elements = document.getElementsByTagName('bmlt-handlebar');
if (elements.length === 0) {
self.showMessage('No <bmlt-handlebar> tags found');
return;
};
var self = this;
self.lock(function() {
if (self.isEmpty(self.meetingData)) {
self.showMessage("No meetings found for parameters specified.");
return;
}
var promises = [self.getServiceBodies(self.meetingData[0]['service_body_bigint'])];
Promise.all(promises)
.then(function(data) {
self.active_service_bodies = [];
self.all_service_bodies = [];
var service_body = data[0][0];
self.all_service_bodies.push(service_body);
var enrichedMeetingData = self.enrichMeetings(self.meetingData);
var customStartupTemplate = crouton_Handlebars.compile('{{startup}}');
customStartupTemplate(enrichedMeetingData);
var customEnrichTemplate = crouton_Handlebars.compile('{{enrich this}}{{console this}}');
customEnrichTemplate(enrichedMeetingData[0]);
var parser = new DOMParser();

while (elements.length > 0) {
var element = elements.item(0);
if (!element.firstChild) {
console.log('<bmlt-handlebar> tag must have at least one child');
element.remove();
continue;
}
var templateString = '';
if (element.firstChild.nodeType === 1) {
if (!element.firstChild.firstChild || element.firstChild.firstChild.nodeType !== 3) {
console.log('<bmlt-handlebar> tag: cannot find textnode');
element.remove();
continue;
}
templateString = element.firstChild.firstChild.textContent;
} else if (element.firstChild.nodeType === 3) {
if (!element.firstChild.nodeType !== 3) {
console.log('<bmlt-handlebar> tag: cannot find textnode');
element.remove();
continue;
}
templateString = element.firstChild.textContent;
}

var template = crouton_Handlebars.compile(templateString);
var handlebarResult = template(enrichedMeetingData[0]);
var htmlDecode = parser.parseFromString('<body>'+handlebarResult+'</body>', "text/html");
if (!htmlDecode.body || !htmlDecode.body.firstChild) {
console.log('<bmlt-handlebar> tag: could not parse the Handlebars result');
element.remove();
continue;
}
var firstPart = htmlDecode.body.firstChild;
var brothers = [];
var thisPart = firstPart;
var nextPart = null;
while (nextPart = thisPart.nextSibling) {
thisPart = nextPart;
brothers.push(thisPart);
}
element.replaceWith(firstPart);
if (brothers) firstPart.after(...brothers);
}
});
});

};

Crouton.prototype.render = function() {
var self = this;
self.lock(function() {
Expand Down
9 changes: 8 additions & 1 deletion croutonjs/src/js/crouton-default-templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ var croutonDefaultTemplates = {
"{{#if this.config.has_meeting_count}}",
"<span class='bmlt_tabs_meeting_count'>{{getWord 'meeting_count'}} {{this.meetings.meetingCount}}</span>",
"{{/if}}"
].join('\n')
].join('\n'),

meeting_link_template: [
"{{#if this.meeting_details_url}}",
"<a href='{{{this.meeting_details_url}}}'><span class='glyphicon glyphicon-search' aria-hidden='true'></span>{{this.meeting_name}}</a>",
"{{else}}",
"{{this.meeting_name}}",
"{{/if}}"
].join('\n')
}
46 changes: 43 additions & 3 deletions partials/_instructions.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<li><code>[meeting_count]</code></li>
<li><code>[group_count]</code></li>
<li><code>[service_body_names]</code></li>
<li><code>[bmlt_handlebar]</code></li>
</ul>
<p>Example: <code>There are currently [group_count] groups, offering a total of [meeting_count] meetings per week.</code></p>
<p><strong>Hints:</strong> you can only have one occurrence of <code>[bmlt_tabs]</code> on a page -- if you want two lists,
Expand Down Expand Up @@ -85,6 +86,13 @@
<p>weekday = view meetings by Weekdays (default)</p>
<p>Another example could be "location_municipality", which would show city if it were available as a button.</p>
</div>
<h3 class="help-accordian"><strong>View By Language or Common Need</strong></h3>
<div>
<p>With this parameter you can initially view meetings by Weekday or any other field, as long as the button_filters_option was added ahead of time.</p>
<p><strong>[bmlt_tabs view_by="weekday"]</strong></p>
<p>weekday = view meetings by Weekdays (default)</p>
<p>Another example could be "location_municipality", which would show city if it were available as a button.</p>
</div>
<h3 class="help-accordian"><strong>Exclude City Button</strong></h3>
<div>
<p>With this parameter you can exclude the City button.</p>
Expand All @@ -99,6 +107,13 @@
<p><strong>[bmlt_tabs button_filters_option="City:location_municipality"]</strong></p>
<p>You can also include multiple buttons with a comma after each pair. Keep in mind that the first part is the word for the button. If using multilingual option, that word must have a translation.</p>
</div>
<h3 class="help-accordian"><strong>Show Format Filter Buttons</strong></h3>
<div>
<p>With this parameter you can include specific buttons.</p>
<p><strong>[bmlt_tabs button_format_filters_option="Common Needs:FC3"]</strong></p>
<p><strong>[bmlt_tabs button_format_filters_option="Languages:LANG"]</strong></p>
<p>You can also include multiple buttons with a comma after each pair. Keep in mind that the first part is the word for the button. If using multilingual option, that word must have a translation.</p>
</div>
<h3 class="help-accordian"><strong>Tabs or No Tabs</strong></h3>
<div>
<p>With this parameter you can display meetings without weekday tabs.</p>
Expand Down Expand Up @@ -132,9 +147,9 @@
<h3 class="help-accordian"><strong>Dropdowns</strong></h3>
<div>
<p>With this parameter you can show or hide the dropdowns.</p>
<p><strong>[bmlt_tabs has_days='0|1' has_cities='0|1' has_groups='0|1' has_areas='0|1' has_regions='0|1' has_locations='0|1' has_sub_province='0|1' has_states='0|1' has_zip_codes='0|1' has_formats='0|1' has_neighborhoods='0|1' has_venues='0|1']</strong></p>
<p>0 = hide dropdown<p>
<p>1 = show dropdown (default)<p>
<p><strong>[bmlt_tabs has_days='0|1' has_cities='0|1' has_groups='0|1' has_areas='0|1' has_regions='0|1' has_locations='0|1' has_sub_province='0|1' has_states='0|1' has_zip_codes='0|1' has_formats='0|1' has_neighborhoods='0|1' has_venues='0|1' has_languages='0|1' has_common_needs='0|1']</strong></p>
<p>0 = hide dropdown (default, for <strong>has_languages</strong> and <strong>has_common_needs</strong>)<p>
<p>1 = show dropdown (default, for all options other than <strong>has_languages</strong> and <strong>has_common_needs</strong>)<p>
</div>
<h3 class="help-accordian"><strong>Dropdown Filters</strong></h3>
<div>
Expand Down Expand Up @@ -225,6 +240,20 @@
<p>Multiple formats require the use of brackets `[]` which can break shortcodes. Replace brackets with `%5B%5D`.</p>
<p><em>This can be overridden using a querystring parameter as well, but use must URL encode the query. Example: <a target="_blank" href="about:blank">http://localhost:8080/?page_id=5&custom_query=%26meeting_key%3Dlocation_sub_province%26meeting_key_value%3DSampson</a></em></p>
</div>
<h3 class="help-accordian"><strong>Query: Select by venue type</strong></h3>
<div>
<p>With this parameter you can add restrictions to root server query, as an alternative to specifying a custom query.
<p><strong>[bmlt_tabs venues="1|2|3"]</strong></p>
<p>Where<ul><li>1 = In-Person Meetings</li><li>2 = Virtual Meetings</li><li>3 = Hybrid Meetings</li></ul>
<p>The values can also be negative, which means that the venue type should be excluded from the results. To specify more the one type, use a comma separated list.</p>
</div>
<h3 class="help-accordian"><strong>Query: Select by format</strong></h3>
<div>
<p>With this parameter you can add restrictions to root server query, as an alternative to specifying a custom query.
<p><strong>[bmlt_tabs formats="123"]</strong></p>
<p>Where the number specified is the shared id code for the format. Use the semantic workshop to look up format codes.
<p>The values can also be negative, which means that the meetings with that format should be excluded from the results. To specify more the one format, use a comma separated list.</p>
</div>
<h3 class="help-accordian"><strong>Companion Map</strong></h3>
<div>
<p>With this parameter you can have crouton display a companion map of all the meetings.</p>
Expand All @@ -247,6 +276,17 @@
<p><strong>[crouton_map map_search_zoom="10"]</strong> - specifies the starting zoom level on the map (default: 10).</p>
<p><strong>[crouton_map map_search_width="-50"]</strong> - specifies how many meetings to return, a positive integer means how many miles or kilometers to search. A negative integer indicates the closest number of meetings from that point with no distance limits. (default: -50 [the fifty closest meetings to the point selected]).</p>
<p><em>The Google API Key must be entered on the crouton settings page for this to work. You must have the 'Google Maps JavaScript API' enabled on your key. For more information on setting up and configuring a Google Maps API key check out this blog article <a target="_blank" href="https://bmlt.app/google-api-key/">https://bmlt.app/google-api-key/</a></em></p>
</div>
<h3 class="help-accordian"><strong>Create Meeting-Detail Pages</strong></h3>
<div>
<p>With this shortcode you can insert a HandlebarJS template into your page.
<p><strong>[bmlt_handlebar]</strong></p>
<p> If the page is called with a query string including "meeting-id=<em>your meeting here</em>"
the default BMLT root server will be accessed to obtain the meeting information used when evaluation the template. The Meeting Data template, and all other templates and helpers
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably meant to say "evaluating" rather than "evaluation" here?

BTW - very cool feature.

used by Crouton are also available for use within the [bmlt-handlebar] tag.</p>
<p>For instance, to put the meeting name as the title of the page, you could have
<code>[bmlt_handlebar]&lt;H1&gt;{{this.meeting_name}}&lt;/H1&gt;[/bmlt_handlebar]</code>
</p>
</div>
<h3 class="help-accordian"><strong>Multilingual Support</strong></h3>
<div>
Expand Down
Loading
Loading