mmenu wordpress plugin - bind open / close events - wordpress

I am using the licenced wordpress plugin version 3.1.0.
I have the menu working, but I cannot access the mmenu API to trigger the button open / close effect I would like to use. Previously I have used the mmenu core version [not WP plugin] and triggered the class changes using this:
var $menu = $("#menu").mmenu({...})
var API = $menu.data("mmenu");
API.bind("open:finish", function () {
$("#menu-btn").addClass("is-active");
});
API.bind("close:finish", function () {
$("#menu-btn").removeClass("is-active");
});
Modifying the var API to use the plugin generated id fails with undefined, probably because the menu creation is managed in a different script.
var API = $('#mm-1').data("mmenu"); //'mm-1' - the plugin generated mmenu id
I have also tried to use jQuery direct on #menu-btn but it is not triggered unless I remove the #menu-btn from the mmenu settings. For example [not copied, just a rough example so please ignore syntax errors]:
$("#menu-btn").click(function(){console.log('click')});
all I need is to add / remove an 'is-active' class to the open menu link [id=menu-btn].

The mmenu adds a body class when opened, so added a mutation observer to check if the has the .mm-wrapper--opened class or not. If it does, add the 'is-active' class to the menu icon (which uses the .hamburger class) and if not, remove it.
if ($('body').hasClass('mm-wrapper--opened')){
$('.hamburger').addClass("is-active");
}
const targetNode = document.body;
const config = { childList : true, attributes: true };
const callback = function(mutationsList, observer) {
for(let mutation of mutationsList) {
if (mutation.type === 'attributes') {
if ($('body').hasClass('mm-wrapper--opened')){
setTimeout(() => { $('.hamburger').addClass("is-active"); }, 500);
}
else {
$('.hamburger').removeClass("is-active");
}
}
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);

Related

Fullcalendar using resources as a function with select menu

Using Fullcalendar 4, I am trying to show/hide my resources using a select menu. When the user selects one of the providers from a menu, I want to only show that one resourc's events.
Above my fullcalendar I have my select menu:
<select id="toggle_providers_calendar" class="form-control" >
<option value="1" selected>Screech Powers</option>
<option value="2">Slater</option>
</select>
I am gathering the resources I need using an ajax call on my included fullcalendar.php page. I am storing them in an object and then trying to control which resources are shown onscreen:
document.addEventListener('DOMContentLoaded', function() {
var resourceData = [];
$.getJSON('ajax_get_json.php?what=schedule_providers_at_location',
function(data) {
$.each(data, function(index) {
resourceData.push({
id: data[index].value,
title: data[index].text
});
});
console.log(resourceData);
});
//below, set the visible resources to whatever is selected in the menu
//using 1 in order for that to show at start
var visibleResourceIds = ["1"];
//below, get the selected id when the the menu is changed and use that in the toggle resource function
$('#toggle_providers_calendar').change(function() {
toggleResource($('#toggle_providers_calendar').val());
});
var calendar_full = document.getElementById('calendar_full');
var calendar = new FullCalendar.Calendar(calendar_full, {
events: {
url: 'ajax_get_json.php?what=location_appointments'
},
height: 700,
resources: function(fetchInfo, successCallback, failureCallback) {
// below, I am trying to filter resources by whether their id is in visibleResourceIds.
var filteredResources = [];
filteredResources = resourceData.filter(function(x) {
return visibleResourceIds.indexOf(x.id) !== -1;
});
successCallback(filteredResources);
},
...
});
// below, my toggle_providers_calendar will trigger this function. Feed it resourceId.
function toggleResource(resourceId) {
var index = visibleResourceIds.indexOf(resourceId);
if (index !== -1) {
visibleResourceIds.splice(index, 1);
} else {
visibleResourceIds.push(resourceId);
}
calendar.refetchResources();
}
To make sure the getJSON is working, I have console.log(resourceData). The information in the console once it's gathered is:
[{id: '1', title: 'Screech Powers'}, {id: '2', title: 'Slater}]
... the above are the correct resources that can be chosen/rendered. So that seems to be okay.
On page load, no resources show at all, when resource id of '1' (Screech Powers) should be shown per my code. Well, at least, that's what I am trying to do right now.
When the menu changes, resources will show/hide, but not based on what's selected; the logic of only showing what is selected in the menu doesn't seem to be working.
I used to use a URL request for my resources: 'ajax_get_json.php?what=schedule_providers_at_location', and it worked fine! All resources show then their events properly. I am just trying to modify it by using a menu to show/hide the resources as needed.
Here's what I'm doing to make it happen so far! In case someone comes across this post ever, this will help.
Here's my code before my fullcalendar code.
var resourceData = [];
var visibleResourceIds = [];
$.getJSON('ajax_get_json.php?what=schedule_providers_at_location',
function(data) {
$.each(data, function(index) {
resourceData.push({
id: data[index].value,
title: data[index].text
});
});
});
$('#toggle_providers_calendar').change(function() {
toggleResource($('#toggle_providers_calendar').val());
});
My select menu with id 'toggle_providers_calendar' is the same as my original post. My fullcalendar resources as a function is the same too.
After the calendar is rendered, here are the changes I made to my toggle resources function:
// menu button/dropdown will trigger this function. Feed it resourceId.
function toggleResource(resourceId) {
visibleResourceIds = [];
//if select all... see if undefined from loading on initial load = true
if ((resourceId == '') || (resourceId === undefined)) {
$.map( resourceData, function( value, index ) {
visibleResourceIds.push(value.id);
});
}
var index = visibleResourceIds.indexOf(resourceId);
if (index !== -1) {
visibleResourceIds.splice(index, 1);
} else {
visibleResourceIds.push(resourceId);
}
calendar.refetchResources();
}
This causes the resources to show and hide properly. If the user selects "Show All" that works too!
In order to have a default resource show on load, I add this to my fullcalendar script:
loading: function(bool) {
if (bool) {
//insert code if still loading
$('.loader').show();
} else {
$('.loader').hide();
if (initial_load) {
initial_load = false;
//code here once done loading and initial_load = true
var default_resource_to_show = "<?php echo $default_provider; ?>";
if (default_resource_to_show) {
//set the menu to that provider and trigger the change event to toggleresrource()
$('#toggle_providers_calendar').val(default_provider).change();
} else {
//pass in nothing meaning 'select all' providers for scheduler to see
toggleResource();
}
}
}
},
I am using a bool variable of initial_load to see if the page was just loaded (basically not loading data without a page refresh). The bool of initial_load = true is set outside of DOMContentLoaded
<script>
//show selected date in title box
var initial_load = true;
document.addEventListener('DOMContentLoaded', function() {
My only current problem is that when toggleResource function is called, the all day vertical time block boundaries don't line up with the rest of the scheduler. Once I start navigating, they do, but I don't understand why it looks like this on initial load or when toggleResource() is called:
Any thoughts on how to correct the alignment of the allday vertical blocks?

React front end for Wordpress API - Adding content.rendered Only secure origins are allowed

Just as a preface, I am using create-react-app boiler plate.
I am trying to parse out a post from the wordpress API into a react component so I can extract all images and make them their own JSX objects. I need to have each post have its own on click method so I cant just use the dangerouslyaddHTML function in React.
Currently, I search through the string of json that had the rendered HTML from the WP content of each post and find all img tags. I then add then image src to an array and set this in my state.
However I am getting this error :
DOMException: Only secure origins are allowed
The site I have this currently hosted on it http://natalie.madeline-omoore.com/build/
The code for part of my component is below:
`componentDidMount(){
var owner;
for(var i = 0; i < this.props.categoryId.length; i++) {
if (this.props.categoryId[i].num === this.props.content.categories[0]) {
owner = this.props.categoryId[i].category;
this.setState({
catname: owner
})
break;
}
}
var theContent = this.props.content.content.rendered;
var output = $(theContent).find("img").map(function() {
return this.src;
}).get();
this.setState({
postImages: output
});
}
click(){
this.updateActive();
this.props.fix();
}
render() {
if (this.props.className === this.state.catname) {
return (
<div >
{ this.props.className === this.state.catname &&
<article className={`${this.state.catname}`} >
{this.state.postImages.map((image, i) =>
<ImageContain key={image} image={image} fix={this.props.fix} />
)}
</article>
}
</div>
);
} else {
return null;
}
}`
I am new to react so thank you!
This sounds like an issue with the 'service worker' that is default with create-react-app
You can deregister the worker by adding the following to index.js:
import { unregister } from './registerServiceWorker';
// ...
unregister();
Be sure to call unregister() after registerServiceWorker() is called.
You can learn more about this here: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#making-a-progressive-web-app
Good luck, and happy coding!

Integrate MPGS session.js in Aurelia SPA

I am trying to integrate the MasterCard Payment Gateway services to a SPA using Aurelia.
I am trying to use the hosted checkout mechanism to integrate MPGS.
I am writing code in the attached event of the Aurelia viewmodel to load the session.js library and on load of the library adding another script element to initialize the session.
The attached method is listed below.
this.mpgsSessionScript = `if (self === top) { var antiClickjack = document.getElementById("antiClickjack"); antiClickjack.parentNode.removeChild(antiClickjack); } else { top.location = self.location; } PaymentSession.configure({ fields: { card: { number: "#card-number", securityCode: "#card-cvv", expiryMonth: "#card-expiry-month", expiryYear: "#card-expiry-year" } }, frameEmbeddingMitigation: ["javascript"], callbacks: { initialized: function(response) { console.log(response); }, formSessionUpdate: function(response) { } } }); function pay() { PaymentSession.updateSessionFromForm('card'); }`;
this.styleElement = document.createElement('style');
this.styleElement.setAttribute('id', "antiClickjack");
this.styleElement.innerText = "body{display:none !important;}";
document.head.appendChild(this.styleElement);
this.scriptElement = document.createElement('script');
this.scriptElement.src = this.sessionJs;
this.scriptElement.onload = () => {
const innerScriptElement = document.createElement('script');
innerScriptElement.innerText = this.mpgsSessionScript;
document.body.appendChild(innerScriptElement);
};
document.body.appendChild(this.scriptElement);
I can successfully run the code the and the script elements are added to DOM and also, the antiClickjack style gets removed, which indicates that the script element gets added.
But the issue is, the card number and the cvv elements are not getting enabled for input. If successfully initialized, the card number and the cvv elements should get enabled.
I do not see any errors in the console. Any help would be appreciated.

Media editor backbone js: Get the current action

I'm creating a plugin that adds an option to the native WP gallery.
When a new gallery is created (clicking the "Create Gallery" button in the media popup), a 'select' element is added, and I have a backbone event listening for the 'change' event of this 'select'.
However, I only want to listen for the change event when the gallery is being newly created, rather than when editing an existing gallery.
My code so far is:
wp.media.view.Settings.Gallery = wp.media.view.Settings.Gallery.extend({
events: function() {
var the_events = {};
//NEED TO GET STATE (ie, 'creating gallery for first time' rather than 'edit gallery'....
var is_create_gallery = true;
//IF WE'RE EDITING, SET IT TO FALSE
//--here--
if (is_create_gallery) {
_.extend( the_events, { 'change select[data-setting="gallerytype"]' : 'gallerytypechanged' } );
}
return the_events;
},
gallerytypechanged: function( e ){
e.preventDefault();
var self = this;
var gallery_type = jQuery( e.currentTarget ).val();
if( gallery_type != 'native' ){
self.update.apply( self, ['gallerytype'] );
}
return self;
},
template: function(view) {
return wp.media.template('gallery-settings')(view) + wp.media.template('gallery-type')(view);
},
});
Basically the --here-- code should be a check to determine whether we're editing an existing gallery, or creating a new one.
Does anybody know where to check which state we're in?
Thanks!
I assume you can detect the state of the gallery outside of your Backbone View.
You could set the is_create_gallery state when initializing the backbone view, then call your view constructor with the custom argument:
var newGallery = // determine the gallery state
var view = new wp.media.view.Settings.Gallery({newGallery: newGallery});
You can access the passed argument in your initialize function like this:
initialize: function (options) {
if (options.newGallery) {
_.extend(this.events, {
'change select[data-setting="gallerytype"]' : 'gallerytypechanged'
});
}
}
Since your events map will be either empty or contain one event, I would remove the events key completely and do the events initialization from initialize.

Letting a user use a compiled RequireJS Widget after it has loaded

I'm writing a JS Widget using RequireJS. After finishing the widget I'm compiling it with r.js and Almond. All goes well - but I couldn't find an easy way to let the user use the widget without using RequireJS himself - as the widget code loads async (RequireJS uses AMD).
What I'm doing now is busy waiting for the widget code to load and using it only after detecting it has loaded. This is not very user-friendly.
Is there a way to let just do something like this?
var widget = new Widget();
instead of doing busy wait like:
count = 0;
function loadWidget() {
if (typeof Widget != 'undefined') {
var p1 = new Widget();
p1.render();
} else {
if (count > 10) {
console.log('Failed to load the Widget');
return false;
}
setTimeout(loadWidget, 50);
count++;
}
}
$(document).ready(function() {
loadWidget();
});
Thanks!
EDIT:
my build.js
({
name: './lib/almond.js',
out: './deploy/sdk.min.js',
baseUrl: '.',
optimize: 'uglify2',
mainConfigFile: 'sdk.js',
include: ['sdk'],
wrap: true
})
Code on the web page (assume no other script tags on page):
<script src="mywidget.js" data-main="scripts/sdk" id="mywidget"></script>
No sure if the 'data-main' is really required as the js is compiled.
You need to follow the instructions provided with Almond. To summarize the essential points what is in the doc there, what you need in your build config the following configuration:
wrap: {
startFile: 'path/to/start.frag',
endFile: 'path/to/end.frag'
}
And the start.frag should be:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define([], factory);
} else {
root.Widget = factory();
}
}(this, function () {
and the end.frag:
return require('main');
}));
The end fragment calls require in its synchronous form, which is really synchronous in this case (and not the pseudo-synchronous sugar that can be used by RequrieJS itself).
I've tried this before. It works.

Resources