diff --git a/.gitignore b/.gitignore
index b2a06a1..0c213d3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
.vscode/*
.DS_Store
.idea
+.phpunit.result.cache
vendor/
logs/
build/
diff --git a/.phpcs.xml b/.phpcs.xml
index b909cb3..2b905e1 100644
--- a/.phpcs.xml
+++ b/.phpcs.xml
@@ -35,7 +35,7 @@
custom standard so you don't have to specify the
patterns on the command line.
-->
- mpdf/*
+ vendor/*
+
You do not have permission to save this configuation!
';
+ } else {
+ $this->admin->save_admin_options();
+ echo '
Your changes were successfully saved!
';
+ $num = delete_transient($this->bread->get_TransientKey($this->bread->getRequestedSetting()));
+ if ($num > 0) {
+ echo "
$num Cache entries deleted
";
+ }
+ }
+ echo '
';
+ } elseif (isset($_REQUEST['pwsix_action']) && $_REQUEST['pwsix_action'] == "import_settings") {
+ echo '
Your file was successfully imported!
';
+ $num = delete_transient($this->bread->get_TransientKey($this->bread->getRequestedSetting()));
+ } elseif (isset($_REQUEST['pwsix_action']) && $_REQUEST['pwsix_action'] == "default_settings_success") {
+ echo '
Your default settings were successfully updated!
';
+ $num = delete_transient($this->bread->get_TransientKey($this->bread->getRequestedSetting()));
+ }
+ $this->bread->fillUnsetOptions();
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/admin/templates/10/flyer-landscape-largefont.json b/admin/templates/10/flyer-landscape-largefont.json
new file mode 100644
index 0000000..4ecfd50
--- /dev/null
+++ b/admin/templates/10/flyer-landscape-largefont.json
@@ -0,0 +1,81 @@
+{
+ "root_server": "",
+ "service_body_1": "Not Used",
+ "service_body_2": "Not Used",
+ "service_body_3": "Not Used",
+ "service_body_4": "Not Used",
+ "service_body_5": "Not Used",
+ "header_font_size": 12,
+ "front_page_content": "
\u00a0<\/p>\r\n
<\/p>\r\n
<\/p>\r\n
<\/p>\r\n
[service_body_1]<\/strong><\/span><\/p>\r\n <\/p>\r\n
MEETING LIST<\/strong><\/span><\/p>\r\n <\/p>\r\n
[date]<\/strong>\u00a0<\/span><\/p>\r\n <\/p>\r\n
<\/p>\r\n
24 HOUR HELPLINE<\/b><\/span><\/p>\r\n NUMBER <\/span><\/p>\r\n <\/p>\r\n
<\/p>\r\n
\u00a0<\/p>\r\n
\u00a0<\/p>\r\n
\u00a0<\/p>\r\n
\u00a0<\/p>\r\n
\u00a0<\/p>\r\n
\u00a0<\/p>\r\n
\u00a0<\/strong><\/p>\r\n\u00a0<\/p>\r\n
\u00a0<\/p>\r\n
https:\/\/na.org<\/b><\/p>\r\n
<\/p>\r\n
SUGGESTIONS FOR EVERYONE<\/strong><\/span><\/p>\r\nDON\\'T USE no matter what<\/strong><\/p>\r\nAsk your Higher Power to keep you clean<\/strong><\/p>\r\nCome early and stay late<\/strong><\/p>\r\nGet a home group<\/strong><\/p>\r\nGo to 90 meetings in 90 days<\/strong><\/p>\r\nRead NA literature daily<\/strong><\/p>\r\nGet and use a sponsor<\/strong><\/p>\r\nUse the PHONE<\/strong><\/p>\r\nKEEP COMING BACK. IT WORKS<\/strong><\/span><\/p>\r\n\u00a0<\/p>\r\n
Meetings Weekly:\u00a0[meeting_count]<\/p>",
+ "front_line_height": "1.0",
+ "content_font_size": 10,
+ "content_line_height": 1.2,
+ "front_page_font_size": 10,
+ "front_page_line_height": "1.0",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "letter",
+ "page_fold": "flyer",
+ "meeting_sort": "day",
+ "cache_time": 0,
+ "page_orientation": "L",
+ "custom_section_content": "
<\/p>\r\n
<\/p>\r\n
\r\n\r\n\r\nMEETING FORMAT LEGEND<\/span><\/strong><\/span><\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n[format_codes_used_basic]<\/p>\r\n
[new_column]<\/p>",
+ "custom_section_line_height": 1,
+ "custom_section_font_size": 12,
+ "column_line": false,
+ "used_format_1": "",
+ "time_clock": "12",
+ "column_gap": 6,
+ "margin_right": 5,
+ "margin_left": 5,
+ "margin_bottom": 5,
+ "margin_top": 5,
+ "meeting_template_content": "
\r\n\r\n\r\ntime<\/strong><\/td>\r\ngroup, location, info, street,\u00a0city, state,\u00a0zip\u00a0(formats)\u00a0comments<\/em><\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>",
+ "col_color": "#274fae",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "sub_header_shown": "display",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "include_protection": false,
+ "base_font": "dejavusanscondensed",
+ "protection_password": "",
+ "custom_query": "",
+ "extra_meetings": [],
+ "authors": [],
+ "pageheader_fontsize": 6.5,
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#000000",
+ "booklet_pages": false,
+ "additional_list_template_content": "",
+ "colorspace": "0",
+ "additional_list_language": "",
+ "weekday_start": "1",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "meeting_name",
+ "additional_list_custom_query": "",
+ "user_agent": "None",
+ "sslverify": "0",
+ "wheelchair_size": "20px",
+ "nonmeeting_footer": "{PAGENO}",
+ "meeting1_footer": "{PAGENO}",
+ "meeting2_footer": "",
+ "bread_version": "2.8.0",
+ "cont_header_shown": 0,
+ "margin_header": 0,
+ "margin_footer": 5,
+ "pageheader_content": "",
+ "watermark": "",
+ "main_grouping": "day",
+ "subgrouping": ""
+}
\ No newline at end of file
diff --git a/admin/templates/20/trifold-landscape-largefont.json b/admin/templates/20/trifold-landscape-largefont.json
new file mode 100644
index 0000000..d9bb6a7
--- /dev/null
+++ b/admin/templates/20/trifold-landscape-largefont.json
@@ -0,0 +1,85 @@
+{
+ "root_server": "",
+ "service_body_1": "Not Used",
+ "service_body_2": "Not Used",
+ "service_body_3": "Not Used",
+ "header_font_size": 14,
+ "front_page_content": "
\r\n
\r\n
\r\nNARCOTICS ANONYMOUS
\r\n[service_body_1]
\r\n
\r\n[month_lower] [year] Wöchentliche Meetings: [meeting_count]
\r\n
\r\n
",
+ "front_line_height": "1.4",
+ "content_font_size": 12,
+ "content_line_height": 1.1,
+ "front_page_font_size": 10.7,
+ "service_body_4": "Not Used",
+ "service_body_5": "Not Used",
+ "front_page_line_height": "1.2",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "letter",
+ "page_fold": "tri",
+ "meeting_sort": "day",
+ "cache_time": 0,
+ "custom_section_content": "\r\n\r\n\r\nMeeting Format Legend \r\n \r\n \r\n
\r\n[format_codes_used_basic]
\r\n
\r\n
\r\n
\r\n[new_column]
",
+ "custom_section_line_height": 1.1,
+ "page_orientation": "L",
+ "meeting_template": "",
+ "custom_section_font_size": 12.3,
+ "column_line": false,
+ "used_format_1": "",
+ "page_height": "258",
+ "column_gap": 5,
+ "margin_right": 5,
+ "margin_left": 5,
+ "margin_bottom": 5,
+ "margin_top": 5,
+ "meeting_template_content": "\r\n\r\n\r\ntime wheelchair \r\ngroup , location, info, street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info \r\n \r\n \r\n
",
+ "col_color": "#bfbfbf",
+ "time_clock": "12",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "include_protection": false,
+ "protection_password": "",
+ "extra_meetings": [],
+ "sub_header_shown": "display",
+ "margin_header": 10,
+ "pageheader_fontsize": 10,
+ "pageheader_text": "",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "base_font": "dejavusanscondensed",
+ "custom_query": "",
+ "watermark": "",
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#ffffff",
+ "booklet_pages": false,
+ "retrieve_all_fields": 1,
+ "weekday_start": "1",
+ "bread_version": "2.8.0",
+ "pageheader_content": "",
+ "authors": [],
+ "colorspace": "0",
+ "cont_header_shown": 1,
+ "user_agent": "None",
+ "main_grouping": "day",
+ "subgrouping": "",
+ "sslverify": "0",
+ "nonmeeting_footer": "Page {PAGENO}",
+ "meeting1_footer": "Page {PAGENO}",
+ "meeting2_footer": "",
+ "wheelchair_size": "20px",
+ "margin_footer": 5,
+ "additional_list_template_content": "",
+ "additional_list_language": "",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "weekday_tinyint,start_time",
+ "additional_list_custom_query": ""
+}
\ No newline at end of file
diff --git a/admin/templates/30/trifold-landscape-largefont.json b/admin/templates/30/trifold-landscape-largefont.json
new file mode 100644
index 0000000..22a1b85
--- /dev/null
+++ b/admin/templates/30/trifold-landscape-largefont.json
@@ -0,0 +1,84 @@
+{
+ "root_server": "",
+ "service_body_1": "Not Used",
+ "service_body_2": "Not Used",
+ "service_body_3": "Not Used",
+ "header_font_size": 12,
+ "front_page_content": "
\r\n
\r\nNARCOTICS ANONYMOUS
\r\n[service_body_1]
\r\n[month_lower] [year] Wöchentliche Meetings: [meeting_count]
\r\n
\r\n
",
+ "front_line_height": "1.4",
+ "content_font_size": 10,
+ "content_line_height": 1.1,
+ "front_page_font_size": 10.7,
+ "service_body_4": "Not Used",
+ "service_body_5": "Not Used",
+ "front_page_line_height": "1.2",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "letter",
+ "page_fold": "tri",
+ "meeting_sort": "day",
+ "cache_time": 0,
+ "custom_section_content": "
\r\n\r\n\r\n\r\nMeeting Format Legend \r\n \r\n \r\n
\r\n[format_codes_used_basic]
\r\n
\r\n
\r\n[new_column]
",
+ "custom_section_line_height": 1.1,
+ "page_orientation": "L",
+ "custom_section_font_size": 10,
+ "column_line": false,
+ "used_format_1": "",
+ "page_height": "258",
+ "column_gap": 5,
+ "margin_right": 5,
+ "margin_left": 5,
+ "margin_bottom": 5,
+ "margin_top": 5,
+ "meeting_template_content": "\r\n\r\n\r\ntime wheelchair \r\ngroup , location, info, street, city, state, zip (formats) comments virtual_meeting_additional_info \r\n \r\n \r\n
",
+ "col_color": "#bfbfbf",
+ "time_clock": "12",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "include_protection": false,
+ "protection_password": "",
+ "extra_meetings": [],
+ "sub_header_shown": "display",
+ "margin_header": 10,
+ "pageheader_fontsize": 10,
+ "pageheader_text": "",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "base_font": "dejavusanscondensed",
+ "custom_query": "",
+ "watermark": "",
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#ffffff",
+ "booklet_pages": false,
+ "retrieve_all_fields": 1,
+ "weekday_start": "1",
+ "bread_version": "2.8.0",
+ "pageheader_content": "",
+ "authors": [],
+ "colorspace": "0",
+ "cont_header_shown": 1,
+ "user_agent": "None",
+ "main_grouping": "day",
+ "subgrouping": "",
+ "sslverify": "0",
+ "nonmeeting_footer": "Page {PAGENO}",
+ "meeting1_footer": "Page {PAGENO}",
+ "meeting2_footer": "",
+ "wheelchair_size": "20px",
+ "margin_footer": 5,
+ "additional_list_template_content": "",
+ "additional_list_language": "",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "same",
+ "additional_list_custom_query": ""
+}
\ No newline at end of file
diff --git a/admin/templates/50/trifold-landscape-medfont.json b/admin/templates/50/trifold-landscape-medfont.json
new file mode 100644
index 0000000..49f2b32
--- /dev/null
+++ b/admin/templates/50/trifold-landscape-medfont.json
@@ -0,0 +1,84 @@
+{
+ "root_server": "",
+ "service_body_1": "Not Used",
+ "service_body_2": "Not Used",
+ "service_body_3": "Not Used",
+ "header_font_size": 10,
+ "front_page_content": "
\r\n
\r\nNARCOTICS ANONYMOUS
\r\n[service_body_1]
\r\n[month_lower] [year] Wöchentliche Meetings: [meeting_count]
\r\n
\r\n
",
+ "front_line_height": "1.4",
+ "content_font_size": 8,
+ "content_line_height": 1.1,
+ "front_page_font_size": 10.7,
+ "service_body_4": "Not Used",
+ "service_body_5": "Not Used",
+ "front_page_line_height": "1.2",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "letter",
+ "page_fold": "tri",
+ "meeting_sort": "day",
+ "cache_time": 0,
+ "custom_section_content": "
\r\n\r\n\r\n\r\nMeeting Format Legend \r\n \r\n \r\n
\r\n[format_codes_used_basic]
\r\n
\r\n
\r\n[new_column]
",
+ "custom_section_line_height": 1.1,
+ "page_orientation": "L",
+ "custom_section_font_size": 10,
+ "column_line": false,
+ "used_format_1": "",
+ "page_height": "258",
+ "column_gap": 5,
+ "margin_right": 5,
+ "margin_left": 5,
+ "margin_bottom": 5,
+ "margin_top": 5,
+ "meeting_template_content": "\r\n\r\n\r\ntime wheelchair \r\ngroup , location, info, street, city, state, zip (formats) comments virtual_meeting_additional_info \r\n \r\n \r\n
",
+ "col_color": "#bfbfbf",
+ "time_clock": "12",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "include_protection": false,
+ "protection_password": "",
+ "extra_meetings": [],
+ "sub_header_shown": "display",
+ "margin_header": 10,
+ "pageheader_fontsize": 10,
+ "pageheader_text": "",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "base_font": "dejavusanscondensed",
+ "custom_query": "",
+ "watermark": "",
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#ffffff",
+ "booklet_pages": false,
+ "retrieve_all_fields": 1,
+ "weekday_start": "1",
+ "bread_version": "2.8.0",
+ "pageheader_content": "",
+ "authors": [],
+ "colorspace": "0",
+ "cont_header_shown": 1,
+ "user_agent": "None",
+ "main_grouping": "day",
+ "subgrouping": "",
+ "sslverify": "0",
+ "nonmeeting_footer": "Page {PAGENO}",
+ "meeting1_footer": "Page {PAGENO}",
+ "meeting2_footer": "",
+ "wheelchair_size": "20px",
+ "margin_footer": 5,
+ "additional_list_template_content": "",
+ "additional_list_language": "",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "same",
+ "additional_list_custom_query": ""
+}
\ No newline at end of file
diff --git a/admin/templates/70/trifold-landscape-medfont.json b/admin/templates/70/trifold-landscape-medfont.json
new file mode 100644
index 0000000..3f086ff
--- /dev/null
+++ b/admin/templates/70/trifold-landscape-medfont.json
@@ -0,0 +1,85 @@
+{
+ "root_server": "",
+ "service_body_1": "Not Used",
+ "service_body_2": "Not Used",
+ "service_body_3": "Not Used",
+ "header_font_size": 10,
+ "front_page_content": "
\r\n
\r\n
\r\nNARCOTICS ANONYMOUS
\r\n[service_body_1]
\r\n
\r\n[month_lower] [year] Weekly Meetings: [meeting_count]
\r\n
\r\n
",
+ "front_line_height": "1.4",
+ "content_font_size": 8,
+ "content_line_height": 1.1,
+ "front_page_font_size": 10.7,
+ "service_body_4": "Not Used",
+ "service_body_5": "Not Used",
+ "front_page_line_height": "1.2",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "letter",
+ "page_fold": "tri",
+ "meeting_sort": "day",
+ "cache_time": 0,
+ "custom_section_content": "\r\n\r\n\r\nMeeting Format Legend \r\n \r\n \r\n
\r\n[format_codes_used_basic]
\r\n
\r\n[new_column]
",
+ "custom_section_line_height": 1.1,
+ "page_orientation": "L",
+ "meeting_template": "",
+ "custom_section_font_size": 12.3,
+ "column_line": false,
+ "used_format_1": "",
+ "page_height": "258",
+ "column_gap": 5,
+ "margin_right": 5,
+ "margin_left": 5,
+ "margin_bottom": 5,
+ "margin_top": 5,
+ "meeting_template_content": "\r\n\r\n\r\ntime wheelchair \r\ngroup , location, info, street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info \r\n \r\n \r\n
",
+ "col_color": "#bfbfbf",
+ "time_clock": "12",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "include_protection": false,
+ "protection_password": "",
+ "extra_meetings": [],
+ "sub_header_shown": "display",
+ "margin_header": 10,
+ "pageheader_fontsize": 10,
+ "pageheader_text": "",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "base_font": "dejavusanscondensed",
+ "custom_query": "",
+ "watermark": "",
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#ffffff",
+ "booklet_pages": false,
+ "retrieve_all_fields": 1,
+ "weekday_start": "1",
+ "bread_version": "2.8.0",
+ "pageheader_content": "",
+ "authors": [],
+ "colorspace": "0",
+ "cont_header_shown": 1,
+ "user_agent": "None",
+ "main_grouping": "day",
+ "subgrouping": "",
+ "sslverify": "0",
+ "nonmeeting_footer": "Page {PAGENO}",
+ "meeting1_footer": "Page {PAGENO}",
+ "meeting2_footer": "",
+ "wheelchair_size": "20px",
+ "margin_footer": 5,
+ "additional_list_template_content": "",
+ "additional_list_language": "",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "meeting_name",
+ "additional_list_custom_query": ""
+}
\ No newline at end of file
diff --git a/admin/templates/80/quadfold-portrait-max80.json b/admin/templates/80/quadfold-portrait-max80.json
new file mode 100644
index 0000000..24389d5
--- /dev/null
+++ b/admin/templates/80/quadfold-portrait-max80.json
@@ -0,0 +1,84 @@
+{
+ "root_server": "",
+ "service_body_1": "Not Used",
+ "service_body_2": "Not Used",
+ "service_body_3": "Not Used",
+ "header_font_size": 10,
+ "front_page_content": "
\r\n
\r\n
\r\nNARCOTICS ANONYMOUS
\r\n[service_body_1]
\r\n
\r\n[month_lower] [year] Weekly Meetings: [meeting_count]
\r\n
\r\n
",
+ "front_line_height": "1.4",
+ "content_font_size": 8,
+ "content_line_height": 1.1,
+ "front_page_font_size": 10.7,
+ "service_body_4": "Not Used",
+ "service_body_5": "Not Used",
+ "front_page_line_height": "1.2",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "letter",
+ "page_fold": "quad",
+ "meeting_sort": "day",
+ "cache_time": 0,
+ "custom_section_content": "\r\n\r\n\r\nMeeting Format Legend \r\n \r\n \r\n
\r\n[format_codes_used_basic]
\r\n
\r\n
\r\n
\r\n
\r\n
\r\n[new_column]
",
+ "custom_section_line_height": 1.1,
+ "page_orientation": "P",
+ "custom_section_font_size": 12.3,
+ "column_line": false,
+ "used_format_1": "",
+ "page_height": "258",
+ "column_gap": 5,
+ "margin_right": 5,
+ "margin_left": 5,
+ "margin_bottom": 5,
+ "margin_top": 5,
+ "meeting_template_content": "\r\n\r\n\r\ntime group , location, info, street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info \r\n \r\n \r\n
",
+ "col_color": "#bfbfbf",
+ "time_clock": "12",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "include_protection": false,
+ "protection_password": "",
+ "extra_meetings": [],
+ "sub_header_shown": "display",
+ "margin_header": 10,
+ "pageheader_fontsize": 10,
+ "pageheader_text": "",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "base_font": "dejavusanscondensed",
+ "custom_query": "",
+ "watermark": "",
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#ffffff",
+ "booklet_pages": false,
+ "retrieve_all_fields": 1,
+ "weekday_start": "1",
+ "bread_version": "2.8.0",
+ "pageheader_content": "",
+ "authors": [],
+ "colorspace": "0",
+ "cont_header_shown": 1,
+ "user_agent": "None",
+ "main_grouping": "day",
+ "subgrouping": "",
+ "sslverify": "0",
+ "nonmeeting_footer": "Page {PAGENO}",
+ "meeting1_footer": "Page {PAGENO}",
+ "meeting2_footer": "",
+ "wheelchair_size": "20px",
+ "margin_footer": 5,
+ "additional_list_template_content": "",
+ "additional_list_language": "",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "same",
+ "additional_list_custom_query": ""
+}
\ No newline at end of file
diff --git a/admin/templates/90/quadfold-portrait-smallfont.json b/admin/templates/90/quadfold-portrait-smallfont.json
new file mode 100644
index 0000000..f760c92
--- /dev/null
+++ b/admin/templates/90/quadfold-portrait-smallfont.json
@@ -0,0 +1,84 @@
+{
+ "root_server": "",
+ "service_body_1": "Not Used",
+ "service_body_2": "Not Used",
+ "service_body_3": "Not Used",
+ "header_font_size": 8,
+ "front_page_content": "
\r\n
\r\n
\r\nNARCOTICS ANONYMOUS
\r\n[service_body_1]
\r\n
\r\n[month_lower] [year] Weekly Meetings: [meeting_count]
\r\n
\r\n
",
+ "front_line_height": "1.4",
+ "content_font_size": 7,
+ "content_line_height": 1.1,
+ "front_page_font_size": 10.7,
+ "service_body_4": "Not Used",
+ "service_body_5": "Not Used",
+ "front_page_line_height": "1.2",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "letter",
+ "page_fold": "quad",
+ "meeting_sort": "day",
+ "cache_time": 0,
+ "custom_section_content": "
\r\n\r\n\r\n\r\nMeeting Format Legend \r\n \r\n \r\n
\r\n[format_codes_used_basic]
\r\n
\r\n
\r\n
\r\n[new_column]
",
+ "custom_section_line_height": 1.1,
+ "page_orientation": "P",
+ "custom_section_font_size": 8,
+ "column_line": false,
+ "used_format_1": "",
+ "page_height": "258",
+ "column_gap": 5,
+ "margin_right": 5,
+ "margin_left": 5,
+ "margin_bottom": 5,
+ "margin_top": 5,
+ "meeting_template_content": "\r\n\r\n\r\ntime group , location, info, street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info \r\n \r\n \r\n
",
+ "col_color": "#bfbfbf",
+ "time_clock": "12",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "include_protection": false,
+ "protection_password": "",
+ "extra_meetings": [],
+ "sub_header_shown": "display",
+ "margin_header": 10,
+ "pageheader_fontsize": 10,
+ "pageheader_text": "Narcotics Anonymous Meetings in der Deutschsprachigen Region",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "base_font": "dejavusanscondensed",
+ "custom_query": "",
+ "watermark": "",
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#ffffff",
+ "booklet_pages": false,
+ "retrieve_all_fields": 1,
+ "weekday_start": "1",
+ "bread_version": "2.8.0",
+ "pageheader_content": "",
+ "authors": [],
+ "colorspace": "0",
+ "cont_header_shown": 1,
+ "user_agent": "None",
+ "main_grouping": "day",
+ "subgrouping": "",
+ "sslverify": "0",
+ "nonmeeting_footer": "Page {PAGENO}",
+ "meeting1_footer": "Page {PAGENO}",
+ "meeting2_footer": "",
+ "wheelchair_size": "20px",
+ "margin_footer": 5,
+ "additional_list_template_content": "",
+ "additional_list_language": "",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "same",
+ "additional_list_custom_query": ""
+}
\ No newline at end of file
diff --git a/admin/templates/99999/book-landscape-medfont.json b/admin/templates/99999/book-landscape-medfont.json
new file mode 100644
index 0000000..7c6c69c
--- /dev/null
+++ b/admin/templates/99999/book-landscape-medfont.json
@@ -0,0 +1,84 @@
+{
+ "root_server": "",
+ "service_body_1": "",
+ "service_body_2": "",
+ "service_body_3": "",
+ "header_font_size": 8,
+ "front_page_content": "
\r\n
\r\n
\r\nNARCOTICS ANONYMOUS [service_body_1]
\r\n
\r\n[month_lower_de] [year] Weekly Meetings: [meeting_count]
\r\n
\r\n
\r\n
\r\n[page_break]
\r\n[start_page_numbers]
",
+ "front_line_height": "1.4",
+ "content_font_size": 7.2,
+ "content_line_height": 1.1,
+ "front_page_font_size": 10.7,
+ "service_body_4": "",
+ "service_body_5": "",
+ "front_page_line_height": "1.2",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "letter",
+ "page_fold": "half",
+ "meeting_sort": "city",
+ "cache_time": 0,
+ "custom_section_content": "\r\n\r\n\r\nMeeting Format Legend \r\n \r\n \r\n
\r\n[format_codes_used_detailed]
",
+ "custom_section_line_height": 1.1,
+ "page_orientation": "L",
+ "custom_section_font_size": 7.2,
+ "column_line": false,
+ "used_format_1": "Not Connected",
+ "page_height": "258",
+ "column_gap": 5,
+ "margin_right": 10,
+ "margin_left": 10,
+ "margin_bottom": 10,
+ "margin_top": 10,
+ "meeting_template_content": "\r\n\r\n\r\ntime group , location, info, street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info \r\n \r\n \r\n
",
+ "col_color": "#bfbfbf",
+ "time_clock": "12",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "include_protection": false,
+ "protection_password": "",
+ "extra_meetings": [],
+ "sub_header_shown": "display",
+ "margin_header": 10,
+ "pageheader_fontsize": 10,
+ "pageheader_text": "",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "base_font": "dejavusanscondensed",
+ "custom_query": "",
+ "watermark": "",
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#ffffff",
+ "booklet_pages": false,
+ "retrieve_all_fields": 1,
+ "weekday_start": "1",
+ "bread_version": "2.8.0",
+ "pageheader_content": "",
+ "authors": 1,
+ "colorspace": "0",
+ "cont_header_shown": 1,
+ "user_agent": "None",
+ "main_grouping": "day",
+ "subgrouping": "",
+ "sslverify": "0",
+ "nonmeeting_footer": "Page {PAGENO}",
+ "meeting1_footer": "Page {PAGENO}",
+ "meeting2_footer": "Page {PAGENO}",
+ "additional_list_template_content": "",
+ "additional_list_language": "",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "",
+ "additional_list_custom_query": "",
+ "wheelchair_size": "20px",
+ "margin_footer": 5
+}
\ No newline at end of file
diff --git a/admin/templates/99999/booklet-landscape-medfont.json b/admin/templates/99999/booklet-landscape-medfont.json
new file mode 100644
index 0000000..c8608e2
--- /dev/null
+++ b/admin/templates/99999/booklet-landscape-medfont.json
@@ -0,0 +1,84 @@
+{
+ "root_server": "",
+ "service_body_1": "Not Used",
+ "service_body_2": "Not Used",
+ "service_body_3": "Not Used",
+ "header_font_size": 12,
+ "front_page_content": "
\r\n
\r\nNARCOTICS ANONYMOUS
\r\n[service_body_1]
\r\n[month_lower] [year] Wöchentliche Meetings: [meeting_count]
\r\n
\r\n
",
+ "front_line_height": "1.4",
+ "content_font_size": 12,
+ "content_line_height": 1.1,
+ "front_page_font_size": 10.7,
+ "service_body_4": "Not Used",
+ "service_body_5": "Not Used",
+ "front_page_line_height": "1.2",
+ "time_option": 1,
+ "remove_space": true,
+ "page_size": "5inch",
+ "page_fold": "half",
+ "meeting_sort": "day",
+ "cache_time": 0,
+ "custom_section_content": "\r\n\r\n\r\nMeeting Format Legend \r\n \r\n \r\n
\r\n[format_codes_used_basic]
",
+ "custom_section_line_height": 1.1,
+ "page_orientation": "L",
+ "custom_section_font_size": 12.3,
+ "column_line": false,
+ "used_format_1": "",
+ "page_height": "258",
+ "column_gap": 5,
+ "margin_right": 5,
+ "margin_left": 5,
+ "margin_bottom": 5,
+ "margin_top": 5,
+ "meeting_template_content": "\r\n\r\n\r\ntime wheelchair \r\ngroup location, info street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info \r\n \r\n \r\n
",
+ "col_color": "#bfbfbf",
+ "time_clock": "12",
+ "header_text_color": "#ffffff",
+ "header_background_color": "#000000",
+ "header_uppercase": 1,
+ "header_bold": 1,
+ "weekday_language": "en",
+ "borough_suffix": "Borough",
+ "county_suffix": "County",
+ "include_protection": false,
+ "protection_password": "",
+ "extra_meetings": [],
+ "sub_header_shown": "display",
+ "margin_header": 10,
+ "pageheader_fontsize": 10,
+ "pageheader_text": "",
+ "neighborhood_suffix": "Neighborhood",
+ "city_suffix": "City",
+ "pagenumbering_font_size": 9,
+ "recurse_service_bodies": 1,
+ "extra_meetings_enabled": 0,
+ "base_font": "dejavusanscondensed",
+ "custom_query": "",
+ "watermark": "",
+ "suppress_heading": 0,
+ "pageheader_textcolor": "#000000",
+ "pageheader_backgroundcolor": "#ffffff",
+ "booklet_pages": true,
+ "retrieve_all_fields": 1,
+ "weekday_start": "1",
+ "bread_version": "2.8.0",
+ "pageheader_content": "",
+ "authors": [],
+ "colorspace": "0",
+ "cont_header_shown": 1,
+ "user_agent": "None",
+ "main_grouping": "day",
+ "subgrouping": "",
+ "sslverify": "0",
+ "nonmeeting_footer": "Page {PAGENO}",
+ "meeting1_footer": "Page {PAGENO}",
+ "meeting2_footer": "",
+ "wheelchair_size": "20px",
+ "margin_footer": 5,
+ "additional_list_template_content": "",
+ "additional_list_language": "",
+ "include_additional_list": false,
+ "additional_list_format_key": "",
+ "additional_list_sort_order": "same",
+ "additional_list_custom_query": ""
+}
\ No newline at end of file
diff --git a/admin/templates/meeting_data_templates.json b/admin/templates/meeting_data_templates.json
new file mode 100644
index 0000000..6b982c7
--- /dev/null
+++ b/admin/templates/meeting_data_templates.json
@@ -0,0 +1,24 @@
+{
+ "One Column Template [Time Meeting Data]": "time group , location, info, street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info
",
+ "Two Column Template [Time] [Meeting Data]": "time wheelchairgroup , location, info, street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info
",
+ "One Column Template with Day [Day Time Meeting Data]": "day_abbr time group , location, info, street,city, state,zip(formats)comments virtual_meeting_link virtual_meeting_additional_info
",
+ "Two Column Template with Day [Day/Time] [Meeting Data]": "day_abbr time wheelchairgroup , location, info, street, city, state, zip (formats) comments virtual_meeting_link virtual_meeting_additional_info
",
+ "Online Meeting Two Column - Link in QR-Code": [
+ "'",
+ "",
+ "",
+ "",
+ "day_abbr time ",
+ "[QRCode code='virtual_meeting_link' size='0.50']
",
+ " ",
+ "group ",
+ "comments
",
+ "formats
",
+ "phone_meeting_number
",
+ "virtual_meeting_additional_info
",
+ " ",
+ " ",
+ " ",
+ "
"
+ ]
+}
\ No newline at end of file
diff --git a/admin/tinymce/code/plugin.js b/admin/tinymce/code/plugin.js
new file mode 100644
index 0000000..9df09b3
--- /dev/null
+++ b/admin/tinymce/code/plugin.js
@@ -0,0 +1,71 @@
+/**
+ * plugin.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+/*global tinymce:true */
+
+tinymce.PluginManager.add(
+ 'code', function (editor) {
+ function showDialog()
+ {
+ var win = editor.windowManager.open(
+ {
+ title: "Source code",
+ body: {
+ type: 'textbox',
+ name: 'code',
+ multiline: true,
+ minWidth: editor.getParam("code_dialog_width", 600),
+ minHeight: editor.getParam("code_dialog_height", Math.min(tinymce.DOM.getViewPort().h - 200, 500)),
+ spellcheck: false,
+ style: 'direction: ltr; text-align: left'
+ },
+ onSubmit: function (e) {
+ // We get a lovely "Wrong document" error in IE 11 if we
+ // don't move the focus to the editor before creating an undo
+ // transation since it tries to make a bookmark for the current selection
+ editor.focus();
+
+ editor.undoManager.transact(
+ function () {
+ editor.setContent(e.data.code);
+ }
+ );
+
+ editor.selection.setCursorLocation();
+ editor.nodeChanged();
+ }
+ }
+ );
+
+ // Gecko has a major performance issue with textarea
+ // contents so we need to set it when all reflows are done
+ win.find('#code').value(editor.getContent({source_view: true}));
+ }
+
+ editor.addCommand("mceCodeEditor", showDialog);
+
+ editor.addButton(
+ 'code', {
+ icon: 'code',
+ tooltip: 'Source code',
+ onclick: showDialog
+ }
+ );
+
+ editor.addMenuItem(
+ 'code', {
+ icon: 'code',
+ text: 'Source code',
+ context: 'tools',
+ onclick: showDialog
+ }
+ );
+ }
+);
\ No newline at end of file
diff --git a/tinymce/code/plugin.min.js b/admin/tinymce/code/plugin.min.js
similarity index 100%
rename from tinymce/code/plugin.min.js
rename to admin/tinymce/code/plugin.min.js
diff --git a/tinymce/contextmenu/plugin.min.js b/admin/tinymce/contextmenu/plugin.min.js
similarity index 100%
rename from tinymce/contextmenu/plugin.min.js
rename to admin/tinymce/contextmenu/plugin.min.js
diff --git a/admin/tinymce/front_page_button/plugin.js b/admin/tinymce/front_page_button/plugin.js
new file mode 100644
index 0000000..1e3d062
--- /dev/null
+++ b/admin/tinymce/front_page_button/plugin.js
@@ -0,0 +1,15 @@
+tinymce.PluginManager.add(
+ 'gavickpro_tc_button', function (editor) {
+
+ editor.addButton(
+ 'gavickpro_tc_button', {
+ text: 'My test button',
+ icon: false,
+ onclick: function () {
+ editor.insertContent('Hello World!');
+ }
+ }
+ );
+
+ }
+);
\ No newline at end of file
diff --git a/admin/tinymce/front_page_button/plugin.min.js b/admin/tinymce/front_page_button/plugin.min.js
new file mode 100644
index 0000000..ae6ee07
--- /dev/null
+++ b/admin/tinymce/front_page_button/plugin.min.js
@@ -0,0 +1,369 @@
+(function () {
+ tinymce.PluginManager.add(
+ 'front_page_button', function ( editor, url ) {
+ editor.addButton(
+ 'front_page_button', {
+ text: 'Meeting List Shortcodes',
+ icon: false,
+ type: 'listbox',
+ menu: [
+ {
+ text: 'INSTRUCTIONS',
+ menu: [
+ {
+ text: 'Video Instructions',
+ onclick: function () {
+ editor.windowManager.open(
+ {
+ title: 'Shortcode Instructions',
+ url: 'https://nameetinglist.org/videos/nameetinglist.mp4',
+ width: 800,
+ height: 600,
+ buttons: [{
+ text: 'Close',
+ onclick: 'close'
+ }]
+ }
+ );
+ }
+ },
+ ]
+ },
+ {
+ text: 'Format Code Legend',
+ menu: [
+ {
+ text: 'Used Format Codes - Abbreviated - Same language as weekdays text',
+ onclick: function () {
+ editor.insertContent('[format_codes_used_basic]');
+ }
+ },
+ {
+ text: 'Used Format Codes - Detailed - Same language as weekdays text',
+ onclick: function () {
+ editor.insertContent('[format_codes_used_detailed]
');
+ }
+ },
+ {
+ text: 'All Format Codes - Abbreviated - Same language as weekdays text',
+ onclick: function () {
+ editor.insertContent('[format_codes_all_basic]
');
+ }
+ },
+ {
+ text: 'All Format Codes - Detailed - Same language as weekdays text',
+ onclick: function () {
+ editor.insertContent('[format_codes_all_detailed]
');
+ }
+ },
+ {
+ text: 'Format Table in other languages',
+ onclick: function() {alert("To insert a format table in another language, simply add _{code} to the shortcode, where code is the standard 2-letter abbreviation for the language. Eg, use '_es' to get spanish")}
+ }
+ ]
+ },
+ {
+ text: 'Helpline Template',
+ onclick: function () {
+ editor.insertContent('Big Bend Area - Tallahassee
877-340-5096
850-224-2321
Daytona Beach Area - Volusia County
800-206-0731
386-628-0318
First Coast Area - Duval County
904-723-5683
');
+ }
+ },
+ {
+ text: 'Phone List Template',
+ onclick: function () {
+ editor.insertContent('');
+ }
+ },
+ {
+ text: 'Header Template',
+ onclick: function () {
+ editor.insertContent('');
+ }
+ },
+ {
+ text: 'Additional Meetinglist Template',
+ onclick: function () {
+ editor.insertContent('[additional_meetinglist]
');
+ }
+ },
+ {
+ text: 'Service Body',
+ menu: [
+ {
+ text: 'Service Body 1',
+ onclick: function () {
+ editor.insertContent('[service_body_1]');
+ }
+ },
+ {
+ text: 'Service Body 2',
+ onclick: function () {
+ editor.insertContent('[service_body_2]');
+ }
+ },
+ {
+ text: 'Service Body 3',
+ onclick: function () {
+ editor.insertContent('[service_body_3]');
+ }
+ },
+ {
+ text: 'Service Body 4',
+ onclick: function () {
+ editor.insertContent('[service_body_4]');
+ }
+ },
+ {
+ text: 'Service Body 5',
+ onclick: function () {
+ editor.insertContent('[service_body_5]');
+ }
+ }
+ ]
+ },
+ {
+ text: 'Date',
+ menu: [
+ { text: 'Month (UPPER CASE)',
+ onclick: function () {
+ editor.insertContent('[month_upper]');
+ } }, { text: 'Month (Lower Case)', onclick: function () {
+ editor.insertContent('[month_lower]'); } }, { text: 'Month French (UPPER CASE)', onclick: function () {
+ editor.insertContent('[month_upper_fr]'); } }, { text: 'Month French (Lower Case)', onclick: function () {
+ editor.insertContent('[month_lower_fr]'); } }, { text: 'Month Spanish (UPPER CASE)', onclick: function () {
+ editor.insertContent('[month_upper_es]'); } }, { text: 'Month Spanish (Lower Case)', onclick: function () {
+ editor.insertContent('[month_lower_es]'); } }, {
+ text: 'Day',
+ onclick: function () {
+ editor.insertContent('[day]');
+ }
+ },
+ {
+ text: 'Year',
+ onclick: function () {
+ editor.insertContent('[year]');
+ }
+ }
+ ]
+ },
+ {
+ text: 'Querystring Overrides',
+ menu: [
+ {
+ text: 'QueryString Custom Text',
+ onclick: function () {
+ editor.insertContent('[querystring_custom_*]');
+ }
+ }
+ ]
+ },
+ {
+ text: 'Meeting Count',
+ onclick: function () {
+ editor.insertContent('[meeting_count]');
+ }
+ },
+ {
+ text: 'New Page (Booklet Only)',
+ onclick: function () {
+ editor.insertContent('[page_break]
');
+ }
+ },
+ {
+ text: 'Start Page Numbers (Booklet Only)',
+ onclick: function () {
+ editor.insertContent('[start_page_numbers]
');
+ }
+ },
+ {
+ text: 'New Column (Tri & Quad Fold Only)',
+ onclick: function () {
+ editor.insertContent('[new_column]
');
+ }
+ }
+ ]
+ }
+ );
+ editor.addButton(
+ 'custom_template_button_1', {
+ text: 'Meeting Templates',
+ icon: false,
+ type: 'listbox',
+ menu: Object.keys(meetingDataTemplates).reduce((carry,item) => {
+ carry.push({
+ text: item,
+ onclick: () => editor.setContent(
+ Array.isArray(meetingDataTemplates[item]) ?
+ meetingDataTemplates[item].join('') :meetingDataTemplates[item])
+ })
+ return carry;
+ },[])
+ }
+ );
+ editor.addButton(
+ 'custom_template_button_2', {
+ text: 'Meeting Template Fields',
+ icon: false,
+ type: 'listbox',
+ menu: [
+ {
+ text: 'Area',
+ menu: [
+ {
+ text: 'Area Name (area)',
+ onclick: function () {
+ editor.insertContent('area');
+ }
+ },
+ {
+ text: 'Area Initial (area_i)',
+ onclick: function () {
+ editor.insertContent('area_i');
+ }
+ }
+ ]
+ },
+ {
+ text: 'Meeting Location',
+ menu: [
+ {
+ text: 'Address (street)',
+ onclick: function () {
+ editor.insertContent('street');
+ }
+ },
+ {
+ text: 'Borough (borough)',
+ onclick: function () {
+ editor.insertContent('borough');
+ }
+ },
+ {
+ text: 'Bus Lines (bus_lines)',
+ onclick: function () {
+ editor.insertContent('bus_lines');
+ }
+ },
+ {
+ text: 'City (city)',
+ onclick: function () {
+ editor.insertContent('city');
+ }
+ },
+ {
+ text: 'County (county)',
+ onclick: function () {
+ editor.insertContent('county');
+ }
+ },
+ {
+ text: 'Location Name (location)',
+ onclick: function () {
+ editor.insertContent('location');
+ }
+ },
+ {
+ text: 'Location Extra Info (info)',
+ onclick: function () {
+ editor.insertContent('info');
+ }
+ },
+ { text: 'Neighborhood (neighborhood)', onclick: function () {
+ editor.insertContent('neighborhood'); } }, { text: 'State (state)', onclick: function () {
+ editor.insertContent('state'); } }, {
+ text: 'Zip Code (zip)',
+ onclick: function () {
+ editor.insertContent('zip');
+ }
+ }
+ ]
+ },
+ {
+ text: 'Meeting Information',
+ menu: [
+ {
+ text: 'Comments (comments)',
+ onclick: function () {
+ editor.insertContent('comments');
+ }
+ },
+ {
+ text: 'Duration Hours (hrs)',
+ onclick: function () {
+ editor.insertContent('hrs');
+ }
+ },
+ {
+ text: 'Duration Minutes (mins)',
+ onclick: function () {
+ editor.insertContent('mins');
+ }
+ },
+ {
+ text: 'Email Contact (email)',
+ onclick: function () {
+ editor.insertContent('email');
+ }
+ },
+ {
+ text: 'Format Codes (formats)',
+ onclick: function () {
+ editor.insertContent('formats');
+ }
+ },
+ {
+ text: 'Group Name (group)',
+ onclick: function () {
+ editor.insertContent('group');
+ }
+ },
+ {
+ text: 'Start Time (time)',
+ onclick: function () {
+ editor.insertContent('time');
+ }
+ },
+ {
+ text: 'Weekday (day)',
+ onclick: function () {
+ editor.insertContent('day');
+ }
+ },
+ {
+ text: 'Weekday Abbreviated (day_abbr)',
+ onclick: function () {
+ editor.insertContent('day_abbr');
+ }
+ },
+ {
+ text: 'Virtual Meeting Link (virtual_meeting_link)',
+ onclick: function () {
+ editor.insertContent('virtual_meeting_link');
+ }
+ },
+ {
+ text: 'Virtual Meeting Info (virtual_meeting_additional_info)',
+ onclick: function () {
+ editor.insertContent('virtual_meeting_additional_info');
+ }
+ },
+ {
+ text: 'Phone Meeting Number (phone_meeting_number)',
+ onclick: function () {
+ editor.insertContent('phone_meeting_number');
+ }
+ },
+ {
+ text: 'QRCode (virtual_meeting_link)',
+ onclick: function () {
+ editor.insertContent('[QRCode code="virtual_meeting_link" size="0.8"]');
+ }
+ },
+ ]
+ }
+ ]
+ }
+ );
+ }
+ );
+})();
\ No newline at end of file
diff --git a/admin/tinymce/table/plugin.js b/admin/tinymce/table/plugin.js
new file mode 100644
index 0000000..207d221
--- /dev/null
+++ b/admin/tinymce/table/plugin.js
@@ -0,0 +1,2967 @@
+/**
+ * Compiled inline version. (Library mode)
+ */
+
+/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
+/*globals $code */
+
+(function (exports, undefined) {
+ "use strict";
+
+ var modules = {};
+
+ function require(ids, callback)
+ {
+ var module, defs = [];
+
+ for (var i = 0; i < ids.length; ++i) {
+ module = modules[ids[i]] || resolve(ids[i]);
+ if (!module) {
+ throw 'module definition dependecy not found: ' + ids[i];
+ }
+
+ defs.push(module);
+ }
+
+ callback.apply(null, defs);
+ }
+
+ function define(id, dependencies, definition)
+ {
+ if (typeof id !== 'string') {
+ throw 'invalid module definition, module id must be defined and be a string';
+ }
+
+ if (dependencies === undefined) {
+ throw 'invalid module definition, dependencies must be specified';
+ }
+
+ if (definition === undefined) {
+ throw 'invalid module definition, definition function must be specified';
+ }
+
+ require(
+ dependencies, function () {
+ modules[id] = definition.apply(null, arguments);
+ }
+ );
+ }
+
+ function defined(id)
+ {
+ return !!modules[id];
+ }
+
+ function resolve(id)
+ {
+ var target = exports;
+ var fragments = id.split(/[.\/]/);
+
+ for (var fi = 0; fi < fragments.length; ++fi) {
+ if (!target[fragments[fi]]) {
+ return;
+ }
+
+ target = target[fragments[fi]];
+ }
+
+ return target;
+ }
+
+ function expose(ids)
+ {
+ for (var i = 0; i < ids.length; i++) {
+ var target = exports;
+ var id = ids[i];
+ var fragments = id.split(/[.\/]/);
+
+ for (var fi = 0; fi < fragments.length - 1; ++fi) {
+ if (target[fragments[fi]] === undefined) {
+ target[fragments[fi]] = {};
+ }
+
+ target = target[fragments[fi]];
+ }
+
+ target[fragments[fragments.length - 1]] = modules[id];
+ }
+ }
+
+ // Included from: js/tinymce/plugins/table/classes/TableGrid.js
+
+ /**
+ * TableGrid.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+ /**
+ * This class creates a grid out of a table element. This
+ * makes it a whole lot easier to handle complex tables with
+ * col/row spans.
+ *
+ * @class tinymce.tableplugin.TableGrid
+ * @private
+ */
+ define(
+ "tinymce/tableplugin/TableGrid", [
+ "tinymce/util/Tools",
+ "tinymce/Env"
+ ], function (Tools, Env) {
+ var each = Tools.each;
+
+ function getSpanVal(td, name)
+ {
+ return parseInt(td.getAttribute(name) || 1, 10);
+ }
+
+ return function (editor, table) {
+ var grid, gridWidth, startPos, endPos, selectedCell, selection = editor.selection, dom = selection.dom;
+
+ function buildGrid()
+ {
+ var startY = 0;
+
+ grid = [];
+ gridWidth = 0;
+
+ each(
+ ['thead', 'tbody', 'tfoot'], function (part) {
+ var rows = dom.select('> ' + part + ' tr', table);
+
+ each(
+ rows, function (tr, y) {
+ y += startY;
+
+ each(
+ dom.select('> td, > th', tr), function (td, x) {
+ var x2, y2, rowspan, colspan;
+
+ // Skip over existing cells produced by rowspan
+ if (grid[y]) {
+ while (grid[y][x]) {
+ x++;
+ }
+ }
+
+ // Get col/rowspan from cell
+ rowspan = getSpanVal(td, 'rowspan');
+ colspan = getSpanVal(td, 'colspan');
+
+ // Fill out rowspan/colspan right and down
+ for (y2 = y; y2 < y + rowspan; y2++) {
+ if (!grid[y2]) {
+ grid[y2] = [];
+ }
+
+ for (x2 = x; x2 < x + colspan; x2++) {
+ grid[y2][x2] = {
+ part: part,
+ real: y2 == y && x2 == x,
+ elm: td,
+ rowspan: rowspan,
+ colspan: colspan
+ };
+ }
+ }
+
+ gridWidth = Math.max(gridWidth, x + 1);
+ }
+ );
+ }
+ );
+
+ startY += rows.length;
+ }
+ );
+ }
+
+ function cloneNode(node, children)
+ {
+ node = node.cloneNode(children);
+ node.removeAttribute('id');
+
+ return node;
+ }
+
+ function getCell(x, y)
+ {
+ var row;
+
+ row = grid[y];
+ if (row) {
+ return row[x];
+ }
+ }
+
+ function setSpanVal(td, name, val)
+ {
+ if (td) {
+ val = parseInt(val, 10);
+
+ if (val === 1) {
+ td.removeAttribute(name, 1);
+ } else {
+ td.setAttribute(name, val, 1);
+ }
+ }
+ }
+
+ function isCellSelected(cell)
+ {
+ return cell && (dom.hasClass(cell.elm, 'mce-item-selected') || cell == selectedCell);
+ }
+
+ function getSelectedRows()
+ {
+ var rows = [];
+
+ each(
+ table.rows, function (row) {
+ each(
+ row.cells, function (cell) {
+ if (dom.hasClass(cell, 'mce-item-selected') || (selectedCell && cell == selectedCell.elm)) {
+ rows.push(row);
+ return false;
+ }
+ }
+ );
+ }
+ );
+
+ return rows;
+ }
+
+ function deleteTable()
+ {
+ var rng = dom.createRng();
+
+ rng.setStartAfter(table);
+ rng.setEndAfter(table);
+
+ selection.setRng(rng);
+
+ dom.remove(table);
+ }
+
+ function cloneCell(cell)
+ {
+ var formatNode, cloneFormats = {};
+
+ if (editor.settings.table_clone_elements !== false) {
+ cloneFormats = Tools.makeMap(
+ (editor.settings.table_clone_elements || 'strong em b i span font h1 h2 h3 h4 h5 h6 p div').toUpperCase(),
+ /[ ,]/
+ );
+ }
+
+ // Clone formats
+ Tools.walk(
+ cell, function (node) {
+ var curNode;
+
+ if (node.nodeType == 3) {
+ each(
+ dom.getParents(node.parentNode, null, cell).reverse(), function (node) {
+ if (!cloneFormats[node.nodeName]) {
+ return;
+ }
+
+ node = cloneNode(node, false);
+
+ if (!formatNode) {
+ formatNode = curNode = node;
+ } else if (curNode) {
+ curNode.appendChild(node);
+ }
+
+ curNode = node;
+ }
+ );
+
+ // Add something to the inner node
+ if (curNode) {
+ curNode.innerHTML = Env.ie ? ' ' : ' ';
+ }
+
+ return false;
+ }
+ }, 'childNodes'
+ );
+
+ cell = cloneNode(cell, false);
+ setSpanVal(cell, 'rowSpan', 1);
+ setSpanVal(cell, 'colSpan', 1);
+
+ if (formatNode) {
+ cell.appendChild(formatNode);
+ } else {
+ if (!Env.ie || Env.ie > 10) {
+ cell.innerHTML = ' ';
+ }
+ }
+
+ return cell;
+ }
+
+ function cleanup()
+ {
+ var rng = dom.createRng(), row;
+
+ // Empty rows
+ each(
+ dom.select('tr', table), function (tr) {
+ if (tr.cells.length === 0) {
+ dom.remove(tr);
+ }
+ }
+ );
+
+ // Empty table
+ if (dom.select('tr', table).length === 0) {
+ rng.setStartBefore(table);
+ rng.setEndBefore(table);
+ selection.setRng(rng);
+ dom.remove(table);
+ return;
+ }
+
+ // Empty header/body/footer
+ each(
+ dom.select('thead,tbody,tfoot', table), function (part) {
+ if (part.rows.length === 0) {
+ dom.remove(part);
+ }
+ }
+ );
+
+ // Restore selection to start position if it still exists
+ buildGrid();
+
+ // If we have a valid startPos object
+ if (startPos) {
+ // Restore the selection to the closest table position
+ row = grid[Math.min(grid.length - 1, startPos.y)];
+ if (row) {
+ selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);
+ selection.collapse(true);
+ }
+ }
+ }
+
+ function fillLeftDown(x, y, rows, cols)
+ {
+ var tr, x2, r, c, cell;
+
+ tr = grid[y][x].elm.parentNode;
+ for (r = 1; r <= rows; r++) {
+ tr = dom.getNext(tr, 'tr');
+
+ if (tr) {
+ // Loop left to find real cell
+ for (x2 = x; x2 >= 0; x2--) {
+ cell = grid[y + r][x2].elm;
+
+ if (cell.parentNode == tr) {
+ // Append clones after
+ for (c = 1; c <= cols; c++) {
+ dom.insertAfter(cloneCell(cell), cell);
+ }
+
+ break;
+ }
+ }
+
+ if (x2 == -1) {
+ // Insert nodes before first cell
+ for (c = 1; c <= cols; c++) {
+ tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);
+ }
+ }
+ }
+ }
+ }
+
+ function split()
+ {
+ each(
+ grid, function (row, y) {
+ each(
+ row, function (cell, x) {
+ var colSpan, rowSpan, i;
+
+ if (isCellSelected(cell)) {
+ cell = cell.elm;
+ colSpan = getSpanVal(cell, 'colspan');
+ rowSpan = getSpanVal(cell, 'rowspan');
+
+ if (colSpan > 1 || rowSpan > 1) {
+ setSpanVal(cell, 'rowSpan', 1);
+ setSpanVal(cell, 'colSpan', 1);
+
+ // Insert cells right
+ for (i = 0; i < colSpan - 1; i++) {
+ dom.insertAfter(cloneCell(cell), cell);
+ }
+
+ fillLeftDown(x, y, rowSpan - 1, colSpan);
+ }
+ }
+ }
+ );
+ }
+ );
+ }
+
+ function merge(cell, cols, rows)
+ {
+ var pos, startX, startY, endX, endY, x, y, startCell, endCell, children, count;
+
+ // Use specified cell and cols/rows
+ if (cell) {
+ pos = getPos(cell);
+ startX = pos.x;
+ startY = pos.y;
+ endX = startX + (cols - 1);
+ endY = startY + (rows - 1);
+ } else {
+ startPos = endPos = null;
+
+ // Calculate start/end pos by checking for selected cells in grid works better with context menu
+ each(
+ grid, function (row, y) {
+ each(
+ row, function (cell, x) {
+ if (isCellSelected(cell)) {
+ if (!startPos) {
+ startPos = {x: x, y: y};
+ }
+
+ endPos = {x: x, y: y};
+ }
+ }
+ );
+ }
+ );
+
+ // Use selection, but make sure startPos is valid before accessing
+ if (startPos) {
+ startX = startPos.x;
+ startY = startPos.y;
+ endX = endPos.x;
+ endY = endPos.y;
+ }
+ }
+
+ // Find start/end cells
+ startCell = getCell(startX, startY);
+ endCell = getCell(endX, endY);
+
+ // Check if the cells exists and if they are of the same part for example tbody = tbody
+ if (startCell && endCell && startCell.part == endCell.part) {
+ // Split and rebuild grid
+ split();
+ buildGrid();
+
+ // Set row/col span to start cell
+ startCell = getCell(startX, startY).elm;
+ setSpanVal(startCell, 'colSpan', (endX - startX) + 1);
+ setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);
+
+ // Remove other cells and add it's contents to the start cell
+ for (y = startY; y <= endY; y++) {
+ for (x = startX; x <= endX; x++) {
+ if (!grid[y] || !grid[y][x]) {
+ continue;
+ }
+
+ cell = grid[y][x].elm;
+
+ /*jshint loopfunc:true */
+ /*eslint no-loop-func:0 */
+ if (cell != startCell) {
+ // Move children to startCell
+ children = Tools.grep(cell.childNodes);
+ each(
+ children, function (node) {
+ startCell.appendChild(node);
+ }
+ );
+
+ // Remove bogus nodes if there is children in the target cell
+ if (children.length) {
+ children = Tools.grep(startCell.childNodes);
+ count = 0;
+ each(
+ children, function (node) {
+ if (node.nodeName == 'BR' && dom.getAttrib(node, 'data-mce-bogus') && count++ < children.length - 1) {
+ startCell.removeChild(node);
+ }
+ }
+ );
+ }
+
+ dom.remove(cell);
+ }
+ }
+ }
+
+ // Remove empty rows etc and restore caret location
+ cleanup();
+ }
+ }
+
+ function insertRow(before)
+ {
+ var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;
+
+ // Find first/last row
+ each(
+ grid, function (row, y) {
+ each(
+ row, function (cell) {
+ if (isCellSelected(cell)) {
+ cell = cell.elm;
+ rowElm = cell.parentNode;
+ newRow = cloneNode(rowElm, false);
+ posY = y;
+
+ if (before) {
+ return false;
+ }
+ }
+ }
+ );
+
+ if (before) {
+ return !posY;
+ }
+ }
+ );
+
+ // If posY is undefined there is nothing for us to do here...just return to avoid crashing below
+ if (posY === undefined) {
+ return;
+ }
+
+ for (x = 0; x < grid[0].length; x++) {
+ // Cell not found could be because of an invalid table structure
+ if (!grid[posY][x]) {
+ continue;
+ }
+
+ cell = grid[posY][x].elm;
+
+ if (cell != lastCell) {
+ if (!before) {
+ rowSpan = getSpanVal(cell, 'rowspan');
+ if (rowSpan > 1) {
+ setSpanVal(cell, 'rowSpan', rowSpan + 1);
+ continue;
+ }
+ } else {
+ // Check if cell above can be expanded
+ if (posY > 0 && grid[posY - 1][x]) {
+ otherCell = grid[posY - 1][x].elm;
+ rowSpan = getSpanVal(otherCell, 'rowSpan');
+ if (rowSpan > 1) {
+ setSpanVal(otherCell, 'rowSpan', rowSpan + 1);
+ continue;
+ }
+ }
+ }
+
+ // Insert new cell into new row
+ newCell = cloneCell(cell);
+ setSpanVal(newCell, 'colSpan', cell.colSpan);
+
+ newRow.appendChild(newCell);
+
+ lastCell = cell;
+ }
+ }
+
+ if (newRow.hasChildNodes()) {
+ if (!before) {
+ dom.insertAfter(newRow, rowElm);
+ } else {
+ rowElm.parentNode.insertBefore(newRow, rowElm);
+ }
+ }
+ }
+
+ function insertCol(before)
+ {
+ var posX, lastCell;
+
+ // Find first/last column
+ each(
+ grid, function (row) {
+ each(
+ row, function (cell, x) {
+ if (isCellSelected(cell)) {
+ posX = x;
+
+ if (before) {
+ return false;
+ }
+ }
+ }
+ );
+
+ if (before) {
+ return !posX;
+ }
+ }
+ );
+
+ each(
+ grid, function (row, y) {
+ var cell, rowSpan, colSpan;
+
+ if (!row[posX]) {
+ return;
+ }
+
+ cell = row[posX].elm;
+ if (cell != lastCell) {
+ colSpan = getSpanVal(cell, 'colspan');
+ rowSpan = getSpanVal(cell, 'rowspan');
+
+ if (colSpan == 1) {
+ if (!before) {
+ dom.insertAfter(cloneCell(cell), cell);
+ fillLeftDown(posX, y, rowSpan - 1, colSpan);
+ } else {
+ cell.parentNode.insertBefore(cloneCell(cell), cell);
+ fillLeftDown(posX, y, rowSpan - 1, colSpan);
+ }
+ } else {
+ setSpanVal(cell, 'colSpan', cell.colSpan + 1);
+ }
+
+ lastCell = cell;
+ }
+ }
+ );
+ }
+
+ function deleteCols()
+ {
+ var cols = [];
+
+ // Get selected column indexes
+ each(
+ grid, function (row) {
+ each(
+ row, function (cell, x) {
+ if (isCellSelected(cell) && Tools.inArray(cols, x) === -1) {
+ each(
+ grid, function (row) {
+ var cell = row[x].elm, colSpan;
+
+ colSpan = getSpanVal(cell, 'colSpan');
+
+ if (colSpan > 1) {
+ setSpanVal(cell, 'colSpan', colSpan - 1);
+ } else {
+ dom.remove(cell);
+ }
+ }
+ );
+
+ cols.push(x);
+ }
+ }
+ );
+ }
+ );
+
+ cleanup();
+ }
+
+ function deleteRows()
+ {
+ var rows;
+
+ function deleteRow(tr)
+ {
+ var pos, lastCell;
+
+ // Move down row spanned cells
+ each(
+ tr.cells, function (cell) {
+ var rowSpan = getSpanVal(cell, 'rowSpan');
+
+ if (rowSpan > 1) {
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
+ pos = getPos(cell);
+ fillLeftDown(pos.x, pos.y, 1, 1);
+ }
+ }
+ );
+
+ // Delete cells
+ pos = getPos(tr.cells[0]);
+ each(
+ grid[pos.y], function (cell) {
+ var rowSpan;
+
+ cell = cell.elm;
+
+ if (cell != lastCell) {
+ rowSpan = getSpanVal(cell, 'rowSpan');
+
+ if (rowSpan <= 1) {
+ dom.remove(cell);
+ } else {
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
+ }
+
+ lastCell = cell;
+ }
+ }
+ );
+ }
+
+ // Get selected rows and move selection out of scope
+ rows = getSelectedRows();
+
+ // Delete all selected rows
+ each(
+ rows.reverse(), function (tr) {
+ deleteRow(tr);
+ }
+ );
+
+ cleanup();
+ }
+
+ function cutRows()
+ {
+ var rows = getSelectedRows();
+
+ dom.remove(rows);
+ cleanup();
+
+ return rows;
+ }
+
+ function copyRows()
+ {
+ var rows = getSelectedRows();
+
+ each(
+ rows, function (row, i) {
+ rows[i] = cloneNode(row, true);
+ }
+ );
+
+ return rows;
+ }
+
+ function pasteRows(rows, before)
+ {
+ var selectedRows = getSelectedRows(),
+ targetRow = selectedRows[before ? 0 : selectedRows.length - 1],
+ targetCellCount = targetRow.cells.length;
+
+ // Nothing to paste
+ if (!rows) {
+ return;
+ }
+
+ // Calc target cell count
+ each(
+ grid, function (row) {
+ var match;
+
+ targetCellCount = 0;
+ each(
+ row, function (cell) {
+ if (cell.real) {
+ targetCellCount += cell.colspan;
+ }
+
+ if (cell.elm.parentNode == targetRow) {
+ match = 1;
+ }
+ }
+ );
+
+ if (match) {
+ return false;
+ }
+ }
+ );
+
+ if (!before) {
+ rows.reverse();
+ }
+
+ each(
+ rows, function (row) {
+ var i, cellCount = row.cells.length, cell;
+
+ // Remove col/rowspans
+ for (i = 0; i < cellCount; i++) {
+ cell = row.cells[i];
+ setSpanVal(cell, 'colSpan', 1);
+ setSpanVal(cell, 'rowSpan', 1);
+ }
+
+ // Needs more cells
+ for (i = cellCount; i < targetCellCount; i++) {
+ row.appendChild(cloneCell(row.cells[cellCount - 1]));
+ }
+
+ // Needs less cells
+ for (i = targetCellCount; i < cellCount; i++) {
+ dom.remove(row.cells[i]);
+ }
+
+ // Add before/after
+ if (before) {
+ targetRow.parentNode.insertBefore(row, targetRow);
+ } else {
+ dom.insertAfter(row, targetRow);
+ }
+ }
+ );
+
+ // Remove current selection
+ dom.removeClass(dom.select('td.mce-item-selected,th.mce-item-selected'), 'mce-item-selected');
+ }
+
+ function getPos(target)
+ {
+ var pos;
+
+ each(
+ grid, function (row, y) {
+ each(
+ row, function (cell, x) {
+ if (cell.elm == target) {
+ pos = {x : x, y : y};
+ return false;
+ }
+ }
+ );
+
+ return !pos;
+ }
+ );
+
+ return pos;
+ }
+
+ function setStartCell(cell)
+ {
+ startPos = getPos(cell);
+ }
+
+ function findEndPos()
+ {
+ var maxX, maxY;
+
+ maxX = maxY = 0;
+
+ each(
+ grid, function (row, y) {
+ each(
+ row, function (cell, x) {
+ var colSpan, rowSpan;
+
+ if (isCellSelected(cell)) {
+ cell = grid[y][x];
+
+ if (x > maxX) {
+ maxX = x;
+ }
+
+ if (y > maxY) {
+ maxY = y;
+ }
+
+ if (cell.real) {
+ colSpan = cell.colspan - 1;
+ rowSpan = cell.rowspan - 1;
+
+ if (colSpan) {
+ if (x + colSpan > maxX) {
+ maxX = x + colSpan;
+ }
+ }
+
+ if (rowSpan) {
+ if (y + rowSpan > maxY) {
+ maxY = y + rowSpan;
+ }
+ }
+ }
+ }
+ }
+ );
+ }
+ );
+
+ return {x : maxX, y : maxY};
+ }
+
+ function setEndCell(cell)
+ {
+ var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan, x, y;
+
+ endPos = getPos(cell);
+
+ if (startPos && endPos) {
+ // Get start/end positions
+ startX = Math.min(startPos.x, endPos.x);
+ startY = Math.min(startPos.y, endPos.y);
+ endX = Math.max(startPos.x, endPos.x);
+ endY = Math.max(startPos.y, endPos.y);
+
+ // Expand end positon to include spans
+ maxX = endX;
+ maxY = endY;
+
+ // Expand startX
+ for (y = startY; y <= maxY; y++) {
+ cell = grid[y][startX];
+
+ if (!cell.real) {
+ if (startX - (cell.colspan - 1) < startX) {
+ startX -= cell.colspan - 1;
+ }
+ }
+ }
+
+ // Expand startY
+ for (x = startX; x <= maxX; x++) {
+ cell = grid[startY][x];
+
+ if (!cell.real) {
+ if (startY - (cell.rowspan - 1) < startY) {
+ startY -= cell.rowspan - 1;
+ }
+ }
+ }
+
+ // Find max X, Y
+ for (y = startY; y <= endY; y++) {
+ for (x = startX; x <= endX; x++) {
+ cell = grid[y][x];
+
+ if (cell.real) {
+ colSpan = cell.colspan - 1;
+ rowSpan = cell.rowspan - 1;
+
+ if (colSpan) {
+ if (x + colSpan > maxX) {
+ maxX = x + colSpan;
+ }
+ }
+
+ if (rowSpan) {
+ if (y + rowSpan > maxY) {
+ maxY = y + rowSpan;
+ }
+ }
+ }
+ }
+ }
+
+ // Remove current selection
+ dom.removeClass(dom.select('td.mce-item-selected,th.mce-item-selected'), 'mce-item-selected');
+
+ // Add new selection
+ for (y = startY; y <= maxY; y++) {
+ for (x = startX; x <= maxX; x++) {
+ if (grid[y][x]) {
+ dom.addClass(grid[y][x].elm, 'mce-item-selected');
+ }
+ }
+ }
+ }
+ }
+
+ function moveRelIdx(cellElm, delta)
+ {
+ var pos, index, cell;
+
+ pos = getPos(cellElm);
+ index = pos.y * gridWidth + pos.x;
+
+ do {
+ index += delta;
+ cell = getCell(index % gridWidth, Math.floor(index / gridWidth));
+
+ if (!cell) {
+ break;
+ }
+
+ if (cell.elm != cellElm) {
+ selection.select(cell.elm, true);
+
+ if (dom.isEmpty(cell.elm)) {
+ selection.collapse(true);
+ }
+
+ return true;
+ }
+ } while (cell.elm == cellElm);
+
+ return false;
+ }
+
+ table = table || dom.getParent(selection.getStart(), 'table');
+
+ buildGrid();
+
+ selectedCell = dom.getParent(selection.getStart(), 'th,td');
+ if (selectedCell) {
+ startPos = getPos(selectedCell);
+ endPos = findEndPos();
+ selectedCell = getCell(startPos.x, startPos.y);
+ }
+
+ Tools.extend(
+ this, {
+ deleteTable: deleteTable,
+ split: split,
+ merge: merge,
+ insertRow: insertRow,
+ insertCol: insertCol,
+ deleteCols: deleteCols,
+ deleteRows: deleteRows,
+ cutRows: cutRows,
+ copyRows: copyRows,
+ pasteRows: pasteRows,
+ getPos: getPos,
+ setStartCell: setStartCell,
+ setEndCell: setEndCell,
+ moveRelIdx: moveRelIdx,
+ refresh: buildGrid
+ }
+ );
+ };
+ }
+ );
+
+ // Included from: js/tinymce/plugins/table/classes/Quirks.js
+
+ /**
+ * Quirks.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+ /**
+ * This class includes fixes for various browser quirks.
+ *
+ * @class tinymce.tableplugin.Quirks
+ * @private
+ */
+ define(
+ "tinymce/tableplugin/Quirks", [
+ "tinymce/util/VK",
+ "tinymce/Env",
+ "tinymce/util/Tools"
+ ], function (VK, Env, Tools) {
+ var each = Tools.each;
+
+ function getSpanVal(td, name)
+ {
+ return parseInt(td.getAttribute(name) || 1, 10);
+ }
+
+ return function (editor) {
+ /**
+ * Fixed caret movement around tables on WebKit.
+ */
+ function moveWebKitSelection()
+ {
+ function eventHandler(e)
+ {
+ var key = e.keyCode;
+
+ function handle(upBool, sourceNode)
+ {
+ var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
+ var currentRow = editor.dom.getParent(sourceNode, 'tr');
+ var siblingRow = currentRow[siblingDirection];
+
+ if (siblingRow) {
+ moveCursorToRow(editor, sourceNode, siblingRow, upBool);
+ e.preventDefault();
+ return true;
+ } else {
+ var tableNode = editor.dom.getParent(currentRow, 'table');
+ var middleNode = currentRow.parentNode;
+ var parentNodeName = middleNode.nodeName.toLowerCase();
+ if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) {
+ var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody');
+ if (targetParent !== null) {
+ return moveToRowInTarget(upBool, targetParent, sourceNode);
+ }
+ }
+ return escapeTable(upBool, currentRow, siblingDirection, tableNode);
+ }
+ }
+
+ function getTargetParent(upBool, topNode, secondNode, nodeName)
+ {
+ var tbodies = editor.dom.select('>' + nodeName, topNode);
+ var position = tbodies.indexOf(secondNode);
+ if (upBool && position === 0 || !upBool && position === tbodies.length - 1) {
+ return getFirstHeadOrFoot(upBool, topNode);
+ } else if (position === -1) {
+ var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1;
+ return tbodies[topOrBottom];
+ } else {
+ return tbodies[position + (upBool ? -1 : 1)];
+ }
+ }
+
+ function getFirstHeadOrFoot(upBool, parent)
+ {
+ var tagName = upBool ? 'thead' : 'tfoot';
+ var headOrFoot = editor.dom.select('>' + tagName, parent);
+ return headOrFoot.length !== 0 ? headOrFoot[0] : null;
+ }
+
+ function moveToRowInTarget(upBool, targetParent, sourceNode)
+ {
+ var targetRow = getChildForDirection(targetParent, upBool);
+
+ if (targetRow) {
+ moveCursorToRow(editor, sourceNode, targetRow, upBool);
+ }
+
+ e.preventDefault();
+ return true;
+ }
+
+ function escapeTable(upBool, currentRow, siblingDirection, table)
+ {
+ var tableSibling = table[siblingDirection];
+
+ if (tableSibling) {
+ moveCursorToStartOfElement(tableSibling);
+ return true;
+ } else {
+ var parentCell = editor.dom.getParent(table, 'td,th');
+ if (parentCell) {
+ return handle(upBool, parentCell, e);
+ } else {
+ var backUpSibling = getChildForDirection(currentRow, !upBool);
+ moveCursorToStartOfElement(backUpSibling);
+ e.preventDefault();
+ return false;
+ }
+ }
+ }
+
+ function getChildForDirection(parent, up)
+ {
+ var child = parent && parent[up ? 'lastChild' : 'firstChild'];
+ // BR is not a valid table child to return in this case we return the table cell
+ return child && child.nodeName === 'BR' ? editor.dom.getParent(child, 'td,th') : child;
+ }
+
+ function moveCursorToStartOfElement(n)
+ {
+ editor.selection.setCursorLocation(n, 0);
+ }
+
+ function isVerticalMovement()
+ {
+ return key == VK.UP || key == VK.DOWN;
+ }
+
+ function isInTable(editor)
+ {
+ var node = editor.selection.getNode();
+ var currentRow = editor.dom.getParent(node, 'tr');
+ return currentRow !== null;
+ }
+
+ function columnIndex(column)
+ {
+ var colIndex = 0;
+ var c = column;
+ while (c.previousSibling) {
+ c = c.previousSibling;
+ colIndex = colIndex + getSpanVal(c, "colspan");
+ }
+ return colIndex;
+ }
+
+ function findColumn(rowElement, columnIndex)
+ {
+ var c = 0, r = 0;
+
+ each(
+ rowElement.children, function (cell, i) {
+ c = c + getSpanVal(cell, "colspan");
+ r = i;
+ if (c > columnIndex) {
+ return false;
+ }
+ }
+ );
+ return r;
+ }
+
+ function moveCursorToRow(ed, node, row, upBool)
+ {
+ var srcColumnIndex = columnIndex(editor.dom.getParent(node, 'td,th'));
+ var tgtColumnIndex = findColumn(row, srcColumnIndex);
+ var tgtNode = row.childNodes[tgtColumnIndex];
+ var rowCellTarget = getChildForDirection(tgtNode, upBool);
+ moveCursorToStartOfElement(rowCellTarget || tgtNode);
+ }
+
+ function shouldFixCaret(preBrowserNode)
+ {
+ var newNode = editor.selection.getNode();
+ var newParent = editor.dom.getParent(newNode, 'td,th');
+ var oldParent = editor.dom.getParent(preBrowserNode, 'td,th');
+
+ return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent);
+ }
+
+ function checkSameParentTable(nodeOne, NodeTwo)
+ {
+ return editor.dom.getParent(nodeOne, 'TABLE') === editor.dom.getParent(NodeTwo, 'TABLE');
+ }
+
+ if (isVerticalMovement() && isInTable(editor)) {
+ var preBrowserNode = editor.selection.getNode();
+ setTimeout(
+ function () {
+ if (shouldFixCaret(preBrowserNode)) {
+ handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
+ }
+ }, 0
+ );
+ }
+ }
+
+ editor.on(
+ 'KeyDown', function (e) {
+ eventHandler(e);
+ }
+ );
+ }
+
+ function fixBeforeTableCaretBug()
+ {
+ // Checks if the selection/caret is at the start of the specified block element
+ function isAtStart(rng, par)
+ {
+ var doc = par.ownerDocument, rng2 = doc.createRange(), elm;
+
+ rng2.setStartBefore(par);
+ rng2.setEnd(rng.endContainer, rng.endOffset);
+
+ elm = doc.createElement('body');
+ elm.appendChild(rng2.cloneContents());
+
+ // Check for text characters of other elements that should be treated as content
+ return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length === 0;
+ }
+
+ // Fixes an bug where it's impossible to place the caret before a table in Gecko
+ // this fix solves it by detecting when the caret is at the beginning of such a table
+ // and then manually moves the caret infront of the table
+ editor.on(
+ 'KeyDown', function (e) {
+ var rng, table, dom = editor.dom;
+
+ // On gecko it's not possible to place the caret before a table
+ if (e.keyCode == 37 || e.keyCode == 38) {
+ rng = editor.selection.getRng();
+ table = dom.getParent(rng.startContainer, 'table');
+
+ if (table && editor.getBody().firstChild == table) {
+ if (isAtStart(rng, table)) {
+ rng = dom.createRng();
+
+ rng.setStartBefore(table);
+ rng.setEndBefore(table);
+
+ editor.selection.setRng(rng);
+
+ e.preventDefault();
+ }
+ }
+ }
+ }
+ );
+ }
+
+ // Fixes an issue on Gecko where it's impossible to place the caret behind a table
+ // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
+ function fixTableCaretPos()
+ {
+ editor.on(
+ 'KeyDown SetContent VisualAid', function () {
+ var last;
+
+ // Skip empty text nodes from the end
+ for (last = editor.getBody().lastChild; last; last = last.previousSibling) {
+ if (last.nodeType == 3) {
+ if (last.nodeValue.length > 0) {
+ break;
+ }
+ } else if (last.nodeType == 1 && (last.tagName == 'BR' || !last.getAttribute('data-mce-bogus'))) {
+ break;
+ }
+ }
+
+ if (last && last.nodeName == 'TABLE') {
+ if (editor.settings.forced_root_block) {
+ editor.dom.add(
+ editor.getBody(),
+ editor.settings.forced_root_block,
+ editor.settings.forced_root_block_attrs,
+ Env.ie && Env.ie < 11 ? ' ' : ' '
+ );
+ } else {
+ editor.dom.add(editor.getBody(), 'br', {'data-mce-bogus': '1'});
+ }
+ }
+ }
+ );
+
+ editor.on(
+ 'PreProcess', function (o) {
+ var last = o.node.lastChild;
+
+ if (last && (last.nodeName == "BR" || (last.childNodes.length == 1
+ && (last.firstChild.nodeName == 'BR' || last.firstChild.nodeValue == '\u00a0')))
+ && last.previousSibling && last.previousSibling.nodeName == "TABLE"
+ ) {
+ editor.dom.remove(last);
+ }
+ }
+ );
+ }
+
+ // this nasty hack is here to work around some WebKit selection bugs.
+ function fixTableCellSelection()
+ {
+ function tableCellSelected(ed, rng, n, currentCell)
+ {
+ // The decision of when a table cell is selected is somewhat involved. The fact that this code is
+ // required is actually a pointer to the root cause of this bug. A cell is selected when the start
+ // and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases)
+ // or the parent of the table (in the case of the selection containing the last cell of a table).
+ var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE');
+ var tableParent, allOfCellSelected, tableCellSelection;
+
+ if (table) {
+ tableParent = table.parentNode;
+ }
+
+ allOfCellSelected = rng.startContainer.nodeType == TEXT_NODE &&
+ rng.startOffset === 0 &&
+ rng.endOffset === 0 &&
+ currentCell &&
+ (n.nodeName == "TR" || n == tableParent);
+
+ tableCellSelection = (n.nodeName == "TD" || n.nodeName == "TH") && !currentCell;
+
+ return allOfCellSelected || tableCellSelection;
+ }
+
+ function fixSelection()
+ {
+ var rng = editor.selection.getRng();
+ var n = editor.selection.getNode();
+ var currentCell = editor.dom.getParent(rng.startContainer, 'TD,TH');
+
+ if (!tableCellSelected(editor, rng, n, currentCell)) {
+ return;
+ }
+
+ if (!currentCell) {
+ currentCell = n;
+ }
+
+ // Get the very last node inside the table cell
+ var end = currentCell.lastChild;
+ while (end.lastChild) {
+ end = end.lastChild;
+ }
+
+ // Select the entire table cell. Nothing outside of the table cell should be selected.
+ if (end.nodeType == 3) {
+ rng.setEnd(end, end.data.length);
+ editor.selection.setRng(rng);
+ }
+ }
+
+ editor.on(
+ 'KeyDown', function () {
+ fixSelection();
+ }
+ );
+
+ editor.on(
+ 'MouseDown', function (e) {
+ if (e.button != 2) {
+ fixSelection();
+ }
+ }
+ );
+ }
+
+ /**
+ * Delete table if all cells are selected.
+ */
+ function deleteTable()
+ {
+ editor.on(
+ 'keydown', function (e) {
+ if ((e.keyCode == VK.DELETE || e.keyCode == VK.BACKSPACE) && !e.isDefaultPrevented()) {
+ var table = editor.dom.getParent(editor.selection.getStart(), 'table');
+
+ if (table) {
+ var cells = editor.dom.select('td,th', table), i = cells.length;
+ while (i--) {
+ if (!editor.dom.hasClass(cells[i], 'mce-item-selected')) {
+ return;
+ }
+ }
+
+ e.preventDefault();
+ editor.execCommand('mceTableDelete');
+ }
+ }
+ }
+ );
+ }
+
+ deleteTable();
+
+ if (Env.webkit) {
+ moveWebKitSelection();
+ fixTableCellSelection();
+ }
+
+ if (Env.gecko) {
+ fixBeforeTableCaretBug();
+ fixTableCaretPos();
+ }
+
+ if (Env.ie > 10) {
+ fixBeforeTableCaretBug();
+ fixTableCaretPos();
+ }
+ };
+ }
+ );
+
+ // Included from: js/tinymce/plugins/table/classes/CellSelection.js
+
+ /**
+ * CellSelection.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+ /**
+ * This class handles table cell selection by faking it using a css class that gets applied
+ * to cells when dragging the mouse from one cell to another.
+ *
+ * @class tinymce.tableplugin.CellSelection
+ * @private
+ */
+ define(
+ "tinymce/tableplugin/CellSelection", [
+ "tinymce/tableplugin/TableGrid",
+ "tinymce/dom/TreeWalker",
+ "tinymce/util/Tools"
+ ], function (TableGrid, TreeWalker, Tools) {
+ return function (editor) {
+ var dom = editor.dom, tableGrid, startCell, startTable, hasCellSelection = true, resizing;
+
+ function clear(force)
+ {
+ // Restore selection possibilities
+ editor.getBody().style.webkitUserSelect = '';
+
+ if (force || hasCellSelection) {
+ editor.dom.removeClass(
+ editor.dom.select('td.mce-item-selected,th.mce-item-selected'),
+ 'mce-item-selected'
+ );
+
+ hasCellSelection = false;
+ }
+ }
+
+ function cellSelectionHandler(e)
+ {
+ var sel, table, target = e.target;
+
+ if (resizing) {
+ return;
+ }
+
+ if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {
+ table = dom.getParent(target, 'table');
+ if (table == startTable) {
+ if (!tableGrid) {
+ tableGrid = new TableGrid(editor, table);
+ tableGrid.setStartCell(startCell);
+
+ editor.getBody().style.webkitUserSelect = 'none';
+ }
+
+ tableGrid.setEndCell(target);
+ hasCellSelection = true;
+ }
+
+ // Remove current selection
+ sel = editor.selection.getSel();
+
+ try {
+ if (sel.removeAllRanges) {
+ sel.removeAllRanges();
+ } else {
+ sel.empty();
+ }
+ } catch (ex) {
+ // IE9 might throw errors here
+ }
+
+ e.preventDefault();
+ }
+ }
+
+ // Add cell selection logic
+ editor.on(
+ 'MouseDown', function (e) {
+ if (e.button != 2 && !resizing) {
+ clear();
+
+ startCell = dom.getParent(e.target, 'td,th');
+ startTable = dom.getParent(startCell, 'table');
+ }
+ }
+ );
+
+ editor.on('mouseover', cellSelectionHandler);
+
+ editor.on(
+ 'remove', function () {
+ dom.unbind(editor.getDoc(), 'mouseover', cellSelectionHandler);
+ }
+ );
+
+ editor.on(
+ 'MouseUp', function () {
+ var rng, sel = editor.selection, selectedCells, walker, node, lastNode;
+
+ function setPoint(node, start)
+ {
+ var walker = new TreeWalker(node, node);
+
+ do {
+ // Text node
+ if (node.nodeType == 3 && Tools.trim(node.nodeValue).length !== 0) {
+ if (start) {
+ rng.setStart(node, 0);
+ } else {
+ rng.setEnd(node, node.nodeValue.length);
+ }
+
+ return;
+ }
+
+ // BR element
+ if (node.nodeName == 'BR') {
+ if (start) {
+ rng.setStartBefore(node);
+ } else {
+ rng.setEndBefore(node);
+ }
+
+ return;
+ }
+ } while ((node = (start ? walker.next() : walker.prev())));
+ }
+
+ // Move selection to startCell
+ if (startCell) {
+ if (tableGrid) {
+ editor.getBody().style.webkitUserSelect = '';
+ }
+
+ // Try to expand text selection as much as we can only Gecko supports cell selection
+ selectedCells = dom.select('td.mce-item-selected,th.mce-item-selected');
+ if (selectedCells.length > 0) {
+ rng = dom.createRng();
+ node = selectedCells[0];
+ rng.setStartBefore(node);
+ rng.setEndAfter(node);
+
+ setPoint(node, 1);
+ walker = new TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
+
+ do {
+ if (node.nodeName == 'TD' || node.nodeName == 'TH') {
+ if (!dom.hasClass(node, 'mce-item-selected')) {
+ break;
+ }
+
+ lastNode = node;
+ }
+ } while ((node = walker.next()));
+
+ setPoint(lastNode);
+
+ sel.setRng(rng);
+ }
+
+ editor.nodeChanged();
+ startCell = tableGrid = startTable = null;
+ }
+ }
+ );
+
+ editor.on(
+ 'KeyUp Drop SetContent', function (e) {
+ clear(e.type == 'setcontent');
+ startCell = tableGrid = startTable = null;
+ resizing = false;
+ }
+ );
+
+ editor.on(
+ 'ObjectResizeStart ObjectResized', function (e) {
+ resizing = e.type != 'objectresized';
+ }
+ );
+
+ return {
+ clear: clear
+ };
+ };
+ }
+ );
+
+ // Included from: js/tinymce/plugins/table/classes/Dialogs.js
+
+ /**
+ * Dialogs.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+ /**
+ * ...
+ *
+ * @class tinymce.tableplugin.Dialogs
+ * @private
+ */
+ define(
+ "tinymce/tableplugin/Dialogs", [
+ "tinymce/util/Tools",
+ "tinymce/Env"
+ ], function (Tools, Env) {
+ var each = Tools.each;
+
+ return function (editor) {
+ var self = this;
+
+ function createColorPickAction()
+ {
+ var colorPickerCallback = editor.settings.color_picker_callback;
+
+ if (colorPickerCallback) {
+ return function () {
+ var self = this;
+
+ colorPickerCallback.call(
+ editor,
+ function (value) {
+ self.value(value).fire('change');
+ },
+ self.value()
+ );
+ };
+ }
+ }
+
+ function createStyleForm(dom)
+ {
+ return {
+ title: 'Advanced',
+ type: 'form',
+ defaults: {
+ onchange: function () {
+ updateStyle(dom, this.parents().reverse()[0], this.name() == "style");
+ }
+ },
+ items: [
+ {
+ label: 'Style',
+ name: 'style',
+ type: 'textbox'
+ },
+
+ {
+ type: 'form',
+ padding: 0,
+ formItemDefaults: {
+ layout: 'grid',
+ alignH: ['start', 'right']
+ },
+ defaults: {
+ size: 7
+ },
+ items: [
+ {
+ label: 'Border color',
+ type: 'colorbox',
+ name: 'borderColor',
+ onaction: createColorPickAction()
+ },
+
+ {
+ label: 'Background color',
+ type: 'colorbox',
+ name: 'backgroundColor',
+ onaction: createColorPickAction()
+ }
+ ]
+ }
+ ]
+ };
+ }
+
+ function removePxSuffix(size)
+ {
+ return size ? size.replace(/px$/, '') : "";
+ }
+
+ function addSizeSuffix(size)
+ {
+ if (/^[0-9]+$/.test(size)) {
+ size += "px";
+ }
+
+ return size;
+ }
+
+ function unApplyAlign(elm)
+ {
+ each(
+ 'left center right'.split(' '), function (name) {
+ editor.formatter.remove('align' + name, {}, elm);
+ }
+ );
+ }
+
+ function unApplyVAlign(elm)
+ {
+ each(
+ 'top middle bottom'.split(' '), function (name) {
+ editor.formatter.remove('valign' + name, {}, elm);
+ }
+ );
+ }
+
+ function buildListItems(inputList, itemCallback, startItems)
+ {
+ function appendItems(values, output)
+ {
+ output = output || [];
+
+ Tools.each(
+ values, function (item) {
+ var menuItem = {text: item.text || item.title};
+
+ if (item.menu) {
+ menuItem.menu = appendItems(item.menu);
+ } else {
+ menuItem.value = item.value;
+
+ if (itemCallback) {
+ itemCallback(menuItem);
+ }
+ }
+
+ output.push(menuItem);
+ }
+ );
+
+ return output;
+ }
+
+ return appendItems(inputList, startItems || []);
+ }
+
+ function updateStyle(dom, win, isStyleCtrl)
+ {
+ var data = win.toJSON();
+ var css = dom.parseStyle(data.style);
+
+ if (isStyleCtrl) {
+ win.find('#borderColor').value(css["border-color"] || '')[0].fire('change');
+ win.find('#backgroundColor').value(css["background-color"] || '')[0].fire('change');
+ } else {
+ css["border-color"] = data.borderColor;
+ css["background-color"] = data.backgroundColor;
+ }
+
+ win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
+ }
+
+ function appendStylesToData(dom, data, elm)
+ {
+ var css = dom.parseStyle(dom.getAttrib(elm, 'style'));
+
+ if (css["border-color"]) {
+ data.borderColor = css["border-color"];
+ }
+
+ if (css["background-color"]) {
+ data.backgroundColor = css["background-color"];
+ }
+
+ data.style = dom.serializeStyle(css);
+ }
+
+ self.tableProps = function () {
+ self.table(true);
+ };
+
+ self.table = function (isProps) {
+ var dom = editor.dom, tableElm, colsCtrl, rowsCtrl, classListCtrl, data = {}, generalTableForm;
+
+ function onSubmitTableForm()
+ {
+ var captionElm;
+
+ updateStyle(dom, this);
+ data = Tools.extend(data, this.toJSON());
+
+ Tools.each(
+ 'backgroundColor borderColor'.split(' '), function (name) {
+ delete data[name];
+ }
+ );
+
+ if (data["class"] === false) {
+ delete data["class"];
+ }
+
+ editor.undoManager.transact(
+ function () {
+ if (!tableElm) {
+ tableElm = editor.plugins.table.insertTable(data.cols || 1, data.rows || 1);
+ }
+
+ editor.dom.setAttribs(
+ tableElm, {
+ cellspacing: data.cellspacing,
+ cellpadding: data.cellpadding,
+ border: data.border,
+ style: data.style,
+ 'class': data['class']
+ }
+ );
+
+ if (dom.getAttrib(tableElm, 'width')) {
+ dom.setAttrib(tableElm, 'width', removePxSuffix(data.width));
+ } else {
+ dom.setStyle(tableElm, 'width', addSizeSuffix(data.width));
+ }
+
+ dom.setStyle(tableElm, 'height', addSizeSuffix(data.height));
+
+ // Toggle caption on/off
+ captionElm = dom.select('caption', tableElm)[0];
+
+ if (captionElm && !data.caption) {
+ dom.remove(captionElm);
+ }
+
+ if (!captionElm && data.caption) {
+ captionElm = dom.create('caption');
+ captionElm.innerHTML = !Env.ie ? ' ' : '\u00a0';
+ tableElm.insertBefore(captionElm, tableElm.firstChild);
+ }
+
+ unApplyAlign(tableElm);
+ if (data.align) {
+ editor.formatter.apply('align' + data.align, {}, tableElm);
+ }
+
+ editor.focus();
+ editor.addVisual();
+ }
+ );
+ }
+
+ if (isProps === true) {
+ tableElm = dom.getParent(editor.selection.getStart(), 'table');
+
+ if (tableElm) {
+ data = {
+ width: removePxSuffix(dom.getStyle(tableElm, 'width') || dom.getAttrib(tableElm, 'width')),
+ height: removePxSuffix(dom.getStyle(tableElm, 'height') || dom.getAttrib(tableElm, 'height')),
+ cellspacing: tableElm ? dom.getAttrib(tableElm, 'cellspacing') : '',
+ cellpadding: tableElm ? dom.getAttrib(tableElm, 'cellpadding') : '',
+ border: tableElm ? dom.getAttrib(tableElm, 'border') : '',
+ caption: !!dom.select('caption', tableElm)[0],
+ 'class': dom.getAttrib(tableElm, 'class')
+ };
+
+ each(
+ 'left center right'.split(' '), function (name) {
+ if (editor.formatter.matchNode(tableElm, 'align' + name)) {
+ data.align = name;
+ }
+ }
+ );
+ }
+ } else {
+ colsCtrl = {label: 'Cols', name: 'cols'};
+ rowsCtrl = {label: 'Rows', name: 'rows'};
+ }
+
+ if (editor.settings.table_class_list) {
+ if (data["class"]) {
+ data["class"] = data["class"].replace(/\s*mce\-item\-table\s*/g, '');
+ }
+
+ classListCtrl = {
+ name: 'class',
+ type: 'listbox',
+ label: 'Class',
+ values: buildListItems(
+ editor.settings.table_class_list,
+ function (item) {
+ if (item.value) {
+ item.textStyle = function () {
+ return editor.formatter.getCssText({block: 'table', classes: [item.value]});
+ };
+ }
+ }
+ )
+ };
+ }
+
+ generalTableForm = {
+ type: 'form',
+ layout: 'flex',
+ direction: 'column',
+ labelGapCalc: 'children',
+ padding: 0,
+ items: [
+ {
+ type: 'form',
+ labelGapCalc: false,
+ padding: 0,
+ layout: 'grid',
+ columns: 2,
+ defaults: {
+ type: 'textbox',
+ maxWidth: 50
+ },
+ items: [
+ colsCtrl,
+ rowsCtrl,
+ {label: 'Width', name: 'width'},
+ {label: 'Height', name: 'height'},
+ {label: 'Cell spacing', name: 'cellspacing'},
+ {label: 'Cell padding', name: 'cellpadding'},
+ {label: 'Border', name: 'border'},
+ {label: 'Caption', name: 'caption', type: 'checkbox'}
+ ]
+ },
+
+ {
+ label: 'Alignment',
+ name: 'align',
+ type: 'listbox',
+ text: 'None',
+ values: [
+ {text: 'None', value: ''},
+ {text: 'Left', value: 'left'},
+ {text: 'Center', value: 'center'},
+ {text: 'Right', value: 'right'}
+ ]
+ },
+
+ classListCtrl
+ ]
+ };
+
+ if (editor.settings.table_advtab !== false) {
+ appendStylesToData(dom, data, tableElm);
+
+ editor.windowManager.open(
+ {
+ title: "Table properties",
+ data: data,
+ bodyType: 'tabpanel',
+ body: [
+ {
+ title: 'General',
+ type: 'form',
+ items: generalTableForm
+ },
+ createStyleForm(dom)
+ ],
+
+ onsubmit: onSubmitTableForm
+ }
+ );
+ } else {
+ editor.windowManager.open(
+ {
+ title: "Table properties",
+ data: data,
+ body: generalTableForm,
+ onsubmit: onSubmitTableForm
+ }
+ );
+ }
+ };
+
+ self.merge = function (grid, cell) {
+ editor.windowManager.open(
+ {
+ title: "Merge cells",
+ body: [
+ {label: 'Cols', name: 'cols', type: 'textbox', value: '1', size: 10},
+ {label: 'Rows', name: 'rows', type: 'textbox', value: '1', size: 10}
+ ],
+ onsubmit: function () {
+ var data = this.toJSON();
+
+ editor.undoManager.transact(
+ function () {
+ grid.merge(cell, data.cols, data.rows);
+ }
+ );
+ }
+ }
+ );
+ };
+
+ self.cell = function () {
+ var dom = editor.dom, cellElm, data, classListCtrl, cells = [];
+
+ function onSubmitCellForm()
+ {
+ updateStyle(dom, this);
+ data = Tools.extend(data, this.toJSON());
+
+ editor.undoManager.transact(
+ function () {
+ each(
+ cells, function (cellElm) {
+ editor.dom.setAttribs(
+ cellElm, {
+ scope: data.scope,
+ style: data.style,
+ 'class': data['class']
+ }
+ );
+
+ editor.dom.setStyles(
+ cellElm, {
+ width: addSizeSuffix(data.width),
+ height: addSizeSuffix(data.height)
+ }
+ );
+
+ // Switch cell type
+ if (data.type && cellElm.nodeName.toLowerCase() != data.type) {
+ cellElm = dom.rename(cellElm, data.type);
+ }
+
+ // Apply/remove alignment
+ unApplyAlign(cellElm);
+ if (data.align) {
+ editor.formatter.apply('align' + data.align, {}, cellElm);
+ }
+
+ // Apply/remove vertical alignment
+ unApplyVAlign(cellElm);
+ if (data.valign) {
+ editor.formatter.apply('valign' + data.valign, {}, cellElm);
+ }
+ }
+ );
+
+ editor.focus();
+ }
+ );
+ }
+
+ // Get selected cells or the current cell
+ cells = editor.dom.select('td.mce-item-selected,th.mce-item-selected');
+ cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
+ if (!cells.length && cellElm) {
+ cells.push(cellElm);
+ }
+
+ cellElm = cellElm || cells[0];
+
+ if (!cellElm) {
+ // If this element is null, return now to avoid crashing.
+ return;
+ }
+
+ data = {
+ width: removePxSuffix(dom.getStyle(cellElm, 'width') || dom.getAttrib(cellElm, 'width')),
+ height: removePxSuffix(dom.getStyle(cellElm, 'height') || dom.getAttrib(cellElm, 'height')),
+ scope: dom.getAttrib(cellElm, 'scope'),
+ 'class': dom.getAttrib(cellElm, 'class')
+ };
+
+ data.type = cellElm.nodeName.toLowerCase();
+
+ each(
+ 'left center right'.split(' '), function (name) {
+ if (editor.formatter.matchNode(cellElm, 'align' + name)) {
+ data.align = name;
+ }
+ }
+ );
+
+ each(
+ 'top middle bottom'.split(' '), function (name) {
+ if (editor.formatter.matchNode(cellElm, 'valign' + name)) {
+ data.valign = name;
+ }
+ }
+ );
+
+ if (editor.settings.table_cell_class_list) {
+ classListCtrl = {
+ name: 'class',
+ type: 'listbox',
+ label: 'Class',
+ values: buildListItems(
+ editor.settings.table_cell_class_list,
+ function (item) {
+ if (item.value) {
+ item.textStyle = function () {
+ return editor.formatter.getCssText({block: 'td', classes: [item.value]});
+ };
+ }
+ }
+ )
+ };
+ }
+
+ var generalCellForm = {
+ type: 'form',
+ layout: 'flex',
+ direction: 'column',
+ labelGapCalc: 'children',
+ padding: 0,
+ items: [
+ {
+ type: 'form',
+ layout: 'grid',
+ columns: 2,
+ labelGapCalc: false,
+ padding: 0,
+ defaults: {
+ type: 'textbox',
+ maxWidth: 50
+ },
+ items: [
+ {label: 'Width', name: 'width'},
+ {label: 'Height', name: 'height'},
+ {
+ label: 'Cell type',
+ name: 'type',
+ type: 'listbox',
+ text: 'None',
+ minWidth: 90,
+ maxWidth: null,
+ values: [
+ {text: 'Cell', value: 'td'},
+ {text: 'Header cell', value: 'th'}
+ ]
+ },
+ {
+ label: 'Scope',
+ name: 'scope',
+ type: 'listbox',
+ text: 'None',
+ minWidth: 90,
+ maxWidth: null,
+ values: [
+ {text: 'None', value: ''},
+ {text: 'Row', value: 'row'},
+ {text: 'Column', value: 'col'},
+ {text: 'Row group', value: 'rowgroup'},
+ {text: 'Column group', value: 'colgroup'}
+ ]
+ },
+ {
+ label: 'H Align',
+ name: 'align',
+ type: 'listbox',
+ text: 'None',
+ minWidth: 90,
+ maxWidth: null,
+ values: [
+ {text: 'None', value: ''},
+ {text: 'Left', value: 'left'},
+ {text: 'Center', value: 'center'},
+ {text: 'Right', value: 'right'}
+ ]
+ },
+ {
+ label: 'V Align',
+ name: 'valign',
+ type: 'listbox',
+ text: 'None',
+ minWidth: 90,
+ maxWidth: null,
+ values: [
+ {text: 'None', value: ''},
+ {text: 'Top', value: 'top'},
+ {text: 'Middle', value: 'middle'},
+ {text: 'Bottom', value: 'bottom'}
+ ]
+ }
+ ]
+ },
+
+ classListCtrl
+ ]
+ };
+
+ if (editor.settings.table_cell_advtab !== false) {
+ appendStylesToData(dom, data, cellElm);
+
+ editor.windowManager.open(
+ {
+ title: "Cell properties",
+ bodyType: 'tabpanel',
+ data: data,
+ body: [
+ {
+ title: 'General',
+ type: 'form',
+ items: generalCellForm
+ },
+
+ createStyleForm(dom)
+ ],
+
+ onsubmit: onSubmitCellForm
+ }
+ );
+ } else {
+ editor.windowManager.open(
+ {
+ title: "Cell properties",
+ data: data,
+ body: generalCellForm,
+ onsubmit: onSubmitCellForm
+ }
+ );
+ }
+ };
+
+ self.row = function () {
+ var dom = editor.dom, tableElm, cellElm, rowElm, classListCtrl, data, rows = [], generalRowForm;
+
+ function onSubmitRowForm()
+ {
+ var tableElm, oldParentElm, parentElm;
+
+ updateStyle(dom, this);
+ data = Tools.extend(data, this.toJSON());
+
+ editor.undoManager.transact(
+ function () {
+ var toType = data.type;
+
+ each(
+ rows, function (rowElm) {
+ editor.dom.setAttribs(
+ rowElm, {
+ scope: data.scope,
+ style: data.style,
+ 'class': data['class']
+ }
+ );
+
+ editor.dom.setStyles(
+ rowElm, {
+ height: addSizeSuffix(data.height)
+ }
+ );
+
+ if (toType != rowElm.parentNode.nodeName.toLowerCase()) {
+ tableElm = dom.getParent(rowElm, 'table');
+
+ oldParentElm = rowElm.parentNode;
+ parentElm = dom.select(toType, tableElm)[0];
+ if (!parentElm) {
+ parentElm = dom.create(toType);
+ if (tableElm.firstChild) {
+ tableElm.insertBefore(parentElm, tableElm.firstChild);
+ } else {
+ tableElm.appendChild(parentElm);
+ }
+ }
+
+ parentElm.appendChild(rowElm);
+
+ if (!oldParentElm.hasChildNodes()) {
+ dom.remove(oldParentElm);
+ }
+ }
+
+ // Apply/remove alignment
+ unApplyAlign(rowElm);
+ if (data.align) {
+ editor.formatter.apply('align' + data.align, {}, rowElm);
+ }
+ }
+ );
+
+ editor.focus();
+ }
+ );
+ }
+
+ tableElm = editor.dom.getParent(editor.selection.getStart(), 'table');
+ cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
+
+ each(
+ tableElm.rows, function (row) {
+ each(
+ row.cells, function (cell) {
+ if (dom.hasClass(cell, 'mce-item-selected') || cell == cellElm) {
+ rows.push(row);
+ return false;
+ }
+ }
+ );
+ }
+ );
+
+ rowElm = rows[0];
+ if (!rowElm) {
+ // If this element is null, return now to avoid crashing.
+ return;
+ }
+
+ data = {
+ height: removePxSuffix(dom.getStyle(rowElm, 'height') || dom.getAttrib(rowElm, 'height')),
+ scope: dom.getAttrib(rowElm, 'scope'),
+ 'class': dom.getAttrib(rowElm, 'class')
+ };
+
+ data.type = rowElm.parentNode.nodeName.toLowerCase();
+
+ each(
+ 'left center right'.split(' '), function (name) {
+ if (editor.formatter.matchNode(rowElm, 'align' + name)) {
+ data.align = name;
+ }
+ }
+ );
+
+ if (editor.settings.table_row_class_list) {
+ classListCtrl = {
+ name: 'class',
+ type: 'listbox',
+ label: 'Class',
+ values: buildListItems(
+ editor.settings.table_row_class_list,
+ function (item) {
+ if (item.value) {
+ item.textStyle = function () {
+ return editor.formatter.getCssText({block: 'tr', classes: [item.value]});
+ };
+ }
+ }
+ )
+ };
+ }
+
+ generalRowForm = {
+ type: 'form',
+ columns: 2,
+ padding: 0,
+ defaults: {
+ type: 'textbox'
+ },
+ items: [
+ {
+ type: 'listbox',
+ name: 'type',
+ label: 'Row type',
+ text: 'None',
+ maxWidth: null,
+ values: [
+ {text: 'Header', value: 'thead'},
+ {text: 'Body', value: 'tbody'},
+ {text: 'Footer', value: 'tfoot'}
+ ]
+ },
+ {
+ type: 'listbox',
+ name: 'align',
+ label: 'Alignment',
+ text: 'None',
+ maxWidth: null,
+ values: [
+ {text: 'None', value: ''},
+ {text: 'Left', value: 'left'},
+ {text: 'Center', value: 'center'},
+ {text: 'Right', value: 'right'}
+ ]
+ },
+ {label: 'Height', name: 'height'},
+ classListCtrl
+ ]
+ };
+
+ if (editor.settings.table_row_advtab !== false) {
+ appendStylesToData(dom, data, rowElm);
+
+ editor.windowManager.open(
+ {
+ title: "Row properties",
+ data: data,
+ bodyType: 'tabpanel',
+ body: [
+ {
+ title: 'General',
+ type: 'form',
+ items: generalRowForm
+ },
+ createStyleForm(dom)
+ ],
+
+ onsubmit: onSubmitRowForm
+ }
+ );
+ } else {
+ editor.windowManager.open(
+ {
+ title: "Row properties",
+ data: data,
+ body: generalRowForm,
+ onsubmit: onSubmitRowForm
+ }
+ );
+ }
+ };
+ };
+ }
+ );
+
+ // Included from: js/tinymce/plugins/table/classes/Plugin.js
+
+ /**
+ * Plugin.js
+ *
+ * Copyright, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://www.tinymce.com/license
+ * Contributing: http://www.tinymce.com/contributing
+ */
+
+ /**
+ * This class contains all core logic for the table plugin.
+ *
+ * @class tinymce.tableplugin.Plugin
+ * @private
+ */
+ define(
+ "tinymce/tableplugin/Plugin", [
+ "tinymce/tableplugin/TableGrid",
+ "tinymce/tableplugin/Quirks",
+ "tinymce/tableplugin/CellSelection",
+ "tinymce/tableplugin/Dialogs",
+ "tinymce/util/Tools",
+ "tinymce/dom/TreeWalker",
+ "tinymce/Env",
+ "tinymce/PluginManager"
+ ], function (TableGrid, Quirks, CellSelection, Dialogs, Tools, TreeWalker, Env, PluginManager) {
+ var each = Tools.each;
+
+ function Plugin(editor)
+ {
+ var clipboardRows, self = this, dialogs = new Dialogs(editor);
+
+ function cmd(command)
+ {
+ return function () {
+ editor.execCommand(command);
+ };
+ }
+
+ function insertTable(cols, rows)
+ {
+ var y, x, html, tableElm;
+
+ html = '';
+
+ for (y = 0; y < rows; y++) {
+ html += '';
+
+ for (x = 0; x < cols; x++) {
+ html += '' + (Env.ie ? " " : ' ') + ' ';
+ }
+
+ html += ' ';
+ }
+
+ html += '
';
+
+ editor.undoManager.transact(
+ function () {
+ editor.insertContent(html);
+
+ tableElm = editor.dom.get('__mce');
+ editor.dom.setAttrib(tableElm, 'id', null);
+
+ editor.dom.setAttribs(tableElm, editor.settings.table_default_attributes || {});
+ editor.dom.setStyles(tableElm, editor.settings.table_default_styles || {});
+ }
+ );
+
+ return tableElm;
+ }
+
+ function handleDisabledState(ctrl, selector)
+ {
+ function bindStateListener()
+ {
+ ctrl.disabled(!editor.dom.getParent(editor.selection.getStart(), selector));
+
+ editor.selection.selectorChanged(
+ selector, function (state) {
+ ctrl.disabled(!state);
+ }
+ );
+ }
+
+ if (editor.initialized) {
+ bindStateListener();
+ } else {
+ editor.on('init', bindStateListener);
+ }
+ }
+
+ function postRender()
+ {
+ /*jshint validthis:true*/
+ handleDisabledState(this, 'table');
+ }
+
+ function postRenderCell()
+ {
+ /*jshint validthis:true*/
+ handleDisabledState(this, 'td,th');
+ }
+
+ function generateTableGrid()
+ {
+ var html = '';
+
+ html = '';
+
+ for (var y = 0; y < 10; y++) {
+ html += '';
+
+ for (var x = 0; x < 10; x++) {
+ html += ' ';
+ }
+
+ html += ' ';
+ }
+
+ html += '
';
+
+ html += '1 x 1
';
+
+ return html;
+ }
+
+ function selectGrid(tx, ty, control)
+ {
+ var table = control.getEl().getElementsByTagName('table')[0];
+ var x, y, focusCell, cell, active;
+ var rtl = control.isRtl() || control.parent().rel == 'tl-tr';
+
+ table.nextSibling.innerHTML = (tx + 1) + ' x ' + (ty + 1);
+
+ if (rtl) {
+ tx = 9 - tx;
+ }
+
+ for (y = 0; y < 10; y++) {
+ for (x = 0; x < 10; x++) {
+ cell = table.rows[y].childNodes[x].firstChild;
+ active = (rtl ? x >= tx : x <= tx) && y <= ty;
+
+ editor.dom.toggleClass(cell, 'mce-active', active);
+
+ if (active) {
+ focusCell = cell;
+ }
+ }
+ }
+
+ return focusCell.parentNode;
+ }
+
+ if (editor.settings.table_grid === false) {
+ editor.addMenuItem(
+ 'inserttable', {
+ text: 'Insert table',
+ icon: 'table',
+ context: 'table',
+ onclick: dialogs.table
+ }
+ );
+ } else {
+ editor.addMenuItem(
+ 'inserttable', {
+ text: 'Insert table',
+ icon: 'table',
+ context: 'table',
+ ariaHideMenu: true,
+ onclick: function (e) {
+ if (e.aria) {
+ this.parent().hideAll();
+ e.stopImmediatePropagation();
+ dialogs.table();
+ }
+ },
+ onshow: function () {
+ selectGrid(0, 0, this.menu.items()[0]);
+ },
+ onhide: function () {
+ var elements = this.menu.items()[0].getEl().getElementsByTagName('a');
+ editor.dom.removeClass(elements, 'mce-active');
+ editor.dom.addClass(elements[0], 'mce-active');
+ },
+ menu: [
+ {
+ type: 'container',
+ html: generateTableGrid(),
+
+ onPostRender: function () {
+ this.lastX = this.lastY = 0;
+ },
+
+ onmousemove: function (e) {
+ var target = e.target, x, y;
+
+ if (target.tagName.toUpperCase() == 'A') {
+ x = parseInt(target.getAttribute('data-mce-x'), 10);
+ y = parseInt(target.getAttribute('data-mce-y'), 10);
+
+ if (this.isRtl() || this.parent().rel == 'tl-tr') {
+ x = 9 - x;
+ }
+
+ if (x !== this.lastX || y !== this.lastY) {
+ selectGrid(x, y, e.control);
+
+ this.lastX = x;
+ this.lastY = y;
+ }
+ }
+ },
+
+ onclick: function (e) {
+ var self = this;
+
+ if (e.target.tagName.toUpperCase() == 'A') {
+ e.preventDefault();
+ e.stopPropagation();
+ self.parent().cancel();
+
+ editor.undoManager.transact(
+ function () {
+ insertTable(self.lastX + 1, self.lastY + 1);
+ }
+ );
+
+ editor.addVisual();
+ }
+ }
+ }
+ ]
+ }
+ );
+ }
+
+ editor.addMenuItem(
+ 'tableprops', {
+ text: 'Table properties',
+ context: 'table',
+ onPostRender: postRender,
+ onclick: dialogs.tableProps
+ }
+ );
+
+ editor.addMenuItem(
+ 'deletetable', {
+ text: 'Delete table',
+ context: 'table',
+ onPostRender: postRender,
+ cmd: 'mceTableDelete'
+ }
+ );
+
+ editor.addMenuItem(
+ 'cell', {
+ separator: 'before',
+ text: 'Cell',
+ context: 'table',
+ menu: [
+ {text: 'Cell properties', onclick: cmd('mceTableCellProps'), onPostRender: postRenderCell},
+ {text: 'Merge cells', onclick: cmd('mceTableMergeCells'), onPostRender: postRenderCell},
+ {text: 'Split cell', onclick: cmd('mceTableSplitCells'), onPostRender: postRenderCell}
+ ]
+ }
+ );
+
+ editor.addMenuItem(
+ 'row', {
+ text: 'Row',
+ context: 'table',
+ menu: [
+ {text: 'Insert row before', onclick: cmd('mceTableInsertRowBefore'), onPostRender: postRenderCell},
+ {text: 'Insert row after', onclick: cmd('mceTableInsertRowAfter'), onPostRender: postRenderCell},
+ {text: 'Delete row', onclick: cmd('mceTableDeleteRow'), onPostRender: postRenderCell},
+ {text: 'Row properties', onclick: cmd('mceTableRowProps'), onPostRender: postRenderCell},
+ {text: '-'},
+ {text: 'Cut row', onclick: cmd('mceTableCutRow'), onPostRender: postRenderCell},
+ {text: 'Copy row', onclick: cmd('mceTableCopyRow'), onPostRender: postRenderCell},
+ {text: 'Paste row before', onclick: cmd('mceTablePasteRowBefore'), onPostRender: postRenderCell},
+ {text: 'Paste row after', onclick: cmd('mceTablePasteRowAfter'), onPostRender: postRenderCell}
+ ]
+ }
+ );
+
+ editor.addMenuItem(
+ 'column', {
+ text: 'Column',
+ context: 'table',
+ menu: [
+ {text: 'Insert column before', onclick: cmd('mceTableInsertColBefore'), onPostRender: postRenderCell},
+ {text: 'Insert column after', onclick: cmd('mceTableInsertColAfter'), onPostRender: postRenderCell},
+ {text: 'Delete column', onclick: cmd('mceTableDeleteCol'), onPostRender: postRenderCell}
+ ]
+ }
+ );
+
+ var menuItems = [];
+ each(
+ "inserttable tableprops deletetable | cell row column".split(' '), function (name) {
+ if (name == '|') {
+ menuItems.push({text: '-'});
+ } else {
+ menuItems.push(editor.menuItems[name]);
+ }
+ }
+ );
+
+ editor.addButton(
+ "table", {
+ type: "menubutton",
+ title: "Table",
+ menu: menuItems
+ }
+ );
+
+ // Select whole table is a table border is clicked
+ if (!Env.isIE) {
+ editor.on(
+ 'click', function (e) {
+ e = e.target;
+
+ if (e.nodeName === 'TABLE') {
+ editor.selection.select(e);
+ editor.nodeChanged();
+ }
+ }
+ );
+ }
+
+ self.quirks = new Quirks(editor);
+
+ editor.on(
+ 'Init', function () {
+ self.cellSelection = new CellSelection(editor);
+ }
+ );
+
+ // Register action commands
+ each(
+ {
+ mceTableSplitCells: function (grid) {
+ grid.split();
+ },
+
+ mceTableMergeCells: function (grid) {
+ var cell;
+
+ cell = editor.dom.getParent(editor.selection.getStart(), 'th,td');
+
+ if (!editor.dom.select('td.mce-item-selected,th.mce-item-selected').length) {
+ dialogs.merge(grid, cell);
+ } else {
+ grid.merge();
+ }
+ },
+
+ mceTableInsertRowBefore: function (grid) {
+ grid.insertRow(true);
+ },
+
+ mceTableInsertRowAfter: function (grid) {
+ grid.insertRow();
+ },
+
+ mceTableInsertColBefore: function (grid) {
+ grid.insertCol(true);
+ },
+
+ mceTableInsertColAfter: function (grid) {
+ grid.insertCol();
+ },
+
+ mceTableDeleteCol: function (grid) {
+ grid.deleteCols();
+ },
+
+ mceTableDeleteRow: function (grid) {
+ grid.deleteRows();
+ },
+
+ mceTableCutRow: function (grid) {
+ clipboardRows = grid.cutRows();
+ },
+
+ mceTableCopyRow: function (grid) {
+ clipboardRows = grid.copyRows();
+ },
+
+ mceTablePasteRowBefore: function (grid) {
+ grid.pasteRows(clipboardRows, true);
+ },
+
+ mceTablePasteRowAfter: function (grid) {
+ grid.pasteRows(clipboardRows);
+ },
+
+ mceTableDelete: function (grid) {
+ grid.deleteTable();
+ }
+ }, function (func, name) {
+ editor.addCommand(
+ name, function () {
+ var grid = new TableGrid(editor);
+
+ if (grid) {
+ func(grid);
+ editor.execCommand('mceRepaint');
+ self.cellSelection.clear();
+ }
+ }
+ );
+ }
+ );
+
+ // Register dialog commands
+ each(
+ {
+ mceInsertTable: dialogs.table,
+ mceTableProps: function () {
+ dialogs.table(true);
+ },
+ mceTableRowProps: dialogs.row,
+ mceTableCellProps: dialogs.cell
+ }, function (func, name) {
+ editor.addCommand(
+ name, function (ui, val) {
+ func(val);
+ }
+ );
+ }
+ );
+
+ // Enable tab key cell navigation
+ if (editor.settings.table_tab_navigation !== false) {
+ editor.on(
+ 'keydown', function (e) {
+ var cellElm, grid, delta;
+
+ if (e.keyCode == 9) {
+ cellElm = editor.dom.getParent(editor.selection.getStart(), 'th,td');
+
+ if (cellElm) {
+ e.preventDefault();
+
+ grid = new TableGrid(editor);
+ delta = e.shiftKey ? -1 : 1;
+
+ editor.undoManager.transact(
+ function () {
+ if (!grid.moveRelIdx(cellElm, delta) && delta > 0) {
+ grid.insertRow();
+ grid.refresh();
+ grid.moveRelIdx(cellElm, delta);
+ }
+ }
+ );
+ }
+ }
+ }
+ );
+ }
+
+ self.insertTable = insertTable;
+ }
+
+ PluginManager.add('table', Plugin);
+ }
+ );
+})(this);
\ No newline at end of file
diff --git a/tinymce/table/plugin.min.js b/admin/tinymce/table/plugin.min.js
similarity index 100%
rename from tinymce/table/plugin.min.js
rename to admin/tinymce/table/plugin.min.js
diff --git a/bmlt-meeting-list.php b/bmlt-meeting-list.php
index b5f6ec5..bcb53a1 100644
--- a/bmlt-meeting-list.php
+++ b/bmlt-meeting-list.php
@@ -1,2981 +1,79 @@
'location_city_subsection',
- 'time' => 'start_time',
- 'state' => 'location_province',
- 'street' => 'location_street',
- 'neighborhood' => 'location_neighborhood',
- 'city' => 'location_municipality',
- 'zip' => 'location_postal_code_1',
- 'location' => 'location_text',
- 'info' => 'location_info',
- 'county' => 'location_sub_province',
- 'group' => 'meeting_name',
- 'email' => 'email_contact',
- 'mins' => 'duration_m',
- 'hrs' => 'duration_h',
- "area" => 'area_name',
- );
- var $section_shortcodes;
- var $service_meeting_result = null;
- const SETTINGS = 'bmlt_meeting_list_settings';
- const OPTIONS_NAME = 'bmlt_meeting_list_options';
- var $optionsName = Bread::OPTIONS_NAME;
- var $options = array();
- var $outside_meeting_result = array();
- var $allSettings = array();
- var $maxSetting = 1;
- var $loaded_setting = 1;
- var $authors_safe = array();
- var $connection_error = '';
- var $protocol = '';
- var $unique_areas = array();
-
- function loadAllSettings()
- {
- $this->allSettings = get_option(Bread::SETTINGS);
- if ($this->allSettings === false) {
- $this->allSettings = array();
- $this->allSettings[1] = "Default Setting";
- $this->maxSetting = 1;
- } else {
- foreach ($this->allSettings as $key => $value) {
- if ($key > $this->maxSetting) {
- $this->maxSetting = $key;
- }
- }
- }
- }
- function startsWith($haystack, $needle)
- {
- $length = strlen($needle);
- return (substr($haystack, 0, $length) === $needle);
- }
- function getCurrentMeetingListHolder()
- {
- $ret = array();
- if (isset($_REQUEST['current-meeting-list'])) {
- $ret['current-meeting-list'] = $_REQUEST['current-meeting-list'];
- } else if (isset($_COOKIE['current-meeting-list'])) {
- $ret['current-meeting-list'] = $_COOKIE['current-meeting-list'];
- }
- return $ret;
- }
- function __construct()
- {
- // Register hooks
- register_activation_hook(__FILE__, array(__CLASS__, 'activation'));
-
- $this->protocol = (strpos(strtolower(home_url()), "https") !== false ? "https" : "http") . "://";
-
- $this->loadAllSettings();
- $holder = $this->getCurrentMeetingListHolder();
-
- $current_settings = isset($holder['current-meeting-list']) ? intval($holder['current-meeting-list']) : 1;
- $this->load_translations();
- if (isset($holder['current-meeting-list']) && !is_admin()) {
- $this->getMLOptions($current_settings);
- add_action('plugins_loaded', array(&$this, 'bmlt_meeting_list' ));
- } else if (is_admin()) {
- $this->requested_setting = $current_settings;
- add_action("admin_init", array(&$this, 'my_sideload_image'));
- add_action("admin_menu", array(&$this, "admin_menu_link"));
- add_filter('tiny_mce_before_init', array(&$this, 'tiny_tweaks'));
- add_filter('mce_external_plugins', array(&$this, 'my_custom_plugins'));
- add_filter('mce_buttons', array(&$this, 'my_register_mce_button'));
- //add_action("admin_notices", array(&$this, "is_root_server_missing"));
- add_action("admin_init", array(&$this, "pwsix_process_settings_export"));
- add_action("admin_init", array(&$this, "pwsix_process_settings_import"));
- add_action("admin_init", array(&$this, "pwsix_process_default_settings"));
- add_action("admin_init", array(&$this, "pwsix_process_settings_admin"));
- add_action("admin_init", array(&$this, "pwsix_process_rename_settings"));
- add_action("admin_init", array(&$this, "my_theme_add_editor_styles"));
- add_action("admin_enqueue_scripts", array(&$this, "enqueue_backend_files"));
- add_action("wp_default_editor", array(&$this, "ml_default_editor"));
- add_filter('tiny_mce_version', array(__CLASS__, 'force_mce_refresh'));
- }
-
- register_deactivation_hook(__FILE__, array(__CLASS__, 'deactivation'));
- }
-
- public static function activation()
- {
- Bread::add_cap();
- }
-
- private static function add_cap()
- {
- $role = $GLOBALS['wp_roles']->role_objects['administrator'];
- if (isset($role) && !$role->has_cap('manage_bread')) {
- $role->add_cap('manage_bread');
- }
- }
-
- public static function deactivation()
- {
- Bread::remove_cap();
- }
-
- private static function remove_cap()
- {
- $role = $GLOBALS['wp_roles']->role_objects['administrator'];
- if (isset($role) && $role->has_cap('manage_bread')) {
- $role->remove_cap('manage_bread');
- }
- }
-
- function ml_default_editor()
- {
- global $my_admin_page;
- $screen = get_current_screen();
- if ($screen->id == $my_admin_page) {
- return "tinymce";
- }
- }
-
- function force_mce_refresh($ver)
- {
- global $my_admin_page;
- $screen = get_current_screen();
- if ($screen->id == $my_admin_page) {
- return $ver + 99;
- }
- }
-
- function my_sideload_image()
- {
- global $my_admin_page;
- $screen = get_current_screen();
- if (isset($screen) && $screen->id == $my_admin_page) {
- if (get_option($this->optionsName) === false) {
- $url = plugin_dir_url(__FILE__) . "includes/nalogo.jpg";
- media_sideload_image($url, 0);
- }
- }
- }
-
- // Register new button in the editor
- function my_register_mce_button($buttons)
- {
- global $my_admin_page;
- $screen = get_current_screen();
- if ($screen->id == $my_admin_page) {
- array_push($buttons, 'front_page_button', 'custom_template_button_1', 'custom_template_button_2');
- }
- return $buttons;
- }
-
- function my_custom_plugins()
- {
- global $my_admin_page;
- $plugins_array = array();
- $screen = get_current_screen();
- if ($screen->id == $my_admin_page) {
- $plugins = array('table', 'code', 'contextmenu' ); //Add any more plugins you want to load here
- //Build the response - the key is the plugin name, value is the URL to the plugin JS
- foreach ($plugins as $plugin) {
- $plugins_array[ $plugin ] = plugins_url('tinymce/', __FILE__) . $plugin . '/plugin.min.js';
- }
- $shortcode_menu = array();
- $shortcode_menu['front_page_button'] = plugins_url('tinymce/', __FILE__) . 'front_page_button/plugin.min.js';
- //let's leave the enhancement mechanism open for now.
- //apply_filters is one option, perhaps we will think of something better.
- //$shortcode_menu = apply_filters("Bread_Adjust_Menu", $shortcode_menu);
- $plugins_array = array_merge($plugins_array, $shortcode_menu);
- }
- return $plugins_array;
- }
-
- // Enable font size & font family selects in the editor
- function tiny_tweaks($initArray)
- {
- global $my_admin_page;
- $screen = get_current_screen();
- if ($screen->id == $my_admin_page) {
- $initArray['fontsize_formats'] = "5pt 6pt 7pt 8pt 9pt 10pt 11pt 12pt 13pt 14pt 15pt 16pt 17pt 18pt 19pt 20pt 22pt 24pt 26pt 28pt 30pt 32pt 34pt 36pt 38pt";
- $initArray['theme_advanced_blockformats'] = 'h2,h3,h4,p';
- $initArray['wordpress_adv_hidden'] = false;
- $initArray['font_formats']='Arial (Default)=arial;';
- $initArray['font_formats'].='Times (Sans-Serif)=times;';
- $initArray['font_formats'].='Courier (Monospace)=courier;';
- $initArray['content_style'] = 'body { font-family: Arial; }';
- }
- return $initArray;
- }
- function get_temp_dir()
- {
- if (!$this->tmp_dir) {
- $dir = get_temp_dir();
- $dir = rtrim($dir, DIRECTORY_SEPARATOR);
- if (!is_dir($dir) || !is_writable($dir)) {
- return false;
- }
- $this->brute_force_cleanup($dir);
- $attempts = 0;
- $path = '';
- do {
- $path = sprintf('%s%s%s%s', $dir, DIRECTORY_SEPARATOR, 'bread', mt_rand(100000, mt_getrandmax()));
- } while (!mkdir($path) && $attempts++ < 100);
- $this->tmp_dir = $path;
- }
- return $this->tmp_dir;
- }
- function is_root_server_missing()
- {
- global $my_admin_page;
- $screen = get_current_screen();
- if ($screen->id == $my_admin_page) {
- $root_server = $this->options['root_server'];
- if ($root_server == '') {
- echo 'Missing BMLT Server in settings for bread.
';
- $url = admin_url('options-general.php?page=bmlt-meeting-list.php');
- echo "
Settings
";
- echo '
';
- } else if (!$this->get_temp_dir()) {
- echo '' . $this->get_temp_dir() . ' temporary directory is not writable.
';
- $url = admin_url('options-general.php?page=bmlt-meeting-list.php');
- echo "
Settings
";
- echo '
';
- }
- }
- }
- function Bread()
- {
- $this->__construct();
- }
-
- /**
- * @desc Adds JS/CSS to the header
- */
- function enqueue_backend_files($hook)
- {
- if ($hook == 'toplevel_page_bmlt-meeting-list') {
- wp_enqueue_script('common');
- wp_enqueue_script('jquery-ui-tabs');
- wp_enqueue_script('jquery-ui-accordion');
- wp_enqueue_script('jquery-ui-dialog');
- wp_enqueue_style("jquery-ui", plugin_dir_url(__FILE__) . "css/jquery-ui.min.css", false, "1.2", 'all');
- wp_enqueue_style("spectrum", plugin_dir_url(__FILE__) . "css/spectrum.css", false, "1.2", 'all');
- wp_enqueue_style("admin", plugin_dir_url(__FILE__) . "css/admin.css", false, "1.2", 'all');
- wp_enqueue_style("chosen", plugin_dir_url(__FILE__) . "css/chosen.min.css", false, "1.2", 'all');
- wp_enqueue_script("bmlt_meeting_list", plugin_dir_url(__FILE__) . "js/bmlt_meeting_list.js", array('jquery'), "1.2", true);
- wp_enqueue_script("tooltipster", plugin_dir_url(__FILE__) . "js/jquery.tooltipster.min.js", array('jquery'), "1.2", true);
- wp_enqueue_script("spectrum", plugin_dir_url(__FILE__) . "js/spectrum.js", array('jquery'), "1.2", true);
- wp_enqueue_script("chosen", plugin_dir_url(__FILE__) . "js/chosen.jquery.min.js", array('jquery'), "1.2", true);
- }
- }
-
- function my_theme_add_editor_styles()
- {
- global $my_admin_page;
- $screen = get_current_screen();
- if (isset($screen) && $screen->id == $my_admin_page) {
- add_editor_style(plugin_dir_url(__FILE__) . "css/editor-style.css");
- }
- }
- function load_translations()
- {
- $files = scandir(dirname(__FILE__)."/lang");
- foreach ($files as $file) {
- if (strpos($file, "translate_")!==0) {
- continue;
- }
- include(dirname(__FILE__)."/lang/".$file);
- $key = substr($file, 10, -4);
- $this->translate[$key] = $translate;
- }
- }
- function getday($day, $abbreviate = false, $language = 'en')
- {
- $data = '';
- $key = "WEEKDAYS";
- if ($abbreviate) {
- $key = "WKDYS";
- }
- return mb_convert_encoding($this->translate[$language][$key][$day], 'UTF-8', mb_list_encodings());
- }
-
- function authenticate_root_server()
- {
- $query_string = http_build_query(array(
- 'admin_action' => 'login',
- 'c_comdef_admin_login' => $this->options['bmlt_login_id'],
- 'c_comdef_admin_password' => $this->options['bmlt_login_password'], '&'));
- return $this->get($this->options['root_server']."/local_server/server_admin/xml.php?" . $query_string);
- }
- function requires_authentication()
- {
- return ($this->options['include_meeting_email'] == 1 || $this->options['include_asm'] == 1);
- }
- function get_root_server_request($url)
- {
- $cookies = null;
-
- if ($this->requires_authentication()) {
- $auth_response = $this->authenticate_root_server();
- $cookies = wp_remote_retrieve_cookies($auth_response);
- }
-
- return $this->get($url, $cookies);
- }
-
- function get_configured_root_server_request($url)
- {
- return $this->get_root_server_request($this->options['root_server']."/".$url);
- }
-
- function get($url, $cookies = array())
- {
- $args = array(
- 'timeout' => '120',
- 'cookies' => $cookies,
- );
- if (isset($this->options['user_agent']) &&
- $this->options['user_agent'] != 'None') {
- $args['headers'] = array(
- 'User-Agent' => $this->options['user_agent']
- );
- }
- if ($this->options['sslverify'] == '1') {
- $args['sslverify'] = false;
- }
- return wp_remote_get($url, $args);
- }
- function get_all_meetings()
- {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults&data_field_key=weekday_tinyint,start_time,service_body_bigint,id_bigint,meeting_name,location_text,email_contact&sort_keys=meeting_name,service_body_bigint,weekday_tinyint,start_time");
- $result = json_decode(wp_remote_retrieve_body($results), true);
-
- $this->unique_areas = $this->get_areas();
- $all_meetings = array();
- foreach ($result as $value) {
- foreach ($this->unique_areas as $unique_area) {
- $area_data = explode(',', $unique_area);
- $area_id = $this->arraySafeGet($area_data, 1);
- if ($area_id === $value['service_body_bigint']) {
- $area_name = $this->arraySafeGet($area_data);
- }
- }
-
- $value['start_time'] = date("g:iA", strtotime($value['start_time']));
- $all_meetings[] = $value['meeting_name'].'||| ['.$this->getday($value['weekday_tinyint'], true, $this->lang).'] ['.$value['start_time'].']||| ['.$area_name.']||| ['.$value['id_bigint'].']';
- }
-
- return $all_meetings;
- }
- function get_fieldkeys()
- {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetFieldKeys");
- return json_decode(wp_remote_retrieve_body($results), true);
- }
- var $standard_keys = array(
- "id_bigint","worldid_mixed","service_body_bigint",
- "weekday_tinyint","start_time","duration_time","formats",
- "lang_enum","longitude","latitude","meeting_name"."location_text",
- "location_info","location_street","location_city_subsection",
- "location_neighborhood","location_municipality","location_sub_province",
- "location_province","location_postal_code_1","location_nation","comments","zone");
- function get_nonstandard_fieldkeys()
- {
- $all_fks = $this->get_fieldkeys();
- $ret = array();
- foreach ($all_fks as $fk) {
- if (!in_array($fk['key'], $this->standard_keys)) {
- $ret[] = $fk;
- }
- }
- $ext_fields = apply_filters("Bread_Enrich_Meeting_Data", array(), array());
- foreach ($ext_fields as $key => $value) {
- $ret[] = array("key" => $key, "description" => $key);
- }
- return $ret;
- }
- function get_areas()
- {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetServiceBodies");
- $result = json_decode(wp_remote_retrieve_body($results), true);
- $unique_areas = array();
-
- foreach ($result as $value) {
- $parent_name = 'Parent ID';
- foreach ($result as $parent) {
- if ($value['parent_id'] == $parent['id']) {
- $parent_name = $parent['name'];
- }
- }
- if ($value['parent_id'] == '') {
- $value['parent_id'] = '0';
- }
- $unique_areas[] = $value['name'] . ',' . $value['id'] . ',' . $value['parent_id'] . ',' . $parent_name;
- }
-
- return $unique_areas;
- }
-
- function get_bmlt_server_lang()
- {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetServerInfo");
- $result = json_decode(wp_remote_retrieve_body($results), true);
- if ($result==null) {
- return 'en';
- }
- $result = $result["0"]["nativeLang"];
-
- return $result;
- }
-
- function testRootServer($override_root_server = null)
- {
- if ($override_root_server == null) {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetServerInfo");
- } else {
- $results = $this->get_root_server_request($override_root_server."/client_interface/json/?switcher=GetServerInfo");
- }
- if ($results instanceof WP_Error) {
- $this->connection_error = $results->get_error_message();
- return false;
- }
- $httpcode = wp_remote_retrieve_response_code($results);
- if ($httpcode != 200 && $httpcode != 302 && $httpcode != 304) {
- $this->connection_error = "HTTP Return Code: ".$httpcode;
- return false;
- }
-
- return json_decode(wp_remote_retrieve_body($results), true);
- }
- // This is used from the AdminUI, not to generate the
- // meeting list.
- function getFormatsForSelect($all = false)
- {
- if ($all) {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetFormats");
- $results = json_decode(wp_remote_retrieve_body($results), true);
- $this->sortBySubkey($results, 'key_string');
- return $results;
- }
- if (!isset($this->options['recurse_service_bodies'])) {
- $this->options['recurse_service_bodies'] = 1;
- }
- $area_data = explode(',', $this->options['service_body_1']);
- $service_body_id = $this->arraySafeGet($area_data, 1);
- if ($this->options['recurse_service_bodies'] == 1) {
- $services = '&recursive=1&services[]=' . $service_body_id;
- } else {
- $services = '&services[]='.$service_body_id;
- }
- if (empty($service_body_id)) {
- $queryUrl = "client_interface/json/?switcher=GetFormats";
- } else {
- $queryUrl = "client_interface/json/?switcher=GetSearchResults$services&get_formats_only";
- }
- $results = $this->get_configured_root_server_request($queryUrl);
- $results = json_decode(wp_remote_retrieve_body($results), true);
- $results = empty($service_body_id) ? $results : $results['formats'];
- $this->sortBySubkey($results, 'key_string');
- return $results;
- }
-
- function sortBySubkey(&$array, $subkey, $sortType = SORT_ASC)
- {
- if (empty($array)) {
- return;
- }
- foreach ($array as $subarray) {
- $keys[] = $subarray[$subkey];
- }
- array_multisort($keys, $sortType, $array);
- }
- function upgrade_settings()
- {
- if (!isset($this->options['cont_header_shown'])
- && isset($this->options['page_height_fix'])) {
- $fix = floatval($this->options['page_height_fix']);
- // say, the height of 2 lines
- $x = floatval($this->options['content_font_size']) *
- floatval($this->options['content_line_height']) * 2.0 * 0.35; // pt to mm
- if ($fix < $x) {
- $this->options['cont_header_shown'] = true;
- } else {
- $this->options['cont_header_shown'] = false;
- }
- unset($this->options['page_height_fix']);
- }
- if ($this->options['weekday_language'] == 'both') {
- $this->options['weekday_language'] = "en_es";
- }
- if ($this->options['weekday_language'] == 'both_po') {
- $this->options['weekday_language'] = "en_po";
- }
- if ($this->options['sub_header_shown'] == '0') {
- $this->options['sub_header_shown'] = 'none';
- }
- if ($this->options['sub_header_shown'] == '1') {
- $this->options['sub_header_shown'] = 'display';
- }
- }
- function bmlt_meeting_list($atts = null, $content = null)
- {
- $import_streams = [];
- ini_set('max_execution_time', 600); // tomato server can take a long time to generate a schedule, override the server setting
- $this->lang = $this->get_bmlt_server_lang();
- // addServiceBody has the side effect that
- // the service body option is overridden, so that it contains
- // only the name of the service body.
- $services = $this->addServiceBody('service_body_1');
- $services .= $this->addServiceBody('service_body_2');
- $services .= $this->addServiceBody('service_body_3');
- $services .= $this->addServiceBody('service_body_4');
- $services .= $this->addServiceBody('service_body_5');
- $area = $this->options['service_body_1'];
-
- if (isset($_GET['custom_query'])) {
- $services = $_GET['custom_query'];
- } elseif ($this->options['custom_query'] !== '') {
- $services = $this->options['custom_query'];
- }
- $this->services = $services;
- if ($this->options['root_server'] == '') {
- echo 'bread Error: BMLT Server missing. Please go to Settings -> bread and verify BMLT Server
';
- exit;
- }
- if ($this->options['service_body_1'] == 'Not Used' && true === ($this->options['custom_query'] == '' )) {
- echo 'bread Error: Service Body 1 missing from configuration. Please go to Settings -> bread and verify Service Body Contact the bread administrator and report this problem!
';
- exit;
- }
- if (headers_sent()) {
- echo 'Headers already sent before Meeting List generation
';
- exit;
- }
-
- $num_columns = 0;
- if (!isset($this->options['suppress_heading'])) {
- $this->options['suppress_heading'] = 0;
- }
- if (!isset($this->options['header_font_size'])) {
- $this->options['header_font_size'] = $this->options['content_font_size'];
- }
- if (!isset($this->options['header_text_color'])) {
- $this->options['header_text_color'] = '#ffffff';
- }
- if (!isset($this->options['header_background_color'])) {
- $this->options['header_background_color'] = '#000000';
- }
- if (!isset($this->options['pageheader_textcolor'])) {
- $this->options['pageheader_textcolor'] = '#000000';
- }
- if (!isset($this->options['pageheader_fontsize']) || floatval($this->options['pageheader_fontsize'])<4) {
- $this->options['pageheader_fontsize'] = '9';
- }
- if (!isset($this->options['pageheader_backgroundcolor'])) {
- $this->options['pageheader_backgroundcolor'] = '#ffffff';
- }
- if (!isset($this->options['margin_left'])) {
- $this->options['margin_left'] = 3;
- }
- if (!isset($this->options['margin_bottom'])) {
- $this->options['margin_bottom'] = 3;
- }
- if (!isset($this->options['margin_top'])) {
- $this->options['margin_top'] = 3;
- }
- if (!isset($this->options['margin_header'])) {
- $this->options['margin_header'] = 3;
- }
- if (!isset($this->options['margin_footer'])) {
- $this->options['margin_footer'] = 5;
- }
- if (!isset($this->options['page_size'])) {
- $this->options['page_size'] = 'legal';
- }
- if (!isset($this->options['page_orientation'])) {
- $this->options['page_orientation'] = 'L';
- }
- if (!isset($this->options['booklet_pages'])) {
- $this->options['booklet_pages'] = false;
- }
- if (!isset($this->options['page_fold'])) {
- $this->options['page_fold'] = 'quad';
- }
- if (!isset($this->options['meeting_sort'])) {
- $this->options['meeting_sort'] = 'day';
- }
- if (!isset($this->options['borough_suffix'])) {
- $this->options['borough_suffix'] = 'Borough';
- }
- if (!isset($this->options['county_suffix'])) {
- $this->options['county_suffix'] = 'County';
- }
- if (!isset($this->options['neighborhood_suffix'])) {
- $this->options['neighborhood_suffix'] = 'Neighborhood';
- }
- if (!isset($this->options['city_suffix'])) {
- $this->options['city_suffix'] = 'City';
- }
- if (!isset($this->options['column_line'])) {
- $this->options['column_line'] = 0;
- }
- if (!isset($this->options['col_color'])) {
- $this->options['col_color'] = '#bfbfbf';
- }
- if (!isset($this->options['custom_section_content'])) {
- $this->options['custom_section_content'] = '';
- }
- if (!isset($this->options['custom_section_line_height'])) {
- $this->options['custom_section_line_height'] = '1';
- }
- if (!isset($this->options['custom_section_font_size'])) {
- $this->options['custom_section_font_size'] = '9';
- }
- if (!isset($this->options['pagenumbering_font_size'])) {
- $this->options['pagenumbering_font_size'] = '9';
- }
- if (!isset($this->options['include_meeting_email'])) {
- $this->options['include_meeting_email'] = 0;
- }
- if (!isset($this->options['include_protection'])) {
- $this->options['include_protection'] = 0;
- }
- if (!isset($this->options['base_font'])) {
- $this->options['base_font'] = 'dejavusanscondensed';
- }
- if (!isset($this->options['colorspace'])) {
- $this->options['colorspace'] = 0;
- }
- if (!isset($this->options['weekday_language'])) {
- $this->options['weekday_language'] = 'en';
- }
- if (!isset($this->options['asm_language'])) {
- $this->options['asm_language'] = '';
- }
- if (!isset($this->options['weekday_start'])) {
- $this->options['weekday_start'] = '1';
- }
- if (!isset($this->options['include_asm'])) {
- $this->options['include_asm'] = '0';
- }
- if (!isset($this->options['asm_format_key'])) {
- $this->options['asm_format_key'] = 'ASM';
- }
- if (!isset($this->options['asm_sort_order'])) {
- $this->options['asm_sort_order'] = 'name';
- }
- if (!isset($this->options['header_uppercase'])) {
- $this->options['header_uppercase'] = '0';
- }
- if (!isset($this->options['header_bold'])) {
- $this->options['header_bold'] = '1';
- }
- if (!isset($this->options['sub_header_shown'])) {
- $this->options['sub_header_shown'] = '0';
- }
- if (!isset($this->options['bmlt_login_id'])) {
- $this->options['bmlt_login_id'] = '';
- }
- if (!isset($this->options['bmlt_login_password'])) {
- $this->options['bmlt_login_password'] = '';
- }
- if (!isset($this->options['protection_password'])) {
- $this->options['protection_password'] = '';
- }
- if (!isset($this->options['cache_time'])) {
- $this->options['cache_time'] = 0;
- }
- if (!isset($this->options['extra_meetings'])) {
- $this->options['extra_meetings'] = [];
- }
- if (!isset($this->options['custom_query'])) {
- $this->options['custom_query'] = '';
- }
- if (!isset($this->options['asm_custom_query'])) {
- $this->options['asm_custom_query'] = '';
- }
- if (!isset($this->options['user_agent'])) {
- $this->options['user_agent'] = 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) +bread';
- }
- if (!isset($this->options['sslverify'])) {
- $this->options['sslverify'] = '0';
- }
- if (!isset($this->options['used_format_1'])) {
- $this->options['used_format_1'] = '';
- }
- if (!isset($this->options['wheelchair_size'])) {
- $this->options['wheelchair_size'] = '20px';
- }
- if (intval($this->options['cache_time']) > 0 && ! isset($_GET['nocache']) &&
- ! isset($_GET['custom_query'])) {
- if (false !== ( $content = get_transient($this->get_TransientKey()) )) {
- $content = pack("H*", $content);
- $name = $this->get_FilePath();
- header('Content-Type: application/pdf');
- header('Content-Length: '.strlen($content));
- header('Content-disposition: inline; filename="'.$name.'"');
- header('Cache-Control: public, must-revalidate, max-age=0');
- header('Pragma: public');
- header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
- header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');
- echo $content;
- exit;
- }
- }
- if (isset($_GET['time_zone'])) {
- $this->target_timezone = timezone_open($_GET['time_zone']);
- }
- // upgrade
- if (!isset($this->options['bread_version'])) {
- if (!($this->options['meeting_sort'] === 'weekday_area'
- || $this->options['meeting_sort'] === 'weekday_city'
- || $this->options['meeting_sort'] === 'weekday_county'
- || $this->options['meeting_sort'] === 'day')) {
- $this->options['weekday_language'] = $this->lang;
- }
- if ($this->options['page_fold']=='half') {
- if ($this->options['page_size']=='A5') {
- $this->options['page_size'] = 'A4';
- }
- $this->options['page_orientation'] = 'L';
- }
- if ($this->options['page_fold']=='tri') {
- $this->options['page_orientation'] = 'L';
- }
- if (substr($this->options['meeting_sort'], 0, 8) == 'weekday_') {
- $this->options['sub_header_shown'] = 'display';
- }
- if (isset($this->options['pageheader_text'])) {
- $this->options['pageheader_content'] = $this->options['pageheader_text'];
- unset($this->options['pageheader_text']);
- }
- if (substr($this->options['root_server'], -1) == '/') {
- $this->options['root_server'] = substr($this->options['root_server'], 0, strlen($this->options['root_server'])-1);
- }
- if (substr($this->options['root_server'], 0, 4) !== 'http') {
- $this->options['root_server'] = 'http://'.$this->options['root_server'];
- }
- }
- $this->upgrade_settings();
- // TODO: The page number is always 5 from botton...this should be adjustable
- if ($this->options['page_fold'] == 'half') {
- if ($this->options['page_size'] == 'letter') {
- $page_type_settings = ['format' => array(139.7,215.9), 'margin_footer' => $this->options['margin_footer']];
- } elseif ($this->options['page_size'] == 'legal') {
- $page_type_settings = ['format' => array(177.8,215.9), 'margin_footer' => $this->options['margin_footer']];
- } elseif ($this->options['page_size'] == 'ledger') {
- $page_type_settings = ['format' => 'letter-P', 'margin_footer' => $this->options['margin_footer']];
- } elseif ($this->options['page_size'] == 'A4') {
- $page_type_settings = ['format' => 'A5-P', 'margin_footer' => $this->options['margin_footer']];
- } elseif ($this->options['page_size'] == 'A5') {
- $page_type_settings = ['format' => 'A6-P', 'margin_footer' => $this->options['margin_footer']];
- } elseif ($this->options['page_size'] == '5inch') {
- $page_type_settings = ['format' => array(197.2,279.4), 'margin_footer' => $this->options['margin_footer']];
- }
- } elseif ($this->options['page_fold'] == 'flyer') {
- if ($this->options['page_size'] == 'letter') {
- $page_type_settings = ['format' => array(93.13,215.9), 'margin_footer' => $this->options['margin_footer']];
- } elseif ($this->options['page_size'] == 'legal') {
- $page_type_settings = ['format' => array(118.53,215.9), 'margin_footer' => $this->options['margin_footer']];
- } elseif ($this->options['page_size'] == 'ledger') {
- $page_type_settings = ['format' => array(143.93,279.4), 'margin_footer' => $this->options['margin_footer']];
- } elseif ($this->options['page_size'] == 'A4') {
- $page_type_settings = ['format' => array(99.0,210.0), 'margin_footer' => $this->options['margin_footer']];
- }
- } elseif ($this->options['page_fold'] == 'full') {
- $ps = $this->options['page_size'];
- if ($ps=='ledger') {
- $ps = 'tabloid';
- }
- $page_type_settings = ['format' => $ps."-".$this->options['page_orientation'], 'margin_footer' => $this->options['margin_footer']];
- } else {
- $ps = $this->options['page_size'];
- if ($ps=='ledger') {
- $ps = 'tabloid';
- }
- $page_type_settings = ['format' => $ps."-".$this->options['page_orientation'], 'margin_footer' => 0];
- }
- $default_font = $this->options['base_font'] == "freesans" ? "dejavusanscondensed" : $this->options['base_font'];
- $mode = 's';
- if ($default_font == 'arial' || $default_font == 'times' || $default_font == 'courier') {
- $mpdf_init_options = [
- 'fontDir' => array(
- __DIR__ . '/mpdf/vendor/mpdf/mpdf/ttfonts',
- __DIR__ . '/fonts',
- ),
- 'tempDir' => $this->get_temp_dir(),
- 'mode' => $mode,
- 'default_font_size' => 7,
- 'fontdata' => [
- "arial" => [
- 'R' => "Arial.ttf",
- 'B' => "ArialBold.ttf",
- 'I' => "ArialItalic.ttf",
- 'BI' => "ArialBoldItalic.ttf",
- ],
- "times" => [
- 'R' => "Times.ttf",
- 'B' => "TimesBold.ttf",
- 'I' => "TimesItalic.ttf",
- 'BI' => "TimesBoldItalic.ttf",
- ],
- "courier" => [
- 'R' => "CourierNew.ttf",
- 'B' => "CourierNewBold.ttf",
- 'I' => "CourierNewItalic.ttf",
- 'BI' => "CourierNewBoldItalic.ttf",
- ]
- ],
- 'default_font' => $default_font,
- 'margin_left' => $this->options['margin_left'],
- 'margin_right' => $this->options['margin_right'],
- 'margin_top' => $this->options['margin_top'],
- 'margin_bottom' => $this->options['margin_bottom'],
- 'margin_header' => $this->options['margin_header'],
- ];
- } else {
- $mpdf_init_options = [
- 'mode' => $mode,
- 'tempDir' => $this->get_temp_dir(),
- 'default_font_size' => 7,
- 'default_font' => $default_font,
- 'margin_left' => $this->options['margin_left'],
- 'margin_right' => $this->options['margin_right'],
- 'margin_top' => $this->options['margin_top'],
- 'margin_bottom' => $this->options['margin_bottom'],
- 'margin_header' => $this->options['margin_header'],
- ];
- }
- $mpdf_init_options['restrictColorSpace'] = $this->options['colorspace'];
- $mpdf_init_options = array_merge($mpdf_init_options, $page_type_settings);
- $mpdf_init_options = apply_filters("Bread_Mpdf_Init_Options", $mpdf_init_options, $this->options);
- @ob_end_clean();
- // We load mPDF only when we need to and as late as possible. This prevents
- // conflicts with other plugins that use the same PSRs in different versions
- // by simply clobbering the other definitions. Since we generate the PDF then
- // die, we shouldn't create any conflicts ourselves.
- require_once plugin_dir_path(__FILE__).'mpdf/vendor/autoload.php';
- $this->mpdf = new mPDF($mpdf_init_options);
- $this->mpdf->setAutoBottomMargin = 'pad';
- $this->mpdf->shrink_tables_to_fit = 1;
- // TODO: Adding a page number really could just be an option or tag.
- if ($this->options['page_fold'] == 'half' || $this->options['page_fold'] == 'full') {
- $this->mpdf->DefHTMLFooterByName('MyFooter', ''.$this->options['nonmeeting_footer'].'
');
- $this->mpdf->DefHTMLFooterByName('_default', ''.$this->options['nonmeeting_footer'].'
');
- $this->mpdf->DefHTMLFooterByName('Meeting1Footer', ''.$this->options['meeting1_footer'].'
');
- $this->mpdf->DefHTMLFooterByName('Meeting2Footer', ''.$this->options['meeting2_footer'].'
');
- }
-
- $this->mpdf->simpleTables = false;
- $this->mpdf->useSubstitutions = false;
- $this->mpdf->mirrorMargins = false;
- $this->mpdf->list_indent_first_level = 1; // 1 or 0 - whether to indent the first level of a list
- // LOAD a stylesheet
- $header_stylesheet = file_get_contents(plugin_dir_path(__FILE__).'css/mpdfstyletables.css');
- $this->mpdf->WriteHTML($header_stylesheet, 1); // The parameter 1 tells that this is css/style only and no body/html/text
- $this->mpdf->SetDefaultBodyCSS('line-height', $this->options['content_line_height']);
- $this->mpdf->SetDefaultBodyCSS('background-color', '#ffffff00');
- if ($this->options['column_line'] == 1 &&
- ($this->options['page_fold'] == 'tri' || $this->options['page_fold'] == 'quad')) {
- $html = '';
- if ($this->options['page_fold'] == 'tri') {
- $html .= '';
- }
- if ($this->options['page_fold'] == 'quad') {
- $html .= '';
- }
- $mpdf_column=new mPDF([
- 'mode' => $mode,
- 'tempDir' => $this->get_temp_dir(),
- 'format' => $mpdf_init_options['format'],
- 'default_font_size' => 7,
- 'default_font' => $default_font,
- 'margin_left' => $this->options['margin_left'],
- 'margin_right' => $this->options['margin_right'],
- 'margin_top' => $this->options['margin_top'],
- 'margin_bottom' => $this->options['margin_bottom'],
- 'margin_footer' => 0,
- 'orientation' => 'P',
- 'restrictColorSpace' => $this->options['colorspace'],
- ]);
-
- $mpdf_column->WriteHTML($html);
- $FilePath = $this->get_temp_dir(). DIRECTORY_SEPARATOR . $this->get_FilePath('_column');
- $mpdf_column->Output($FilePath, 'F');
- $h = \fopen($FilePath, 'rb');
- $stream = new \setasign\Fpdi\PdfParser\StreamReader($h, false);
- $import_streams[$FilePath] = $stream;
- $pagecount = $this->mpdf->SetSourceFile($stream);
- $tplId = $this->mpdf->importPage($pagecount);
- $this->mpdf->SetPageTemplate($tplId);
- }
-
- $this->section_shortcodes = array(
- '' => '',
- ' [page_break]
' => ' ',
- '[page_break]
' => ' ',
- '[page_break]' => ' ',
- '' => ' ',
- "[area]" => strtoupper($this->options['service_body_1']),
- '[new_column]
' => ' ',
- '[new_column]
' => ' ',
- '[new_column]' => ' ',
- '[page_break no_page_number]' => ' ',
- '[start_page_numbers]' => ' ',
- "[month_lower]" => date("F"),
- "[month_upper]" => strtoupper(date("F")),
- "[month]" => strtoupper(date("F")),
- "[day]" => strtoupper(date("j")),
- "[year]" => strtoupper(date("Y")),
- "[service_body]" => strtoupper($this->options['service_body_1']),
- "[service_body_1]" => strtoupper($this->options['service_body_1']),
- "[service_body_2]" => strtoupper($this->options['service_body_2']),
- "[service_body_3]" => strtoupper($this->options['service_body_3']),
- "[service_body_4]" => strtoupper($this->options['service_body_4']),
- "[service_body_5]" => strtoupper($this->options['service_body_5']),
-
- );
- $this->unique_areas = $this->get_areas();
- // Extensions
- $this->section_shortcodes = apply_filters("Bread_Section_Shortcodes", $this->section_shortcodes, $this->unique_areas, $this->formats_used);
-
- if (isset($this->options['pageheader_content'])) {
- $data = $this->options['pageheader_content'];
- $this->standard_shortcode_replacement($data, 'pageheader');
- $header_style = "vertical-align: top; text-align: center; font-weight: bold;margin-top:3px;margin-bottom:3px;";
- $header_style .= "color:".$this->options['pageheader_textcolor'].";";
- $header_style .= "background-color:".$this->options['pageheader_backgroundcolor'].";";
- $header_style .= "font-size:".$this->options['pageheader_fontsize']."pt;";
- $header_style .= "line-height:".$this->options['content_line_height'].";";
-
- $this->mpdf->SetHTMLHeader(
- ''.$data.'
',
- 'O'
- );
- }
- if (isset($this->options['watermark'])) {
- $this->mpdf->SetWatermarkImage($this->options['watermark'], 0.2, 'F');
- $this->mpdf->showWatermarkImage = true;
- }
- $sort_keys = 'weekday_tinyint,start_time,meeting_name';
- $get_used_formats = '&get_used_formats';
- $select_language = '';
- if ($this->options['weekday_language'] != $this->lang) {
- $select_language = '&lang_enum='.$this->getSingleLanguage($this->options['weekday_language']);
- }
- if ($this->options['used_format_1'] == '') {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults$services&sort_keys=$sort_keys$get_used_formats$select_language");
- } elseif ($this->options['used_format_1'] != '') {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults$services&sort_keys=$sort_keys&get_used_formats&formats[]=".$this->options['used_format_1'].$select_language);
- }
-
- $result = json_decode(wp_remote_retrieve_body($results), true);
- if (!empty($this->options['extra_meetings'])) {
- $extras = "";
- foreach ((array)$this->options['extra_meetings'] as $value) {
- $data = array(" [", "]");
- $value = str_replace($data, "", $value);
- $extras .= "&meeting_ids[]=".$value;
- }
-
- $extra_results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults&sort_keys=".$sort_keys."".$extras."".$get_used_formats.$select_language);
- $extra_result = json_decode(wp_remote_retrieve_body($extra_results), true);
- if ($extra_result <> null) {
- $result_meetings = array_merge($result['meetings'], $extra_result['meetings']);
- foreach ($result_meetings as $key => $row) {
- $weekday[$key] = $row['weekday_tinyint'];
- $start_time[$key] = $row['start_time'];
- }
-
- array_multisort($weekday, SORT_ASC, $start_time, SORT_ASC, $result_meetings);
- $this->formats_used = array_merge($result['formats'], $extra_result['formats']);
- } else {
- $this->formats_used = $result['formats'];
- $result_meetings = $result['meetings'];
- }
- } else {
- $this->formats_used = $result['formats'];
- $result_meetings = $result['meetings'];
- }
-
- if ($result_meetings == null) {
- echo "";
- echo 'No Meetings Found
Or
Internet or Server Problem
'.$this->options['root_server'].'
Please try again or contact your BMLT Administrator
';
- exit;
- }
- $this->adjust_timezone($result_meetings, $this->target_timezone);
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetFormats$select_language");
- $this->formats_all = json_decode(wp_remote_retrieve_body($results), true);
- if ($this->options['asm_language']=='') {
- $this->options['asm_language'] = $this->options['weekday_language'];
- }
- $this->formats_by_key[$this->options['weekday_language']] = array();
- foreach ($this->formats_all as $thisFormat) {
- $this->formats_by_key[$this->options['weekday_language']][$thisFormat['key_string']] = $thisFormat;
- if ($thisFormat['world_id'] == 'WCHR') {
- $this->wheelchair_format = $thisFormat;
- }
- }
- if (isset($this->options['asm_format_key']) && strlen($this->options['asm_format_key'])>0) {
- if ($this->options['weekday_language'] != $this->options['asm_language']) {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetFormats&lang_enum=".$this->getSingleLanguage($this->options['asm_language']));
- $formats_all = json_decode(wp_remote_retrieve_body($results), true);
- $this->sortBySubkey($formats_all, 'key_string');
- $this->formats_by_key[$this->options['asm_language']] = array();
- foreach ($formats_all as $thisFormat) {
- $this->formats_by_key[$this->options['asm_language']][$thisFormat['key_string']] = $thisFormat;
- if ($thisFormat['key_string']==$this->options['asm_format_key']) {
- $this->options['asm_format_id'] = $thisFormat['id'];
- }
- }
- } elseif (substr($this->options['asm_format_key'], 0, 1)!='@') {
- if (isset($this->formats_by_key[$this->options['weekday_language']][$this->options['asm_format_key']])) {
- $this->options['asm_format_id'] = $this->formats_by_key[$this->options['weekday_language']][$this->options['asm_format_key']]['id'];
- }
- }
- }
- if (strpos($this->options['custom_section_content'].$this->options['front_page_content'].$this->options['last_page_content'], '[format_codes_used_basic_es') !== false) {
- if ($this->options['used_format_1'] == '') {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults$services&sort_keys=time$get_used_formats&lang_enum=es");
- } else {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults$services&sort_keys=time&get_used_formats&lang_enum=es&formats[]=".$this->options['used_format_1']);
- }
- $result_es = json_decode(wp_remote_retrieve_body($results), true);
- $this->formats_spanish = $result_es['formats'];
- $this->sortBySubkey($this->formats_spanish, 'key_string');
- }
- if (strpos($this->options['custom_section_content'].$this->options['front_page_content'].$this->options['last_page_content'], '[format_codes_used_basic_fr') !== false) {
- if ($this->options['used_format_1'] == '') {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults$services&sort_keys=time$get_used_formats&lang_enum=fr");
- } else {
- $results = $this->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults$services&sort_keys=time&get_used_formats&lang_enum=fr&formats[]=".$this->options['used_format_1']);
- }
- $result_fr = json_decode(wp_remote_retrieve_body($results), true);
- $this->formats_french = $result_fr['formats'];
- $this->sortBySubkey($this->formats_french, 'key_string');
- }
-
- if ($this->options['include_asm'] === '0') {
- $countmax = count($this->formats_used);
- for ($count = 0; $count < $countmax; $count++) {
- if ($this->formats_used[$count]['key_string'] == $this->options['asm_format_key']) {
- unset($this->formats_used[$count]);
- }
- }
- $this->formats_used = array_values($this->formats_used);
- }
- $this->sortBySubkey($this->formats_used, 'key_string');
- $this->sortBySubkey($this->formats_all, 'key_string');
-
- $this->meeting_count = count($result_meetings);
-
- $result_meetings = $this->orderByWeekdayStart($result_meetings);
- if ($this->options['page_fold'] === 'full' || $this->options['page_fold'] === 'half' || $this->options['page_fold'] === 'flyer') {
- $num_columns = 0;
- } elseif ($this->options['page_fold'] === 'tri') {
- $num_columns = 3;
- } elseif ($this->options['page_fold'] === 'quad') {
- $num_columns = 4;
- } elseif ($this->options['page_fold'] === '') {
- $this->options['page_fold'] = 'quad';
- $num_columns = 4;
- }
-
- $this->mpdf->SetColumns($num_columns, '', $this->options['column_gap']);
- if ($this->options['page_fold'] == 'half' || $this->options['page_fold'] == 'full') {
- $this->write_front_page();
- }
- $this->mpdf->WriteHTML('td{font-size: '.$this->options['content_font_size']."pt;line-height:".$this->options['content_line_height'].';background-color:#ffffff00;}', 1);
- $this->mpdf->SetDefaultBodyCSS('font-size', $this->options['content_font_size'] . 'pt');
- $this->mpdf->SetDefaultBodyCSS('line-height', $this->options['content_line_height']);
- $this->mpdf->SetDefaultBodyCSS('background-color', '#ffffff00');
- $this->upgradeHeaderData();
- if ($this->options['page_fold'] == 'half' || $this->options['page_fold'] == 'full') {
- $this->WriteHTML(' ');
- }
- $this->writeMeetings($result_meetings, $this->options['meeting_template_content'], $this->options['weekday_language'], $this->options['include_asm']==0 ? -1 : 0, true);
-
- if ($this->options['page_fold'] !== 'half' && $this->options['page_fold'] !== 'full') {
- $this->write_custom_section();
- $this->write_front_page();
- } else {
- $this->WriteHTML(' ');
- if (trim($this->options['last_page_content']) !== '') {
- $this->write_last_page();
- }
- }
- $this->mpdf->SetDisplayMode('fullpage', 'two');
- if ($this->options['page_fold'] == 'half') {
- $FilePath = $this->get_temp_dir(). DIRECTORY_SEPARATOR . $this->get_FilePath('_half');
- $this->mpdf->Output($FilePath, 'F');
- $mpdfOptions = [
- 'mode' => $mode,
- 'tempDir' => $this->get_temp_dir(),
- 'default_font_size' => '',
- 'margin_left' => 0,
- 'margin_right' => 0,
- 'margin_top' => 0,
- 'margin_bottom' => 0,
- 'margin_footer' => 0,
- 'orientation' => 'L',
- 'restrictColorSpace' => $this->options['colorspace'],
- ];
- $ps = $this->options['page_size'];
- if ($ps=='ledger') {
- $mpdfOptions['format'] = 'tabloid';
- } elseif ($ps == '5inch') {
- $mpdfOptions['format'] = array(197.2,279.4);
- } else {
- $mpdfOptions['format'] = $ps.'-L';
- }
- $mpdfOptions['curlUserAgent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0';
- $mpdfOptions = apply_filters("Bread_Mpdf_Init_Options", $mpdfOptions, $this->options);
- $mpdftmp=new mPDF($mpdfOptions);
- $this->mpdf->shrink_tables_to_fit = 1;
- $ow = $mpdftmp->h;
- $oh = $mpdftmp->w;
- $pw = $mpdftmp->w / 2;
- $ph = $mpdftmp->h;
- $h = \fopen($FilePath, 'rb');
- $stream = new \setasign\Fpdi\PdfParser\StreamReader($h, false);
- $import_streams[$FilePath] = $stream;
- $pagecount = $mpdftmp->SetSourceFile($stream);
- $pp = $this->get_booklet_pages($pagecount);
- foreach ($pp as $v) {
- $mpdftmp->AddPage();
- if ($v[0]>0 & $v[0]<=$pagecount) {
- $tplIdx = $mpdftmp->importPage($v[0]);
- $mpdftmp->UseTemplate($tplIdx, 0, 0, $pw, $ph);
- }
- if ($v[1]>0 & $v[1]<=$pagecount) {
- $tplIdx = $mpdftmp->importPage($v[1]);
- $mpdftmp->UseTemplate($tplIdx, $pw, 0, $pw, $ph);
- }
- }
- $this->mpdf = $mpdftmp;
- } else if ($this->options['page_fold'] == 'full' && $this->options['booklet_pages']) {
- $FilePath = $this->get_temp_dir(). DIRECTORY_SEPARATOR . $this->get_FilePath('_full');
- $this->mpdf->Output($FilePath, 'F');
- $mpdfOptions = [
- 'mode' => $mode,
- 'tempDir' => $this->get_temp_dir(),
- 'default_font_size' => '',
- 'margin_left' => 0,
- 'margin_right' => 0,
- 'margin_top' => 0,
- 'margin_bottom' => 0,
- 'margin_footer' => 6,
- 'orientation' => $this->options['page_orientation'],
- 'restrictColorSpace' => $this->options['colorspace'],
- ];
- $mpdfOptions['format'] = $this->options['page_size']."-".$this->options['page_orientation'];
- /** this is because mPDF has an old UA and SiteGround is complaining
- * It will be fixed in the next release of mPDF, but we can't wait that long.
- * But, when a new mPDF comes out, remove this line.
- */
- $mpdf_config['curlUserAgent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0';
- /* */
- $mpdfOptions = apply_filters("Bread_Mpdf_Init_Options", $mpdfOptions, $this->options);
- $mpdftmp=new mPDF($mpdfOptions);
- $this->mpdf->shrink_tables_to_fit = 1;
- //$mpdftmp->SetImportUse();
- $h = \fopen($FilePath, 'rb');
- $stream = new \setasign\Fpdi\PdfParser\StreamReader($h, false);
- $import_streams[$FilePath] = $stream;
- $np = $mpdftmp->SetSourceFile($stream);
- $pp = 4*ceil($np/4);
- for ($i=1; $i<$np; $i++) {
- $mpdftmp->AddPage();
- $tplIdx = $mpdftmp->ImportPage($i);
- $mpdftmp->UseTemplate($tplIdx);
- }
- for ($i=$np; $i<$pp; $i++) {
- $mpdftmp->AddPage();
- }
- $mpdftmp->AddPage();
- $tplIdx = $mpdftmp->ImportPage($np);
- $mpdftmp->UseTemplate($tplIdx);
- $this->mpdf = $mpdftmp;
- } else if ($this->options['page_fold'] == 'flyer') {
- $FilePath = $this->get_temp_dir(). DIRECTORY_SEPARATOR . $this->get_FilePath('_flyer');
- $this->mpdf->Output($FilePath, 'F');
- $mpdfOptions = [
- 'mode' => $mode,
- 'tempDir' => $this->get_temp_dir(),
- 'default_font_size' => '',
- 'margin_left' => 0,
- 'margin_right' => 0,
- 'margin_top' => 0,
- 'margin_bottom' => 0,
- 'margin_footer' => 6,
- 'format' => $this->options['page_size'].'-L',
- 'orientation' => 'L',
- 'restrictColorSpace' => $this->options['colorspace'],
- ];
- $mpdftmp=new mPDF($mpdfOptions);
- $this->mpdf->shrink_tables_to_fit = 1;
- //$mpdftmp->SetImportUse();
- $h = \fopen($FilePath, 'rb');
- $stream = new \setasign\Fpdi\PdfParser\StreamReader($h, false);
- $import_streams[$FilePath] = $stream;
- $np = $mpdftmp->SetSourceFile($stream);
- $ow = $mpdftmp->w;
- $oh = $mpdftmp->h;
- $fw = $ow / 3;
- $mpdftmp->AddPage();
- $tplIdx = $mpdftmp->importPage(1);
- $mpdftmp->UseTemplate($tplIdx, 0, 0);
- $mpdftmp->UseTemplate($tplIdx, $fw, 0);
- $mpdftmp->UseTemplate($tplIdx, $fw+$fw, 0);
- $sep = $this->columnSeparators($oh);
- if (!empty($sep)) {
- $mpdftmp->writeHTML($sep);
- }
- $mpdftmp->AddPage();
- $tplIdx = $mpdftmp->ImportPage(2);
- $mpdftmp->UseTemplate($tplIdx, 0, 0);
- $mpdftmp->UseTemplate($tplIdx, $fw, 0);
- $mpdftmp->UseTemplate($tplIdx, $fw+$fw, 0);
- if (!empty($sep)) {
- $mpdftmp->writeHTML($sep);
- }
- $this->mpdf = $mpdftmp;
- }
- if ($this->options['include_protection'] == 1) {
- // 'copy','print','modify','annot-forms','fill-forms','extract','assemble','print-highres'
- $this->mpdf->SetProtection(array('copy','print','print-highres'), '', $this->options['protection_password']);
- }
- if (headers_sent()) {
- echo 'Headers already sent before PDF generation
';
- } else {
- if (intval($this->options['cache_time']) > 0 && ! isset($_GET['nocache'])
- && !isset($_GET['custom_query'])) {
- $content = $this->mpdf->Output('', 'S');
- $content = bin2hex($content);
- $transient_key = $this->get_TransientKey();
- set_transient($transient_key, $content, intval($this->options['cache_time']) * HOUR_IN_SECONDS);
- }
- $FilePath = apply_filters("Bread_Download_Name", $this->get_FilePath(), $this->options['service_body_1'], $this->allSettings[$this->loaded_setting]);
- $this->mpdf->Output($FilePath, 'I');
- }
- foreach ($import_streams as $FilePath => $stream) {
- @unlink($FilePath);
- }
- $this->rrmdir($this->get_temp_dir());
- exit;
- }
- function rrmdir($dir)
- {
- if (is_dir($dir)) {
- $objects = scandir($dir);
- foreach ($objects as $object) {
- if ($object != "." && $object != "..") {
- if (is_dir($dir. DIRECTORY_SEPARATOR .$object) && !is_link($dir."/".$object)) {
- $this->rrmdir($dir. DIRECTORY_SEPARATOR .$object);
- } else {
- @unlink($dir. DIRECTORY_SEPARATOR .$object);
- }
- }
- }
- @rmdir($dir);
- }
- }
- function brute_force_cleanup($dir)
- {
- if (is_dir($dir)) {
- $objects = scandir($dir);
- foreach ($objects as $object) {
- if ($object != "." && $object != "..") {
- if (str_starts_with($object, "bread")) {
- $filename = $dir . DIRECTORY_SEPARATOR .$object;
- if (time()-filemtime($filename) > 24 * 3600) {
- $this->rrmdir($filename);
- }
- }
- }
- }
- }
- }
- function orderByWeekdayStart(&$result_meetings)
- {
- $days = array_column($result_meetings, 'weekday_tinyint');
- $today_str = $this->options['weekday_start'];
- return array_merge(
- array_splice($result_meetings, array_search($today_str, $days)),
- array_splice($result_meetings, 0)
- );
- }
- function get_FilePath($pos = '')
- {
- $site = '';
- if (is_multisite()) {
- $site = get_current_blog_id().'_';
- }
- return "meetinglist_".$site.$this->loaded_setting.$pos.'_'.strtolower(date("njYghis")).".pdf";
- }
- function adjust_timezone(&$meetings, $target_timezone)
- {
- if (!$target_timezone) {
- return;
- }
- $target_midnight = new DateTime();
- $target_midnight->setTimezone($target_timezone);
- $target_midnight->setTime(23, 59);
- $target_yesterday = new DateTime();
- $target_yesterday->setTimezone($target_timezone);
- $target_yesterday->setTime(0, 0);
- foreach ($meetings as &$meeting) {
- if (!empty($meeting['time_zone'])) {
- $meeting_time_zone = timezone_open($meeting['time_zone']);
- if ($meeting_time_zone) {
- $date = date_create($meeting['start_time'], $meeting_time_zone);
- date_timezone_set($date, $target_timezone);
- $meeting['start_time'] = $date->format('H:i');
- if ($date >= $target_midnight) {
- $meeting['weekday_tinyint'] = $meeting['weekday_tinyint']+1;
- if ($meeting['weekday_tinyint']==8) {
- $meeting['weekday_tinyint'] = 1;
- }
- } elseif ($date < $target_yesterday) {
- $meeting['weekday_tinyint'] = $meeting['weekday_tinyint']-1;
- if ($meeting['weekday_tinyint']==0) {
- $meeting['weekday_tinyint'] = 7;
- }
- }
- }
- }
- }
- usort($meetings, array($this, "sortDayTime"));
- }
- function sortDayTime($a, $b)
- {
- if ($a['weekday_tinyint'] < $b['weekday_tinyint']) {
- return -1;
- }
- if ($a['weekday_tinyint'] > $b['weekday_tinyint']) {
- return 1;
- }
- if ($a['start_time'] < $b['start_time']) {
- return -1;
- }
- if ($a['start_time'] > $b['start_time']) {
- return 1;
- }
- if ($a['duration_time'] < $b['duration_time']) {
- return -1;
- }
- if ($a['duration_time'] > $b['duration_time']) {
- return 1;
- }
- return 0;
- }
- // include_asm = 0 - let everything through
- // 1 - only meetings with asm format
- // -1 - only meetings without asm format
- function writeMeetings($result_meetings, $template, $lang, $include_asm, $asm_flag)
- {
- $headerMeetings = $this->getHeaderMeetings($result_meetings, $lang, $include_asm, $asm_flag);
- $unique_heading = $this->getUniqueHeadings($headerMeetings);
-
- $header_style = "color:".$this->options['header_text_color'].";";
- $header_style .= "background-color:".$this->options['header_background_color'].";";
- $header_style .= "font-size:".$this->options['header_font_size']."pt;";
- $header_style .= "line-height:".$this->options['content_line_height'].";";
- $header_style .= "text-align:center;padding-top:2px;padding-bottom:3px;";
-
- if ($this->options['header_uppercase'] == 1) {
- $header_style .= 'text-transform: uppercase;';
- }
- if ($this->options['header_bold'] == 0) {
- $header_style .= 'font-weight: normal;';
- }
- if ($this->options['header_bold'] == 1) {
- $header_style .= 'font-weight: bold;';
- }
- $cont = '('.$this->translate[$lang]['CONT'].')';
-
-
- $template = wpautop(stripslashes($template));
- $template = preg_replace('/[[:^print:]]/', ' ', $template);
-
- $template = str_replace(" ", " ", $template);
- $analysedTemplate = $this->analyseTemplate($template);
- $first_meeting = true;
- $newMajorHeading = false;
- /***
- * You might be wondering why I am not using keep-with-table...
- * The problem is, keep with table doesn't work with columns, only pages.
- * We want to check that a header and at least one meeting fits, so we write it
- * to a test PDF, see how big it is, and check if it will fit.
- */
- $test_pages = deep_copy($this->mpdf);
- foreach ($unique_heading as $this_heading_raw) {
- $newMajorHeading = true;
- if ($this->skip_heading($this_heading_raw)) {
- continue;
- }
- $this_heading = $this->remove_sort_key($this_heading_raw);
- $unique_subheading = array_keys($headerMeetings[$this_heading_raw]);
- asort($unique_subheading, SORT_NATURAL | SORT_FLAG_CASE);
- foreach ($unique_subheading as $this_subheading_raw) {
- $newSubHeading = true;
- $this_subheading = $this->remove_sort_key($this_subheading_raw);
- foreach ($headerMeetings[$this_heading_raw][$this_subheading_raw] as $meeting_value) {
- $header = '';
- if ($newSubHeading && !empty($this->options['combine_headings'])) {
- $header_string = $this->options['combine_headings'];
- $header_string = str_replace('main_grouping', $this_heading, $header_string);
- $header_string = str_replace('subgrouping', $this_subheading, $header_string);
- $header .= "".$header_string."
";
- } elseif (!empty($this->options['subgrouping'])) {
- if ($newMajorHeading === true) {
- $xtraMargin = '';
- if (!$first_meeting) {
- $xtraMargin = 'margin-top:2pt;';
- }
- $header .= ''.$this_heading."
";
- }
- if ($newSubHeading && $this->options['sub_header_shown']=='display') {
- $header .= "".$this_subheading."
";
- }
- } elseif ($newMajorHeading === true) {
- $header .= "".$this_heading."
";
- }
- if ($this->options['suppress_heading']==1) {
- $header = '';
- }
- $data = $header . $this->write_single_meeting(
- $meeting_value,
- $template,
- $analysedTemplate,
- $meeting_value['area_name']
- );
- $this->writeBreak($test_pages);
- $y_startpos = $test_pages->y;
- @$test_pages->WriteHTML($data);
- $y_diff = $test_pages->y - $y_startpos;
- if ($y_diff >= $this->mpdf->h - ($this->mpdf->y + $this->mpdf->bMargin + 5) - $this->mpdf->kwt_height) {
- $this->writeBreak($this->mpdf);
- if (!$newMajorHeading && $this->options['cont_header_shown']) {
- $header = "".$this_heading." " . $cont . "
";
- $data = $header.$data;
- }
- }
- $this->WriteHTML($data);
- $first_meeting = false;
- $newSubHeading = false;
- $newMajorHeading = false;
- }
- }
- }
- }
- function asm_test($value, $flag = false)
- {
- if (empty($this->options['asm_format_key'])) {
- return false;
- }
- $format_key = $this->options['asm_format_key'];
- if ($format_key == "@Virtual@") {
- if ($flag && $this->isHybrid($value)) {
- return false;
- }
- return $this->isVirtual($value) || $this->isHybrid($value);
- }
- if ($format_key == "@F2F@") {
- return !$this->isVirtual($value) || $this->isHybrid($value);
- }
- $enFormats = explode(",", $value['formats']);
- return in_array($format_key, $enFormats);
- }
- function isHybrid($value)
- {
- $enFormats = explode(",", $value['formats']);
- return in_array('HY', $enFormats);
- }
- function isVirtual($value)
- {
- $enFormats = explode(",", $value['formats']);
- return in_array('VM', $enFormats);
- }
- // include_asm = 0 - let everything through
- // 1 - only meetings with asm format
- // -1 - only meetings without asm format
- function getHeaderMeetings(&$result_meetings, $lang, $include_asm, $asm_flag)
- {
- $levels = $this->getHeaderLevels();
- $headerMeetings = array();
- foreach ($result_meetings as &$value) {
- $value = $this->enhance_meeting($value, $lang);
- $asm_test = $this->asm_test($value, $asm_flag);
- if ((( $include_asm < 0 && $asm_test ) ||
- ( $include_asm > 0 && !$asm_test ))) {
- continue;
- }
-
- $main_grouping = $this->getHeaderItem($value, 'main_grouping');
- if (!isset($headerMeetings[$main_grouping])) {
- $headerMeetings[$main_grouping] = array();
- if ($levels == 1) {
- $headerMeetings[$main_grouping][0] = array();
- }
- }
- if ($levels == 2) {
- $subgrouping = $this->getHeaderItem($value, 'subgrouping');
- if (!isset($headerMeetings[$main_grouping][$subgrouping])) {
- $headerMeetings[$main_grouping][$subgrouping] = array();
- }
- $headerMeetings[$main_grouping][$subgrouping][] = $value;
- } else {
- $headerMeetings[$main_grouping][0][] = $value;
- }
- }
- return $headerMeetings;
- }
- function getUniqueHeadings($headerMeetings)
- {
- $unique_heading = array_keys($headerMeetings);
- asort($unique_heading, SORT_NATURAL | SORT_FLAG_CASE);
- return $unique_heading;
- }
- function remove_sort_key($this_heading)
- {
- if (mb_substr($this_heading, 0, 1)=='[') {
- $end = strpos($this_heading, ']');
- if ($end>0) {
- return trim(substr($this_heading, $end+1));
- }
- }
- return $this_heading;
- }
- function skip_heading($this_heading)
- {
- return (mb_substr($this_heading, 0, 5)=='[XXX]');
- }
- function writeBreak($mpdf)
- {
- if ($this->options['page_fold'] === 'half' || $this->options['page_fold'] === 'full') {
- $mpdf->WriteHTML("");
- } else {
- $mpdf->WriteHTML(" ");
- }
- }
- function getOptionForDisplay($option, $default = '')
- {
- return empty($this->options[$option])?$default:esc_html($this->options[$option]);
- }
- function columnSeparators($oh)
- {
- if ($this->options['column_line'] == 1) {
- return '
- ';
- }
- }
- function getHeaderLevels()
- {
- if (!empty($this->options['subgrouping'])) {
- return 2;
- }
- return 1;
- }
- function getHeaderItem($value, $name)
- {
- if (empty($this->options[$name])) {
- return '';
- }
- $grouping = '';
- if ($this->options[$name]=='service_body_bigint') {
- foreach ($this->unique_areas as $unique_area) {
- $area_data = explode(',', $unique_area);
- $area_name = $this->arraySafeGet($area_data);
- $area_id = $this->arraySafeGet($area_data, 1);
- if ($area_id === $value['service_body_bigint']) {
- return $area_name;
- }
- }
- return 'Area not found';
- } elseif ($this->options[$name]=='day') {
- $off = intval($this->options['weekday_start']);
- $day = intval($value['weekday_tinyint']);
- if ($day < $off) {
- $day = $day + 7;
- }
- return '['.str_pad($day, 2, '0', STR_PAD_LEFT).']'.$value['day'];
- } elseif (isset($value[$this->options[$name]])) {
- $grouping = $this->parse_field($value[$this->options[$name]]);
- }
- $alt = '';
- if ($grouping==''
- && !empty($this->options[$name.'_alt'])
- && isset($value[$this->options[$name.'_alt']])) {
- $grouping = $this->parse_field($value[$this->options[$name.'_alt']]);
- $alt = '_alt';
- }
- if (strlen(trim($grouping))==0) {
- return 'NO DATA';
- }
- if (!empty($this->options[$name.$alt.'_suffix'])) {
- return $grouping.' '.$this->options[$name.$alt.'_suffix'];
- }
- return $grouping;
- }
- function upgradeHeaderData()
- {
- $this->options['combine_headings'] = '';
- if ($this->options['meeting_sort'] === 'user_defined') {
- if ($this->options['sub_header_shown'] == 'combined') {
- $this->options['combine_headings'] = 'main_grouping - subgrouping';
- }
- return;
- }
- unset($this->options['subgrouping']);
- if ($this->options['meeting_sort'] === 'state') {
- $this->options['main_grouping'] = 'location_province';
- $this->options['subgrouping'] = 'location_municipality';
- $this->options['combine_headings'] = 'subgrouping, main_grouping';
- } elseif ($this->options['meeting_sort'] === 'city') {
- $this->options['main_grouping'] = 'location_municipality';
- } elseif ($this->options['meeting_sort'] === 'borough') {
- $this->options['main_grouping'] = 'location_city_subsection';
- $this->options['main_grouping_suffix'] = $this->options['borough_suffix'];
- } elseif ($this->options['meeting_sort'] === 'county') {
- $this->options['main_grouping'] = 'location_sub_province';
- $this->options['main_grouping_alt_suffix'] = $this->options['county_suffix'];
- } elseif ($this->options['meeting_sort'] === 'borough_county') {
- $this->options['main_grouping'] = 'location_city_subsection';
- $this->options['main_grouping_suffix'] = $this->options['borough_suffix'];
- $this->options['main_grouping_alt'] = 'location_sub_province';
- $this->options['main_grouping_alt_suffix'] = $this->options['county_suffix'];
- } elseif ($this->options['meeting_sort'] === 'neighborhood_city') {
- $this->options['main_grouping'] = 'location_neighborhood';
- $this->options['main_grouping_suffix'] = $this->options['neighborhood_suffix'];
- $this->options['main_grouping_alt'] = 'location_municipality';
- $this->options['main_grouping_alt_suffix'] = $this->options['city_suffix'];
- } elseif ($this->options['meeting_sort'] === 'group') {
- $this->options['main_grouping'] = 'meeting_name';
- } elseif ($this->options['meeting_sort'] === 'weekday_area') {
- $this->options['main_grouping'] = 'day';
- $this->options['subgrouping'] = 'service_body_bigint';
- } elseif ($this->options['meeting_sort'] === 'weekday_city') {
- $this->options['main_grouping'] = 'day';
- $this->options['subgrouping'] = 'location_municipality';
- } elseif ($this->options['meeting_sort'] === 'weekday_county') {
- $this->options['main_grouping'] = 'day';
- $this->options['subgrouping'] = 'location_sub_province';
- } else {
- $this->options['main_grouping'] = 'day';
- }
- }
- function get_area_name($meeting_value)
- {
- foreach ($this->unique_areas as $unique_area) {
- $area_data = explode(',', $unique_area);
- $area_id = $this->arraySafeGet($area_data, 1);
- if ($area_id === $meeting_value['service_body_bigint']) {
- return $this->arraySafeGet($area_data);
- }
- }
- return '';
- }
- function analyseTemplate($template)
- {
- $arr = preg_split('/\W+/', $template, 0, PREG_SPLIT_OFFSET_CAPTURE);
- $arr = array_reverse($arr, true);
- $ret = array();
- foreach ($arr as $item) {
- if (strlen($item[0])<3) {
- continue;
- }
- if ($item[0]=='table') {
- continue;
- }
- if ($item[0]=='tbody') {
- continue;
- }
- if ($item[0]=='strong') {
- continue;
- }
- if ($item[0]=='left') {
- continue;
- }
- if ($item[0]=='right') {
- continue;
- }
- if ($item[0]=='top') {
- continue;
- }
- if ($item[0]=='bottom') {
- continue;
- }
- if ($item[0]=='center') {
- continue;
- }
- if ($item[0]=='align') {
- continue;
- }
- if ($item[0]=='font') {
- continue;
- }
- if ($item[0]=='size') {
- continue;
- }
- if ($item[0]=='text') {
- continue;
- }
- if ($item[0]=='style') {
- continue;
- }
- if ($item[0]=='family') {
- continue;
- }
- if ($item[0]=='vertical') {
- continue;
- }
- if ($item[0]=='color') {
- continue;
- }
- if ($item[0]=='QRCode') {
- continue;
- }
- if ($item[1]>0 && $template[$item[1]-1]=='['
- && $template[$item[1]+strlen($item[0])]==']') {
- $item[0] = '['.$item[0].']';
- $item[1] = $item[1] - 1;
- $item[2] = true;
- } else {
- $item[2] = false;
- }
- $ret[] = $item;
- }
- return $ret;
- }
- function enhance_meeting(&$meeting_value, $lang)
- {
- $duration = explode(':', $meeting_value['duration_time']);
- $minutes = intval($duration[0])*60 + intval($duration[1]) + intval($duration[2]);
- $meeting_value['duration_m'] = $minutes;
- $meeting_value['duration_h'] = rtrim(rtrim(number_format($minutes/60, 2), 0), '.');
- $space = ' ';
- if ($this->options['remove_space'] == 1) {
- $space = '';
- }
- if ($this->options['time_clock'] == null || $this->options['time_clock'] == '12' || $this->options['time_option'] == '') {
- $time_format = "g:i".$space."A";
- } elseif ($this->options['time_clock'] == '24fr') {
- $time_format = "H\hi";
- } else {
- $time_format = "H:i";
- }
- if ($this->options['time_option'] == 1 || $this->options['time_option'] == '') {
- $meeting_value['start_time'] = date($time_format, strtotime($meeting_value['start_time']));
- if ($meeting_value['start_time'] == '12:00PM' || $meeting_value['start_time'] == '12:00 PM') {
- $meeting_value['start_time'] = 'NOON';
- }
- } elseif ($this->options['time_option'] == '2') {
- $addtime = '+ ' . $minutes . ' minutes';
- $end_time = date($time_format, strtotime($meeting_value['start_time'] . ' ' . $addtime));
- $meeting_value['start_time'] = date($time_format, strtotime($meeting_value['start_time']));
- if ($lang=='fa') {
- $meeting_value['start_time'] = $this->toPersianNum($end_time).$space.'-'.$space.$this->toPersianNum($meeting_value['start_time']);
- } else {
- $meeting_value['start_time'] = $meeting_value['start_time'].$space.'-'.$space.$end_time;
- }
- } elseif ($this->options['time_option'] == '3') {
- $time_array = array("1:00", "2:00", "3:00", "4:00", "5:00", "6:00", "7:00", "8:00", "9:00", "10:00", "11:00", "12:00");
- $temp_start_time = date("g:i", strtotime($meeting_value['start_time']));
- $temp_start_time_2 = date("g:iA", strtotime($meeting_value['start_time']));
- if ($temp_start_time_2 == '12:00PM') {
- $start_time = 'NOON';
- } elseif (in_array($temp_start_time, $time_array)) {
- $start_time = date("g", strtotime($meeting_value['start_time']));
- } else {
- $start_time = date("g:i", strtotime($meeting_value['start_time']));
- }
- $addtime = '+ ' . $minutes . ' minutes';
- $temp_end_time = date("g:iA", strtotime($meeting_value['start_time'] . ' ' . $addtime));
- $temp_end_time_2 = date("g:i", strtotime($meeting_value['start_time'] . ' ' . $addtime));
- if ($temp_end_time == '12:00PM') {
- $end_time = 'NOON';
- } elseif (in_array($temp_end_time_2, $time_array)) {
- $end_time = date("g".$space."A", strtotime($temp_end_time));
- } else {
- $end_time = date("g:i".$space."A", strtotime($temp_end_time));
- }
- $meeting_value['start_time'] = $start_time.$space.'-'.$space.$end_time;
- }
-
- $meeting_value['day_abbr'] = $this->getday($meeting_value['weekday_tinyint'], true, $lang);
- $meeting_value['day'] = $this->getday($meeting_value['weekday_tinyint'], false, $lang);
- $area_name = $this->get_area_name($meeting_value);
- $meeting_value['area_name'] = $area_name;
- $meeting_value['area_i'] = substr($area_name, 0, 1);
-
- $meeting_value['wheelchair'] = '';
- if (!is_null($this->wheelchair_format)) {
- $fmts = explode(',', $meeting_value['format_shared_id_list']);
- if (in_array($this->wheelchair_format['id'], $fmts)) {
- $meeting_value['wheelchair'] = ' ';
- }
- }
- // Extensions.
- return apply_filters("Bread_Enrich_Meeting_Data", $meeting_value, $this->formats_by_key[$lang]);
- }
- function write_single_meeting($meeting_value, $template, $analysedTemplate, $area_name)
- {
- $data = $template;
- $namedValues = array();
- foreach ($meeting_value as $field => $notUsed) {
- $namedValues[$field] = $this->get_field($meeting_value, $field);
- }
- foreach ($this->legacy_synonyms as $syn => $field) {
- $namedValues[$syn] = $namedValues[$field];
- }
- foreach ($analysedTemplate as $item) {
- $name = $item[0];
- if ($item[2]) {
- $name = substr($name, 1, strlen($name)-2);
- }
- if (isset($namedValues[$name])) {
- $data = substr_replace($data, $namedValues[$name], $item[1], strlen($item[0]));
- }
- }
- $qr_pos = strpos($data, "[QRCode");
- if ($qr_pos) {
- $qr_end = strpos($data, ']', $qr_pos);
- $data = substr($data, 0, $qr_pos).
- ' '.
- substr($data, $qr_end+1);
- }
- $search_strings = array();
- $replacements = array();
- $clean_up = array(
- ' ' => '',
- ' ' => '',
- ' ' => '',
- ' ' => '',
- ' ' => '',
- ' ' => '',
- ' ' => ' ',
- ' ' => ' ',
- ' ' => ' ',
- '
' => '',
- '()' => '',
- ' ' => 'line_break',
- ' ' => 'line_break',
- 'line_break line_break' => ' ',
- 'line_breakline_break' => ' ',
- 'line_break' => ' ',
- ' ,' => ' ',
- ', ' => ' ',
- ', ' => ' ',
- ',' => '
',
- ", , ," => ",",
- ", *," => ",",
- ", ," => ",",
- " , " => " ",
- ", (" => " (",
- ',' => '',
- ', ' => '',
- );
- foreach ($clean_up as $key => $value) {
- $search_strings[] = $key;
- $replacements[] = $value;
- }
- $data = str_replace($search_strings, $replacements, $data);
- return $data;
- }
- function get_booklet_pages($np, $backcover = true)
- {
- $lastpage = $np;
- $np = 4*ceil($np/4);
- $pp = array();
- for ($i=1; $i<=$np/2; $i++) {
- $p1 = $np - $i + 1;
- if ($backcover) {
- if ($i == 1) {
- $p1 = $lastpage;
- } else if ($p1 >= $lastpage) {
- $p1 = 0;
- }
- }
- if ($i % 2 == 1) {
- $pp[] = array( $p1, $i );
- } else {
- $pp[] = array( $i, $p1 );
- }
- }
- return $pp;
- }
-
- function write_front_page()
- {
-
- $this->mpdf->WriteHTML('td{font-size: '.$this->options['front_page_font_size']."pt;line-height:".$this->options['front_page_line_height'].';}', 1);
- $this->mpdf->SetDefaultBodyCSS('line-height', $this->options['front_page_line_height']);
- $this->mpdf->SetDefaultBodyCSS('font-size', $this->options['front_page_font_size'] . 'pt');
- $this->mpdf->SetDefaultBodyCSS('background-color', '#ffffff00');
- $this->options['front_page_content'] = wp_unslash($this->options['front_page_content']);
- $this->standard_shortcode_replacement($this->options['front_page_content'], 'front_page');
-
-
- $querystring_custom_items = array();
- preg_match_all('/(\[querystring_custom_\d+\])/', $this->options['front_page_content'], $querystring_custom_items);
- foreach ($querystring_custom_items[0] as $querystring_custom_item) {
- $mod_qs_ci = str_replace("]", "", str_replace("[", "", $querystring_custom_item));
- $this->options['front_page_content'] = str_replace($querystring_custom_item, (isset($_GET[$mod_qs_ci]) ? $_GET[$mod_qs_ci] : "NOT SET"), $this->options['front_page_content']);
- }
- $this->writeHTMLwithServiceMeetings($this->options['front_page_content'], 'front_page');
- $this->mpdf->showWatermarkImage = false;
- }
-
- function write_last_page()
- {
- $this->mpdf->WriteHTML('td{font-size: '.$this->options['last_page_font_size']."pt;line-height:".$this->options['last_page_line_height'].';}', 1);
- $this->mpdf->SetDefaultBodyCSS('font-size', $this->options['last_page_font_size'] . 'pt');
- $this->mpdf->SetDefaultBodyCSS('line-height', $this->options['last_page_line_height']);
- $this->mpdf->SetDefaultBodyCSS('background-color', '#ffffff00');
- $this->standard_shortcode_replacement($this->options['last_page_content'], 'last_page');
- $this->writeHTMLwithServiceMeetings($this->options['last_page_content'], 'last_page');
- }
-
- function write_custom_section()
- {
- $this->mpdf->SetHTMLHeader();
- if (isset($this->options['pageheader_content']) && trim($this->options['pageheader_content'])) {
- $this->mpdf->SetTopMargin($this->options['margin_header']);
- }
- $this->mpdf->SetDefaultBodyCSS('line-height', $this->options['custom_section_line_height']);
- $this->mpdf->SetDefaultBodyCSS('font-size', $this->options['custom_section_font_size'] . 'pt');
- $this->mpdf->SetDefaultBodyCSS('background-color', '#ffffff00');
- $this->standard_shortcode_replacement($this->options['custom_section_content'], 'custom_section');
- $this->mpdf->WriteHTML('td{font-size: '.$this->options['custom_section_font_size']."pt;line-height:".$this->options['custom_section_line_height'].';}', 1);
- $this->writeHTMLwithServiceMeetings($this->options['custom_section_content'], 'custom_section');
- }
- function locale_month_replacement($data, $case, $sym)
- {
- $strpos = strpos($data, "[month_$case"."_");
- if ($strpos !== false) {
- $locLang = substr($data, $strpos+13, 2);
- if (!isset($this->translate[$locLang])) {
- $locLang = 'en';
- }
- $fmt = new IntlDateFormatter(
- $this->translate[$locLang]['LOCALE'],
- IntlDateFormatter::FULL,
- IntlDateFormatter::FULL
- );
- $fmt->setPattern($sym);
- $month = ucfirst(mb_convert_encoding($fmt->format(time()), 'UTF-8', 'ISO-8859-1'));
- if ($case=='upper') {
- $month = mb_strtoupper($month, 'UTF-8');
- }
- return substr_replace($data, $month, $strpos, 16);
- }
- return $data;
- }
- function standard_shortcode_replacement(&$data, $page)
- {
- $search_strings = array();
- $replacements = array();
- foreach ($this->section_shortcodes as $key => $value) {
- $search_strings[] = $key;
- $replacements[] = $value;
- }
-
- $search_strings[] = '[meeting_count]';
- $replacements[] = $this->meeting_count;
- $data = $this->options[$page.'_content'];
- $data = $this->locale_month_replacement($data, 'lower', "LLLL");
- $data = $this->locale_month_replacement($data, 'upper', "LLLL");
- $data = str_replace($search_strings, $replacements, $data);
- $this->replace_format_shortcodes($data, $page);
- $data = str_replace("[date]", strtoupper(date("F Y")), $data);
- if ($this->target_timezone) {
- $data = str_replace('[timezone]', $this->target_timezone->getName(), $data);
- }
- }
- function writeHTML($str)
- {
- //$str = htmlentities($str);
- @$this->mpdf->WriteHTML(wpautop(stripslashes($str)));
- }
- function writeHTMLwithServiceMeetings($data, $page)
- {
- $strs = array('
[service_meetings]
','[service_meetings]',
- '[additional_meetings]
','[additional_meetings]');
-
- foreach ($strs as $str) {
- $pos = strpos($data, $str);
- if (!$pos) {
- continue;
- }
- if ($this->options['page_fold'] == 'half' || $this->options['page_fold'] == 'full') {
- $this->WriteHTML(' ');
- }
- $this->WriteHTML(substr($data, 0, $pos));
- $this->write_service_meetings($this->options[$page.'_font_size'], $this->options[$page.'_line_height']);
- if ($this->options['page_fold'] == 'half' || $this->options['page_fold'] == 'full') {
- $this->WriteHTML(' ');
- }
- $this->WriteHTML(substr($data, $pos+strlen($str)));
- return;
- }
- $this->WriteHTML($data);
- }
- function replace_format_shortcodes(&$data, $page_name)
- {
-
- $this->shortcode_formats('[format_codes_used_basic]', false, $this->formats_used, $page_name, $data);
- $this->shortcode_formats('[format_codes_used_detailed]', true, $this->formats_used, $page_name, $data);
- $this->shortcode_formats('[format_codes_used_basic_es]', false, $this->formats_spanish, $page_name, $data);
- $this->shortcode_formats('[format_codes_used_detailed_es]', true, $this->formats_spanish, $page_name, $data);
- $this->shortcode_formats('[format_codes_used_basic_fr]', false, $this->formats_french, $page_name, $data);
- $this->shortcode_formats('[format_codes_all_basic]', false, $this->formats_all, $page_name, $data);
- $this->shortcode_formats('[format_codes_all_detailed]', true, $this->formats_all, $page_name, $data);
- }
- function shortcode_formats($shortcode, $detailed, $formats, $page, &$str)
- {
- $pos = strpos($str, $shortcode);
- if ($pos==false) {
- return;
- }
- $value = '';
- if ($detailed) {
- $value = $this->write_detailed_formats($formats, $page);
- } else {
- $value = $this->write_formats($formats, $page);
- }
- $str = substr($str, 0, $pos).$value.substr($str, $pos+strlen($shortcode));
- }
- function write_formats($formats, $page)
- {
- if ($formats == null) {
- return '';
- }
- $this->mpdf->WriteHTML('td{font-size: '.$this->options[$page.'_font_size']."pt;line-height:".$this->options[$page.'_line_height'].';}', 1);
- $data = "options[$page.'_line_height'].";'>";
- for ($count = 0; $count < count($formats); $count++) {
- $data .= '';
- $data .= "".$formats[$count]['key_string']." ";
- $data .= "".$formats[$count]['name_string']." ";
- $count++;
- if ($count >= count($formats)) {
- $data .= " ";
- $data .= " ";
- } else {
- $data .= "".$formats[$count]['key_string']." ";
- $data .= "".$formats[$count]['name_string']." ";
- }
- $data .= " ";
- }
- $data .= "
";
- return $data;
- }
- function asm_required($data)
- {
- return strpos($data, '[service_meetings]') || strpos($data, '[additional_meetings]');
- }
- function write_detailed_formats($formats, $page)
- {
- if ($formats == null) {
- return '';
- }
- $this->mpdf->WriteHTML('td{font-size: '.$this->options[$page.'_font_size']."pt;line-height:".$this->options[$page.'_line_height'].';}', 1);
- $data = "options[$page.'_line_height'].";'>";
- for ($count = 0; $count < count($formats); $count++) {
- if (isset($this->options[$page.'_font_size']) && isset($this->options[$page . '_line_height'])) {
- $data .= "options[$page . '_line_height'] . ";font-weight:bold;'>" . $formats[$count]['key_string'] . " ";
- $data .= "options[$page . '_line_height'] . ";'>(" . $formats[$count]['name_string'] . ") " . $formats[$count]['description_string'] . " ";
- }
- }
- $data .= "
";
- return $data;
- }
- private function parse_field($text)
- {
- if ($text!='') {
- $exploded = explode("#@-@#", $text);
- $knt = count($exploded);
- if ($knt > 1) {
- $text = $exploded[$knt-1];
- }
- }
- return $text;
- }
- public function arraySafeGet($arr, $i = 0)
- {
- return is_array($arr) ? $arr[$i] ?? '': '';
- }
- function get_field($obj, $field)
- {
- $value = '';
- if (isset($obj[$field])) {
- $value = $this->parse_field($obj[$field]);
- }
- return $value;
- }
- function write_service_meetings($font_size, $line_height)
- {
- if ($this->service_meeting_result == null) {
- $sort_order = $this->options['asm_sort_order'];
- if ($sort_order=='same') {
- $sort_order = 'weekday_tinyint,start_time';
- }
- $asm_id = "";
- if (isset($this->options['asm_format_id'])) {
- $asm_id = '&formats[]='.$this->options['asm_format_id'];
- }
- $services = $this->services;
- if (!empty($this->options['asm_custom_query'])) {
- $services = $this->options['asm_custom_query'];
- }
- $asm_query = "client_interface/json/?switcher=GetSearchResults$services$asm_id&sort_keys=$sort_order";
- // I'm not sure we need this, but for now we need to emulate the old behavior
- if ($this->options['asm_format_key']==='ASM') {
- $asm_query .= "&advanced_published=0";
- }
- $results = $this->get_configured_root_server_request($asm_query);
- $this->service_meeting_result = json_decode(wp_remote_retrieve_body($results), true);
- if ($sort_order == 'weekday_tinyint,start_time') {
- $this->adjust_timezone($this->service_meeting_result, $this->target_timezone);
- $this->service_meeting_result = $this->orderByWeekdayStart($this->service_meeting_result);
- }
- }
- if ($this->options['asm_sort_order']=='same') {
- if (isset($this->options['asm_template_content']) && trim($this->options['asm_template_content'])) {
- $template = $this->options['asm_template_content'];
- } else {
- $template = $this->options['meeting_template_content'];
- }
- $this->writeMeetings($this->service_meeting_result, $template, $this->options['asm_language'], 1, false);
- return;
- }
- $temp = array();
- foreach ($this->service_meeting_result as $value) {
- $value = $this->enhance_meeting($value, $this->options['asm_language']);
- if ($this->asm_test($value, false)) {
- $temp[] = $value;
- }
- }
- $this->service_meeting_result = $temp;
- if (empty($temp)) {
- return;
- }
- $data = '';
- $template = '';
- if (isset($this->options['asm_template_content']) && trim($this->options['asm_template_content'])) {
- $template = $this->options['asm_template_content'];
- } else {
- $data .= "";
- }
- foreach ($this->service_meeting_result as $value) {
- $area_name = $this->get_area_name($value);
- if ($template != '') {
- $template = str_replace(" ", " ", $template);
- $data .= $this->write_single_meeting(
- $value,
- $template,
- $this->analyseTemplate($template),
- $area_name
- );
- continue;
- }
- $display_string = ''.$value['meeting_name'].' ';
- if (!strstr($value['comments'], 'Open Position')) {
- $display_string .= ' - ' . $value['start_time'] . ' ';
- }
-
- if (trim($value['location_text'])) {
- $display_string .= ' - '.trim($value['location_text']);
- }
- if (trim($value['location_street'])) {
- $display_string .= ' - ' . trim($value['location_street']);
- }
- if (trim($value['location_city_subsection'])) {
- $display_string .= ' ' . trim($value['location_city_subsection']);
- }
- if (trim($value['location_neighborhood'])) {
- $display_string .= ' ' . trim($value['location_neighborhood']);
- }
- if (trim($value['location_municipality'])) {
- $display_string .= ' '.trim($value['location_municipality']);
- }
- if (trim($value['location_province'])) {
- //$display_string .= ' '.trim ( $value['location_province'] );
- }
- if (trim($value['location_postal_code_1'])) {
- $display_string .= ' ' . trim($value['location_postal_code_1']);
- }
- if (trim($value['location_info'])) {
- $display_string .= " (".trim($value['location_info']).")";
- }
-
- if (isset($value['email_contact']) && $value['email_contact'] != '' && $this->options['include_meeting_email'] == 1) {
- $str = $this->parse_field($value['email_contact']);
- $value['email_contact'] = $str;
- $value['email_contact'] = ' ('.$value['email_contact'].' )';
- } else {
- $value['email_contact'] = '';
- }
- $display_string .= $value['email_contact'];
- $data .= "".$display_string." ";
- }
- if ($template == '') {
- $data .= "
";
- }
- $this->writeHTML($data);
- }
-
- /**
- * @desc Adds the options sub-panel
- */
- function admin_menu_link()
- {
- global $my_admin_page;
- Bread::add_cap();
- $my_admin_page = add_menu_page('Meeting List', 'Meeting List', 'manage_bread', basename(__FILE__), array(&$this, 'admin_options_page'), 'dashicons-admin-page');
- }
-
- function bmltrootserverurl_meta_box()
- {
- global $connect;
- ?>
- BMLT Server:
-
- BMLT Server Implementations
- getMLOptions($this->requested_setting);
- $this->lang = $this->get_bmlt_server_lang();
- ?>
-
-
-
- options['bread_version'] = sanitize_text_field($_POST['bread_version']);
- $this->options['front_page_content'] = wp_kses_post($_POST['front_page_content']);
- $this->options['last_page_content'] = wp_kses_post($_POST['last_page_content']);
- $this->options['front_page_line_height'] = $_POST['front_page_line_height'];
- $this->options['front_page_font_size'] = floatval($_POST['front_page_font_size']);
- $this->options['last_page_font_size'] = floatval($_POST['last_page_font_size']);
- $this->options['last_page_line_height'] = floatval($_POST['last_page_line_height']);
- $this->options['content_font_size'] = floatval($_POST['content_font_size']);
- $this->options['suppress_heading'] = floatval($_POST['suppress_heading']);
- $this->options['header_font_size'] = floatval($_POST['header_font_size']);
- $this->options['header_text_color'] = validate_hex_color($_POST['header_text_color']);
- $this->options['header_background_color'] = validate_hex_color($_POST['header_background_color']);
- $this->options['header_uppercase'] = intval($_POST['header_uppercase']);
- $this->options['header_bold'] = intval($_POST['header_bold']);
- $this->options['sub_header_shown'] = sanitize_text_field($_POST['sub_header_shown']);
- $this->options['cont_header_shown'] = intval($_POST['cont_header_shown']);
- $this->options['column_gap'] = isset($_POST['column_gap']) ?
- intval($_POST['column_gap']) : 5;
- $this->options['margin_right'] = intval($_POST['margin_right']);
- $this->options['margin_left'] = intval($_POST['margin_left']);
- $this->options['margin_bottom'] = intval($_POST['margin_bottom']);
- $this->options['margin_top'] = intval($_POST['margin_top']);
- $this->options['margin_header'] = intval($_POST['margin_header']);
- $this->options['margin_footer'] = isset($_POST['margin_footer']) ?
- intval($_POST['margin_footer']): 5;
- $this->options['pageheader_fontsize'] = floatval($_POST['pageheader_fontsize']);
- $this->options['pageheader_textcolor'] = validate_hex_color($_POST['pageheader_textcolor']);
- $this->options['pageheader_backgroundcolor'] = validate_hex_color($_POST['pageheader_backgroundcolor']);
- $this->options['pageheader_content'] = wp_kses_post($_POST['pageheader_content']);
- $this->options['watermark'] = sanitize_text_field($_POST['watermark']);
- $this->options['page_size'] = sanitize_text_field($_POST['page_size']);
- $this->options['page_orientation'] = validate_page_orientation($_POST['page_orientation']);
- $this->options['page_fold'] = sanitize_text_field($_POST['page_fold']);
- $this->options['booklet_pages'] = isset($_POST['booklet_pages']) ?
- boolval($_POST['booklet_pages']): false;
- $this->options['meeting_sort'] = sanitize_text_field($_POST['meeting_sort']);
- $this->options['main_grouping'] = sanitize_text_field($_POST['main_grouping']);
- $this->options['subgrouping'] = sanitize_text_field($_POST['subgrouping']);
- $this->options['borough_suffix'] = sanitize_text_field($_POST['borough_suffix']);
- $this->options['county_suffix'] = sanitize_text_field($_POST['county_suffix']);
- $this->options['neighborhood_suffix'] = sanitize_text_field($_POST['neighborhood_suffix']);
- $this->options['city_suffix'] = sanitize_text_field($_POST['city_suffix']);
- $this->options['meeting_template_content'] = wp_kses_post($_POST['meeting_template_content']);
- $this->options['asm_template_content'] = wp_kses_post($_POST['asm_template_content']);
- $this->options['column_line'] = isset($_POST['column_line']) ?
- boolval($_POST['column_line']) : 0;
- $this->options['col_color'] = isset($_POST['col_color']) ?
- validate_hex_color($_POST['col_color']) : '#bfbfbf';
- $this->options['custom_section_content'] = wp_kses_post($_POST['custom_section_content']);
- $this->options['custom_section_line_height'] = floatval($_POST['custom_section_line_height']);
- $this->options['custom_section_font_size'] = floatval($_POST['custom_section_font_size']);
- $this->options['pagenumbering_font_size'] = isset($_POST['pagenumbering_font_size']) ?
- floatval($_POST['pagenumbering_font_size']) : '9';
- $this->options['used_format_1'] = sanitize_text_field($_POST['used_format_1']);
- $this->options['include_meeting_email'] = isset($_POST['include_meeting_email']) ? boolval($_POST['include_meeting_email']) : false;
- $this->options['recurse_service_bodies'] = isset($_POST['recurse_service_bodies']) ? 1 : 0;
- $this->options['extra_meetings_enabled'] = isset($_POST['extra_meetings_enabled']) ? intval($_POST['extra_meetings_enabled']) : 0;
- $this->options['include_protection'] = boolval($_POST['include_protection']);
- $this->options['weekday_language'] = sanitize_text_field($_POST['weekday_language']);
- $this->options['asm_language'] = sanitize_text_field($_POST['asm_language']);
- $this->options['weekday_start'] = sanitize_text_field($_POST['weekday_start']);
- $this->options['meeting1_footer'] = isset($_POST['meeting1_footer']) ?
- sanitize_text_field($_POST['meeting1_footer']) : '';
- $this->options['meeting2_footer'] = isset($_POST['meeting2_footer']) ?
- sanitize_text_field($_POST['meeting2_footer']) :'';
- $this->options['nonmeeting_footer'] = isset($_POST['nonmeeting_footer']) ?
- sanitize_text_field($_POST['nonmeeting_footer']):'';
- $this->options['include_asm'] = boolval($_POST['include_asm']);
- $this->options['asm_format_key'] = sanitize_text_field($_POST['asm_format_key']);
- $this->options['asm_sort_order'] = sanitize_text_field($_POST['asm_sort_order']);
- $this->options['bmlt_login_id'] = sanitize_text_field($_POST['bmlt_login_id']);
- $this->options['bmlt_login_password'] = sanitize_text_field($_POST['bmlt_login_password']);
- $this->options['base_font'] = sanitize_text_field($_POST['base_font']);
- $this->options['colorspace'] = sanitize_text_field($_POST['colorspace']);
- $this->options['wheelchair_size'] = sanitize_text_field($_POST['wheelchair_size']);
- $this->options['protection_password'] = sanitize_text_field($_POST['protection_password']);
- $this->options['time_clock'] = sanitize_text_field($_POST['time_clock']);
- $this->options['time_option'] = intval($_POST['time_option']);
- $this->options['remove_space'] = boolval($_POST['remove_space']);
- $this->options['content_line_height'] = floatval($_POST['content_line_height']);
- $this->options['root_server'] = validate_url($_POST['root_server']);
- $this->options['service_body_1'] = sanitize_text_field($_POST['service_body_1']);
- $this->options['service_body_2'] = sanitize_text_field($_POST['service_body_2']);
- $this->options['service_body_3'] = sanitize_text_field($_POST['service_body_3']);
- $this->options['service_body_4'] = sanitize_text_field($_POST['service_body_4']);
- $this->options['service_body_5'] = sanitize_text_field($_POST['service_body_5']);
- $this->options['cache_time'] = intval($_POST['cache_time']);
- $this->options['custom_query'] = sanitize_text_field($_POST['custom_query']);
- $this->options['asm_custom_query'] = sanitize_text_field($_POST['asm_custom_query']);
- $this->options['user_agent'] = isset($_POST['user_agent']) ? sanitize_text_field($_POST['user_agent']) : 'None';
- $this->options['sslverify'] = isset($_POST['sslverify']) ? '1' : '0';
- $this->options['extra_meetings'] = array();
- if (isset($_POST['extra_meetings'])) {
- foreach ($_POST['extra_meetings'] as $extra) {
- $this->options['extra_meetings'][] = wp_kses_post($extra);
- }
- }
- $authors = $_POST['authors_select'];
- $this->options['authors'] = array();
- foreach ($authors as $author) {
- $this->options['authors'][] = intval($author);
- }
- $user = wp_get_current_user();
- if (!in_array($user->ID, $this->options['authors'])) {
- $this->options['authors'][] = $user->ID;
- }
- set_transient('admin_notice', 'Please put down your weapon. You have 20 seconds to comply.');
- if (!$this->current_user_can_modify()) {
- echo 'You do not have permission to save this configuation!
';
- } else {
- $this->save_admin_options();
- echo '
Your changes were successfully saved!
';
- $num = delete_transient($this->get_TransientKey());
- if ($num > 0) {
- echo "
$num Cache entries deleted
";
- }
- }
- echo '
';
- } elseif (isset($_REQUEST['pwsix_action']) && $_REQUEST['pwsix_action'] == "import_settings") {
- echo '
Your file was successfully imported!
';
- $num = delete_transient($this->get_TransientKey());
- } elseif (isset($_REQUEST['pwsix_action']) && $_REQUEST['pwsix_action'] == "default_settings_success") {
- echo '
Your default settings were successfully updated!
';
- $num = delete_transient($this->get_TransientKey());
- }
- global $wpdb;
- $query = "SELECT COUNT(*) FROM {$wpdb->posts} WHERE guid LIKE '%default_nalogo.jpg%'";
- if ($wpdb->get_var($query) == 0) {
- $url = plugin_dir_url(__FILE__) . "includes/default_nalogo.jpg";
- media_sideload_image($url, 0);
- }
- $this->fillUnsetOptions();
-
- $this->authors_safe = $this->options['authors'];
- ?>
-
-
-
-
-
-
-
-
-
-
- options[$option]) || strlen(trim($this->options[$option])) == 0) {
- $this->options[$option] = $default;
- }
- }
- function fillUnsetStringOption($option, $default)
- {
- if (!isset($this->options[$option])) {
- $this->options[$option] = $default;
- }
- }
- function fillUnsetArrayOption($option, $default)
- {
- if (!isset($this->options[$option])) {
- $this->options[$option] = $default;
- } else if (!is_array($this->options[$option])) {
- if (is_string($this->options[$option]) && strlen(trim($this->options[$option])) > 0) {
- $this->options[$option] = [ trim($this->options[$option]) ];
- } else {
- $this->options[$option] = $default;
- }
- }
- }
- function fillUnsetOptions()
- {
- $this->fillUnsetOption('front_page_line_height', '1.0');
- $this->fillUnsetOption('front_page_font_size', '10');
- $this->fillUnsetOption('last_page_font_size', '10');
- $this->fillUnsetOption('content_font_size', '9');
- $this->fillUnsetOption('header_font_size', $this->options['content_font_size']);
- $this->fillUnsetOption('pageheader_fontsize', $this->options['header_font_size']);
- if (floatval($this->options['pageheader_fontsize']) < 4) {
- $this->options['pageheader_fontsize'] = 6;
- }
- $this->fillUnsetOption('suppress_heading', 0);
- $this->fillUnsetOption('header_text_color', '#ffffff');
- $this->fillUnsetOption('header_background_color', '#000000');
- $this->fillUnsetOption('pageheader_textcolor', '#000000');
- $this->fillUnsetOption('pageheader_backgroundcolor', '#ffffff');
- $this->fillUnsetOption('header_uppercase', '0');
- $this->fillUnsetOption('header_bold', '1');
- $this->fillUnsetOption('sub_header_shown', 'none');
- $this->fillUnsetOption('margin_top', 3);
- $this->fillUnsetOption('margin_bottom', 3);
- $this->fillUnsetOption('margin_left', 3);
- $this->fillUnsetOption('margin_right', 3);
- $this->fillUnsetOption('column_gap', "5");
- $this->fillUnsetOption('content_line_height', '1.0');
- $this->fillUnsetOption('last_page_line_height', '1.0');
- $this->fillUnsetOption('page_size', 'legal');
- $this->fillUnsetOption('page_orientation', 'L');
- $this->fillUnsetOption('page_fold', 'quad');
- $this->fillUnsetOption('meeting_sort', 'day');
- $this->fillUnsetStringOption('booklet_pages', false);
- $this->fillUnsetStringOption('borough_suffix', 'Borough');
- $this->fillUnsetStringOption('county_suffix', 'County');
- $this->fillUnsetStringOption('neighborhood_suffix', 'Neighborhood');
- $this->fillUnsetStringOption('city_suffix', 'City');
- $this->fillUnsetStringOption('meeting_template_content', '');
- $this->fillUnsetStringOption('asm_template_content', '');
- $this->fillUnsetOption('column_line', 0);
- $this->fillUnsetOption('col_color', '#bfbfbf');
- $this->fillUnsetStringOption('custom_section_content', '');
- $this->fillUnsetOption('custom_section_line_height', '1');
- $this->fillUnsetOption('custom_section_font_size', '9');
- $this->fillUnsetOption('pagenumbering_font_size', '9');
- $this->fillUnsetStringOption('used_format_1', '');
- $this->fillUnsetOption('include_meeting_email', 0);
- $this->fillUnsetOption('base_font', 'dejavusanscondensed');
- $this->fillUnsetOption('colorspace', 0);
- $this->fillUnsetOption('recurse_service_bodies', 1);
- $this->fillUnsetOption('extra_meetings_enabled', 0);
- $this->fillUnsetOption('include_protection', 0);
- $this->fillUnsetOption('weekday_language', 'en');
- $this->fillUnsetStringOption('asm_language', ''); // same as main language
- $this->fillUnsetOption('weekday_start', '1');
- $this->fillUnsetOption('include_asm', '0');
- $this->fillUnsetOption('asm_format_key', '');
- $this->fillUnsetOption('asm_sort_order', 'name');
- $this->fillUnsetStringOption('bmlt_login_id', '');
- $this->fillUnsetStringOption('bmlt_login_password', '');
- $this->fillUnsetStringOption('protection_password', '');
- $this->fillUnsetStringOption('custom_query', '');
- $this->fillUnsetStringOption('asm_custom_query', '');
- $this->fillUnsetStringOption('user_agent', 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) +bread');
- $this->fillUnsetOption('sslverify', '0');
- $this->fillUnsetOption('cache_time', 0);
- $this->fillUnsetOption('wheelchair_size', "20px");
- $this->fillUnsetArrayOption('extra_meetings', []);
- if (!isset($this->options['extra_meetings'])) {
- if (count($this->options['extra_meetings'])>0) {
- $this->options['extra_meetings_enabled'] = 1;
- } else {
- $this->options['extra_meetings_enabled'] = 0;
- }
- }
- $this->fillUnsetArrayOption('authors', []);
- $my_footer = isset($this->translate[$this->options['weekday_language']]) ?
- $this->translate[$this->options['weekday_language']]['PAGE'].' {PAGENO}' : '{PAGENO}';
- $this->fillUnsetStringOption('nonmeeting_footer', $my_footer);
- $this->fillUnsetStringOption('meeting1_footer', $this->options['nonmeeting_footer']);
- $this->fillUnsetStringOption('meeting2_footer', $this->options['nonmeeting_footer']);
- }
- function get_TransientPrefix()
- {
- return '_bread';
- }
- function get_TransientKey()
- {
- return $this->get_TransientPrefix().'__'.$this->loaded_setting;
- }
- function pwsix_process_settings_admin()
- {
- $this->getMLOptions($this->requested_setting);
- if (isset($_POST['bmltmeetinglistsave']) && $_POST['bmltmeetinglistsave'] == 'Save Changes') {
- return;
- }
- if (empty($_POST['pwsix_action']) || 'settings_admin' != $_POST['pwsix_action']) {
- return;
- }
- if (! wp_verify_nonce($_POST['pwsix_settings_admin_nonce'], 'pwsix_settings_admin_nonce')) {
- return;
- }
- if (isset($_POST['delete'])) {
- if (!$this->current_user_can_modify()) {
- return;
- }
- if ($this->loaded_setting == 1) {
- return;
- }
- unset($this->allSettings[$this->loaded_setting]);
- update_option(Bread::SETTINGS, $this->allSettings);
- $this->getMLOptions(1);
- $this->loaded_setting = 1;
- $this->requested_setting = 1;
- } elseif (isset($_POST['duplicate'])) {
- if (!$this->current_user_can_create()) {
- return;
- }
- $id = $this->maxSetting + 1;
- $this->optionsName = $this->generateOptionName($id);
- $this->authors_safe = array();
- $this->options['authors'] = array();
- $this->save_admin_options();
- $this->allSettings[$id] = 'Setting '.$id;
- update_option(Bread::SETTINGS, $this->allSettings);
- $this->maxSetting = $id;
- $this->getMLOptions($id);
- }
- }
- function pwsix_process_rename_settings()
- {
- $this->getMLOptions($this->requested_setting);
- if (isset($_POST['bmltmeetinglistsave']) && $_POST['bmltmeetinglistsave'] == 'Save Changes') {
- return;
- }
- if (empty($_POST['pwsix_action']) || 'rename_setting' != $_POST['pwsix_action']) {
- return;
- }
- if (! wp_verify_nonce($_POST['pwsix_rename_nonce'], 'pwsix_rename_nonce')) {
- return;
- }
- if (! $this->current_user_can_modify()) {
- return;
- }
-
- $this->allSettings[$this->loaded_setting] = sanitize_text_field($_POST['setting_descr']);
- update_option(Bread::SETTINGS, $this->allSettings);
- }
- /**
- * Process a settings export that generates a .json file of the shop settings
- */
- function pwsix_process_settings_export()
- {
- $this->getMLOptions($this->requested_setting);
- if (isset($_POST['bmltmeetinglistsave']) && $_POST['bmltmeetinglistsave'] == 'Save Changes') {
- return;
- }
- if (empty($_REQUEST['pwsix_action']) || 'export_settings' != $_REQUEST['pwsix_action']) {
- return;
- }
- if (! wp_verify_nonce($_POST['pwsix_export_nonce'], 'pwsix_export_nonce')) {
- return;
- }
- if (! current_user_can('manage_bread')) { // TODO: Is this necessary? Why not let the user make a copy
- return;
- }
-
- $blogname = str_replace(" - ", " ", get_option('blogname').'-'.$this->allSettings[$this->loaded_setting]);
- $blogname = str_replace(" ", "-", $blogname);
- $date = date("m-d-Y");
- $blogname = trim(preg_replace('/[^a-z0-9]+/', '-', strtolower($blogname)), '-');
- $json_name = $blogname.$date.".json"; // Naming the filename will be generated.
- $settings = get_option($this->optionsName);
- foreach ($settings as $key => $value) {
- $value = maybe_unserialize($value);
- $need_options[$key] = $value;
- }
- $json_file = json_encode($need_options); // Encode data into json data
- ignore_user_abort(true);
- header('Content-Type: application/json; charset=utf-8');
- header("Content-Disposition: attachment; filename=$json_name");
- header("Expires: 0");
- echo json_encode($settings);
- exit;
- }
- function current_user_can_modify()
- {
- if (! current_user_can('manage_bread')) {
- return false;
- }
- $user = wp_get_current_user();
- if (in_array('administrator', $user->roles)) {
- return true;
- }
- if (!is_array($this->authors_safe) || empty($this->authors_safe)) {
- return true;
- }
- if (in_array($user->ID, $this->authors_safe)) {
- return true;
- }
- return false;
- }
- function current_user_can_create()
- {
- if (! current_user_can('manage_bread')) {
- return false;
- }
- return true;
- }
- /**
- * Process a settings import from a json file
- */
- function pwsix_process_settings_import()
- {
- $this->getMLOptions($this->requested_setting);
- if (isset($_POST['bmltmeetinglistsave']) && $_POST['bmltmeetinglistsave'] == 'Save Changes') {
- return;
- }
- if (empty($_REQUEST['pwsix_action']) || 'import_settings' != $_REQUEST['pwsix_action']) {
- return;
- }
- if (empty($_REQUEST['pwsix_import_nonce']) || !wp_verify_nonce($_REQUEST['pwsix_import_nonce'], 'pwsix_import_nonce')) {
- return;
- }
- if (! current_user_can('manage_bread')) {
- return;
- }
- $file_name = $_FILES['import_file']['name'];
- $tmp = explode('.', $file_name);
- $extension = end($tmp);
- if ($extension != 'json') {
- wp_die(__('Please upload a valid .json file'));
- }
- $import_file = $_FILES['import_file']['tmp_name'];
- if (empty($import_file)) {
- wp_die(__('Please upload a file to import'));
- }
- $file_size = $_FILES['import_file']['size'];
- if ($file_size > 500000) {
- wp_die(__('File size greater than 500k'));
- }
- $encode_options = file_get_contents($import_file);
- while (0 === strpos(bin2hex($encode_options), 'efbbbf')) {
- $encode_options = substr($encode_options, 3);
- }
- $settings = json_decode($encode_options, true);
- $settings['authors'] = $this->authors_safe;
- update_option($this->optionsName, $settings);
- setcookie('pwsix_action', "import_settings", time()+10);
- setcookie('current-meeting-list', $this->loaded_setting, time()+10);
- wp_safe_redirect(admin_url('?page=bmlt-meeting-list.php'));
- }
+/**
+ * Currently plugin version.
+ * Start at version 2.8.0 and use SemVer - https://semver.org
+ * Rename this for your plugin and update it as you release new versions.
+ */
+define('BREAD_VERSION', '2.8.0');
- /**
- * Process a default settings
- */
- function pwsix_process_default_settings()
- {
- $this->getMLOptions($this->requested_setting);
- if (! current_user_can('manage_bread') ||
- (isset($_POST['bmltmeetinglistsave']) && $_POST['bmltmeetinglistsave'] == 'Save Changes' )) {
- return;
- } elseif (isset($_REQUEST['pwsix_action']) && 'three_column_default_settings' == $_REQUEST['pwsix_action']) {
- if (! wp_verify_nonce($_POST['pwsix_submit_three_column'], 'pwsix_submit_three_column')) {
- die('Whoops! There was a problem with the data you posted. Please go back and try again.');
- }
- $import_file = plugin_dir_path(__FILE__) . "includes/three_column_settings.json";
- } elseif (isset($_REQUEST['pwsix_action']) && 'four_column_default_settings' == $_REQUEST['pwsix_action']) {
- if (! wp_verify_nonce($_POST['pwsix_submit_four_column'], 'pwsix_submit_four_column')) {
- die('Whoops! There was a problem with the data you posted. Please go back and try again.');
- }
- $import_file = plugin_dir_path(__FILE__) . "includes/four_column_settings.json";
- } elseif (isset($_REQUEST['pwsix_action']) && 'booklet_default_settings' == $_REQUEST['pwsix_action']) {
- if (! wp_verify_nonce($_POST['pwsix_submit_booklet'], 'pwsix_submit_booklet')) {
- die('Whoops! There was a problem with the data you posted. Please go back and try again.');
- }
- $import_file = plugin_dir_path(__FILE__) . "includes/booklet_settings.json";
- } else {
- return;
- }
- if (empty($import_file)) {
- wp_die(__('Error importing default settings file'));
- }
- $encode_options = file_get_contents($import_file);
- $settings = json_decode($encode_options, true);
- $settings['authors'] = $this->authors_safe;
- update_option($this->optionsName, $settings);
- setcookie('pwsix_action', "default_settings_success", time()+10);
- setcookie('current-meeting-list', $this->loaded_setting, time()+10);
- wp_safe_redirect(admin_url('?page=bmlt-meeting-list.php'));
- }
+/**
+ * The code that runs during plugin activation.
+ * This action is documented in includes/class-bread-activator.php
+ */
+function activate_bread()
+{
+ include_once plugin_dir_path(__FILE__) . 'includes/class-bread-activator.php';
+ Bread_Activator::activate();
+}
- /**
- * @desc Adds the Settings link to the plugin activate/deactivate page
- */
- function filter_plugin_actions($links, $file)
- {
- $settings_link = '
' . __('Settings') . ' ';
- array_unshift($links, $settings_link); // before other links
- return $links;
- }
+/**
+ * The code that runs during plugin deactivation.
+ * This action is documented in includes/class-bread-deactivator.php
+ */
+function deactivate_bread()
+{
+ include_once plugin_dir_path(__FILE__) . 'includes/class-bread-deactivator.php';
+ Bread_Deactivator::deactivate();
+}
- /**
- * Retrieves the plugin options from the database.
- * @return array
- */
- function getMLOptions($current_setting)
- {
- if ($current_setting < 1 and is_admin()) {
- $current_setting = 1;
- }
- if ($current_setting != 1) {
- $this->optionsName = $this->generateOptionName($current_setting);
- } else {
- $this->optionsName = Bread::OPTIONS_NAME;
- }
- //Don't forget to set up the default options
- if (!$theOptions = get_option($this->optionsName)) {
- if ($current_setting != 1) {
- unset($this->allSettings[$current_setting]);
- update_option(Bread::SETTINGS, $this->allSettings);
- die('Undefined setting: '. $current_setting);
- }
- $import_file = plugin_dir_path(__FILE__) . "includes/three_column_settings.json";
- $encode_options = file_get_contents($import_file);
- $theOptions = json_decode($encode_options, true);
- update_option($this->optionsName, $theOptions);
- }
- $this->options = $theOptions;
- $this->fillUnsetOptions();
- $this->upgrade_settings();
- $this->authors_safe = isset($theOptions['authors']) ? $theOptions['authors'] : array();
- $this->loaded_setting = $current_setting;
- }
+register_activation_hook(__FILE__, 'activate_bread');
+register_deactivation_hook(__FILE__, 'deactivate_bread');
- private function generateOptionName($current_setting)
- {
- return Bread::OPTIONS_NAME . '_' . $current_setting;
- }
- private function addServiceBody($service_body_name)
- {
- if (false === ( $this->options[$service_body_name] == 'Not Used' )) {
- $area_data = explode(',', $this->options[$service_body_name]);
- $area = $this->arraySafeGet($area_data);
- $this->options[$service_body_name] = ($area == 'NOT USED' ? '' : $area);
- $service_body_id = $this->arraySafeGet($area_data, 1);
- if ($this->options['recurse_service_bodies'] == 1) {
- return '&recursive=1&services[]=' . $service_body_id;
- } else {
- return '&services[]='.$service_body_id;
- }
- }
- }
- /**
- * Saves the admin options to the database.
- */
- function save_admin_options()
- {
- update_option($this->optionsName, $this->options);
- return;
- }
- public function getLatestRootVersion()
- {
- $results = $this->get("https://api.github.com/repos/bmlt-enabled/bmlt-root-server/releases/latest");
- $httpcode = wp_remote_retrieve_response_code($results);
- $response_message = wp_remote_retrieve_response_message($results);
- if ($httpcode != 200 && $httpcode != 302 && $httpcode != 304 && ! empty($response_message)) {
- return 'Problem Connecting to Server!';
- };
- $body = wp_remote_retrieve_body($results);
- $result = json_decode($body, true);
- return $result['name'];
- }
- } //End Class bread
-} // end if
-//instantiate the class
-if (class_exists("Bread")) {
- $BMLTMeetinglist_instance = new Bread();
+/**
+ * The core plugin class that is used to define internationalization,
+ * admin-specific hooks, and public-facing site hooks.
+ */
+require plugin_dir_path(__FILE__) . 'includes/class-bread.php';
+require plugin_dir_path(__FILE__) . 'includes/class-bread-bmlt.php';
+/**
+ * Begins execution of the plugin.
+ *
+ * Since everything within the plugin is registered via hooks,
+ * then kicking off the plugin from this point in the file does
+ * not affect the page life cycle.
+ *
+ * @since 2.8.0
+ */
+function run_bread()
+{
+
+ $plugin = new Bread();
+ $plugin->run();
}
+run_bread();
diff --git a/bread.php b/bread.php
index 299ca7b..6fef63f 100644
--- a/bread.php
+++ b/bread.php
@@ -1 +1 @@
-
\ No newline at end of file
+=7.4"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1"
+ },
+ "time": "2024-10-08T18:51:32+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "2.0.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
+ "reference": "54750ef60c58e43759730615a392c31c80e23176",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-phar": "*",
+ "ext-xmlwriter": "*",
+ "phar-io/version": "^3.0.1",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/2.0.4"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:33:53+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.2.1"
+ },
+ "time": "2022-02-21T01:04:05+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "11.0.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "f7f08030e8811582cc459871d28d6f5a1a4d35ca"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/f7f08030e8811582cc459871d28d6f5a1a4d35ca",
+ "reference": "f7f08030e8811582cc459871d28d6f5a1a4d35ca",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^5.3.1",
+ "php": ">=8.2",
+ "phpunit/php-file-iterator": "^5.1.0",
+ "phpunit/php-text-template": "^4.0.1",
+ "sebastian/code-unit-reverse-lookup": "^4.0.1",
+ "sebastian/complexity": "^4.0.1",
+ "sebastian/environment": "^7.2.0",
+ "sebastian/lines-of-code": "^3.0.1",
+ "sebastian/version": "^5.0.2",
+ "theseer/tokenizer": "^1.2.3"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.4.1"
+ },
+ "suggest": {
+ "ext-pcov": "PHP extension that provides line coverage",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "11.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.7"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-10-09T06:21:38+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "5.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6",
+ "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-08-27T05:02:59+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "5.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2",
+ "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^11.0"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T05:07:44+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "4.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964",
+ "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T05:08:43+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "7.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3",
+ "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T05:09:35+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "11.2.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "1dc0fedac703199e8704de085e47dd46bac0dde4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1dc0fedac703199e8704de085e47dd46bac0dde4",
+ "reference": "1dc0fedac703199e8704de085e47dd46bac0dde4",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.10.1",
+ "phar-io/manifest": "^2.0.3",
+ "phar-io/version": "^3.0.2",
+ "php": ">=8.2",
+ "phpunit/php-code-coverage": "^11.0",
+ "phpunit/php-file-iterator": "^5.0",
+ "phpunit/php-invoker": "^5.0",
+ "phpunit/php-text-template": "^4.0",
+ "phpunit/php-timer": "^7.0",
+ "sebastian/cli-parser": "^3.0",
+ "sebastian/code-unit": "^3.0",
+ "sebastian/comparator": "^6.0",
+ "sebastian/diff": "^6.0",
+ "sebastian/environment": "^7.0",
+ "sebastian/exporter": "^6.1.2",
+ "sebastian/global-state": "^7.0",
+ "sebastian/object-enumerator": "^6.0",
+ "sebastian/type": "^5.0",
+ "sebastian/version": "^5.0"
+ },
+ "suggest": {
+ "ext-soap": "To be able to generate mocks based on WSDL files"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "11.2-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/11.2.6"
+ },
+ "funding": [
+ {
+ "url": "https://phpunit.de/sponsors.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-07-03T05:51:49+00:00"
+ },
+ {
+ "name": "sebastian/cli-parser",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180",
+ "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:41:36+00:00"
+ },
+ {
+ "name": "sebastian/code-unit",
+ "version": "3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit.git",
+ "reference": "6bb7d09d6623567178cf54126afa9c2310114268"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/6bb7d09d6623567178cf54126afa9c2310114268",
+ "reference": "6bb7d09d6623567178cf54126afa9c2310114268",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/code-unit",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+ "security": "https://github.com/sebastianbergmann/code-unit/security/policy",
+ "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:44:28+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "4.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "183a9b2632194febd219bb9246eee421dad8d45e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e",
+ "reference": "183a9b2632194febd219bb9246eee421dad8d45e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+ "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy",
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:45:54+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "6.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "43d129d6a0f81c78bee378b46688293eb7ea3739"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/43d129d6a0f81c78bee378b46688293eb7ea3739",
+ "reference": "43d129d6a0f81c78bee378b46688293eb7ea3739",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.2",
+ "sebastian/diff": "^6.0",
+ "sebastian/exporter": "^6.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.4"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/6.2.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-10-31T05:30:08+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "4.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "ee41d384ab1906c68852636b6de493846e13e5a0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0",
+ "reference": "ee41d384ab1906c68852636b6de493846e13e5a0",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:49:50+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "6.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544",
+ "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0",
+ "symfony/process": "^4.2 || ^5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:53:05+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "7.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5",
+ "reference": "855f3ae0ab316bbafe1ba4e16e9f3c078d24a0c5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "https://github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "security": "https://github.com/sebastianbergmann/environment/security/policy",
+ "source": "https://github.com/sebastianbergmann/environment/tree/7.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:54:44+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "6.1.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e",
+ "reference": "c414673eee9a8f9d51bbf8d61fc9e3ef1e85b20e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=8.2",
+ "sebastian/recursion-context": "^6.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/6.1.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:56:19+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "7.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "3be331570a721f9a4b5917f4209773de17f747d7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7",
+ "reference": "3be331570a721f9a4b5917f4209773de17f747d7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "sebastian/object-reflector": "^4.0",
+ "sebastian/recursion-context": "^6.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "7.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "https://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:57:36+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a",
+ "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T04:58:38+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "6.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "f5b498e631a74204185071eb41f33f38d64608aa"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa",
+ "reference": "f5b498e631a74204185071eb41f33f38d64608aa",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "sebastian/object-reflector": "^4.0",
+ "sebastian/recursion-context": "^6.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T05:00:13+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "4.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9",
+ "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T05:01:32+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "6.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "694d156164372abbd149a4b85ccda2e4670c0e16"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16",
+ "reference": "694d156164372abbd149a4b85ccda2e4670c0e16",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-07-03T05:10:34+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "5.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/461b9c5da241511a2a0e8f240814fb23ce5c0aac",
+ "reference": "461b9c5da241511a2a0e8f240814fb23ce5c0aac",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^11.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "security": "https://github.com/sebastianbergmann/type/security/policy",
+ "source": "https://github.com/sebastianbergmann/type/tree/5.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-09-17T13:12:04+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "5.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874",
+ "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "security": "https://github.com/sebastianbergmann/version/security/policy",
+ "source": "https://github.com/sebastianbergmann/version/tree/5.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2024-10-09T05:16:32+00:00"
+ },
{
"name": "squizlabs/php_codesniffer",
- "version": "3.9.2",
+ "version": "3.10.3",
"source": {
"type": "git",
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
- "reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480"
+ "reference": "62d32998e820bddc40f99f8251958aed187a5c9c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/aac1f6f347a5c5ac6bc98ad395007df00990f480",
- "reference": "aac1f6f347a5c5ac6bc98ad395007df00990f480",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/62d32998e820bddc40f99f8251958aed187a5c9c",
+ "reference": "62d32998e820bddc40f99f8251958aed187a5c9c",
"shasum": ""
},
"require": {
@@ -611,7 +2133,57 @@
"type": "open_collective"
}
],
- "time": "2024-04-23T20:25:34+00:00"
+ "time": "2024-09-18T10:38:58+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2024-03-03T12:36:25+00:00"
}
],
"aliases": [],
diff --git a/includes/booklet_settings.json b/includes/booklet_settings.json
deleted file mode 100644
index f21adfb..0000000
--- a/includes/booklet_settings.json
+++ /dev/null
@@ -1 +0,0 @@
-{"root_server":"","service_body_1":"","service_body_2":"Not Used","service_body_3":"Not Used","header_font_size":9.5,"area_service_meetings":null,"helplines":null,"helplines_line_height":null,"front_page_content":"
NARCOTICS ANONYMOUS<\/strong><\/span><\/p>\r\n <\/p>\r\n
<\/p>\r\n
[service_body_1]<\/span><\/strong><\/p>\r\n <\/p>\r\n
<\/p>\r\n
MEETING LIST<\/strong><\/span><\/p>\r\n <\/p>\r\n
<\/p>\r\n
<\/p>\r\n
<\/a>\u00a0<\/p>\r\n <\/p>\r\n
<\/p>\r\n
\u00a0<\/p>\r\n
<\/p>\r\n
<\/p>\r\n
[date]<\/strong><\/span><\/p>\r\n <\/p>\r\n
<\/p>\r\n
<\/p>\r\n
<\/p>\r\n
<\/p>\r\n
<\/p>\r\n
To The Newcomer\u00a0<\/strong><\/span><\/p>\r\nThis meeting list is dedicated to you and is produced to help you find meetings throughout the\u00a0<\/span><\/span>[service_body_1]. The information in this book was as accurate as possible at the time of printing. Sometimes groups have to move or change their time. If you go to a listed meeting and it is not there, go to another meeting. If you can, please call our office at: (555) 555-5555, so that we can correct our meeting list for future printings. At Narcotics Anonymous, YOU are the most important person.<\/span>\u00a0<\/span><\/p>\r\n\u00a0<\/p>\r\n
\u00a0<\/p>\r\n
We Do Recover\u00a0<\/strong><\/span><\/p>\r\n\u00a0\u201cWhen at the end of the road we find that we can no longer function as a human being, either with or without drugs, we all face the same dilemma. What is there to do? There seems to be this alternative: Either to go on as best we can to the bitter ends - Jails, Institution, or Death - or find a new way to live. In years gone by, very few addicts had this last choice. Those who are addicted today are more fortunate. For the first time in man\\'s entire history, a simple way has been proving itself in the lives of many addicts. It is a simple spiritual, (not religious) program known as NARCOTICS ANONYMOUS.\u201d<\/span><\/p>\r\n[page_break][start_page_numbers]<\/p>\r\n
\r\n\r\n\r\nTHE TWELVE STEPS<\/span><\/strong><\/span><\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n\r\n\r\n\r\n\r\n1.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe admitted that we were powerless over our addiction, that our lives had become unmanageable.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n2.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe came to believe that a Power greater than ourselves could restore us to sanity.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n3.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe made a decision to turn our will and our lives over to the care of God as we understood Him.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n4.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe made a searching and fearless moral inventory of ourselves.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n5.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe admitted to God, to ourselves, and to another human being the exact nature of our wrongs.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n6.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe were entirely ready to have God remove all these defects of character.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n7.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe humbly asked Him to remove our shortcomings.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n8.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe made a list of all persons we had harmed and became willing to make amends to them all.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n9.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe made direct amends to such people wherever possible, except when to do so would injure them or others.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n10.<\/span><\/p>\r\n<\/td>\r\n
\r\nWe continued to take personal inventory and when we were wrong promptly admitted it.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n11.\u00a0<\/span><\/p>\r\n<\/td>\r\n
\r\nWe sought through prayer and meditation to improve our conscious contact with God as we understood Him, praying only for knowledge of His will for us and the power to carry that out.\u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n12.\u00a0<\/span><\/p>\r\n<\/td>\r\n
\r\nHaving had a spiritual awakening as a result of these steps, we tried to carry this message to addicts, and to practice these principles in all our affairs. \u00a0<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n <\/p>\r\n
[page_break]<\/p>\r\n
\r\n\r\n\r\nMeeting Format Legend<\/span><\/strong><\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n[format_codes_used_basic]<\/p>\r\n
<\/p>\r\n
\r\n\r\n\r\nHelplines<\/span><\/strong><\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n\r\n\r\n\r\n\r\nService Body 1<\/p>\r\n<\/td>\r\n
Number 1<\/td>\r\n<\/tr>\r\n \r\n\r\nService Body 2<\/p>\r\n<\/td>\r\n
Number 2<\/td>\r\n<\/tr>\r\n \r\n\r\n <\/p>\r\n<\/td>\r\n
\r\n <\/p>\r\n<\/td>\r\n<\/tr>\r\n
\r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n[page_break]<\/p>","front_line_height":"1.4","area_service_meetings_line_height":null,"content_font_size":9,"content_line_height":1.2,"front_page_font_size":11.4,"service_body_4":"Not Used","service_body_5":"Not Used","page_layout":null,"last_page_content":"
[page_break]<\/p>\r\n
\r\n\r\n\r\nTHE TWELVE TRADITIONS<\/span><\/strong><\/span><\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n\r\n\r\n\r\n\r\n1.<\/span><\/p>\r\n<\/td>\r\n
\r\nOur common welfare should come first; personal recovery depends on NA unity.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n2.<\/span><\/p>\r\n<\/td>\r\n
\r\nFor our group purpose there is but one ultimate authority\u2014 a loving God as He may express Himself in our group conscience. Our leaders are but trusted servants; they do not govern.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n3.<\/span><\/p>\r\n<\/td>\r\n
\r\nThe only requirement for membership is a desire to stop using.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n4.<\/span><\/p>\r\n<\/td>\r\n
\r\nEach group should be autonomous except in matters affecting other groups or NA as a whole.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n5.<\/span><\/p>\r\n<\/td>\r\n
\r\nEach group has but one primary purpose\u2014to carry the message to the addict who still suffers.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n6.<\/span><\/p>\r\n<\/td>\r\n
\r\nAn NA group ought never endorse, finance, or lend the NA name to any related facility or outside enterprise, lest problems of money, property, or prestige divert us from our primary purpose.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n7.<\/span><\/p>\r\n<\/td>\r\n
\r\nEvery NA group ought to be fully self-supporting, declining outside contributions.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n8.<\/span><\/p>\r\n<\/td>\r\n
\r\nNarcotics Anonymous should remain forever nonprofessional, but our service centers may employ special workers.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n9.<\/span><\/p>\r\n<\/td>\r\n
\r\nNA, as such, ought never be organized, but we may create service boards or committees directly responsible to those they serve.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n10.<\/span><\/p>\r\n<\/td>\r\n
\r\nNarcotics Anonymous has no opinion on outside issues; hence the NA name ought never be drawn into public controversy.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n11.\u00a0<\/span><\/p>\r\n<\/td>\r\n
\r\nOur public relations policy is based on attraction rather than promotion; we need always maintain personal anonymity at the level of press, radio, and films.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n\r\n\r\n12.\u00a0<\/span><\/p>\r\n<\/td>\r\n
\r\nAnonymity is the spiritual foundation of all our Traditions, ever reminding us to place principles before personalities.<\/span><\/p>\r\n<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n[page_break]<\/p>\r\n
\r\n\r\n\r\nName<\/span><\/strong><\/td>\r\n Phone Number<\/span><\/strong><\/td>\r\n<\/tr>\r\n\r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n \r\n\u00a0<\/td>\r\n \u00a0<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>","front_page_line_height":"1.1","last_page_line_height":1.2,"time_option":1,"remove_space":true,"helplines_font_size":null,"format_codes":null,"format_codes_font_size":null,"format_codes_line_height":null,"page_size":"5inch","page_fold":"half","meeting_sort":"city","cache_time":0,"show_status":null,"use_custom_section":null,"custom_section_content":"","custom_section_line_height":1,"page_orientation":"L","area_service_meetings_font_size":null,"which_format_codes":null,"custom_section_font_size":9,"include_meeting_email":false,"bmlt_login_id":"","bmlt_login_password":"","last_page_font_size":12,"column_line":false,"used_format_1":"","column_gap":5,"margin_right":5,"margin_left":5,"margin_bottom":5,"margin_top":5,"meeting_template_content":"day_abbr<\/strong><\/span><\/span> time<\/strong><\/span><\/span> group<\/strong>, location, info, street, city, state, zip (formats)\u00A0comments<\/em><\/span><\/div>","col_color":"#bfbfbf","time_clock":"12","header_text_color":"#ffffff","header_background_color":"#000000","header_uppercase":1,"header_bold":1,"logo_copied":"done","weekday_language":"en","include_asm":false,"sub_header_shown":1,"borough_suffix":"Borough","county_suffix":"County","neighborhood_suffix":"Neighborhood","city_suffix":"City","pagenumbering_font_size":9,"recurse_service_bodies":1,"extra_meetings_enabled":0,"include_protection":false,"base_font":"dejavusanscondensed","protection_password":"","custom_query":"","extra_meetings":[]}
\ No newline at end of file
diff --git a/includes/class-bread-activator.php b/includes/class-bread-activator.php
new file mode 100644
index 0000000..dc11ee6
--- /dev/null
+++ b/includes/class-bread-activator.php
@@ -0,0 +1,40 @@
+
+ */
+class Bread_Activator
+{
+
+ /**
+ * Short Description. (use period)
+ *
+ * Long Description.
+ *
+ * @since 2.8.0
+ */
+ public static function activate()
+ {
+ $role = $GLOBALS['wp_roles']->role_objects['administrator'];
+ if (isset($role) && !$role->has_cap('manage_bread')) {
+ $role->add_cap('manage_bread');
+ }
+ }
+}
diff --git a/includes/class-bread-bmlt.php b/includes/class-bread-bmlt.php
new file mode 100644
index 0000000..b5f518f
--- /dev/null
+++ b/includes/class-bread-bmlt.php
@@ -0,0 +1,277 @@
+bread = $bread;
+ }
+
+ public function get_configured_root_server_request($url, $raw = false)
+ {
+ $results = $this->bread->bmlt()->get($this->bread->getOption('root_server') . "/" . $url);
+ if ($raw) {
+ return $results;
+ }
+ return json_decode(wp_remote_retrieve_body($results), true);
+ }
+ public function get_formats_by_language(string $lang)
+ {
+ return $this->bread->bmlt()->get_configured_root_server_request("client_interface/json/?switcher=GetFormats&lang_enum=$lang");
+ }
+ /**
+ * Undocumented function
+ *
+ * @param string $url The BMLT call.
+ * @return WP_Error | array The result of the call.
+ */
+ private function get(string $url): WP_Error | array
+ {
+ $args = array(
+ 'timeout' => '120',
+ );
+ if ($this->bread->getOption('user_agent') != 'None') {
+ $args['headers'] = array(
+ 'User-Agent' => $this->bread->getOption('user_agent')
+ );
+ }
+ if ($this->bread->getOption('sslverify') == '1') {
+ $args['sslverify'] = false;
+ }
+ return wp_remote_get($url, $args);
+ }
+ /**
+ * Gets all the meetins in the root server as an array with id=>string. Used to select extra meetings.
+ *
+ * @return array
+ */
+ public function get_all_meetings(): array
+ {
+ $lang = $this->bread->bmlt()->get_bmlt_server_lang();
+ $result = $this->bread->bmlt()->get_configured_root_server_request("client_interface/json/?switcher=GetSearchResults&data_field_key=weekday_tinyint,start_time,service_body_bigint,id_bigint,meeting_name,location_text,email_contact&sort_keys=meeting_name,service_body_bigint,weekday_tinyint,start_time");
+
+ $unique_areas = $this->bread->bmlt()->get_areas();
+ $all_meetings = array();
+ foreach ($result as $value) {
+ foreach ($unique_areas as $unique_area) {
+ $area_data = explode(',', $unique_area);
+ $area_id = $this->bread->arraySafeGet($area_data, 1);
+ if ($area_id === $value['service_body_bigint']) {
+ $area_name = $this->bread->arraySafeGet($area_data);
+ }
+ }
+
+ $value['start_time'] = date("g:iA", strtotime($value['start_time']));
+ $all_meetings[$value['id_bigint']] = strip_tags($value['meeting_name'] . ' - ' . $this->bread->getday($value['weekday_tinyint'], true, $lang) . ' ' . $value['start_time'] . ' in ' . $area_name . ' at ' . $value['location_text']);
+ }
+
+ return $all_meetings;
+ }
+ public function get_fieldkeys()
+ {
+ $ret = $this->bread->bmlt()->get_configured_root_server_request("client_interface/json/?switcher=GetFieldKeys");
+ return is_null($ret) ? array() : $ret;
+ }
+ private $standard_keys = array(
+ "id_bigint",
+ "worldid_mixed",
+ "service_body_bigint",
+ "weekday_tinyint",
+ "start_time",
+ "duration_time",
+ "formats",
+ "lang_enum",
+ "longitude",
+ "latitude",
+ "meeting_name" . "location_text",
+ "location_info",
+ "location_street",
+ "location_city_subsection",
+ "location_neighborhood",
+ "location_municipality",
+ "location_sub_province",
+ "location_province",
+ "location_postal_code_1",
+ "location_nation",
+ "comments",
+ "zone"
+ );
+ public function get_nonstandard_fieldkeys()
+ {
+ $all_fks = $this->bread->bmlt()->get_fieldkeys();
+ $ret = array();
+ foreach ($all_fks as $fk) {
+ if (!in_array($fk['key'], $this->standard_keys)) {
+ $ret[] = $fk;
+ }
+ }
+ $ext_fields = apply_filters("Bread_Enrich_Meeting_Data", array(), array());
+ foreach ($ext_fields as $key => $value) {
+ $ret[] = array("key" => $key, "description" => $key);
+ }
+ return $ret;
+ }
+ /**
+ * Generates a list of service bodies to be used in the admin UI's drop downs.
+ *
+ * @return array the service bodies.
+ */
+ public function get_areas()
+ {
+ if (!empty($this->unique_areas)) {
+ return $this->unique_areas;
+ }
+ $result = $this->bread->bmlt()->get_configured_root_server_request("client_interface/json/?switcher=GetServiceBodies");
+ $this->unique_areas = array();
+
+ foreach ($result as $value) {
+ $parent_name = 'Parent ID';
+ foreach ($result as $parent) {
+ if ($value['parent_id'] == $parent['id']) {
+ $parent_name = $parent['name'];
+ }
+ }
+ if ($value['parent_id'] == '') {
+ $value['parent_id'] = '0';
+ }
+ $this->unique_areas[] = $value['name'] . ',' . $value['id'] . ',' . $value['parent_id'] . ',' . $parent_name;
+ }
+
+ return $this->unique_areas;
+ }
+ /**
+ * Gets the default language of the root server.
+ *
+ * @return string 2 character string ISO standard for the language.
+ */
+ public function get_bmlt_server_lang(): string
+ {
+ if ($this->bmlt_server_lang == '') {
+ $result = $this->bread->bmlt()->testRootServer();
+ if (!($result && is_array($result) && is_array($result[0]))) {
+ return 'en';
+ }
+ $this->bmlt_server_lang = ($result == null) ? 'en' : $result["0"]["nativeLang"];
+ }
+ return $this->bmlt_server_lang;
+ }
+ /**
+ * Check if this is a valid BMLT server.
+ *
+ * @param $override_root_server
+ * @return array the results of GetServerInfo
+ */
+ public function testRootServer(string $override_root_server = null): array|bool
+ {
+ if ($override_root_server == null) {
+ $results = $this->bread->bmlt()->get_configured_root_server_request("client_interface/json/?switcher=GetServerInfo", true);
+ } else {
+ $results = $this->bread->bmlt()->get($override_root_server . "/client_interface/json/?switcher=GetServerInfo");
+ }
+ if ($results instanceof WP_Error) {
+ $this->connection_error = $results->get_error_message();
+ return false;
+ }
+ $httpcode = wp_remote_retrieve_response_code($results);
+ if ($httpcode != 200 && $httpcode != 302 && $httpcode != 304) {
+ $this->connection_error = "HTTP Return Code: " . $httpcode;
+ return false;
+ }
+
+ return json_decode(wp_remote_retrieve_body($results), true);
+ }
+ /**
+ * This is used from the AdminUI, not to generate the meeting list.
+ *
+ * @param boolean $all should we get all the formats defined in the root server, or only those used in the service body. This respects the option recurse_service_bodies but only the first service body.
+ * @return array the formats
+ */
+ public function getFormatsForSelect(bool $all = false): array
+ {
+ if ($all) {
+ $results = $this->bread->bmlt()->get_configured_root_server_request("client_interface/json/?switcher=GetFormats");
+ $this->bread->bmlt()->sortBySubkey($results, 'key_string');
+ return $results;
+ }
+ $area_data = explode(',', $this->bread->getOption('service_body_1'));
+ $service_body_id = $this->bread->arraySafeGet($area_data, 1);
+ if ($this->bread->getOption('recurse_service_bodies') == 1) {
+ $services = '&recursive=1&services[]=' . $service_body_id;
+ } else {
+ $services = '&services[]=' . $service_body_id;
+ }
+ if (empty($service_body_id)) {
+ $queryUrl = "client_interface/json/?switcher=GetFormats";
+ } else {
+ $queryUrl = "client_interface/json/?switcher=GetSearchResults$services&get_formats_only";
+ }
+ $results = $this->bread->bmlt()->get_configured_root_server_request($queryUrl);
+ $results = empty($service_body_id) ? $results : $results['formats'];
+ $this->sortBySubkey($results, 'key_string');
+ return $results;
+ }
+ /**
+ * Convenient front end to array_multisort. Sorts the array in place.
+ *
+ * @param array $array The array to be sorted.
+ * @param string $subkey The key to be sorted by.
+ * @param [type] $sortType SORT_ASC (default) or SORT_DESC
+ * @return void
+ */
+ public function sortBySubkey(array &$array, string $subkey, int $sortType = SORT_ASC): void
+ {
+ if (empty($array)) {
+ return;
+ }
+ foreach ($array as $subarray) {
+ $keys[] = $subarray[$subkey];
+ }
+ array_multisort($keys, $sortType, $array);
+ }
+ /**
+ * Generate that part of the BMLT query-string that reflects the service bodies being queried.
+ *
+ * @return string Something to paste into the URL
+ */
+ public function generateDefaultQuery(): string
+ {
+ // addServiceBody has the side effect that
+ // the service body option is overridden, so that it contains
+ // only the name of the service body.
+ $services = $this->addServiceBody('service_body_1');
+ $services .= $this->addServiceBody('service_body_2');
+ $services .= $this->addServiceBody('service_body_3');
+ $services .= $this->addServiceBody('service_body_4');
+ $services .= $this->addServiceBody('service_body_5');
+ return $services;
+ }
+ private function addServiceBody($service_body_name)
+ {
+ if (false === ($this->bread->getOption($service_body_name) == 'Not Used')) {
+ $area_data = explode(',', $this->bread->getOption($service_body_name));
+ $area = $this->bread->arraySafeGet($area_data);
+ $this->bread->setOption($service_body_name, ($area == 'NOT USED' ? '' : $area));
+ $service_body_id = $this->bread->arraySafeGet($area_data, 1);
+ if ($this->bread->getOption('recurse_service_bodies') == 1) {
+ return '&recursive=1&services[]=' . $service_body_id;
+ } else {
+ return '&services[]=' . $service_body_id;
+ }
+ }
+ }
+ public function parse_field($text)
+ {
+ if ($text != '') {
+ $exploded = explode("#@-@#", $text);
+ $knt = count($exploded);
+ if ($knt > 1) {
+ $text = $exploded[$knt - 1];
+ }
+ }
+ return $text;
+ }
+}
diff --git a/includes/class-bread-deactivator.php b/includes/class-bread-deactivator.php
new file mode 100644
index 0000000..0941f5d
--- /dev/null
+++ b/includes/class-bread-deactivator.php
@@ -0,0 +1,40 @@
+
+ */
+class Bread_Deactivator
+{
+
+ /**
+ * Short Description. (use period)
+ *
+ * Long Description.
+ *
+ * @since 2.8.0
+ */
+ public static function deactivate()
+ {
+ $role = $GLOBALS['wp_roles']->role_objects['administrator'];
+ if (isset($role) && $role->has_cap('manage_bread')) {
+ $role->remove_cap('manage_bread');
+ }
+ }
+}
diff --git a/includes/class-bread-i18n.php b/includes/class-bread-i18n.php
new file mode 100644
index 0000000..514f96d
--- /dev/null
+++ b/includes/class-bread-i18n.php
@@ -0,0 +1,45 @@
+
+ */
+class Bread_i18n
+{
+
+
+ /**
+ * Load the plugin text domain for translation.
+ *
+ * @since 2.8.0
+ */
+ public function load_plugin_textdomain()
+ {
+
+ load_plugin_textdomain(
+ 'bread',
+ false,
+ dirname(dirname(plugin_basename(__FILE__))) . '/languages/'
+ );
+ }
+}
diff --git a/includes/class-bread-loader.php b/includes/class-bread-loader.php
new file mode 100644
index 0000000..e0f5f2a
--- /dev/null
+++ b/includes/class-bread-loader.php
@@ -0,0 +1,132 @@
+
+ */
+class Bread_Loader
+{
+
+ /**
+ * The array of actions registered with WordPress.
+ *
+ * @since 2.8.0
+ * @access protected
+ * @var array $actions The actions registered with WordPress to fire when the plugin loads.
+ */
+ protected $actions;
+
+ /**
+ * The array of filters registered with WordPress.
+ *
+ * @since 2.8.0
+ * @access protected
+ * @var array $filters The filters registered with WordPress to fire when the plugin loads.
+ */
+ protected $filters;
+
+ /**
+ * Initialize the collections used to maintain the actions and filters.
+ *
+ * @since 2.8.0
+ */
+ public function __construct()
+ {
+
+ $this->actions = array();
+ $this->filters = array();
+ }
+
+ /**
+ * Add a new action to the collection to be registered with WordPress.
+ *
+ * @since 2.8.0
+ * @param string $hook The name of the WordPress action that is being registered.
+ * @param object $component A reference to the instance of the object on which the action is defined.
+ * @param string $callback The name of the function definition on the $component.
+ * @param int $priority Optional. The priority at which the function should be fired. Default is 10.
+ * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1.
+ */
+ public function add_action($hook, $component, $callback, $priority = 10, $accepted_args = 1)
+ {
+ $this->actions = $this->add($this->actions, $hook, $component, $callback, $priority, $accepted_args);
+ }
+
+ /**
+ * Add a new filter to the collection to be registered with WordPress.
+ *
+ * @since 2.8.0
+ * @param string $hook The name of the WordPress filter that is being registered.
+ * @param object $component A reference to the instance of the object on which the filter is defined.
+ * @param string $callback The name of the function definition on the $component.
+ * @param int $priority Optional. The priority at which the function should be fired. Default is 10.
+ * @param int $accepted_args Optional. The number of arguments that should be passed to the $callback. Default is 1
+ */
+ public function add_filter($hook, $component, $callback, $priority = 10, $accepted_args = 1)
+ {
+ $this->filters = $this->add($this->filters, $hook, $component, $callback, $priority, $accepted_args);
+ }
+
+ /**
+ * A utility function that is used to register the actions and hooks into a single
+ * collection.
+ *
+ * @since 2.8.0
+ * @access private
+ * @param array $hooks The collection of hooks that is being registered (that is, actions or filters).
+ * @param string $hook The name of the WordPress filter that is being registered.
+ * @param object $component A reference to the instance of the object on which the filter is defined.
+ * @param string $callback The name of the function definition on the $component.
+ * @param int $priority The priority at which the function should be fired.
+ * @param int $accepted_args The number of arguments that should be passed to the $callback.
+ * @return array The collection of actions and filters registered with WordPress.
+ */
+ private function add($hooks, $hook, $component, $callback, $priority, $accepted_args)
+ {
+
+ $hooks[] = array(
+ 'hook' => $hook,
+ 'component' => $component,
+ 'callback' => $callback,
+ 'priority' => $priority,
+ 'accepted_args' => $accepted_args
+ );
+
+ return $hooks;
+ }
+
+ /**
+ * Register the filters and actions with WordPress.
+ *
+ * @since 2.8.0
+ */
+ public function run()
+ {
+ include_once plugin_dir_path(__FILE__).'class-bread-bmlt.php';
+
+ foreach ($this->filters as $hook) {
+ add_filter($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']);
+ }
+
+ foreach ($this->actions as $hook) {
+ add_action($hook['hook'], array($hook['component'], $hook['callback']), $hook['priority'], $hook['accepted_args']);
+ }
+ }
+}
diff --git a/includes/class-bread.php b/includes/class-bread.php
new file mode 100644
index 0000000..fd6c499
--- /dev/null
+++ b/includes/class-bread.php
@@ -0,0 +1,785 @@
+
+ */
+class Bread
+{
+
+ /**
+ * The loader that's responsible for maintaining and registering all hooks that power
+ * the plugin.
+ *
+ * @since 2.8.0
+ * @access protected
+ * @var Bread_Loader $loader Maintains and registers all hooks for the plugin.
+ */
+ protected $loader;
+
+ /**
+ * The unique identifier of this plugin.
+ *
+ * @since 2.8.0
+ * @access protected
+ * @var string $plugin_name The string used to uniquely identify this plugin.
+ */
+ protected $plugin_name;
+
+ /**
+ * The current version of the plugin.
+ *
+ * @since 2.8.0
+ * @access protected
+ * @var string $version The current version of the plugin.
+ */
+ protected $version;
+ public const SETTINGS = 'bmlt_meeting_list_settings';
+ public const OPTIONS_NAME = 'bmlt_meeting_list_options';
+ private $optionsName;
+ private $allSettings = array();
+ private $maxSetting = 1;
+ /**
+ * The setting we are editing, generating or otherwise working with. Generally set with query string "?current-meeting-list".
+ *
+ * @var integer
+ */
+ private int $requested_setting = 1;
+ private $protocol;
+ private string $tmp_dir;
+ /**
+ * The settings that detemine how the meeting list should be generated.
+ *
+ * @var array
+ */
+ private array $options = array();
+ /**
+ * Translations for things like weekday names. Two dimensions, first is language code, second is key value for text.
+ *
+ * @var array
+ */
+ private array $translate = array();
+ private bool $generating_meeting_list = false;
+ private bool $exporting_meeting_list = false;
+ /**
+ * The wizard wants to know if we are generating the first meeting list for this site.
+ *
+ * @var boolean
+ */
+ private bool $initial_setting = false;
+ /**
+ * The helper class for accessing the BMLT root server.
+ *
+ * @var Bread_Bmlt
+ */
+ private Bread_Bmlt $bread_bmlt;
+ public function bmlt(): Bread_Bmlt
+ {
+ return $this->bread_bmlt;
+ }
+ public function temp_dir(): string
+ {
+ return $this->tmp_dir;
+ }
+ public function getOption($name): mixed
+ {
+ if (!isset($this->options[$name])) {
+ return '';
+ }
+ return $this->options[$name];
+ }
+ public function emptyOption($name): bool
+ {
+ return empty($this->options[$name]);
+ }
+ public function getOptionForDisplay($option, $default = '')
+ {
+ return empty($this->options[$option]) ? $default : esc_html($this->options[$option]);
+ }
+ public function setOption($name, $value)
+ {
+ return $this->options[$name] = $value;
+ }
+ public function appendOption($name, $value)
+ {
+ return $this->options[$name][] = $value;
+ }
+ /**
+ * mPDF needs to have a temporary directory available. This is a problem for some hosting providers, so we need some
+ * logic to make sure it is available, and also to clean up after ourselves, to save disk space.
+ *
+ * @return string
+ */
+ private static function setup_temp_dir(): string
+ {
+ $dir = get_temp_dir();
+ $dir = rtrim($dir, DIRECTORY_SEPARATOR);
+ if (!is_dir($dir) || !is_writable($dir)) {
+ return false;
+ }
+ Bread::brute_force_cleanup($dir);
+ $attempts = 0;
+ $path = '';
+ do {
+ $path = sprintf('%s%s%s%s', $dir, DIRECTORY_SEPARATOR, 'bread', mt_rand(100000, mt_getrandmax()));
+ } while (!mkdir($path) && $attempts++ < 100);
+ return $path;
+ }
+ private static function brute_force_cleanup($dir)
+ {
+ if (is_dir($dir)) {
+ $objects = scandir($dir);
+ foreach ($objects as $object) {
+ if ($object != "." && $object != "..") {
+ if (str_starts_with($object, "bread")) {
+ $filename = $dir . DIRECTORY_SEPARATOR . $object;
+ if (time() - filemtime($filename . (is_dir($filename) ? '/.' : '')) > 24 * 3600) {
+ Bread::rrmdir($filename);
+ }
+ }
+ }
+ }
+ }
+ }
+ public function removeTempDir()
+ {
+ Bread::rrmdir($this->temp_dir());
+ }
+ private static function rrmdir($dir)
+ {
+ if (is_dir($dir)) {
+ $objects = scandir($dir);
+ foreach ($objects as $object) {
+ if ($object != "." && $object != "..") {
+ if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . "/" . $object)) {
+ Bread::rrmdir($dir . DIRECTORY_SEPARATOR . $object);
+ } else {
+ @unlink($dir . DIRECTORY_SEPARATOR . $object);
+ }
+ }
+ }
+ @rmdir($dir);
+ }
+ }
+ private function loadAllSettings($holder): int
+ {
+ if (isset($holder['bread_preview_settings'])) {
+ $this->allSettings = array();
+ $this->allSettings[1] = $holder['bread_preview_settings'];
+ } else {
+ $this->allSettings = get_option(Bread::SETTINGS);
+ }
+ if ($this->allSettings === false) {
+ $this->allSettings = array();
+ $this->allSettings[1] = array();
+ $this->maxSetting = 1;
+ } else {
+ foreach ($this->allSettings as $key => $value) {
+ if ($key > $this->maxSetting) {
+ $this->maxSetting = $key;
+ }
+ }
+ }
+ return isset($holder['current-meeting-list']) ? intval($holder['current-meeting-list']) : 1;
+ }
+ /**
+ * Undocumented function
+ *
+ * @param [type] $id
+ * @param [type] $name
+ * @return void
+ */
+ public function setAndSaveSetting($id, $name): void
+ {
+ $this->allSettings[$id] = $name;
+ update_option(Bread::SETTINGS, $this->allSettings);
+ }
+ public function getSettingName($id)
+ {
+ return $this->allSettings[$id];
+ }
+ public function getSettingNames()
+ {
+ return $this->allSettings;
+ }
+ public function deleteSetting($id)
+ {
+ unset($this->allSettings[$id]);
+ update_option(Bread::SETTINGS, $this->allSettings);
+ }
+ /**
+ * Example the superglobals $_REQUEST, $_SESSION and $_COOKIE and try to determine the settings-id, putting the
+ * results in a container.
+ *
+ * @return array
+ */
+ private function getCurrentMeetingListHolder(): array
+ {
+ $ret = array();
+ if (isset(($_REQUEST['preview-meeting-list'])) && !is_admin()) {
+ session_start();
+ $ret['bread_preview_settings'] = $_SESSION['bread_preview_settings'];
+ $ret['current-meeting-list'] = 1;
+ // TODO check that the value is equal to some security option we've set, otherwise reject.
+ }
+ if (isset($_REQUEST['current-meeting-list'])) {
+ $ret['current-meeting-list'] = $_REQUEST['current-meeting-list'];
+ } elseif (isset($_REQUEST['export-meeting-list'])) {
+ $ret['current-meeting-list'] = $_REQUEST['export-meeting-list'];
+ $this->exporting_meeting_list = true;
+ } elseif (isset($_COOKIE['current-meeting-list'])) {
+ $ret['current-meeting-list'] = $_COOKIE['current-meeting-list'];
+ }
+ $this->generating_meeting_list = !empty($ret) && !is_admin() && !$this->exporting_meeting_list;
+ return $ret;
+ }
+ /**
+ * Undocumented function
+ *
+ * @return void
+ */
+ public function generatingMeetingList(): bool
+ {
+ return $this->generating_meeting_list;
+ }
+ public function exportingMeetingList(): bool
+ {
+ return $this->exporting_meeting_list;
+ }
+ public function generateOptionName($current_setting)
+ {
+ return Bread::OPTIONS_NAME . '_' . $current_setting;
+ }
+ /**
+ * Retrieves the plugin options from the database.
+ *
+ * @return array
+ */
+ public function &getConfigurationForSettingId($current_setting)
+ {
+ if ($current_setting < 1) {
+ $current_setting = is_admin() ? 1 : $this->requested_setting;
+ }
+ if (is_array($this->allSettings[$current_setting])) {
+ $this->options = $this->allSettings[$current_setting];
+ } else {
+ if ($current_setting != 1) {
+ $this->optionsName = $this->generateOptionName($current_setting);
+ } else {
+ $this->optionsName = Bread::OPTIONS_NAME;
+ }
+ //Don't forget to set up the default options
+ if (!$theOptions = get_option($this->optionsName)) {
+ if ($current_setting != 1) {
+ unset($this->allSettings[$current_setting]);
+ update_option(Bread::SETTINGS, $this->allSettings);
+ die('Undefined setting: ' . $current_setting);
+ }
+ $this->initial_setting = true;
+ $import_file = plugin_dir_path(__FILE__) . "../admin/templates/30/trifold-landscape-largefont.json";
+ $encode_options = file_get_contents($import_file);
+ $theOptions = json_decode($encode_options, true);
+ update_option($this->optionsName, $theOptions);
+ }
+ $this->setOptions($theOptions);
+ }
+
+ $this->requested_setting = $current_setting;
+ return $this->options;
+ }
+ public function getOptions()
+ {
+ return $this->options;
+ }
+ public function setOptions(array $theOptions)
+ {
+ $this->options = $theOptions;
+ $this->fillUnsetOptions();
+ $this->upgrade_settings();
+ }
+ public function getOptionsName()
+ {
+ return $this->optionsName;
+ }
+ public function setOptionsName($name)
+ {
+ return $this->optionsName = $name;
+ }
+ public function getRequestedSetting()
+ {
+ return $this->requested_setting;
+ }
+ public function setRequestedSetting($id)
+ {
+ $this->requested_setting = $id;
+ }
+ /**
+ * Define the core functionality of the plugin.
+ *
+ * Set the plugin name and the plugin version that can be used throughout the plugin.
+ * Load the dependencies, define the locale, and set the hooks for the admin area and
+ * the public-facing side of the site.
+ *
+ * @since 2.8.0
+ */
+ public function __construct()
+ {
+ if (defined('BREAD_VERSION')) {
+ $this->version = BREAD_VERSION;
+ } else {
+ $this->version = '2.8.0';
+ }
+ $this->plugin_name = 'bread';
+ $this->tmp_dir = $this->setup_temp_dir();
+ $this->protocol = (strpos(strtolower(home_url()), "https") !== false ? "https" : "http") . "://";
+
+ $holder = $this->getCurrentMeetingListHolder();
+ $this->requested_setting = $this->loadAllSettings($holder);
+ $this->bread_bmlt = new Bread_Bmlt($this);
+
+ $this->load_dependencies();
+ $this->set_locale();
+ $this->load_translations();
+ $this->define_admin_hooks();
+ $this->define_public_hooks();
+ }
+ function load_translations()
+ {
+ $files = scandir(dirname(__FILE__) . "/lang");
+ foreach ($files as $file) {
+ if (strpos($file, "translate_") !== 0) {
+ continue;
+ }
+ include dirname(__FILE__) . "/lang/" . $file;
+ $key = substr($file, 10, -4);
+ $this->translate[$key] = $translate;
+ }
+ }
+ public function getTranslateTable()
+ {
+ return $this->translate;
+ }
+ public function getProtocol()
+ {
+ return $this->protocol;
+ }
+ /**
+ * Did any settings exist before?
+ *
+ * @return bool true when no setting existed previously, ie, if we should create setting 1.
+ */
+ public function getInitialSetting()
+ {
+ return $this->initial_setting;
+ }
+ /**
+ * Load the required dependencies for this plugin.
+ *
+ * Include the following files that make up the plugin:
+ *
+ * - Bread_Loader. Orchestrates the hooks of the plugin.
+ * - Bread_i18n. Defines internationalization functionality.
+ * - Bread_Admin. Defines all hooks for the admin area.
+ * - Bread_Public. Defines all hooks for the public side of the site.
+ *
+ * Create an instance of the loader which will be used to register the hooks
+ * with WordPress.
+ *
+ * @since 2.8.0
+ * @access private
+ */
+ private function load_dependencies()
+ {
+
+ /**
+ * The class responsible for orchestrating the actions and filters of the
+ * core plugin.
+ */
+ include_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-bread-loader.php';
+
+ /**
+ * The class responsible for defining internationalization functionality
+ * of the plugin.
+ */
+ include_once plugin_dir_path(dirname(__FILE__)) . 'includes/class-bread-i18n.php';
+
+ /**
+ * The class responsible for defining all actions that occur in the admin area.
+ */
+ include_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-bread-admin.php';
+
+ /**
+ * The class that creates the main menu item in the admin area, shared between bread and crouton.
+ */
+ include_once plugin_dir_path(dirname(__FILE__)) . 'admin/class-bmltenabled-admin.php';
+
+ /**
+ * The class responsible for defining all actions that occur in the public-facing
+ * side of the site.
+ */
+ include_once plugin_dir_path(dirname(__FILE__)) . 'public/class-bread-public.php';
+
+ $this->loader = new Bread_Loader();
+ }
+
+ /**
+ * Define the locale for this plugin for internationalization.
+ *
+ * Uses the Bread_i18n class in order to set the domain and to register the hook
+ * with WordPress.
+ *
+ * @since 2.8.0
+ * @access private
+ */
+ private function set_locale()
+ {
+
+ $plugin_i18n = new Bread_i18n();
+
+ $this->loader->add_action('plugins_loaded', $plugin_i18n, 'load_plugin_textdomain');
+ }
+ /**
+ * Register all of the hooks related to the admin area functionality
+ * of the plugin.
+ *
+ * @since 2.8.0
+ * @access private
+ */
+ private function define_admin_hooks()
+ {
+ $bmltenabled_admin = new BmltEnabled_Admin();
+ $plugin_admin = new Bread_Admin($this->get_plugin_name(), $this->get_version(), $bmltenabled_admin, $this);
+
+ $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_styles');
+ $this->loader->add_action('admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts');
+
+ $this->loader->add_action("admin_menu", $bmltenabled_admin, "admin_menu_link");
+ $this->loader->add_action("BmltEnabled_Submenu", $plugin_admin, "admin_submenu_link");
+ $this->loader->add_filter("BmltEnabled_Slugs", $plugin_admin, "submenu_slug");
+ $this->loader->add_filter('tiny_mce_before_init', $plugin_admin, 'tiny_tweaks');
+ $this->loader->add_filter('mce_external_plugins', $plugin_admin, 'my_custom_plugins');
+ $this->loader->add_filter('mce_buttons', $plugin_admin, 'my_register_mce_button');
+ //add_action("admin_notices", $plugin_admin, "is_root_server_missing");
+ $this->loader->add_action("admin_init", $plugin_admin, "my_theme_add_editor_styles");
+ $this->loader->add_action("wp_default_editor", $plugin_admin, "ml_default_editor");
+ $this->loader->add_filter('tiny_mce_version', $plugin_admin, 'force_mce_refresh');
+
+ // This is a public function. nameetinglists.org wants to let people see each others settings.
+ // It's OK now, since there is no more login stuff.
+ $this->loader->add_action('plugins_loaded', $plugin_admin, 'download_settings');
+ }
+
+ /**
+ * Register all of the hooks related to the public-facing functionality
+ * of the plugin.
+ *
+ * @since 2.8.0
+ * @access private
+ */
+ private function define_public_hooks()
+ {
+
+ $plugin_public = new Bread_Public($this->get_plugin_name(), $this->get_version(), $this);
+
+ $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_styles');
+ $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts');
+ $this->loader->add_action('plugins_loaded', $plugin_public, 'bmlt_meeting_list');
+ }
+
+ /**
+ * Run the loader to execute all of the hooks with WordPress.
+ *
+ * @since 2.8.0
+ */
+ public function run()
+ {
+ $this->loader->run();
+ }
+
+ /**
+ * The name of the plugin used to uniquely identify it within the context of
+ * WordPress and to define internationalization functionality.
+ *
+ * @since 2.8.0
+ * @return string The name of the plugin.
+ */
+ public function get_plugin_name()
+ {
+ return $this->plugin_name;
+ }
+
+ /**
+ * The reference to the class that orchestrates the hooks with the plugin.
+ *
+ * @since 2.8.0
+ * @return Bread_Loader Orchestrates the hooks of the plugin.
+ */
+ public function get_loader()
+ {
+ return $this->loader;
+ }
+
+ /**
+ * Retrieve the version number of the plugin.
+ *
+ * @since 2.8.0
+ * @return string The version number of the plugin.
+ */
+ public function get_version()
+ {
+ return $this->version;
+ }
+ /**
+ * Return a blank if the key is unset
+ *
+ * @param array $arr
+ * @param string $key
+ * @return string
+ */
+ public static function arraySafeGet(array $arr, string $key = "0"): string
+ {
+ return $arr[$key] ?? '';
+ }
+ public function getday($day, $abbreviate = false, $language = 'en')
+ {
+ $key = "WEEKDAYS";
+ if ($abbreviate) {
+ $key = "WKDYS";
+ }
+ return $this->translate[$language][$key][$day];
+ }
+ private function fillUnsetOption($option, $default)
+ {
+ if (!isset($this->options[$option]) || strlen(trim($this->options[$option])) == 0) {
+ $this->options[$option] = $default;
+ }
+ }
+ private function fillUnsetStringOption($option, $default)
+ {
+ if (!isset($this->options[$option])) {
+ $this->options[$option] = $default;
+ }
+ }
+ private function fillUnsetArrayOption($option, $default)
+ {
+ if (!isset($this->options[$option])) {
+ $this->options[$option] = $default;
+ } else if (!is_array($this->options[$option])) {
+ if (is_string($this->options[$option]) && strlen(trim($this->options[$option])) > 0) {
+ $this->options[$option] = [trim($this->options[$option])];
+ } else {
+ $this->options[$option] = $default;
+ }
+ }
+ }
+ /**
+ * Make sure the data from frontend or from DB is usuable. This might involve upgrading data from earlier versions of Bread.
+ *
+ * @return void
+ */
+ public function fillUnsetOptions()
+ {
+ $this->fillUnsetOptionsInner();
+ $this->removeDeprecated();
+ }
+ private function removeDeprecated()
+ {
+ unset($this->options['include_meeting_email']);
+ unset($this->options['bmlt_login_id']);
+ unset($this->options['bmlt_login_password']);
+ }
+ private function fillUnsetOptionsInner()
+ {
+ $this->fillUnsetOption('front_page_line_height', '1.0');
+ $this->fillUnsetOption('front_page_font_size', '10');
+ $this->fillUnsetOption('content_font_size', '9');
+ $this->fillUnsetOption('header_font_size', $this->options['content_font_size']);
+ $this->fillUnsetOption('pageheader_fontsize', $this->options['header_font_size']);
+ if (floatval($this->options['pageheader_fontsize']) < 4) {
+ $this->options['pageheader_fontsize'] = 6;
+ }
+ $this->fillUnsetOption('suppress_heading', 0);
+ $this->fillUnsetOption('header_text_color', '#ffffff');
+ $this->fillUnsetOption('header_background_color', '#000000');
+ $this->fillUnsetOption('pageheader_textcolor', '#000000');
+ $this->fillUnsetOption('pageheader_backgroundcolor', '#ffffff');
+ $this->fillUnsetOption('header_uppercase', '0');
+ $this->fillUnsetOption('header_bold', '1');
+ $this->fillUnsetOption('sub_header_shown', 'none');
+ $this->fillUnsetOption('margin_top', 3);
+ $this->fillUnsetOption('margin_bottom', 3);
+ $this->fillUnsetOption('margin_left', 3);
+ $this->fillUnsetOption('margin_right', 3);
+ $this->fillUnsetOption('column_gap', "5");
+ $this->fillUnsetOption('content_line_height', '1.0');
+ $this->fillUnsetOption('page_size', 'legal');
+ $this->fillUnsetOption('page_orientation', 'L');
+ $this->fillUnsetOption('page_fold', 'quad');
+ $this->fillUnsetOption('meeting_sort', 'day');
+ $this->fillUnsetStringOption('booklet_pages', false);
+ $this->fillUnsetStringOption('borough_suffix', 'Borough');
+ $this->fillUnsetStringOption('county_suffix', 'County');
+ $this->fillUnsetStringOption('neighborhood_suffix', 'Neighborhood');
+ $this->fillUnsetStringOption('city_suffix', 'City');
+ $this->fillUnsetStringOption('meeting_template_content', '');
+ $this->fillUnsetStringOption('additional_list_template_content', '');
+ $this->fillUnsetOption('column_line', 0);
+ $this->fillUnsetOption('col_color', '#bfbfbf');
+ $this->fillUnsetStringOption('custom_section_content', '');
+ $this->fillUnsetOption('custom_section_line_height', '1');
+ $this->fillUnsetOption('custom_section_font_size', '9');
+ $this->fillUnsetOption('pagenumbering_font_size', '9');
+ $this->fillUnsetStringOption('used_format_1', '');
+ $this->fillUnsetOption('base_font', 'dejavusanscondensed');
+ $this->fillUnsetOption('colorspace', 0);
+ $this->fillUnsetOption('recurse_service_bodies', 1);
+ $this->fillUnsetOption('extra_meetings_enabled', 0);
+ $this->fillUnsetOption('include_protection', 0);
+ $this->fillUnsetOption('weekday_language', 'en');
+ $this->fillUnsetStringOption('additional_list_language', ''); // same as main language
+ $this->fillUnsetOption('weekday_start', '1');
+ $this->fillUnsetOption('include_additional_list', '0');
+ $this->fillUnsetOption('additional_list_format_key', '');
+ $this->fillUnsetOption('additional_list_sort_order', 'name');
+ $this->fillUnsetStringOption('protection_password', '');
+ $this->fillUnsetStringOption('custom_query', '');
+ $this->fillUnsetStringOption('additional_list_custom_query', '');
+ $this->fillUnsetStringOption('user_agent', 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) +bread');
+ $this->fillUnsetOption('sslverify', '0');
+ $this->fillUnsetOption('cache_time', 0);
+ $this->fillUnsetOption('wheelchair_size', "20px");
+ $this->fillUnsetArrayOption('extra_meetings', []);
+ if (!isset($this->options['extra_meetings'])) {
+ if (count($this->options['extra_meetings']) > 0) {
+ $this->options['extra_meetings_enabled'] = 1;
+ } else {
+ $this->options['extra_meetings_enabled'] = 0;
+ }
+ }
+ $this->fillUnsetArrayOption('authors', []);
+ $my_footer = isset($this->translate[$this->options['weekday_language']]) ?
+ $this->translate[$this->options['weekday_language']]['PAGE'] . ' {PAGENO}' : '{PAGENO}';
+ $this->fillUnsetStringOption('nonmeeting_footer', $my_footer);
+ $this->fillUnsetStringOption('meeting1_footer', $this->options['nonmeeting_footer']);
+ $this->fillUnsetStringOption('meeting2_footer', $this->options['nonmeeting_footer']);
+ }
+ /**
+ * Does the work of upgrading from earlier versions.
+ */
+ private function upgrade_settings(): void
+ {
+ if (!isset($this->options['bread_version'])) {
+ if (!($this->options['meeting_sort'] === 'weekday_area'
+ || $this->options['meeting_sort'] === 'weekday_city'
+ || $this->options['meeting_sort'] === 'weekday_county'
+ || $this->options['meeting_sort'] === 'day')) {
+ $this->options['weekday_language'] = $this->bmlt()->get_bmlt_server_lang();
+ }
+ if ($this->options['page_fold'] == 'half') {
+ if ($this->options['page_size'] == 'A5') {
+ $this->options['page_size'] = 'A4';
+ }
+ $this->options['page_orientation'] = 'L';
+ }
+ if ($this->options['page_fold'] == 'tri') {
+ $this->options['page_orientation'] = 'L';
+ }
+ if (substr($this->options['meeting_sort'], 0, 8) == 'weekday_') {
+ $this->options['sub_header_shown'] = 'display';
+ }
+ if (isset($this->options['pageheader_text'])) {
+ $this->options['pageheader_content'] = $this->options['pageheader_text'];
+ unset($this->options['pageheader_text']);
+ }
+ if (substr($this->options['root_server'], -1) == '/') {
+ $this->options['root_server'] = substr($this->options['root_server'], 0, strlen($this->options['root_server']) - 1);
+ }
+ if (substr($this->options['root_server'], 0, 4) !== 'http') {
+ $this->options['root_server'] = 'http://' . $this->options['root_server'];
+ }
+ }
+ if (!isset($this->options['cont_header_shown'])
+ && isset($this->options['page_height_fix'])
+ ) {
+ $fix = floatval($this->options['page_height_fix']);
+ // say, the height of 2 lines
+ $x = floatval($this->options['content_font_size']) *
+ floatval($this->options['content_line_height']) * 2.0 * 0.35; // pt to mm
+ if ($fix < $x) {
+ $this->options['cont_header_shown'] = true;
+ } else {
+ $this->options['cont_header_shown'] = false;
+ }
+ unset($this->options['page_height_fix']);
+ }
+ if ($this->options['weekday_language'] == 'both') {
+ $this->options['weekday_language'] = "en_es";
+ }
+ if ($this->options['weekday_language'] == 'both_po') {
+ $this->options['weekday_language'] = "en_po";
+ }
+ if ($this->options['sub_header_shown'] == '0') {
+ $this->options['sub_header_shown'] = 'none';
+ }
+ if ($this->options['sub_header_shown'] == '1') {
+ $this->options['sub_header_shown'] = 'display';
+ }
+ $this->renamed_option('asm_format_key', 'additional_list_format_key');
+ $this->renamed_option('asm_sort_order', 'additional_list_sort_order');
+ $this->renamed_option('asm_language', 'additional_list_language');
+ $this->renamed_option('asm_custom_query', 'additional_list_custom_query');
+ $this->renamed_option('asm_template_content', 'additional_list_template_content');
+ if (!isset($this->options['bread_version']) || $this->options['bread_version'] < '2.8') {
+ if (($this->options['page_fold'] == 'half' || $this->options['page_fold'] == 'full') && trim($this->options['last_page_content']) !== '') {
+ $this->options['custom_section_content'] = $this->options['last_page_content'];
+ $this->options['custom_section_font_size'] = $this->options['last_page_font_size'];
+ $this->options['custom_section_line_height'] = $this->options['last_page_line_height'];
+ unset($this->options['last_page_content']);
+ unset($this->options['last_page_line_height']);
+ unset($this->options['last_page_font_size']);
+ }
+ }
+ $this->options['bread_version'] = BREAD_VERSION;
+ }
+ private function renamed_option(string $old, string $new)
+ {
+ if (!empty($this->options[$old])) {
+ if (empty($this->options[$new])) {
+ $this->options[$new] = $this->options[$old];
+ unset($this->options[$old]);
+ }
+ }
+ }
+ /**
+ * Stores the current settings in the Wordpress Options DB.
+ *
+ * @return void
+ */
+ public function updateOptions()
+ {
+ update_option(Bread::getOptionsName(), $this->options);
+ }
+ public static function get_TransientKey($setting): string
+ {
+ return '_bread__' . $setting;
+ }
+ public function getMaxSetting(): int
+ {
+ return $this->maxSetting;
+ }
+}
diff --git a/includes/default_nalogo.jpg b/includes/default_nalogo.jpg
deleted file mode 100644
index 8302613..0000000
Binary files a/includes/default_nalogo.jpg and /dev/null differ
diff --git a/includes/four_column_settings.json b/includes/four_column_settings.json
deleted file mode 100644
index 9c3874a..0000000
--- a/includes/four_column_settings.json
+++ /dev/null
@@ -1 +0,0 @@
-{"root_server":"","service_body_1":"","service_body_2":"Not Used","service_body_3":"Not Used","service_body_4":"Not Used","service_body_5":"Not Used","area_service_meetings":null,"helplines":null,"helplines_line_height":null,"helplines_font_size":null,"format_codes":null,"format_codes_font_size":"9","format_codes_line_height":"1.0","front_page_content":"\u00a0 <\/p>\r\n
<\/p>\r\n
[area]<\/b><\/span><\/p>\r\n NARCOTICS ANONYMOUS<\/strong><\/span><\/p>\r\nMEETING LIST<\/strong><\/span><\/p>\r\n\u00a0<\/p>\r\n
[date]<\/b><\/span><\/p>\r\n <\/p>\r\n
24 HOUR HELPLINE<\/b><\/span><\/p>\r\n NUMBER <\/span><\/p>\r\n\u00a0<\/span><\/p>\r\n\u00a0<\/p>\r\n
www.na.org<\/b><\/span><\/p>\r\n \u00a0<\/p>\r\n
SUGGESTIONS FOR EVERYONE<\/span><\/strong><\/p>\r\n