Figma Plugin - help programmatically creating text style - promise

I am trying to create Figma Text styles via a plugin that reads from my design tokens. The problem I am having is when setting the custom font, the promise to load it does not resolve, so it seems to stall the function.
Am I missing something here?
async function createNewTextStyle(token) {
// Style does not yet exist, so create it
const newStyle = figma.createTextStyle();
// the new text style is preloaded with Roboto, so we need to load that
await figma.loadFontAsync(newStyle.fontName);
// This is the font i want to set my text style to.
// it seems that this promise never resolves (or errors).
await figma.loadFontAsync({
family: 'SF Pro Text',
style: 'Regular',
});
// Set the properties of the text style
newStyle.fontName = {
family: 'SF Pro Text',
style: 'Regular',
};
newStyle.name = designToken.name;
newStyle.fontSize = designToken.value;
newStyle.lineHeight = { value: designToken.lineHeight, unit: 'PIXELS' };
}

Hmmm... it looks like you're missing the .then callback that's usually used to handle a promise resolution.
Also, your variable name designToken is not defined in your code, but you're using token (from your function parameters).
Try this in your plugin:
async function createNewTextStyle(token) {
// Style does not yet exist, so create it
const newStyle = figma.createTextStyle();
// the new text style is preloaded with Roboto, so we need to load that
await figma.loadFontAsync(newStyle.fontName);
// This is the font i want to set my text style to.
figma.loadFontAsync({
family: 'SF Pro Text',
style: 'Regular',
}).then(() => {
// Set the properties of the text style
newStyle.fontName = {
family: 'SF Pro Text',
style: 'Regular',
};
newStyle.name = token.name;
newStyle.fontSize = token.value;
newStyle.lineHeight = { value: token.lineHeight, unit: 'PIXELS' };
});
}

Related

Custom web-chat background image

I am trying to make my own chatbot but am unsure of how to change the background image to my own jpg.
I have tried to place the code in the <body> and inside the styleOptions but none of my methods work.
Below is my html file:
<body style = "background-image: url('CorpBotOrchestrator/Images/whatsapp.jpg');">
<div id="webchat" role="main">Loading...</div>
<script>
styleOptions: {
bubbleFromUserBackground: 'LightBlue',
hideUploadButton: true,
botAvatarImage: 'https://learn.microsoft.com/en-us/azure/bot-service/v4sdk/media/logo_bot.svg?view=azure-bot-service-4.0',
//make the speech bubbles round
bubbleBorderRadius: 20,
bubbleFromUserBorderRadius: 20,
}
}, document.getElementById('webchat'));
})().catch(err => console.error(err));
</script>
</body>
Thank you in advance!
You will want to instantiate your web chat in the following way to change the background image of the activities window. Be aware that, in the BotFramework-WebChat styleSet object, there is activity which represents the individual messages, cards, etc., that are sent, and there is activities which represents the window of scrolling messages. It is the latter we will be working with.
Also, be aware, that because you are directly specifying a DOM element and property, albeit via web chat, should some aspect of web chat receive an update that changes the element or property used, this can cause a breaking change for you. Additionally, you will need to pass all the property values necessary as, generally, this strips all default values from the webchat element you are working with.
const styleSet = createStyleSet ( {
bubbleBackground: 'blue',
bubbleFromUserBackground: 'red',
bubbleBorderRadius: 18,
bubbleFromUserBorderRadius: 18,
} );
styleSet.activities = {
...styleSet.activities,
backgroundImage: "url('<someUrlLink>')";
}
window.WebChat.renderWebChat( {
directLine: [...],
styleSet
});
Hope of help!
EDIT
styleOptions can actually be passed in using the spread operator into styleSet. In this way, you can continue to use the ease of styleOptions for customizing and largely remain within best practices of Web Chat.
const styleOptions = {
bubbleBackground: 'blue',
bubbleFromUserBackground: 'red',
bubbleBorderRadius: 18,
bubbleFromUserBorderRadius: 18
}
const styleSet = createStyleSet ( {
...styleOptions,
} );
styleSet.activities = {
...styleSet.activities,
backgroundImage: "url('<someUrlLink>')";
}
window.WebChat.renderWebChat( {
directLine: [...],
styleSet
});

Display AboutDialog from GNOME Shell Extension

