Link add-on SDK panel to toolbar button - javascript

The add-on SDK attaches panels to widgets as seen here. I would like to achieve the same effect using the add-on SDK with a toolbar button instead.
The toolbar button I'm using is of the type menu-button, which means that the left side is an icon and has an oncommand listener. The right side is a drop-down arrow which shows its contents on click. Here's the code to create such a button with the add-on SDK:
const doc = require('sdk/window/utils').getMostRecentBrowserWindow().document;
var navBar = doc.getElementById('nav-bar')
var btn = doc.createElement('toolbarbutton');
btn.setAttribute('id', 'hylytit');
btn.setAttribute('type', 'menu-button');
btn.setAttribute('class', 'toolbarbutton-1');
btn.setAttribute('image', data.url('resources/hylyt_off.png'));
btn.setAttribute('orient', 'horizontal');
btn.setAttribute('label', 'Hylyt.it');
btn.addEventListener('command', function(event) {
if (event.button===0) btnClick();
console.log(TAG+'button clicked');
}, false);
var panel = doc.createElement('panel');
panel.setAttribute('id', 'search-panel');
panel.addEventListener('command', function(event) {
console.log(TAG+'dropdown clicked');
}, false);
var label = doc.createElement('label');
label.setAttribute('control', 'name');
label.setAttribute('value', 'Article List');
var textbox = doc.createElement('textbox');
textbox.setAttribute('id', 'name');
panel.appendChild(label);
panel.appendChild(textbox);
btn.appendChild(panel);
navBar.appendChild(btn);
The panel above is not an add-on SDK panel, it's a XUL panel and is severely limited in that it can't be styled with CSS. On top of this, the panel's onCommand listener never fires despite the fact that the btn's onCommand fires as expected. The XUL panel shows itself when I click the dropdown button (as long as it has children), but because I can't access its click handler, I can't just create an add-on SDK panel on click.
So my question is this. Is there a way to access the toolbar button's menu portion's click handler or is there a way to append an add-on SDK panel as a child of a toolbar button?

