Detect opening of PluginSidebar in Wordpress Gutenberg - wordpress

I'm looking to reinitialise some settings and state data when my PluginSidebar is reopened, but I'm struggling to find anything useful in wp.data core/editor or similar that I could use to best create a subscription.
Does gutenberg provide any such data where I can check to see if the side panel is open or shut, so that I could fire a function of my choice every time it opens?
At present, I have a mutationObserver in place listening to see if it opens, which is quite clunky.
Some pseudo-code of my preferred approach.
subscribe(() => {
if (select('core/editor').isPluginSidebarOpen()) {
open = true
} else {
open = false
}
})

Your pseudo-code is so very close.. the function exists and is called isPluginSidebarOpened and comes from core/edit-post, eg:
import { subscribe, select } from '#wordpress/data';
subscribe(() => {
if (select('core/edit-post').isPluginSidebarOpened()) {
// Is open..
} else {
// Is closed..
}
});

Related

Run code in specific part of URL in Iron Router

I have an application which makes heavy use of features, separated by specific users, which have different roles.
The problem is that I want to restrict access to some templates, if, for instance, the user is not an Admin.
Currently, I have this:
Router.route('createUser', {
path: '/admin/users/',
onBeforeAction: function() {
if(!isAdmin()) {
Router.go('/');
}
this.next();
}
});
But, specifying that if(isAdmin()) call to every other route is a pain. I want to know if there is any other easy and less error prone way to do it.
Maybe some regex magic would do, but I don't seem to find any examples of use.
First i will recommend you to read this meteor:common-mistakes on the profile editing part
So i will recommend you to better use the alanningroles-meteor package.
Is super easy to use, here is a Online DEMO and the Source Code if you have doubts.
On the router level you can create an onBefore hooks like this.
isAdmin = function(){
var currentUser = Meteor.user()
isUserSuperAdmin = Roles.userIsInRole(currentUser,'Super-Admin'); //using alaning roles.
if(isUserSuperAdmin){ //or use isAdmin();
this.next();
}else{
this.render('accessDenied')
}
}
Router.onBeforeAction('accessDenied', {only: ['admin','otherAdminRoute',etc]});
You can have an onBeforeAction hook combined with only for all routes like so:
var isAdmin = function() {
// Whatever logic you have for checking admin
if (!admin) {
Router.go("/");
}
this.next();
}
Router.onBeforeAction(isAdmin, {
only: ["admin/users"] // Specify other admin templates here
});

Is there any way to insert a callback before/after a templates context is updated?

I'm aware of Template.onRendered, however I have the need to destroy and setup some plugins that act on the dom when the actual context is updated.
So saying I have content template, I'd need something similar to the following:
Template.content.onBeforeChange(function () {
$(".editor").editable("destroy");
});
Template.content.onAfterChange(function () {
$(".editor").editable();
});
Is there any current way I can achieve this with the existing Template api?
You should be able to detect a context change within a template autorun by looking at currentData like this:
Template.content.onRendered(function() {
this.autorun(function() {
if (Template.currentData()) {
// the context just changed - insert code here
}
});
});
I'm unclear if that works for your particular case because this technique only gets you the equivalent of onAfterChange.

How to prevent navigating to another page in meteor iron router

