Wordpress―run JS after Widget was created in Admin panel - widget

I am developing a Wordpress Theme that includes a custom Widget, everything works out fine but there is one thing I do not know how to implement correctly:
I would like to run some Javascript after the Widget Instance was created in the admin panel, that means in the very moment after the widget was dropped in a sidebar, not after saving.
I have no Problems with running JS after the page was loaded or the Widget was saved, I want to run Javascript after the User just dropped a new Instance into the side bar, what actually can happen more than once without page reload.
Greetings philipp

Another way of doing this I just figured out --
I'm going to show a more complex example involving dependencies, though realise the bit in Custom_Widget::form() is the real answer to the question:
function add_js_deps() {
if (is_admin()) {
wp_enqueue_script('jquery-ui-accordion');
}
}
add_action( 'init', 'add_js_deps' ); // "init" because wp_enqueue_scripts is too late.
// Then in the widget....
class Custom_Widget extends WP_Widget {
public function form($instance) {
/** Collapsing accordion-y form HTML here **/
wp_enqueue_script('custom-js', plugins_url('js/my.js', __FILE__), array('jquery-ui-accordion'), '1.0.0', true);
}
}
I'd argue this is the better route as it has dependency management and you won't have a bunch of JavaScript mid-way into your DOM. Using wp_enqueue_script is generally always the more WordPressian way of doing things regardless.

Place a script tag in the widget form function.
function form($instance)
{
?><script type="text/javascript">console.log("firing javascript");</script>
<?php
//form details...
}
I eventually went a different way with this. Loaded our plugin admin script on the page using wp_enque_script and then just used jquery selectors and an event handler to target the right widget.
$('div.widgets-sortables')
.on('sortstop', function (event, ui) {
// only if this widget has the proper identifier...do something
if (ui.item.find('.my_widget').length == 0)
return;
run some function...
Still not my favourite technique...but it is cleaner then coding it in the widget. Does require a variable to track created widgets and using the "this" variable is useful

Related

Swing JTabbedPane : addChangeListener or addContainerListener or both?

I have one swing code written by other person. For swing tabbed pane, he has added both change and container listener and both calls the same method:
addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent theEvent ) {
someMethod();
}
} );
addContainerListener(new ContainerAdapter() {
public void componentAdded(ContainerEvent theEvent) {
someMethod();
}
public void componentRemoved(ContainerEvent theEvent) {
someMethod();
}
} );
Whenever tab is removed from this tabbed pane, it internally calls JTabbedPane.removeTabAt(int index), which in turn calls fireStateChanged() causing new change event listened by change listener.
Now as new component (tab) is removed from tabbed pane, it also calls componentRemoved(ContainerEvent theEvent) method of container listener.
Both change even and container events, then calls same method someMethod(), which does set background and foreground colors.
I would like to know, if this kind code might cause some issues. Recently we are facing random IndexOutOfBoundException exeptions. I am just wondering, if this is causing this issue.
Also as per my understanding in swing, once event is listened, logic inside it should be executed using worker thread (e.g. SwingWorker). Please let me know if this is correct.
I am new to swing, thus any hint would be appreciated.
Thanks.
Whenever tab is removed from this tabbed pane, it internally calls
JTabbedPane.removeTabAt(int index), which in turn calls
fireStateChanged() causing new change event listened by change
listener.
This is true if the removed tab is also the selected tab. In the other cases, you won't be notified.
You need to choose what event you want to listen to:
Addition/Removal of components?--> go for ContainerListener
Selected tab? --> go for ChangeListener
I would like to know, if this kind code might cause some issues.
Recently we are facing random IndexOutOfBoundException exeptions. I am
just wondering, if this is causing this issue.
Since there is no line in your sample code that could throw that Exception, it is impossible to answer your question. Post an SSCCE that shows your issue.
Also as per my understanding in swing, once event is listened, logic
inside it should be executed using worker thread (e.g. SwingWorker).
Please let me know if this is correct.
It depends:
If you need to modify anything in the UI, anything related to Swing, it needs to be executed on the EDT (Event Dispatching Thread) and thus, SwingWorker is not an option.
If you need to perform business logic operations, and especially if they can be lengthy, then you should indeed use a SwingWorker or any other mechanism to execute that code in another thread than the EDT. Consider visiting the Swing tag wiki on "Concurrency"

