Using jQuery in a firefox extension - javascript

I'm trying to develop a firefox extension which draws a toolbar at the base of every webpage.
Until now i managed to make jQuery work and i proved it by running
$("body",mr.env).css("background","black");
in the mr.on=function().
This code just makes the background color of the webpage black whenever i click the menu item associated with the addon.
But, if i try to run
$('body',mr.env).append( ' <img src="img/check.png" /> ' );
it simply fails. It doesn't show any error in Error Console and the image isn't displayed.
Why is that?
This is my overlay XUL :
<script src="window.js"/>
<link href="style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="jquery-1.4.4.min.js"></script>
<!-- Firefox Tools menu -->
<menupopup id="menu_ToolsPopup">
<menuitem id="menu_crypt_demo" class="" image=""
label="Use DnsResolver?" insertbefore="javascriptConsole" accesskey="o"
oncommand="DnsResolver.onMenuItemCommand(event);">
</menuitem>
</menupopup>
This is the JavaScript file (window.js):
var DnsResolver = {
onLoad: function() {
// initialization code
this.initialized = true;
},
onMenuItemCommand: function() {
testextension.on();
window.open("chrome://dnsresolver/content/window.xul", "", "chrome");
}
};
window.addEventListener("load", function(e) { DnsResolver.onLoad(e); }, false);
if(!testextension){ var testextension={};}
(function(){
var mr=testextension;
mr.on=function(){
mr.loadLibraries(mr);
var jQuery = mr.jQuery;
var $ = function(selector,context){ return new jQuery.fn.init(selector,context||window._content.document); };
$.fn = $.prototype = jQuery.fn;
mr.env=window._content.document;
/*$("body",mr.env).css("background","black");*/
$('body',mr.env).append('<img src="img/check.png" />');
$(mr.env).ready(function(){
// hide and make visible the show
$("span.close a",mr.env).click(function() {
$("#tbar"),mr.env.slideToggle("fast");
$("#tbarshow",mr.env).fadeIn("slow");
});
// show tbar and hide the show bar
$("span.show a",mr.env).click(function() {
$("#tbar",mr.env).slideToggle("fast");
$("#tbarshow",mr.env).fadeOut();
});
});
/*$("body",mr.env).css("background","black");*/
}
// Loading the Jquery from the mozilla subscript method
mr.loadLibraries = function(context){
var loader = Components.classes["#mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://dnsresolver/content/jquery-1.4.4.min.js",context);
var jQuery = window.jQuery.noConflict(true);
if( typeof(jQuery.fn._init) == 'undefined') { jQuery.fn._init = jQuery.fn.init; }
mr.jQuery = jQuery;
}
})();

Starting with Firefox 3, chrome resources can no longer be referenced from within <img>, <script>, or other elements contained in, or added to, content that was loaded from an untrusted source. This restriction applies to both elements defined by the untrusted source and to elements added by trusted extensions. If such references need to be explicitly allowed, set the contentaccessible flag to yes to obtain the behaviour found in older versions of Firefox.

