Why does Gmail go bonkers once Modernizr is dynamically loaded in it? - javascript

Entering this into the Chrome or Safari inspector console, inside Gmail:
function load(url,cb){var x=document.body.appendChild(document.createElement('script'));x.src=url;x.onload=function(){console.log("Dynamically loaded "+url);if(cb){cb();}};if(!cb){x.setAttribute('async','')}}
load("https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js",function(){alert("Modernizr loaded");});
Causes the layout of much of the text to go crazy.
Can this be explained? I'd like for my tool (which involves running a bookmarklet which dynamically loads Modernizr) to work on Gmail.

Modernizer adds a lot of classes to the <html> tag, and one of those classes is js. I couldn't find anything in the documentation that describes what that represents, although I suspect it just represents JavaScript support. Google has minified their classes, so they are all short two letter items (probably generated). One of them happens to be js as well, which is causing a lot of text to get centered.
In fact, to un-hose it, just remove the js class from the <html> tag after dynamically loading your script and it fixes itself.
Here's a fixed version:
function load(url,cb){var x=document.body.appendChild(document.createElement('script'));x.src=url;x.onload=function(){console.log("Dynamically loaded "+url);if(cb){cb();}};if(!cb){x.setAttribute('async','')}}
load("https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js",function(){var htmlElement = document.getElementsByTagName("html")[0]; htmlElement.className = htmlElement.className.replace
( /(?:^|\s)js(?!\S)/g , '' ); alert("Modernizr loaded");});

Related

What is this code for in the head of the DiscoverWestworld.com website? [duplicate]

In Google Chrome’s Developer Tools, I see a #shadow-root right under <html lang="en"> tag. what does it do and what is it used for? I don’t see it in Firefox nor in IE; only in Chrome, is this a special feature?
If I open it, it shows <head> and <body> and a link beside named reveal, by clicking, it points to the <head> and <body>, nothing else.
This is a special indicator that a Shadow DOM exists. These have existed for years, but developers have never been given APIs into it until recently. Chrome has had this functionality for a while, other browsers are still catching up. It can be toggled in the DevTools Settings under the "Elements" section. Uncheck the "Show User Agent Shadow DOM". This will at least hide away any Shadow DOMs created internally (like select elements.) I am unsure right away if it affects user-created ones, such as custom elements.
These come up in things like iframes as well, where you have a separate DOM tree nested inside of another.
The Shadow DOM is simply saying that some part of the page, has its own DOM within it. Styles and scripting can be scoped within that element so what runs in it only executes in that boundary.
This is one of the primary pieces needed for Web Components to work. Which is a new technology allowing developers to build their own encapsulated components that developers can use just like any other HTML element.
As an example of Shadow DOM, when you have a <video> tag on a web page, its shown as just one tag in the main DOM, but if you enable Shadow DOM, you will be able to see the video player's HTML(player DOM).
This is explained aptly in this article, http://webcomponents.org/articles/introduction-to-shadow-dom/
In the case of web components, there is a fundamental problem that makes widgets built out of HTML and JavaScript hard to use.
Problem: The DOM tree inside a widget isn’t encapsulated from the rest of the page. This lack of encapsulation means your document stylesheet might accidentally apply to parts inside the widget; your JavaScript might accidentally modify parts inside the widget; your IDs might overlap with IDs inside the widget and so on.
Shadow DOM addresses the DOM tree encapsulation problem.
For example, if you had markup like this:
<button>Hello, world!</button>
<script>
var host = document.querySelector('button');
var root = host.createShadowRoot();
root.textContent = 'こんにちは、影の世界!';
</script>
then instead of
Hello, world!
your page looks like
こんにちは、影の世界!
Not only that, if JavaScript on the page asks what the button’s textContent is, it isn’t going to get “こんにちは、影の世界!”, but “Hello, world!” because the DOM subtree under the shadow root is encapsulated.
NOTE: I have picked up above content from https://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/ as it helped me understand shadow DOM a little better than answers already here. I have added relevant content here so that it helps others but do take a look at the link for detailed discussion on same.

Jquery image bookmarklet not working in Django