View instantiating another view

I'm separating my code similar to MVC (models, views, and controllers).
Let's say I have two view classes, one is conceptually a page (contains many items) and another is just a widget (like a list of recent news).
Here are the ways I see of doing it:
The controller instantiates both the page and widget classes, then passes the widget object into the page. If the page has a lot of widgets, I'd have to figure out how to pass it all in without it being confusing.
class PageController {
function foo() {
Widget widget1 = new Widget();
Widget widget2 = new Widget();
Page page = new Page(widget1, widget2);
}
}
class Page {
function Page(Widget widget1, Widget widget2) {
//do something with the widgets
}
}
The page instantiates the widget class. But now the page class has references to all sorts of views instead of being able to place the view where ever as long as it has the appropriate interface.
class PageController {
function foo() {
Page page = new Page();
}
}
class Page {
function Page() {
Widget widget1 = new Widget();
Widget widget2 = new Widget();
//do something with the widgets
}
}
Something else?
What is your advice and why?
Thank you.
I actually side with approach 1 in some ways. I would say Page should be able to be instantiated with or without widgets. You can add a collection of widgets to begin with and/or one at a time through some other provision within the Page as you run through your business logic and rules.
This gives you more flexibility to modify the construction of page as you go.
Widgets contain information on how they function and their presentation within the layout of the page.
Page should only be responsible for getting the information/instructions from the contained widgets and initialize/render them.
This will allow for a more flexible and fluid design.
Conceptually, #2 makes the most sense to me.
It's perfectly fine to have coupling between views if one type of view contains another. For example, it should be the page's job to manage where to place each widget, when to hide certain widgets etc.
However, the page shouldn't care about events pertaining to those widgets unless it needs to. If a widget has a button, it should just callback to a controller and skip telling the page... unless it causes the widget to be resized and the page needs to lay things out differently.
Hopefully this is useful to you.

create a link that opens a page and runs a function contained in the link

I am still learning PHP so my question may seem a little obvious but...
My question relates to opencart but is probably quite a common practice on many websites. I am creating a opencart module and in that module i have several buttons that complete different tasks. Now I have assigned the button the correct 'href' with the path and appropriate action. eg
$this->data['dosomething'] = $this->url->link('module/modulename/dosomething', 'token=' . $this->session->data['token'], 'SSL');
Note: I have called the module and action a general name for the purposes of my question.
In the controller I then have a private function called 'index', followed by a private function called 'dosomething' like below
public function index() {
* insert code *
}
public function dosomething() {
*insert code*
$this->redirect($this->url->link('module/modulename', 'token=' . $this->session->data['token'], 'SSL'));
}
Now, I would like to know how do I get the button to direct to the module controller and then run the 'dosomething' function. I could put something information in the link, ie action=dosomething and do it this way but most of opencart simply uses the text of the last / as the action. If I use the href stated above I get a error as it is trying to find the controller and template located in 'module/modulename/dosomething' rather than the controller and template located in 'module/modulename' USING the function 'dosomething'.
I hope this makes sense. I see that many other scripts in opencart successfully use this method but I just cant figure out how? I am sure I missing something obvious.
What you are doing is correct. OpenCart's framework will use the third piece of the route if specified as the method. If you try
public function dosomething() {
die('OK');
}
Then go to the url you've got, it should just show a blank white page with OK written on it. My guess is the error doesn't actually relate to the controller being an issue, and more to do with something else you've done. Either that, or the method and the third part of the route aren't a match, or the dosomething method isn't public

All-in-one location/hashchange history management library

