BMLT Root Server
server_admin_javascript.js
Go to the documentation of this file.
1 /*
2  This file is part of the Basic Meeting List Toolbox (BMLT).
3 
4  Find out more at: https://bmlt.app
5 
6  BMLT is free software: you can redistribute it and/or modify
7  it under the terms of the MIT License.
8 
9  BMLT is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  MIT License for more details.
13 
14  You should have received a copy of the MIT License along with this code.
15  If not, see <https://opensource.org/licenses/MIT>.
16 */
17 /********************************************************************************************
18 *######################################### MAIN CODE #######################################*
19 ********************************************************************************************/
20 
22 {
23  // #mark -
24  // #mark ########## Class Declaration ##########
25  // #mark -
26 
27  /************************************************************************************//**
28  * DATA MEMBERS *
29  ****************************************************************************************/
30  var m_server_admin_panel_shown = null; ///< This will be true if the "Server Administration" panel is exposed.
31  var m_account_panel_shown = null; ///< This will be true if the "My Account" panel is exposed.
32  var m_search_specifier_shown = null; ///< This is true, if the meeting search specifier form is shown.
33  var m_meeting_editor_panel_shown = null; ///< This will be true if the "Edit Meetings" panel is exposed.
34  var m_service_body_editor_panel_shown = null; ///< This is true, if the Service Body Editor is shown.
35  var m_ajax_request_in_progress = null; ///< This is any AJAX request currently under way.
36  var m_success_fade_duration = null; ///< Number of milliseconds for a success fader.
37  var m_failure_fade_duration = null; ///< Number of milliseconds for a failure fader.
38  var m_search_results = null; ///< This will contain any meeting search results.
39  var m_meeting_results_container_div = null; ///< This will hold any search result display elements (allows easy disposal)
40  var m_editing_window_open = null; ///< If there is a meeting editor open, it is recorded here. There can only be one...
41  var m_user_editor_panel_shown = null; ///< Set to true, if the user editor is open.
42  var m_warn_user_to_refresh = null; ///< If this is true, then a warning alert will be shown to the user.
43  var m_format_editor_table_rows = null; ///< This is used to track the number of rows in the format editor table.
44 
45  this.validationMessageTypes = {
46  "ERROR": "error",
47  "WARN": "warn"
48  }
49 
50  /************************************************************************************//**
51  * METHODS *
52  ****************************************************************************************/
53 
54  // #mark -
55  // #mark Affects All Sections
56  // #mark -
57 
58  /************************************************************************************//**
59  * \brief If one of the upper sections has been edited, it can affect the Account, *
60  * Meeting or Service Body sections. In this case, the user needs to log out, *
61  * then back in again (or refresh the page, but signing out is easier to *
62  * explain). This sets an orange fader in each affected section, and also sets *
63  * the trigger for an alert that explains it. *
64  ****************************************************************************************/
65  this.setWarningFaders = function () {
66  if ( document.getElementById('bmlt_admin_fader_service_body_editor_warn_div') ) {
67  document.getElementById('bmlt_admin_fader_service_body_editor_warn_div').className = 'bmlt_admin_fader_div';
68  };
69 
70  if ( document.getElementById('bmlt_admin_fader_meeting_editor_warn_div') ) {
71  document.getElementById('bmlt_admin_fader_meeting_editor_warn_div').className = 'bmlt_admin_fader_div';
72  };
73 
74  if ( document.getElementById('bmlt_admin_fader_account_warn_div') ) {
75  document.getElementById('bmlt_admin_fader_account_warn_div').className = 'bmlt_admin_fader_div';
76  };
77 
78  this.m_warn_user_to_refresh = true;
79  };
80 
81  /************************************************************************************//**
82  * \brief This displays that alert. *
83  ****************************************************************************************/
84  this.showWarningAlert = function () {
85  if ( this.m_warn_user_to_refresh ) { // Only if needed.
86  alert(g_need_refresh_message_alert_text);
87  this.m_warn_user_to_refresh = false;
88  };
89  };
90 
91  // #mark -
92  // #mark Text Item Handlers
93  // #mark -
94 
95  /************************************************************************************//**
96  * \brief When a text input (either <input> or <textarea> is initialized, we can set *
97  * up a default text value that is displayed when the item is empty and not in *
98  * focus. If we don't send in a specific value, then the current value of the *
99  * text item is considered to be the default. *
100  ****************************************************************************************/
101  this.handleTextInputLoad = function (
102  in_text_item,
103  in_default_value,
104  in_small
105  ) {
106  if ( in_text_item ) {
107  in_text_item.original_value = in_text_item.value;
108  if ( !in_text_item.small ) {
109  in_text_item.small = false;
110  };
111 
112  if ( !in_text_item.tiny ) {
113  in_text_item.tiny = false;
114  };
115 
116  in_text_item.small = in_text_item.small || in_small;
117 
118  if ( in_default_value != null ) {
119  in_text_item.defaultValue = in_default_value;
120  } else {
121  in_text_item.defaultValue = in_text_item.value;
122  };
123 
124  in_text_item.value = in_text_item.original_value;
125 
126  if ( !in_text_item.value || (in_text_item.value == in_text_item.defaultValue) ) {
127  in_text_item.value = in_text_item.defaultValue;
128  in_text_item.className = 'bmlt_text_item' + (in_text_item.small ? '_small' : (in_text_item.med ? '_med' : (in_text_item.tiny ? '_tiny' : ''))) + ' bmlt_text_item_dimmed';
129  } else {
130  in_text_item.className = 'bmlt_text_item' + (in_text_item.small ? '_small' : (in_text_item.med ? '_med' : (in_text_item.tiny ? '_tiny' : '')));
131  };
132  };
133  };
134 
135  /************************************************************************************//**
136  * \brief This just makes sure that the className is correct. *
137  ****************************************************************************************/
138  this.setTextItemClass = function (
139  in_text_item, ///< This is the text item to check.
140  is_focused ///< true, if the item is in focus
141  ) {
142  if ( in_text_item ) {
143  if ( !is_focused && ((in_text_item.value == null) || (in_text_item.value == in_text_item.defaultValue)) ) {
144  in_text_item.className = 'bmlt_text_item' + (in_text_item.small ? '_small' : (in_text_item.med ? '_med' : (in_text_item.tiny ? '_tiny' : ''))) + ' bmlt_text_item_dimmed';
145  } else {
146  in_text_item.className = 'bmlt_text_item' + (in_text_item.small ? '_small' : (in_text_item.med ? '_med' : (in_text_item.tiny ? '_tiny' : '')));
147  };
148  };
149  };
150 
151  /************************************************************************************//**
152  * \brief When a text item receives focus, we clear any default text. *
153  ****************************************************************************************/
154  this.handleTextInputFocus = function ( in_text_item
155  ) {
156  if ( in_text_item ) {
157  if ( in_text_item.value == in_text_item.defaultValue ) {
158  in_text_item.value = '';
159  };
160 
161  this.setTextItemClass(in_text_item, true);
162  this.validateAccountGoButton();
163  };
164  };
165 
166  /************************************************************************************//**
167  * \brief When a text item loses focus, we restore any default text, if the item was *
168  * left empty. *
169  ****************************************************************************************/
170  this.handleTextInputBlur = function ( in_text_item
171  ) {
172  if ( in_text_item ) {
173  if ( !in_text_item.value ) {
174  in_text_item.value = in_text_item.defaultValue;
175  };
176 
177  this.setTextItemClass(in_text_item, false);
178  this.validateAccountGoButton();
179  };
180  };
181 
182  /************************************************************************************//**
183  * \brief This is called when executing a paste. It avoids leaving in the default text.*
184  ****************************************************************************************/
185  this.handleTextInputPaste = function ( in_text_item
186  ) {
187  if ( in_text_item ) {
188  this.setTextItemClass(in_text_item, true);
189  this.validateAccountGoButton();
190  };
191  };
192 
193  /************************************************************************************//**
194  * \brief When a text item has its text changed, we check to see if it needs to have *
195  * its classname changed to the default (usually won't make a difference, as *
196  * the text item will be in focus, anyway). *
197  ****************************************************************************************/
198  this.handleTextInputChange = function (
199  in_text_item,
200  in_meeting_id
201  ) {
202  if ( in_text_item ) {
203  this.validateAccountGoButton();
204  this.validateMeetingEditorButton(in_meeting_id);
205  };
206  };
207 
208  /************************************************************************************//**
209  * \brief When a text item has its text changed, we check to see if it needs to have *
210  * its classname changed to the default (usually won't make a difference, as *
211  * the text item will be in focus, anyway). *
212  ****************************************************************************************/
213  this.setItemValue = function (
214  in_item,
215  in_meeting_id,
216  in_value_field
217  ) {
218  var eval_str = '';
219 
220  if ( (null == in_meeting_id) && (null != in_item.meeting_id) ) {
221  in_meeting_id = in_item.meeting_id;
222  };
223 
224  if ( !in_value_field ) {
225  in_value_field = in_item.element;
226  };
227 
228  var editor_object_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id.toString() + '_div';
229  var editor_object = document.getElementById(editor_object_id);
230 
231  if ( (in_item.type == 'text') || (in_item.name == 'textarea') ) {
232  var value = in_item.value.toString();
233 
234  value = value.replace(/'/g, "\\'"); // Make sure to escape apostrophes.
235 
236  if ( value && (value != in_item.defaultValue) ) {
237  eval_str = 'editor_object.meeting_object.' + in_value_field + ' = \'' + value + '\';';
238  } else {
239  if ( 0 == in_meeting_id ) {
240  eval_str = 'delete editor_object.meeting_object.' + in_value_field + ';';
241  } else {
242  eval_str = 'editor_object.meeting_object.' + in_value_field + ' = \'\';';
243  };
244  };
245  };
246 
247  if ( eval_str ) {
248  eval(eval_str);
249  };
250 
251  if ( in_item ) {
252  this.validateAccountGoButton();
253  this.validateMeetingEditorButton(in_meeting_id);
254  this.handleNewAddressInfo(in_meeting_id);
255  };
256  };
257 
258  // #mark -
259  // #mark ########## Account Info Section ##########
260  // #mark -
261 
262  /************************************************************************************//**
263  * \brief Toggles the selected item of the Server Administration section. *
264  ****************************************************************************************/
265  this.toggleServerAdminSelect = function () {
266  var selectedValue = document.getElementById('bmlt_admin_server_admin_select').value;
267  var updateWorldIdsDiv = document.getElementById('bmlt_admin_server_admin_update_world_ids_edit_form_inner_div');
268  var nawsImportDiv = document.getElementById('bmlt_admin_server_admin_naws_import_edit_form_inner_div');
269  if (selectedValue === "naws_import") {
270  updateWorldIdsDiv.className = 'bmlt_admin_server_admin_update_world_ids_edit_form_inner_div item_hidden';
271  nawsImportDiv.className = 'bmlt_admin_server_admin_naws_import_edit_form_inner_div';
272  } else {
273  updateWorldIdsDiv.className = 'bmlt_admin_server_admin_update_world_ids_edit_form_inner_div';
274  nawsImportDiv.className = 'bmlt_admin_server_admin_naws_import_edit_form_inner_div item_hidden';
275  }
276  };
277 
278  /************************************************************************************//**
279  * \brief Toggles the visibility of the Server Administration section. *
280  ****************************************************************************************/
281  this.toggleServerAdmin = function () {
282  this.m_server_admin_panel_shown = !this.m_server_admin_panel_shown;
283 
284  var the_disclosure_div = document.getElementById('bmlt_admin_server_admin_disclosure_div');
285  var the_account_info_div = document.getElementById('bmlt_admin_server_admin_wrapper_div');
286 
287  if ( this.m_server_admin_panel_shown) {
288  the_disclosure_div.className = 'bmlt_admin_server_admin_disclosure_div bmlt_admin_server_admin_disclosure_div_open';
289  the_account_info_div.className = 'bmlt_admin_server_admin_wrapper_div';
290  } else {
291  the_disclosure_div.className = 'bmlt_admin_server_admin_disclosure_div bmlt_admin_server_admin_disclosure_div_closed';
292  the_account_info_div.className = 'bmlt_admin_server_admin_wrapper_div bmlt_admin_server_admin_wrapper_div_hidden';
293  }
294  };
295 
296  /************************************************************************************//**
297  * \brief Toggles the visibility of the account info section. *
298  ****************************************************************************************/
299  this.toggleAccountInfo = function () {
300  this.m_account_panel_shown = !this.m_account_panel_shown;
301 
302  var the_disclosure_div = document.getElementById('bmlt_admin_user_account_disclosure_div');
303  var the_account_info_div = document.getElementById('bmlt_admin_user_account_wrapper_div');
304 
305  if ( this.m_account_panel_shown) {
306  var email_field = document.getElementById('bmlt_admin_user_email_input');
307  var description_field = document.getElementById('bmlt_admin_user_description_textarea');
308  var password_field = document.getElementById('bmlt_admin_user_account_password_input');
309 
310  this.handleTextInputBlur(email_field);
311  this.handleTextInputBlur(description_field);
312  this.handleTextInputBlur(password_field);
313 
314  the_disclosure_div.className = 'bmlt_admin_user_account_disclosure_div bmlt_admin_user_account_disclosure_div_open';
315  the_account_info_div.className = 'bmlt_admin_user_account_wrapper_div';
316  this.showWarningAlert();
317  } else {
318  the_disclosure_div.className = 'bmlt_admin_user_account_disclosure_div bmlt_admin_user_account_disclosure_div_closed';
319  the_account_info_div.className = 'bmlt_admin_user_account_wrapper_div bmlt_admin_user_account_wrapper_div_hidden';
320  };
321  };
322 
323  /************************************************************************************//**
324  * \brief This checks the values of the text items in the My Account section. If any *
325  * of them are different from their default, we enable the GO button. *
326  ****************************************************************************************/
327  this.validateAccountGoButton = function () {
328  var email_field = document.getElementById('bmlt_admin_user_email_input');
329  var password_field = document.getElementById('bmlt_admin_user_account_password_input');
330  var ajax_button = document.getElementById('bmlt_admin_account_change_ajax_button');
331  var description = document.getElementById('bmlt_admin_user_description_textarea');
332  var name_field = document.getElementById('bmlt_admin_user_name_input');
333  var login_field = document.getElementById('bmlt_admin_user_login_input');
334 
335  if ( email_field && password_field && ajax_button && description ) {
336  if ( (email_field.value != email_field.original_value && email_field.value != email_field.defaultValue)
337  || (description.value != description.original_value && description.value != description.defaultValue)
338  || (name_field && (name_field.value != name_field.original_value))
339  || (login_field && (login_field.value != login_field.original_value))
340  || (password_field.value && (password_field.value != password_field.defaultValue)) ) {
341  ajax_button.className = 'bmlt_admin_ajax_button';
342  } else {
343  ajax_button.className = 'bmlt_admin_ajax_button button_disabled';
344  };
345  };
346  };
347 
348  /************************************************************************************//**
349  * \brief This is called when the World ID update file input changes *
350  ****************************************************************************************/
351  this.handleWorldIDFileInputChange = function() {
352  var file_input = document.getElementById('bmlt_admin_naws_spreadsheet_file_input');
353  var save_button = document.getElementById('bmlt_admin_update_world_ids_ajax_button');
354 
355  if (file_input.files && file_input.files.length > 0) {
356  save_button.className = 'bmlt_admin_ajax_button';
357  } else {
358  save_button.className = 'bmlt_admin_ajax_button button_disabled';
359  }
360  };
361 
362  /************************************************************************************//**
363  * \brief This is called when the NAWS Import file input changes *
364  ****************************************************************************************/
365  this.handleNAWSImportFileInputChange = function() {
366  var file_input = document.getElementById('bmlt_admin_naws_import_file_input');
367  var save_button = document.getElementById('bmlt_admin_naws_import_ajax_button');
368 
369  if (file_input.files && file_input.files.length > 0) {
370  save_button.className = 'bmlt_admin_ajax_button';
371  } else {
372  save_button.className = 'bmlt_admin_ajax_button button_disabled';
373  }
374  };
375 
376  /************************************************************************************//**
377  * \brief This is called to initiate an AJAX process to update world IDs from file *
378  ****************************************************************************************/
379  this.handleUpdateWorldIDsFromSpreadsheet = function() {
380  var file_input = document.getElementById('bmlt_admin_naws_spreadsheet_file_input');
381  var save_button = document.getElementById('bmlt_admin_update_world_ids_ajax_button');
382  if (!file_input || !file_input.files || !file_input.files.length) {
383  return;
384  }
385 
386  if ( this.m_ajax_request_in_progress ) {
387  this.m_ajax_request_in_progress.abort();
388  this.m_ajax_request_in_progress = null;
389  }
390 
391  this.m_ajax_request_in_progress = BMLT_AjaxRequest_FileUpload(
392  g_ajax_callback_uri + '&do_update_world_ids=1',
393  function(response) {admin_handler_object.handleUpdateWorldIDsFromSpreadsheetCallback(response);},
394  file_input.files[0]
395  );
396  this.setUpdateWorldIDsThrobber(true);
397  save_button.className = 'bmlt_admin_ajax_button button_disabled';
398  };
399 
400  this.handleUpdateWorldIDsFromSpreadsheetCallback = function(response) {
401  var file_input = document.getElementById('bmlt_admin_naws_spreadsheet_file_input');
402  var save_button = document.getElementById('bmlt_admin_update_world_ids_ajax_button');
403  this.setUpdateWorldIDsThrobber(false);
404  file_input.value = '';
405  save_button.className = 'bmlt_admin_ajax_button button_disabled';
406 
407  if (response && response.responseText) {
408  if (response.responseText === 'NOT AUTHORIZED') {
409  alert(g_AJAX_Auth_Failure);
410  return;
411  }
412 
413  eval('var result = ' + response.responseText + ';');
414  if (!result) {
415  return;
416  }
417 
418  if (result.success) {
419  var report = g_num_meetings_updated_text + result.report.updated.length.toString() + "\n\n";
420  report += g_num_meetings_not_updated_text + result.report.not_updated.length.toString();
421  if (result.report.not_found.length) {
422  report += "\n\n";
423  report += g_warning_text + ": " + result.report.not_found.length.toString() + " " + g_meetings_not_found_text + result.report.not_found.join(", ");
424  }
425  alert(report);
426  } else {
427  alert(g_errors_text + ":\n" + result.errors.join("\n"));
428  }
429  }
430  };
431 
432  /************************************************************************************//**
433  * \brief This is called to initiate an AJAX process to import meetings from file *
434  ****************************************************************************************/
435  this.handleNAWSImport = function() {
436  var file_input = document.getElementById('bmlt_admin_naws_import_file_input');
437  var save_button = document.getElementById('bmlt_admin_naws_import_ajax_button');
438  var publish_button = document.getElementById('bmlt_admin_naws_import_publish_checkbox');
439  if (!file_input || !file_input.files || !file_input.files.length) {
440  return;
441  }
442 
443  if ( this.m_ajax_request_in_progress ) {
444  this.m_ajax_request_in_progress.abort();
445  this.m_ajax_request_in_progress = null;
446  }
447 
448  this.m_ajax_request_in_progress = BMLT_AjaxRequest_FileUpload(
449  g_ajax_callback_uri + '&do_naws_import=1&initialValueForPublished=' + (publish_button.checked ? 'TRUE' : 'FALSE'),
450  function(response) {admin_handler_object.handleNAWSImportCallback(response);},
451  file_input.files[0]
452  );
453  this.setNAWSImportThrobber(true);
454  save_button.className = 'bmlt_admin_ajax_button button_disabled';
455  };
456 
457  this.handleNAWSImportCallback = function(response) {
458  var file_input = document.getElementById('bmlt_admin_naws_import_file_input');
459  var save_button = document.getElementById('bmlt_admin_naws_import_ajax_button');
460  this.setNAWSImportThrobber(false);
461  file_input.value = '';
462  save_button.className = 'bmlt_admin_ajax_button button_disabled';
463 
464  if (response && response.responseText) {
465  if (response.responseText === 'NOT AUTHORIZED') {
466  alert(g_AJAX_Auth_Failure);
467  return;
468  }
469 
470  eval('var result = ' + response.responseText + ';');
471  if (!result) {
472  return;
473  }
474 
475  if (result.success) {
476  var report = g_service_bodies_created_text + result.report.num_service_bodies_created.toString() + "\n\n";
477  report += g_users_created_text + result.report.num_users_created.toString() + "\n\n";
478  report += g_meetings_created_text + result.report.num_meetings_created.toString() + "\n\n";
479  report += g_server_admin_ui_refresh_ui_text;
480  alert(report);
481  } else {
482  alert(g_errors_text + ": " + result.errors);
483  }
484  }
485  };
486 
487  /************************************************************************************//**
488  * \brief Displays or hides the AJAX Throbber for the Update World IDs button *
489  ****************************************************************************************/
490  this.setUpdateWorldIDsThrobber = function(visible) {
491  var button_span = document.getElementById('bmlt_admin_update_world_ids_ajax_button_span');
492  var throbber_span = document.getElementById('bmlt_admin_update_world_ids_ajax_button_throbber_span');
493  throbber_span.className = 'bmlt_admin_value_left' + (visible ? '' : ' item_hidden');
494  button_span.className = 'bmlt_admin_value_left' + (visible ? ' item_hidden' : '');
495  };
496 
497  /************************************************************************************//**
498  * \brief Displays or hides the AJAX Throbber for the NAWS Import button *
499  ****************************************************************************************/
500  this.setNAWSImportThrobber = function(visible) {
501  var button_span = document.getElementById('bmlt_admin_naws_import_ajax_button_span');
502  var throbber_span = document.getElementById('bmlt_admin_naws_import_ajax_button_throbber_span');
503  throbber_span.className = 'bmlt_admin_value_left' + (visible ? '' : ' item_hidden');
504  button_span.className = 'bmlt_admin_value_left' + (visible ? ' item_hidden' : '');
505  };
506 
507 
508  /************************************************************************************//**
509  * \brief This is called to initiate an AJAX process to change the account settings. *
510  ****************************************************************************************/
511  this.handleAccountChange = function () {
512  var email_field = document.getElementById('bmlt_admin_user_email_input');
513  var password_field = document.getElementById('bmlt_admin_user_account_password_input');
514  var description = document.getElementById('bmlt_admin_user_description_textarea');
515  var affected_user_id = document.getElementById('account_affected_user_id');
516  var name_field = document.getElementById('bmlt_admin_user_name_input');
517  var login_field = document.getElementById('bmlt_admin_user_login_input');
518 
519  // We only do something if there is a difference.
520  if ( (affected_user_id.value == g_current_user_id) // Belt and suspenders...
521  && ((email_field.value != email_field.original_value)
522  || (description.value != description.original_value)
523  || (name_field && (name_field.value != name_field.original_value))
524  || (login_field && (login_field.value != login_field.original_value))
525  || (password_field.value && (password_field.value != password_field.defaultValue)))
526  ) {
527  if ( g_min_pw_len && (password_field.value && (password_field.value != password_field.defaultValue)) && (password_field.value.length < g_min_pw_len) ) {
528  alert(sprintf(g_min_password_length_string, g_min_pw_len));
529  } else {
530  this.setMyAccountThrobber(true);
531  var uri = g_ajax_callback_uri + '&target_user=' + encodeURIComponent(g_current_user_id);
532  if ( name_field && (name_field.value != name_field.original_value) ) {
533  uri += '&account_name_value=' + encodeURIComponent(name_field.value);
534  };
535 
536  if ( login_field && (login_field.value != login_field.original_value) ) {
537  uri += '&account_login_value=' + encodeURIComponent(login_field.value);
538  };
539 
540  if ( email_field.value != email_field.original_value ) {
541  uri += '&account_email_value=' + encodeURIComponent(email_field.value);
542  };
543 
544  if ( description.value != description.original_value ) {
545  uri += '&account_description_value=' + encodeURIComponent(description.value);
546  };
547 
548  if ( password_field.value && (password_field.value != password_field.defaultValue) ) {
549  uri += '&account_password_value=' + encodeURIComponent(password_field.value);
550  };
551 
552  if ( this.m_ajax_request_in_progress ) {
553  this.m_ajax_request_in_progress.abort();
554  this.m_ajax_request_in_progress = null;
555  };
556 
557  var salt = new Date();
558  uri += '&salt=' + salt.getTime();
559 
560  this.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req) {
561  admin_handler_object.handleAccountChangeAJAXCallback(in_req); }, 'post');
562  };
563  };
564  };
565 
566  /************************************************************************************//**
567  * \brief This is called to initiate an AJAX process to change the account settings. *
568  ****************************************************************************************/
569  this.handleAccountChangeAJAXCallback = function (in_http_request
570  ) {
571  var email_field = document.getElementById('bmlt_admin_user_email_input');
572  var password_field = document.getElementById('bmlt_admin_user_account_password_input');
573  var description = document.getElementById('bmlt_admin_user_description_textarea');
574 
575  this.m_ajax_request_in_progress = null;
576  if ( in_http_request.responseText ) {
577  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
578  alert(g_AJAX_Auth_Failure);
579  } else {
580  eval('var json_object = ' + in_http_request.responseText + ';');
581  };
582  };
583 
584  if ( json_object.ACCOUNT_CHANGED ) {
585  var success = true;
586 
587  if ( json_object.ACCOUNT_CHANGED.EMAIL_CHANGED == true ) {
588  email_field.original_value = email_field.value;
589  } else if ( json_object.ACCOUNT_CHANGED.EMAIL_CHANGED == false ) {
590  success = false;
591  };
592 
593  if ( json_object.ACCOUNT_CHANGED.DESCRIPTION_CHANGED == true ) {
594  description.original_value = description.value;
595  } else if ( json_object.ACCOUNT_CHANGED.DESCRIPTION_CHANGED == false ) {
596  success = false;
597  };
598 
599  var reload = false;
600  if ( json_object.ACCOUNT_CHANGED.PASSWORD_CHANGED == true ) {
601  reload = true;
602  } else if ( json_object.ACCOUNT_CHANGED.PASSWORD_CHANGED == false ) {
603  success = false;
604  };
605 
606  if ( json_object.ACCOUNT_CHANGED.PASSWORD_CHANGED == true ) {
607  reload = true;
608  } else if ( json_object.ACCOUNT_CHANGED.PASSWORD_CHANGED == false ) {
609  success = false;
610  };
611 
612  if ( reload ) {
613  window.location.href = g_logout_uri;
614  };
615 
616  password_field.value = '';
617  this.validateAccountGoButton();
618 
619  if ( success ) {
620  BMLT_Admin_StartFader('bmlt_admin_fader_account_success_div', this.m_success_fade_duration);
621  } else {
622  BMLT_Admin_StartFader('bmlt_admin_fader_account_fail_div', this.m_failure_fade_duration);
623  };
624  } else {
625  BMLT_Admin_StartFader('bmlt_admin_fader_account_fail_div', this.m_failure_fade_duration);
626  };
627 
628  this.handleTextInputBlur(email_field);
629  this.handleTextInputBlur(password_field);
630  this.handleTextInputBlur(description);
631 
632  this.setMyAccountThrobber(false);
633  };
634 
635  /************************************************************************************//**
636  * \brief Displays or hides the AJAX Throbber for the My Account button. *
637  ****************************************************************************************/
638  this.setMyAccountThrobber = function ( in_shown ///< If true, the throbber is show. If false, it is hidden.
639  ) {
640  var button_span = document.getElementById('bmlt_admin_account_change_ajax_button_span');
641  var throbber_span = document.getElementById('bmlt_admin_account_change_ajax_button_throbber_span');
642 
643  throbber_span.className = 'bmlt_admin_value_left' + (in_shown ? '' : ' item_hidden');
644  button_span.className = 'bmlt_admin_value_left' + (in_shown ? ' item_hidden' : '');
645  };
646 
647  // #mark -
648  // #mark ########## Meeting Editor Section ##########
649  // #mark -
650 
651  /************************************************************************************//**
652  * \brief This opens the editor to a particular meeting, as given by an ID. *
653  ****************************************************************************************/
654  this.openMeetingForEditing = function ( in_meeting_id ///< The ID of the meeting to be opened.
655  ) {
656  this.m_meeting_editor_panel_shown = false;
657  this.toggleMeetingEditor();
658  var uri = g_ajax_callback_uri + '&do_meeting_search=1&simple_other_fields=1&SearchStringAll=1&SearchString=' + parseInt(in_meeting_id);
659  this.clearSearchResults();
660  this.callRootServerForMeetingSearch(uri);
661  };
662 
663  /************************************************************************************//**
664  * \brief Toggles the visibility of the meeting editor section. *
665  ****************************************************************************************/
666  this.toggleMeetingEditor = function () {
667  this.m_meeting_editor_panel_shown = !this.m_meeting_editor_panel_shown;
668 
669  var the_disclosure_div = document.getElementById('bmlt_admin_meeting_editor_disclosure_div');
670  var the_editor_div = document.getElementById('bmlt_admin_meeting_editor_wrapper_div');
671 
672  if ( this.m_meeting_editor_panel_shown ) {
673  the_disclosure_div.className = 'bmlt_admin_meeting_editor_disclosure_div bmlt_admin_meeting_editor_disclosure_div_open';
674  the_editor_div.className = 'bmlt_admin_meeting_editor_wrapper_div';
675  this.showWarningAlert();
676  } else {
677  the_disclosure_div.className = 'bmlt_admin_meeting_editor_disclosure_div bmlt_admin_meeting_editor_disclosure_div_closed';
678  the_editor_div.className = 'bmlt_admin_meeting_editor_wrapper_div bmlt_admin_meeting_editor_wrapper_div_hidden';
679  };
680  };
681 
682  /************************************************************************************//**
683  * \brief Returns an object with the meeting data for the meeting ID passed in. *
684  * \returns a meeting object. Null if none found, or invalid ID. *
685  ****************************************************************************************/
686  this.getMeetingObjectById = function (
687  in_meeting_id, ///< The ID of the meeting to fetch
688  in_as_a_copy ///< If true, then the returned meeting object will be a clone (new object).
689  ) {
690  var ret = null;
691 
692  if ( in_meeting_id && this.m_search_results && this.m_search_results.length ) {
693  for (var c = 0; c < this.m_search_results.length; c++) {
694  if ( in_meeting_id == this.m_search_results[c].id_bigint ) {
695  var obj = this.m_search_results[c];
696 
697  if ( in_as_a_copy ) {
698  ret = JSON.parse(JSON.stringify(obj));
699  } else {
700  ret = obj;
701  };
702  break;
703  };
704  };
705  };
706 
707  if ( !ret ) { // If we did not find the meeting, we create a placeholder for it.
708  ret = new Object;
709  ret.longitude = g_default_longitude;
710  ret.latitude = g_default_latitude;
711  ret.start_time = g_default_meeting_start_time;
712 
713  var dur = g_default_meeting_duration.split(':');
714  dur[0] = parseInt(dur[0], 10);
715  dur[1] = parseInt(dur[1], 10);
716  ret.duration_time = sprintf('%02d:%02d:00', dur[0], dur[1]);
717 
718  ret.weekday_tinyint = g_default_meeting_weekday.toString();
719  ret.id_bigint = 0; // All new meetings are ID 0.
720  ret.published = g_default_meeting_published;
721  ret.service_body_bigint = g_service_bodies_array[0][0].toString();
722  ret.formats = '';
723  ret.format_shared_id_list = '';
724  };
725 
726  ret.zoom = g_default_zoom;
727 
728  return ret;
729  };
730 
731  // #mark -
732  // #mark Search For Meetings Tab
733  // #mark -
734 
735  /************************************************************************************//**
736  * \brief Selecte the search specifier tab. *
737  ****************************************************************************************/
738  this.selectSearchSpecifierTab = function () {
739  var tab_specifier_element = document.getElementById('bmlt_admin_meeting_editor_tab_specifier_div');
740  var tab_editor_element = document.getElementById('bmlt_admin_meeting_editor_tab_results_div');
741  var tab_specifier_link = document.getElementById('bmlt_admin_meeting_editor_tab_specifier_a');
742  var tab_editor_link = document.getElementById('bmlt_admin_meeting_editor_tab_results_a');
743  var search_specifier_element = document.getElementById('bmlt_admin_meeting_editor_form_specifier_div');
744  var meeting_editor_element = document.getElementById('bmlt_admin_meeting_editor_form_div');
745 
746  tab_specifier_element.className = 'bmlt_admin_tab_div_left bmlt_admin_tab_div_selected';
747  tab_editor_element.className = 'bmlt_admin_tab_div_right bmlt_admin_tab_div_not_selected';
748 
749  tab_editor_link.setAttribute('href', '');
750  tab_editor_link.href = 'javascript:admin_handler_object.selectMeetingEditorTab()';
751  tab_specifier_link.removeAttribute("href");
752 
753  search_specifier_element.className = 'bmlt_admin_meeting_editor_form_specifier_div';
754  meeting_editor_element.className = 'bmlt_admin_meeting_editor_form_div item_hidden';
755  }
756 
757  /************************************************************************************//**
758  * \brief This makes sure that the "All" checkbox syncs with the weekdays. *
759  ****************************************************************************************/
760  this.handleWeekdayCheckBoxChanges = function ( in_checkbox_index ///< The checkbox that triggered the call.
761  ) {
762  var all_checkbox = document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_0');
763  var weekday_checkboxes = new Array(
764  document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_1'),
765  document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_2'),
766  document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_3'),
767  document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_4'),
768  document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_5'),
769  document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_6'),
770  document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_7')
771  );
772 
773  if ( in_checkbox_index ) {
774  var weekday_selected = true;
775  for (var c = 0; c < 7; c++) {
776  if ( !weekday_checkboxes[c].checked ) {
777  weekday_selected = false;
778  };
779  };
780 
781  all_checkbox.checked = weekday_selected;
782  } else {
783  for (var c = 0; c < 7; c++) {
784  weekday_checkboxes[c].checked = all_checkbox.checked;
785  };
786  };
787  };
788 
789  /************************************************************************************//**
790  * \brief This handles Service body checkboxes. *
791  ****************************************************************************************/
792  this.handleServiceCheckBoxChanges = function ( in_service_body_id ///< The checkbox that triggered the call.
793  ) {
794  var the_checkbox = document.getElementById('bmlt_admin_meeting_search_service_body_checkbox_' + in_service_body_id);
795 
796  if ( the_checkbox ) {
797  var my_children = this.getServiceBodyChildren(in_service_body_id);
798  for (var c = 0; my_children && (c < my_children.length); c++) {
799  var child_id = my_children[c][0];
800  var child_checkbox = document.getElementById('bmlt_admin_meeting_search_service_body_checkbox_' + child_id);
801  if ( child_checkbox ) {
802  child_checkbox.checked = the_checkbox.checked;
803  this.handleServiceCheckBoxChanges(child_id);
804  };
805  };
806  };
807  };
808 
809  /************************************************************************************//**
810  * \brief This returns the Service body ID of the given Service body ID. *
811  * \returns an integer that is the ID of the parent Service body. *
812  ****************************************************************************************/
813  this.getServiceBodyParentID = function ( in_service_body_id
814  ) {
815  var the_object = null;
816 
817  for (var c = 0; c < g_service_bodies_array.length; c++) {
818  if ( g_service_bodies_array[c][0] == in_service_body_id ) {
819  the_object = g_service_bodies_array[c];
820  break;
821  };
822  };
823 
824  return the_object[1];
825  };
826 
827  /************************************************************************************//**
828  * \brief Returns an array of Service body objects that are direct descendants of the *
829  * given Service body, as specified by ID. *
830  * \returns an array of Service body objects. *
831  ****************************************************************************************/
832  this.getServiceBodyChildren = function ( in_service_body_id
833  ) {
834  var ret_array = null;
835 
836  for (var c = 0; c < g_service_bodies_array.length; c++) {
837  if ( this.getServiceBodyParentID(g_service_bodies_array[c][0]) == in_service_body_id ) {
838  if ( ! ret_array ) {
839  ret_array = new Array();
840  };
841 
842  ret_array[ret_array.length] = g_service_bodies_array[c];
843  };
844  };
845 
846  return ret_array;
847  };
848 
849  /************************************************************************************//**
850  * \brief Returns the name of the given Service body, by ID. *
851  * \returns a string. *
852  ****************************************************************************************/
853  this.getServiceBodyName = function ( in_service_body_id
854  ) {
855  var the_object = null;
856 
857  for (var c = 0; c < g_service_bodies_array.length; c++) {
858  if ( g_service_bodies_array[c][0] == in_service_body_id ) {
859  the_object = g_service_bodies_array[c];
860  break;
861  };
862  };
863 
864  return the_object[2];
865  };
866 
867  /************************************************************************************//**
868  * \brief Displays the Search Results or specifier, dependent upon the switch. *
869  ****************************************************************************************/
870  this.setSearchResultsVisibility = function () {
871  var search_specifier_div = document.getElementById('bmlt_admin_meeting_editor_form_specifier_div');
872  var search_results_div = document.getElementById('bmlt_admin_meeting_editor_form_results_div');
873 
874  if ( this.m_search_specifier_shown ) {
875  search_specifier_div.className = 'bmlt_admin_meeting_editor_form_specifier_div';
876  search_results_div.className = 'bmlt_admin_meeting_editor_form_results_div item_hidden';
877  } else {
878  search_specifier_div.className = 'bmlt_admin_meeting_editor_form_specifier_div item_hidden';
879  search_results_div.className = 'bmlt_admin_meeting_editor_form_results_div';
880  };
881  };
882 
883  // #mark -
884  // #mark Do A Meeting Search
885  // #mark -
886 
887  /************************************************************************************//**
888  * \brief Reacts to the "Search For Meetings" button being hit. *
889  ****************************************************************************************/
890  this.searchForMeetings = function () {
891  var button_span = document.getElementById('bmlt_admin_meeting_search_ajax_button_span');
892  var throbber_span = document.getElementById('bmlt_admin_meeting_search_ajax_button_throbber_span');
893 
894  var uri = this.createSearchURI();
895 
896  button_span.className = 'bmlt_admin_value_left item_hidden';
897  throbber_span.className = 'bmlt_admin_value_left';
898 
899  this.clearSearchResults();
900  this.callRootServerForMeetingSearch(uri);
901  };
902 
903 
904  /************************************************************************************//**
905  * \brief Clears any previous search results. *
906  ****************************************************************************************/
907  this.clearSearchResults = function () {
908  var the_outer_container = document.getElementById('bmlt_admin_meeting_editor_form_results_inner_div');
909  var the_main_results_display = document.getElementById('bmlt_admin_meeting_editor_form_results_div');
910 
911  if ( this.m_meeting_results_container_div ) { // Make sure we're starting from scratch.
912  this.m_meeting_results_container_div.innerHTML = '';
913  this.m_meeting_results_container_div = null;
914  };
915 
916  the_outer_container.innerHTML = '';
917  the_main_results_display.className = 'bmlt_admin_meeting_editor_form_results_div item_hidden"';
918 
919  this.m_search_results = null;
920  };
921 
922  /************************************************************************************//**
923  * \brief This function constructs a URI to the root server that reflects the search *
924  * parameters, as specified by the search specification section. *
925  * \returns a string, containing the complete URI. *
926  ****************************************************************************************/
927  this.createSearchURI = function () {
928  var uri = g_ajax_callback_uri + '&do_meeting_search=1&sort_key=time&simple_other_fields=1';
929 
930  var search_string = document.getElementById('bmlt_admin_text_specifier_input').value;
931 
932  if ( search_string == document.getElementById('bmlt_admin_text_specifier_input').defaultValue ) {
933  search_string = null;
934  };
935 
936  var is_location = document.getElementById('bmlt_admin_meeting_search_text_is_a_location_checkbox').checked;
937  var weekdays = new Array;
938 
939  if ( !document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_0').checked ) {
940  for (var c = 1; c < 8; c++) {
941  if ( document.getElementById('bmlt_admin_meeting_search_weekday_checkbox_' + c).checked ) {
942  weekdays[weekdays.length] = c;
943  };
944  };
945  };
946 
947  var service_bodies = new Array();
948 
949  if ( g_service_bodies_array.length > 1 ) {
950  for (var c = 0; c < g_service_bodies_array.length; c++) {
951  var service_body_id = g_service_bodies_array[c][0];
952  var sb_checkbox = document.getElementById('bmlt_admin_meeting_search_service_body_checkbox_' + service_body_id);
953  if ( sb_checkbox && sb_checkbox.checked ) {
954  service_bodies[service_bodies.length] = service_body_id;
955  };
956  };
957  } else {
958  service_bodies[0] = g_service_bodies_array[0][0];
959  };
960 
961  var starts_after = new Array();
962  var starts_before = new Array();
963 
964  if ( document.getElementById('bmlt_admin_meeting_search_start_time_morn_checkbox').checked ) {
965  starts_after = new Array(0, 0);
966  starts_before = new Array(12, 0);
967  } else if ( document.getElementById('bmlt_admin_meeting_search_start_time_aft_checkbox').checked ) {
968  starts_after = new Array(11, 59);
969  starts_before = new Array(18, 0);
970  } else if ( document.getElementById('bmlt_admin_meeting_search_start_time_eve_checkbox').checked ) {
971  starts_after = new Array(17, 59);
972  starts_before = new Array(23, 59);
973  };
974 
975  if ( search_string ) {
976  uri += '&SearchStringAll=1&SearchString=' + encodeURIComponent(search_string) + (is_location ? '&StringSearchIsAnAddress=1' : '');
977  };
978 
979  if ( weekdays.length ) {
980  for (var c = 0; c < weekdays.length; c++) {
981  uri += '&weekdays[]=' + parseInt(weekdays[c], 10);
982  };
983  };
984 
985  if ( service_bodies.length ) {
986  for (var c = 0; c < service_bodies.length; c++) {
987  uri += '&services[]=' + parseInt(service_bodies[c], 10);
988  };
989  };
990 
991  if ( starts_after.length ) {
992  uri += '&StartsAfterH=' + starts_after[0];
993  uri += '&StartsAfterM=' + starts_after[1];
994  };
995 
996  if ( starts_before.length ) {
997  uri += '&StartsBeforeH=' + starts_before[0];
998  uri += '&StartsBeforeM=' + starts_before[1];
999  };
1000 
1001  var pub_select = document.getElementById('bmlt_admin_single_meeting_editor_template_meeting_publish_search_select');
1002 
1003  if ( pub_select.value ) {
1004  uri += '&advanced_published=' + pub_select.value;
1005  };
1006 
1007  return uri;
1008  };
1009 
1010  /************************************************************************************//**
1011  * \brief Does an AJAX call for a JSON response, based on the given criteria and *
1012  * callback function. *
1013  * The callback will be a function in the following format: *
1014  * function ajax_callback ( in_json_obj ) *
1015  * where "in_json_obj" is the response, converted to a JSON object. *
1016  * it will be null if the function failed. *
1017  ****************************************************************************************/
1018  this.callRootServerForMeetingSearch = function (in_uri ///< The URI to call (with all the parameters).
1019  ) {
1020  if ( this.m_ajax_request_in_progress ) {
1021  this.m_ajax_request_in_progress.abort();
1022  this.m_ajax_request_in_progress = null;
1023  };
1024 
1025  var salt = new Date();
1026  in_uri += '&salt=' + salt.getTime();
1027 
1028  this.m_ajax_request_in_progress = BMLT_AjaxRequest(in_uri, function (in_req) {
1029  admin_handler_object.meetingSearchResultsCallback(in_req); }, 'post');
1030  };
1031 
1032  /************************************************************************************//**
1033  * \brief This is the meeting search results callback. *
1034  ****************************************************************************************/
1035  this.meetingSearchResultsCallback = function ( in_response_object ///< The HTTPRequest response object.
1036  ) {
1037  var button_span = document.getElementById('bmlt_admin_meeting_search_ajax_button_span');
1038  var throbber_span = document.getElementById('bmlt_admin_meeting_search_ajax_button_throbber_span');
1039  var text_reply = in_response_object.responseText;
1040 
1041  throbber_span.className = 'bmlt_admin_value_left item_hidden';
1042  button_span.className = 'bmlt_admin_value_left';
1043 
1044  if ( text_reply ) {
1045  var json_builder = 'var response_object = ' + text_reply + ';';
1046 
1047  // This is how you create JSON objects.
1048  eval(json_builder);
1049 
1050  if ( response_object.length ) {
1051  this.processSearchResults(response_object);
1052  location.hash = '#bmlt_admin_meeting_editor_form_results_banner_div';
1053  } else {
1054  alert(g_no_search_results_text);
1055  };
1056  } else {
1057  alert(g_no_search_results_text);
1058  };
1059  };
1060 
1061  /************************************************************************************//**
1062  * \brief This creates the meeting search results. *
1063  ****************************************************************************************/
1064  this.processSearchResults = function ( in_search_results_json_object ///< The search results, as a JSON object.
1065  ) {
1066  this.m_search_results = in_search_results_json_object;
1067 
1068  for (var c = 0; c < this.m_search_results.length; c++) {
1069  if ( this.m_search_results[c] ) {
1070  // The reason we do this whacky stuff, is that the formats may not be in the same order from the server as we keep them, so this little dance re-orders them.
1071  var format_array = new Array;
1072  var main_formats = g_format_object_array;
1073  var mtg_formats = this.m_search_results[c].formats.split(',');
1074 
1075  for (var i = 0; i < main_formats.length; i++) {
1076  for (var n = 0; n < mtg_formats.length; n++) {
1077  if ( main_formats[i].key == mtg_formats[n] ) {
1078  format_array[format_array.length] = mtg_formats[n];
1079  };
1080  };
1081  };
1082 
1083  this.m_search_results[c].formats = format_array.join(',');
1084 
1085  var dur = this.m_search_results[c].duration_time.split(':');
1086  dur[0] = parseInt(dur[0], 10);
1087  dur[1] = parseInt(dur[1], 10);
1088  this.m_search_results[c].duration_time = sprintf('%02d:%02d:00', dur[0], dur[1]);
1089  };
1090  };
1091 
1092  this.createMeetingList();
1093 
1094  this.selectMeetingEditorTab();
1095  };
1096 
1097  /************************************************************************************//**
1098  * \brief This creates the DOM tree of the meeting list.
1099  ****************************************************************************************/
1100  this.createMeetingList = function () {
1101  this.m_search_results.sort(admin_handler_object.sortSearchResultsCallback);
1102 
1103  var the_outer_container = document.getElementById('bmlt_admin_meeting_editor_form_results_inner_div');
1104  var the_results_header = document.getElementById('bmlt_admin_meeting_editor_form_results_banner_div');
1105  var the_main_results_display = document.getElementById('bmlt_admin_meeting_editor_form_results_div');
1106 
1107  if ( this.m_meeting_results_container_div ) {
1108  this.m_meeting_results_container_div.innerHTML = '';
1109  this.m_meeting_results_container_div = null;
1110  };
1111 
1112  the_outer_container.innerHTML = '';
1113  the_main_results_display.className = 'bmlt_admin_meeting_editor_form_results_div item_hidden"';
1114  this.m_meeting_results_container_div = document.createElement('div'); // Create the container element.
1115  this.m_meeting_results_container_div.className = 'bmlt_admin_meeting_search_results_container_div';
1116 
1117  for (var c = 0; c < this.m_search_results.length; c++) {
1118  if ( this.m_search_results[c] ) {
1119  var outer_meeting_div = document.createElement('div'); // Create the container element.
1120  outer_meeting_div.meeting_id = this.m_search_results[c].id_bigint;
1121  outer_meeting_div.className = 'bmlt_admin_meeting_search_results_single_meeting_outer_container_' + ((this.m_search_results[c].published != '0') ? 'published' : 'unpublished') + '_div';
1122 
1123  var single_meeting_div = document.createElement('div'); // Create the container element.
1124  single_meeting_div.meeting_id = this.m_search_results[c].id_bigint;
1125  single_meeting_div.className = 'bmlt_admin_meeting_search_results_single_meeting_container_div' + ((c % 2) ? ' meeting_line_odd' : ' meeting_line_even');
1126  single_meeting_div.id = 'bmlt_admin_meeting_search_results_single_meeting_' + single_meeting_div.meeting_id +'_div';
1127 
1128  this.createOneMeetingNode(single_meeting_div, this.m_search_results[c]);
1129 
1130  outer_meeting_div.appendChild(single_meeting_div);
1131 
1132  this.m_meeting_results_container_div.appendChild(outer_meeting_div);
1133  };
1134  };
1135 
1136  var breaker_breaker_rubber_duck = document.createElement('div'); // This is a break element.
1137  breaker_breaker_rubber_duck.className = 'clear_both';
1138  this.m_meeting_results_container_div.appendChild(breaker_breaker_rubber_duck);
1139 
1140  the_outer_container.appendChild(this.m_meeting_results_container_div);
1141  the_main_results_display.className = 'bmlt_admin_meeting_editor_form_results_div"';
1142 
1143  the_results_header.innerHTML = (this.m_search_results.length > 1) ? sprintf(g_meeting_editor_result_count_format, this.m_search_results.length) : '';
1144  };
1145 
1146  /************************************************************************************//**
1147  * \brief Sorts the search results by weekday, then time.
1148  ****************************************************************************************/
1149  this.sortSearchResultsCallback = function (
1150  in_object_a,
1151  in_object_b
1152  ) {
1153  if ( in_object_a && in_object_b ) {
1154  var a_start = in_object_a.start_time.toString().split(':');
1155  var b_start = in_object_b.start_time.toString().split(':');
1156  var a_time = (parseInt(in_object_a.weekday_tinyint, 10) * 100000) + (parseInt(a_start[0], 10) * 100) + parseInt(a_start[1], 10);
1157  var b_time = (parseInt(in_object_b.weekday_tinyint, 10) * 100000) + (parseInt(b_start[0], 10) * 100) + parseInt(b_start[1], 10);
1158 
1159  return (a_time > b_time) ? 1 : ((a_time < b_time) ? -1 : 0);
1160  } else if ( in_object_a && !in_object_b ) {
1161  return -1;
1162  } else if ( in_object_b && !in_object_a ) {
1163  return 1;
1164  };
1165 
1166  return 0;
1167  };
1168 
1169  /************************************************************************************//**
1170  * \brief
1171  ****************************************************************************************/
1172  this.createOneMeetingNode = function (
1173  in_single_meeting_div, ///< The containing div element.
1174  in_meeting_object ///< The meeting object.
1175  ) {
1176  var meeting_editorLink = document.createElement('a');
1177  meeting_editorLink.href = 'javascript:admin_handler_object.toggleMeetingSingleEditor(' + in_meeting_object.id_bigint + ', false)';
1178  meeting_editorLink.className = 'bmlt_admin_meeting_search_results_single_meeting_a';
1179 
1180  var element_span = document.createElement('span'); // Create the container element.
1181  element_span.className = 'bmlt_admin_meeting_search_results_single_meeting_weekday_span';
1182  var text_node = document.createTextNode(g_weekday_name_array[in_meeting_object.weekday_tinyint - 1]);
1183  element_span.appendChild(text_node);
1184  meeting_editorLink.appendChild(element_span);
1185 
1186  element_span = document.createElement('span'); // Create the container element.
1187  element_span.className = 'bmlt_admin_meeting_search_results_single_meeting_start_time_span';
1188  var start_time = in_meeting_object.start_time;
1189  var start_time = in_meeting_object.start_time.toString().split(':');
1190  var hours = 0;
1191  var minutes = 0;
1192  var midnight = false;
1193  var noon = false;
1194  var pm = false;
1195 
1196  if ( start_time && (start_time.length > 1) ) {
1197  var hours = parseInt(start_time[0], 10);
1198  var minutes = parseInt(start_time[1], 10);
1199  var midnight = false;
1200  var noon = false;
1201  var pm = false;
1202 
1203  if ( (hours == 23) && (minutes > 55) ) {
1204  midnight = true;
1205  } else {
1206  if ( (hours == 12) && (minutes == 0) ) {
1207  noon = true;
1208  } else {
1209  if ( hours > 23 ) {
1210  hours = 23;
1211  };
1212 
1213  if ( hours < 0 ) {
1214  hours = 0;
1215  };
1216 
1217  if ( minutes > 59 ) {
1218  minutes = 59;
1219  };
1220 
1221  if ( minutes < 0 ) {
1222  minutes = 0;
1223  };
1224 
1225  if ( minutes % g_default_minute_interval ) {
1226  minutes += g_default_minute_interval;
1227 
1228  if ( minutes >= 60 ) {
1229  hours++;
1230  minutes -= 60;
1231  };
1232  };
1233  };
1234  };
1235 
1236  if ( hours > 12 ) {
1237  hours -= 12;
1238  pm = true;
1239  } else if ( (hours == 12) && (minutes > 0) ) {
1240  pm = true;
1241  };
1242  };
1243 
1244  if ( midnight ) {
1245  start_time = g_time_values[3];
1246  } else if ( noon ) {
1247  start_time = g_time_values[2];
1248  } else {
1249  start_time = sprintf('%d:%02d %s', hours, minutes, (pm ? g_time_values[1] : g_time_values[0]));
1250  };
1251 
1252  text_node = document.createTextNode(start_time);
1253  element_span.appendChild(text_node);
1254  meeting_editorLink.appendChild(element_span);
1255 
1256  element_span = document.createElement('span'); // Create the container element.
1257  element_span.className = 'bmlt_admin_meeting_search_results_single_meeting_meeting_name_span';
1258  text_node = document.createTextNode(in_meeting_object.meeting_name + (in_meeting_object.location_street ? ', ' + in_meeting_object.location_street : '') + (in_meeting_object.location_city_subsection ? ', ' + in_meeting_object.location_city_subsection : '') + (in_meeting_object.location_municipality ? ', ' + in_meeting_object.location_municipality : '') + (in_meeting_object.location_province ? ', ' + in_meeting_object.location_province : '') + (in_meeting_object.location_sub_province ? ', (' + in_meeting_object.location_sub_province + ')' : '') + (in_meeting_object.location_postal_code_1 ? ', ' + in_meeting_object.location_postal_code_1 : ''));
1259  element_span.appendChild(text_node);
1260  meeting_editorLink.appendChild(element_span);
1261 
1262  in_single_meeting_div.appendChild(meeting_editorLink);
1263  var breaker_breaker_rubber_duck = document.createElement('div'); // This is a break element.
1264  breaker_breaker_rubber_duck.className = 'clear_both';
1265  in_single_meeting_div.appendChild(breaker_breaker_rubber_duck);
1266  };
1267 
1268  // #mark -
1269  // #mark Edit Meetings Tab
1270  // #mark -
1271 
1272  /************************************************************************************//**
1273  * \brief Selects the meeting editor tab. *
1274  ****************************************************************************************/
1275  this.selectMeetingEditorTab = function () {
1276  var tab_specifier_element = document.getElementById('bmlt_admin_meeting_editor_tab_specifier_div');
1277  var tab_editor_element = document.getElementById('bmlt_admin_meeting_editor_tab_results_div');
1278  var tab_specifier_link = document.getElementById('bmlt_admin_meeting_editor_tab_specifier_a');
1279  var tab_editor_link = document.getElementById('bmlt_admin_meeting_editor_tab_results_a');
1280  var search_specifier_element = document.getElementById('bmlt_admin_meeting_editor_form_specifier_div');
1281  var meeting_editor_element = document.getElementById('bmlt_admin_meeting_editor_form_div');
1282 
1283  tab_specifier_element.className = 'bmlt_admin_tab_div_left bmlt_admin_tab_div_not_selected';
1284  tab_editor_element.className = 'bmlt_admin_tab_div_right bmlt_admin_tab_div_selected';
1285 
1286  tab_specifier_link.setAttribute('href', '');
1287  tab_specifier_link.href = 'javascript:admin_handler_object.selectSearchSpecifierTab()';
1288  tab_editor_link.removeAttribute("href");
1289 
1290  search_specifier_element.className = 'bmlt_admin_meeting_editor_form_specifier_div item_hidden';
1291  meeting_editor_element.className = 'bmlt_admin_meeting_editor_form_div';
1292  }
1293 
1294  /************************************************************************************//**
1295  * \brief Brings up a new meeting screen. *
1296  ****************************************************************************************/
1297  this.toggleMeetingSingleEditor = function (
1298  in_meeting_id,
1299  in_no_confirm
1300  ) {
1301  var display_parent = document.getElementById('bmlt_admin_meeting_search_results_single_meeting_' + in_meeting_id + '_div');
1302 
1303  if ( display_parent ) {
1304  if ( !display_parent.meeting_editor_object ) {
1305  var proceed = true;
1306  if ( !in_no_confirm && (this.m_editing_window_open != null) && this.isMeetingDirty(this.m_editing_window_open.meeting_id) ) {
1307  proceed = confirm(g_meeting_editor_already_editing_confirm);
1308  };
1309 
1310  if ( proceed ) {
1311  if ( this.m_editing_window_open != null ) {
1312  if ( this.m_editing_window_open.meeting_editor_object && (this.m_editing_window_open.meeting_editor_object.parentNode == this.m_editing_window_open) ) {
1313  this.m_editing_window_open.removeChild(this.m_editing_window_open.meeting_editor_object);
1314  this.m_editing_window_open.meeting_editor_object = null;
1315  } else {
1316  document.getElementById('bmlt_admin_meeting_editor_new_meeting_0_editor_display').className = 'item_hidden';
1317  document.getElementById('bmlt_admin_meeting_editor_form_meeting_0_button').className = 'bmlt_admin_ajax_button button';
1318  };
1319 
1320  this.m_editing_window_open = null;
1321  };
1322 
1323  display_parent.meeting_editor_object = document.createElement('div'); // Create the container element.
1324  display_parent.meeting_editor_object.className = 'bmlt_admin_meeting_search_results_editor_container_div';
1325  display_parent.appendChild(display_parent.meeting_editor_object);
1326  display_parent.meeting_id = in_meeting_id;
1327 
1328  this.m_editing_window_open = display_parent;
1329  this.createNewMeetingEditorScreen(display_parent.meeting_editor_object, in_meeting_id);
1330  location.hash = '#bmlt_admin_meeting_search_results_single_meeting_' + parseInt(in_meeting_id, 10) + '_div';
1331  };
1332  } else {
1333  var proceed = true;
1334  if ( !in_no_confirm && (this.m_editing_window_open != null) && this.isMeetingDirty(this.m_editing_window_open.meeting_id) ) {
1335  proceed = confirm(g_meeting_closure_confirm_text);
1336  };
1337 
1338  if ( proceed ) {
1339  if ( display_parent.meeting_editor_object && (display_parent.meeting_editor_object.parentNode == display_parent) ) {
1340  display_parent.removeChild(display_parent.meeting_editor_object);
1341  };
1342 
1343  this.m_editing_window_open.meeting_id = null;
1344  display_parent.meeting_editor_object = null;
1345  };
1346  };
1347  };
1348  };
1349 
1350  /************************************************************************************//**
1351  * \brief Brings up a new meeting screen. *
1352  ****************************************************************************************/
1353  this.createANewMeetingButtonHit = function ( in_button_object
1354  ) {
1355  var display_parent = document.getElementById('bmlt_admin_meeting_editor_new_meeting_0_editor_display');
1356  var new_meeting_button = document.getElementById('bmlt_admin_meeting_editor_form_meeting_0_button');
1357 
1358  display_parent.innerHTML = '';
1359 
1360  var proceed = true;
1361  if ( (this.m_editing_window_open != null) && this.isMeetingDirty(this.m_editing_window_open.meeting_id) ) {
1362  proceed = confirm(g_meeting_editor_already_editing_confirm);
1363  };
1364 
1365  if ( proceed ) {
1366  if ( this.m_editing_window_open != null ) {
1367  this.cancelMeetingEdit(this.m_editing_window_open.meeting_id, true);
1368  };
1369 
1370  this.createNewMeetingEditorScreen(display_parent, 0);
1371 
1372  new_meeting_button.className = 'bmlt_admin_ajax_button button item_hidden';
1373  display_parent.className = 'bmlt_admin_meeting_editor_meeting_editor_display';
1374  this.changeSaveMeetingButtonToCopy(0);
1375 
1376  this.m_editing_window_open = document.getElementById('bmlt_admin_single_meeting_editor_0_div');
1377  this.m_editing_window_open.meeting_id = 0;
1378  };
1379  };
1380 
1381  /************************************************************************************//**
1382  * \brief
1383  ****************************************************************************************/
1384  this.changeSaveMeetingButtonToCopy = function ( in_meeting_id ///< The BMLT ID of the meeting that is being edited.
1385  ) {
1386  var save_button = document.getElementById('bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id +'_save_button');
1387  save_button.innerHTML = g_Create_new_meeting_button_name;
1388  this.validateMeetingEditorButton(in_meeting_id);
1389  };
1390 
1391  /************************************************************************************//**
1392  * \brief
1393  ****************************************************************************************/
1394  this.changeCopyMeetingButtonToSave = function ( in_meeting_id ///< The BMLT ID of the meeting that is being edited.
1395  ) {
1396  var save_button = document.getElementById('bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id +'_save_button');
1397  save_button.innerHTML = g_Save_meeting_button_name;
1398  this.validateMeetingEditorButton(in_meeting_id);
1399  };
1400 
1401  /************************************************************************************//**
1402  * \brief Validate meeting data before it can be saved.
1403  ****************************************************************************************/
1404  this.checkURL = function(string) {
1405  let url;
1406  try {
1407  url = new URL(string);
1408  } catch (_) {
1409  return false;
1410  }
1411  return ["http:", "https:", "teamspeak:"].includes(url.protocol);
1412  }
1413 
1414  this.validateMeetingDetails = function ( in_meeting_id ) {
1415  var errors = [];
1416  var warnings = [];
1417  var show_warnings = false;
1418  var venue_type = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_venue_type").find("input:radio[name=venue_type]:checked").val();
1419  var isInpersonOrHybrid = venue_type === 'inperson' || venue_type === 'hybrid';
1420  var isVirtualOrHybrid = venue_type === 'virtual' || venue_type === 'virtualTC' || venue_type === 'hybrid';
1421  var street = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_street_text_input").val().trim();
1422  var city = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_city_text_input").val().trim();
1423  // the state might be specified either as a text field, or selected from a list of options
1424  var s = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_state_text_input");
1425  if (s.length==0) {
1426  s = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_state_select_input");
1427  }
1428  var state = s.val().trim();
1429  var zip = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_zip_text_input").val().trim();
1430  var url = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_virtual_meeting_link_text_input").val().trim();
1431  var phone = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_phone_meeting_number_text_input").val().trim();
1432  var additional = $("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_virtual_meeting_additional_info_text_input").val().trim();
1433 
1434  $(".error_helper_text").remove();
1435  $(".warn_helper_text").remove();
1436  // Error checks as follows:
1437  // - One of the radio buttons for venue_type must be checked
1438  // - Virtual or Hybrid meetings must have at least one of a URL, phone number, or Virtual Meeting Additional Information
1439  // - Virtual Meeting Link must contains a valid URL if it's non-empty
1440  if (venue_type == null) {
1441  errors.push(this.setValidationMessage("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_venue_type",
1442  "meeting_editor_screen_meeting_venue_type_validation",
1443  this.validationMessageTypes.ERROR));
1444  }
1445 
1446  if (isVirtualOrHybrid && url === '' && phone === '' && additional === '') {
1447  // use "_meeting_virtual_meeting_additional_info_text_input" instead of "_meeting_virtual_meta" to position this error under the additional info field
1448  errors.push(this.setValidationMessage("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_virtual_meta",
1449  "meeting_editor_screen_meeting_virtual_info_missing",
1450  this.validationMessageTypes.ERROR,
1451  true));
1452  }
1453 
1454  // require that the virtual meeting link contains a valid URL if it's non-empty
1455  if (url !== '' && !this.checkURL(url)) {
1456  errors.push(this.setValidationMessage("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_virtual_meeting_link_text_input",
1457  "meeting_editor_screen_meeting_url_validation",
1458  this.validationMessageTypes.ERROR));
1459  }
1460 
1461  // Warnings as follows:
1462  // - Every meeting should have some location information (minimally, either city/state or zip). Later this should probably be required.
1463  // - In-person and hybrid meetings should have a street address.
1464  // - Either Virtual Meeting Link or Phone Meeting Dial-in Number field should be filled in for a virtual or hybrid meeting.
1465  // - Virtual Meeting Additional Information should be filled in if there is a Virtual Meeting Link (only checked for virtual meetings).
1466  //
1467  // Notes about warnings:
1468  // - If there is something in Virtual Meeting Additional Information, there should also be something in either Virtual Meeting Link
1469  // or Phone Meeting Dial-in Number ... but we only need to warn about this if the meeting is a virtual or hybrid meeting. So we
1470  // don't actually need a separate check for this.
1471  //
1472 
1473  // check that there is either a city/state or a zip
1474  if ( !(city !== '' && state !== '' || zip !== '') ) {
1475  warnings.push(this.setValidationMessage("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_city_text_input",
1476  "meeting_editor_screen_meeting_location_warning",
1477  this.validationMessageTypes.WARN));
1478  }
1479 
1480  if (isInpersonOrHybrid) {
1481  if (street === '') {
1482  warnings.push(this.setValidationMessage("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_street_text_input",
1483  "meeting_editor_screen_meeting_address_warning",
1484  this.validationMessageTypes.WARN));
1485  }
1486  }
1487 
1488  if (isVirtualOrHybrid) {
1489  if (url === '' && phone === '') {
1490  // use "_meeting_virtual_meeting_additional_info_text_input" instead of "_meeting_virtual_meta" to position this warning under the additional info field
1491  warnings.push(this.setValidationMessage("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_virtual_meta",
1492  "meeting_editor_screen_meeting_url_or_phone_warning",
1493  this.validationMessageTypes.WARN,
1494  true));
1495  }
1496 
1497  if (url !== '' && additional === '') {
1498  warnings.push(this.setValidationMessage("#bmlt_admin_single_meeting_editor_" + in_meeting_id + "_meeting_virtual_meeting_additional_info_text_input",
1499  "meeting_editor_screen_meeting_additional_warning",
1500  this.validationMessageTypes.WARN));
1501  }
1502  }
1503 
1504  if (errors.length == 0 && warnings.length > 0) {
1505  var s = my_localized_strings['comdef_server_admin_strings']['meeting_editor_screen_meeting_validation_warning'];
1506  show_warnings = !confirm(s + "\n----------\n" + warnings.join("\n\n"));
1507  }
1508 
1509  return { "errors": errors, "warnings": warnings, "show_warnings": show_warnings };
1510  }
1511 
1512  // put an error or warning message in the appropriate spot in the DOM, and return the message
1513  this.setValidationMessage = function ( selector, resource, type, use_spacer = false ) {
1514  var r = my_localized_strings['comdef_server_admin_strings'][resource];
1515  var s = "<div class='" + type + "_helper_text'>" + r + "</div>";
1516  var t = (use_spacer ? "<div class='virtual_error_warn_spacer'>" + s + "</div>" : s);
1517  $(selector).parent().append(t);
1518  return r;
1519  }
1520 
1521  // put an error or warning message below the save button in the DOM along with a warning emoji
1522  this.setValidationSaveMessage = function ( selector, resource, type, messages ) {
1523  var r = my_localized_strings['comdef_server_admin_strings'][resource];
1524  var t = "<div class='save_error_spacer'><div class='" + type + "_helper_text'>" + "<table><tr><td class='error_emoji'>\u26A0 </td><td>" + r + messages + "</td></tr></table></div></div>";
1525  $(selector).parent().append(t);
1526  }
1527 
1528  /************************************************************************************//**
1529  * \brief
1530  ****************************************************************************************/
1531  this.saveMeeting = function ( in_meeting_id
1532  ) {
1533  if ( !in_meeting_id ) {
1534  in_meeting_id = 0; // Just to make sure...
1535  };
1536 
1537  var save_button = document.getElementById('bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id + '_save_button');
1538 
1539  if ( save_button.className == 'bmlt_admin_ajax_button button' ) {
1540  var root_element = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
1541  var new_meeting_id = in_meeting_id;
1542  var copy_checkbox = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_duplicate_checkbox');
1543  var throbber_span = document.getElementById('bmlt_admin_' + in_meeting_id + '_save_ajax_button_throbber_span');
1544  var save_a = document.getElementById('bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id + '_save_button');
1545  var meeting_sent = false;
1546 
1547  var validation = this.validateMeetingDetails(in_meeting_id);
1548  if ( validation.errors.length > 0 || validation.show_warnings ) {
1549  if ( validation.errors.length > 0 ) {
1550  this.setValidationSaveMessage('#bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id + '_save_button',
1551  'meeting_editor_screen_meeting_validation_failed',
1552  this.validationMessageTypes.ERROR,
1553  validation.errors.join(' '));
1554  }
1555  if (validation.warnings.length > 0) {
1556  this.setValidationSaveMessage('#bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id + '_save_button',
1557  'meeting_editor_screen_meeting_validation_warnings',
1558  this.validationMessageTypes.WARN,
1559  validation.warnings.join(' '));
1560  }
1561  return;
1562  }
1563 
1564  if ( !copy_checkbox.checked && new_meeting_id && this.m_search_results && this.m_search_results.length ) {
1565  for (var c = 0; c < this.m_search_results.length; c++) {
1566  if ( new_meeting_id == this.m_search_results[c].id_bigint ) {
1567  save_a.className = 'item_hidden';
1568  throbber_span.className = 'bmlt_admin_ajax_button_throbber_span';
1569  if (g_auto_geocoding_enabled && root_element.original_address_line !== this.getAddressLine(in_meeting_id)) {
1570  var sendMeetingToServer = this.sendMeetingToServer;
1571  this.lookupLocation(in_meeting_id, function () {
1572  sendMeetingToServer(in_meeting_id, false); });
1573  } else {
1574  this.sendMeetingToServer(in_meeting_id, false);
1575  }
1576  meeting_sent = true;
1577  break;
1578  }
1579  }
1580  }
1581 
1582  if ( !meeting_sent ) {
1583  save_a.className = 'item_hidden';
1584  throbber_span.className = 'bmlt_admin_ajax_button_throbber_span';
1585  if (g_auto_geocoding_enabled && root_element.original_address_line !== this.getAddressLine(in_meeting_id)) {
1586  var sendMeetingToServer = this.sendMeetingToServer;
1587  this.lookupLocation(in_meeting_id, function () {
1588  sendMeetingToServer(in_meeting_id, true); });
1589  } else {
1590  this.sendMeetingToServer(in_meeting_id, true);
1591  }
1592  }
1593  }
1594  };
1595 
1596  /************************************************************************************//**
1597  * \brief
1598  ****************************************************************************************/
1599  this.cancelMeetingEdit = function (
1600  in_meeting_id,
1601  in_no_confirm
1602  ) {
1603  if ( !this.isMeetingDirty(in_meeting_id) || (this.isMeetingDirty(in_meeting_id) && (in_no_confirm || confirm(g_meeting_closure_confirm_text))) ) {
1604  var parent_id = 'bmlt_admin_meeting_editor_new_meeting_' + in_meeting_id + '_editor_display';
1605 
1606  var display_parent = document.getElementById(parent_id);
1607 
1608  var editor = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
1609 
1610  if ( editor && editor.main_map ) {
1611  editor.main_map = null;
1612  };
1613 
1614  var map_div = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_map_div');
1615 
1616  if ( map_div ) {
1617  map_div.innerHTML = '';
1618  };
1619 
1620  if ( display_parent ) {
1621  if ( display_parent.m_ajax_request_in_progress ) {
1622  display_parent.m_ajax_request_in_progress.abort();
1623  display_parent.m_ajax_request_in_progress = null;
1624  };
1625 
1626  display_parent.innerHTML = '';
1627  display_parent.className = 'item_hidden';
1628 
1629  if ( in_meeting_id == 0 ) {
1630  var new_meeting_button = document.getElementById('bmlt_admin_meeting_editor_form_meeting_0_button');
1631  new_meeting_button.className = 'bmlt_admin_ajax_button button';
1632  };
1633 
1634  var mtg_window = document.getElementById('bmlt_admin_meeting_search_results_single_meeting_' + in_meeting_id + '_div');
1635 
1636  if ( mtg_window ) {
1637  if ( mtg_window.meeting_editor_object && mtg_window.meeting_editor_object.parentNode && (mtg_window.meeting_editor_object.parentNode == mtg_window) ) {
1638  mtg_window.removeChild(mtg_window.meeting_editor_object);
1639  };
1640 
1641  mtg_window.meeting_editor_object = null;
1642  };
1643 
1644  this.m_editing_window_open = null;
1645  } else {
1646  this.toggleMeetingSingleEditor(in_meeting_id, true);
1647  };
1648  };
1649  };
1650 
1651  /************************************************************************************//**
1652  * \brief
1653  ****************************************************************************************/
1654  this.deleteMeeting = function ( in_meeting_id
1655  ) {
1656  var confirm_str = g_meeting_editor_screen_delete_button_confirm;
1657 
1658  if ( confirm(confirm_str) ) {
1659  var root_element = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
1660 
1661  if ( root_element.m_ajax_request_in_progress ) {
1662  root_element.m_ajax_request_in_progress.abort();
1663  root_element.m_ajax_request_in_progress = null;
1664  };
1665 
1666  var uri = g_ajax_callback_uri + '&delete_meeting=' + in_meeting_id;
1667 
1668  var throbber_span = document.getElementById('bmlt_admin_' + in_meeting_id + '_delete_ajax_button_throbber_span');
1669  var delete_a = document.getElementById('bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id + '_delete_button');
1670  delete_a.className = 'item_hidden';
1671  throbber_span.className = 'bmlt_admin_ajax_button_throbber_span';
1672 
1673  var salt = new Date();
1674  uri += '&salt=' + salt.getTime();
1675 
1676  root_element.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req) {
1677  admin_handler_object.handleDeleteMeetingAJAXCallback(in_req); }, 'get');
1678  };
1679  };
1680 
1681  /************************************************************************************//**
1682  * \brief
1683  ****************************************************************************************/
1684  this.handleDeleteMeetingAJAXCallback = function (in_http_request
1685  ) {
1686  if ( in_http_request.responseText ) {
1687  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
1688  alert(g_AJAX_Auth_Failure);
1689  } else {
1690  eval('var json_object = ' + in_http_request.responseText + ';');
1691  };
1692  };
1693 
1694  if ( json_object ) {
1695  if ( json_object.success ) {
1696  for (var c = 0; c < this.m_search_results.length; c++) {
1697  if ( this.m_search_results[c].id_bigint == json_object.report ) {
1698  this.m_search_results[c] = null;
1699  this.m_search_results.splice(c, 1);
1700  break;
1701  };
1702  };
1703 
1704  this.cancelMeetingEdit(json_object.report, true);
1705  this.createMeetingList();
1706  BMLT_Admin_StartFader('bmlt_admin_fader_meeting_editor_delete_success_div', this.m_success_fade_duration);
1707  } else {
1708  BMLT_Admin_StartFader('bmlt_admin_fader_meeting_editor_delete_fail_div', this.m_failure_fade_duration);
1709  };
1710  } else {
1711  BMLT_Admin_StartFader('bmlt_admin_fader_meeting_editor_delete_fail_div', this.m_failure_fade_duration);
1712  };
1713  };
1714 
1715  /************************************************************************************//**
1716  * \brief
1717  ****************************************************************************************/
1718  this.isMeetingDirty = function (in_meeting_id ///< The BMLT ID of the meeting that will be dirtified.
1719  ) {
1720  var editor = document.getElementById('bmlt_admin_single_meeting_editor_' + parseInt(in_meeting_id, 10) + '_div');
1721 
1722  if ( editor && editor.meeting_object ) {
1723  var editor_object = JSON.stringify(editor.meeting_object);
1724  var original_object = JSON.stringify(this.getMeetingObjectById(in_meeting_id, false));
1725  return (editor_object != original_object);
1726  };
1727 
1728  return false;
1729  };
1730 
1731  /************************************************************************************//**
1732  * \brief
1733  ****************************************************************************************/
1734  this.validateMeetingEditorButton = function (in_meeting_id
1735  ) {
1736  var save_button = document.getElementById('bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id + '_save_button');
1737  var dup_checkbox = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_duplicate_checkbox');
1738 
1739  if ( save_button ) {
1740  var enable = this.isMeetingDirty(in_meeting_id) || ((in_meeting_id > 0) && dup_checkbox && dup_checkbox.checked);
1741  if ( enable ) {
1742  save_button.className = 'bmlt_admin_ajax_button button';
1743  } else {
1744  save_button.className = 'bmlt_admin_ajax_button button_disabled';
1745  };
1746  };
1747  };
1748 
1749  /************************************************************************************//**
1750  * \brief This is called to initiate an AJAX process to change the account settings. *
1751  ****************************************************************************************/
1752  this.sendMeetingToServer = function (
1753  in_meeting_id,
1754  is_new_meeting
1755  ) {
1756  var new_editor = document.getElementById('bmlt_admin_single_meeting_editor_' + parseInt(in_meeting_id, 10) + '_div');
1757 
1758  if ( is_new_meeting ) {
1759  new_editor.meeting_object.id_bigint = 0;
1760  };
1761 
1762  var serialized_meeting_object = JSON.stringify(new_editor.meeting_object);
1763 
1764  if ( is_new_meeting ) {
1765  new_editor.meeting_object.id_bigint = in_meeting_id;
1766  };
1767 
1768  var uri = g_ajax_callback_uri + '&set_meeting_change=' + encodeURIComponent(serialized_meeting_object);
1769 
1770  if ( new_editor.m_ajax_request_in_progress ) {
1771  new_editor.m_ajax_request_in_progress.abort();
1772  new_editor.m_ajax_request_in_progress = null;
1773  };
1774 
1775  var salt = new Date();
1776  uri += '&salt=' + salt.getTime();
1777 
1778  new_editor.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function ( in_req, in_orig_meeting_id ) {
1779  admin_handler_object.handleMeetingChangeAJAXCallback(in_req,in_orig_meeting_id); }, 'post', in_meeting_id);
1780  };
1781 
1782  /************************************************************************************//**
1783  * \brief This is called to initiate an AJAX process to change the account settings. *
1784  ****************************************************************************************/
1785  this.handleMeetingChangeAJAXCallback = function (
1786  in_http_request,
1787  in_orig_meeting_id
1788  ) {
1789  if ( in_http_request.responseText ) {
1790  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
1791  alert(g_AJAX_Auth_Failure);
1792  } else {
1793  eval('var json_object = ' + in_http_request.responseText + ';');
1794  };
1795  };
1796 
1797  if ( json_object ) {
1798  var meeting_changed = false;
1799 
1800  if ( json_object.error ) {
1801  alert(json_object.report);
1802  } else {
1803  if ( this.m_search_results ) {
1804  for (var c = 0; c < this.m_search_results.length; c++) {
1805  if ( this.m_search_results[c].id_bigint == json_object[0].id_bigint ) {
1806  this.m_search_results[c] = json_object[0];
1807  single_meeting_div_id = 'bmlt_admin_meeting_search_results_single_meeting_' + json_object[0].id_bigint +'_div';
1808 
1809  var single_meeting_div = document.getElementById(single_meeting_div_id);
1810 
1811  if ( single_meeting_div ) {
1812  single_meeting_div.innerHTML = '';
1813  this.createOneMeetingNode(single_meeting_div, this.m_search_results[c]);
1814  meeting_changed = true;
1815  };
1816 
1817  break;
1818  };
1819  };
1820  };
1821  };
1822 
1823  if ( !meeting_changed ) {
1824  if ( !this.m_search_results ) {
1825  this.m_search_results = new Array;
1826  };
1827 
1828  this.m_search_results[this.m_search_results.length] = json_object[0];
1829  BMLT_Admin_StartFader('bmlt_admin_fader_meeting_editor_add_success_div', this.m_success_fade_duration);
1830  } else {
1831  BMLT_Admin_StartFader('bmlt_admin_fader_meeting_editor_success_div', this.m_success_fade_duration);
1832  };
1833 
1834  this.cancelMeetingEdit(in_orig_meeting_id, true);
1835  this.createMeetingList();
1836  if (json_object && json_object[0] && json_object[0].id_bigint) {
1837  this.toggleMeetingSingleEditor(json_object[0].id_bigint);
1838  }
1839  } else {
1840  if ( in_orig_meeting_id ) {
1841  BMLT_Admin_StartFader('bmlt_admin_fader_meeting_editor_fail_div', this.m_failure_fade_duration);
1842  } else {
1843  BMLT_Admin_StartFader('bmlt_admin_fader_meeting_editor_add_fail_div', this.m_failure_fade_duration);
1844  };
1845  };
1846  };
1847 
1848  // #mark -
1849  // #mark Creating A New Meeting Editor
1850  // #mark -
1851 
1852  /************************************************************************************//**
1853  * \brief This creates a new meeting details editor screen. *
1854  * \returns A new DOM hierarchy with the initialized editor. *
1855  ****************************************************************************************/
1856  this.createNewMeetingEditorScreen = function (
1857  in_parent_element, ///< The parent element of the new instance.
1858  in_meeting_id ///< The BMLT ID of the meeting that will be edited. If null, then it is a new meeting.
1859  ) {
1860  // We first see if one already exists.
1861  var new_editor = document.getElementById('bmlt_admin_single_meeting_editor_' + parseInt(in_meeting_id, 10) + '_div');
1862 
1863  if ( !new_editor ) {
1864  var template_dom_list = document.getElementById('bmlt_admin_single_meeting_editor_template_div');
1865 
1866  var meeting_name_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_name_text_input';
1867  var meeting_cc_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_cc_text_input';
1868  var meeting_contact_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_contact_text_input';
1869 
1870  var meeting_location_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_location_text_input';
1871  var meeting_info_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_info_text_input';
1872  var meeting_street_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_street_text_input';
1873  var meeting_neighborhood_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_neighborhood_text_input';
1874  var meeting_borough_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_borough_text_input';
1875  var meeting_city_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_city_text_input';
1876  var meeting_county_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_county_text_input';
1877  var meeting_state_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_state_text_input';
1878  var meeting_zip_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_zip_text_input';
1879  var meeting_nation_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_nation_text_input';
1880  var meeting_longitude_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_longitude_text_input';
1881  var meeting_latitude_text_item_id = 'bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_latitude_text_input';
1882 
1883  if ( template_dom_list ) { // This makes an exact copy of the template (including IDs, so we'll need to change those).
1884  new_editor = template_dom_list.cloneNode(true);
1885  // This function replaces all of the spots that say "template" with the given ID. That gives us unique IDs.
1886  BMLT_Admin_changeTemplateIDToUseThisID(new_editor, in_meeting_id);
1887  new_editor.meeting_object = this.getMeetingObjectById(in_meeting_id, true);
1888  new_editor.map_disclosed = false;
1889 
1890  new_editor.className = 'bmlt_admin_single_meeting_editor_div';
1891 
1892  in_parent_element.appendChild(new_editor);
1893 
1894  this.handleTextInputLoad(document.getElementById(meeting_name_text_item_id));
1895  this.handleTextInputLoad(document.getElementById(meeting_cc_text_item_id), null, true);
1896  this.handleTextInputLoad(document.getElementById(meeting_contact_text_item_id));
1897  this.handleTextInputLoad(document.getElementById(meeting_location_text_item_id));
1898  this.handleTextInputLoad(document.getElementById(meeting_info_text_item_id));
1899  this.handleTextInputLoad(document.getElementById(meeting_street_text_item_id));
1900  this.handleTextInputLoad(document.getElementById(meeting_neighborhood_text_item_id));
1901  this.handleTextInputLoad(document.getElementById(meeting_borough_text_item_id));
1902  this.handleTextInputLoad(document.getElementById(meeting_city_text_item_id));
1903  this.handleTextInputLoad(document.getElementById(meeting_zip_text_item_id), null, true);
1904  this.handleTextInputLoad(document.getElementById(meeting_nation_text_item_id), null, true);
1905  this.handleTextInputLoad(document.getElementById(meeting_longitude_text_item_id), 0, true);
1906  this.handleTextInputLoad(document.getElementById(meeting_latitude_text_item_id), 0, true);
1907 
1908  var meeting_state_text_input = document.getElementById(meeting_state_text_item_id);
1909  if (meeting_state_text_input !== null) {
1910  this.handleTextInputLoad(meeting_state_text_input, null, g_auto_geocoding_enabled && g_county_auto_geocoding_enabled);
1911  }
1912 
1913  var meeting_county_text_input = document.getElementById(meeting_county_text_item_id);
1914  if (meeting_county_text_input !== null) {
1915  this.handleTextInputLoad(meeting_county_text_input, null, g_auto_geocoding_enabled && g_county_auto_geocoding_enabled);
1916  }
1917 
1918  var map_disclosure_a = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_map_disclosure_a');
1919  map_disclosure_a.href = 'javascript:admin_handler_object.toggleMeetingMapDisclosure(' + in_meeting_id + ')';
1920 
1921  var select_duplicate_checkbox = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_duplicate_checkbox');
1922  select_duplicate_checkbox.onchange = function () {
1923  var save_button = document.getElementById('bmlt_admin_meeting_editor_form_meeting_' + in_meeting_id + '_save_button');
1924  if ( this.checked ) {
1925  save_button.innerHTML = g_Create_new_meeting_button_name;
1926  } else {
1927  save_button.innerHTML = g_Save_meeting_button_name;
1928  };
1929 
1930  admin_handler_object.validateMeetingEditorButton(in_meeting_id);
1931  };
1932  };
1933  };
1934 
1935  this.populateMeetingEditorForm(new_editor);
1936  new_editor.original_address_line = this.getAddressLine(in_meeting_id);
1937  return new_editor;
1938  };
1939 
1940  /************************************************************************************//**
1941  * \brief
1942  ****************************************************************************************/
1943  this.populateMeetingEditorForm = function ( in_meeting_editor ///< This is the meeting editor object that will be set up for this meeting.
1944  ) {
1945  var meeting_object = in_meeting_editor.meeting_object;
1946  var meeting_id = meeting_object.id_bigint;
1947 
1948  if ( !meeting_id ) { // We add a header for the new meeting form.
1949  var template_header = document.getElementById('bmlt_admin_meeting_editor_' + meeting_id + '_meeting_header');
1950  template_header.innerHTML = g_new_meeting_header_text;
1951  };
1952 
1953  document.getElementById('bmlt_admin_meeting_id_' + meeting_id +'_display').innerHTML = meeting_id;
1954 
1955  var meeting_published_checkbox = document.getElementById('bmlt_admin_meeting_' + meeting_id + '_published_checkbox');
1956 
1957  var meeting_name_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_name_text_input');
1958  var meeting_cc_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_cc_text_input');
1959  var meeting_location_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_location_text_input');
1960  var meeting_info_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_info_text_input');
1961  var meeting_street_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_street_text_input');
1962  var meeting_neighborhood_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_neighborhood_text_input');
1963  var meeting_borough_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_borough_text_input');
1964  var meeting_city_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_city_text_input');
1965  var meeting_county_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_county_text_input');
1966  var meeting_county_select_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_county_select_input');
1967  var meeting_state_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_state_text_input');
1968  var meeting_state_select_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_state_select_input');
1969  var meeting_zip_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_zip_text_input');
1970  var meeting_nation_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_nation_text_input');
1971  var meeting_longitude_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_longitude_text_input');
1972  var meeting_latitude_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_latitude_text_input');
1973  var meeting_contact_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_contact_text_input');
1974 
1975  meeting_name_text_item.value = htmlspecialchars_decode(meeting_object.meeting_name ? meeting_object.meeting_name : meeting_name_text_item.value);
1976  this.setTextItemClass(meeting_name_text_item);
1977  meeting_name_text_item.onkeyup = function () {
1978  admin_handler_object.setItemValue(this, meeting_id, 'meeting_name')};
1979  meeting_name_text_item.onfocus = function () {
1980  admin_handler_object.handleTextInputFocus(this)};
1981  meeting_name_text_item.onblur = function () {
1982  admin_handler_object.handleTextInputBlur(this)};
1983  meeting_name_text_item.onpaste = function () {
1984  var input = this;
1985  setTimeout(function () {
1986  admin_handler_object.setItemValue(input, meeting_id, 'meeting_name'); }, 0);
1987  };
1988  meeting_name_text_item.oncut = function () {
1989  var input = this;
1990  setTimeout(function () {
1991  admin_handler_object.setItemValue(input, meeting_id, 'meeting_name'); }, 0);
1992  };
1993 
1994 
1995  meeting_cc_text_item.value = htmlspecialchars_decode(meeting_object.worldid_mixed ? meeting_object.worldid_mixed : meeting_cc_text_item.value);
1996  this.setTextItemClass(meeting_cc_text_item);
1997  meeting_cc_text_item.onkeyup = function () {
1998  admin_handler_object.setItemValue(this, meeting_id, 'worldid_mixed')};
1999  meeting_cc_text_item.onfocus = function () {
2000  admin_handler_object.handleTextInputFocus(this)};
2001  meeting_cc_text_item.onblur = function () {
2002  admin_handler_object.handleTextInputBlur(this)};
2003  meeting_cc_text_item.onpaste = function () {
2004  var input = this;
2005  setTimeout(function () {
2006  admin_handler_object.setItemValue(input, meeting_id, 'worldid_mixed'); }, 0);
2007  };
2008  meeting_cc_text_item.oncut = function () {
2009  var input = this;
2010  setTimeout(function () {
2011  admin_handler_object.setItemValue(input, meeting_id, 'worldid_mixed'); }, 0);
2012  };
2013 
2014 
2015  meeting_location_text_item.value = htmlspecialchars_decode(meeting_object.location_text ? meeting_object.location_text : meeting_location_text_item.value);
2016  this.setTextItemClass(meeting_location_text_item);
2017  meeting_location_text_item.onkeyup = function () {
2018  admin_handler_object.setItemValue(this, meeting_id, 'location_text')};
2019  meeting_location_text_item.onfocus = function () {
2020  admin_handler_object.handleTextInputFocus(this)};
2021  meeting_location_text_item.onblur = function () {
2022  admin_handler_object.handleTextInputBlur(this)};
2023  meeting_location_text_item.onpaste = function () {
2024  var input = this;
2025  setTimeout(function () {
2026  admin_handler_object.setItemValue(input, meeting_id, 'location_text'); }, 0);
2027  };
2028  meeting_location_text_item.oncut = function () {
2029  var input = this;
2030  setTimeout(function () {
2031  admin_handler_object.setItemValue(input, meeting_id, 'location_text'); }, 0);
2032  };
2033 
2034 
2035  meeting_info_text_item.value = htmlspecialchars_decode(meeting_object.location_info ? meeting_object.location_info : meeting_info_text_item.value);
2036  this.setTextItemClass(meeting_info_text_item);
2037  meeting_info_text_item.onkeyup = function () {
2038  admin_handler_object.setItemValue(this, meeting_id, 'location_info')};
2039  meeting_info_text_item.onfocus = function () {
2040  admin_handler_object.handleTextInputFocus(this)};
2041  meeting_info_text_item.onblur = function () {
2042  admin_handler_object.handleTextInputBlur(this)};
2043  meeting_info_text_item.onpaste = function () {
2044  var input = this;
2045  setTimeout(function () {
2046  admin_handler_object.setItemValue(input, meeting_id, 'location_info'); }, 0);
2047  };
2048  meeting_info_text_item.oncut = function () {
2049  var input = this;
2050  setTimeout(function () {
2051  admin_handler_object.setItemValue(input, meeting_id, 'location_info'); }, 0);
2052  };
2053 
2054  meeting_street_text_item.value = htmlspecialchars_decode(meeting_object.location_street ? meeting_object.location_street : meeting_street_text_item.value);
2055  this.setTextItemClass(meeting_street_text_item);
2056  meeting_street_text_item.onkeyup = function () {
2057  admin_handler_object.setItemValue(this, meeting_id, 'location_street')};
2058  meeting_street_text_item.onfocus = function () {
2059  admin_handler_object.handleTextInputFocus(this)};
2060  meeting_street_text_item.onblur = function () {
2061  admin_handler_object.handleTextInputBlur(this)};
2062  meeting_street_text_item.onpaste = function () {
2063  var input = this;
2064  setTimeout(function () {
2065  admin_handler_object.setItemValue(input, meeting_id, 'location_street'); }, 0);
2066  };
2067  meeting_street_text_item.oncut = function () {
2068  var input = this;
2069  setTimeout(function () {
2070  admin_handler_object.setItemValue(input, meeting_id, 'location_street'); }, 0);
2071  };
2072 
2073 
2074  meeting_neighborhood_text_item.value = htmlspecialchars_decode(meeting_object.location_neighborhood ? meeting_object.location_neighborhood : meeting_neighborhood_text_item.value);
2075  this.setTextItemClass(meeting_neighborhood_text_item);
2076  meeting_neighborhood_text_item.onkeyup = function () {
2077  admin_handler_object.setItemValue(this, meeting_id, 'location_neighborhood')};
2078  meeting_neighborhood_text_item.onfocus = function () {
2079  admin_handler_object.handleTextInputFocus(this)};
2080  meeting_neighborhood_text_item.onblur = function () {
2081  admin_handler_object.handleTextInputBlur(this)};
2082  meeting_neighborhood_text_item.onpaste = function () {
2083  var input = this;
2084  setTimeout(function () {
2085  admin_handler_object.setItemValue(input, meeting_id, 'location_neighborhood'); }, 0);
2086  };
2087  meeting_neighborhood_text_item.oncut = function () {
2088  var input = this;
2089  setTimeout(function () {
2090  admin_handler_object.setItemValue(input, meeting_id, 'location_neighborhood'); }, 0);
2091  };
2092 
2093 
2094  meeting_borough_text_item.value = htmlspecialchars_decode(meeting_object.location_city_subsection ? meeting_object.location_city_subsection : meeting_borough_text_item.value);
2095  this.setTextItemClass(meeting_borough_text_item);
2096  meeting_borough_text_item.onkeyup = function () {
2097  admin_handler_object.setItemValue(this, meeting_id, 'location_city_subsection')};
2098  meeting_borough_text_item.onfocus = function () {
2099  admin_handler_object.handleTextInputFocus(this)};
2100  meeting_borough_text_item.onblur = function () {
2101  admin_handler_object.handleTextInputBlur(this)};
2102  meeting_borough_text_item.onpaste = function () {
2103  var input = this;
2104  setTimeout(function () {
2105  admin_handler_object.setItemValue(input, meeting_id, 'location_city_subsection'); }, 0);
2106  };
2107  meeting_borough_text_item.oncut = function () {
2108  var input = this;
2109  setTimeout(function () {
2110  admin_handler_object.setItemValue(input, meeting_id, 'location_city_subsection'); }, 0);
2111  };
2112 
2113 
2114  meeting_city_text_item.value = htmlspecialchars_decode(meeting_object.location_municipality ? meeting_object.location_municipality : meeting_city_text_item.value);
2115  this.setTextItemClass(meeting_city_text_item);
2116  meeting_city_text_item.onkeyup = function () {
2117  admin_handler_object.setItemValue(this, meeting_id, 'location_municipality')};
2118  meeting_city_text_item.onfocus = function () {
2119  admin_handler_object.handleTextInputFocus(this)};
2120  meeting_city_text_item.onblur = function () {
2121  admin_handler_object.handleTextInputBlur(this)};
2122  meeting_city_text_item.onpaste = function () {
2123  var input = this;
2124  setTimeout(function () {
2125  admin_handler_object.setItemValue(input, meeting_id, 'location_municipality'); }, 0);
2126  };
2127  meeting_city_text_item.oncut = function () {
2128  var input = this;
2129  setTimeout(function () {
2130  admin_handler_object.setItemValue(input, meeting_id, 'location_municipality'); }, 0);
2131  };
2132 
2133 
2134  if (meeting_county_text_item !== null) {
2135  meeting_county_text_item.value = htmlspecialchars_decode(meeting_object.location_sub_province ? meeting_object.location_sub_province : meeting_county_text_item.value);
2136  this.setTextItemClass(meeting_county_text_item);
2137  meeting_county_text_item.onkeyup = function () {
2138  admin_handler_object.setItemValue(this, meeting_id, 'location_sub_province')};
2139  meeting_county_text_item.onfocus = function () {
2140  admin_handler_object.handleTextInputFocus(this)};
2141  meeting_county_text_item.onblur = function () {
2142  admin_handler_object.handleTextInputBlur(this)};
2143  meeting_county_text_item.onpaste = function () {
2144  var input = this;
2145  setTimeout(function () {
2146  admin_handler_object.setItemValue(input, meeting_id, 'location_sub_province');
2147  }, 0);
2148  };
2149  meeting_county_text_item.oncut = function () {
2150  var input = this;
2151  setTimeout(function () {
2152  admin_handler_object.setItemValue(input, meeting_id, 'location_sub_province');
2153  }, 0);
2154  };
2155  } else {
2156  if ( meeting_object.location_sub_province ) {
2157  for (var i = 0; i < meeting_county_select_item.options.length; i++) {
2158  var option = meeting_county_select_item.options[i];
2159  if ( option.value === meeting_object.location_sub_province ) {
2160  meeting_county_select_item.selectedIndex = i;
2161  break;
2162  }
2163  }
2164  }
2165  meeting_county_select_item.onchange = function () {
2166  admin_handler_object.reactToMeetingCountySelect(meeting_id);
2167  }
2168  }
2169 
2170 
2171  if (meeting_state_text_item !== null) {
2172  meeting_state_text_item.value = htmlspecialchars_decode(meeting_object.location_province ? meeting_object.location_province : meeting_state_text_item.value);
2173  this.setTextItemClass(meeting_state_text_item);
2174  meeting_state_text_item.onkeyup = function () {
2175  admin_handler_object.setItemValue(this, meeting_id, 'location_province')};
2176  meeting_state_text_item.onfocus = function () {
2177  admin_handler_object.handleTextInputFocus(this)};
2178  meeting_state_text_item.onblur = function () {
2179  admin_handler_object.handleTextInputBlur(this)};
2180  meeting_state_text_item.onpaste = function () {
2181  var input = this;
2182  setTimeout(function () {
2183  admin_handler_object.setItemValue(input, meeting_id, 'location_province');
2184  }, 0);
2185  };
2186  meeting_state_text_item.oncut = function () {
2187  var input = this;
2188  setTimeout(function () {
2189  admin_handler_object.setItemValue(input, meeting_id, 'location_province');
2190  }, 0);
2191  };
2192  } else {
2193  if ( meeting_object.location_province ) {
2194  for (var i = 0; i < meeting_state_select_item.options.length; i++) {
2195  var option = meeting_state_select_item.options[i];
2196  if ( option.value === meeting_object.location_province ) {
2197  meeting_state_select_item.selectedIndex = i;
2198  break;
2199  }
2200  }
2201  }
2202  meeting_state_select_item.onchange = function () {
2203  admin_handler_object.reactToMeetingStateSelect(meeting_id);}
2204  }
2205 
2206 
2207  meeting_zip_text_item.value = htmlspecialchars_decode(meeting_object.location_postal_code_1 ? meeting_object.location_postal_code_1 : meeting_zip_text_item.value);
2208  this.setTextItemClass(meeting_zip_text_item);
2209  meeting_zip_text_item.onkeyup = function () {
2210  admin_handler_object.setItemValue(this, meeting_id, 'location_postal_code_1')};
2211  meeting_zip_text_item.onfocus = function () {
2212  admin_handler_object.handleTextInputFocus(this)};
2213  meeting_zip_text_item.onblur = function () {
2214  admin_handler_object.handleTextInputBlur(this)};
2215  meeting_zip_text_item.onpaste = function () {
2216  var input = this;
2217  setTimeout(function () {
2218  admin_handler_object.setItemValue(input, meeting_id, 'location_postal_code_1'); }, 0);
2219  };
2220  meeting_zip_text_item.oncut = function () {
2221  var input = this;
2222  setTimeout(function () {
2223  admin_handler_object.setItemValue(input, meeting_id, 'location_postal_code_1'); }, 0);
2224  };
2225 
2226 
2227  meeting_nation_text_item.value = htmlspecialchars_decode(meeting_object.location_nation ? meeting_object.location_nation : meeting_nation_text_item.value);
2228  this.setTextItemClass(meeting_nation_text_item);
2229  meeting_nation_text_item.onkeyup = function () {
2230  admin_handler_object.setItemValue(this, meeting_id, 'location_nation')};
2231  meeting_nation_text_item.onfocus = function () {
2232  admin_handler_object.handleTextInputFocus(this)};
2233  meeting_nation_text_item.onblur = function () {
2234  admin_handler_object.handleTextInputBlur(this)};
2235  meeting_nation_text_item.onpaste = function () {
2236  var input = this;
2237  setTimeout(function () {
2238  admin_handler_object.setItemValue(input, meeting_id, 'location_nation'); }, 0);
2239  };
2240  meeting_nation_text_item.oncut = function () {
2241  var input = this;
2242  setTimeout(function () {
2243  admin_handler_object.setItemValue(input, meeting_id, 'location_nation'); }, 0);
2244  };
2245 
2246 
2247  meeting_longitude_text_item.value = htmlspecialchars_decode(meeting_object.longitude ? meeting_object.longitude : meeting_longitude_text_item.value);
2248  this.setTextItemClass(meeting_longitude_text_item);
2249  meeting_longitude_text_item.onkeyup = function () {
2250  admin_handler_object.setItemValue(this, meeting_id, 'longitude')};
2251  meeting_longitude_text_item.onfocus = function () {
2252  admin_handler_object.handleTextInputFocus(this)};
2253  meeting_longitude_text_item.onblur = function () {
2254  admin_handler_object.handleTextInputBlur(this)};
2255  meeting_longitude_text_item.onpaste = function () {
2256  var input = this;
2257  setTimeout(function () {
2258  admin_handler_object.setItemValue(input, meeting_id, 'longitude'); }, 0);
2259  };
2260  meeting_longitude_text_item.oncut = function () {
2261  var input = this;
2262  setTimeout(function () {
2263  admin_handler_object.setItemValue(input, meeting_id, 'longitude'); }, 0);
2264  };
2265 
2266 
2267  meeting_latitude_text_item.value = htmlspecialchars_decode(meeting_object.latitude ? meeting_object.latitude : meeting_latitude_text_item.value);
2268  this.setTextItemClass(meeting_latitude_text_item);
2269  meeting_latitude_text_item.onkeyup = function () {
2270  admin_handler_object.setItemValue(this, meeting_id, 'latitude')};
2271  meeting_latitude_text_item.onfocus = function () {
2272  admin_handler_object.handleTextInputFocus(this)};
2273  meeting_latitude_text_item.onblur = function () {
2274  admin_handler_object.handleTextInputBlur(this)};
2275  meeting_latitude_text_item.onpaste = function () {
2276  var input = this;
2277  setTimeout(function () {
2278  admin_handler_object.setItemValue(input, meeting_id, 'latitude'); }, 0);
2279  };
2280  meeting_latitude_text_item.oncut = function () {
2281  var input = this;
2282  setTimeout(function () {
2283  admin_handler_object.setItemValue(input, meeting_id, 'latitude'); }, 0);
2284  };
2285 
2286 
2287  meeting_contact_text_item.value = htmlspecialchars_decode(meeting_object.email_contact ? meeting_object.email_contact : meeting_contact_text_item.value);
2288  this.setTextItemClass(meeting_contact_text_item);
2289  meeting_contact_text_item.onkeyup = function () {
2290  admin_handler_object.setItemValue(this, meeting_id, 'email_contact')};
2291  meeting_contact_text_item.onfocus = function () {
2292  admin_handler_object.handleTextInputFocus(this)};
2293  meeting_contact_text_item.onblur = function () {
2294  admin_handler_object.handleTextInputBlur(this)};
2295  meeting_contact_text_item.onpaste = function () {
2296  var input = this;
2297  setTimeout(function () {
2298  admin_handler_object.setItemValue(input, meeting_id, 'email_contact'); }, 0);
2299  };
2300  meeting_contact_text_item.oncut = function () {
2301  var input = this;
2302  setTimeout(function () {
2303  admin_handler_object.setItemValue(input, meeting_id, 'email_contact'); }, 0);
2304  };
2305 
2306 
2307  meeting_published_checkbox.checked = (meeting_object ? true : false);
2308 
2309  this.setFormatCheckboxes(meeting_object);
2310  this.setWeekday(meeting_object);
2311  this.setMeetingStartTime(meeting_object);
2312  this.setMeetingDuration(meeting_object);
2313  if (g_meeting_time_zones_enabled) {
2314  this.setMeetingTimeZone(meeting_object);
2315  }
2316  this.setServiceBody(meeting_object);
2317  this.setUpOtherTab(meeting_object);
2318 
2319  this.setPublished(meeting_object);
2320  this.handleNewAddressInfo(meeting_id);
2321  this.setFormatCheckboxHandlers(meeting_object);
2322  };
2323 
2324  /************************************************************************************//**
2325  * \brief
2326  ****************************************************************************************/
2327  this.setMeetingStartTime = function (in_meeting_object
2328  ) {
2329  var meeting_id = in_meeting_object.id_bigint;
2330 
2331  var time_hour_select = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_start_hour_select');
2332  var time_minute_select = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_start_minute_select');
2333  var time_am_radio = document.getElementById('bmlt_admin_' + meeting_id + '_time_am_radio');
2334  var time_pm_radio = document.getElementById('bmlt_admin_' + meeting_id + '_time_pm_radio');
2335 
2336  var start_time = in_meeting_object.start_time.toString().split(':');
2337 
2338  if ( start_time && (start_time.length > 1) ) {
2339  var hours = parseInt(start_time[0], 10);
2340  var minutes = parseInt(start_time[1], 10);
2341  var midnight = false;
2342  var noon = false;
2343  var pm = false;
2344 
2345  if ( (hours == 23) && (minutes > 55) ) {
2346  midnight = true;
2347  } else {
2348  if ( (hours == 12) && (minutes == 0) ) {
2349  noon = true;
2350  } else {
2351  if ( hours > 23 ) {
2352  hours = 23;
2353  };
2354 
2355  if ( hours < 0 ) {
2356  hours = 0;
2357  };
2358 
2359  if ( minutes > 59 ) {
2360  minutes = 59;
2361  };
2362 
2363  if ( minutes < 0 ) {
2364  minutes = 0;
2365  };
2366 
2367  if ( minutes % g_default_minute_interval ) {
2368  minutes += g_default_minute_interval;
2369 
2370  if ( minutes >= 60 ) {
2371  hours++;
2372  minutes -= 60;
2373  };
2374  };
2375  };
2376  };
2377 
2378  if ( hours > 12 ) {
2379  hours -= 12;
2380  pm = true;
2381  } else if ( (hours == 0) && (minutes > 0) ) {
2382  pm = false;
2383  hours = 12;
2384  } else if ( (hours == 12) && (minutes > 0) ) {
2385  pm = true;
2386  };
2387  };
2388 
2389  if ( midnight ) {
2390  BMLT_Admin_setSelectByValue(time_minute_select, 0);
2391  BMLT_Admin_setSelectByValue(time_hour_select, 0);
2392  } else if ( noon ) {
2393  BMLT_Admin_setSelectByValue(time_hour_select, 13);
2394  BMLT_Admin_setSelectByValue(time_minute_select, 0);
2395  } else {
2396  BMLT_Admin_setSelectByValue(time_hour_select, hours);
2397  BMLT_Admin_setSelectByValue(time_minute_select, minutes);
2398  };
2399 
2400  if ( pm ) {
2401  time_am_radio.checked = false;
2402  time_pm_radio.checked = true;
2403  } else {
2404  time_pm_radio.checked = false;
2405  time_am_radio.checked = true;
2406  };
2407 
2408  this.reactToTimeSelect(meeting_id);
2409 
2410  time_hour_select.onchange = function () {
2411  admin_handler_object.reactToTimeSelect(meeting_id); };
2412  time_minute_select.onchange = function () {
2413  admin_handler_object.reactToTimeSelect(meeting_id); };
2414  time_am_radio.onchange = function () {
2415  admin_handler_object.reactToTimeSelect(meeting_id); };
2416  time_pm_radio.onchange = function () {
2417  admin_handler_object.reactToTimeSelect(meeting_id); };
2418  };
2419 
2420  /************************************************************************************//**
2421  * \brief
2422  ****************************************************************************************/
2423  this.setMeetingDuration = function ( in_meeting_object
2424  ) {
2425  var meeting_id = in_meeting_object.id_bigint;
2426 
2427  var time_hour_select = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_duration_hour_select');
2428  var time_minute_select = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_duration_minute_select');
2429 
2430  var duration_time = in_meeting_object.duration_time.split(':');
2431 
2432  if ( duration_time && (duration_time.length > 1) ) {
2433  var hours = parseInt(duration_time[0], 10);
2434  var minutes = parseInt(duration_time[1], 10);
2435  var oe = false;
2436 
2437  if ( hours == 24 ) {
2438  oe = true;
2439  } else {
2440  if ( minutes % g_default_minute_interval ) {
2441  minutes += g_default_minute_interval;
2442 
2443  if ( minutes >= 60 ) {
2444  hours++;
2445  minutes -= 60;
2446  };
2447  };
2448 
2449  if ( hours > 23 ) {
2450  hours = 23;
2451  };
2452 
2453  if ( hours < 0 ) {
2454  hours = 0;
2455  };
2456  };
2457  };
2458 
2459  if ( oe ) {
2460  BMLT_Admin_setSelectByValue(time_hour_select, 24);
2461  BMLT_Admin_setSelectByValue(time_minute_select, 0);
2462  } else {
2463  BMLT_Admin_setSelectByValue(time_hour_select, hours);
2464  BMLT_Admin_setSelectByValue(time_minute_select, minutes);
2465  };
2466 
2467  this.reactToDurationSelect(meeting_id);
2468 
2469  time_hour_select.onchange = function () {
2470  admin_handler_object.reactToDurationSelect(meeting_id); };
2471  };
2472 
2473  /************************************************************************************//**
2474  * \brief
2475  ****************************************************************************************/
2476  this.setMeetingTimeZone = function (in_meeting_object) {
2477  var meeting_id = in_meeting_object.id_bigint;
2478 
2479  var time_zone_select = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_time_zone_select');
2480 
2481  BMLT_Admin_setSelectByStringValue(time_zone_select, in_meeting_object.time_zone);
2482 
2483  this.reactToTimeZoneSelect(meeting_id);
2484 
2485  time_zone_select.onchange = function () { admin_handler_object.reactToTimeZoneSelect(meeting_id); }
2486  };
2487 
2488  /************************************************************************************//**
2489  * \brief
2490  ****************************************************************************************/
2491  this.setServiceBody = function (in_meeting_object
2492  ) {
2493  var meeting_id = in_meeting_object.id_bigint;
2494 
2495  var service_body_select = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_sb_select');
2496 
2497  if ( service_body_select ) {
2498  BMLT_Admin_setSelectByValue(service_body_select, in_meeting_object.service_body_bigint);
2499 
2500  this.reactToSBSelect(meeting_id);
2501 
2502  service_body_select.onchange = function () {
2503  admin_handler_object.reactToSBSelect(meeting_id); };
2504  };
2505  };
2506 
2507  /************************************************************************************//**
2508  * \brief
2509  ****************************************************************************************/
2510  this.setWeekday = function (in_meeting_object
2511  ) {
2512  var meeting_id = in_meeting_object.id_bigint;
2513 
2514  var weekday_select = document.getElementById('bmlt_admin_single_meeting_editor_' + meeting_id + '_meeting_weekday_select');
2515 
2516  BMLT_Admin_setSelectByValue(weekday_select, in_meeting_object.weekday_tinyint);
2517 
2518  this.reactToWeekdaySelect(meeting_id);
2519 
2520  weekday_select.onchange = function () {
2521  admin_handler_object.reactToWeekdaySelect(meeting_id); };
2522  };
2523 
2524  /************************************************************************************//**
2525  * \brief
2526  ****************************************************************************************/
2527  this.setPublished = function ( in_meeting_object
2528  ) {
2529  var meeting_id = in_meeting_object.id_bigint;
2530 
2531  var published_checkbox = document.getElementById('bmlt_admin_meeting_' + meeting_id + '_published_checkbox');
2532 
2533  published_checkbox.checked = in_meeting_object.published == '1';
2534 
2535  this.reactToPublishedCheck(meeting_id);
2536 
2537  published_checkbox.onchange = function () {
2538  admin_handler_object.reactToPublishedCheck(meeting_id); };
2539  published_checkbox.onclick = function () {
2540  admin_handler_object.reactToPublishedCheck(meeting_id); };
2541  };
2542 
2543  /************************************************************************************//**
2544  * \brief
2545  ****************************************************************************************/
2546  this.setFormatCheckboxHandlers = function ( in_meeting_object
2547  ) {
2548  var meeting_id = in_meeting_object.id_bigint;
2549  var main_formats = g_format_object_array;
2550 
2551  for (var c = 0; c < main_formats.length; c++) {
2552  var format_checkbox = document.getElementById('bmlt_admin_meeting_' + in_meeting_object.id_bigint + '_format_' + main_formats[c].id + '_checkbox');
2553 
2554  if ( format_checkbox ) {
2555  format_checkbox.onchange = function () {
2556  admin_handler_object.reactToFormatCheckbox(format_checkbox, meeting_id); };
2557  format_checkbox.onclick = function () {
2558  admin_handler_object.reactToFormatCheckbox(format_checkbox, meeting_id); };
2559  };
2560  };
2561  };
2562 
2563  // #mark -
2564  // #mark ########## Meeting Editor Internal Tabs ##########
2565  // #mark -
2566 
2567  /************************************************************************************//**
2568  * \brief Selects the meeting editor tab. *
2569  ****************************************************************************************/
2570  this.selectAnEditorTab = function (
2571  in_tab_index,
2572  in_meeting_id
2573  ) {
2574  var tabs = new Array(
2575  document.getElementById('bmlt_admin_meeting_editor_' + in_meeting_id + '_tab_item_basic_a'),
2576  document.getElementById('bmlt_admin_meeting_editor_' + in_meeting_id + '_tab_item_location_a'),
2577  document.getElementById('bmlt_admin_meeting_editor_' + in_meeting_id + '_tab_item_format_a'),
2578  document.getElementById('bmlt_admin_meeting_editor_' + in_meeting_id + '_tab_item_other_a'),
2579  document.getElementById('bmlt_admin_meeting_editor_' + in_meeting_id + '_tab_item_history_a')
2580  );
2581 
2582  var sheets = new Array(
2583  document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_basic_sheet_div'),
2584  document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_location_sheet_div'),
2585  document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_format_sheet_div'),
2586  document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_other_sheet_div'),
2587  document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_history_sheet_div')
2588  );
2589 
2590  for (var c = 0; c < tabs.length; c++) {
2591  var tab_class = '';
2592  var sheet_class = '';
2593 
2594  if ( c == in_tab_index ) {
2595  tab_class = 'bmlt_admin_meeting_editor_tab_item_a_selected';
2596  sheet_class = 'bmlt_admin_meeting_option_sheet_div';
2597  if ( c == 4 ) {
2598  this.openHistoryTab(in_meeting_id);
2599  };
2600  } else {
2601  tab_class = 'bmlt_admin_meeting_editor_tab_item_a_unselected';
2602  if ( c == 4 ) {
2603  tab_class += ' hide_in_new_meeting';
2604  };
2605  sheet_class = 'bmlt_admin_meeting_option_sheet_div item_hidden';
2606  };
2607 
2608  tabs[c].className = tab_class;
2609  sheets[c].className = sheet_class;
2610  };
2611  };
2612 
2613  // #mark -
2614  // #mark Basic Tab
2615  // #mark -
2616 
2617  /************************************************************************************//**
2618  * \brief
2619  ****************************************************************************************/
2620  this.respondToBasicTabSelection = function (in_meeting_id ///< The BMLT ID of the meeting that is being edited.
2621  ) {
2622  this.selectAnEditorTab(0);
2623  };
2624 
2625  /************************************************************************************//**
2626  * \brief
2627  ****************************************************************************************/
2628  this.reactToTimeSelect = function ( in_meeting_id ///< The meeting ID
2629  ) {
2630  var time_hour_select = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_start_hour_select');
2631  var time_items = document.getElementById('bmlt_admin_' + in_meeting_id + '_time_span');
2632  var time_pm_radio = document.getElementById('bmlt_admin_' + in_meeting_id + '_time_pm_radio');
2633  var time_minute_select = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_start_minute_select');
2634 
2635  time_items.className = 'bmlt_admin_time_span' + (( (time_hour_select.options[time_hour_select.selectedIndex].value == 0) || (time_hour_select.options[time_hour_select.selectedIndex].value == 13) ) ? ' item_hidden' : '');
2636 
2637  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2638  var the_meeting_object = editor_object.meeting_object;
2639 
2640  var timeval = '';
2641 
2642  if ( time_hour_select.options[time_hour_select.selectedIndex].value == 0 ) {
2643  timeval = '23:59:00';
2644  } else if ( time_hour_select.options[time_hour_select.selectedIndex].value == 13 ) {
2645  timeval = '12:00:00';
2646  } else {
2647  var hour = parseInt(time_hour_select.options[time_hour_select.selectedIndex].value, 10);
2648  var minute = parseInt(time_minute_select.options[time_minute_select.selectedIndex].value, 10)
2649 
2650  if ( time_pm_radio.checked && (hour != 12) ) {
2651  hour += 12;
2652  } else if ( !time_pm_radio.checked && (hour == 12) ) {
2653  hour = 0;
2654  }
2655 
2656  timeval = sprintf('%02d:%02d:00', hour, minute);
2657  };
2658 
2659  the_meeting_object.start_time = timeval;
2660  this.validateMeetingEditorButton(in_meeting_id);
2661  };
2662 
2663  /************************************************************************************//**
2664  * \brief
2665  ****************************************************************************************/
2666  this.reactToDurationSelect = function ( in_meeting_id ///< The meeting ID
2667  ) {
2668  var time_hour_select = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_duration_hour_select');
2669  var time_items = document.getElementById('bmlt_admin_' + in_meeting_id + '_duration_span');
2670 
2671  time_items.className = 'bmlt_admin_time_span' + ((time_hour_select.value == 24) ? ' item_hidden' : '');
2672 
2673  var time_minute_select = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_duration_minute_select');
2674  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2675  var the_meeting_object = editor_object.meeting_object;
2676  var timeval = '';
2677 
2678  if ( time_hour_select.options[time_hour_select.selectedIndex].value == 24 ) {
2679  timeval = '24:00:00';
2680  } else {
2681  timeval = sprintf('%02d:%02d:00', parseInt(time_hour_select.options[time_hour_select.selectedIndex].value, 10), parseInt(time_minute_select.options[time_minute_select.selectedIndex].value, 10));
2682  };
2683 
2684  the_meeting_object.duration_time = timeval;
2685  this.validateMeetingEditorButton(in_meeting_id);
2686  };
2687 
2688  this.reactToMeetingStateSelect = function (in_meeting_id) {
2689  var meeting_state_select_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_state_select_input');
2690  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2691  var the_meeting_object = editor_object.meeting_object;
2692  the_meeting_object.location_province = meeting_state_select_item.options[meeting_state_select_item.selectedIndex].value;
2693  this.handleNewAddressInfo(in_meeting_id);
2694  this.validateMeetingEditorButton(in_meeting_id);
2695  };
2696 
2697  this.reactToMeetingCountySelect = function (in_meeting_id) {
2698  var meeting_county_select_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_county_select_input');
2699  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2700  var the_meeting_object = editor_object.meeting_object;
2701  the_meeting_object.location_sub_province = meeting_county_select_item.options[meeting_county_select_item.selectedIndex].value;
2702  this.handleNewAddressInfo(in_meeting_id);
2703  this.validateMeetingEditorButton(in_meeting_id);
2704  };
2705 
2706  /************************************************************************************//**
2707  * \brief
2708  ****************************************************************************************/
2709  this.reactToSBSelect = function (in_meeting_id ///< The meeting ID
2710  ) {
2711  var service_body_select = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_sb_select');
2712 
2713  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2714  var the_meeting_object = editor_object.meeting_object;
2715 
2716  the_meeting_object.service_body_bigint = service_body_select.value.toString();
2717  this.validateMeetingEditorButton(in_meeting_id);
2718  };
2719 
2720  /************************************************************************************//**
2721  * \brief
2722  ****************************************************************************************/
2723  this.reactToPublishedCheck = function ( in_meeting_id ///< The meeting ID
2724  ) {
2725  var published_checkbox = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_published_checkbox');
2726 
2727  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2728  var the_meeting_object = editor_object.meeting_object;
2729  the_meeting_object.published = published_checkbox.checked ? '1' : '0';
2730 
2731  var unpublishedNoteDiv = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_unpublished_note_div');
2732  if (published_checkbox.checked) {
2733  unpublishedNoteDiv.className += ' item_hidden';
2734  } else {
2735  unpublishedNoteDiv.className = unpublishedNoteDiv.className.replace(" item_hidden", "");
2736  }
2737  this.validateMeetingEditorButton(in_meeting_id);
2738  };
2739 
2740  /************************************************************************************//**
2741  * \brief
2742  ****************************************************************************************/
2743  this.reactToWeekdaySelect = function ( in_meeting_id ///< The meeting ID
2744  ) {
2745  var weekday_select = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_weekday_select');
2746 
2747  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2748  var the_meeting_object = editor_object.meeting_object;
2749 
2750  the_meeting_object.weekday_tinyint = weekday_select.value.toString();
2751  this.validateMeetingEditorButton(in_meeting_id);
2752  };
2753 
2754  /************************************************************************************//**
2755  * \brief
2756  ****************************************************************************************/
2757  this.reactToTimeZoneSelect = function ( in_meeting_id ///< The meeting ID
2758  ) {
2759  var time_zone_select = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_time_zone_select');
2760 
2761  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2762  var the_meeting_object = editor_object.meeting_object;
2763 
2764  the_meeting_object.time_zone = time_zone_select.value.toString();
2765  this.validateMeetingEditorButton(in_meeting_id);
2766  };
2767 
2768  // #mark -
2769  // #mark Location Tab
2770  // #mark -
2771 
2772  /************************************************************************************//**
2773  * \brief
2774  ****************************************************************************************/
2775  this.handleNewAddressInfo = function ( in_meeting_id ///< The BMLT ID of the meeting being edited.
2776  ) {
2777  var meeting_street_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_street_text_input');
2778  var meeting_borough_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_borough_text_input');
2779  var meeting_city_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_city_text_input');
2780  var meeting_state_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_state_text_input');
2781  var meeting_state_select_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_state_select_input');
2782  var meeting_zip_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_zip_text_input');
2783  var meeting_nation_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_nation_text_input');
2784 
2785  if ( meeting_street_text_item && meeting_borough_text_item && meeting_city_text_item && ( meeting_state_text_item || meeting_state_select_item ) && meeting_zip_text_item && meeting_nation_text_item ) {
2786  var street_text = meeting_street_text_item.value;
2787  var borough_text = meeting_borough_text_item.value;
2788  var city_text = meeting_city_text_item.value;
2789  var state_text = meeting_state_text_item ? meeting_state_text_item.value : meeting_state_select_item.options[meeting_state_select_item.selectedIndex].value;
2790  var zip_text = meeting_zip_text_item.value;
2791  var nation_text = meeting_nation_text_item.value;
2792  };
2793  };
2794 
2795 
2796  /************************************************************************************//**
2797  * \brief
2798  ****************************************************************************************/
2799  this.getAddressLine = function (in_meeting_id) {
2800  var meeting_street_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_street_text_input');
2801  var meeting_borough_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_borough_text_input');
2802  var meeting_city_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_city_text_input');
2803  var meeting_state_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_state_text_input');
2804  var meeting_state_select_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_state_select_input');
2805  var meeting_zip_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_zip_text_input');
2806  var meeting_nation_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_nation_text_input');
2807 
2808  var street_text = (meeting_street_text_item.value != meeting_street_text_item.defaultValue) ? meeting_street_text_item.value : '';
2809  var borough_text = (meeting_borough_text_item.value != meeting_borough_text_item.defaultValue) ? meeting_borough_text_item.value : '';
2810  var city_text = (meeting_city_text_item.value != meeting_city_text_item.defaultValue) ? meeting_city_text_item.value : '';
2811  var state_text = meeting_state_text_item ? ((meeting_state_text_item.value != meeting_state_text_item.defaultValue) ? meeting_state_text_item.value : '') : meeting_state_select_item.options[meeting_state_select_item.selectedIndex].value;
2812  var zip_text = (meeting_zip_text_item.value != meeting_zip_text_item.defaultValue) ? meeting_zip_text_item.value : '';
2813  var nation_text = (meeting_nation_text_item.value != meeting_nation_text_item.defaultValue) ? meeting_nation_text_item.value : '';
2814 
2815  if ( !nation_text ) {
2816  nation_text = g_region_bias;
2817  };
2818 
2819  // What we do here, is try to create a readable address line to be sent off for geocoding. We just try to clean it up as much as possible.
2820  var address_line = sprintf('%s,%s,%s,%s,%s,%s', street_text, borough_text, city_text, state_text, zip_text, nation_text);
2821 
2822  address_line = address_line.replace(/,+/g, ', ');
2823  address_line = address_line.replace(/^, /g, '');
2824  address_line = address_line.replace(/, $/g, '');
2825  return address_line;
2826  };
2827 
2828  this.lookupLocation = function (in_meeting_id, successCallback) {
2829  if (!g_google_api_key_is_good) {
2830  alert("The meeting couldn't be saved because there is a problem with the Google Maps API Key.");
2831  return;
2832  }
2833 
2834  var address_line = this.getAddressLine(in_meeting_id);
2835  var editor_object = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2836  var the_meeting_object = editor_object.meeting_object;
2837 
2838  if ( address_line != ', ' ) {
2839  if ( !the_meeting_object.m_geocoder ) {
2840  the_meeting_object.m_geocoder = new google.maps.Geocoder;
2841  }
2842 
2843  the_meeting_object.m_geocoder.geocode(
2844  { 'address' : address_line },
2845  function ( in_geocode_response, status ) {
2846  if (status !== 'OK') {
2847  alert(g_meeting_lookup_failed);
2848  return;
2849  }
2850  admin_handler_object.sGeoCallback(in_geocode_response, in_meeting_id);
2851  if (successCallback) {
2852  successCallback();
2853  }
2854  }
2855  );
2856  } else {
2857  alert(g_meeting_lookup_failed_not_enough_address_info);
2858  }
2859  };
2860  /****************************************************************************************//**
2861  * \brief This catches the AJAX response, and fills in the response form. *
2862  ********************************************************************************************/
2863 
2864  this.sGeoCallback = function (
2865  in_geocode_response, ///< The JSON object.
2866  in_meeting_id ///< The ID of the meeting.
2867  ) {
2868  var meeting_editor = document.getElementById('bmlt_admin_single_meeting_editor_' + parseInt(in_meeting_id, 10) + '_div');
2869 
2870  if ( meeting_editor ) {
2871  var the_meeting_object = meeting_editor.meeting_object;
2872 
2873  if ( in_geocode_response && in_geocode_response.length && (google.maps.OK == in_geocode_response[0].status) ) {
2874  var lng = in_geocode_response[0].geometry.location.lng();
2875  var lat = in_geocode_response[0].geometry.location.lat();
2876 
2877  delete the_meeting_object.m_geocoder;
2878 
2879  var map_center = new google.maps.LatLng(lat, lng);
2880  this.setMeetingLongLat(map_center, in_meeting_id);
2881  if (meeting_editor.main_map) {
2882  meeting_editor.main_map.panTo(map_center);
2883  this.displayMainMarkerInMap(in_meeting_id);
2884  google.maps.event.removeListener(the_meeting_object.m_geocoder);
2885  }
2886 
2887  if (g_auto_geocoding_enabled && g_county_auto_geocoding_enabled) {
2888  var meeting_county_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_county_text_input');
2889  if (meeting_county_text_item) {
2890  for (var i = 0; i < in_geocode_response[0].address_components.length; i++) {
2891  var component = in_geocode_response[0].address_components[i];
2892  if (component.types && component.types[0] === "administrative_area_level_2") {
2893  var county = component.long_name;
2894  if (county.endsWith(" County")) {
2895  county = county.substring(0, county.length - 7);
2896  }
2897  meeting_county_text_item.value = county;
2898  this.setItemValue(meeting_county_text_item, in_meeting_id, 'location_sub_province');
2899  break;
2900  }
2901  }
2902  }
2903  }
2904 
2905  if (g_auto_geocoding_enabled && g_county_auto_geocoding_enabled) {
2906  var meeting_zip_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_zip_text_input');
2907  if (meeting_zip_text_item) {
2908  if (meeting_county_text_item) {
2909  for (var i = 0; i < in_geocode_response[0].address_components.length; i++) {
2910  var component = in_geocode_response[0].address_components[i];
2911  if (component.types && component.types[0] === "postal_code") {
2912  var zipCode = component.long_name;
2913  meeting_zip_text_item.value = zipCode;
2914  this.setItemValue(meeting_zip_text_item, in_meeting_id, 'location_postal_code_1');
2915  break;
2916  }
2917  }
2918  }
2919  }
2920  }
2921 
2922  this.validateMeetingEditorButton(in_meeting_id);
2923  } else {
2924  alert(in_geocode_response[0].status.toString());
2925  };
2926  } else {
2927  alert(g_meeting_lookup_failed);
2928  };
2929  };
2930 
2931  /************************************************************************************//**
2932  * \brief This toggles the map disclosure. *
2933  ****************************************************************************************/
2934  this.toggleMeetingMapDisclosure = function ( in_meeting_id ///< The meeting ID of the editor that gets this map.
2935  ) {
2936  var root_element = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2937  var map_disclosure_div = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_map_disclosure_div');
2938  var map_div = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_map_div');
2939  var longlat_div = document.getElementById('bmlt_admin_single_location_' + in_meeting_id + '_long_lat_div');
2940 
2941  root_element.map_disclosed = !root_element.map_disclosed;
2942 
2943  map_disclosure_div.className = 'bmlt_admin_single_meeting_disclosure_map_div' + (root_element.map_disclosed ? '_open' : '_closed');
2944  map_div.className = 'bmlt_admin_single_meeting_map_div' + (root_element.map_disclosed ? '' : ' item_hidden');
2945  longlat_div.className = root_element.map_disclosed ? 'bmlt_admin_single_location_long_lat_div item_hidden' : 'bmlt_admin_single_location_long_lat_div';
2946 
2947  if ( root_element.map_disclosed && !root_element.main_map ) {
2948  root_element.main_map = this.createEditorMap(root_element, in_meeting_id);
2949  };
2950  };
2951 
2952  /************************************************************************************//**
2953  * \brief This creates the map for the editor. *
2954  * \returns the map object. *
2955  ****************************************************************************************/
2956  this.createEditorMap = function (
2957  in_editor_parent, ///< The main editor div object.
2958  in_meeting_id ///< The meeting ID of the editor that gets this map.
2959  ) {
2960  var meeting_map_holder = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_inner_map_div');
2961  var map_center = new google.maps.LatLng(in_editor_parent.meeting_object.latitude, in_editor_parent.meeting_object.longitude);
2962 
2963  var myOptions = {
2964  'center': map_center,
2965  'zoom': in_editor_parent.meeting_object.zoom,
2966  'mapTypeId': google.maps.MapTypeId.ROADMAP,
2967  'mapTypeControlOptions': { 'style': google.maps.MapTypeControlStyle.DROPDOWN_MENU },
2968  'zoomControl': true,
2969  'mapTypeControl': true,
2970  'disableDoubleClickZoom' : true,
2971  'draggableCursor': "crosshair",
2972  'scaleControl' : true
2973  };
2974 
2975  myOptions.zoomControlOptions = { 'style': google.maps.ZoomControlStyle.LARGE };
2976 
2977  in_editor_parent.m_main_map = new google.maps.Map(meeting_map_holder, myOptions);
2978 
2979  if ( in_editor_parent.m_main_map ) {
2980  in_editor_parent.m_main_map.setOptions({'scrollwheel': false}); // For some reason, it ignores setting this in the options.
2981  google.maps.event.addListener(in_editor_parent.m_main_map, 'click', function (in_event) {
2982  admin_handler_object.respondToMapClick(in_event, in_meeting_id); });
2983  in_editor_parent.m_main_map.initialcall = google.maps.event.addListener(in_editor_parent.m_main_map, 'tilesloaded', function (in_event) {
2984  admin_handler_object.tilesLoaded(in_meeting_id); });
2985  this.displayMainMarkerInMap(in_meeting_id);
2986  };
2987 
2988  return ( in_editor_parent.m_main_map );
2989  };
2990 
2991  /************************************************************************************//**
2992  * \brief
2993  ****************************************************************************************/
2994  this.tilesLoaded = function (in_meeting_id ///< The meeting this map is associated with.
2995  ) {
2996  var root_element = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
2997 
2998  if ( root_element && root_element.main_map && root_element.m_main_map.initialcall ) {
2999  google.maps.event.removeListener(root_element.m_main_map.initialcall);
3000  root_element.m_main_map.initialcall = null;
3001  };
3002 
3003  this.displayMainMarkerInMap(in_meeting_id);
3004  };
3005 
3006  /************************************************************************************//**
3007  * \brief
3008  ****************************************************************************************/
3009  this.respondToMapClick = function (
3010  in_event, ///< The Google Maps event
3011  in_meeting_id ///< The meeting this map is associated with.
3012  ) {
3013  var root_element = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
3014  var map_center = in_event.latLng;
3015  root_element.main_map.panTo(map_center);
3016  this.setMeetingLongLat(map_center, in_meeting_id);
3017  this.displayMainMarkerInMap(in_meeting_id);
3018  };
3019 
3020  /************************************************************************************//**
3021  * \brief
3022  ****************************************************************************************/
3023  this.respondToMarkerDragEnd = function (
3024  in_event, ///< The Google Maps event
3025  in_meeting_id ///< The meeting this map is associated with.
3026  ) {
3027  var root_element = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
3028  var map_center = in_event.latLng;
3029  root_element.main_map.panTo(map_center);
3030  this.setMeetingLongLat(map_center, in_meeting_id);
3031  };
3032 
3033  /************************************************************************************//**
3034  * \brief This displays the "Your Position" marker in the results map. *
3035  ****************************************************************************************/
3036  this.displayMainMarkerInMap = function ( in_meeting_id ///< The meeting this map is associated with.
3037  ) {
3038  var root_element = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
3039 
3040  if ( root_element && root_element.main_map ) {
3041  if ( root_element.main_map.main_marker ) {
3042  root_element.main_map.main_marker.setMap(null);
3043  root_element.main_map.main_marker = null;
3044  };
3045 
3046  m_icon_image = new google.maps.MarkerImage(g_style_dir + "/images/NACenterMarker.png", new google.maps.Size(21, 36), new google.maps.Point(0,0), new google.maps.Point(11, 36));
3047  m_icon_shadow = new google.maps.MarkerImage(g_style_dir + "/images/NACenterMarkerS.png", new google.maps.Size(43, 36), new google.maps.Point(0,0), new google.maps.Point(11, 36));
3048 
3049  root_element.main_map.main_marker = new google.maps.Marker({
3050  'position': root_element.main_map.getCenter(),
3051  'map': root_element.main_map,
3052  'icon': m_icon_image,
3053  'shadow': m_icon_shadow,
3054  'clickable': false,
3055  'cursor': 'pointer',
3056  'draggable': true
3057  });
3058  google.maps.event.addListener(root_element.main_map.main_marker, 'dragend', function (in_event) {
3059  admin_handler_object.respondToMarkerDragEnd(in_event, in_meeting_id); });
3060  };
3061  };
3062 
3063  /************************************************************************************//**
3064  * \brief
3065  ****************************************************************************************/
3066  this.setMeetingLongLat = function (
3067  in_longLat,
3068  in_meeting_id
3069  ) {
3070  var root_element = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div');
3071  var meeting_object = root_element.meeting_object;
3072  var meeting_longitude_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_longitude_text_input');
3073  var meeting_latitude_text_item = document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_meeting_latitude_text_input');
3074 
3075  var lng = (Math.round(100000000.0 * in_longLat.lng()) / 100000000.0);
3076  var lat = (Math.round(100000000.0 * in_longLat.lat()) / 100000000.0);
3077 
3078  meeting_object.longitude = lng;
3079  meeting_object.latitude = lat;
3080 
3081  meeting_longitude_text_item.value = htmlspecialchars_decode(meeting_object.longitude);
3082  meeting_latitude_text_item.value = htmlspecialchars_decode(meeting_object.latitude);
3083 
3084  this.setItemValue(meeting_longitude_text_item, in_meeting_id, 'longitude');
3085  this.setItemValue(meeting_latitude_text_item, in_meeting_id, 'latitude');
3086 
3087  this.validateMeetingEditorButton(in_meeting_id);
3088  };
3089 
3090  // #mark -
3091  // #mark Format Tab
3092  // #mark -
3093 
3094  /************************************************************************************//**
3095  * \brief
3096  ****************************************************************************************/
3097  this.setFormatCheckboxes = function (in_meeting_object
3098  ) {
3099  var format_keys_string = '';
3100 
3101  if (in_meeting_object) {
3102  if (in_meeting_object.format_shared_id_list) {
3103  format_keys_string = in_meeting_object.format_shared_id_list;
3104  };
3105  };
3106 
3107  var format_keys = new Array();
3108 
3109  // God, this is such an abomination.
3110  // If the format is one integer, or badly formed, then it might not split, in which case, we need to parse it.
3111  if (format_keys_string) {
3112  var splittee = format_keys_string.split(',');
3113  if (splittee && splittee.length) {
3114  format_keys = splittee.map((v) => {return parseInt(v);});
3115  } else {
3116  format_keys[0] = parseInt(format_keys_string);
3117  };
3118  };
3119 
3120  var venue_type_format_selections = { "HY": false, "TC": false, "VM": false };
3121  var main_formats = g_format_object_array;
3122  for (var c = 0; c < main_formats.length; c++) {
3123  var format_checkbox = document.getElementById('bmlt_admin_meeting_' + in_meeting_object.id_bigint + '_format_' + main_formats[c].id + '_checkbox');
3124 
3125  if (this.isVenueTypeFormatBySharedId(main_formats[c].id)) {
3126  $(format_checkbox).closest("div.bmlt_admin_meeting_one_format_div").hide();
3127  }
3128 
3129  if ( format_checkbox ) {
3130  for (var i = 0; i < format_keys.length; i++) {
3131  if ( format_checkbox.value == format_keys[i] ) {
3132 
3133  if (this.venueTypeSharedIdDict['HY'] === main_formats[c].id) {
3134  venue_type_format_selections['HY'] = true;
3135  } else if (this.venueTypeSharedIdDict['TC'] === main_formats[c].id) {
3136  venue_type_format_selections['TC'] = true;
3137  } else if (this.venueTypeSharedIdDict['VM'] === main_formats[c].id) {
3138  venue_type_format_selections['VM'] = true;
3139  }
3140 
3141  format_checkbox.checked = true;
3142  break;
3143  };
3144  };
3145  };
3146  };
3147 
3148  if (!venue_type_format_selections['VM'] && !venue_type_format_selections['TC'] && venue_type_format_selections['HY']) {
3149  document.getElementById("bmlt_admin_single_meeting_editor_" + in_meeting_object.id_bigint + "_meeting_venue_type_hybrid").checked = true;
3150  } else if (venue_type_format_selections['VM'] && venue_type_format_selections['TC'] && !venue_type_format_selections['HY']) {
3151  document.getElementById("bmlt_admin_single_meeting_editor_" + in_meeting_object.id_bigint + "_meeting_venue_type_virtualTC").checked = true;
3152  } else if (venue_type_format_selections['VM'] && !venue_type_format_selections['TC'] && !venue_type_format_selections['HY']) {
3153  document.getElementById("bmlt_admin_single_meeting_editor_" + in_meeting_object.id_bigint + "_meeting_venue_type_virtual").checked = true;
3154  } else if (!venue_type_format_selections['VM'] && !venue_type_format_selections['TC'] && !venue_type_format_selections['HY']) {
3155  document.getElementById("bmlt_admin_single_meeting_editor_" + in_meeting_object.id_bigint + "_meeting_venue_type_inperson").checked = true;
3156  }
3157 
3158  this.reactToFormatCheckbox(null, in_meeting_object.id_bigint);
3159 
3160  // The reason we do this whacky stuff, is that the formats may not be in the same order from the server as we keep them, so this little dance re-orders them.
3161  if ( in_meeting_object.id_bigint && this.m_search_results && this.m_search_results.length ) {
3162  for (var c = 0; c < this.m_search_results.length; c++) {
3163  if ( in_meeting_object.id_bigint == this.m_search_results[c].id_bigint ) {
3164  this.m_search_results[c].formats = in_meeting_object.formats;
3165  break;
3166  };
3167  };
3168  };
3169 
3170  this.validateMeetingEditorButton(in_meeting_object.id_bigint);
3171  };
3172 
3173  /************************************************************************************//**
3174  * \brief
3175  ****************************************************************************************/
3176  this.reactToFormatCheckbox = function (
3177  in_checkbox_object,
3178  in_meeting_id
3179  ) {
3180  var format_array = new Array;
3181  var main_formats = g_format_object_array;
3182 
3183  for (var c = 0; c < main_formats.length; c++) {
3184  var format_checkbox = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_format_' + main_formats[c].id + '_checkbox');
3185 
3186  if ( format_checkbox && format_checkbox.checked ) {
3187  format_array[format_array.length] = parseInt(format_checkbox.value);
3188  };
3189  };
3190 
3191  format_array.sort(function(a,b) {return a-b;});
3192 
3193  document.getElementById('bmlt_admin_single_meeting_editor_' + in_meeting_id + '_div').meeting_object.format_shared_id_list = format_array.join(',');
3194  this.validateMeetingEditorButton(in_meeting_id);
3195  };
3196 
3197  // #mark -
3198  // #mark Other Tab
3199  // #mark -
3200 
3201  /************************************************************************************//**
3202  * \brief
3203  ****************************************************************************************/
3204  this.setUpOtherTab = function ( in_meeting_object
3205  ) {
3206  for (var c = 0; c < g_other_field_ids.length; c++) {
3207  var element = g_other_field_ids[c];
3208  var val = in_meeting_object[element];
3209  var elementID = 'bmlt_admin_single_meeting_editor_' + in_meeting_object.id_bigint + '_meeting_' + element + '_text_input';
3210  var text_field = document.getElementById(elementID);
3211 
3212  var def_val = text_field.value;
3213 
3214  if ( val ) {
3215  var val_ar = val.toString().split("#@-@#");
3216 
3217  if ( val_ar && (val_ar.length == 2 ) ) {
3218  val = val_ar[1];
3219  } else if ( val_ar && (val_ar.length == 3 ) ) {
3220  val = val_ar[2];
3221  };
3222 
3223  text_field.value = htmlspecialchars_decode(val);
3224  };
3225 
3226  this.setTextItemClass(text_field);
3227  text_field.meeting_id = in_meeting_object.id_bigint;
3228  text_field.element = element.toString();
3229  text_field.onkeyup = function () {
3230  admin_handler_object.setItemValue(this)};
3231  text_field.onfocus = function () {
3232  admin_handler_object.handleTextInputFocus(this)};
3233  text_field.onblur = function () {
3234  admin_handler_object.handleTextInputBlur(this)};
3235  text_field.onpaste = function () {
3236  var input = this;
3237  setTimeout(function () {
3238  admin_handler_object.setItemValue(input); }, 0);
3239  };
3240  text_field.oncut = function () {
3241  var input = this;
3242  setTimeout(function () {
3243  admin_handler_object.setItemValue(input); }, 0);
3244  };
3245 
3246  text_field = null;
3247  };
3248  };
3249 
3250  // #mark -
3251  // #mark History Tab
3252  // #mark -
3253 
3254  /************************************************************************************//**
3255  * \brief
3256  ****************************************************************************************/
3257  this.openHistoryTab = function ( in_meeting_id
3258  ) {
3259  var option_sheet = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_history_sheet_div');
3260  var history_list = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_history_list_div');
3261 
3262  if ( !history_list ) {
3263  this.fetchMeetingHistory(in_meeting_id);
3264  };
3265  };
3266 
3267  /************************************************************************************//**
3268  * \brief
3269  ****************************************************************************************/
3270  this.fetchMeetingHistory = function ( in_meeting_id
3271  ) {
3272  var new_editor = document.getElementById('bmlt_admin_single_meeting_editor_' + parseInt(in_meeting_id, 10) + '_div');
3273  var uri = g_ajax_callback_uri + '&get_meeting_history=' + in_meeting_id;
3274 
3275  if ( new_editor.m_ajax_request_in_progress ) {
3276  new_editor.m_ajax_request_in_progress.abort();
3277  new_editor.m_ajax_request_in_progress = null;
3278  };
3279 
3280  var salt = new Date();
3281  uri += '&salt=' + salt.getTime();
3282 
3283  new_editor.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req,in_id) {
3284  admin_handler_object.fetchMeetingHistoryAJAXCallback(in_req,in_id); }, 'get', in_meeting_id);
3285  };
3286 
3287  /************************************************************************************//**
3288  * \brief
3289  ****************************************************************************************/
3290  this.fetchMeetingHistoryAJAXCallback = function (
3291  in_http_request,
3292  in_meeting_id
3293  ) {
3294  if ( in_http_request.responseText ) {
3295  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
3296  alert(g_AJAX_Auth_Failure);
3297  } else {
3298  eval('var json_object = ' + in_http_request.responseText + ';');
3299  };
3300  };
3301 
3302  if ( json_object ) {
3303  var meeting_changed = false;
3304 
3305  if ( json_object.error ) {
3306  alert(json_object.report);
3307  } else {
3308  document.getElementById('bmlt_admin_history_ajax_button_' + in_meeting_id + '_throbber_div').className = 'bmlt_admin_history_ajax_button_throbber_div item_hidden';
3309  var option_sheet = document.getElementById('bmlt_admin_meeting_' + in_meeting_id + '_history_sheet_div');
3310  var history_list = document.createElement('div');
3311  history_list.id = 'bmlt_admin_meeting_' + in_meeting_id + '_history_list_div';
3312  history_list.className = 'bmlt_admin_meeting_history_list_div';
3313 
3314  if ( json_object.length ) {
3315  for (var c = 0; c < json_object.length; c++) {
3316  var history_item = document.createElement('div');
3317  history_item.id = 'bmlt_admin_meeting_' + in_meeting_id + '_history_' + json_object[c].id + '_list_item_div';
3318  history_item.className = 'bmlt_admin_meeting_history_list_item_div';
3319 
3320  var header_items = sprintf(g_history_header_format.toString().replace(/&gt;/g, '>').replace(/&lt;/g, '<'), json_object[c].date, json_object[c].user);
3321  history_item.innerHTML = header_items;
3322 
3323  if ( json_object[c].description.length ) {
3324  var item = document.createElement('div');
3325  item.className = 'bmlt_admin_meeting_history_list_item_line_div bmlt_admin_meeting_history_list_item_description_div';
3326  for (var i = 0; i < json_object[c].description.length; i++) {
3327  var inner_item = document.createElement('div');
3328  inner_item.className = 'bmlt_admin_meeting_history_list_item_description_line_div';
3329  inner_item.appendChild(document.createTextNode(json_object[c].description[i].toString().replace(/&quot;/g, '"')));
3330  item.appendChild(inner_item);
3331  };
3332 
3333  history_item.appendChild(item);
3334  };
3335 
3336  history_list.appendChild(history_item);
3337  };
3338  } else {
3339  history_list.innerHTML = g_history_no_history_available_text.toString().replace(/&gt;/g, '>').replace(/&lt;/g, '<');
3340  };
3341 
3342  option_sheet.appendChild(history_list);
3343  };
3344  };
3345  };
3346 
3347  // #mark -
3348  // #mark ########## Service Body Editor Section ##########
3349  // #mark -
3350 
3351  /************************************************************************************//**
3352  * \brief Toggles the visibility of the Service body editor section. *
3353  ****************************************************************************************/
3354  this.toggleServiceBodyEditor = function () {
3355  this.m_service_body_editor_panel_shown = !this.m_service_body_editor_panel_shown;
3356 
3357  var the_disclosure_div = document.getElementById('bmlt_admin_service_body_editor_disclosure_div');
3358  var the_editor_div = document.getElementById('bmlt_admin_service_body_editor_wrapper_div');
3359 
3360  if ( this.m_service_body_editor_panel_shown ) {
3361  the_disclosure_div.className = 'bmlt_admin_service_body_editor_disclosure_div bmlt_admin_service_body_editor_disclosure_div_open';
3362  the_editor_div.className = 'bmlt_admin_service_body_editor_wrapper_div';
3363  this.showWarningAlert();
3364  } else {
3365  the_disclosure_div.className = 'bmlt_admin_service_body_editor_disclosure_div bmlt_admin_service_body_editor_disclosure_div_closed';
3366  the_editor_div.className = 'bmlt_admin_service_body_editor_wrapper_div bmlt_admin_service_body_editor_wrapper_div_hidden';
3367  };
3368  };
3369 
3370  /************************************************************************************//**
3371  * \brief This sets up the Service Body Editor for the selected Service body. *
3372  ****************************************************************************************/
3373  this.populateServiceBodyEditor = function () {
3374  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3375  var service_body_select = document.getElementById('bmlt_admin_single_service_body_editor_sb_select');
3376 
3377  var sb_id = 0;
3378 
3379  if ( main_service_body_editor.service_body_object && (this.isServiceBodyDirty() != null) ) {
3380  if ( !confirm(g_service_body_dirty_confirm_text) ) {
3381  service_body_select.selectedIndex = this.isServiceBodyDirty();
3382  return;
3383  };
3384  };
3385 
3386  var index = 0;
3387  var selected_service_body_object = null;
3388 
3389  if ( service_body_select ) { // If we are able to switch between multiple Service bodies, we can do so here.
3390  index = service_body_select.selectedIndex;
3391  if ( service_body_select.options[index] ) {
3392  sb_id = service_body_select.options[index].value;
3393  } else {
3394  sb_id = 0;
3395  };
3396  } else {
3397  sb_id = g_editable_service_bodies_array[0][0];
3398  };
3399 
3400  var save_button_a = document.getElementById('bmlt_admin_service_body_editor_form_service_body_save_button');
3401 
3402  if ( sb_id == 0 ) { // See if we will be creating a new one.
3403  save_button_a.innerHTML = g_service_body_create_button;
3404  main_service_body_editor.className = 'bmlt_admin_single_service_body_editor_div bmlt_admin_new_sb_editor';
3405  selected_service_body_object = this.makeANewSB();
3406  } else {
3407  var sb_object = null;
3408 
3409  for (var c = 0; c < g_service_bodies_array.length; c++) {
3410  if ( g_service_bodies_array[c][0] == sb_id ) {
3411  sb_object = g_service_bodies_array[c];
3412  break;
3413  };
3414  };
3415 
3416  save_button_a.innerHTML = g_service_body_save_button;
3417  main_service_body_editor.className = 'bmlt_admin_single_service_body_editor_div';
3418  // This makes a copy of the Service body object, so we can modify it.
3419  selected_service_body_object = JSON.parse(JSON.stringify(sb_object));
3420  };
3421 
3422  main_service_body_editor.service_body_object = selected_service_body_object;
3423 
3424  var id_display = document.getElementById('service_body_admin_id_display');
3425  id_display.innerHTML = selected_service_body_object[0].toString();
3426 
3427  this.setServiceBodyUser(selected_service_body_object);
3428 
3429  var name_text_input = document.getElementById('bmlt_admin_service_body_editor_sb_name_text_input');
3430 
3431  name_text_input.value = htmlspecialchars_decode(selected_service_body_object[2]);
3432  this.handleTextInputLoad(name_text_input, g_service_body_name_default_prompt_text);
3433 
3434  var description_textarea = document.getElementById('bmlt_admin_sb_description_textarea');
3435 
3436  description_textarea.value = htmlspecialchars_decode(selected_service_body_object[3]);
3437  this.handleTextInputLoad(description_textarea, g_service_body_description_default_prompt_text);
3438 
3439  var email_text_input = document.getElementById('bmlt_admin_service_body_editor_sb_email_text_input');
3440 
3441  email_text_input.value = htmlspecialchars_decode(selected_service_body_object[6]);
3442  this.handleTextInputLoad(email_text_input, g_service_body_email_default_prompt_text);
3443 
3444  var uri_text_input = document.getElementById('bmlt_admin_service_body_editor_sb_uri_text_input');
3445 
3446  uri_text_input.value = htmlspecialchars_decode(selected_service_body_object[7]);
3447  this.handleTextInputLoad(uri_text_input, g_service_body_uri_default_prompt_text);
3448 
3449  var world_id_text_input = document.getElementById('bmlt_admin_single_service_body_editor_world_cc_text_input');
3450 
3451  world_id_text_input.value = htmlspecialchars_decode(selected_service_body_object[12]);
3452  var naws_link_div = document.getElementById('service_body_editor_naws_link_div');
3453  var naws_link_a = document.getElementById('service_body_editor_naws_link_a');
3454 
3455  var helpline_text_input = document.getElementById('bmlt_admin_single_service_body_editor_helpline_text_input');
3456 
3457  helpline_text_input.value = htmlspecialchars_decode(selected_service_body_object[8]);
3458  this.handleTextInputLoad(helpline_text_input, g_service_body_helpline_default_prompt_text);
3459 
3460  if ( selected_service_body_object[12] ) { // We only show the NAWS dump link if we have a World ID.
3461  naws_link_div.className = 'naws_link_div';
3462  naws_link_a.href = 'client_interface/csv/?switcher=GetNAWSDump&sb_id=' + selected_service_body_object[0];
3463  } else {
3464  naws_link_div.className = 'item_hidden';
3465  };
3466 
3467  this.handleTextInputLoad(world_id_text_input, g_service_body_world_cc_default_prompt_text, true);
3468 
3469  var type_select = document.getElementById('bmlt_admin_single_service_body_editor_type_select');
3470 
3471  if ( type_select ) {
3472  var setIndex = 0;
3473 
3474  for (var c = 0; c < type_select.options.length; c ++) {
3475  if ( type_select.options[c].value == selected_service_body_object[9] ) {
3476  setIndex = c;
3477  break;
3478  };
3479  };
3480 
3481  type_select.selectedIndex = setIndex;
3482  };
3483 
3484  var service_body_parent_select = document.getElementById('bmlt_admin_single_service_body_editor_parent_select');
3485 
3486  if ( service_body_parent_select ) {
3487  for (var c = 0; c < service_body_parent_select.options.length; c++) {
3488  service_body_parent_select.options[c].selected = false;
3489  service_body_parent_select.options[c].disabled = false;
3490  };
3491 
3492  if ( document.getElementById('parent_popup_option_' + selected_service_body_object[0]) ) {
3493  document.getElementById('parent_popup_option_' + selected_service_body_object[0]).disabled = true;
3494  };
3495 
3496  if ( document.getElementById('parent_popup_option_' + selected_service_body_object[1]) ) {
3497  document.getElementById('parent_popup_option_' + selected_service_body_object[1]).selected = true;
3498  };
3499  };
3500 
3502 
3504 
3505  var perm_checkbox = document.getElementById('bmlt_admin_service_body_delete_perm_checkbox');
3506  if ( perm_checkbox ) {
3507  perm_checkbox.checked = false;
3508  };
3509 
3510  };
3511 
3512  /************************************************************************************//**
3513  * \brief This simply creates a brand-new, unsullied Service body object. *
3514  * \returns a new Service body object (which is really an array). *
3515  ****************************************************************************************/
3516  this.makeANewSB = function () {
3517  var new_service_body_object = new Array;
3518  new_service_body_object[0] = 0;
3519  new_service_body_object[1] = 0;
3520  new_service_body_object[2] = '';
3521  new_service_body_object[3] = '';
3522  new_service_body_object[4] = g_users[1][0];
3523  new_service_body_object[5] = '0';
3524  new_service_body_object[6] = '';
3525  new_service_body_object[7] = '';
3526  new_service_body_object[8] = '';
3527  new_service_body_object[9] = 'AS';
3528  new_service_body_object[10] = true;
3529  new_service_body_object[11] = true;
3530  new_service_body_object[12] = '';
3531 
3532  return new_service_body_object;
3533  };
3534 
3535  /************************************************************************************//**
3536  * \brief This handles display of the Service body user. *
3537  ****************************************************************************************/
3538  this.setServiceBodyUser = function ( in_selected_service_body ///< The selected Service body array element (which is an array)
3539  ) {
3540  // One of these will be available -they are mutually exclusive.
3541  var user_single_display = document.getElementById('single_user_service_body_admin_span');
3542  var user_select_element = document.getElementById('bmlt_admin_single_service_body_editor_principal_user_select');
3543  var sb_primary_user = null;
3544  var user_index = 0; // This will be used to correlate the user to the position in the menu.
3545 
3546  // Get the user info that corresponds to this Service body's primary user.
3547  for (; user_index < g_users.length; user_index++) {
3548  if ( g_users[user_index][0] == in_selected_service_body[4] ) {
3549  sb_primary_user = g_users[user_index];
3550  break;
3551  };
3552  };
3553 
3554  if ( sb_primary_user ) {
3555  if ( user_single_display ) {
3556  user_single_display.innerHTML = sb_primary_user[2];
3557  } else if ( user_select_element ) {
3558  for (var c = 0; c < user_select_element.options.length; c++) {
3559  if ( user_select_element.options[c].value == in_selected_service_body[4] ) {
3560  user_select_element.selectedIndex = c;
3561  break;
3562  };
3563  };
3564  };
3565  };
3566  };
3567 
3568  /************************************************************************************//**
3569  * \brief This is called when a Service Body Editor checkbox is clicked. *
3570  ****************************************************************************************/
3571  this.setServiceBodyEditorCheckboxes = function () {
3572  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3573 
3574  var users = main_service_body_editor.service_body_object[5].toString().split(',');
3575 
3576  if ( users && users.length && g_users && g_users.length ) {
3577  for (var c = 0; c < g_users.length; c++) {
3578  var checkbox = document.getElementById('service_body_admin_editor_user_' + g_users[c][0] +'_checkbox');
3579  if ( checkbox ) {
3580  checkbox.checked = false;
3581 
3582  for (var i = 0; i < users.length; i++) {
3583  if ( users[i] == g_users[c][0] ) {
3584  checkbox.checked = true;
3585  break;
3586  };
3587  };
3588  };
3589  };
3590  };
3591  };
3592 
3593  /************************************************************************************//**
3594  * \brief This is called when a Service Body Editor checkbox is clicked. *
3595  ****************************************************************************************/
3597  in_user_id, ///< The ID of the user.
3598  in_checkbox_object ///< The Checkbox DOM object
3599  ) {
3600  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3601 
3602  var new_users = new Array;
3603 
3604  if ( g_users && g_users.length ) {
3605  for (var c = 0; c < g_users.length; c++) {
3606  var checkbox = document.getElementById('service_body_admin_editor_user_' + g_users[c][0] +'_checkbox');
3607  if ( checkbox && checkbox.checked ) {
3608  new_users[new_users.length] = g_users[c][0];
3609  };
3610  };
3611  };
3612 
3613  if ( new_users.length ) {
3614  main_service_body_editor.service_body_object[5] = new_users.join(',').toString();
3615  } else {
3616  main_service_body_editor.service_body_object[5] = '0';
3617  };
3618 
3620  };
3621 
3622  /************************************************************************************//**
3623  * \brief This sets the state of the Service body editor save button. *
3624  ****************************************************************************************/
3626  var save_button = document.getElementById('bmlt_admin_service_body_editor_form_service_body_save_button');
3627  var cancel_button = document.getElementById('bmlt_admin_service_body_editor_form_meeting_template_cancel_button');
3628 
3629  if ( this.isServiceBodyDirty() != null ) {
3630  save_button.className = 'bmlt_admin_ajax_button button';
3631  cancel_button.className = 'bmlt_admin_ajax_button button';
3632  } else {
3633  save_button.className = 'bmlt_admin_ajax_button button_disabled';
3634  cancel_button.className = 'bmlt_admin_ajax_button button_disabled';
3635  };
3636 
3637  var delete_span = document.getElementById('service_body_editor_delete_span');
3638 
3639  if ( delete_span ) {
3640  document.getElementById('bmlt_admin_meeting_editor_form_service_body_delete_button').className = 'bmlt_admin_ajax_button button'; // We set this in either case, as IE "sticks."
3641  if ( g_service_bodies_array.length > 1 ) {
3642  delete_span.className = 'bmlt_admin_meeting_editor_form_middle_button_single_span bmlt_admin_delete_button_span hide_in_new_service_body_admin';
3643  } else {
3644  delete_span.className = 'item_hidden';
3645  };
3646  };
3647  };
3648 
3649  /************************************************************************************//**
3650  * \brief See if changes have been made to the Service body. *
3651  * \returns the service body index (if changed). Null, otherwise (Check for null) *
3652  ****************************************************************************************/
3653  this.isServiceBodyDirty = function () {
3654  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3655  var edited_service_body_object = main_service_body_editor.service_body_object;
3656  var original_service_body = null;
3657  var index = 0;
3658 
3659  if ( edited_service_body_object[0] > 0 ) {
3660  for (; index < g_service_bodies_array.length; index++) {
3661  if ( g_service_bodies_array[index][0] == edited_service_body_object[0] ) {
3662  original_service_body = g_service_bodies_array[index];
3663  break;
3664  };
3665  };
3666  } else {
3667  original_service_body = this.makeANewSB();
3668  };
3669 
3670  var current = JSON.stringify(edited_service_body_object);
3671  var orig = JSON.stringify(original_service_body);
3672  var ret = ( (current != orig) ? index : null );
3673 
3674  return ret;
3675  };
3676 
3677  /************************************************************************************//**
3678  * \brief This goes through the Service body (except the checkboxes) and recalculates *
3679  * the state of the edited object. *
3680  ****************************************************************************************/
3681  this.recalculateServiceBody = function () {
3682  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3683 
3684  var name_text_input = document.getElementById('bmlt_admin_service_body_editor_sb_name_text_input');
3685 
3686  if ( name_text_input && name_text_input.value && (name_text_input.value != name_text_input.defaultValue) ) {
3687  main_service_body_editor.service_body_object[2] = name_text_input.value;
3688  } else {
3689  main_service_body_editor.service_body_object[2] = '';
3690  };
3691 
3692  var description_textarea = document.getElementById('bmlt_admin_sb_description_textarea');
3693 
3694  if ( description_textarea && description_textarea.value && (description_textarea.value != description_textarea.defaultValue) ) {
3695  main_service_body_editor.service_body_object[3] = description_textarea.value;
3696  } else {
3697  main_service_body_editor.service_body_object[3] = '';
3698  };
3699 
3700  var email_text_input = document.getElementById('bmlt_admin_service_body_editor_sb_email_text_input');
3701 
3702  if ( email_text_input && email_text_input.value && (email_text_input.value != email_text_input.defaultValue) ) {
3703  main_service_body_editor.service_body_object[6] = email_text_input.value;
3704  } else {
3705  main_service_body_editor.service_body_object[6] = '';
3706  };
3707 
3708  var uri_text_input = document.getElementById('bmlt_admin_service_body_editor_sb_uri_text_input');
3709 
3710  if ( uri_text_input && uri_text_input.value && (uri_text_input.value != uri_text_input.defaultValue) ) {
3711  main_service_body_editor.service_body_object[7] = uri_text_input.value;
3712  } else {
3713  main_service_body_editor.service_body_object[7] = '';
3714  };
3715 
3716  var world_id_text_input = document.getElementById('bmlt_admin_single_service_body_editor_world_cc_text_input');
3717 
3718  if ( world_id_text_input && world_id_text_input.value && (world_id_text_input.value != world_id_text_input.defaultValue) ) {
3719  main_service_body_editor.service_body_object[12] = world_id_text_input.value;
3720  } else {
3721  main_service_body_editor.service_body_object[12] = '';
3722  };
3723 
3724  var helpline_text_input = document.getElementById('bmlt_admin_single_service_body_editor_helpline_text_input');
3725 
3726  if ( helpline_text_input && helpline_text_input.value && (helpline_text_input.value != helpline_text_input.defaultValue) ) {
3727  main_service_body_editor.service_body_object[8] = helpline_text_input.value;
3728  } else {
3729  main_service_body_editor.service_body_object[8] = '';
3730  };
3731 
3732  var user_select = document.getElementById('bmlt_admin_single_service_body_editor_principal_user_select');
3733 
3734  if ( user_select && user_select.options[user_select.selectedIndex].value ) {
3735  main_service_body_editor.service_body_object[4] = parseInt(user_select.options[user_select.selectedIndex].value, 10);
3736  };
3737 
3738  var type_select = document.getElementById('bmlt_admin_single_service_body_editor_type_select');
3739 
3740  if ( type_select && type_select.options[type_select.selectedIndex].value ) {
3741  main_service_body_editor.service_body_object[9] = type_select.options[type_select.selectedIndex].value;
3742  };
3743 
3744  var service_body_parent_select = document.getElementById('bmlt_admin_single_service_body_editor_parent_select');
3745 
3746  if ( service_body_parent_select ) {
3747  main_service_body_editor.service_body_object[1] = parseInt(service_body_parent_select.value, 10);
3748  };
3749 
3751  };
3752 
3753  /************************************************************************************//**
3754  * \brief
3755  ****************************************************************************************/
3757  in_text_item,
3758  in_value_index
3759  ) {
3760  var val = '';
3761 
3762  if ( in_text_item ) {
3763  if ( !in_text_item.value || (in_text_item.value == in_text_item.defaultValue) ) {
3764  in_text_item.className = 'bmlt_text_item' + (in_text_item.small ? '_small' : (in_text_item.med ? '_med' : (in_text_item.tiny ? '_tiny' : ''))) + ' bmlt_text_item_dimmed';
3765  } else {
3766  val = in_text_item.value;
3767  in_text_item.className = 'bmlt_text_item' + (in_text_item.small ? '_small' : (in_text_item.med ? '_med' : (in_text_item.tiny ? '_tiny' : '')));
3768  };
3769  };
3770 
3771  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3772  main_service_body_editor.service_body_object[in_value_index] = val;
3773 
3774  this.recalculateServiceBody();
3776  };
3777 
3778  /************************************************************************************//**
3779  * \brief This cancels the Service body editing session. *
3780  ****************************************************************************************/
3781  this.cancelServiceBodyEdit = function () {
3782  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3783  main_service_body_editor.service_body_object = null;
3785  };
3786 
3787  // These functions will trigger AJAX transactions.
3788 
3789  /************************************************************************************//**
3790  * \brief This saves the current Service body. *
3791  ****************************************************************************************/
3792  this.saveServiceBody = function () {
3793  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3794 
3795  if ( main_service_body_editor.service_body_object[0] == 0 ) {
3796  this.createServiceBody();
3797  } else {
3798  if ( this.isServiceBodyDirty() != null ) {
3799  var button_object = document.getElementById('bmlt_admin_service_body_editor_form_service_body_save_button');
3800  var throbber_object = document.getElementById('bmlt_admin_service_body_save_ajax_button_throbber_span');
3801 
3802  var serialized_object = JSON.stringify(main_service_body_editor.service_body_object);
3803 
3804  var uri = g_ajax_callback_uri + '&set_service_body_change=' + encodeURIComponent(serialized_object);
3805 
3806  if ( main_service_body_editor.m_ajax_request_in_progress ) {
3807  main_service_body_editor.m_ajax_request_in_progress.abort();
3808  main_service_body_editor.m_ajax_request_in_progress = null;
3809  };
3810 
3811  var salt = new Date();
3812  uri += '&salt=' + salt.getTime();
3813 
3814  button_object.className = 'item_hidden';
3815  throbber_object.className = 'bmlt_admin_ajax_button_throbber_span';
3816 
3817  main_service_body_editor.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req) {
3818  admin_handler_object.saveServiceBodyAJAXCallback(in_req); }, 'post');
3819  };
3820  };
3821  };
3822 
3823  /************************************************************************************//**
3824  * \brief This is the AJAX callback handler for the save operation. *
3825  ****************************************************************************************/
3826  this.saveServiceBodyAJAXCallback = function (in_http_request ///< The HTTPRequest object
3827  ) {
3828  if ( in_http_request.responseText ) {
3829  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
3830  alert(g_AJAX_Auth_Failure);
3831  } else {
3832  eval('var json_object = ' + in_http_request.responseText + ';');
3833  };
3834 
3835  if ( json_object ) {
3836  if ( !json_object.success ) {
3837  alert(json_object.report);
3838  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_editor_fail_div', this.m_failure_fade_duration);
3839  } else {
3840  for (var index = 0; index < g_service_bodies_array.length; index++) {
3841  if ( g_service_bodies_array[index][0] == json_object.service_body[0] ) {
3842  g_service_bodies_array[index] = json_object.service_body;
3843  break;
3844  };
3845  };
3846 
3847  for (var index = 0; index < g_editable_service_bodies_array.length; index++) {
3848  if ( g_editable_service_bodies_array[index][0] == json_object.service_body[0] ) {
3849  g_editable_service_bodies_array[index] = json_object.service_body;
3850  break;
3851  };
3852  };
3853 
3854  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3855  main_service_body_editor.m_ajax_request_in_progress = null;
3856  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_editor_success_div', this.m_success_fade_duration);
3857  };
3858  } else {
3859  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_editor_fail_div', this.m_failure_fade_duration);
3860  };
3861  } else {
3862  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_editor_fail_div', this.m_failure_fade_duration);
3863  };
3864 
3865  document.getElementById('bmlt_admin_service_body_save_ajax_button_throbber_span').className = 'item_hidden';
3867  };
3868 
3869  /************************************************************************************//**
3870  * \brief This creates a new Service body. *
3871  ****************************************************************************************/
3872  this.createServiceBody = function () {
3873  if ( this.isServiceBodyDirty() != null ) {
3874  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3875  var button_object = document.getElementById('bmlt_admin_service_body_editor_form_service_body_save_button');
3876  var throbber_object = document.getElementById('bmlt_admin_service_body_save_ajax_button_throbber_span');
3877 
3878  var serialized_object = JSON.stringify(main_service_body_editor.service_body_object);
3879 
3880  var uri = g_ajax_callback_uri + '&create_new_service_body=' + encodeURIComponent(serialized_object);
3881 
3882  if ( main_service_body_editor.m_ajax_request_in_progress ) {
3883  main_service_body_editor.m_ajax_request_in_progress.abort();
3884  main_service_body_editor.m_ajax_request_in_progress = null;
3885  };
3886 
3887  var salt = new Date();
3888  uri += '&salt=' + salt.getTime();
3889 
3890  button_object.className = 'item_hidden';
3891  throbber_object.className = 'bmlt_admin_ajax_button_throbber_span';
3892 
3893  main_service_body_editor.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req) {
3894  admin_handler_object.createServiceBodyAJAXCallback(in_req); }, 'post');
3895  };
3896  };
3897 
3898  /************************************************************************************//**
3899  * \brief This is the AJAX callback handler for the create operation. *
3900  ****************************************************************************************/
3901  this.createServiceBodyAJAXCallback = function (in_http_request ///< The HTTPRequest object
3902  ) {
3903  if ( in_http_request.responseText ) {
3904  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
3905  alert(g_AJAX_Auth_Failure);
3906  } else {
3907  eval('var json_object = ' + in_http_request.responseText + ';');
3908  };
3909 
3910  if ( json_object ) {
3911  if ( !json_object.success ) {
3912  alert(json_object.report);
3913  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_create_fail_div', this.m_failure_fade_duration);
3914  } else {
3915  g_service_bodies_array[g_service_bodies_array.length] = json_object.service_body;
3916  g_editable_service_bodies_array[g_editable_service_bodies_array.length] = json_object.service_body;
3917  var service_body_select = document.getElementById('bmlt_admin_single_service_body_editor_sb_select');
3918  var new_option = document.createElement('option');
3919  new_option.value = htmlspecialchars_decode(json_object.service_body[0]);
3920  new_option.text = htmlspecialchars_decode(json_object.service_body[2]);
3921 
3922  try {
3923  // for IE earlier than version 8
3924  service_body_select.add(new_option, service_body_select.options[service_body_select.options.length - 2]);
3925  } catch (e) {
3926  service_body_select.add(new_option, service_body_select.options.length - 2);
3927  };
3928 
3929  service_body_select.selectedIndex = service_body_select.options.length - 3;
3930  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3931  main_service_body_editor.m_ajax_request_in_progress = null;
3932  main_service_body_editor.service_body_object = null;
3934  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_create_success_div', this.m_success_fade_duration);
3935  document.getElementById('bmlt_admin_service_body_save_ajax_button_throbber_span').className = 'item_hidden';
3936  this.setWarningFaders();
3937  };
3938  } else {
3939  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_create_fail_div', this.m_failure_fade_duration);
3940  };
3941  } else {
3942  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_create_fail_div', this.m_failure_fade_duration);
3943  };
3944 
3945  document.getElementById('bmlt_admin_service_body_save_ajax_button_throbber_span').className = 'item_hidden';
3947  };
3948 
3949  /************************************************************************************//**
3950  * \brief This deletes the current Service body. *
3951  ****************************************************************************************/
3952  this.deleteServiceBody = function () {
3953  if ( g_service_bodies_array.length > 1 ) {
3954  var perm_check = document.getElementById('bmlt_admin_service_body_delete_perm_checkbox');
3955  var confirm_str = g_service_body_delete_button_confirm + (( perm_check && perm_check.checked ) ? ("\n" + g_service_body_delete_button_confirm_perm) : '');
3956 
3957  if ( confirm(confirm_str) ) {
3958  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3959 
3960  if ( main_service_body_editor.m_ajax_request_in_progress ) {
3961  main_service_body_editor.m_ajax_request_in_progress.abort();
3962  main_service_body_editor.m_ajax_request_in_progress = null;
3963  };
3964 
3965  var id = main_service_body_editor.service_body_object[0];
3966  var uri = g_ajax_callback_uri + '&delete_service_body=' + id + (( perm_check && perm_check.checked ) ? '&permanently=1' : '');
3967 
3968  var throbber_span = document.getElementById('bmlt_admin_service_body_delete_ajax_button_throbber_span').className = 'bmlt_admin_ajax_button_throbber_span';
3969  var delete_a = document.getElementById('bmlt_admin_meeting_editor_form_service_body_delete_button').className = 'item_hidden';
3970 
3971  var salt = new Date();
3972  uri += '&salt=' + salt.getTime();
3973 
3974  main_service_body_editor.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req) {
3975  admin_handler_object.deleteServiceBodyAJAXCallback(in_req); }, 'get');
3976  };
3977  };
3978  };
3979 
3980  /************************************************************************************//**
3981  * \brief This is the AJAX callback handler for the delete operation. *
3982  ****************************************************************************************/
3983  this.deleteServiceBodyAJAXCallback = function ( in_http_request ///< The HTTPRequest object
3984  ) {
3985  if ( in_http_request.responseText ) {
3986  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
3987  alert(g_AJAX_Auth_Failure);
3988  } else {
3989  eval('var json_object = ' + in_http_request.responseText + ';');
3990  };
3991 
3992  if ( json_object ) {
3993  var main_service_body_editor = document.getElementById('bmlt_admin_single_service_body_editor_div');
3994  main_service_body_editor.service_body_object = null;
3995 
3996  if ( !json_object.success ) {
3997  alert(json_object.report);
3998  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_editor_delete_fail_div', this.m_failure_fade_duration);
3999  } else {
4000  var service_body_select = document.getElementById('bmlt_admin_single_service_body_editor_sb_select');
4001  service_body_select.selectedIndex = 0;
4002  for (var index = 0; index < g_editable_service_bodies_array.length; index++) {
4003  if ( g_editable_service_bodies_array[index][0] == parseInt(json_object.id, 10) ) {
4004  service_body_select.remove(index);
4005  g_editable_service_bodies_array.splice(index, 1);
4006  break;
4007  };
4008  };
4009 
4010  for (var index = 0; index < g_service_bodies_array.length; index++) {
4011  if ( g_service_bodies_array[index][0] == parseInt(json_object.id, 10) ) {
4012  g_service_bodies_array.splice(index, 1);
4013  break;
4014  };
4015  };
4016 
4017  // If we leave any orphans, we clean them up, here.
4018  for (var index = 0; index < g_editable_service_bodies_array.length; index++) {
4019  var whosMyDaddy = false;
4020 
4021  var parent_id = g_editable_service_bodies_array[index][1];
4022  for (var c = 0; c < g_editable_service_bodies_array.length; c++) {
4023  if ( g_editable_service_bodies_array[c][0] == parent_id ) {
4024  whosMyDaddy = true;
4025  break;
4026  };
4027  };
4028 
4029  if ( !whosMyDaddy ) {
4030  g_editable_service_bodies_array[index][1] = 0;
4031  };
4032  };
4033 
4034  for (var index = 0; index < g_editable_service_bodies_array.length; index++) {
4035  var whosMyDaddy = false;
4036 
4037  var parent_id = g_service_bodies_array[index][1];
4038  for (var c = 0; c < g_service_bodies_array.length; c++) {
4039  if ( g_service_bodies_array[c][0] == parent_id ) {
4040  whosMyDaddy = true;
4041  break;
4042  };
4043  };
4044 
4045  if ( !whosMyDaddy ) {
4046  g_service_bodies_array[index][1] = 0;
4047  };
4048  };
4049 
4050  main_service_body_editor.m_ajax_request_in_progress = null;
4051  document.getElementById('bmlt_admin_service_body_delete_ajax_button_throbber_span').className = 'item_hidden';
4053  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_editor_delete_success_div', this.m_success_fade_duration);
4054  };
4055  } else {
4056  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_editor_delete_fail_div', this.m_failure_fade_duration);
4057  };
4058  } else {
4059  BMLT_Admin_StartFader('bmlt_admin_fader_service_body_editor_delete_fail_div', this.m_failure_fade_duration);
4060  };
4061 
4062  document.getElementById('bmlt_admin_service_body_delete_ajax_button_throbber_span').className = 'item_hidden';
4064  };
4065 
4066  // #mark -
4067  // #mark ########## User Editor Section ##########
4068  // #mark -
4069 
4070  /************************************************************************************//**
4071  * \brief Toggles the visibility of the Service body editor section. *
4072  ****************************************************************************************/
4073  this.toggleUserEditor = function () {
4074  this.m_user_editor_panel_shown = !this.m_user_editor_panel_shown;
4075 
4076  var the_disclosure_div = document.getElementById('bmlt_admin_user_editor_disclosure_div');
4077  var the_editor_div = document.getElementById('bmlt_admin_user_editor_wrapper_div');
4078 
4079  if ( this.m_user_editor_panel_shown ) {
4080  the_disclosure_div.className = 'bmlt_admin_user_editor_disclosure_div bmlt_admin_user_editor_disclosure_div_open';
4081  the_editor_div.className = 'bmlt_admin_user_editor_wrapper_div';
4082  } else {
4083  the_disclosure_div.className = 'bmlt_admin_user_editor_disclosure_div bmlt_admin_user_editor_disclosure_div_closed';
4084  the_editor_div.className = 'bmlt_admin_user_editor_wrapper_div bmlt_admin_user_editor_wrapper_div_hidden';
4085  };
4086  };
4087 
4088  /************************************************************************************//**
4089  * \brief This sets up the Service Body Editor for the selected Service body. *
4090  ****************************************************************************************/
4091  this.populateUserEditor = function () {
4092  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4093  var selected_user_select = document.getElementById('bmlt_admin_single_user_editor_user_select');
4094  var selected_user_id = selected_user_select.options[selected_user_select.options.selectedIndex].value;
4095  var selected_user_object = null;
4096  var save_button_a = document.getElementById('bmlt_admin_user_editor_form_user_save_button');
4097 
4098  for (var c = 0; c < g_users.length; c++) {
4099  if ( g_users[c][0] == selected_user_id ) {
4100  selected_user_object = JSON.parse(JSON.stringify(g_users[c])); // This ensures the user is a separate object.
4101  break;
4102  };
4103  };
4104 
4105  if ( !main_user_editor_div.current_user_object
4106  || (main_user_editor_div.current_user_object && !this.isUserDirty())
4107  || (main_user_editor_div.current_user_object && this.isUserDirty() && confirm(g_user_dirty_confirm_text)) ) {
4108  this.last_selected_user_index = selected_user_select.options.selectedIndex;
4109  var password_label = document.getElementById('bmlt_admin_user_editor_password_label');
4110  if ( !selected_user_object ) {
4111  selected_user_object = this.makeANewUser();
4112 
4113  save_button_a.innerHTML = g_user_create_button;
4114  main_user_editor_div.className = 'bmlt_admin_single_user_editor_div bmlt_admin_new_user_editor';
4115  password_label.innerHTML = g_user_new_password_label;
4116  } else {
4117  save_button_a.innerHTML = g_user_save_button;
4118  main_user_editor_div.className = 'bmlt_admin_single_user_editor_div';
4119  password_label.innerHTML = g_user_password_label;
4120  };
4121 
4122  if ( selected_user_object ) {
4123  if ( selected_user_object[5] == 1 ) { // This should never be, but just in case...
4124  main_user_editor_div.className = 'bmlt_admin_single_user_editor_div bmlt_admin_new_user_editor';
4125  };
4126 
4127  main_user_editor_div.current_user_object = selected_user_object;
4128 
4129  var id_text_item = document.getElementById('user_editor_id_display');
4130  id_text_item.innerHTML = selected_user_object[0];
4131 
4132  var login_field = document.getElementById('bmlt_admin_user_editor_login_input');
4133  login_field.value = htmlspecialchars_decode(selected_user_object[1]);
4134  this.handleTextInputBlur(login_field);
4135 
4136  var name_field = document.getElementById('bmlt_admin_user_editor_name_input');
4137  name_field.value = htmlspecialchars_decode(selected_user_object[2]);
4138  this.handleTextInputBlur(name_field);
4139 
4140  var description_textarea = document.getElementById('bmlt_admin_user_editor_description_textarea');
4141  description_textarea.value = htmlspecialchars_decode(selected_user_object[3]);
4142  this.handleTextInputBlur(description_textarea);
4143 
4144  var email_field = document.getElementById('bmlt_admin_user_editor_email_input');
4145  email_field.value = htmlspecialchars_decode(selected_user_object[4]);
4146  this.handleTextInputBlur(email_field);
4147 
4148  var password_field = document.getElementById('bmlt_admin_user_editor_password_input');
4149  password_field.value = htmlspecialchars_decode(selected_user_object[0] ? g_user_password_default_text : g_user_new_password_default_text);
4150  this.handleTextInputLoad(password_field);
4151 
4152  var user_level_popup_span = document.getElementById('user_editor_single_non_service_body_admin_display');
4153  var user_level_sa_span = document.getElementById('user_editor_single_service_body_admin_display');
4154 
4155  if ( selected_user_object[5] != 1 ) {
4156  user_level_popup_span.className = 'bmlt_admin_value_left';
4157  user_level_sa_span.className = 'item_hidden';
4158  var user_level_popup_select = document.getElementById('bmlt_admin_single_user_editor_level_select');
4159  user_level_popup_select.selectedIndex = (selected_user_object[5] == 2) ? 0 : ((selected_user_object[5] == 5) ? 1 : 3 );
4160  } else // This should never be, but just in case...
4161  {
4162  user_level_popup_span.className = 'item_hidden';
4163  user_level_sa_span.className = 'bmlt_admin_value_left light_italic_display';
4164  };
4165  };
4166 
4167  var user_owner_id = parseInt(selected_user_object[7]);
4168  var user_owner_field = document.getElementById('bmlt_admin_single_user_editor_user_owner_select');
4169  for (var i = 0; i < user_owner_field.options.length; i++) {
4170  var option = user_owner_field.options[i];
4171  if ( user_owner_id === -1 && parseInt(option.value) === 1 ) {
4172  user_owner_field.selectedIndex = i;
4173  break;
4174  } else if ( parseInt(option.value) === user_owner_id ) {
4175  user_owner_field.selectedIndex = i;
4176  break;
4177  }
4178  }
4179  } else if ( this.last_selected_user_index !== undefined ) {
4180  selected_user_select.options.selectedIndex = this.last_selected_user_index;
4181  }
4182 
4183  var perm_checkbox = document.getElementById('bmlt_admin_user_delete_perm_checkbox');
4184  if ( perm_checkbox ) {
4185  perm_checkbox.checked = false;
4186  };
4187 
4189  };
4190 
4191  /************************************************************************************//**
4192  * \brief Reads the current user editor state, and sets the main object accordingly. *
4193  ****************************************************************************************/
4194  this.readUserEditorState = function () {
4195  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4196 
4197  var login_field = document.getElementById('bmlt_admin_user_editor_login_input');
4198  main_user_editor_div.current_user_object[1] = (login_field.value && (login_field.value != login_field.defaultValue)) ? login_field.value : '';
4199 
4200  var name_field = document.getElementById('bmlt_admin_user_editor_name_input');
4201  main_user_editor_div.current_user_object[2] = (name_field.value && (name_field.value != name_field.defaultValue)) ? name_field.value : '';
4202 
4203  var description_textarea = document.getElementById('bmlt_admin_user_editor_description_textarea');
4204  main_user_editor_div.current_user_object[3] = (description_textarea.value && (description_textarea.value != description_textarea.defaultValue)) ? description_textarea.value : '';
4205 
4206  var email_field = document.getElementById('bmlt_admin_user_editor_email_input');
4207  main_user_editor_div.current_user_object[4] = (email_field.value && (email_field.value != email_field.defaultValue)) ? email_field.value : '';
4208 
4209  var user_level_select = document.getElementById('bmlt_admin_single_user_editor_level_select');
4210  main_user_editor_div.current_user_object[5] = parseInt(user_level_select.options[user_level_select.selectedIndex].value, 10);
4211 
4212  var password_field = document.getElementById('bmlt_admin_user_editor_password_input');
4213  main_user_editor_div.current_user_object[6] = (password_field.value && (password_field.value != password_field.defaultValue)) ? password_field.value : '';
4214 
4215  var user_owner_select = document.getElementById('bmlt_admin_single_user_editor_user_owner_select');
4216  main_user_editor_div.current_user_object[7] = parseInt(user_owner_select.options[user_owner_select.selectedIndex].value, 10);
4217 
4219  };
4220 
4221  /************************************************************************************//**
4222  * \brief Saves the user state. *
4223  ****************************************************************************************/
4224  this.saveUser = function () {
4225  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4226 
4227  var pw = main_user_editor_div.current_user_object[6];
4228 
4229  if ( g_min_pw_len && pw && (pw.length < g_min_pw_len) ) {
4230  alert(sprintf(g_min_password_length_string, g_min_pw_len));
4231  } else {
4232  if ( main_user_editor_div.current_user_object[0] == 0 ) {
4233  this.createUser();
4234  } else {
4235  if ( this.isUserDirty() ) {
4236  var button_object = document.getElementById('bmlt_admin_user_editor_form_user_save_button');
4237  var throbber_object = document.getElementById('bmlt_admin_user_save_ajax_button_throbber_span');
4238 
4239  var serialized_object = JSON.stringify(main_user_editor_div.current_user_object);
4240 
4241  var uri = g_ajax_callback_uri + '&set_user_change=' + encodeURIComponent(serialized_object);
4242 
4243  if ( main_user_editor_div.m_ajax_request_in_progress ) {
4244  main_user_editor_div.m_ajax_request_in_progress.abort();
4245  main_user_editor_div.m_ajax_request_in_progress = null;
4246  };
4247 
4248  var salt = new Date();
4249  uri += '&salt=' + salt.getTime();
4250 
4251  button_object.className = 'item_hidden';
4252  throbber_object.className = 'bmlt_admin_ajax_button_throbber_span';
4253 
4254  main_user_editor_div.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req) {
4255  admin_handler_object.saveUserAJAXCallback(in_req); }, 'post');
4256  };
4257  };
4258  };
4259  };
4260 
4261  /************************************************************************************//**
4262  * \brief This is the AJAX callback handler for the save operation. *
4263  ****************************************************************************************/
4264  this.saveUserAJAXCallback = function (in_http_request ///< The HTTPRequest object
4265  ) {
4266  if ( in_http_request.responseText ) {
4267  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
4268  alert(g_AJAX_Auth_Failure);
4269  } else {
4270  eval('var json_object = ' + in_http_request.responseText + ';');
4271  };
4272 
4273  if ( json_object ) {
4274  if ( !json_object.success ) {
4275  alert(json_object.report);
4276  BMLT_Admin_StartFader('bmlt_admin_fader_user_editor_fail_div', this.m_failure_fade_duration);
4277  } else {
4278  for (var index = 0; index < g_users.length; index++) {
4279  if ( g_users[index][0] == json_object.user[0] ) {
4280  g_users[index] = json_object.user;
4281  break;
4282  };
4283  };
4284 
4285  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4286  main_user_editor_div.m_ajax_request_in_progress = null;
4287  BMLT_Admin_StartFader('bmlt_admin_fader_user_editor_success_div', this.m_success_fade_duration);
4288  };
4289  } else {
4290  BMLT_Admin_StartFader('bmlt_admin_fader_user_editor_fail_div', this.m_failure_fade_duration);
4291  };
4292  } else {
4293  BMLT_Admin_StartFader('bmlt_admin_fader_user_editor_fail_div', this.m_failure_fade_duration);
4294  };
4295 
4296  document.getElementById('bmlt_admin_user_save_ajax_button_throbber_span').className = 'item_hidden';
4298  };
4299 
4300  /************************************************************************************//**
4301  * \brief This creates a new user. *
4302  ****************************************************************************************/
4303  this.createUser = function () {
4304  if ( this.isUserDirty() ) {
4305  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4306 
4307  if ( main_user_editor_div.current_user_object[6] ) { // New users must have a password.
4308  var button_object = document.getElementById('bmlt_admin_user_editor_form_user_save_button');
4309  var throbber_object = document.getElementById('bmlt_admin_user_save_ajax_button_throbber_span');
4310 
4311  var serialized_object = JSON.stringify(main_user_editor_div.current_user_object);
4312 
4313  var uri = g_ajax_callback_uri + '&create_new_user=' + encodeURIComponent(serialized_object);
4314 
4315  if ( main_user_editor_div.m_ajax_request_in_progress ) {
4316  main_user_editor_div.m_ajax_request_in_progress.abort();
4317  main_user_editor_div.m_ajax_request_in_progress = null;
4318  };
4319 
4320  var salt = new Date();
4321  uri += '&salt=' + salt.getTime();
4322 
4323  button_object.className = 'item_hidden';
4324  throbber_object.className = 'bmlt_admin_ajax_button_throbber_span';
4325 
4326  main_user_editor_div.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req) {
4327  admin_handler_object.createUserAJAXCallback(in_req); }, 'post');
4328  } else {
4329  alert(g_user_create_password_alert_text);
4330  };
4331  };
4332  };
4333 
4334  /************************************************************************************//**
4335  * \brief This is the AJAX callback handler for the create operation. *
4336  ****************************************************************************************/
4337  this.createUserAJAXCallback = function (in_http_request ///< The HTTPRequest object
4338  ) {
4339  if ( in_http_request.responseText ) {
4340  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
4341  alert(g_AJAX_Auth_Failure);
4342  } else {
4343  eval('var json_object = ' + in_http_request.responseText + ';');
4344  };
4345 
4346  if ( json_object ) {
4347  if ( !json_object.success ) {
4348  alert(json_object.report);
4349  BMLT_Admin_StartFader('bmlt_admin_fader_user_create_fail_div', this.m_failure_fade_duration);
4350  } else {
4351  g_users[g_users.length] = json_object.user;
4352  var user_select = document.getElementById('bmlt_admin_single_user_editor_user_select');
4353  var new_option = document.createElement('option');
4354  new_option.value = htmlspecialchars_decode(json_object.user[0]);
4355  new_option.text = htmlspecialchars_decode(json_object.user[2]);
4356 
4357  try {
4358  // for IE earlier than version 8
4359  user_select.add(new_option, user_select.options[user_select.options.length - 2]);
4360  } catch (e) {
4361  user_select.add(new_option, user_select.options.length - 2);
4362  };
4363 
4364  user_select.selectedIndex = user_select.options.length - 3;
4365  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4366  main_user_editor_div.m_ajax_request_in_progress = null;
4367  main_user_editor_div.current_user_object = null;
4368  this.populateUserEditor();
4369  BMLT_Admin_StartFader('bmlt_admin_fader_user_create_success_div', this.m_success_fade_duration);
4370  document.getElementById('bmlt_admin_user_save_ajax_button_throbber_span').className = 'item_hidden';
4371  this.setWarningFaders();
4372  };
4373  } else {
4374  BMLT_Admin_StartFader('bmlt_admin_fader_user_create_fail_div', this.m_failure_fade_duration);
4375  };
4376  } else {
4377  BMLT_Admin_StartFader('bmlt_admin_fader_user_create_fail_div', this.m_failure_fade_duration);
4378  };
4379 
4380  document.getElementById('bmlt_admin_user_save_ajax_button_throbber_span').className = 'item_hidden';
4382  };
4383 
4384  /************************************************************************************//**
4385  * \brief Deletes the user. *
4386  ****************************************************************************************/
4387  this.deleteUser = function () {
4388  if ( g_users.length > 1 ) {
4389  var perm_check = document.getElementById('bmlt_admin_user_delete_perm_checkbox');
4390  var confirm_str = g_user_delete_button_confirm + (( perm_check && perm_check.checked ) ? ("\n" + g_user_delete_button_confirm_perm) : '');
4391 
4392  if ( confirm(confirm_str) ) {
4393  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4394 
4395  if ( main_user_editor_div.m_ajax_request_in_progress ) {
4396  main_user_editor_div.m_ajax_request_in_progress.abort();
4397  main_user_editor_div.m_ajax_request_in_progress = null;
4398  };
4399 
4400  var id = main_user_editor_div.current_user_object[0];
4401  var uri = g_ajax_callback_uri + '&delete_user=' + id + (( perm_check && perm_check.checked ) ? '&permanently=1' : '');
4402 
4403  document.getElementById('bmlt_admin_user_delete_ajax_button_throbber_span').className = 'bmlt_admin_ajax_button_throbber_span';
4404  document.getElementById('bmlt_admin_meeting_editor_form_user_delete_button').className = 'item_hidden';
4405 
4406  var salt = new Date();
4407  uri += '&salt=' + salt.getTime();
4408 
4409  main_user_editor_div.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req) {
4410  admin_handler_object.deleteUserAJAXCallback(in_req); }, 'get');
4411  };
4412  };
4413  };
4414 
4415  /************************************************************************************//**
4416  * \brief This is the AJAX callback handler for the delete operation. *
4417  ****************************************************************************************/
4418  this.deleteUserAJAXCallback = function ( in_http_request ///< The HTTPRequest object
4419  ) {
4420  if ( in_http_request.responseText ) {
4421  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
4422  alert(g_AJAX_Auth_Failure);
4423  } else {
4424  eval('var json_object = ' + in_http_request.responseText + ';');
4425  };
4426 
4427  if ( json_object ) {
4428  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4429  main_user_editor_div.current_user_object = null;
4430 
4431  if ( !json_object.success ) {
4432  alert(json_object.report);
4433  BMLT_Admin_StartFader('bmlt_admin_fader_user_editor_delete_fail_div', this.m_failure_fade_duration);
4434  } else {
4435  var user_select = document.getElementById('bmlt_admin_single_user_editor_user_select');
4436  user_select.selectedIndex = 0;
4437  for (var index = 0; index < user_select.options.length; index++) {
4438  if ( parseInt(user_select.options[index].value, 10) == parseInt(json_object.report, 10) ) {
4439  user_select.remove(index);
4440  break;
4441  };
4442  };
4443 
4444  for (var index = 0; index < g_users.length; index++) {
4445  if ( parseInt(g_users[index][0], 10) == parseInt(json_object.report, 10) ) {
4446  g_users.splice(index, 1);
4447  break;
4448  };
4449  };
4450 
4451  main_user_editor_div.m_ajax_request_in_progress = null;
4452  document.getElementById('bmlt_admin_user_delete_ajax_button_throbber_span').className = 'item_hidden';
4453  this.populateUserEditor();
4454  BMLT_Admin_StartFader('bmlt_admin_fader_user_editor_delete_success_div', this.m_success_fade_duration);
4455  alert(g_user_meeting_editor_note);
4456  };
4457  } else {
4458  BMLT_Admin_StartFader('bmlt_admin_fader_user_editor_delete_fail_div', this.m_failure_fade_duration);
4459  };
4460  } else {
4461  BMLT_Admin_StartFader('bmlt_admin_fader_user_editor_delete_fail_div', this.m_failure_fade_duration);
4462  };
4463 
4464  document.getElementById('bmlt_admin_user_delete_ajax_button_throbber_span').className = 'item_hidden';
4466  };
4467 
4468  /************************************************************************************//**
4469  * \brief Resets the user to the original state. *
4470  ****************************************************************************************/
4471  this.cancelUserEdit = function () {
4472  var main_user_editor_div = document.getElementById('bmlt_admin_single_user_editor_div');
4473  main_user_editor_div.current_user_object = null;
4474  this.populateUserEditor();
4475  };
4476 
4477  /************************************************************************************//**
4478  * \brief See if changes have been made to the User. *
4479  * \returns true, if the user has been changed. *
4480  ****************************************************************************************/
4481  this.isUserDirty = function () {
4482  var edited_user_object = document.getElementById('bmlt_admin_single_user_editor_div').current_user_object;
4483  var original_user_object = null;
4484  var index = 0;
4485 
4486  if ( edited_user_object[0] > 0 ) {
4487  for (; index < g_users.length; index++) {
4488  if ( g_users[index][0] == edited_user_object[0] ) {
4489  original_user_object = g_users[index];
4490  break;
4491  };
4492  };
4493  } else {
4494  original_user_object = this.makeANewUser();
4495  };
4496 
4497  var current = JSON.stringify(edited_user_object);
4498  var orig = JSON.stringify(original_user_object);
4499  var ret = (current != orig);
4500 
4501  return ret;
4502  };
4503 
4504  /************************************************************************************//**
4505  * \brief This simply creates a brand-new, unsullied User object. *
4506  * \returns a new user object (which is really an array). *
4507  ****************************************************************************************/
4508  this.makeANewUser = function () {
4509  var new_user_object = new Array;
4510  new_user_object[0] = 0;
4511  new_user_object[1] = '';
4512  new_user_object[2] = '';
4513  new_user_object[3] = '';
4514  new_user_object[4] = '';
4515  new_user_object[5] = 4;
4516  new_user_object[6] = '';
4517  new_user_object[7] = -1;
4518 
4519  return new_user_object;
4520  };
4521 
4522  /************************************************************************************//**
4523  * \brief This sets the state of the User editor save button. *
4524  ****************************************************************************************/
4525  this.validateUserEditorButtons = function () {
4526  var save_button = document.getElementById('bmlt_admin_user_editor_form_user_save_button');
4527  var cancel_button = document.getElementById('bmlt_admin_user_editor_form_user_editor_cancel_button');
4528  var delete_button = document.getElementById('bmlt_admin_meeting_editor_form_user_delete_button');
4529 
4530  if ( this.isUserDirty() ) {
4531  save_button.className = 'bmlt_admin_ajax_button button';
4532  cancel_button.className = 'bmlt_admin_ajax_button button';
4533  } else {
4534  save_button.className = 'bmlt_admin_ajax_button button_disabled';
4535  cancel_button.className = 'bmlt_admin_ajax_button button_disabled';
4536  };
4537 
4538  if ( g_is_server_admin ) {
4539  delete_button.className = 'bmlt_admin_ajax_button button';
4540  } else {
4541  delete_button.className = 'bmlt_admin_ajax_button button_disabled';
4542  }
4543 
4544  };
4545 
4546  // #mark -
4547  // #mark ########## Format Editor Section ##########
4548  // #mark -
4549 
4550  /************************************************************************************//**
4551  * \brief Toggles the visibility of the Format editor section. *
4552  ****************************************************************************************/
4553  this.toggleFormatEditor = function () {
4554  this.m_user_editor_panel_shown = !this.m_user_editor_panel_shown;
4555 
4556  var the_disclosure_div = document.getElementById('bmlt_admin_format_editor_disclosure_div');
4557  var the_editor_div = document.getElementById('bmlt_admin_format_editor_wrapper_div');
4558 
4559  if ( this.m_user_editor_panel_shown ) {
4560  the_disclosure_div.className = 'bmlt_admin_format_editor_disclosure_div bmlt_admin_format_editor_disclosure_div_open';
4561  the_editor_div.className = 'bmlt_admin_format_editor_wrapper_div';
4562  } else {
4563  the_disclosure_div.className = 'bmlt_admin_format_editor_disclosure_div bmlt_admin_format_editor_disclosure_div_closed';
4564  the_editor_div.className = 'bmlt_admin_format_editor_wrapper_div bmlt_admin_format_editor_wrapper_div_hidden';
4565  };
4566  };
4567 
4568  /************************************************************************************//**
4569  * \brief methods and variables for venue type format codes *
4570  ****************************************************************************************/
4571  this.getSharedIdForVenueTypeFormat = function(format_key) {
4572  // Get the shared_id for format_key (which should be one of 'HY', 'TC', or 'VM). This looks just at the English
4573  // versions of the formats; there might be a different key in other languages.
4574  // If there is more than one format with format_key, return the smallest shared ID. The
4575  // migrations code and menu changes are supposed to ensure that there is at least one. The migrations code
4576  // should also have ensured that there is an English version of each of these venue type formats (although some
4577  // of the other formats might not necessarily have an English version, hence the check).
4578  var id = null;
4579  for (var index = 0; index < g_formats_array.length; index++) {
4580  var f = g_formats_array[index]['formats'];
4581  if ('en' in f && 'key' in f['en'] && f['en']['key'] === format_key) {
4582  var i = parseInt(f['en']['shared_id']);
4583  if (!id || i < id) {
4584  id = i;
4585  }
4586  }
4587  }
4588  return id;
4589  }
4590 
4591  this.isVenueTypeFormatBySharedId = function(shared_id) {
4592  for (var i = 0; i < this.venueTypeFormatSharedIds.length; i++) {
4593  if (this.venueTypeFormatSharedIds[i] === shared_id) {
4594  return true;
4595  }
4596  }
4597  return false;
4598  }
4599 
4600  this.venueTypeFormatSharedIds = [
4601  this.getSharedIdForVenueTypeFormat('VM'),
4602  this.getSharedIdForVenueTypeFormat('HY'),
4604  ];
4605 
4607  'VM': this.getSharedIdForVenueTypeFormat('VM'),
4608  'HY': this.getSharedIdForVenueTypeFormat('HY'),
4609  'TC': this.getSharedIdForVenueTypeFormat('TC')
4610  };
4611 
4612  this.toggleVenueTypeFormat = function(id_bigint, master_format_code, checked) {
4613  var checkbox = document.getElementById("bmlt_admin_meeting_" + id_bigint + "_format_" + this.venueTypeSharedIdDict[master_format_code].toString() + "_checkbox");
4614  checkbox.checked = checked;
4615  $(checkbox).trigger('change');
4616  }
4617 
4618  this.venueTypeClick = function(event, id_bigint) {
4619  var venueType = $(event).val();
4620  if (venueType === "hybrid") {
4621  this.toggleVenueTypeFormat(id_bigint, 'HY', true);
4622  this.toggleVenueTypeFormat(id_bigint, 'TC', false);
4623  this.toggleVenueTypeFormat(id_bigint, 'VM', false);
4624  } else if (venueType === "virtualTC") {
4625  this.toggleVenueTypeFormat(id_bigint, 'HY', false);
4626  this.toggleVenueTypeFormat(id_bigint, 'TC', true);
4627  this.toggleVenueTypeFormat(id_bigint, 'VM', true);
4628  } else if (venueType === "virtual") {
4629  this.toggleVenueTypeFormat(id_bigint, 'HY', false);
4630  this.toggleVenueTypeFormat(id_bigint, 'TC', false);
4631  this.toggleVenueTypeFormat(id_bigint, 'VM', true);
4632  } else {
4633  this.toggleVenueTypeFormat(id_bigint, 'HY', false);
4634  this.toggleVenueTypeFormat(id_bigint, 'TC', false);
4635  this.toggleVenueTypeFormat(id_bigint, 'VM', false);
4636  }
4637  }
4638 
4639  /************************************************************************************//**
4640  * \brief This sets up the Format Editor for the selected Format. *
4641  ****************************************************************************************/
4642  this.populateFormatEditor = function () {
4643  var format_table = document.getElementById('bmlt_admin_format_editor_table');
4644 
4645  for (var index = 0; index < g_formats_array.length; index++) {
4646  var format_group = g_formats_array[index];
4647  var format_id = format_group.id;
4648  var format_lang_group = JSON.parse(JSON.stringify(format_group.formats)); // This will always be a copy.
4649 
4650  this.createFormatRow(index, format_id, format_lang_group, format_table, 0);
4651  };
4652 
4653  var create_format_line_tr = format_table.insertRow(-1);
4654  create_format_line_tr.id = 'format_create_line_tr';
4655 
4656  var format_create_td = create_format_line_tr.insertCell(-1);
4657  format_create_td.id = 'format_create_td';
4658  format_create_td.className = 'format_create_td';
4659 
4660  format_create_td.setAttribute('colspan', 6);
4661  format_create_td.colSpan = 6;
4662  var format_create_a = document.createElement('a');
4663  format_create_a.id = 'format_editor_create_a';
4664  format_create_a.className = 'bmlt_admin_ajax_button';
4665  format_create_a.appendChild(document.createTextNode(g_format_editor_create_format_button_text));
4666  format_create_a.href = 'javascript:admin_handler_object.createFormatOpen()';
4667 
4668  format_create_td.appendChild(format_create_a);
4669  };
4670 
4671  this.checkAllServiceBodies = function(button) {
4672  var desiredState = button.innerText == g_check_all_text;
4673  for (var i = 0; i < g_service_bodies_array.length; i++) {
4674  var serviceBodyId = g_service_bodies_array[i][0];
4675  var checkbox = document.getElementById("bmlt_admin_meeting_search_service_body_checkbox_" + serviceBodyId);
4676  checkbox.checked = desiredState;
4677  }
4678  button.innerText = desiredState ? g_uncheck_all_text : g_check_all_text;
4679  };
4680 
4681  /************************************************************************************//**
4682  * \brief This populates the format display list *
4683  ****************************************************************************************/
4684  this.createFormatRow = function (
4685  in_index, ///< The index, for styling the row.
4686  in_format_id, ///< The shared ID for the format
4687  in_format_lang_group, ///< The format objects
4688  in_container_table, ///< The table that will contain this row.
4689  in_offset ///< If the insertion needs to be offset, this is how much.
4690  ) {
4691  in_offset = parseInt(in_offset, 10); // Just to make sure.
4692  var format_line_tr = null;
4693  // The number of lines per format is the number of languages plus 2: one for NAWS code, and one for format_type
4694  var insertion_point = (g_formats_array.length + in_offset) * (g_langs.length + 2);
4695 
4696  var rowIsVenueTypeFormat = this.isVenueTypeFormatBySharedId(parseInt(in_format_id));
4697 
4698  if ( document.getElementById('format_create_line_tr') ) {
4699  format_line_tr = in_container_table.insertRow(insertion_point);
4700  insertion_point++;
4701  } else {
4702  format_line_tr = in_container_table.insertRow(-1);
4703  insertion_point = -1;
4704  };
4705 
4706  format_line_tr.id = 'format_editor_line_' + in_format_id + '_tr';
4707 
4708  var container_row = format_line_tr;
4709  var id_td = container_row.insertCell(-1);
4710  id_td.id = 'format_editor_id_' + in_format_id + '_td';
4711  id_td.className = 'format_editor_id_td';
4712  var node_text = (parseInt(in_format_id, 10) != 0) ? in_format_id.toString() : '';
4713 
4714  if ( node_text ) {
4715  id_td.appendChild(document.createTextNode(node_text));
4716  } else {
4717  id_td.innerHTML = '&nbsp;';
4718  };
4719 
4720  id_td.setAttribute('rowspan', g_langs.length + 1);
4721  id_td.rowSpan = g_langs.length;
4722  for (var c = 0; c < g_langs.length; c++) {
4723  var lang_key = g_langs[c];
4724  var format = (in_format_lang_group != null) ? (in_format_lang_group[lang_key] ? in_format_lang_group[lang_key] : '') : '';
4725 
4726  if ( !format ) {
4727  format = new Object;
4728  format.shared_id = in_format_id;
4729  format.lang_key = lang_key;
4730  format.lang_name = g_lang_names[lang_key];
4731  format.key = '';
4732  format.name = '';
4733  format.description = '';
4734 
4735  if ( !in_format_lang_group ) {
4736  in_format_lang_group = new Object;
4737  };
4738 
4739  in_format_lang_group[lang_key] = format;
4740  };
4741 
4742  var unique_id = in_format_id + '_' + lang_key;
4743 
4744  if ( c > 0 ) {
4745  container_row = in_container_table.insertRow(insertion_point);
4746  if ( insertion_point > 0 ) {
4747  insertion_point++;
4748  };
4749  container_row.id = 'format_editor_' + lang_key + '_line_' + in_format_id + '_tr';
4750  };
4751 
4752  container_row.format_group_objects = in_format_lang_group;
4753  if ( !in_format_id ) {
4754  container_row.className = 'new_format_line';
4755  } else {
4756  container_row.className = 'format_editor_format_line_tr format_editor_format_line_' + ((in_index % 2) ? 'even' : 'odd') + '_tr';
4757  };
4758 
4759  var format_lang_td = container_row.insertCell(-1);
4760  format_lang_td.id = 'format_editor_lang_' + unique_id + '_td';
4761  format_lang_td.className = 'format_editor_lang_td';
4762  format_lang_td.appendChild(document.createTextNode(format.lang_name));
4763 
4764  var format_key_td = container_row.insertCell(-1);
4765  format_key_td.id = 'format_editor_key_' + in_format_id + '_td';
4766  format_key_td.className = 'format_editor_key_td';
4767 
4768  var format_key_input = document.createElement('input');
4769  format_key_input.type = 'text';
4770  if (rowIsVenueTypeFormat && lang_key == 'en') {
4771  format_key_input.disabled = true;
4772  };
4773  format_key_input.format_object = format;
4774  format_key_input.data_member_name = 'key';
4775  format_key_input.tiny = true;
4776  format_key_input.value = htmlspecialchars_decode(format.key);
4777  format_key_input.defaultValue = '';
4778  format_key_input.id = 'bmlt_format_key_' + unique_id + '_text_item';
4779  format_key_input.onfocus= function () {
4780  admin_handler_object.handleTextInputFocus(this); };
4781  format_key_input.onblur= function () {
4782  admin_handler_object.handleTextInputBlur(this); };
4783  format_key_input.onkeyup = function () {
4784  admin_handler_object.handleFormatTextInput(this); };
4785  format_key_input.onpaste = function () {
4786  var input = this;
4787  setTimeout(function () {
4788  admin_handler_object.handleFormatTextInput(input); }, 0);
4789  };
4790  format_key_input.oncut = function () {
4791  var input = this;
4792  setTimeout(function () {
4793  admin_handler_object.handleFormatTextInput(input); }, 0);
4794  };
4795 
4796 
4797  format_key_td.appendChild(format_key_input);
4798 
4799  var format_name_td = container_row.insertCell(-1);
4800  format_name_td.id = 'format_editor_name_' + unique_id + '_td';
4801  format_name_td.className = 'format_editor_name_td';
4802 
4803  var format_name_input = document.createElement('input');
4804  format_name_input.type = 'text';
4805  format_name_input.format_object = format;
4806  format_name_input.data_member_name = 'name';
4807  format_name_input.small = true;
4808  format_name_input.value = htmlspecialchars_decode(format.name);
4809  format_name_input.defaultValue = '';
4810  format_name_input.id = 'bmlt_format_name_' + unique_id + '_text_item';
4811  format_name_input.onfocus= function () {
4812  admin_handler_object.handleTextInputFocus(this); };
4813  format_name_input.onblur= function () {
4814  admin_handler_object.handleTextInputBlur(this); };
4815  format_name_input.onkeyup = function () {
4816  admin_handler_object.handleFormatTextInput(this); };
4817  format_name_input.onpaste = function () {
4818  var input = this;
4819  setTimeout(function () {
4820  admin_handler_object.handleFormatTextInput(input); }, 0);
4821  };
4822  format_name_input.oncut = function () {
4823  var input = this;
4824  setTimeout(function () {
4825  admin_handler_object.handleFormatTextInput(input); }, 0);
4826  };
4827 
4828 
4829  format_name_td.appendChild(format_name_input);
4830 
4831  var format_description_td = container_row.insertCell(-1);
4832  format_description_td.id = 'format_editor_decription_' + unique_id + '_td';
4833  format_description_td.className = 'format_editor_description_td';
4834 
4835  var format_description_input = document.createElement('textarea');
4836  format_description_input.format_object = format;
4837  format_description_input.data_member_name = 'description';
4838  format_description_input.value = htmlspecialchars_decode(format.description);
4839  format_description_input.id = 'bmlt_format_description_' + unique_id + '_text_item';
4840  format_description_input.med = true;
4841  format_description_input.onfocus= function () {
4842  admin_handler_object.handleTextInputFocus(this); };
4843  format_description_input.onblur= function () {
4844  admin_handler_object.handleTextInputBlur(this); };
4845  format_description_input.onkeyup = function () {
4846  admin_handler_object.handleFormatTextInput(this); };
4847  format_description_input.onpaste = function () {
4848  var input = this;
4849  setTimeout(function () {
4850  admin_handler_object.handleFormatTextInput(input); }, 0);
4851  };
4852  format_description_input.oncut = function () {
4853  var input = this;
4854  setTimeout(function () {
4855  admin_handler_object.handleFormatTextInput(input); }, 0);
4856  };
4857 
4858 
4859  format_description_td.appendChild(format_description_input);
4860 
4861  if ( c == 0 ) {
4862  var format_buttons_td = container_row.insertCell(-1);
4863  format_buttons_td.id = 'format_editor_buttons_' + in_format_id + '_td';
4864  format_buttons_td.className = 'format_editor_buttons_td' + ((in_format_id == 0) ? ' bmlt_admin_new_format_editor_td' : '');
4865  format_buttons_td.setAttribute('rowspan', g_langs.length);
4866  format_buttons_td.rowSpan = g_langs.length;
4867 
4868  var format_change_div = document.createElement('div');
4869  format_change_div.id = 'format_editor_change_' + in_format_id + '_div';
4870  format_change_div.className = 'format_editor_change_div';
4871 
4872  var format_change_a = document.createElement('a');
4873  format_change_a.id = 'format_editor_change_' + in_format_id + '_a';
4874  format_change_a.format_group_objects = in_format_lang_group;
4875  format_change_a.className = 'bmlt_admin_ajax_button button_disabled';
4876  if ( in_format_id ) {
4877  format_change_a.appendChild(document.createTextNode(g_format_editor_change_format_button_text));
4878  } else {
4879  format_change_a.appendChild(document.createTextNode(g_format_editor_create_this_format_button_text));
4880  };
4881 
4882  format_change_a.href = 'javascript:admin_handler_object.saveFormat(' + in_format_id + ')';
4883 
4884  format_change_div.appendChild(format_change_a);
4885 
4886  var new_throbber_span = document.createElement('span');
4887  new_throbber_span.className = 'item_hidden';
4888  new_throbber_span.id = 'format_editor_change_' + in_format_id + '_throbber_span';
4889 
4890  var new_throbber_img = document.createElement('img');
4891  new_throbber_img.src = g_throbber_image_loc;
4892  new_throbber_img.setAttribute('alt', 'AJAX Throbber');
4893 
4894  new_throbber_span.appendChild(new_throbber_img);
4895  format_change_div.appendChild(new_throbber_span);
4896  format_buttons_td.appendChild(format_change_div);
4897 
4898  if ( g_formats_array.length > 1 && !rowIsVenueTypeFormat ) { // Can't delete the last format or venue type formats
4899  var format_delete_div = document.createElement('div');
4900  format_delete_div.id = 'format_editor_delete_' + in_format_id + '_div';
4901  format_delete_div.className = 'format_editor_delete_div hide_in_new_format_admin';
4902 
4903  var format_delete_a = document.createElement('a');
4904  format_delete_a.id = 'format_editor_delete_' + in_format_id + '_a';
4905  format_change_a.format_group_objects = in_format_lang_group;
4906  format_delete_a.className = 'bmlt_admin_ajax_button';
4907  format_delete_a.appendChild(document.createTextNode(g_format_editor_delete_format_button_text));
4908  format_delete_a.href = 'javascript:admin_handler_object.deleteFormat(' + in_format_id + ')';
4909 
4910  format_delete_div.appendChild(format_delete_a);
4911  var new_throbber_span = document.createElement('span');
4912  new_throbber_span.className = 'item_hidden';
4913  new_throbber_span.id = 'format_editor_delete_' + in_format_id + '_throbber_span';
4914 
4915  var new_throbber_img = document.createElement('img');
4916  new_throbber_img.src = g_throbber_image_loc;
4917  new_throbber_img.setAttribute('alt', 'AJAX Throbber');
4918 
4919  new_throbber_span.appendChild(new_throbber_img);
4920  format_delete_div.appendChild(new_throbber_span);
4921  format_buttons_td.appendChild(format_delete_div);
4922  };
4923  };
4924 
4925  this.handleTextInputLoad(format_key_input, '');
4926  this.handleTextInputLoad(format_name_input, g_format_editor_name_default_text);
4927  this.handleTextInputLoad(format_description_input, g_format_editor_description_default_text);
4928  };
4929 
4930  container_row = in_container_table.insertRow(insertion_point);
4931  // if we're not in create_format mode
4932  if ( insertion_point > 0 ) {
4933  insertion_point++;
4934  };
4935  container_row.id = 'format_editor_naws_id_' + in_format_id + '_tr';
4936  var row_className = 'format_editor_naws_id_tr format_editor_format_line_' + ((in_index % 2) ? 'even' : 'odd') + '_tr';
4937 
4938  if ( in_format_id == 0 ) {
4939  row_className = 'format_editor_naws_id_tr new_format_line';
4940  };
4941 
4942  container_row.className = row_className;
4943 
4944  var naws_td = container_row.insertCell(-1);
4945  naws_td.id = 'format_editor_naws_id_' + in_format_id + '_td';
4946  naws_td.className = 'format_editor_naws_id_td';
4947  naws_td.setAttribute('colspan', 6);
4948 
4949  var naws_menu_prompt = document.createElement('label');
4950  naws_menu_prompt.id = 'format_editor_naws_id_' + in_format_id + '_label';
4951  naws_menu_prompt.className = 'format_editor_naws_id_label';
4952  naws_menu_prompt.setAttribute('for', 'format_editor_naws_id_' + in_format_id + '_select');
4953 
4954  naws_menu_prompt.appendChild(document.createTextNode(g_naws_popup_prompt));
4955  naws_td.appendChild(naws_menu_prompt);
4956 
4957  naws_menu = document.createElement('select');
4958  // the venue type formats have a fixed corresponding NAWS format
4959  if (rowIsVenueTypeFormat) {
4960  naws_menu.disabled = true;
4961  };
4962  naws_menu.id = 'format_editor_naws_id_' + in_format_id + '_select';
4963  naws_menu.className = 'format_editor_naws_id_select';
4964  naws_menu.format_group_objects = in_format_lang_group;
4965  naws_menu.shared_id = in_format_id;
4966  naws_menu.data_member_name = 'worldid_mixed';
4967  naws_menu.onchange = function () {
4968  admin_handler_object.handleFormatNAWSSelectInput(this); };
4969 
4970  for (var i = 0; i < g_naws_values.length; i++) {
4971  var val = g_naws_values[i].value ? htmlspecialchars_decode(g_naws_values[i].value) : '';
4972  if ( val ) {
4973  var key = g_naws_values[i].key ? g_naws_values[i].key: '';
4974  var opt = document.createElement('option');
4975  opt.value = htmlspecialchars_decode(key);
4976  opt.appendChild(document.createTextNode(htmlspecialchars_decode(val)));
4977  };
4978 
4979  naws_menu.appendChild(opt);
4980  };
4981 
4982  var key_match = false;
4983 
4984  var format_world_id_key = in_format_lang_group.en.worldid_mixed ? htmlspecialchars_decode(in_format_lang_group.en.worldid_mixed) : null;
4985 
4986  // Make sure the correct value is selected.
4987  if ( format_world_id_key ) {
4988  for (var i = 0; i < g_naws_values.length; i++) {
4989  var key = g_naws_values[i].key ? htmlspecialchars_decode(g_naws_values[i].key) : '';
4990  if ( key == format_world_id_key ) {
4991  key_match = true;
4992  naws_menu.selectedIndex = i;
4993  break;
4994  };
4995  };
4996  };
4997 
4998  if ( !key_match ) {
4999  naws_menu.selectedIndex = 0;
5000  };
5001 
5002  naws_td.appendChild(naws_menu);
5003 
5004  /************************************************************************************//**
5005  * \brief Handle data input from the text items. *
5006  ****************************************************************************************/
5007  this.handleFormatNAWSSelectInput = function ( in_select_input_object ///< This will contain the affected select input
5008  ) {
5009  var new_value = in_select_input_object.options[in_select_input_object.selectedIndex].value;
5010 
5011  for (var c = 0; c < g_langs.length; c++) {
5012  in_select_input_object.format_group_objects[g_langs[c]].worldid_mixed = new_value;
5013  };
5014 
5015  this.evaluateFormatState(in_select_input_object.shared_id);
5016  };
5017  /***
5018  * Begin Format-Type-Enum
5019  */
5020  container_row = in_container_table.insertRow(insertion_point);
5021  container_row.id = 'format_editor_formatType_' + in_format_id + '_tr';
5022  var row_className = 'format_editor_naws_id_tr format_editor_format_line_' + ((in_index % 2) ? 'even' : 'odd') + '_tr';
5023 
5024  if ( in_format_id == 0 ) {
5025  row_className = 'format_editor_naws_id_tr new_format_line';
5026  };
5027 
5028  container_row.className = row_className;
5029 
5030  var formatType_td = container_row.insertCell(-1);
5031  formatType_td.id = 'format_editor_formatType_' + in_format_id + '_td';
5032  formatType_td.className = 'format_editor_naws_id_td';
5033  formatType_td.setAttribute('colspan', 6);
5034 
5035  var formatType_menu_prompt = document.createElement('label');
5036  formatType_menu_prompt.id = 'format_editor_naws_id_' + in_format_id + '_label';
5037  formatType_menu_prompt.className = 'format_editor_naws_id_label';
5038  formatType_menu_prompt.setAttribute('for', 'format_editor_formatType_' + in_format_id + '_select');
5039 
5040  formatType_menu_prompt.appendChild(document.createTextNode(g_formatType_popup_prompt));
5041  formatType_td.appendChild(formatType_menu_prompt);
5042 
5043  formatType_menu = document.createElement('select');
5044  // the venue type formats have a fixed formatType
5045  if (rowIsVenueTypeFormat) {
5046  formatType_menu.disabled = true;
5047  };
5048  formatType_menu.id = 'format_editor_formatType_' + in_format_id + '_select';
5049  formatType_menu.className = 'format_editor_naws_id_select';
5050  formatType_menu.format_group_objects = in_format_lang_group;
5051  formatType_menu.shared_id = in_format_id;
5052  formatType_menu.data_member_name = 'format_type_enum';
5053  formatType_menu.onchange = function () {
5054  admin_handler_object.handleFormatTypeSelectInput(this); };
5055 
5056  for (var i = 0; i < g_formatType_values.length; i++) {
5057  var val = g_formatType_values[i].value ? htmlspecialchars_decode(g_formatType_values[i].value) : '';
5058  if ( val ) {
5059  var key = g_formatType_values[i].key ? g_formatType_values[i].key: '';
5060  var opt = document.createElement('option');
5061  opt.value = htmlspecialchars_decode(key);
5062  opt.appendChild(document.createTextNode(htmlspecialchars_decode(val)));
5063  };
5064 
5065  formatType_menu.appendChild(opt);
5066  };
5067 
5068  var key_match = false;
5069  var format_type_key = in_format_lang_group.en.type ? htmlspecialchars_decode(in_format_lang_group.en.type) : null;
5070 
5071  // Make sure the correct value is selected.
5072  if ( format_type_key ) {
5073  for (var i = 0; i < g_formatType_values.length; i++) {
5074  var key = g_formatType_values[i].key ? htmlspecialchars_decode(g_formatType_values[i].key) : '';
5075  if ( key == format_type_key ) {
5076  key_match = true;
5077  formatType_menu.selectedIndex = i;
5078  break;
5079  };
5080  };
5081  };
5082 
5083  if ( !key_match ) {
5084  formatType_menu.selectedIndex = 0;
5085  };
5086 
5087  formatType_td.appendChild(formatType_menu);
5088 
5089  /************************************************************************************//**
5090  * \brief Handle data input from the text items. *
5091  ****************************************************************************************/
5092  this.handleFormatTypeSelectInput = function ( in_select_input_object ///< This will contain the affected select input
5093  ) {
5094  var new_value = in_select_input_object.options[in_select_input_object.selectedIndex].value;
5095 
5096  for (var c = 0; c < g_langs.length; c++) {
5097  in_select_input_object.format_group_objects[g_langs[c]].type = new_value;
5098  };
5099 
5100  this.evaluateFormatState(in_select_input_object.shared_id);
5101  };
5102 
5103  /************************************************************************************//**
5104  * \brief This goes through all the formats in the list, and ensures they have the *
5105  * proper styling to them. *
5106  ****************************************************************************************/
5107  this.restyleFormats = function () {
5108  for (var index = 0; index < g_formats_array.length; index++) {
5109  var format_group = g_formats_array[index];
5110  var format_id = format_group.id;
5111  for (var c = 0; c < g_langs.length; c++) {
5112  var lang_key = g_langs[c];
5113  var format_row = null;
5114  var format_row_2 = document.getElementById('format_editor_naws_id_' + format_id + '_tr');
5115  var format_row_3 = document.getElementById('format_editor_formatType_' + format_id + '_tr');
5116  format_row_3.className = format_row_2.className = 'format_editor_naws_id_tr format_editor_format_line_' + ((index % 2) ? 'even' : 'odd') + '_tr';
5117 
5118  if ( c == 0 ) {
5119  format_row = document.getElementById('format_editor_line_' + format_id + '_tr');
5120  } else {
5121  format_row = document.getElementById('format_editor_' + lang_key + '_line_' + format_id + '_tr');
5122  };
5123 
5124  if ( format_row ) {
5125  format_row.className = 'format_editor_format_line_tr format_editor_format_line_' + ((index % 2) ? 'even' : 'odd') + '_tr';
5126  };
5127  };
5128  };
5129  };
5130 
5131  /************************************************************************************//**
5132  * \brief Opens a new format editor row.. *
5133  ****************************************************************************************/
5134  this.createFormatOpen = function () {
5135  // There can only be one...
5136  var existing_new_format = document.getElementById('format_editor_line_0_tr');
5137  var create_button = document.getElementById('format_editor_create_a');
5138 
5139  if ( !existing_new_format ) {
5140  var table_element = document.getElementById('bmlt_admin_format_editor_table');
5141  this.createFormatRow(0, 0, null, table_element, 0);
5142  create_button.innerHTML = g_format_editor_cancel_create_format_button_text;
5143  create_button.href = 'javascript:admin_handler_object.cancelCreateNewFormat()';
5144  } else {
5145  create_button.innerHTML = g_format_editor_create_format_button_text;
5146  create_button.href = 'javascript:admin_handler_object.createFormatOpen()';
5147  };
5148  };
5149 
5150  /************************************************************************************//**
5151  * \brief Creates a new format editor row.. *
5152  ****************************************************************************************/
5153  this.cancelCreateNewFormat = function () {
5154  var existing_new_format = document.getElementById('format_editor_line_0_tr');
5155  var create_button = document.getElementById('format_editor_create_a');
5156 
5157  if ( document.getElementById('format_editor_line_0_tr') ) {
5158  existing_new_format.parentNode.removeChild(existing_new_format);
5159 
5160  for (var c = 1; c < g_langs.length; c++) { // The format section is actually multiple lines; one for each language.
5161  var lang_key = g_langs[c];
5162  var container_row = document.getElementById('format_editor_' + lang_key + '_line_0_tr');
5163 
5164  container_row.parentNode.removeChild(container_row);
5165  };
5166 
5167  var container_row = document.getElementById('format_editor_naws_id_0_tr');
5168  container_row.parentNode.removeChild(container_row);
5169 
5170  container_row = document.getElementById('format_editor_formatType_0_tr');
5171  container_row.parentNode.removeChild(container_row);
5172 
5173  create_button.innerHTML = g_format_editor_create_format_button_text;
5174  create_button.href = 'javascript:admin_handler_object.createFormatOpen()';
5175  };
5176  };
5177 
5178  /************************************************************************************//**
5179  * \brief Saves the changed format. *
5180  ****************************************************************************************/
5181  this.saveFormat = function ( in_format_id ///< The shared ID of the format.
5182  ) {
5183  var the_button = document.getElementById('format_editor_change_' + in_format_id + '_a');
5184 
5185  if ( this.isFormatDirty(in_format_id) ) {
5186  var edited_format_group = the_button.format_group_objects; // We fetch the format from the button.
5187 
5188  var new_id = in_format_id;
5189 
5190  if ( !new_id ) {
5191  var new_id = this.getNextFormatID();
5192  for (var c = 0; c < g_langs.length; c++) {
5193  edited_format_group[g_langs[c]].shared_id = new_id;
5194  };
5195  };
5196 
5197  // Special cases for the venue type formats HY, TC, and VM.
5198  // First check for key errors; if there is an error, pop up a warning and then return without saving.
5199  if ( this.formatCheckForKeyError(new_id, edited_format_group) ) {
5200  return;
5201  }
5202  // Next make sure that venue type formats have the correct world_id and type. (The only case where
5203  // this would happen is if there is a newly added additional format language -- but these values can't
5204  // be changed for venue type formats, so the user couldn't otherwise fix it.) *
5205  if ( this.isVenueTypeFormatBySharedId(new_id) ) {
5206  // just use the values for English (which should be correct already)
5207  var world_id = edited_format_group['en']['worldid_mixed'];
5208  var format_type = edited_format_group['en']['type'];
5209  for ( var k in edited_format_group ) {
5210  edited_format_group[k]['worldid_mixed'] = world_id;
5211  edited_format_group[k]['type'] = format_type;
5212  }
5213  }
5214 
5215  var json_to_send_to_server = JSON.stringify(edited_format_group); // We will be sending as a JSON object.
5216  var throbber_span = document.getElementById('format_editor_change_' + in_format_id + '_throbber_span');
5217  the_button.className = 'item_hidden';
5218  throbber_span.className = 'bmlt_admin_general_ajax_button_throbber_div';
5219 
5220  var format_line_tr = document.getElementById('format_editor_line_' + in_format_id + '_tr');
5221 
5222  var uri = g_ajax_callback_uri + '&set_format_change=' + encodeURIComponent(json_to_send_to_server);
5223 
5224  if ( format_line_tr.m_ajax_request_in_progress ) {
5225  format_line_tr.m_ajax_request_in_progress.abort();
5226  format_line_tr.m_ajax_request_in_progress = null;
5227  };
5228 
5229  var salt = new Date();
5230  uri += '&salt=' + salt.getTime();
5231 
5232  format_line_tr.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req,id) {
5233  admin_handler_object.saveFormatAJAXCallback(in_req,id); }, 'post',in_format_id);
5234  };
5235  };
5236 
5237  /************************************************************************************//**
5238  * \brief AJAX callback for the save operation. *
5239  ****************************************************************************************/
5240  this.saveFormatAJAXCallback = function (
5241  in_http_request, ///< The HTTPRequest object
5242  in_format_id
5243  ) {
5244  var the_button = document.getElementById('format_editor_change_' + in_format_id + '_a');
5245  var throbber_span = document.getElementById('format_editor_change_' + in_format_id + '_throbber_span');
5246  var edited_format_group = the_button.format_group_objects; // We fetch the format from the button.
5247 
5248  throbber_span.className = 'item_hidden';
5249  the_button.className = 'bmlt_admin_ajax_button';
5250  if ( in_http_request.responseText ) {
5251  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
5252  alert(g_AJAX_Auth_Failure);
5253  } else {
5254  eval('var json_object = ' + in_http_request.responseText + ';');
5255  };
5256  if ( json_object ) {
5257  if ( !json_object.success ) {
5258  alert(json_object.report);
5259  BMLT_Admin_StartFader('bmlt_admin_fader_format_editor_fail_div', this.m_failure_fade_duration);
5260  } else {
5261  edited_format_group = json_object.report;
5262  var index = 0;
5263  var handled = false;
5264  while ( index <= g_formats_array.length ) {
5265  if ( index == g_formats_array.length ) {
5266  g_formats_array[index] = new Object;
5267  g_formats_array[index].id = edited_format_group[g_langs[0]].shared_id;
5268  this.cancelCreateNewFormat();
5269  var format_table = document.getElementById('bmlt_admin_format_editor_table');
5270  this.createFormatRow(index, g_formats_array[index].id, edited_format_group, format_table, -1);
5271  handled = true;
5272  break;
5273  };
5274 
5275  if ( edited_format_group[g_langs[0]].shared_id == g_formats_array[index].id ) {
5276  g_formats_array[index].formats = JSON.parse(JSON.stringify(edited_format_group));
5277  BMLT_Admin_StartFader('bmlt_admin_fader_format_editor_success_div', this.m_success_fade_duration);
5278 
5279  if ( in_format_id ) {
5280  the_button.className += ' button_disabled';
5281  };
5282 
5283  this.restyleFormats();
5284  handled = true;
5285  break;
5286  };
5287 
5288  index++;
5289  };
5290 
5291  // If we went through without interruption, then the job was not complete.
5292  if ( !handled ) {
5293  BMLT_Admin_StartFader('bmlt_admin_fader_format_editor_fail_div', this.m_failure_fade_duration);
5294  };
5295  };
5296  };
5297  } else {
5298  BMLT_Admin_StartFader('bmlt_admin_fader_format_editor_fail_div', this.m_failure_fade_duration);
5299  };
5300  };
5301 
5302  /************************************************************************************//**
5303  * \brief Deletes the format. *
5304  ****************************************************************************************/
5305  this.deleteFormat = function ( in_format_id ///< The shared ID of the format.
5306  ) {
5307  if ( confirm(g_format_editor_delete_button_confirm) ) {
5308  var the_button = document.getElementById('format_editor_delete_' + in_format_id + '_a');
5309  var the_format_group = the_button.format_group_objects; // We fetch the format from the button.
5310  var format_line_tr = document.getElementById('format_editor_line_' + in_format_id + '_tr');
5311 
5312  var throbber_span = document.getElementById('format_editor_delete_' + in_format_id + '_throbber_span');
5313  the_button.className = 'item_hidden';
5314  throbber_span.className = 'bmlt_admin_general_ajax_button_throbber_div';
5315 
5316  var uri = g_ajax_callback_uri + '&delete_format=' + in_format_id;
5317 
5318  if ( format_line_tr.m_ajax_request_in_progress ) {
5319  format_line_tr.m_ajax_request_in_progress.abort();
5320  format_line_tr.m_ajax_request_in_progress = null;
5321  };
5322 
5323  var salt = new Date();
5324  uri += '&salt=' + salt.getTime();
5325 
5326  format_line_tr.m_ajax_request_in_progress = BMLT_AjaxRequest(uri, function (in_req,id) {
5327  admin_handler_object.deleteFormatAJAXCallback(in_req,id); }, 'post', in_format_id);
5328  };
5329  };
5330 
5331  /************************************************************************************//**
5332  * \brief AJAX callback for the save operation. *
5333  ****************************************************************************************/
5334  this.deleteFormatAJAXCallback = function (
5335  in_http_request, ///< The HTTPRequest object
5336  in_format_id ///< The format being deleted.
5337  ) {
5338  var the_button = document.getElementById('format_editor_delete_' + in_format_id + '_a');
5339  var throbber_span = document.getElementById('format_editor_delete_' + in_format_id + '_throbber_span');
5340  throbber_span.className = 'item_hidden';
5341  the_button.className = 'bmlt_admin_ajax_button';
5342 
5343  if ( in_http_request.responseText ) {
5344  if ( in_http_request.responseText == 'NOT AUTHORIZED' ) {
5345  alert(g_AJAX_Auth_Failure);
5346  } else {
5347  eval('var json_object = ' + in_http_request.responseText + ';');
5348  };
5349 
5350  if ( json_object ) {
5351  if ( !json_object.success ) {
5352  alert(json_object.report);
5353  BMLT_Admin_StartFader('bmlt_admin_fader_format_editor_delete_fail_div', this.m_failure_fade_duration);
5354  } else {
5355  var the_id = parseInt(json_object.report, 10);
5356  var index = 0;
5357  var handled = false;
5358 
5359  while ( index <= g_formats_array.length ) {
5360  if ( parseInt(g_formats_array[index].id, 10) == the_id ) {
5361  var container_row = document.getElementById('format_editor_line_' + the_id + '_tr');
5362 
5363  container_row.parentNode.removeChild(container_row);
5364 
5365  for (var c = 1; c < g_langs.length; c++) { // The format section is actually multiple lines; one for each language.
5366  var lang_key = g_langs[c];
5367  container_row = document.getElementById('format_editor_' + lang_key + '_line_' + the_id + '_tr');
5368  container_row.parentNode.removeChild(container_row);
5369  };
5370 
5371  container_row = document.getElementById('format_editor_naws_id_' + the_id + '_tr');
5372  container_row.parentNode.removeChild(container_row);
5373  container_row = document.getElementById('format_editor_formatType_' + the_id + '_tr');
5374  container_row.parentNode.removeChild(container_row);
5375 
5376  this.setWarningFaders();
5377  if ( g_formats_array.length > 1 ) {
5378  g_formats_array.splice(index, 1);
5379  } else {
5380  g_formats_array = Array();
5381  };
5382  BMLT_Admin_StartFader('bmlt_admin_fader_format_editor_delete_success_div', this.m_success_fade_duration);
5383  this.restyleFormats();
5384  handled = true;
5385  break;
5386  };
5387 
5388  index++;
5389  };
5390 
5391  if ( !handled ) {
5392  BMLT_Admin_StartFader('bmlt_admin_fader_format_editor_delete_fail_div', this.m_failure_fade_duration);
5393  };
5394  };
5395  };
5396  } else {
5397  BMLT_Admin_StartFader('bmlt_admin_fader_format_editor_delete_fail_div', this.m_failure_fade_duration);
5398  };
5399  };
5400 
5401  /************************************************************************************//**
5402  * \brief Handle data input from the text items. *
5403  ****************************************************************************************/
5404  this.handleFormatTextInput = function ( in_text_input_object ///< This will contain the affected text input
5405  ) {
5406  eval('in_text_input_object.format_object.' + in_text_input_object.data_member_name + ' = in_text_input_object.value;');
5407 
5408  this.evaluateFormatState(in_text_input_object.format_object.shared_id);
5409  };
5410 
5411  /************************************************************************************//**
5412  * \brief This function evaluates a changed format, and sets up the buttons. *
5413  ****************************************************************************************/
5414  this.evaluateFormatState = function ( in_format_id /// The ID of the format to check
5415  ) {
5416  var format_change_a = document.getElementById('format_editor_change_' + in_format_id + '_a');
5417 
5418  var className = 'bmlt_admin_ajax_button' + (this.isFormatDirty(in_format_id) ? '' : ' button_disabled');
5419 
5420  format_change_a.className = className;
5421  };
5422 
5423  /************************************************************************************//**
5424  * \brief This function checks if a format has been changed. *
5425  * \returns a Boolean. TRUE, if the format has been changed.
5426  ****************************************************************************************/
5427  this.isFormatDirty = function ( in_format_id /// The ID of the format to check
5428  ) {
5429  var format_change_a = document.getElementById('format_editor_change_' + in_format_id + '_a');
5430  var original_format_group_object = null;
5431  var edited_format_group_object = format_change_a.format_group_objects; // The edited format group is attached to the change button.
5432 
5433  for (var index = 0; index < g_formats_array.length; index++) {
5434  var format_group = g_formats_array[index];
5435  if ( in_format_id == format_group.id ) {
5436  original_format_group_object = format_group.formats;
5437  break;
5438  };
5439  };
5440 
5441  // We now have the original (unmodified) format group. We now compare this group to the values of the edite format group.
5442  // We compare them the simple way, by stringifying them, and comparing the strings.
5443 
5444  var original_string = JSON.stringify(original_format_group_object);
5445  var new_string = JSON.stringify(edited_format_group_object);
5446 
5447  return ( original_string != new_string );
5448  };
5449 
5450  /*********************************************************************************************//**
5451  * \brief This function checks for two kinds of key errors: *
5452  * 1) if one or more keys is missing for a venue type format (in any language) *
5453  * 2) if one of the reserved keys HY, TC, or VM is being used for English for some other format *
5454  * Pop up a warning if there is a key error. *
5455  * \returns a Boolean. TRUE, if there is a key error; FALSE if the keys are OK. *
5456  *************************************************************************************************/
5457  this.formatCheckForKeyError = function ( in_format_id, // The ID of the format to check
5458  edited_format_group // the new format to check
5459  ) {
5460  // if this is a venue type format, make sure it has a key for each language
5461  if ( this.isVenueTypeFormatBySharedId(in_format_id) ) {
5462  for ( var k in edited_format_group ) {
5463  if ( edited_format_group[k]['key'].trim() === '' ) {
5464  confirm(my_localized_strings['comdef_server_admin_strings']['format_editor_missing_key']);
5465  return true;
5466  }
5467  }
5468  return false;
5469  }
5470  // it's not a venue type format -- check if it's using one of the reserved keys for English
5471  if ( 'en' in edited_format_group && ['HY','TC','VM'].includes(edited_format_group['en']['key']) ) {
5472  confirm(my_localized_strings['comdef_server_admin_strings']['format_editor_reserved_key']);
5473  return true;
5474  }
5475  return false;
5476  };
5477 
5478  /************************************************************************************//**
5479  * \brief This will return a new format ID that comes after all the available ones. *
5480  * \returns an integer, containing the next format ID. *
5481  ****************************************************************************************/
5482  this.getNextFormatID = function () {
5483  var ret = 0;
5484 
5485  for (var index = 0; index < g_formats_array.length; index++) {
5486  var format_group = g_formats_array[index];
5487  if ( parseInt(format_group.id, 10) > ret ) {
5488  ret = parseInt(format_group.id, 10);
5489  };
5490  };
5491 
5492  return ( ret + 1 );
5493  };
5494  };
5495 
5496  // #mark -
5497  // #mark ########## Constructor ##########
5498  // #mark -
5499 
5500  /************************************************************************************//**
5501  * CONSTRUCTOR *
5502  ****************************************************************************************/
5503  this.m_server_admin_panel_shown = false;
5504  this.m_account_panel_shown = false;
5505  this.m_search_specifier_shown = true;
5506  this.m_meeting_editor_panel_shown = false;
5507  this.m_warn_user_to_refresh = false;
5508  this.m_success_fade_duration = 10000; ///< 10 seconds for a success fader.
5509  this.m_failure_fade_duration = 10000; ///< 10 seconds for a failure fader.
5510  this.m_format_editor_table_rows = 0;
5511 };
5512 
5513 // #mark -
5514 // #mark ########## Global Functions ##########
5515 // #mark -
5516 
5518 
5519 // #mark -
5520 // #mark AJAX Handler
5521 // #mark -
5522 
5523 /****************************************************************************************//**
5524  * \brief A simple, generic AJAX file upload function. *
5525  * *
5526  * \returns a new XMLHTTPRequest object. *
5527  ********************************************************************************************/
5529  url, ///< The URI to be called
5530  callback, ///< The success callback
5531  file, ///< The file object
5532  extra_data ///< If supplied, extra data to be delivered to the callback.
5533 ) {
5534  /************************************************************************************//**
5535  * \brief Create a generic XMLHTTPObject. *
5536  * *
5537  * This will account for the various flavors imposed by different browsers. *
5538  * *
5539  * \returns a new XMLHTTPRequest object. *
5540  ****************************************************************************************/
5541 
5542  function createXMLHTTPObject()
5543  {
5544  var XMLHttpArray = [
5545  function () {
5546  return new XMLHttpRequest()},
5547  function () {
5548  return new ActiveXObject("Msxml2.XMLHTTP")},
5549  function () {
5550  return new ActiveXObject("Msxml2.XMLHTTP")},
5551  function () {
5552  return new ActiveXObject("Microsoft.XMLHTTP")}
5553  ];
5554 
5555  var xmlhttp = false;
5556 
5557  for (var i=0; i < XMLHttpArray.length; i++) {
5558  try {
5559  xmlhttp = XMLHttpArray[i]();
5560  } catch (e) {
5561  continue;
5562  };
5563  break;
5564  };
5565 
5566  return xmlhttp;
5567  };
5568 
5569  var req = createXMLHTTPObject();
5570  req.finalCallback = callback;
5571 
5572  if ( extra_data != null ) {
5573  req.extra_data = extra_data;
5574  }
5575  req.open("POST", url, true);
5576  req.onreadystatechange = function() {
5577  if ( req.readyState != 4 ) {
5578  return;
5579  }
5580  if ( req.status != 200 ) {
5581  return;
5582  }
5583  callback(req, req.extra_data);
5584  req = null;
5585  };
5586 
5587  var formData = new FormData();
5588  formData.append("thefile", file);
5589  req.send(formData);
5590 
5591  return req;
5592 };
5593 
5594 /****************************************************************************************//**
5595  * \brief A simple, generic AJAX request function. *
5596  * *
5597  * \returns a new XMLHTTPRequest object. *
5598  ********************************************************************************************/
5600  url, ///< The URI to be called
5601  callback, ///< The success callback
5602  method, ///< The method ('get' or 'post')
5603  extra_data ///< If supplied, extra data to be delivered to the callback.
5604 ) {
5605  /************************************************************************************//**
5606  * \brief Create a generic XMLHTTPObject. *
5607  * *
5608  * This will account for the various flavors imposed by different browsers. *
5609  * *
5610  * \returns a new XMLHTTPRequest object. *
5611  ****************************************************************************************/
5612 
5613  function createXMLHTTPObject()
5614  {
5615  var XMLHttpArray = [
5616  function () {
5617  return new XMLHttpRequest()},
5618  function () {
5619  return new ActiveXObject("Msxml2.XMLHTTP")},
5620  function () {
5621  return new ActiveXObject("Msxml2.XMLHTTP")},
5622  function () {
5623  return new ActiveXObject("Microsoft.XMLHTTP")}
5624  ];
5625 
5626  var xmlhttp = false;
5627 
5628  for (var i=0; i < XMLHttpArray.length; i++) {
5629  try {
5630  xmlhttp = XMLHttpArray[i]();
5631  } catch (e) {
5632  continue;
5633  };
5634  break;
5635  };
5636 
5637  return xmlhttp;
5638  };
5639 
5640  var req = createXMLHTTPObject();
5641  req.finalCallback = callback;
5642  var sVars = null;
5643  method = method.toString().toUpperCase();
5644  var drupal_kludge = '';
5645 
5646  // Split the URL up, if this is a POST.
5647  if ( method == "POST" ) {
5648  var rmatch = /^([^\?]*)\?(.*)$/.exec(url);
5649  url = rmatch[1];
5650  sVars = rmatch[2];
5651  // This horrible, horrible kludge, is because Drupal insists on having its q parameter in the GET list only.
5652  var rmatch_kludge = /(q=admin\/settings\/bmlt)&?(.*)/.exec(rmatch[2]);
5653  if ( rmatch_kludge && rmatch_kludge[1] ) {
5654  url += '?'+rmatch_kludge[1];
5655  sVars = rmatch_kludge[2];
5656  };
5657  };
5658  if ( extra_data != null ) {
5659  req.extra_data = extra_data;
5660  };
5661  req.open(method, url, true);
5662  if ( method == "POST" ) {
5663  req.setRequestHeader("Method", "POST "+url+" HTTP/1.1");
5664  req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
5665  };
5666  req.onreadystatechange = function ( ) {
5667  if ( req.readyState != 4 ) {
5668  return;
5669  }
5670  if ( req.status != 200 ) {
5671  return;
5672  }
5673  callback(req, req.extra_data);
5674  req = null;
5675  };
5676  req.send(sVars);
5677 
5678  return req;
5679 };
5680 
5681 // #mark -
5682 // #mark Utility Functions
5683 // #mark -
5684 
5685 /****************************************************************************************//**
5686 * \brief Starts the message "fader." *
5687 * *
5688 * Simple fader, taken from here: *
5689 * http://www.switchonthecode.com/tutorials/javascript-tutorial-simple-fade-animation *
5690 ********************************************************************************************/
5692  in_eid, ///< The element ID to be faded.
5693  in_fade_time ///< The number of seconds to fade.
5694 ) {
5695  var in_element = document.getElementById(in_eid);
5696  if ( in_element ) {
5697  in_element.className = 'bmlt_admin_fader_div';
5698  in_element.FadeTimeTotal = in_fade_time;
5699  in_element.FadeTimeLeft = in_element.FadeTimeTotal;
5700  setTimeout("BMLT_Admin_animateFade(" + new Date().getTime() + ",'" + in_eid + "')", 33);
5701  };
5702 };
5703 
5704 /****************************************************************************************//**
5705 * \brief Animates the fade. *
5706 * *
5707 * Simple fader, taken from here: *
5708 * http://www.switchonthecode.com/tutorials/javascript-tutorial-simple-fade-animation *
5709 ********************************************************************************************/
5711  lastTick, ///< The time of the last tick.
5712  in_eid ///< The element ID
5713 ) {
5714  var in_element = document.getElementById(in_eid);
5715  if ( in_element ) {
5716  var curTick = new Date().getTime();
5717  var elapsedTicks = curTick - lastTick;
5718 
5719  if ( in_element.FadeTimeLeft <= elapsedTicks ) {
5720  in_element.className = 'bmlt_admin_fader_div item_hidden';
5721  in_element.FadeTimeTotal = null;
5722  in_element.FadeTimeLeft = null;
5723  in_element.FadeState = null;
5724  in_element.style.opacity = null;
5725  in_element.style.filter = null;
5726  return;
5727  };
5728 
5729  in_element.FadeTimeLeft -= elapsedTicks;
5730 
5731  var newOpVal = in_element.FadeTimeLeft/in_element.FadeTimeTotal;
5732 
5733  in_element.style.opacity = newOpVal;
5734  in_element.style.filter = 'alpha(opacity = ' + (newOpVal*100) + ')';
5735 
5736  setTimeout("BMLT_Admin_animateFade(" + curTick + ",'" + in_eid + "')", 33);
5737  };
5738 };
5739 
5740 /****************************************************************************************//**
5741 * \brief This allows you to get objects within a DOM node hierarchy that have a certain *
5742 * element name (type, such as 'div' or 'a'), and a className. *
5743 * This can be used to "drill into" a DOM hierarchy that doesn't have IDs. *
5744 * \returns an array of DOM elements that meet the criteria. *
5745 ********************************************************************************************/
5747  in_container_element, ///< The DOM node that contains the hierarchy
5748  in_element_type, ///< The type of node that you are seeking.
5749  in_element_className ///< The className for that element.
5750 ) {
5751  var starting_pool = in_container_element.getElementsByTagName(in_element_type);
5752  var ret = [];
5753  for (c = 0; c < starting_pool.length; c++) {
5754  if ( starting_pool[c].className == in_element_className ) {
5755  ret.append(starting_pool[c]);
5756  };
5757 
5758  var ret2 = BMLT_Admin_getChildElementsByClassName(starting_pool[c], in_element_type, in_element_className);
5759 
5760  if ( ret2 && ret2.length ) {
5761  ret = ret.concat(ret2);
5762  };
5763  };
5764 
5765  return ret;
5766 };
5767 
5768 /****************************************************************************************//**
5769 * \brief This allows you to search a particular DOM hierarchy for an element with an ID. *
5770 * This is useful for changing Node IDs in the case of cloneNode(). *
5771 * \returns a single DOM element, with the given ID. *
5772 ********************************************************************************************/
5774  in_container_element, ///< The DOM node that contains the hierarchy
5775  in_element_id ///< The ID you are looking for.
5776 ) {
5777  var ret = null;
5778 
5779  if ( in_container_element && in_container_element.id == in_element_id ) { // Low-hanging fruit.
5780  ret = in_container_element;
5781  } else {
5782  // If we have kids, we check each of them for the ID.
5783  if ( in_container_element && in_container_element.childNodes && in_container_element.childNodes.length ) {
5784  for (var c = 0; c < in_container_element.childNodes.length; c++) {
5785  ret = BMLT_Admin_getChildElementsById(in_container_element.childNodes[c], in_element_id);
5786 
5787  if ( ret ) {
5788  break;
5789  };
5790  };
5791  };
5792  };
5793 
5794  return ret;
5795 };
5796 
5797 /****************************************************************************************//**
5798 * \brief This replaces every instance of 'template' in a hierarchy's element ids with the *
5799 * the given ID. *
5800 ********************************************************************************************/
5802  in_container_element, ///< The DOM node that contains the hierarchy
5803  in_element_id ///< The ID you are replacing with.
5804 ) {
5805  var ret = null;
5806 
5807  if ( in_container_element ) {
5808  if ( in_container_element.attributes && in_container_element.attributes.length ) {
5809  for (var c = 0; c < in_container_element.attributes.length; c++) {
5810  if ( in_container_element.attributes[c].nodeValue ) {
5811  in_container_element.attributes[c].nodeValue = in_container_element.attributes[c].nodeValue.toString().replace(/template/g, in_element_id);
5812  };
5813  };
5814  };
5815 
5816  if ( in_container_element.id ) {
5817  in_container_element.id = in_container_element.id.replace(/template/g, in_element_id);
5818  };
5819  };
5820 
5821  // If we have kids, we check each of them for the ID.
5822  if ( in_container_element && in_container_element.childNodes && in_container_element.childNodes.length ) {
5823  for (var c = 0; c < in_container_element.childNodes.length; c++) {
5824  BMLT_Admin_changeTemplateIDToUseThisID(in_container_element.childNodes[c], in_element_id);
5825  };
5826  };
5827 
5828  return ret;
5829 };
5830 
5831 /************************************************************************************//**
5832  * \brief
5833  ****************************************************************************************/
5835  in_select_object,
5836  in_value
5837 ) {
5838  var setIndex = 0;
5839 
5840  for (var c = 0; c < in_select_object.options.length; c ++) {
5841  if (in_select_object.options[c].value == in_value) {
5842  setIndex = c;
5843  break;
5844  }
5845  }
5846 
5847  in_select_object.selectedIndex = setIndex;
5848 }
5849 
5850 /************************************************************************************//**
5851 * \brief
5852 ****************************************************************************************/
5854  in_select_object,
5855  in_value
5856 ) {
5857  var setIndex = 0;
5858 
5859  for (var c = 0; c < in_select_object.options.length; c ++) {
5860  if ( parseInt(in_select_object.options[c].value, 10) == parseInt(in_value, 10) ) {
5861  setIndex = c;
5862  break;
5863  };
5864  };
5865 
5866  in_select_object.selectedIndex = setIndex;
5867 };
5868 
5869 /****************************************************************************************//**
5870 * \brief This just traps the enter key for the text entry. *
5871 ********************************************************************************************/
5872 function BMLT_Admin_keyDown(event)
5873 {
5874  if ( admin_handler_object.m_search_specifier_shown && (event.keyCode == 13) ) {
5875  admin_handler_object.searchForMeetings();
5876  };
5877 };
5878 
5879 // #mark -
5880 // #mark ########## Third-Party Code ##########
5881 // #mark -
5883  string,
5884  quote_style
5885 ) {
5886  // http://kevin.vanzonneveld.net
5887  // + original by: Mirek Slugen
5888  // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
5889  // + bugfixed by: Mateusz "loonquawl" Zalega
5890  // + input by: ReverseSyntax
5891  // + input by: Slawomir Kaniecki
5892  // + input by: Scott Cariss
5893  // + input by: Francois
5894  // + bugfixed by: Onno Marsman
5895  // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
5896  // + bugfixed by: Brett Zamir (http://brett-zamir.me)
5897  // + input by: Ratheous
5898  // + input by: Mailfaker (http://www.weedem.fr/)
5899  // + reimplemented by: Brett Zamir (http://brett-zamir.me)
5900  // + bugfixed by: Brett Zamir (http://brett-zamir.me)
5901  // * example 1: htmlspecialchars_decode("<p>this -&gt; &quot;</p>", 'ENT_NOQUOTES');
5902  // * returns 1: '<p>this -> &quot;</p>'
5903  // * example 2: htmlspecialchars_decode("&amp;quot;");
5904  // * returns 2: '&quot;'
5905  var optTemp = 0,
5906  i = 0,
5907  noquotes = false;
5908 
5909  if (typeof quote_style === 'undefined') {
5910  quote_style = 2;
5911  };
5912 
5913  string = string.toString().replace(/&lt;/g, '<').replace(/&gt;/g, '>');
5914  var OPTS = {
5915  'ENT_NOQUOTES': 0,
5916  'ENT_HTML_QUOTE_SINGLE': 1,
5917  'ENT_HTML_QUOTE_DOUBLE': 2,
5918  'ENT_COMPAT': 2,
5919  'ENT_QUOTES': 3,
5920  'ENT_IGNORE': 4
5921  };
5922 
5923  if (quote_style === 0) {