@@ -208,8 +208,8 @@
may need to be adjusted to reflect those changes.
Font Size and Line Height can be overridden using HTML mark-up in the meeting text.
+ Font Size and Line Height can be overridden using HTML mark-up in the meeting text.
';
?>
@@ -225,9 +225,9 @@
$editor_id,
'tinymce'=> array('toolbar1' => 'bold,italic,underline,strikethrough,bullist,numlist,alignleft,aligncenter,alignright,alignjustify,link,unlink,table,undo,redo,fullscreen', 'toolbar2' => 'formatselect,fontsizeselect,fontselect,forecolor,backcolor,indent,outdent,pastetext,removeformat,charmap,code', 'toolbar3' => 'custom_template_button_1,custom_template_button_2')
);
- wp_editor(stripslashes($this->options['meeting_template_content']), $editor_id, $settings);
+ wp_editor(stripslashes(Bread::getOption('meeting_template_content')), $editor_id, $settings);
?>
@@ -258,15 +258,15 @@
The additional list may include fields that might be used for say "service meetings". To access these fields
you must login with an service body administrator account.
Login ID:
-
+
Password:
-
+
$editor_id,
'tinymce'=> array('toolbar1' => 'bold,italic,underline,strikethrough,bullist,numlist,alignleft,aligncenter,alignright,alignjustify,link,unlink,table,undo,redo,fullscreen', 'toolbar2' => 'formatselect,fontsizeselect,fontselect,forecolor,backcolor,indent,outdent,pastetext,removeformat,charmap,code', 'toolbar3' => 'custom_template_button_1,custom_template_button_2')
);
- wp_editor(stripslashes($this->options['asm_template_content']), $editor_id, $settings);
+ wp_editor(stripslashes(Bread::getOption('asm_template_content')), $editor_id, $settings);
?>
You do not have permission to save this configuation!
';
+ } else {
+ $this->admin->save_admin_options();
+ echo '
Your changes were successfully saved!
';
+ $num = delete_transient(Bread::get_TransientKey($this->admin->loaded_setting));
+ 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(Bread::get_TransientKey($this->admin->loaded_setting));
+ } elseif (isset($_REQUEST['pwsix_action']) && $_REQUEST['pwsix_action'] == "default_settings_success") {
+ echo '
Your default settings were successfully updated!
';
+ $num = delete_transient(Bread::get_TransientKey($this->admin->loaded_setting));
+ }
+ 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);
+ }
+ Bread::fillUnsetOptions();
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..aa1fc01
--- /dev/null
+++ b/admin/tinymce/front_page_button/plugin.min.js
@@ -0,0 +1,409 @@
+(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: 'Cheatsheet',
+ onclick: function () {
+ editor.windowManager.open(
+ {
+ title: 'Shortcode Instructions',
+ url: 'https://nameetinglist.org/videos/table.html',
+ width: 650,
+ height: 530,
+ buttons: [{
+ text: 'Close',
+ onclick: 'close'
+ }]
+ }
+ );
+ }
+ }
+ ]
+ },
+ {
+ text: 'Format Code Legend',
+ menu: [
+ {
+ text: 'Used Format Codes - Abbreviated - English',
+ onclick: function () {
+ editor.insertContent('
[format_codes_used_basic]');
+ }
+ },
+ {
+ text: 'Used Format Codes - Abbreviated - Spanish',
+ onclick: function () {
+ editor.insertContent('
[format_codes_used_basic_es]
');
+ }
+ },
+ {
+ text: 'Used Format Codes - Abbreviated - French',
+ onclick: function () {
+ editor.insertContent('
Légende format de réunion
[format_codes_used_basic_fr]
');
+ }
+ },
+ {
+ text: 'Used Format Codes - Detailed - English',
+ onclick: function () {
+ editor.insertContent('
[format_codes_used_detailed]
');
+ }
+ },
+ {
+ text: 'Used Format Codes - Detailed - Spanish',
+ onclick: function () {
+ editor.insertContent('
[format_codes_used_detailed_es]
');
+ }
+ },
+ {
+ text: 'All Format Codes - Abbreviated - English',
+ onclick: function () {
+ editor.insertContent('
[format_codes_all_basic]
');
+ }
+ },
+ {
+ text: 'All Format Codes - Detailed - English',
+ onclick: function () {
+ editor.insertContent('
[format_codes_all_detailed]
');
+ }
+ }
+ ]
+ },
+ {
+ 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: 'Service Meetings Template',
+ onclick: function () {
+ editor.insertContent('
[service_meetings]
');
+ }
+ },
+ {
+ 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: [
+ {
+ text: 'One Column Template [Meeting Data]',
+ onclick: function () {
+ editor.insertContent('
time group , location, info, street, city, state, zip (formats) comments
');
+ }
+ },
+ {
+ text: 'Two Column Template [Time] [Meeting Data]',
+ onclick: function () {
+ editor.insertContent('
time group, location, info, street, city, state, zip (formats) comments
');
+ }
+ },
+ {
+ text: 'Three Column Template [Day] [Time] [Meeting Data]',
+ onclick: function () {
+ editor.insertContent('
day_abbr time group , location, info, street, city, state, zip (formats) comments
');
+ }
+ }
+ ]
+ }
+ );
+ 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
deleted file mode 100644
index b5f6ec5..0000000
--- a/bmlt-meeting-list.php
+++ /dev/null
@@ -1,2981 +0,0 @@
- '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'));
- }
-
- /**
- * 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'));
- }
-
- /**
- * @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;
- }
-
- /**
- * 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;
- }
-
- 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();
-}
diff --git a/bread.php b/bread.php
index 299ca7b..02cff2b 100644
--- a/bread.php
+++ b/bread.php
@@ -1 +1,84 @@
-
\ No newline at end of file
+run();
+}
+run_bread();
diff --git a/composer.json b/composer.json
index 7c35b33..dd4fc23 100644
--- a/composer.json
+++ b/composer.json
@@ -17,6 +17,6 @@
"squizlabs/php_codesniffer": "3.*"
},
"config": {
- "vendor-dir": "mpdf/vendor"
+ "vendor-dir": "vendor"
}
}
diff --git a/composer.lock b/composer.lock
index ab46952..63f9626 100644
--- a/composer.lock
+++ b/composer.lock
@@ -181,16 +181,16 @@
},
{
"name": "mpdf/qrcode",
- "version": "v1.2.0",
+ "version": "v1.2.1",
"source": {
"type": "git",
"url": "https://github.com/mpdf/qrcode.git",
- "reference": "0c09fce8b28707611c3febdd1ca424d40f172184"
+ "reference": "5320c512776aa3c199bd8be8f707ec83d9779d85"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/mpdf/qrcode/zipball/0c09fce8b28707611c3febdd1ca424d40f172184",
- "reference": "0c09fce8b28707611c3febdd1ca424d40f172184",
+ "url": "https://api.github.com/repos/mpdf/qrcode/zipball/5320c512776aa3c199bd8be8f707ec83d9779d85",
+ "reference": "5320c512776aa3c199bd8be8f707ec83d9779d85",
"shasum": ""
},
"require": {
@@ -237,7 +237,7 @@
],
"support": {
"issues": "https://github.com/mpdf/qrcode/issues",
- "source": "https://github.com/mpdf/qrcode/tree/v1.2.0"
+ "source": "https://github.com/mpdf/qrcode/tree/v1.2.1"
},
"funding": [
{
@@ -245,7 +245,7 @@
"type": "custom"
}
],
- "time": "2022-01-11T09:42:41+00:00"
+ "time": "2024-06-04T13:40:39+00:00"
},
{
"name": "myclabs/deep-copy",
@@ -411,16 +411,16 @@
},
{
"name": "psr/log",
- "version": "3.0.0",
+ "version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
- "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"shasum": ""
},
"require": {
@@ -455,22 +455,22 @@
"psr-3"
],
"support": {
- "source": "https://github.com/php-fig/log/tree/3.0.0"
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
},
- "time": "2021-07-14T16:46:02+00:00"
+ "time": "2024-09-11T13:17:53+00:00"
},
{
"name": "setasign/fpdi",
- "version": "v2.6.0",
+ "version": "v2.6.1",
"source": {
"type": "git",
"url": "https://github.com/Setasign/FPDI.git",
- "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad"
+ "reference": "09a816004fcee9ed3405bd164147e3fdbb79a56f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Setasign/FPDI/zipball/a6db878129ec6c7e141316ee71872923e7f1b7ad",
- "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad",
+ "url": "https://api.github.com/repos/Setasign/FPDI/zipball/09a816004fcee9ed3405bd164147e3fdbb79a56f",
+ "reference": "09a816004fcee9ed3405bd164147e3fdbb79a56f",
"shasum": ""
},
"require": {
@@ -521,7 +521,7 @@
],
"support": {
"issues": "https://github.com/Setasign/FPDI/issues",
- "source": "https://github.com/Setasign/FPDI/tree/v2.6.0"
+ "source": "https://github.com/Setasign/FPDI/tree/v2.6.1"
},
"funding": [
{
@@ -529,22 +529,22 @@
"type": "tidelift"
}
],
- "time": "2023-12-11T16:03:32+00:00"
+ "time": "2024-09-02T10:17:15+00:00"
}
],
"packages-dev": [
{
"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 +611,7 @@
"type": "open_collective"
}
],
- "time": "2024-04-23T20:25:34+00:00"
+ "time": "2024-09-18T10:38:58+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..de2dadb
--- /dev/null
+++ b/includes/class-bread-bmlt.php
@@ -0,0 +1,220 @@
+ 'login',
+ 'c_comdef_admin_login' => Bread::getOption('bmlt_login_id'),
+ 'c_comdef_admin_password' => Bread::getOption('bmlt_login_password'), '&')
+ );
+ return Bread_Bmlt::get(Bread::getOption('root_server')."/local_server/server_admin/xml.php?" . $query_string);
+ }
+ public static function requires_authentication()
+ {
+ return (Bread::getOption('include_meeting_email') == 1 || Bread::getOption('include_asm') == 1);
+ }
+
+ public static function get_root_server_request($url)
+ {
+ $cookies = null;
+
+ if (Bread_Bmlt::requires_authentication()) {
+ $auth_response = Bread_Bmlt::authenticate_root_server();
+ $cookies = wp_remote_retrieve_cookies($auth_response);
+ }
+
+ return Bread_Bmlt::get($url, $cookies);
+ }
+
+ public static function get_configured_root_server_request($url)
+ {
+ return Bread_Bmlt::get_root_server_request(Bread::getOption('root_server')."/".$url);
+ }
+
+ private static function get($url, $cookies = array())
+ {
+ $args = array(
+ 'timeout' => '120',
+ 'cookies' => $cookies,
+ );
+ if (Bread::getOption('user_agent') != 'None') {
+ $args['headers'] = array(
+ 'User-Agent' => Bread::getOption('user_agent')
+ );
+ }
+ if (Bread::getOption('sslverify') == '1') {
+ $args['sslverify'] = false;
+ }
+ return wp_remote_get($url, $args);
+ }
+ public static function get_all_meetings()
+ {
+ $lang = Bread_Bmlt::get_bmlt_server_lang();
+ $results = 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");
+ $result = json_decode(wp_remote_retrieve_body($results), true);
+
+ $unique_areas = Bread_Bmlt::get_areas();
+ $all_meetings = array();
+ foreach ($result as $value) {
+ foreach ($unique_areas as $unique_area) {
+ $area_data = explode(',', $unique_area);
+ $area_id = Bread::arraySafeGet($area_data, 1);
+ if ($area_id === $value['service_body_bigint']) {
+ $area_name = Bread::arraySafeGet($area_data);
+ }
+ }
+
+ $value['start_time'] = date("g:iA", strtotime($value['start_time']));
+ $all_meetings[] = $value['meeting_name'].'||| ['.Bread::getday($value['weekday_tinyint'], true, $lang).'] ['.$value['start_time'].']||| ['.$area_name.']||| ['.$value['id_bigint'].']';
+ }
+
+ return $all_meetings;
+ }
+ public static function get_fieldkeys()
+ {
+ $results = Bread_Bmlt::get_configured_root_server_request("client_interface/json/?switcher=GetFieldKeys");
+ return json_decode(wp_remote_retrieve_body($results), true);
+ }
+ private static $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 static function get_nonstandard_fieldkeys()
+ {
+ $all_fks = Bread_Bmlt::get_fieldkeys();
+ $ret = array();
+ foreach ($all_fks as $fk) {
+ if (!in_array($fk['key'], Bread_Bmlt::$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;
+ }
+ public static function get_areas()
+ {
+ $results = Bread_Bmlt::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;
+ }
+
+ public static function get_bmlt_server_lang()
+ {
+ $results = Bread_Bmlt::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;
+ }
+
+ public static function testRootServer($override_root_server = null)
+ {
+ if ($override_root_server == null) {
+ $results = Bread_Bmlt::get_configured_root_server_request("client_interface/json/?switcher=GetServerInfo");
+ } else {
+ $results = Bread_Bmlt::get_root_server_request($override_root_server."/client_interface/json/?switcher=GetServerInfo");
+ }
+ if ($results instanceof WP_Error) {
+ Bread_Bmlt::$connection_error = $results->get_error_message();
+ return false;
+ }
+ $httpcode = wp_remote_retrieve_response_code($results);
+ if ($httpcode != 200 && $httpcode != 302 && $httpcode != 304) {
+ Bread_Bmlt::$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.
+ public static function getFormatsForSelect($all = false)
+ {
+ if ($all) {
+ $results = Bread_Bmlt::get_configured_root_server_request("client_interface/json/?switcher=GetFormats");
+ $results = json_decode(wp_remote_retrieve_body($results), true);
+ Bread_Bmlt::sortBySubkey($results, 'key_string');
+ return $results;
+ }
+ $area_data = explode(',', Bread::getOption('service_body_1'));
+ $service_body_id = Bread::arraySafeGet($area_data, 1);
+ if (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 = Bread_Bmlt::get_configured_root_server_request($queryUrl);
+ $results = json_decode(wp_remote_retrieve_body($results), true);
+ $results = empty($service_body_id) ? $results : $results['formats'];
+ Bread_Bmlt::sortBySubkey($results, 'key_string');
+ return $results;
+ }
+
+ public static function sortBySubkey(&$array, $subkey, $sortType = SORT_ASC)
+ {
+ if (empty($array)) {
+ return;
+ }
+ foreach ($array as $subarray) {
+ $keys[] = $subarray[$subkey];
+ }
+ array_multisort($keys, $sortType, $array);
+ }
+ public static function generateDefaultQuery() {
+ // addServiceBody has the side effect that
+ // the service body option is overridden, so that it contains
+ // only the name of the service body.
+ $services = Bread_Bmlt::addServiceBody('service_body_1');
+ $services .= Bread_Bmlt::addServiceBody('service_body_2');
+ $services .= Bread_Bmlt::addServiceBody('service_body_3');
+ $services .= Bread_Bmlt::addServiceBody('service_body_4');
+ $services .=Bread_Bmlt::addServiceBody('service_body_5');
+ return $services;
+ }
+ private static function addServiceBody($service_body_name)
+ {
+ if (false === ( Bread::getOption($service_body_name) == 'Not Used' )) {
+ $area_data = explode(',', Bread::getOption($service_body_name));
+ $area = Bread::arraySafeGet($area_data);
+ Bread::setOption($service_body_name, ($area == 'NOT USED' ? '' : $area));
+ $service_body_id = Bread::arraySafeGet($area_data, 1);
+ if (Bread::getOption('recurse_service_bodies') == 1) {
+ return '&recursive=1&services[]=' . $service_body_id;
+ } else {
+ return '&services[]='.$service_body_id;
+ }
+ }
+ }
+}
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..19d9121
--- /dev/null
+++ b/includes/class-bread.php
@@ -0,0 +1,643 @@
+
+ */
+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;
+ private $requested_setting = 1;
+ private $protocol;
+ private static $instance = null;
+ private $tmp_dir;
+ private $options = array();
+ private $translate = array();
+ public static function temp_dir()
+ {
+ return Bread::$instance->tmp_dir;
+ }
+ public static function getOption($name)
+ {
+ if (!isset(Bread::$instance->options[$name])) {
+ return '';
+ }
+ return Bread::$instance->options[$name];
+ }
+ public static function emptyOption($name)
+ {
+ return empty(Bread::$instance->options[$name]);
+ }
+ public static function getOptionForDisplay($option, $default = '')
+ {
+ return empty(Bread::$instamce->options[$option])?$default:esc_html(Bread::$instance->options[$option]);
+ }
+ public static function setOption($name, $value)
+ {
+ return Bread::$instance->options[$name] = $value;
+ }
+ private static function setup_temp_dir()
+ {
+ $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) > 24 * 3600) {
+ Bread::rrmdir($filename);
+ }
+ }
+ }
+ }
+ }
+ }
+ public static function removeTempDir()
+ {
+ Bread::rrmdir(Bread::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()
+ {
+ $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;
+ }
+ }
+ }
+ }
+ public static function renameSetting($id, $name)
+ {
+ Bread::$instance->allSettings[$id] = $name;
+ update_option(Bread::SETTINGS, Bread::$instance->allSettings);
+ }
+ public static function getSettingName($id)
+ {
+ return Bread::$instance->allSettings[$id];
+ }
+ public static function getSettingNames()
+ {
+ return Bread::$instance->allSettings;
+ }
+ public static function deleteSetting($id)
+ {
+ unset(Bread::$instance->allSettings[$id]);
+ update_option(Bread::SETTINGS, Bread::$instance->allSettings);
+ }
+ private 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;
+ }
+
+
+ public static function generateOptionName($current_setting)
+ {
+ return Bread::OPTIONS_NAME . '_' . $current_setting;
+ }
+ public static function getMLOptions($current_setting)
+ {
+ Bread::$instance->getMLOptionsInner($current_setting);
+ }
+ /**
+ * Retrieves the plugin options from the database.
+ *
+ * @return array
+ */
+ private function getMLOptionsInner($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->requested_setting = $current_setting;
+ }
+ public static function getOptionsName()
+ {
+ return Bread::$instance->optionsName;
+ }
+ public static function setOptionsName($name)
+ {
+ return Bread::$instance->optionsName = $name;
+ }
+ public static function getRequestedSetting()
+ {
+ return Bread::$instance->requested_setting;
+ }
+ public static function setRequestedSetting($id)
+ {
+ Bread::$instance->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';
+ Bread::$instance = $this;
+ $this->tmp_dir = $this->setup_temp_dir();
+ $this->protocol = (strpos(strtolower(home_url()), "https") !== false ? "https" : "http") . "://";
+
+ $this->loadAllSettings();
+ $holder = $this->getCurrentMeetingListHolder();
+
+ $this->requested_setting = isset($holder['current-meeting-list']) ? intval($holder['current-meeting-list']) : 1;
+ $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 static function getTranslateTable()
+ {
+ return Bread::$instance->translate;
+ }
+ public static function getProtocol()
+ {
+ return Bread::$instance->protocol;
+ }
+ /**
+ * 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 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()
+ {
+
+ $plugin_admin = new Bread_Admin($this->get_plugin_name(), $this->get_version());
+
+ $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", $plugin_admin, "admin_menu_link");
+ $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, "pwsix_process_settings_export");
+ $this->loader->add_action("admin_init", $plugin_admin, "pwsix_process_settings_import");
+ $this->loader->add_action("admin_init", $plugin_admin, "pwsix_process_default_settings");
+ $this->loader->add_action("admin_init", $plugin_admin, "pwsix_process_settings_admin");
+ $this->loader->add_action("admin_init", $plugin_admin, "pwsix_process_rename_settings");
+ $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');
+ }
+
+ /**
+ * 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->options);
+
+ $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_styles');
+ $this->loader->add_action('wp_enqueue_scripts', $plugin_public, 'enqueue_scripts');
+ if (isset($this->getCurrentMeetingListHolder()['current-meeting-list']) && !is_admin()) {
+ $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;
+ }
+ public static function arraySafeGet($arr, $i = 0)
+ {
+ return is_array($arr) ? $arr[$i] ?? '': '';
+ }
+ public static function getday($day, $abbreviate = false, $language = 'en')
+ {
+ $key = "WEEKDAYS";
+ if ($abbreviate) {
+ $key = "WKDYS";
+ }
+ return mb_convert_encoding(Bread::$instance->translate[$language][$key][$day], 'UTF-8', mb_list_encodings());
+ }
+ function fillUnsetOption($option, $default)
+ {
+ if (!isset($this->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;
+ }
+ }
+ }
+ public static function fillUnsetOptions()
+ {
+ Bread::$instance->fillUnsetOptionsInner();
+ }
+ function fillUnsetOptionsInner()
+ {
+ $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']);
+ }
+ public static function upgradeSettings()
+ {
+ Bread::$instance->upgrade_settings();
+ }
+ function upgrade_settings()
+ {
+ // 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'];
+ }
+ }
+ 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';
+ }
+ }
+ public static function updateOptions()
+ {
+ update_option(Bread::getOptionsName(), Bread::$instance->options);
+ }
+ public static function get_TransientKey($setting)
+ {
+ return '_bread__'.$setting;
+ }
+}
diff --git a/includes/default_nalogo.jpg b/includes/default_nalogo.jpg
deleted file mode 100644
index 830261375a2d615ffbee176c4d85688acfa68cb7..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 17191
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