First of all, I know there's libraries that provide polyfills for location.pushState/popState (History.js, Hash.js, jQuery hashchange), so please don't just link to those.
I need a more powerful library to achieve the following in a RIA:
User clicks a link
library is notified and loads context via Ajax (no complete reload!)
All <a> elements are leveraged with a click handler that
prevents page reloads in 2. (preventDefault) and
calls location.pushState instead / sets location.hash for older browsers
loaded content is inserted in page and replaces current content
Continue with 1.
Also, previously loaded content should be restored as the user navigates back.
As an example, klick through Google+ in Internet Explorer <10 and any other browser.
Is there anything that comes even close? I need support for IE8, FF10, Safari 5 and Chrome 18. Also, it should have a permissive license like MIT or Apache.
I believe Sammy.js ( http://sammyjs.org) (MIT-licenced) has the best focus on what you want to do, with its 2 main pillars being:
Routes
Events
I could quote from the docs but it's pretty straightforward:
setup clientside routes that relate to stuff to be done, e.g: update the view through ajax
link events to call routes, e.g: call the route above when I click an link. (You would have to make sure e.preventDefault is called in the defined event I believe, since this is an app decision really, so that can't be abstracted away by any library that you're going to use imho)
Some relevant docs
http://sammyjs.org/docs
http://sammyjs.org/docs/routes
http://sammyjs.org/docs/events
Example for a route: (from http://sammyjs.org/docs/tutorials/json_store_1)
this.get('#/', function(context) {
$.ajax({
url: 'data/items.json',
dataType: 'json',
success: function(items) {
$.each(items, function(i, item) {
context.log(item.title, '-', item.artist);
});
}
});
});
Or something like
this.get('#/', function(context) {
context.app.swap(''); ///the 'swap' here indicates a cleaning of the view
//before partials are loaded, effectively rerendering the entire screen. NOt doing the swap enables you to do infinite-scrolling / appending style, etc.
// ...
});
Of course other clientside MVC-frameworks could be an option too, which take away even more plumbing, but might be overkill in this situation.
a pretty good (and still fairly recent) comparison:
http://codebrief.com/2012/01/the-top-10-javascript-mvc-frameworks-reviewed/
( I use Spine.js myself ) .
Lastly, I thought it might be useful to include an answer I've written a while ago that goes into detail to the whole best-practice (as I see it) in client-side refreshes, etc. Perhaps you find it useful:
Accessibility and all these JavaScript frameworks
I currently use PathJS in one of my applications.
It has been the best decision that i have made.
For your particular usecase take a look at HTML5 Example.
The piece of code that that makes the example work (from the source):
<script type="text/javascript">
// This example makes use of the jQuery library.
// You can use any methods as actions in PathJS. You can define them as I do below,
// assign them to variables, or use anonymous functions. The choice is yours.
function notFound(){
$("#output .content").html("404 Not Found");
$("#output .content").addClass("error");
}
function setPageBackground(){
$("#output .content").removeClass("error");
}
// Here we define our routes. You'll notice that I only define three routes, even
// though there are four links. Each route has an action assigned to it (via the
// `to` method, as well as an `enter` method. The `enter` method is called before
// the route is performed, which allows you to do any setup you need (changes classes,
// performing AJAX calls, adding animations, etc.
Path.map("/users").to(function(){
$("#output .content").html("Users");
}).enter(setPageBackground);
Path.map("/about").to(function(){
$("#output .content").html("About");
}).enter(setPageBackground);
Path.map("/contact").to(function(){
$("#output .content").html("Contact");
}).enter(setPageBackground);
// The `Path.rescue()` method takes a function as an argument, and will be called when
// a route is activated that you have not yet defined an action for. On this example
// page, you'll notice there is no defined route for the "Unicorns!?" link. Since no
// route is defined, it calls this method instead.
Path.rescue(notFound);
$(document).ready(function(){
// This line is used to start the HTML5 PathJS listener. This will modify the
// `window.onpopstate` method accordingly, check that HTML5 is supported, and
// fall back to hashtags if you tell it to. Calling it with no arguments will
// cause it to do nothing if HTML5 is not supported
Path.history.listen();
// If you would like it to gracefully fallback to Hashtags in the event that HTML5
// isn't supported, just pass `true` into the method.
// Path.history.listen(true);
$("a").click(function(event){
event.preventDefault();
// To make use of the HTML5 History API, you need to tell your click events to
// add to the history stack by calling the `Path.history.pushState` method. This
// method is analogous to the regular `window.history.pushState` method, but
// wraps calls to it around the PathJS dispatched. Conveniently, you'll still have
// access to any state data you assign to it as if you had manually set it via
// the standard methods.
Path.history.pushState({}, "", $(this).attr("href"));
});
});
</script>
PathJS has some of the most wanted features of a routing library:
Lightweight
Supports the HTML5 History API, the 'onhashchange' method, and graceful degredation
Supports root routes, rescue methods, paramaterized routes, optional route components (dynamic routes), and Aspect Oriented Programming
Well Tested (tests available in the ./tests directory)
Compatible with all major browsers (Tested on Firefox 3.6, Firefox 4.0, Firefox 5.0, Chrome 9, Opera 11, IE7, IE8, IE9)
Independant of all third party libraries, but plays nice with all of them
I found the last too points most attractive.
You can find them here
I hope you find this useful.
i'd like to suggest a combination of
crossroads.js as a router
http://millermedeiros.github.com/crossroads.js/
and hasher for handling browser history and hash urls (w/ plenty of fallback solutions):
https://github.com/millermedeiros/hasher/
(based on http://millermedeiros.github.com/js-signals/)
This will still require a few lines of code (to load ajax content etc.), but give you loads and loads of other possibilities when handling a route.
Here's an example using jQuery (none of the above libraries require jQuery, i'm just lazy...)
http://fiddle.jshell.net/Fe5Kz/2/show/light
HTML
<ul id="menu">
<li>
foo
</li>
<li>
bar/baz
</li>
</ul>
<div id="content"></div>
JS
//register routes
crossroads.addRoute('foo', function() {
$('#content').html('this could be ajax loaded content or whatever');
});
crossroads.addRoute('bar/{baz}', function(baz) {
//maybe do something with the parameter ...
//$('#content').load('ajax_url?baz='+baz, function(){
// $('#content').html('bar route called with parameter ' + baz);
//});
$('#content').html('bar route called with parameter ' + baz);
});
//setup hash handling
function parseHash(newHash, oldHash) {
crossroads.parse(newHash);
}
hasher.initialized.add(parseHash);
hasher.changed.add(parseHash);
hasher.init();
//add click listener to menu items
$('#menu li a').on('click', function(e) {
e.preventDefault();
$('#menu a').removeClass('active');
$(this).addClass('active');
hasher.setHash($(this).attr('href'));
});​
Have you looked at the BigShelf sample SPA (Single Page Application) from Microsoft? It sounds like it covers how to achieve most of what you're asking.
It makes use of History.js, a custom wrapper object to easily control navigation called NavHistory and Knockout.js for click handling.
Here's an extremely abbreviated workflow of how this works: first you'll need to initialize a NavHistory object which wraps history.js and registers a callback which executes when there is a push state or hash change:
var nav = new NavHistory({
params: { page: 1, filter: "all", ... etc ... },
onNavigate: function (navEntry) {
// Respond to the incoming sort/page/filter parameters
// by updating booksDataSource and re-querying the server
}
});
Next, you'll define one or more Knockout.js view models with commands that can be bound to links buttons, etc:
var ViewModel = function (nav) {
this.search = function () {
nav.navigate({ page: 2, filter: '', ... }); // JSON object matching the NavHistory params
};
}
Finally, in your markup, you'll use Knockout.js to bind your commands to various elements:
<a data-bind="click: search">...</a>
The linked resources are much more detailed in explaining how all of this works. Unfortunately, it's not a single framework like you're seeking, but you'd be surprised how easy it is to get this working.
One more thing, following the BigShelf example, the site I'm building is fully cross-browser compatible, IE6+, Firefox, Safari (mobile and desktop) and Chrome (mobile and desktop).
The AjaxTCR Library seems to cover all bases and contains robust methods that I haven't seen before. It's released under a BSD License (Open Source Initiative).
For example, here are five AjaxTCR.history(); methods:
init(onStateChangeCallback, initState);
addToHistory(id, data, title, url, options);
getAll();
getPosition();
enableBackGuard(message, immediate);
The above addToHistory(); has enough parameters to allow for deep hash-linking in websites.
More eye-candy of .com.cookie(), .storage(), and .template() provides more than enough methods to handle any session data requirements.
The well documented AjaxTCR API webpage has a plethora of information with downloadable doc's to boot!
Status Update:
That website also has an Examples Webpage Section including downloadable .zip files with ready to use Front End(Client) and Back End(Server) project files.
Notably are the following ready-to-use examples:
One-way Cookie
HttpOnly Cookies
History Stealing
History Explorer
There are quite a bit other examples that rounds out the process to use many of their API methods, making any small learning curve faster to complete.
Several suggestions
ExtJs, see their History Example, and here are the docs.
YUI Browser History Manager.
jQuery BBQ seem to provide a more advanced feature-set over jQuery.hashcode.
ReallySimpleHistory may also be of help, though it's quite old and possibly outdated.
Note: ExtJs History has been extended to optimize duplicate (redundant) calls to add().
PJAX is the process you're describing.
The more advanced pjax techniques will even start to preload the content, when the user hovers over the link.
This is a good pjax library.
https://github.com/MoOx/pjax
You mark the containers which need will be updated on the subsequent requests:
new Pjax({ selectors: ["title", ".my-Header", ".my-Content", ".my-Sidebar"] })
So in the above, only the title, the .my-header, .my-content, and .my-sidebar will be replaced with the content from the ajax call.
Somethings to look out for
Pay attention to how your JS loads and detects when the page is ready. The javascript will not reload on new pages. Also pay attention to when any analytics calls get called, for the same reason.

How do I access the popup page DOM from bg page in Chrome extension?

In Google Chrome's extension developer section, it says
The HTML pages inside an extension
have complete access to each other's
DOMs, and they can invoke functions on
each other. ... The popup's contents
are a web page defined by an HTML file
(popup.html). The popup doesn't need
to duplicate code that's in the
background page (background.html)
because the popup can invoke functions
on the background page
I've loaded and tested jQuery, and can access DOM elements in background.html with jQuery, but I cannot figure out how to get access to DOM elements in popup.html from background.html.
can you discuss why you would want to do that? A background page is a page that lives forever for the life time of your extension. While the popup page only lives when you click on the popup.
In my opinion, it should be refactored the other way around, your popup should request something from the background page. You just do this in the popup to access the background page:
chrome.extension.getBackgroundPage()
But if you insist, you can use simple communication with extension pages with sendRequest() and onRequest. Perhaps you can use chrome.extension.getViews
I understand why you want to do this as I have run into the problem myself.
The easiest thing I could think of was using Google's method of a callback - the sendRequest and onRequest methods work as well, but I find them to be clunky and less straightforward.
Popup.js
chrome.extension.getBackgroundPage().doMethod(function(params)
{
// Work with modified params
// Use local variables
});
Background.html
function doMethod(callback)
{
if(callback)
{
// Create/modify params if needed
var params;
// Invoke the callback
callback(params);
}
}
As other answers mention, you can call background.js functions from popup.js like so:
var _background = chrome.extension.getBackgroundPage();
_background.backgroundJsFunction();
But to access popup.js or popup.html from background.js, you're supposed to use the messages architecture like so:
// in background.js
chrome.runtime.sendMessage( { property: value } );
// in popup.js
chrome.runtime.onMessage.addListener(handleBackgroundMessages);
function handleBackgroundMessages(message)
{
if (message.property === value)
// do stuff
}
However, it seems that you can synchronously access popup.js from background.js, just like you can synchronously access the other way around. chrome.extension.getViews can get you the popup window object, and you can use that to call functions, access variables, and access the DOM.
var _popup = chrome.extension.getViews( { type: 'popup' } )[0];
_popup.popupJsFunction();
_popup.document.getElementById('element');
_popup.document.title = 'poop'
Note that getViews() will return [] if the popup is not open, so you have to handle that.
I'm not sure why no one else mentioned this. Perhaps there's some pitfalls or bad practices to this that I've overlooked? But in my limited testing in my own extension, it seems to work.