I'm working on a web interface with the help of primefaces framework.
In that interface, one of the objectives is to have the code divided in javascript functions that do not share information between each other and they don't allow being invoked by other parts (that eases testing and reduces the number and complexity of possible use-cases).
All "parts" are encapsulated using:
(function (window, document, undefined){
var $ = window.jQuery;
// main content here
})(window,document);
The communication required between each part is minimal and the required one is made using DOM events where an object is passed between each other. (if the event is not caught, it's just a functionality that didn't act. If it caused something to break, the js does not stop working, among other reasons).
This has been working for quite a while with minimal bugs found until I had to work with jsf+primefaces.
By reading the documentation, primefaces has many XML tags that do not map to HTML tags. One of the main ones I have to work with is <p:ajax>.
This tag was many on*-like attributes whose concept works much like the HTML3's ideology of writing javascript in HTML's "on*" attributes. Still, those <p:ajax> are always attached to specific XML elements like <h:inputText> or <p:commandButton> and that's where I started looking at.
In primefaces documentation, there's information about the inline on* attributes but I was fully unable to find information about jsf or primefaces' personalized DOM events.
How it appears with primefaces, I'm forced to change the javascript code so that functions/methods can be called inline in the HTML. That would require a lot of work also because, depending on the situation, the js code might even not be there (because the feature it enables is not required for that page).
How do I make the system on primefaces such that I have my javascript fully detached from the jsf/primefaces XML (and the whole HTML output I can manage).
EDIT:
I ran out of ideas on where to look at, I'll work on looking at primefaces source code now. I may get better luck there.
EDIT:
Meanwhile I got some ideas for searching using different keywords and I found this(see: "Client Side API"):
http://courses.coreservlets.com/Course-Materials/pdf/jsf/primefaces/users-guide/p-ajaxStatus.pdf
This is near what I wanted but it seems like it does not exist for the elements I mentioned above. I'll work on continuing searching for more.
After some testing, investigation, etc... I was finally able to understand the whole story of what was happening.
Primefaces was doing everything right after all! The <p:ajax> has the correct code to send all the events it should! The problem lies in jQuery itself.
jQuery's trigger() method (and it's shortcuts) works in such way that it handles all events directly inside jQuery bubbling and calling the callbacks registered using on() (or any of the shorthands).
The main issue in jQuery is that it only resend the "click" event to the DOM because it tries to use a method in the DOM element with the same name as the event. In the DOM, (at the moment) the only situation when that happens is the "click" event. That's why I was getting the click event and not the rest of the events.
With that, the mistery and confusion was, finally, solved. uff!
Related
I have a very basic question about grouping (jQuery) plugin initializations-- and really any type of script-- into a single script throughout a website: in my templates, I typically have a "tools.js" file that includes various plugin initializations, click functions and the like. For the sake of ease, neatness and number of server requests, I like to keep these functions/script calls centralized in a single file, however, on certain pages, various scripts won't apply-- say, a fitvids.js script initialization that might be used on one page with a video, and not on another. Thus, I'm wondering if this is problematic in any way, i.e. can this create problems if a certain library isn't included on a given page-- but it's initialization is-- or a selector referenced in a click function is not present on a given page?
Thanks for any insight here.
In my design, I will have only shared code like plugin definitions or common utility methods shared between pages. The functional code like event handlers or plugin initialization for each page will be kept separate.
If there is a cross cutting concern in multiple pages then it will be either converted as a plugin or as a utility method which will be placed in a shared file but the actual usage will be done for each page separately.
If the selector is not present in the DOM and has a click handler in js, it should not be a problem. The reason behind is that the click function is never triggered. It is an issue if the attached handler is executed by any chance and js can't find your selector.
Consider the simple link below:
Link
I understand there are two ways to run a function when a user clicks this element:
$(".mylink").click(function () {
and
Link
Is there a performance difference between the two, or any other practical reason I should use one over the other?
Using $('.mylink').click(function(){ is better as it follows standard event registration model. (jQuery internally uses addEventListener and attachEvent).
Basically registering an event in modern way is the unobtrusive way of handling events. Also to register more than one event listener for the target you can call addEventListener() for the same target.
Read jQuery.click() vs onClick
and How does inline Javascript (in HTML) work?
https://softwareengineering.stackexchange.com/questions/86589/why-should-i-avoid-inline-scripting
They have the same functional behavior, there is no difference whatsoever.
The difference is in code modularity and maintainability.
Using the first method is preferred and more appropriate because it doesn't mix between HTML and JavaScript, a concept called Unobtrusive JavaScript.
If you have worked in the early days of HTML, then you should remember when there were all those attributes like background, color, font ... etc.
Then CSS came in, and everybody told us not to use those old attributes anymore because they mix presentation with document structure, instead we should use CSS to control layout and look of the document.
This is similar to that idea but it is now used for code, separate functionality from document structure.
Edit: Quoting from #mplungjan comment in order to be more accurate:
That there is no difference is not true. href="javascript:myFunction()" does not have the ability to cancel the actual click with a preventDefault or return false. Hence animated gifs will stop running in some browsers and older browsers would even partially unload the page. Also if the function returned a value, the page would be replaced with that value, seen when beginners try href="javascript:window.open..." and get [object object] on the page
Jquery like any other good JavaScript frameworks supplies you with functionality independent of browser platform wrapping all the intricacies, which you may not care about or don't want to care about.
I think using a framework is better instead of using pure JavaScript and doing all the stuff from scratch, unless you usage is very limited.
I definitely recommend JQuery!
The first one is JQuery convention of an event listener. You need to include jquery library in order to use it. The second one is a Javascript convention. You don't need to include any library or extra code to run. There are no differences in terms of performance, but as I told if you do not want to include any kind of library you should use the second example.
I'm creating a Wordpress plugin, which adds a metabox right under the post editor containing a button. The plugin also loads a Javascript file right below the closing </body> tag.
PURPOSE
At the moment, what I am trying to achieve with the plugin is simple. When a user enters content to the editor and then clicks the button inside the metabox, I want to modify the editor's content.
JS CODE
In its simplest form:
jQuery(document).ready(function($) {
$('#button').on('click', function(e) {
e.preventDefault();
var editor = tinyMCE.get("content");
editor.setContent(some_content);
});
});
PROBLEM
The problem is that editor variable returns undefined.
FIREBUG (when trying to set var editor)
wpActiveEditor : "content"
editors : [ ]
activeEditor : null
WHAT HAVE I TRIED
I have tried many, many things (also many small tweaks) found on Tinymce's documentation and here on Stackoverflow but the problem still remains the same.
Any help would be very appreciated.
PS. The content textarea is visible when running my tests.
When the Editor first loads with the "Text" mode active, tinymce does not get initialized, therefore you cannot use tinyMCE.get(), as opposed to the "Visual" mode.
(I hadn't noticed that it actually works on the "Visual" mode, as I was keep testing it on the "Text" mode)
So, a conditional statement is necessary to determine first which tab is active. I solved my problem with this method:
function setEditorContent(val) {
var $_editorTextArea = $('#content');
$_editorTextArea.is(':visible') ? $_editorTextArea.val(val) : tinyMCE.get('content').setContent(val);
}
Hope this answer will prevent some headaches :)
Well, a live example would help a lot.
This way i can only guess: It looks a bit as if you cannot get the editor you want.
There are two possible reasons that come into my mind:
The editor id you are using is not the id of your editor
To verify this you check the id of your editors soure html element (in most cases a textarea).If there is no id set tinymce will use "content" as default.
There iy no editor initialized at all
To verify this you can use console.log(tinymce.editors) in your javascript console. If no editor is initialized then you will get an empty array.
Many years later but maybe this will help someone...
In addition to everything said above some consideration needs to be paid to the JS event model. Consider:
TinyMCE may not initialize (and the tinymce global may not be available) until the document is done loading. The OP correctly wrapped calls in jQuery(fn), which will solve this. This is relevant if you're using an added framework that initializes and tries to manipulate the editors (like AngularJS directives).
Parts of initialization seem to be asynchronous so even if you wrap everything in jQuery(fn) the editors may not be available until later. WP loads Underscore as part of Backbone so wrapping initial attempts to locate editors in _.defer(fn) seems to get me lots of mileage. This could be done with the native JS setTimeout as well.
Beyond the fantastic answer by #m.spyratos, it may be helpful to note that you can hook mode change events (Visual/Text) by adding a jQuery click event handler to button.switch-tmce[data-wp-editor="my_editor_id"] and button.switch-html[data-wp-editor="my_editor_id"] for when the user selects Visual or Text, respectively. Your version may vary but I found that the textarea goes away when switching to Visual mode and the tinymce.editor instance goes away when switching to Text mode. Hooking to these events gives a persistent means to re-hook when the user decides to change modes.
As a quick reference, you can attach to the editor object (activeEditor or something in editors[], which is keyed by editor ID) to receive any and all changes in visual editor content with by hooking to the editor with editor.on('NodeChange keyup', fn) and a single event callback. I included blur in my solution as well, for posterity. The text editor content can be hooked with jQuery('textarea#my_editor_id').on('keyup', fn).
I have successfully managed multiple editors on a page that are entirely two-way bound entirely through JS; the editors are created with wp_editor and no initial content then loaded asynchronously (via AJAX in my case) and managed through multiple edit cycles without a server round-trip. This is possible, if not slightly convoluted.
Generally, there are 3 ways (that I am aware of) to execute javascript from an <a/> tag:
1) Use onclick():
hello
2) Directly link:
hello
3) Or attach externally:
// In an onload event or similar
document.getElementById('hello').onclick = window.alert('Hello');
return false;
<a id="hello" href="#">hello</a>
I am actually loading the link via AJAX, so #3 is basically out. So, is it better to do #1 or #2 or something completely different? Also, why? What are the pitfalls that I should be aware of?
Also of note, the anchor really doesn't link anywhere, hence the href="#", I am using a so the styles conform as this is still an object to be clicked and a button is inappropriate in the context.
Thanks
If you are loading the content via ajax and need to hook up event handlers, then you have these choices:
Put a javascript handler in your HTML with your option 1) or 2). In my mind option 1) is a cleaner way of specifying it, but I don't think there's a mountain of difference between 1) or 2) - they both do essentially the same thing. I'm not a fan of this option in general because I think there's value in keeping the markup and the code separate.
After loading the content with ajax, call some local code that will find and hook up all the links. This would be the same kind of code you would have in your page and execute on DOMReady if the HTML had been static HTML in your page. I would use addEventListener (falling back to attachEvent) to hook up this way as it more cleanly allows multiple listeners for a single object.
Call some code after you load the content with ajax that finds all the links and hooks up the clicks to some generic click handler that can then examine meta data in the link and figure out what should be done on that click based on the meta data. For example, this meta data could be attributes on the clicked link.
When you load the content, also load code that can find each link individually and hook up an appropriate event handler for each link much the way one would do it if the content was just being loaded in a regular page. This would meet the desire of separating HTML from JS as the JS would find each appropriate link and hook up an event handler for it with addEventListener or attachEvent.
Much like jQuery .live() works, hook up a generic event handler for unhandled clicks on links at the document level and dispatch each click based on some meta data in the link.
Run some code that uses an actual framework like jQuery's .live() capability rather than building your own capability.
Which I would use would depend a little on the circumstances.
First of all, of your three options for attaching an event handler, I'd use a new option #4. I'd use addEventListener (falling back to attachEvent for old versions of IE) rather than assigning to onclick because this more cleanly allows for multiple listeners on an item. If it were me, I'd be using a framework (jQuery or YUI) that makes the cross browser compatibility invisible. This allows complete separation of HTML and JS (no JS inline with the HTML) which I think is desirable in any project involving more than one person and just seems cleaner to me..
Then, it's just a question for me for which of the options above I'd use to run the code that hooks up these event listeners.
If there were a lot of different snippets of HTML that I was dynamically loading and it would be cleaner if they were all "standalone" and separately maintainable, then I would want to load both HTML and relevant code at the same time so have the newly loaded code handle hooking up to it's appropriate links.
If a generic standalone system wasn't really required because there were only a few snippets to be loaded and the code to handle them could be pre-included in the page, then I'd probably just make a function call after the HTML snippet was loaded via ajax to have the javascript hook up to the links in the snippet that had just been loaded. This would maintain the complete separation between HTML and JS, but be pretty easy to implement. You could put some sort of key object in each snippet that would identify which piece of JS to call or could be used as a parameter to pass to the JS or the JS could just examine the snippet to see which objects were available and hook up to whichever ones were present.
Number 3 is not "out" if you want to load via AJAX.
var link = document.createElement("a");
//Add attributes (href, text, etc...)
link.onclick = function () { //This has to be a function, not a string
//Handle the click
return false; //to prevent following the link
};
parent.appendChild(link); //Add it to the DOM
Modern browsers support a Content Security Policy or CSP. This is the highest level of web security and strongly recommended if you can apply it because it completely blocks all XSS attacks.
The way that CSP does this is disabling all the vectors where a user could inject Javascript into a page - in your question that is both options 1 and 2 (especially 1).
For this reason best practice is always option 3, as any other option will break if CSP is enabled.
I'm a firm believer of separating javascript from markup. There should be a distinct difference, IMHO, between what is for display purposes and what is for execution purposes. With that said, avoid using onclick attribute and embedding javascript:* in a href attribute.
Alternatives?
You can include javascript library files using AJAX.
You can setup javascript to look for changes in the DOM (i.e. if it's a "standard task", make the anchor use a CSS class name that can be used to bind a specific mechanism when it's later added dynamically. (jQuery does a great job at this with .delegate()))
Run your scripts POST-AJAX call. (Bring in the new content, then use javascript to [re]bind the functionality) e.g.:
function ajaxCallback(content){
// add content to dom
// search within newly added content for elements that need binding
}
In javascript, what are the pro's and con's of encoding an onclick event in the DOM and in the HTML itself?
Which, if either, is better than the other and why?
Your question almost answers itself when you refer to "the HTML itself".
JavaScript is not HTML -- Keeping the HTML and the JavaScript in separate locations is a benefit all by itself. Makes it easier to (humanly) read the HTML, and keeping all the JS in the same location makes it easier to track everything down all at once.
It is better to write your Javascript in Javascript, as OtherMichael says. It is even better to use proper DOM events (addEventListener and attachEvent) rather than on_____, in order to avoid conflicts and allow multiple callbacks for the same event.
Attaching events to an CSS-style ID (or classes), as Jquery does so well, means that if you don't have JS enabled, it will automatically fall through to any links that are referenced. That's good practice, and will help to make sure that your page works in even quite simple browsers, such as some mobile handsets.
It's also good practice to layer the underlying data (the HTML), presentation (CSS) and behaviour (Javascript). Changing individual layers is a lot easier if they are well structured.