I'm tying my hand at a bit of Javascript to create a Safari Extension. I was running into some issues debugging it, so I stripped out the extension-specific components to test some things out. Short version: clicking the button generated by this javascript (moveButton) doesn't do anything. I don't get any errors in Safari's console, and the best Googling I can do hasn't turned up anything useful.
I'm generating all the button code in Javascript because once I adapt it back to my extension, I need to pass an array.
Any thoughts or suggestions? Am I out to lunch entirely?
function popoverEvent(event) {
var tabs = new Array("test1","test2","test3");
var tabsElement = document.getElementById("tab-list");
tabsElement.innerHTML = ""; // clear previous contents
var formElement = document.createElement('form');
formElement.setAttribute('name', 'tabs-form');
for (var i = 0; i < tabs.length; i++ ) {
var labelElement = document.createElement('label');
labelElement.setAttribute('for', 'tab' + i);
var divElement = document.createElement('div');
var inputElement = document.createElement('input');
inputElement.setAttribute('id', 'tab' + i);
inputElement.setAttribute('name', 'tabcheckboxes');
inputElement.setAttribute('value', i);
inputElement.setAttribute('type', 'checkbox');
var titleElement = document.createTextNode('testTitle' + i);
var urlElement = document.createElement('div');
urlElement.setAttribute('class', 'url');
urlElement.innerHTML = "testURL" + i;
divElement.appendChild(inputElement);
divElement.appendChild(titleElement);
divElement.appendChild(urlElement);
labelElement.appendChild(divElement);
formElement.appendChild(labelElement);
}
// Create button
var moveButton = document.createElement('button');
moveButton.setAttribute('type', 'button');
moveButton.onClick=function() {alert('Here is a pop up message');};
moveButton.innerHTML = "Move to New Window";
formElement.appendChild(moveButton);
tabsElement.appendChild(formElement);
}
You should use onclick not onClick:
Change:
moveButton.onClick=function() {alert('Here is a pop up message');};
To:
moveButton.onclick=function() {alert('Here is a pop up message');};
var moveButton = document.createElement('input');
moveButton.type = "submit"; //don't need that
moveButton.setAttribute('type', 'button');
moveButton.onClick=function() {alert('Here is a pop up message');};
moveButton.innerHTML = "Move to New Window";
didn't mean to set type twice , but create element 'input' not 'button'
Related
I'm trying to create a browser extension popup (in JS) that creates a number of buttons with links that open up different webpages. The function takes a number of parameters, the main one being b_link which is an array of URL's to the website. For some reason, only the last URL in array is applied to all of the buttons that are created.
I'm not entirely sure what the problem is, I could speculate but I don't think that would be productive. One thing I did notice and had to compensate for was using b_link in the lambda function. Just using b_link[i], the lambda function only saw undefined so no webpage opened, but using var tmpLink = b_link[i]; at least gets the link into the function and allows a webpage to open.
How should I make these buttons so that they all have their own links, rather than only the last one in the array?
The function in question:
function createSiteButton(numBtns, b_id, b_class, b_text, b_link, b_bg)
{
// check if the input text is an array
if (Array.isArray(b_text))
{
// create the new set of buttons
for (i= 0; i < numBtns; i++)
{
var newButton = document.createElement('button');
var tmpLink = b_link[i];
newButton.id = b_id;
newButton.class = b_class;
newButton.innerHTML = b_text[i];
newButton.style.background = b_bg;
newButton.addEventListener("click", function()
{
if (tmpLink)
{
window.open(tmpLink, "_blank");
}
});
button_array[i] = newButton;
}
// add the new buttons the screen
for (i= 0; i < numBtns; i++)
{
divID.appendChild(button_array[i]);
}
}
}
I found a way to do this via creating an a element, setting href via a.href = tmpLink and appending the button to the a element as a child. The final function is:
function createSiteButton(numBtns, b_id, b_class, b_text, b_link, b_bg)
{
var outputElem = document.getElementById('output');
// check if the input text is an array
if (Array.isArray(b_text))
{
//var tmpLink = null;
// create the new set of buttons
for (i= 0; i < numBtns; i++)
{
var a = document.createElement('a');
var newButton = document.createElement('button');
var tmpLink = b_link[i];
newButton.id = b_id;
newButton.class = b_class;
newButton.innerHTML = b_text[i];
newButton.style.background = b_bg;
a.href = tmpLink;
a.appendChild(newButton);
divID.appendChild(a);
button_array[i] = newButton;
}
}
}
I am trying to dynamically add an anchor element through Javascript. The problem I have is the onclick event is not firing. I believe the problem is how I am generating the HTML. I am creating an array and then push my HTML code to the array. After I have created my output I am joining the array and then adding it to the div tag I have.
var itemLink = new Object();
itemLink.LinkName = "Edit User";
itemLink.LinkListClass = "";
itemLink.LinkListRole = "";
itemLink.LinkFunction = function() {
//do something specific with rowItem variable
alert(rowItem);
}
var aTag = document.createElement("a");
aTag.setAttribute('class', 'btn btn-primary');
aTag.innerHTML = itemLink.LinkName;
aTag.setAttribute('href', '#');
var rowItem = 'abc1111'; //would be setting the rowId or some sort of identifier
aTag.onclick = itemLink.LinkFunction;
var output = [];
output.push('<table>');
output.push('<thead>');
output.push('<tr><th>col1</th><th>col2</th></tr>');
output.push('</thead>');
output.push('<tbody>');
output.push('<tr><td>col1 data</td><td>col2 data</td></tr>');
output.push('</tbody></table>')
var d1 = document.createElement('div');
d1.appendChild(aTag);
output.push(d1.innerHTML);
var mainView = document.getElementById('mainViewer');
mainView.innerHTML = output.join('');
<div id="mainViewer"></div>
When I generate the output without the use of the array and joining of the output, the anchor element gets created and the onclick event works just fine.
Any ideas?
I will have multiple anchor links and I don't want to hardcode the function name. I want the onclick event to fire whatever function the itemLink Object has set.
What's the problem? You bind a function to a temp DOM element, then append its html, not its events (that's how innerHTML works). So when a link appended to the DOM, it's a different DOM link, so although the link looks the same it's not.
So, what is the solution? to push a DOM element instead of string, something like this:
//var itemLink = new Object();
//itemLink.LinkName = "Edit User";
//itemLink.LinkListClass = "";
//itemLink.LinkListRole = "";
//itemLink.LinkFunction = function() {
//do something specific with rowItem variable
//alert(rowItem);
//}
var itemLink = {
LinkName: "Edit User",
LinkListClass: "",
LinkListRole: "",
LinkFunction: function() {
//do something specific with rowItem variable
alert(rowItem);
}
};
var aTag = document.createElement("a");
aTag.setAttribute('class', 'btn btn-primary');
aTag.innerHTML = itemLink.LinkName;
aTag.setAttribute('href', '#');
var rowItem = 'abc1111'; //would be setting the rowId or some sort of identifier
aTag.onclick = itemLink.LinkFunction;
var output = [];
output.push('<table>');
output.push('<thead>');
output.push('<tr><th>col1</th><th>col2</th></tr>');
output.push('</thead>');
output.push('<tbody>');
output.push('<tr><td>col1 data</td><td>col2 data</td></tr>');
output.push('</tbody></table>')
var mainView = document.getElementById('mainViewer');
mainView.innerHTML = output.join('');
var d1 = document.createElement('div');
d1.appendChild(aTag);
mainView.appendChild(d1)
<div id="mainViewer"></div>
Thanks to #David Thomas for his comment :)
I have made my full FF extension, and there is a button in the URL bar. The boss now wants the button to show a certain string when you hover over it. Here is my current code for the button:
var loadURLButton = function(doc, urlBtnClick) {
var urlBarIcons = doc.getElementById('urlbar-icons')
var btn = doc.createElement('toolbarbutton');
btn.setAttribute('id', 'urlbutton');
btn.setAttribute('image', require('sdk/self').data.url("canNone.png"));
btn.addEventListener('command', urlBtnClick, false);
urlBarIcons.appendChild(btn);
return btn;
}
var doc = require('sdk/window/utils').getMostRecentBrowserWindow().document;
var urlbarButton = loadURLButton(doc, openTab);
What can I add to this in order to make some id pop up on hover?
Awwwww man all that work for nothing. The attribute is not tooltip but it is tooltiptext! So just do btn.setAttribute('tooltiptext', 'what ever you want');
var loadURLButton = function(doc, urlBtnClick) {
var urlBarIcons = doc.getElementById('urlbar-icons')
var btn = doc.createElement('toolbarbutton');
btn.setAttribute('id', 'urlbutton');
btn.setAttribute('tooltiptext', 'mytt');
btn.setAttribute('image', 'chrome://branding/content/icon32.png');
btn.addEventListener('command', urlBtnClick, false);
urlBarIcons.appendChild(btn);
return btn;
}
var doc = document;
var urlbarButton = loadURLButton(doc, null);
I see the issue i tried setting attribute of tooltip on it and all the anonys children and it didnt work.
So Im thinking of attachinga panel to it. This code doesnt work but we're in the right direction:
https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/panel#Examples
var loadURLButton = function(doc, urlBtnClick) {
var urlBarIcons = doc.getElementById('urlbar-icons')
var tooltip = doc.createElement('panel');
tooltip.setAttribute('style', 'width:100px;height:100px;background-color:red;');
tooltip.setAttribute('id', 'mytt');
tooltip.textContent = 'my toold tip';
var btn = doc.createElement('toolbarbutton');
btn.setAttribute('id', 'urlbutton');
btn.setAttribute('tooltip', 'mytt');
btn.setAttribute('image', 'chrome://branding/content/icon32.png');
btn.addEventListener('command', urlBtnClick, false);
btn.appendChild(tooltip)
urlBarIcons.appendChild(btn);
return btn;
}
var doc = document;
var urlbarButton = loadURLButton(doc, null);
I am having an issue deleting or replacing a div with a either an empty div or a new veriosn of the div. I have tried to destroy the div with delete $targetname I've tried to replace the div with $("#divname").replace() and I seem to be missing some. I have the function tied to a button click that also clears a textarea and that part works fine but my form continues to show the divs that are getting appended but never removed. Below is the link to the fiddle for my code, any help is appreciated.
http://jsfiddle.net/fNfK8/
emWindow = window.open("", null, "height=400,width=800,status=yes,toolbar=no,menubar=no,location=no");
emWindow.document.title = "Emote Builder";
emWindow.document.body.style.background = "#00214D";
emWindow.document.body.style.color = "White";
// create a form and set properties
var emForm = document.createElement('form');
emForm.id = 'emForm';
// insert into the body of the new window
emWindow.document.body.appendChild(emForm);
// add text before the input
var emoteBuildL = document.createElement('emoteBuildL');
emForm.appendChild(document.createTextNode('Emote Build Window:'));
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
// add a text input
var emoteBuild = document.createElement('textarea');
emoteBuild.type = 'text';
emoteBuild.name = 'emoteBuild';
emoteBuild.id = 'emoteBuild';
emoteBuild.rows = 6;
emoteBuild.cols = 80;
emoteBuild.value = '';
emForm.appendChild(emoteBuild);
var emoteTosend = document.getElementById('emoteBuild');
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
var ePreview = document.createElement('button');
ePreview.type = 'button';
ePreview.innerHTML = 'Preview Emote';
ePreview.onclick = emoteFunc;
emForm.appendChild(ePreview);
var eSubmit = document.createElement('button');
eSubmit.type = 'button';
eSubmit.innerHTML = 'Send Emote';
eSubmit.onclick = function () {
client.send_direct("" + emoteBuild.value);
};
emForm.appendChild(eSubmit);
var eClear = document.createElement('button');
eClear.type = 'button';
eClear.innerHTML = 'Clear Emotes';
eClear.onclick = function () {
emoteBuild.value = '';
delete $emPreviews;
};
emForm.appendChild(eClear);
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
// add text before the input
var emotePviewL = document.createElement('emotePviewL');
emForm.appendChild(document.createTextNode('Emote Previews:'));
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
function emoteFunc() {
var emPreview = emoteBuild.value;
emPreview = emPreview.replace(/%%(.+?)%%/g, "\<font color=\"red\"\>\"$1\"\</font\>");
emPreview = emPreview.replace(/%%/g, "\"");
emPreview = emPreview.replace(/\^/g, "");
emPreview = emPreview.replace(/(\w+_him)/g, "(him/her)");
emPreview = emPreview.replace(/(\w+_his)/g, "(his/her)");
emPreview = emPreview.replace(/(\w+_he)/g, "(he/she)");
emPreview = emPreview.replace(/#/g, "");
var div = document.createElement("div");
div.class = 'emPreviews';
div.id = 'emPreviews';
div.style.color = "black";
div.style.backgroundColor = "white";
div.innerHTML = emPreview;
emForm.appendChild(div);
emForm.appendChild(linebreak);
}
You will find it very much more efficient to put the HTML into a separate file and use that as the source for the new window. Alternatively, use document.write to add content to the page, e.g. the following replaces about 20 lines at the start of your script:
function openWin() {
var emWindow = window.open("", null, "height=400,width=800,status=yes");
emWindow.document.write(
'<!doctype html><title>Emote Builder<\/title>' +
'<style type="text/css">body{background-color: #00214D;color:White;}<\/style>' +
'<form id="emForm">' +
'Emote Build Window:<br>' +
'<textarea name="emoteBuild" id="emoteBuild" rows="6" cols="80"><\/textarea>'
);
emWindow.document.close();
}
Note that when you do:
var linebreak = document.createElement('br');
it creates an element in the current document, but then:
emForm.appendChild(linebreak);
appends it to an element in a different document. You really should do:
var linebreak = emWindow.document.createElement('br');
emForm.appendChild(linebreak);
Or just put it in the HTML above.
You are also creating a button in the opener window, appending it to the form, then having it call a function in the opener. The new window has a new global context, it doesn't have access to the opener's scope. You can do:
ePreview.onclick = window.opener.emoteFunc;
or similar but you might find that blocked in some browsers.
I'd suggest you re–write the function to firstly generate the HTML you want, then write it to a new window using emWindow.document.write. Don't forget to call emWindow.document.close at the end.
Edit
Remember that you are working across documents. So if you are still running the script in the opener (the original window), you have to preface any reference to methods in the child window with a reference to emWindow, e.g. to get a reference to the form in the child window you have to use:
function emoteFunc() {
// Get a reference to the form in the child window
var emPreview = emWindow.document.getElementById('emoteBuild');
...
// Create a div in the child window to append to it
var div = emWidnow.document.createElement('div');
...
// The form and div are in the same document, so just append
emForm.appendChild(div);
// Create a BR element in the child and append it
emForm.appendChild(emWindow.document.createElement('br'));
...
}
Edit 2
Here is a trivial example of sending data between a child and opener.
<script>
var win;
function newWin(){
win = window.open('','','');
win.document.write(
'<title>new window<\/title>' +
'<script>function getValue() {' +
'document.getElementById("i0").value = opener.document.forms.f0.i0.value;}<\/script>' +
'<input id="i0">' +
'<input type="button" onclick="getValue()" value="Get value from opener">' +
'<input type="button" onclick="opener.getValue()" value="Get value using function in opener">'
);
win.document.close();
};
function getValue() {
console.log('getValue called');
console.log(win.document.getElementById('i0').value);
win.document.getElementById('i0').value = document.f0.i0.value;
}
function sendValue(value) {
win.document.getElementById('i0').value = value;
}
</script>
<button onclick="newWin()">Open child</button>
<form id="f0">
<p>Value to get from child
<input name="i0" value="value in opener">
<input type="button" value="Send value" onclick="sendValue(this.form.i0.value)">
</form>
You will discover that (in IE at least) you can:
call a function in the child window to get a value from the opener
call a function in the opener to send a value to the child
call a function in one window from the other,
but you can't call a function in the other window that updates the current window, that's one too many hops.
So any function you want to call from the child should be in the child, and any function you want to call from the opener should be in the opener.
I have the following js code:
function createConBox() {
var charDiv = document.getElementById("characterList"); // reference to "characterList" div
header = document.createElement("p"); // creates the <p> tag
charDiv.appendChild(header); // adds the <p> tag to the parent node
title = document.createTextNode("Show Only Lines By:"); // creates the text string
header.appendChild(title); // adds the text string to the parent node
// create select box and add elements
selectBox = document.createElement("select");
selectBox.setAttribute("id", "cList");
charDiv.appendChild(selectBox);
charNames = uniqueElemText("h3"); // array of character names
newOption = document.createElement("option");
selectBox.appendChild(newOption);
newOptionTitle = document.createTextNode("Show All Lines");
newOption.appendChild(newOptionTitle);
for (i = 0; i < charNames.length; i++) {
newOption = document.createElement("option");
selectBox.appendChild(newOption);
newOptionTitle = document.createTextNode(charNames[i]);
newOption.appendChild(newOptionTitle);
}
}
function showLines() {
alert("The Box has been changed");
}
Every time the option in the box is changed, I want it to call 'showLines()'. However, every time I try to implement an event, I can only get it to trigger when the page loads, and never again thereafter.
selectBox.onchange = showLines; should solve your problem.
in some browsers onchange get fired only after blurring select box. to over come this you can use onclick instead of onchange
My guess is that you're doing this:
selectBox.onchange = showLines();
If that's the case, just remove the ():
selectBox.onchange = showLines;
When I pass dynamically id in case then what I do:
var selectcell = tablerow.insertCell(1);
var selectelmt = document.createElement('select');
selectelmt.name = 'Select';
selectelmt.value = 'select';
selectelmt.classList = 'form-control input-sm cobclass';
selectelmt.onchange= onselectchange(i);
selectelmt.id = 'cobselect' + i;
selectelmt.options[0] = new Option('select');
selectcell.appendChild(selectelmt);
// ddrbind(i);
show();
i++;`