Im working through Django By Example and in one chapter a Jquery bookmarklet is built within a Django app so that a user can easily save jpg images from a website into their user profile area within the Django app.
Im not an experienced JS or Jquery programmer but I did some JS some years back and can read the code however the tutorial does give exact instructions on what to do which I have followed and although I have managed to get the bookmarklet button to appear in my bookmarks bar in Chrome, nothing happens when I click it when browsing a webpage with jpg images.
This is my local Django dashboard where the bookmarklet button is added to the bookmarks bar and this part works fine
and this is what it should look like when clicked on, this is the part where nothing happens for me
these are the relevant js files
https://github.com/davejonesbkk/bookmarks/blob/master/images/templates/bookmarklet_launcher.js
https://github.com/davejonesbkk/bookmarks/blob/master/images/static/js/bookmarklet.js
the only thing I can see that is different with these compared to the files that came with the book is the indentation is a bit off but for some reason the indentation does seem to have changed a bit when I uploaded to Git and they dont look like that locally. Is indentation important in JS?
I followed the same book with the same examples but didn't had any trouble. Make sure your dashboard.html file is referring to the correct javascript file. If nothing works try to add the bookmark manually, you can see how that's done over here http://www.howtogeek.com/189358/beginner-geek-how-to-use-bookmarklets-on-any-device/ it'll sure to work.
And answer to your last question, Indentation is not as important in JavaScript as it's in Python, as python doesn't use any curly braces "{}" or semi-colons ";". But you can write your entire javascript code in a single line and it'll work because your using curly braces everywhere to tell which line of code ends where.
I agree with all the above. In addition, the following:
Error I noticed in the book:
In bookmarklet-launcher.js the js function being called from bookmarklet.js is called myBookmarklet(), however there is no function called this way in bookmarklet.js. So, you may want to use the same name in both js files.
Practically speaking however, the bookmarklet will always work because, not finding a myBookmarklet function in memory, bookmarklet-launcher.js appends the bookmarklet.js script to the body element and, being bookmarklet.js a self-invoking function, its content executed (without the need it to being called). There are some additional interesting technicalities here (the key function in bookmarklet.js is not self invoking but it will anyway be always called because of the script checking whether jQuery is present...) but ok, this is more relevant for those busy with the mentioned book (Django 2 by example).
Check whether bookmarkled, once you click on it, is added to the
current webpage:
2.1. Open devtools (F12 on Chrome) and check e.g. in the html head element whether you find the newly added link element containing the css attribute and/or in the body element whether you find the script element containing the reference to the bookmarklet.js file.
2.2. Alternative: Add an alert message on top of the bookmarklet.js script so that it will be launched if it is correctly loaded. Example:
(function(){
alert('bookmarkled loaded!');
var jquery_version =...
Make sure you're trying to use it on a HTTP site only. Since you're serving from same protocol. HTTPS site would always tell say: There is a problem loadingbyour jquery. That's how I solved mine.
dude.I have solved the problems I met like you.
The most important thing is that noticing the syntax error(without warnings),mainly caused by ignoring blank.
for example, in the line:
jQuery('#bookmarklet .images').append('<img src="'+image_url+'"/>');
between #bookmarklet and .images should lie a blank space,because of jquery syntax rules(meaning to search tag with id of bookmarklet and search tag with class equaling images within result previously).
Another two places worth notice are codes containing #bookmarklet .images a and #bookmarklet #close,requiring blank spaces between filter condition.
That's where I found I made mistaks mainly after studying syntax of jquery.
You'd better compare your codes with codes already loaded up to github by someone to make sure there are no more little errors(such as spelling).

WP - JS - Get Instance of Tinymce Editor

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.

JQuery translate function not working in firefox / chrome

I have a HTML page which is divided into two frames. Separate web sites are being opened by users in those frames as I provided an open web site option.
These web sites can be in any language. So. i need to translate the languages of these websites to English.
I am using JQuery translate function for this which is not working. As I am new to JQuery, I may be using incorrect syntax / way.
I have tried this code in Firefox, which is not working.
I have tried in Chrome, but I am not able to know that it is working or not because of the default language translate option of the Google Chrome.
I have also searched StackOverFlow Questions, but I didn't find anything.
$(function(){ //on document ready
$('body').translate('en');
})
Here is a link to the plugin: http://code.google.com/p/jquery-translate/wiki/TranslateMethod
First of all, the jQuery library and the script should be called from one of the frames, not the container page, otherwise it won't work.
The jQuery function jQuery() (or $()) looks by default in the current document. In order to apply that function to a frame you should specify the context as a second argument of the function. In this case it would be like:
$(function() {
$('body', window.parent.frames[0].document).translate('en');
});
You can obviously change the index of the array frames (frames[0], frames[1], ecc..) to match the frame that you want to translate.
edit: you can also set a name to the frame (putting the attribute name in the tag <frame> and then call it using window.frame_name.document.

How does one properly test a javascript widget?

So, I've written a little javascript widget. All a user has to do is paste a script tag into the page, and right below it I insert a div with all of the content the user has requested.
Many sites do similar things, such as Twitter, Delicious and even StackOverflow.
What I'm curious about is how to test this widget to make sure that it will work properly on everyone's webpage. I'm not using an iframe, so I really want to make sure that this code will work when inserted most places. I know it looks the same in all browsers.
Suggestions? Or should I just build one hundred web pages and insert my script tag and see if it works? I would hope there is an easier way than that.
Once you have confirmed that your javascript works cross-browser in a controlled environment, here are some things that might cause problems when used on an actual website:
CSS
You're using a CSS class that is already being used (for a different purpose) by the target website
You're using positioning that might interfere with the site's CSS
The elements you are using are being styled by the website's CSS (you might want to use some sort of "reset" CSS that applies only to your widget)
HTML
You're creating elements with the same id attribute as an element that already exists on the website
You're specifying a name attribute that is already being used (while name can be used for multiple elements, you may not be expecting that)
Javascript
What is the expected behaviour without Javascript enabled? If your script creates everything, is it acceptable for nothing to be present without JS?
At very basic you should make sure your widget works for following test-cases. I am sure then it will work on all web-pages -
http/https: There should not be any warning for HTTPS pages for unencrypted content.
<script> / <no-script>: What if JavaScript is disabled? Is your widget still visible?
What happens when third-party cookies are disabled? Does your widget still work?
Layout-box restrictions: When parent div element's size is less than your widget. Does your widget overflow the given size and destroys owners page?
By keeping all your Javascripts under a namespace (global object) with a very unique name, you should be pretty much OK. Also, you can simply use an anonymous function if you just want to print out something.
Similar question: How to avoid name clashes in JavaScript widgets

Categories

Resources