Thanks for pointing me in the direction of arrow panels. Is there a way to place an HTML file in one rather than having to dynamically create XUL elements? The effect I'm trying to achieve is similar to the Pocket extension, which does one thing when the button part is clicked and another when the arrow is clicked. – willlma 7 hours ago
You have 900+ rep, you should know better. It is common knowledge to create another question topic rather then ask how to do something different in a comment especially after solution acceptance.
Nonetheless, this is what you do to accomplish the Pocket toolbarbutton effect. Based on code supplied by contributor above.
Ask another question and I'll move this there and you can accept my solution there.
var doc = document;
var navBar = doc.getElementById('nav-bar')
var btn = doc.createElement('toolbarbutton');
btn.setAttribute('id', 'hylytit');
btn.setAttribute('type', 'menu-button');
btn.setAttribute('class', 'toolbarbutton-1');
btn.setAttribute('image', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowMjgwMTE3NDA3MjA2ODExODcxRjlGMzUzNEZGQkNGQiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxRUM5MTQ0MkJFNkUxMUUxOUM3NzgwMzc3MDc2Rjk1MCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxRUM5MTQ0MUJFNkUxMUUxOUM3NzgwMzc3MDc2Rjk1MCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgTWFjaW50b3NoIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDI4MDExNzQwNzIwNjgxMTg3MUZFQTk0QUU4RTMwMEYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDI4MDExNzQwNzIwNjgxMTg3MUY5RjM1MzRGRkJDRkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5kJv/fAAAByUlEQVR42qRTPWvCYBC+mKiolFYURVSwfoCLkw4iGDM5WoO460/o4tKuHToV+gd0t5Ku4mQWJ8Fd/NhEpy6K3+ldakKsi+ALb3hzd89zd8+9L6MoCtyyOPpkMpl3m81WM5lMV4GOxyOsVqu3Xq/3qhIEg8Ga1+sFs9l8FcFut4P5fP6Cxz8CAvt8PmBZ9iqCw+Ggn9WaKTOB9/s9FAoF4Hn+LIjOZCMfxVGrWrWcFkRiWiwWiMfjIv6GOI77kGUZ1us15PN5SKVSz2ifttvtL2yBPRNRI1gsFiCK4pMkSVUE/GBrn5vN5i4ajVYxpFEsFuuRSIR1u91wQcAwDOAkwOl0VjBjCIFit9sdoOshl8sNsLp6IBCoOBwOME5LJSABqU8i8Pv91Kcwm83kdDrNk9/lcslYTYLi7HY7aBidIJvNTjqdziNpQBmIBDVIoFDT05TuPR6PCqbs2+0WBEGYqJWfbmKx2WxKo9FIDSAbtgDL5VLNQqRWq1Vtky4R6gDlcpnE/mYMV7nearUqw+FQJzEuDRyLxaBUKjXQVDVWoJNgFZV+vw/j8VgXi4DhcBiSySRl18H6+P5tAbekXC7p5DuLZ259jb8CDAAxmdyX9iaHkQAAAABJRU5ErkJggg==');
btn.setAttribute('orient', 'horizontal');
btn.setAttribute('label', 'Hylyt.it');
////
var toolbarbuttonPanel = doc.createElement('panel');
toolbarbuttonPanel.setAttribute('id', 'toolbarbutton-panel');
toolbarbuttonPanel.setAttribute('type', 'arrow');
var toolbarbuttonLabel = doc.createElement('label');
toolbarbuttonLabel.setAttribute('value', 'toolbarbutton panel');
toolbarbuttonPanel.appendChild(toolbarbuttonLabel);
////
////
var dropmarkerPanel = doc.createElement('panel');
dropmarkerPanel.setAttribute('id', 'dropmarker-panel');
dropmarkerPanel.setAttribute('type', 'arrow');
var dropmarkerLabel = doc.createElement('label');
dropmarkerLabel.setAttribute('value', 'dropmarker panel');
dropmarkerPanel.appendChild(dropmarkerLabel);
////
navBar.appendChild(btn);
var mainPopupSet = document.querySelector('#mainPopupSet');
mainPopupSet.appendChild(dropmarkerPanel);
mainPopupSet.appendChild(toolbarbuttonPanel);
btn.addEventListener('click',function(event) {
console.log('event.originalTarget',event.originalTarget);
if (event.originalTarget.nodeName == 'toolbarbutton') {
dropmarkerPanel.openPopup(btn);
} else if (event.originalTarget.nodeName == 'xul:toolbarbutton') {
toolbarbuttonPanel.openPopup(btn);
}
}, false);

Panels don't have an onCommand method see MDN - Panels Article
You can make your panel stylized, give it type arrow like panel.setAttribute('type', 'arrow') and then to attach to your button. I didn't give it type arrow below.
Heres the working code. Copy paste to scratchpad and set Environment > Browser then run it.
var doc = document; //to put this back in sdk do const doc = require('sdk/window/utils').getMostRecentBrowserWindow().document;
var navBar = doc.getElementById('nav-bar')
var btn = doc.createElement('toolbarbutton');
btn.setAttribute('id', 'hylytit');
btn.setAttribute('type', 'menu-button');
btn.setAttribute('class', 'toolbarbutton-1');
btn.setAttribute('image', ''); //i made this image blank because i dont have the image and im running from scratchpad
btn.setAttribute('orient', 'horizontal');
btn.setAttribute('label', 'Hylyt.it');
var panel = doc.createElement('panel');
btn.addEventListener('command', function(event) { //moved this below var panel = doc.createElement because panel needs to be crated before we write this function
//if (event.button===0) btnClick();
//console.log(TAG+'button clicked'); //what is TAG? its undefeined for me
panel.openPopup(btn);
}, false);
panel.setAttribute('id', 'search-panel');
/*
panel.addEventListener('command', function(event) {
console.log(TAG+'dropdown clicked'); //what is TAG? its undefeined for me
}, false);
*/
var label = doc.createElement('label');
label.setAttribute('control', 'name');
label.setAttribute('value', 'Article List');
var textbox = doc.createElement('textbox');
textbox.setAttribute('id', 'name');
panel.appendChild(label);
panel.appendChild(textbox);
btn.appendChild(panel);
navBar.appendChild(btn);

You can create a Toolbarbutton and Panel using the Addon SDK and some Jetpack modules. Try toolbarwidget-jplib and browser-action-jplib by Rob--W.
You can easy add a button to the toolbar and style the panel whatever you want with css / html:
var badge = require('browserAction').BrowserAction({
default_icon: 'images/icon19.png', // optional
default_title: 'Badge title', // optional; shown in tooltip
default_popup: 'popup.html' // optional
});

Related

How to set the button in my toolbar to disabled

I have created a toolbar in my windows 10 UWP winjs app and I want to disable some of the buttons.
I append attributes to the button like so :
new WinJS.UI.Command(null, {
disable: true,
id: 'cmdSave',
label: 'save',
section: 'primary',
type: 'button',
icon: 'save',
onclick: clickbuttonprintout()
});
I have looked through the winjs css files and found many disabled tags. Is it possible to set the button to disabled like I have appended other attributes above ?
Figured this out :
You select the button, set it to disabled and then process it.
var thisBtn = document.getElementById('cmdSave');
thisBtn.disabled = true;
WinJS.UI.process(btn); //this is key
With this in mind, I set up a function so I can pass different buttons to it:
function disableButton(buttonID){
var btn = document.getElementById(buttonID);
btn.disabled = true;
WinJS.UI.process(btn);
}
P.S
Even though this is not part of the question, it may help people.
What about editing the attributes on the button too ? Ive made this function to edit any attribute on a winjs button :
function changeButtonAttributes(buttonId, element, attribute) {
var btn = document.getElementById(buttonId); //select button
btn.winControl[element] = attribute; //button.element = attribute
WinJS.UI.process(btn); //process all
}
Hope that helps :)