I have a form page and I want to alert user if he leaves it without saving the form.
Typically I can achieve this purpose by stating a function window.onBeforeUnload.
window.onBeforeUnload = function(){return 'Please save the form before navigating';}
But it seems doesn't work in my project using Meteor and Iron Router.
Any suggestion?
This is maybe a hacky version, but it works:
isUnsaved = ->
return unless #ready()
unless confirm 'Do you really want to leave the page?'
Router.go(#url)
Router.onStop isUnsaved,
only: [
'editPost'
]
Old post, but just solved it. Here is my solution :
Router.route('/myPath', {
unload: function (e, obj) {
if(Session.get("hasChanged")){
if (confirm("Are you sure you want to navigate away ?")) {
// Go and do some action
}else{
// Redirect to itself : nothing happend
this.redirect('/myPath');
}
}
}
}

CodeMirror - AutoComplete "options" not setting right

I am using CodeMirror and attempting to do some CSS styling to the autocomplete pop up. This is a bit difficult, because I need it to not go away when I go to inspect styles and stuff.
So I hunted for a way to do this. I found this code in show-hint.js
if (options.closeOnUnfocus !== false) {
var closingOnBlur;
cm.on("blur", this.onBlur = function () { closingOnBlur = setTimeout(function () { completion.close(); }, 100); });
cm.on("focus", this.onFocus = function () { clearTimeout(closingOnBlur); });
}
If I comment this out, then the autocomplete pop up does not go away when I click on other things; That's what I wanted. But I thought I would explore this more and try to determine what to do to toggle this on and off at will.
So I wanted to be able to set this closeOnUnfocus option on my own. That seemed simple enough.
I cannot find a way to do this, though. Exploring further I found an example on code mirror's website that demonstrates a way to setup the autocomplete system using the following code;
CodeMirror.commands.autocomplete = function(cm) {
CodeMirror.showHint(cm, CodeMirror.hint.anyword);
}
Exploring further, show-hint.js starts out with a function called showHint that has this signature;
CodeMirror.showHint = function (cm, getHints, options) {
// We want a single cursor position.
if (cm.somethingSelected()) return;
if (getHints == null) {
if (options && options.async) return;
else getHints = CodeMirror.hint.auto;
}
if (cm.state.completionActive) cm.state.completionActive.close();
var completion = cm.state.completionActive = new Completion(cm, getHints, options || {});
CodeMirror.signal(cm, "startCompletion", cm);
if (completion.options.async)
getHints(cm, function (hints) { completion.showHints(hints); }, completion.options);
else
return completion.showHints(getHints(cm, completion.options));
};
Okay, so it stands to reason that I could accomplish what I want by passing my option through here; like this...
CodeMirror.commands.autocomplete = function (cm) {
CodeMirror.showHint(cm, CodeMirror.hint.anyword, {
closeOnUnfocus: false
});
}
But this doesn't work - in fact, it seems that the options just don't get passed at all. If I do a console.log in the show-hint.js, the options are outright ignored. They never get through.
So how can I pass options through? I am very confused.
If you want to change the styles of of the hint menu, just use the provided CSS hooks. There is no need to mess around with the autocomplete handlers. e.g.:
.CodeMirror-hints {
background-color: red;
}
.CodeMirror-hint {
background-color: green;
}
.CodeMirror-hint-active {
background-color: blue;
color: yellow;
}
And here's a live Demo.
I've just started to use Codemirror (v4.1) and I've found the same problem. After checking show-hint.js contents it seems that documentation is not updated.
Try to write this when you want to get the suggestions:
CodeMirror.showHint({hint: CodeMirror.hint.deluge, completeSingle: false, closeOnUnfocus: true});
If you need to use the async mode of getting suggestions (it was my case), now you have to do this before previous snippet:
CodeMirror.hint.deluge.async = true;
Hope this helps!
You can pass the options like this :
CodeMirror.showHint(cm,CodeMirror.hint.anyword,{completeSingle: false,closeOnUnfocus:false});
You can write the code as follows:
editor.on("keyup",function(cm){
CodeMirror.showHint(cm,CodeMirror.hint.deluge,{completeSingle: false});
});
It's working for me.

How do I handle dojo datagrid cell updates so I can post them back automatically to the server?

I am using dojo datagrid to display my data. When the end user edit the cell values it should be updated in the server using ajax calls(when the focus goes out of the cell).
Else, I should have a Edit & update/cancel buttons for each row to handle the same feature.
But I don know how to place edit & update buttons inside the grid and capture their events.
By default dojo updates only local the store value(client side). how can I save the updated cell values into the server?
do we need to write any override methods to do so??
I am new to dojo. Any detailed explanation or sample codes would be much appreciated.
Could anyone lend a hand to solve this issue??
Thank you
Regards,
Raj
To be able to push the updates server-side, you've to override _saveCustom() or _saveEverything(). Here is a piece of code (a bit cleaned-up) I'm using to persist an update.
Note that the code below relies on the private _getModifiedItems() because the DataGrid accepts inline editions. If you do know the list of modified items (because the edition is done in a popup and you keep the item key somewhere), retreiving the modified item is simpler.
module.submitUpdates = function() {
var store = <from a variable local to the module>
if (store.isDirty() confirm("Updates to be persisted. Continue?")) {
store._saveCustom = function(saveCompleteCallback, saveFailedCallback) {
var modifiedItem = _getModifiedItems(store)[0];
dojo.xhrPost( {
headers: { "content-type": "application/json; charset=utf-8" },
content: dojo.toJson(modifiedItem),
handleAs: "json",
load: function(response) {
if (response !== null && response.success) {
saveCompleteCallback();
}
else {
saveFailedCallback(response);
}
},
error: saveFailedCallback,
url: "/API/<Object>"
});
};
store.save( {
onComplete : function() {
module.loadCachingRuleList();
},
onError : function(errorData, request) {
_reportUpdateFailure(errorData, errMsg);
}
});
}
};
Here is the code I use to get all updated items when the user is about to loose an updated DataGrid (because he leaves the page or because he wants to refresh the grid content).
Note that the following code was using Dojo 1.3. I haven't check if it's easier with Dojo 1.4... I hope that dojo.Stateful that's going to be introduced in Dojo 1.5 will simplify it, otherwise we'll have to wait for Dojo 1.6 ;)
var _getModifiedItems = function(store) {
var modifiedItems = [];
if (store !== null && store._pending !== null) {
if (store._pending._modifiedItems !== null) {
for (var modifiedItemKey in store._pending._modifiedItems) {
if (store._itemsByIdentity) {
modifiedItems.push(store._itemsByIdentity[modifiedItemKey]);
}
else {
modifiedItems.push(store._arrayOfAllItems[modifiedItemKey]);
}
}
}
if (store._pending._newItems !== null) {
for (var modifiedItemKey in store._pending._newItems) {
if (store._itemsByIdentity) {
modifiedItems.push(store._itemsByIdentity[modifiedItemKey]);
}
else {
modifiedItems.push(store._arrayOfAllItems[modifiedItemKey]);
}
}
}
}
return modifiedItems;
};
var _getDeletedItems = function(store) {
var deletedItems = [];
if (store !== null && store._pending !== null && store._pending._deletedItems !== null) {
for (var deletedItemKey in store._pending._deletedItems) {
if (store._itemsByIdentity) {
deletedItems.push(store._itemsByIdentity[deletedItemKey]);
}
else {
deletedItems.push(store._arrayOfAllItems[deletedItemKey]);
}
}
}
return deletedItems;
};
I hope this helps,
A+, Dom
This isn't a very detailed explanation but yes you should override the method that handles user data entries as I don't see an event for this. So basically create a new class that inherits from the data grid, find the method in the source code that handles the editing and override it to give it an extra action to post it back to the server. You'll want to call the datagrid's default action in that method too.
Some information here (that you probably are already aware of):
http://docs.dojocampus.org/dojox/grid/DataGrid#editing-data
I've extended Dojo's default components before, it's not hard. I find that it's always good to examine the Dojo source and to just be careful when upgrading Dojo to make sure new versions don't break existing features.
To avoid hacking your dojo library, just switch to the YUI2 data table; it's cell editor accepts the asyncsubmitter function that sends your edits to your sever
This is the description from documentation
asyncSubmitter
Function
Implementer defined function that can submit the input value to a server. This function must accept the arguments fnCallback and oNewValue. When the submission is complete, the function must also call fnCallback(bSuccess, oNewValue) to finish the save routine in the CellEditor. This function can also be used to perform extra validation or input value manipulation.
YUI2DataTable

Resources