forked from kongondo/MenuBuilder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ProcessMenuBuilder.js
527 lines (468 loc) · 18.3 KB
/
ProcessMenuBuilder.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
/**
*
* Javascript file for PW Module ProcessMenuBuilder
*
* @author Francis Otieno (Kongondo) <[email protected]>
*
* https://github.com/kongondo/ProcessMenuBuilder
* Created March 2015, major update December 2017
*
*/
function ProcessMenuBuilder($) {
/*************************************************************/
// SCRIPT GLOBAL VARIABLES
/* @note:
- global variables NOT prefixed with '$'.
- function parameters and variables PREFIXED with '$'
*/
//var someVar, anotherVar;
/*************************************************************/
// FUNCTIONS
/**
* Asm Select: Hide children level inputs if selected page is 'Home'.
*
* @param object $sel The Asm Select.
*
*/
function hideAsmHomeChildrenLevelInputs($sel) {
var $opt = $sel.children('option[value="1"]');
var $rel = null;
if ($opt.length) {
$rel = $opt.attr("rel");
$("ol.asmList")
.children('li[rel="' + $rel + '"]')
.find("select.asm_include_children, input.asm_mb_max_level")
.addClass("hide");
}
}
/**
* Autocomplete: Hide children level inputs if selected page is 'Home'.
*
* @param object $i The Autocomplete input.
*
*/
function hideAutocompleteHomeChildrenLevelInputs() {
setTimeout(function () {
var $lastAdded = $('#item_addpages_items li:last');
var $lastAddedValue = $lastAdded.find('.itemValue').text();
if (1 === parseInt($lastAddedValue)) {
$lastAdded.find("select.ac_include_children, input.ac_mb_max_level")
.addClass("hide");
}
},100);// delay
}
/**
* Page Select Multiple Select: Hide children level inputs if selected page is 'Home'.
*
* @param object $a The 'add pages' anchor of the Page Select Multiple.
*
*/
function hidePageListSelectMultipleHomeChildrenLevelInputs($a) {
var $div = $a.closest("div.PageListItem");
if ($div.hasClass("PageListID1")) {
$('li.ui-state-default:not(".itemTemplate")')
.children("span.itemValue")
.filter(function() {
// Matches exact string
var $text = parseInt($(this).text());
return $text === 1;
})
.parent()
.find("select.pls_include_children, input.pls_mb_max_level")
.addClass("hide");
}
}
/**
* Toggle select/unselect all menu items in the list of menus table..
*
* @param object $i The (un)select all checkbox input.
*
*/
function toggleAllCheckboxes($i) {
if ($i.prop("checked")) $("input.toggle").prop("checked", true);
else $("input.toggle").prop("checked", false);
}
/**
* Used to force send (POST) new tab value of NEW custom menu items.
*
* @param object $i The checkbox for (un)setting NEW custom menu item to open in a new tab.
*
*/
function toggleNewTabValue($i) {
if ($i.prop("checked")) {
$i.val(1);
$i.parent().find("input.newtabhidden").val(1);
}
else {
$i.val(0);
$i.parent().find("input.newtabhidden").val(0);
}
}
/**
* Toggle show/hide panels in Build Tab.
*
*/
function togglePanels() {
/** toggle view/hide each menu's settings editor **/
$("div.settings").hide();
$(".item_expand_settings, .item_title_main").click(function() {
var $id = $(this).attr("data-id");
//$('#menu_edit'+id).toggle();
$("#menu_edit" + $id).slideToggle(500);
$("a")
.find('[data-id="' + $id + '"]')
.toggleClass("fa-caret-down")
.toggleClass("fa-caret-up");
});
/** Toggle view/hide add page menu items panel **/
$("#wrap_item_addpages").hide(); //hide li wrapper for add page menus items on load
$("#add_page_menu_items").click(function(e) {
// show/hide the asmSelect for adding page menu items
$("#wrap_item_addpages").toggle(250);
e.preventDefault(); //prevent default click <a> action from happening!
e.stopPropagation();
});
/** Toggle view/hide add custom menu items panel **/
$("#item_addcustom").hide(); //hide li wrapper for add custom menu items settings on load
$("#add_custom_menu_items").click(function(e) {
$("#item_addcustom").toggle(250);
e.preventDefault();
e.stopPropagation();
});
/** Toggle view/hide add pages selector menu items panel **/
$("#wrap_item_addselector").hide(); //hide div for add custom menu items settings on load
$("#add_selector_menu_items").click(function(e) {
$("#wrap_item_addselector").toggle(250);
e.preventDefault();
e.stopPropagation();
});
}
/**
* Clone a row in the custom menu items inputs' table.
*
* Used to add new custom menu items.
*
*/
function clonePageRow() {
var $tr = $("table.menu_add_custom_items_table tr:last");
var $clone = $tr.clone(true);
$clone.find("input[type=text]").attr("value", "");
$("table.menu_add_custom_items_table").append($clone);
$clone.find("input:first").focus();
return false;
}
/**
* Remove row from the custom menu items inputs' table.
*
* @param object $a The trash icon anchor.
*
*/
function removeTr($a) {
var $tr = $a.closest("tr");
if ($tr.prev("tr").find("input").length) $tr.remove();
return false;
}
/**
* Remove a menu item added to the menu items tree/list.
*
* Used in the menu sortable list.
*
* @param object $a The trash icon anchor.
*
*/
function removeMenuItem($a) {
var $li = $a.closest("li");
$li.remove();
return false;
}
/**
* Remove all menu items.
*
* Used in the menu sortable list.
*
*/
function removeAllMenuItems() {
$("ol.sortable").empty();
}
/**
* Hide other buttons when on delete tab, and restore them when leaving delete tab.
*
* Copied from ProcessPageEdit.js
*
* @param object $newTab The tab we are changing to.
* @param object $oldTab The tab we've just left.
*
*/
function toggleShowSaveButtons($newTab, $oldTab) {
if($newTab.attr('id') == 'ProcessMenuBuilderDelete') {
$(".InputfieldSubmit:not(#wrap_submit_delete):visible").addClass('hide').hide();
} else if($oldTab.attr('id') == 'ProcessMenuBuilderDelete') {
$(".InputfieldSubmit.hide").removeClass('hide').show();
}
}
/**
* Check and trigger deletion of a single menu being edited.
*
* @param object $b The delete menu button.
*
*/
function menuDeleteConfirm($b) {
if (!$("#menu_delete_confirm").is(":checked")) {
$("#wrap_menu_delete_confirm label").effect("highlight", {}, 500);
return;
}
$b.before("<input type='hidden' name='menu_delete' value='1'>");
$("#MenuBuilderEdit").submit();
}
/**
* Inserts the extraheader labels in the Page select list items.
*
* These are for CSS ID, Class, Include Children and Max Level.
* These are used in the modified select markup (autocomplete, asm and page list select multiple).
*
*/
function pagesSelectMBAddExtraLabels() {
var $headers = $('div#menu_items_headers');
$("#item_addpages_items,ol.asmList").before($headers);
}
/**
* Get the general menu configs sent by the module ProcessMenuBuilder.
*
* @return object|false $jsProcessMenuBuilderConfigs Return configurations if found, else false.
*
*/
function processMenuBuilderConfigs() {
// general menu configs
var $jsProcessMenuBuilderConfigs = config.ProcessMenuBuilder;
if (!jQuery.isEmptyObject($jsProcessMenuBuilderConfigs)) return $jsProcessMenuBuilderConfigs;
else return false;
}
/**
* Get the configs sent by the module ProcessMenuBuilder for Nested Sortable.
*
* @return object|false $jsNestedSortableConfigs Return configurations if found, else false.
*
*/
function processMenuBuilderNestedSortableConfigs() {
// Nested Sortable configs
var $jsNestedSortableConfigs = config.ProcessMenuBuilderNestedSortable;
if (!jQuery.isEmptyObject($jsNestedSortableConfigs)) return $jsNestedSortableConfigs;
else return false;
}
/**
* Set the configs sent by the module ProcessMenuBuilder for Nested Sortable.
*
*/
function setNestedSortableConfigs($jsNestedSortableConfigs) {
$("ol.sortable").nestedSortable({
rootID: 0, // name given to items at the root level; default is null
disableNesting: "mjs-nestedSortable-no-nesting",
forcePlaceholderSize: true,
handle: "div",
helper: "clone",
listType: "ol",
items: "li",
opacity: 0.6,
placeholder: "placeholder",
revert: 250,
tolerance: "pointer",
toleranceElement: "> div",
containment: "ol#sortable_main",
//****** custom ******
maxLevels: $jsNestedSortableConfigs.config.maxLevels,
//disableParentChange: $jsNestedSortableConfigs.config.disableParentChange,//@todo -not working; stops drag n drop
expandOnHover: $jsNestedSortableConfigs.config.expandOnHover,
//protectRoot: $jsNestedSortableConfigs.config.protectRoot,//@@todo - unsure: //@todo -not working; stops drag n drop
//rtl: $jsNestedSortableConfigs.config.rtl,//@todo -not working; stops drag n drop
startCollapsed: $jsNestedSortableConfigs.config.startCollapsed,
tabSize: $jsNestedSortableConfigs.config.tabSize,
doNotClear: $jsNestedSortableConfigs.config.doNotClear
/*isTree: $jsNestedSortableConfigs.config.isTree,*/ //@todo -not working; stops drag n drop
//disableNesting: //@todo - not sure whether to add this
});
}
/**
* Initiate WireTabs for use in the Process Module.
*
*/
function initWireTabs() {
var $form = $("#MenuBuilderEdit");
// remove scripts, because they've already been executed since we are manipulating the DOM below (WireTabs)
// which would cause any scripts to get executed twice
$form.find("script").remove();
// init Wire Tabs for this form
$form.WireTabs({
items: $(".WireTab"),
skipRememberTabIDs: ["ProcessMenuBuilderDelete"],
rememberTabs: true
});
}
/**
* Initiate Sortable on menu items.
*
* Used in the menu sortable list drag and drop.
* This is used to create relationships between menu items (parent, child, etc).
*
*/
function initMenuSortable() {
$("div#menu_sortable_wrapper .sortable").sortable({
// FUNCTION TO CAPTURE PARENT IDs OF MENU ITEMS ON DRAG & DROP EVENT AND SAVE THESE FOR EACH MENU ITEM [in their individual hidden fields]
update: function(event, ui) {
// create an array of menu item_id's and their parent_id's. Update parent ids at the finish of the drag/drop event [function - toArray]
var $order = $(".sortable").sortable("toArray");
// loop through the values [this is a 2 dimensional object ]
for (var $key in $order) {
// the item id; retrieved via the key 'item_id' which is the name given by toArray
var $id = $order[$key].item_id;
var $parent = $order[$key].parent_id; // the parent id
// update each menu item's hidden parent field value to store the new parent
$("#item_parent" + $id).val($parent);
/*
* note:
* Here we look for the id that matches the item_id, e.g. #item_parent5.
* This matching ensures correct assignment of parentage.
* Note, item_parent id is not the ID of the PW page parent!
* The ID of the parent is the value of this input field, item_parent[]. Need the item_parent{$id} here for convenience.
*
*/
}
}
});
}
/**
* Sets the active menu item in a Multi Lingual setup.
*
* Used in cases where no active menu has been set.
*
* @param object $s The span representing the menu item title.
*
*/
function multilingualSetActiveMenuItemLanguage($s) {
var $p = $s.parent();
var $c = $p.next("div.settings").children("div.menu_edit_language_selector");
var $s = $c.find("span.menu_language_active");
if (!$s.length) {
var $f = $c.find("span.menu_language_selector ").filter(":first");
$f.addClass("menu_language_active");
var $id = $f.attr("data-language");
$("div#" + $id).show();
}
}
/**
* Language tab selector for menu items in a Multi Lingual setup.
*
*/
function multilingualLanguageSelector($s) {
$s.siblings(".menu_language_selector").removeClass("menu_language_active");
$s.addClass("menu_language_active");
var $id = $s.attr("data-language");
var $p = $s.parent();
$p.next("div.menu_language_wrapper").children().hide();
$("div#" + $id).show();
}
/**
* Initialise this script.
*
*/
function init() {
/* 01. #### WIRE TABS #### */
initWireTabs();
/* 02. #### MENU ITEMS LIST TABLE #### */
/** Fix for MarkupAdminDataTable: Don't enable sorting on first column with input checkbox **/
//if ($.tablesorter != undefined) $.tablesorter.defaults.headers = {0:{sorter:false}};
//if we are NOT on the menu items table, for sortable tables, disable sorting on first column
if (!$("table").hasClass("no_disable")) {
if ($.tablesorter != undefined)
$.tablesorter.defaults.headers = { 0: { sorter: false } }; //works but requires two clicks to kick-in!
}
/* on change in select to limit menus show in table */
//note: broken in PW dev 2.5.7. See issue #784 on GitHub - removeClass() fix
$("#limit").change(function() {
$(this).closest("form").removeClass("nosubmit").submit();
}); // @note workaround for PW issue #784 (GitHub)
/** Toggle all checkboxes in the list of menus table **/
$(document).on("change", "input.toggle_all", function () {
toggleAllCheckboxes($(this));
});
/* 03. #### BUILD MENU TAB #### */
/** MB CUSTOM AsmSelect OUTPUT **/
$(".InputfieldAsmSelect select[multiple=multipleMB]").each(function() {
var $t = $(this);
var $options;
if (typeof config === "undefined") $options = { sortable: true };
else $options = config[$t.attr("id")];
$t.asmSelectMB($options); // asmSelectMB() is our modified AsmSelect's function (see jquery.asmselect-mb.js)
});
/** insert extraheader labels in the Page select list items **/
pagesSelectMBAddExtraLabels();
/** Add a tr **/
$("form#MenuBuilderEdit").on("click", "a.addrow", function() {clonePageRow()});
/** Remove a tr **/
$("form#MenuBuilderEdit").on("click", "a.remove_row", function () { removeTr($(this)) });
/** Remove a menu item **/
$("form#MenuBuilderEdit").on("click", "a.remove_menu", function () { removeMenuItem($(this)) });
/** Remove all menu items **/
$("form#MenuBuilderEdit").on("click", "a#remove_menus", function (e) {
e.preventDefault();
removeAllMenuItems();
});
/** Toggle view/hide panels **/
togglePanels();
/** Hide children level inputs if selected item page is 'Home' **/
// for modified InputfieldAsmSelect::render
$(document).on("change", "select.asmSelect", function () { hideAsmHomeChildrenLevelInputs($(this)) });
// for modified InputfieldPageAutocomplete::render
$("input#item_addpages_input").on("autocompletechange", function (event, ui) {
hideAutocompleteHomeChildrenLevelInputs();
});
// for modified InputfieldPageListSelectMultiple::render
$(document).on("click", "li.PageListActionSelect a", function () {
hidePageListSelectMultipleHomeChildrenLevelInputs($(this))
});
/** @note: for testing tab changes **/
/* $(document).on('wiretabclick', function($event, $newTab, $oldTab) {
console.log("Tab changed to: " + $newTab.attr('id'));
});
*/
/** hide other buttons when on delete tab, and restore them when leaving delete tab **/
$(document).on('wiretabclick', function(event, $newTab, $oldTab) {
toggleShowSaveButtons($newTab, $oldTab);
});
/** Force send custom items new tab value **/
// we use a hidden input to send value based on 'checked' propert of new_tab checkbox
// Toggle value of new tab + closest corresponding hidden input
$("input.newtab").change(function () {toggleNewTabValue($(this))});
/* 04. #### NESTEDSORTABLE CONFIGS #### */
// nestedSortable custom configs for each menu (defined in ProcessMenuBuilder::nestedSortableConfigs())
var $jsNestedSortableConfigs = processMenuBuilderNestedSortableConfigs();
if ($jsNestedSortableConfigs) setNestedSortableConfigs($jsNestedSortableConfigs);
/** Sortable menu items **/
initMenuSortable();
/* 05. #### DELETE MENU TAB #### */
// trigger a submit_delete submission. this is necessary because when submit_delete is an <input type='submit'> then
// some browsers call it (rather than submit_save) when the enter key is pressed in a text field. This solution
// by-passes that undesirable behavior.
$("#menu_delete").click(function () {menuDeleteConfirm($(this))});
/* 06. #### MULTI LINGUAL #### */
// @note: only check if in multi lingual site
var $jsProcessMenuBuilderConfigs = processMenuBuilderConfigs();
if ($jsProcessMenuBuilderConfigs) {
var $multiLingualUse = $jsProcessMenuBuilderConfigs.config.multilingual;
if ($multiLingualUse) {
/** Multi Lingual: if no active menu, set first language as active **/
$("div.handle").on("click", "span.item_title_main", function () { multilingualSetActiveMenuItemLanguage($(this)) });
/** Multi Lingual: language selector **/
$("div#menu_sortable_wrapper" ).on("click", "span.menu_language_selector", function() {
multilingualLanguageSelector($(this));
});
}
}
}
// initialise script
init();
}// END ProcessMenuBuilder()
/*************************************************************/
// READY
jQuery(document).ready(function($) {
ProcessMenuBuilder($);
});