Hiding field of custom-multi-field using javascript in listener

I have customized form of multi-field in a component having two variations.
In one variation of my component I want to hide a field (title) which is inside custom-multi-field . I am using the following JavaScript code in listener.
This code is not working. Where am I wrong?
function() {
var dialog = this.findParentByType('dialog');
var contenttype = dialog.getField("./type").getValue();
var teaserlinks = dialog.getField("./teaserlinks");
var title = dialog.getField("./teaserlinks").getField("./title");
alert(title);
if(contenttype == 'variation-1'){
teaserlinks.show();
title.hide();
}
else if(contenttype == 'variation-2'){
teaserlinks.show();
}
}
Try using the hidden property of node. Initially set the hidden property to true and in javascript file change the hidden property to false (or as per your requirement).
Few imp points first before answer:
you have to write listener in your widget file only.
below is the sample code where in I have 2 fields. 1st field is mytext field and another field is myselection. On changing the value in myselection field I am toggling visibility of my text field.
Below is snippet:
this.mytext = new CQ.form.textField({...})
this.myselection = new CQ.form.Selection({
fieldLabel:"my selection",
type:"select",
width : "325",
allowBlank:false,
defaultType:"String[]",
fieldDescription : "Select value from dropdown",
options: "/a/b/c.json",
listeners : {
selectionchanged : function(){
var mytext = this.findParentByType('mywidget').mytext;
mytext.hide();
}
}
});
I hope this will be helpful.
I have no knowledge about aem and Adobe CQ5 but I can give you some hints how to debug your script.
First of all don't use alert for debugging! (BTW what does alert(title); show?)
I would recommend to open the browser console (e.g. Press <F12> on Firefox and switch to the tab "Console").
Herein the browser displays all exceptions and error messages. Additionally you can output some text with console.log("...");` from your script.
Here is my edit of your program. Perhaps the output can help you.
function()
{
var dialog = this.findParentByType('dialog');
var contenttype = dialog.getField("./type").getValue();
var teaserlinks = dialog.getField("./teaserlinks");
var title = dialog.getField("./teaserlinks").getField("./title");
console.dir(title);
console.log(contenttype);
teaserlinks.show();
if(contenttype == 'variation-1')
{
title.hide();
}
else if(contenttype == 'variation-2')
{
title.show();
}
}
And, console.dir(<object>); shows you the object structure to one level deep.

TinyMCE Enable button while in read only mode

I have a TinyMCE 4.x instance where the text should be in read only mode. But I still have some buttons that I want to have enabled. For example, one button could provide a character count for the part of the text I've selected.
But when I turn on read only mode for TinyMCE all buttons are disabled. Can I enable just my buttons while still retaining read only mode?
It's probably too late for you but other people may pass by here.
I came up by writing this function
function enableTinyMceEditorPlugin(editorId, pluginName, commandName) {
var htmlEditorDiv = document.getElementById(editorId).previousSibling;
var editor = tinymce.get(editorId);
var buttonDiv = htmlEditorDiv.querySelectorAll('.mce-i-' + pluginName.toLowerCase())[0].parentElement.parentElement;
buttonDiv.className = buttonDiv.className.replace(' mce-disabled', '');
buttonDiv.removeAttribute('aria-disabled');
buttonDiv.firstChild.onclick = function () {
editor.execCommand(commandName);
};
}
It does the trick in 2 steps:
make the button clickable (remove mce-disabled CSS class and remove the aria-disabled property)
assign the good command to the click event
And in my editor init event I call the function.
editor.on('init', function () {
if (readOnly) {
editor.setMode('readonly');
enableTinyMceEditorPlugin(htmlEditorId, 'preview', 'mcePreview');
enableTinyMceEditorPlugin(htmlEditorId, 'code', 'mceCodeEditor');
}
});
Current version of TinyMCE for which I wrote this code is 4.4.3. It may break in a future version, specifically about the selectors to get and modify the good HTML elements.
Command identifiers can be found at this page otherwise you can also find them under tinymce\plugins\PluginName\plugin(.min).js
Here is a simple way to enable your custom toolbar button and attach a click event handler inside a read only TinyMCE editor using JQUERY:
//Initialize read only Tinymce editor so that Lock button is also disabled
function initReadOnlyTinyMCE() {
tinymce.init({
selector: '#main'
, toolbar: 'myLockButton'
, body_class: 'main-div'
, content_css: 'stylesheets/index.css'
, readonly: true
, setup: function (readOnlyMain) {
readOnlyMain.addButton('myLockButton', { //Lock button is disabled because readonly is set to true
image: 'images/lock.png'
, tooltip: 'Lock Editor'
});
}
});
}
function displayReadOnlyTinyMCEwithLockButtonEnabled() {
var edContent = $('main').html();
$("#main").empty();
initReadOnlyTinyMCE(true);
tinyMCE.activeEditor.setContent(edContent);
//enable the lock button and attach a click event handler
$('[aria-label="Lock Editor"]').removeClass("mce-disabled");
$('[aria-label="Lock Editor"]').removeAttr("aria-disabled");
$('[aria-label="Lock Editor"]').attr("onclick", "LockEditor()");
}
function LockEditor() {
alert("Tiny mce editor is locked by the current user!!");
//Write your logic to lock the editor...
}
I couldn't find an easy way to do this. The simplest way is to remove the contenteditable attribute from the iframe body instead and substitute a read only toolbar set. It also means that people will still be able to copy content from the editor.
$("iframe").contents().find("body").removeAttr("contenteditable");
How about this :
editor.addButton('yourButton', {
title: 'One can Enable/disable TinyMCE',
text: "Disable",
onclick: function (ee) {
editor.setMode('readonly');
if($(ee.target).text() == "Disable"){
var theEle = $(ee.target).toggle();
var edit = editor;
var newBut = "<input type='button' style='opacity:1;color:white; background-color:orange;' value='Enable'/>";
$(newBut).prependTo($(theEle).closest("div")).click(function(e){
edit.setMode('design');
$(e.target).remove();
$(theEle).toggle();
});
}
}
});
You can try to run the code below:
$("#tinymce").contentEditable="false";
if you have more than one editors, you can use their id like below
$("#tinymce[data-id='idOfTheEditor']").contentEditable="false";

Print preview xulrunner

So I'm having this problem with opening print preview in xulrunner.
I open print preview but i can't get the navigation toolbar.
This is the code from PrintUtils.js where the toolbar is created:
var XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
printPreviewTB = document.createElementNS(XUL_NS, "toolbar");
printPreviewTB.setAttribute("PrintPreview", true);
printPreviewTB.id = "print-preview-toolbar";
printPreviewTB.className = "toolbar-primary";
And later it does this:
var navToolbox = this._callback.getNavToolb
navToolbox.parentNode.insertBefore(printPreviewTB, browser);
I'm providing the navToolbox, that's the place where the toolbar is inserted but it doesn't show. As I said, print preview opens perfectly, pages formatted and everything but without toolbar.
Anyone have any idea why?
Ok, i found soulution, if anyone is interested.
So when enternig printPreview you have to pass an object with 5 functions:
getSourceBrowser, getPrintPreviewBrowser, getNavToolbox, onEnter and onExit.
With getNavToolbox you pass the reference to toolbar (placeholder) where you want to place standard navigation toolbar (with print button, zoom, and others).
I have done all that but you have to bind to that toolbar, like this :
toolbar.style.MozBinding = url('chrome://global/content/printPreviewBindings.xml#printpreviewtoolbar')";
I'm doing that in the onEnter function.
But i also had problem with the enterPrintPreview function from PrintUtils.js.
In this part of code:
var printPreviewTB = document.getElementById("print-preview-toolbar");
if (printPreviewTB) {
printPreviewTB.updateToolbar();
tmptoolbar.updateToolbar();
var browser = this._callback.getPrintPreviewBrowser();
browser.collapsed = false;
browser.contentWindow.focus();
return;
}
printPreviewTB.updateToolbar(); throws error.
I fixed this by getting the reference to the toolbar that i passed in getNavToolbox function and then calling updateToolbar on him, like this:
var printPreviewTB = document.getElementById("print-preview-toolbar");
if (printPreviewTB) {
var tmptoolbar = this._callback.getNavToolbox();
tmptoolbar.updateToolbar();
var browser = this._callback.getPrintPreviewBrowser();
browser.collapsed = false;
browser.contentWindow.focus();
return;
}
And now everything works fine.

How to add content to a containerNode that already has its content from href using dijit.Dialog

I’m new with this javascript and dijit.
My problem: In my js-function I’m building up a dijit.Dialog, using parameters that has been sent to the function.
One of the parameters is a href to en external xhtml-file that contains only the text that’s supposed to be shown in the dialog. Now, I want to add a div with one more link to the dialog, in the containerNode (with a link that's supposed to be specific for every single user).
The problem is that I can se that the added div is there until I reach dialog.show, after that it disapears. The text from the xhtml takes over. If I put it in the domNode (like the button) it shows up in the wrong place.
I've also tried another approach, to let the link be in the external href (in file three), give it an id and tried to reach it that way and manipulate it. Like this:
document.getElementById("bytlosen").href="www.xxx.se";
But it doesn't work. I get "document.getElementById(...) is null.
I would be SO happy if anyone can help me how to add the div (link) to the dialog! It doesn't matter if I
have it in file three and can reach it from file two and manipulate it,
simply adds the div in the js (in file two), or
any other way?
I have three files:
file one.xhtml (calling file two):
<li>Kontakta oss</li>
file two.js:
Xxxx.contactsDialog = function(title, href, cssClass, destroy) {
if (href) {
var options = {
title: title,
href: href
};
if (cssClass)
options["class"] = cssClass;
var dialog = new dijit.Dialog(options);
var div = document.createElement("div");
var bytLosen = document.createElement("a");
bytLosen.appendChild(document.createTextNode("Byt lösenord"));
bytLosen.setAttribute("href", "https://xxxx.xxx.se/xxx/xxx/xxxx=xxxx&TARGET=xxx.xxx.se");
bytLosen.setAttribute("target", "_blank");
div.appendChild(bytLosen);
dialog.containerNode.appendChild(div);
var okButton = document.createElement("button");
okButton.setAttribute("type", "submit");
okButton.setAttribute("style", "margin-top: 10px");
okButton.innerHTML = "Ok";
dojo.addClass(okButton, "button");
dialog.domNode.appendChild(okButton);
dialog.startup();
dialog.show();
dojo.connect(okButton, "onclick", function() {
dialog.hide();
if (destroy) {
dialog.destroy();
}
});
return true;
} else
return false;
};
file three.html:
<div class="popupHeader">Synpunkter och felanmälan <span style="font-weight: normal">skickas till:</span></div>
<div>ajourhallning-xxx#xx.se</div>
<div class="popupHeader">Länkar <span style="font-weight: normal">(till xxxx's externa hemsida)</span></div>
<div>www.xxxxx.se</div>
<div>www.xxxx.se/xxx</div>
<div class="popupHeader">Byt lösenord</div>

Categories

Resources