Use the HTML tab in FireFox to know actually if the img element was added. It probably was added and the problem is with your URL.
I remember when building my FireFox extensions, that files are located through a special protocol (chrome:// I think), where you put the name of the extension and can browse through it.

Related

Calling a CSS within Javascript

I am creating a Safari extension that clears Outlook.com advertisements and other content. I have made two versions of the extension, one with CSS and one Javascript. However, there is a delay when removing the elements with Javascript. I was wondering is it possible to call a CSS file using Javascript so that it removes the elements quicker?
If anyone has made a Safari extension or is familiar with it, how can I make check box that will call a specific CSS file? For example, there is a CSS file called 'ads' and I have checkbox with the 'Key' ads and I want to be able to find a way so that I can call it when the checkbox has been checked.
I hope you understand what I am trying to say :) It is a bit difficult to write what I want to say.
Thanks.
This is the proxy.html file that calls the functions.
<!doctype html>
<html lang="en">
<head>
<script type="text/javascript">
var data = new Object();
safari.application.addEventListener( "message", function( e ) {
if( e.name === "getData" ) {
data.advertisements = safari.extension.settings.getItem( "advertisements" );
};
}, false );
</script>
</head>
<body>
</body>
</html>
Here is the script.js file.
$(function() {
safari.self.addEventListener( "message", function( e ) {
if( e.name === "setData" ) {
handleEvents( e.message );
}
}, false );
safari.self.tab.dispatchMessage( "getData" );
function handleEvents( e ){
if (e.advertisements !='show') {
var customStyles = document.createElement('style');
customStyles.appendChild(document.createTextNode('#RightRailContainer {display: none !important;} .WithRightRail {right: 0 !important;}'));
document.documentElement.insertBefore(customStyles);
}
Yes you can. In JavaScript you can use a function to create DOM elements:
document.createElement("link"); // Create CSS element.
Then you can use .setAttribute(attr, value) to give attributes to the created element. You can do something like this:
var file=document.createElement("link");
file.setAttribute("rel", "stylesheet");
file.setAttribute("type", "text/css");
file.setAttribute("href", "main.css");
Note: You can also set the property directly doing file.[attr] = [value]. For example, this does the same thing as the above code:
var file=document.createElement("link");
file.rel = "stylesheet";
file.type = "text/css";
file.href = "main.css";

wami-recorder - Wami.startRecording is not a function

I am trying to implement Wami-Recorder as described here on stackoverflow with basically the same setup as in the accepted answer ie swfobject.js, recorder.js, and gui.js included in the head tag, the html controls contained in the divs:
<div id="recorder">
<button id="record">Record</button>
<button id="play">Play</button>
</div>
<div id="flash"></div>
and the JavaScript is just sitting at the bottom of the page just before the html end tag:
<script>
Wami.setup({
id: 'flash' // where to put the flash object
});
// initialize some global vars
var recording = '';
var recordingUrl = '';
var playBackUrl = '';
// get button elements
var record = $('#record');
var play = $('#play');
// define functions
function startRecording() {
recording = 'temp.wav';
recordingUrl = 'http://localhost/temp/wami/test/save_file.php?filename=' + recording;
Wami.startRecording(recordingUrl);
// update button attributes
record.html('Stop').unbind().click(function() {
stopRecording();
});
}
function stopRecording() {
Wami.stopRecording();
// get the recording for playback
playBackUrl = 'http://localhost/temp/wami/test/' + recording;
// update button attributes
record.html('Record').unbind().click(function() {
startRecording();
});
}
function startPlaying() {
Wami.startPlaying(playBackUrl);
// update button attributes
play.html('Stop').unbind().click(function() {
stopPlaying();
});
}
function stopPlaying() {
Wami.stopPlaying();
// update button attributes
play.html('Play').unbind().click(function() {
startPlaying();
});
}
// add initial click functions
record.click(function() {
startRecording();
});
play.click(function() {
startPlaying();
});
</script>
</body>
Now, I've never actually seen a working demo of Wami-Recorder, but I'm assuming there should actually be something in the flash container when it loads...? I get no error, and I can right click the area where the flash embed should be and the context menu confirms that there's a flash object loaded, and Firebug shows the DOM has been modified to:
<div id="recorder">
<button id="record">Record</button>
<button id="play">Play</button>
</div>
<div id="flash">
<div id="widb06765e52be" style="position: absolute;">
<object id="wid36dd0ea1ccc" width="214" height="137" type="application/x-shockwave-flash" data="Wami.swf" style="visibility: visible;">
<param name="allowScriptAccess" value="always">
<param name="wmode" value="transparent">
<param name="flashvars" value="visible=false&loadedCallback=Wami._callbacks['wid9ebef515c0b']&console=true">
</object>
</div>
</div>
as well as that the Wami.swf file was fetched via GET with 200 status.
Still, when I click the Record button, I get TypeError: Wami.startRecording is not a function. I'm assuming it's some sort of context issue, in that Wami is not a global for use inside a function for some reason. If so, can anyone explain why? If this is not the case, what have I overlooked?
Edit:
At one point I had tried to implement a more object-oriented way of doing things with:
var Audio = {
setup: function() {
Wami.setup("wami");
}
record: function() {
Audio.status("Recording...");
Wami.startRecording("https://wami-recorder.appspot.com/audio");
}
play: function() {
Wami.startPlaying("https://wami-recorder.appspot.com/audio");
}
stop: function() {
Audio.status("");
Wami.stopRecording();
Wami.stopPlaying();
}
status: function(msg) {
$('#status').html(msg);
}
};
And I would fire the functions from within the document.ready() method depending upon other conditions. The original implementation throws the exact same error, and I stripped it all out to try this more direct approach... to no avail.
You're on the right track! This is a lot of writing, but I hope it helps :-D
On the default implementation using the sample code from the Google repos, you do see the Flash GUI because it's initialized, but in this example, it does not and relies on the HTML buttons. The Flash is still on the page right below the buttons but white one white.
Your error
Using your code and files, the only way I was able to duplicate your error was to access the file via the file system:
file:///c:/xampp/htdocs/wami/index.html
Accessing the same content through a web server:
http://localhost/wami/index.html
works great.
So my assumption is that you don't have a web server to test on and are using the file system instead. I included links to XAMPP and basic setup instructions below, as well as the working code sample.
My setup:
I'm using XAMPP so the browser URL is set to http://localhost/wami/index.html.
You can download XAMPP here.
On Windows, it will install in C:\xampp by default.
Place all your files in C:\xampp\htdocs\wami and you should be all set.
Start APACHE in the XAMPP console
Open a browser and navigate to http://localhost/wami/index.html
I placed all files in that folder (all WAMI files including save_file.php). Once ran, and the first WAV file was created, I elevated the permissions on it for testing (right-click, add FULL CONTROL permission for All Users (I'm on Windows 7).
Full working code sample (same as yours but has the entire code chunk for reference. I removed https:// from the JavaScript call since mixing http and https can cause security popups and broken JavaScript)
I used the PHP file as-is with this code:
<?php
// get the filename
parse_str($_SERVER['QUERY_STRING'], $params);
$file = isset($params['filename']) ? $params['filename'] : 'temp.wav';
// save the recorded audio to that file
$content = file_get_contents('php://input');
$fh = fopen($file, 'w') or die("can't open file");
fwrite($fh, $content);
fclose($fh);
?>
And the HTML file:
<!-- index.html -->
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script src="recorder.js"></script>
</head>
<body>
<div id="recorder">
<button id="record">Record</button>
<button id="play">Play</button>
</div>
<div id="flash"></div>
<script type="text/javascript">
// initialize Wami
Wami.setup({
id: 'flash' // where to put the flash object
});
// initialize some global vars
var recording = '';
var recordingUrl = '';
var playBackUrl = '';
// get button elements
var record = $('#record');
var play = $('#play');
// define functions
function startRecording() {
recording = 'temp.wav';
recordingUrl = 'save_file.php?filename=' + recording;
Wami.startRecording(recordingUrl);
// update button attributes
record.html('Stop').unbind().click(function() {
stopRecording();
});
}
function stopRecording() {
Wami.stopRecording();
// get the recording for playback
playBackUrl = recording;
// update button attributes
record.html('Record').unbind().click(function() {
startRecording();
});
}
function startPlaying() {
Wami.startPlaying(playBackUrl);
// update button attributes
play.html('Stop').unbind().click(function() {
stopPlaying();
});
}
function stopPlaying() {
Wami.stopPlaying();
// update button attributes
play.html('Play').unbind().click(function() {
startPlaying();
});
}
// add initial click functions
record.click(function() {
startRecording();
});
play.click(function() {
startPlaying();
});
</script>
</body>
</html>
The flash object was being embedded in the page, but none of the event listeners were working. I have since switched to jRecorder link, and with a few modifications to the code, have it working with no issues.

Cortado Ogg-player in MediaElement.js - almost working

I made a few changes to the MEjs demo player, to enable playback of OGG in IE/Safari browsers, using the Cortado Java applet.
I have play/pause working, and although getPlayPosition() isn't getting the current position in milliseconds as described in the documentation, applet.currentTime and applet.duration work well for this purpose.
I thought it would be simple to hook these up to the current position indicators on the mejs player, but I'm running into a problem. setCurrentTime on the object is causing DOM Exception: InVALID_STATE_ERR (11) in IE, and a similar error happens in Safari. Apparently the object I'm trying to set no longer exists?
The code below will play and pause, and even give the seconds/total in the console (F12 tools MUST be enabled in IE.) Is there a good way to connect this to the play bar?
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>HTML5 MediaElement</title>
<script src="../build/jquery.js"></script>
<script src="../build/mediaelement-and-player.js"></script>
<link rel="stylesheet" href="../build/mediaelementplayer.min.css" />
</head>
<body>
<h1>MediaElementPlayer.js</h1>
<p>Audio player</p>
<h2>OGG Player</h2>
<audio id="player2" src="http://www.archive.org/download/memoirs_holmes_0709_librivox/holmesmemoirs02doyle.ogg" type="" controls="controls">
</audio>
<script>
MediaElementPlayer.prototype.buildplaypauseOrig =
MediaElementPlayer.prototype.buildplaypause;
MediaElementPlayer.prototype.buildplaypause = function(a,b,c,d) {
if (d.src.indexOf('.ogg') !=-1 /* && IE or safari */) {
if (jQuery(this.$node).find('applet').length==0) {
jQuery(this.$node).append('<applet code="com.fluendo.player.Cortado.class" codebase="http://theora.org/" archive="cortado.jar" width="100" height="100">'+
'<param name="url" value="'+d.src+'"/><param name="seekable" value="true"/><param name="autoPlay", value="false"/></applet>');
}
var el = this.$node; //mejs audio element
var initonload = function() {
if (el.find('applet')[0].isActive) {
var applet = el.find('applet')[0];
// This is where it fails: mejs.players[0].setCurrentTime or d.setCurrentTime cause dom exception
console.log(applet.code);
console.log(applet.currentTime);
/*mejs.players[0]*/ //d.setCurrentTime(applet.currentTime);
console.log(applet.duration);
/*mejs.players[0]*/ //d.media.duration = applet.duration;
} else {
window.setTimeout(initonload,100);
}
}
d.addEventListener("play",function() {
var audio = el.attr('src');
window.setInterval(function() {
//try {
var applet = el.find('applet')[0];
console.log(applet.currentTime);
// This is where it fails: mejs.players[0].setCurrentTime or d.setCurrentTime cause dom exception
//mejs.players[0].setCurrentTime(applet.currentTime);
console.log(applet.duration);
/*mejs.players[0]*/ //d.media.duration = applet.duration;
//}catch(e) {console.log(e)}
//console.log(applet.getPlayPosition()+"ms");
},1000);
//jQuery(this).find('applet')[0].setParam('url',audio);
el.find('applet')[0].doPlay();
});
d.addEventListener("pause",function() {
var applet = el.find('applet')[0];
applet.doPause();
});
d.addEventListener("load",function(e) {
alert('load');
});
}
this.buildplaypauseOrig(a,b,c,d);
}
mejs.HtmlMediaElementShim.determinePlaybackOrig =
mejs.HtmlMediaElementShim.determinePlayback
mejs.HtmlMediaElementShim.determinePlayback = function(htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
var res = this.determinePlaybackOrig(htmlMediaElement, options, supportsMediaTag, isMediaTag, src);
//if (mejs.MediaFeatures.isIE) {
res.method = 'native';
//}
return res;
}
$('audio,video').mediaelementplayer();
</script>
</body>
</html>
This is using MeJS 2.10.3.
[EDIT]
After inspecting the MediaElement.js code, it seems that mejs.players is not an array, but an object, and in order to access the first player, you would have to look into mejs.players['mep_0'], since mejs.players[0] would be undefined.
My guess would be that jQuery fails to create an interactive <applet> element, since, from my experience, jQuery (which heavily relies on document.createDocumentFragment) sometimes fails to attach/trigger events on dynamically created/cloned DOM nodes, especially in IE, which could be the cause for this DOM error that you're seeing, because your <applet> object probably failed to initialize.
To try and fix this problem, I'd suggest to use the native document.createElement and document.appendChild methods instead of the jQuery.append.
if (jQuery(this.$node).find('applet').length==0) {
var createElem = function(name, attributes) {
var el = document.createElement(name);
attributes = attributes || {};
for (var a in attributes) {
el.setAttribute(a, attributes[a]);
}
return el;
};
var applet = createElem('applet',{
code:'com.fluendo.player.Cortado.class',
codebase: 'http://theora.org/',
archive: 'cortado.jar',
width: 100,
height: 100
});
applet.appendChild(createElem('param', {name:'url', value:d.src}));
applet.appendChild(createElem('param', {name:'seekable', value: 'true'}));
applet.appendChild(createElem('param', {name:'autoPlay', value: 'false'}));
this.$node.get(0).appendChild(applet);
}

Assigning some style from the styles-box in CKEditor through JavaScript

How can I simulate user-selection of some style from the styles-box, through JS? I want to put some shortcut buttons that assign some of the popular styles with one click.
EDIT:
I don't care if it'll be in-editor button or outer button.
I don't want css-style assignment; I want CKEditor-style assignment (those of the styles-box).
I haven't used CKEditor, but, I saw your question and thought "That would be fun to figure out." Well, here is what I figured out:
(yes, I found terrible documentation, but, that's not the point...I will give them props for commenting their code, though.)
///
// function to add buttons that trigger styles to be applied.
//
// editor - CKEDITOR - instance of editor you want command attached to.
// buttonName - String - name of the button
// buttonLabel - String - humane readable name of the button
// commandName - String - name of command, the way to call this command from CKEDITOR.execCommand()
// styleDefinition - StyleDefinition - obj defining the style you would like to apply when this command is called.
///
var addButtonCommand = function( editor, buttonName, buttonLabel, commandName, styleDefiniton )
{
var style = new CKEDITOR.style( styleDefiniton );
editor.attachStyleStateChange( style, function( state )
{
!editor.readOnly && editor.getCommand( commandName ).setState( state );
});
editor.addCommand( commandName, new CKEDITOR.styleCommand( style ) );
editor.ui.addButton( buttonName,
{
label : buttonLabel,
command : commandName
//adding an icon here should display the button on the toolbar.
//icon : "path to img",
});
};
//Get the editor instance you want to use. Normally the same as the ID of the textarea CKEditor binds to.
var editor1 = CKEDITOR.instances.editor1;
//If you look at ckeditor/_source/plugins/styles/default.js you will see that this selects the first element. That list is read into the array 'default'.
var blueTitleStyle = CKEDITOR.stylesSet.registered.default[0];
//Or, you can define the style like this: See http://dev.ckeditor.com/wiki/Components/Styles for more info on style definitions.
var blueTitleStyle = {
name : 'Blue Title',
element : 'h3',
styles : { 'color' : 'Blue' }
};
addButtonCommand(editor1, 'BlueTitle', 'BlueTitle', 'bluetitle', blueTitleStyle);
Here is a Javascript function to aid your click events:
//function used to execute the command. Only used for calling the command when not calling from a button. (Like an A with an onClick bound to it.)
//pulled this function right out of the api.html example in the ckeditor/_samples dir.
function ExecuteCommand( commandName )
{
// Get the editor instance that we want to interact with.
var oEditor = CKEDITOR.instances.editor1;
// Check the active editing mode.
if ( oEditor.mode == 'wysiwyg' )
{
// Execute the command.
// http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.editor.html#execCommand
oEditor.execCommand( commandName );
}
else
{
alert( 'You must be in WYSIWYG mode!' );
}
}
Now, you can create a link like this:
<a href='#' class='setBlueTitle'>Set Blue Title</a>
and use a bit of jQuery to spice it up:
<script type="text/javascript">
$(document).ready(function(){
$(".setBlueTitle").onClick(function(e){
//stops the click from changing the page and whatever other default action would happen.
e.preventDefault();
ExecuteCommand('bluetitle');
});
});
</script>
I am not 100% sure about the button icon part. I didn't have an icon to try it with. But, according to a few posts, it should work fine. Regardless, the jQuery click binding works.
That should be pretty much it! I had to do quite a bit of digging around to figure this out, but it certainly is satisfying to see it work!
Here's one option
First, you can setup the desired styles you want to try out in a CSS class. Then, you can set the className for the test div when you click that button. Here's a simple example:
test.css:
.bold {
font-weight: bold;
}
.italic {
font-style: italic;
}
test.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css" />
</head>
<body>
<input type="button" onclick="document.getElementById('testStyleDiv').className='bold'" value="bold"/>
<input type="button" onclick="document.getElementById('testStyleDiv').className='italic'" value="italic"/>
<div id="testStyleDiv">foo</div>
</body>
</html>

jQuery Cookie Question

I've looked around a lot, and can't seem to find anything that's simple enough for me to do...
I've set up a web page that detects which browser is currently running, and if it's something other than Firefox 4.0, it displays a hidden div that gives a warning stating that the page is best viewed in Firefox 4.0 or greater. Within that div is a button that hides the div onclick.
I'm looking for a way to remember that this button has been clicked during a session, so that when a user clicks on my "home" page, they don't get the same message every time.
Current code:
<head>
<script src="js/browsercheck.js"></script>
<script type="text/javascript">
// external script "browsercheck.js" checks
// which browser/version is being used
// check browser and display message if != Firefox 4.0 or >
function checkBrowser() {
var browser = BrowserDetect.browser;
var version = BrowserDetect.version;
if (browser == "Firefox") {
if (version >= 4) {
// do nothing
}
} else {
document.getElementById("coverall").style.visibility="visible";
document.getElementById("browser").innerHTML = browser + " " + version;
}
}
// remove overlay if user commands
function removeCoverall() {
document.getElementById("coverall").style.visibility="hidden";
}
</script>
</head>
<body>
<div id="coverall" style="visibility:hidden;">
<p>I see you're using <span id="browser"></span>. Please use Firefox.</p>
<button type="button" onclick="removeCoverall()">I understand</button>
</div>
</body>
Using jQuery and the cookie plugin, you can do:
function removeCoverall() {
$.cookie("user_clicked_ok", "true");
document.getElementById("coverall").style.visibility="hidden";
}
$(window).ready(function() {
if ($.cookie("user_clicked_ok")=="true") {removeCoverall();}
});
More details at: http://www.electrictoolbox.com/jquery-cookies/
In the removeCoverall function you could set a cookie which indicates that the user closed the div and in checkBrowser function verify if the cookie is present before showing the div.
You seem to have the right idea, you need cookies! YUM!
JS
function removeCoverall() {
var date = new Date();
date.setTime(date.getTime()+(7*24*60*60*1000));// expires in one week
document.cookie = 'skipNotify=1;expires='+date.toGMTString()+'; path=/';
document.getElementById("coverall").style.visibility="hidden";
}
Now retrieving the cookie can be difficult in javascript, but you can use PHP!
PHP
function checkBrowser() {
<?php if(isset($_COOKIE['skipNotify']))echo'return;';?>
var browser = BrowserDetect.browser;
var version = BrowserDetect.version;
if (browser == "Firefox") {
if (version >= 4) {
// do nothing
}
} else {
document.getElementById("coverall").style.visibility="visible";
document.getElementById("browser").innerHTML = browser + " " + version;
}
}
The above code injects a return statement if the user has the cookie, so the call to the function won't do anything.
As mentioned in the other posts, I highly recommend you use jQuery for all your javascript needs. It's very popular, stable and useful! I only gave my answer as it does not use any third party solution.

Categories

Resources