I'm trying to display a Gtk.AboutDialog from my GNOME Shell extension. I wrote the following function:
_showAbout: function() {
var authors = ["Ralf"];
// Create the About dialog
let aboutDialog = new Gtk.AboutDialog({ title: "About AboutDialogTest",
program_name: "MyExtension Version " + MySelf.metadata.version,
copyright: "AboutDialogTest \xa9 2018",
authors: authors,
website: "https://...",
website_label: "MyExtension Homepage",
comments: "GNOME Shell extension to test AboutDialog"
});
// Connect the Close button to the destroy signal for the dialog
aboutDialog.connect("response", function() {
aboutDialog.destroy();
});
aboutDialog.show();
}
Well, the about dialog is displayed, but not correctly. I can get the dialog to the front by clicking, but clicking on [x] doesn't close the dialog. The dialog can be closed by hitting ESC.
In syslog I see the following messages:
org.gnome.Shell.desktop[4033]: Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged.
org.gnome.Shell.desktop[4033]: Window manager warning: Buggy client sent a _NET_ACTIVE_WINDOW message with a timestamp of 0 for 0xe0022c (About Abou)
I'm in a extension, so I have no "transient parent". At least I don't know how to get one.
Any idea what I have to do to display it properly?
Ok, I'll answer my own question.
From my understanding it is not possible to use a GTK dialog in a GNOME Shell extension. If a "About Dialog" is needed, roll your own using modaldialog.js.
This is not as cool as the GTK stuff, but at least something.
const St = imports.gi.St;
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const ModalDialog = imports.ui.modalDialog;
const Clutter = imports.gi.Clutter;
const ExtensionUtils = imports.misc.extensionUtils;
const MySelf = ExtensionUtils.getCurrentExtension();
const MyAboutDialog = new Lang.Class({
Name: 'MyAboutDialog',
Extends: ModalDialog.ModalDialog,
_init: function() {
this.parent({ styleClass: 'extension-dialog' });
this.setButtons([{ label: "OK",
action: Lang.bind(this, this._onClose),
key: Clutter.Escape
}]);
let box = new St.BoxLayout({ vertical: true});
this.contentLayout.add(box);
let gicon = new Gio.FileIcon({ file: Gio.file_new_for_path(MySelf.path + "/icons/icon.png") });
let icon = new St.Icon({ gicon: gicon });
box.add(icon);
box.add(new St.Label({ text: "AboutDialogTest Version " + MySelf.metadata.version, x_align: Clutter.ActorAlign.CENTER, style_class: "title-label" }));
box.add(new St.Label({ text: "GNOME Shell extension to display an About Dialog.", x_align: Clutter.ActorAlign.CENTER }));
box.add(new St.Label({ text: "This program comes with absolutely no warranty.", x_align: Clutter.ActorAlign.CENTER, style_class: "warn-label" }));
box.add(new St.Label({ text: "Copyright © 2017-2018 BlahBlahBlah", x_align: Clutter.ActorAlign.CENTER, style_class: "copyright-label" }));
},
_onClose: function(button, event) {
this.close(global.get_current_time());
},
});
And call it like this:
_showAbout2: function() {
let dialog = new MyAboutDialog();
dialog.open(global.get_current_time());
},

CKEditor widget receives data after it has been rendered

Looking at the docs you can pass startup data to a widget:
editor.execCommand( 'simplebox', {
startupData: {
align: 'left'
}
} );
However this data is pointless as there seems to be no way to affect the template output - it has already been generated before the widget's init, and also the data isn't even available at that point:
editor.widgets.add('uselesswidget', {
init: function() {
// `this.data` is empty..
// `this.dataReady` is false..
// Modifying `this.template` here does nothing..
// this.template = new CKEDITOR.template('<div>new content</div>');
// Just after init setData is called..
this.on('data', function(e) {
// `e.data` has the data but it's too late to affect the tpl..
});
},
template: '<div>there seems to be no good way of creating the widget based on the data..</div>'
});
Also adding a CKEditor tag throws a "Uncaught TypeError: Cannot read property 'align' of undefined" exception so it seems the data is also not passed to the original template:
template: '<div>Align: {align}</div>'
What is the point of having a CKEDITOR.template.output function which can accept a context, if there's no way of dynamically passing data?
The only horribly hacky solution I've found so far is to intercept the command in a beforeCommandExec and block it, then modify the template and manually execute the command again..
Any ideas to generate dynamic templates based on passed data? Thanks.
Here's how I did it.
Widget definition:
template:
'<div class="myEditable"></div>',
init: function () {
// Wait until widget fires data event
this.on('data', function(e) {
if (this.data.content) {
// Clear previous values and set initial content
this.element.setHtml('')
var newElement = CKEDITOR.dom.element.createFromHtml( this.data.content );
this.element.append(newElement,true);
this.element.setAttribute('id', this.data.id);
}
// Create nestedEditable
this.initEditable('myEditable', {
selector: '.myEditable',
allowedContent: this.data.allowedContent
})
});
}
Dynamic widget creation:
editor.execCommand('myEditable', {startupData: {
id: "1",
content: "some <em>text</em>",
allowedContent: {
'em ul li': true,
}
}});

How to remove an event listener?

I use the Mozilla's Add-on Builder. I am looking for a way to remove an event listener in a contentScript. I use the port way to communicate between add-on script code and the content script code.
The problem is the callback on event "response" is called more than once. I want it to be called once and declared in the callback of the event show.
Can someone help me with that?
main.js code:
var Panel = require("panel").Panel;
var popup_panel = Panel({
width: 286,
height: 340,
contentURL: require("self").data.url("popup.html"),
allow: { script: true },
contentScriptWhen: "end",
contentScriptFile : [
require("self").data.url("test.js")
],
onShow: function(){
this.port.emit("show");
var pan = this;
this.port.on("hide", function(){pan.hide();});
}
});
var Widget = require("widget").Widget;
var widget = Widget({
id: "mozilla-icon",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico",
panel: popup_panel
});
popup_panel.port.on("get", function(){
popup_panel.port.emit("response");
});
Content script (test.js):
self.port.on("show", function(){
console.log("show");
function response(){
console.log("reponse called");
}
self.port.emit("get");
self.port.once("response", response);
self.port.removeListener("response", response);
});
full source code
Finally I found the problem. It is a bug in the add-on kit. In the file api-utils/lib/content/content-worker.js in the function removeListener the index is always -1.
The parameter given in the indexOf is the name of the event and it search a function. It is incorrect.
So to solve the problem I replace the line let index = listeners[name].indexOf(name); by let index = listeners[name].indexOf(callback);.
EDIT
The bug has been fixed. It will publish in the version 1.10 see here

Find URL of current tab. Making a FireFox Browser add-on

I'm making a Firefox Browser Add-on and need to find the url of the current tab
I've tried this post Opening a URL in current tab/window from a Firefox Extension but it tells me that 'window' is not defined. (I think because I am making an add-on rather than an extension.)
Here's what I've tried to do:
var widgets = require('widget');
var tabs = require('tabs');
var widget1 = widgets.Widget({
id: "widget1",
label: "widget1",
contentURL: "http://www.mozilla.org/favicon",
onClick: function() {
console.log(tabs.url);
}
})
I've made a widget such that when I click it the url of the current tab should be 'console.log'ed.
Doesn't seem to happen! Keep getting "info: undefined" which clearly means that tabs.url isn't returning anything. But this seems to be the way to use it according to https://addons.mozilla.org/en-US/developers/docs/sdk/1.5/packages/addon-kit/docs/tabs.html
Anyone have any ideas?
Thanks,
Will
You're almost there:
const { ActionButton } = require("sdk/ui/button/action");
const clipboard = require("sdk/clipboard");
const tabs = require('sdk/tabs');
let button = ActionButton({
id: "my-button-id",
label: "Button Label",
icon: {
"32": "chrome://mozapps/skin/extensions/extensionGeneric.png"
},
onClick: function(state) {
let url = tabs.activeTab.url;
console.log("active tab url:", url);
require("sdk/notifications").notify({
title: "Active Tab's Url is "+url,
text: "Click to copy.",
onClick: function() {
clipboard.set(url);
}
});
}
});
You should check out the documentation on the tabs module.
Note: I've updated this code example to use the new ui modules available since Firefox 29 - the 'widget' module used in the original question was valid at the time but has since been deprecated and then removed.

Resources