Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add feature to insert emoji into pages directly #10

Merged
merged 9 commits into from
Apr 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions assets/texts/de/privacy.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
Dieses Add-on sendet keine Informationen zum Add-on-Autor oder einer Drittpartei.

Eine Erklärung aller Berechtigungen, die dieses Add-on erfragt kann auf https://github.com/rugk/awesome-emoji-picker/blob/master/assets/texts/de/permissions.md gefunden werden.
Eine Erklärung aller Berechtigungen, die dieses Add-on erfragt, kann auf https://github.com/rugk/awesome-emoji-picker/blob/master/assets/texts/de/permissions.md gefunden werden.

== DIENSTE VON DRITTEN ==

Dieses ADD-ON nutzt den „Sync storage” des Browser's um die Einstellungen zu speicheren. Wenn der NUTZER Sync” im Browser aktiviert, werden die Einstellungen des Add-ons hoch geladen und zwischen den Geräten, die mit dem (Mozilla) Account des Browsers verbunden sind, synchronisiert. Wenn dies nicht gemacht wird, werden die Daten lokal auf dem Gerät gespeichert.
Dieses ADD-ON nutzt den „Sync storage” des Browser's um die Einstellungen zu speicheren. Wenn der NUTZER Sync” im Browser aktiviert, werden die Einstellungen des Add-ons hoch geladen und zwischen den Geräten, die mit dem (Mozilla) Account des Browsers verbunden sind, synchronisiert. Wenn dies nicht gemacht wird, werden die Daten lokal auf dem Gerät gespeichert.
In Mozilla Firefox werden die Daten Ende-zu-Ende-verschlüsselt bevor sie hoch geladen und auf den Servern von Mozilla gespeichert werden.
Siehe https://accounts.firefox.com/legal/privacy und https://www.mozilla.org/privacy/firefox/#c-privacy-topic-8 für Mozilla's Datenschutzerklärung über dieses Thema.
9 changes: 7 additions & 2 deletions scripts/manifests/dev.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
},

// testing version allows loading unit test libraries from CDNs
"content_security_policy": "default-src 'self'; img-src data: https://unpkg.com",
"content_security_policy": "default-src 'self'; img-src data:; style-src 'self' https://unpkg.com; script-src 'self' https://unpkg.com",
"icons": {
"32": "icons/icon_32.png",
"64": "icons/icon_64.png",
Expand All @@ -41,7 +41,12 @@
"default_locale": "en",

"permissions": [
"storage"
"storage",
"activeTab"
],

"optional_permissions": [
"clipboardWrite"
],

"applications": {
Expand Down
7 changes: 6 additions & 1 deletion scripts/manifests/firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@
"default_locale": "en",

"permissions": [
"storage"
"storage",
"activeTab"
],

"optional_permissions": [
"clipboardWrite"
],

"applications": {
Expand Down
35 changes: 32 additions & 3 deletions src/common/modules/data/DefaultSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@
* @module data/DefaultSettings
*/

export const DEFAULT_SETTINGS = Object.freeze({
/**
* An object of all default settings.
*
* @private
* @const
* @type {Object}
*/
const defaultSettings = {
popupIconColored: true,
emojiPicker: {
set: "native",
Expand All @@ -13,6 +20,28 @@ export const DEFAULT_SETTINGS = Object.freeze({
emojiTooltip: false,
emojiSize: 24
},
copyEmoji: "native",
pickerResult: {
automaticInsert: true,
emojiCopy: true,
// emojiCopyOnlyFallback MUST NOT be true, as optional clipboardWrite
// permission is required for this
// (As it leads to an error, that may happen in reality with sync, however,
// it is anyway, handled in the options, but not really nice to see it
// directly after installing the add-on)
emojiCopyOnlyFallback: false,
resultType: "native",
},
emojiMart: {}
});
};

// freeze the inner objects, this is strongly recommend
Object.values(defaultSettings).map(Object.freeze);

/**
* Export the default settings to be used.
*
* @public
* @const
* @type {Object}
*/
export const DEFAULT_SETTINGS = Object.freeze(defaultSettings);
28 changes: 28 additions & 0 deletions src/content_scripts/insertIntoPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use strict";

/**
* Return the username, you want to follow.
*
* @function
* @param {string} newText
* @returns {void}
*/
function insertIntoPage(newText) { // eslint-disable-line no-unused-vars
const elFocused = document.activeElement;

// does not work in Firefox currently for text fields, only for context editable
// see https://bugzilla.mozilla.org/show_bug.cgi?id=1220696
if (document.execCommand("insertText", false, newText)) {
return elFocused.value;
}

const start = elFocused.selectionStart;
const end = elFocused.selectionEnd;

if (start !== undefined && end !== undefined) {
elFocused.setRangeText(newText, start, end, "end");
return elFocused.value;
}

throw new Error("nothing selected");
}
9 changes: 7 additions & 2 deletions src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
},

// testing version allows loading unit test libraries from CDNs
"content_security_policy": "default-src 'self'; img-src data: https://unpkg.com",
"content_security_policy": "default-src 'self'; img-src data:; style-src 'self' https://unpkg.com; script-src 'self' https://unpkg.com",
"icons": {
"32": "icons/icon_32.png",
"64": "icons/icon_64.png",
Expand All @@ -41,7 +41,12 @@
"default_locale": "en",

"permissions": [
"storage"
"storage",
"activeTab"
],

"optional_permissions": [
"clipboardWrite"
],

"applications": {
Expand Down
Empty file removed src/options/modules/.gitkeep
Empty file.
137 changes: 108 additions & 29 deletions src/options/modules/CustomOptionTriggers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@
*/

import * as AutomaticSettings from "/common/modules/AutomaticSettings/AutomaticSettings.js";
import * as CommonMessages from "/common/modules/MessageHandler/CommonMessages.js";
import * as CustomMessages from "/common/modules/MessageHandler/CustomMessages.js";

// used to apply options
import * as IconHandler from "/common/modules/IconHandler.js";

const CLIPBOARD_WRITE_PERMISSION = {
permissions: ["clipboardWrite"]
};
const MESSAGE_EMOJI_COPY_PERMISSION = "emojiCopyOnlyFallbackPermissionInfo";

let addonHasClipboardWritePermission = false;
let clipboardWriteRequestMessageIsShown = false;

/**
* Adjust UI if QR code size option is changed.
*
Expand Down Expand Up @@ -43,6 +53,85 @@ function saveEmojiSet(param) {
return AutomaticSettings.Trigger.overrideContinue(param.optionValue);
}

/**
* Requests the permission for pickerResult settings.
*
* @private
* @param {Object} optionValue
* @param {string} [option]
* @param {Object} [event]
* @returns {Promise}
*/
function applyPickerResultPermissions(optionValue, option, event) {
let retPromise;
const isUserInteractionHandler = event.type === "input" || event.type === "click" || event.type === "change";

if (optionValue.emojiCopyOnlyFallback && // if we require a permission
!addonHasClipboardWritePermission // and not already granted
) {
// no action button by default
let actionButton = {};
// if we cannot actually request the permission, let's show a useful
// message, at least
if (!isUserInteractionHandler) {
clipboardWriteRequestMessageIsShown = true;

actionButton = {
text: "Grant permission",
action: (param) => {
return applyPickerResultPermissions(optionValue, option, param.event);
}
};
}

CustomMessages.showMessage(MESSAGE_EMOJI_COPY_PERMISSION,
"We need the permission to copy data into the clipboard for this feature.",
false,
actionButton);

// if we were called from an input handler, we can request the permission
// otherwise, we return now
if (!isUserInteractionHandler) {
return Promise.resolve();
}

retPromise = browser.permissions.request(CLIPBOARD_WRITE_PERMISSION).catch((error) => {
console.error(error);
// convert error to negative return value
return null;
}).then((permissionSuccessful) => {
switch (permissionSuccessful) {
case true:
// permission has been granted
addonHasClipboardWritePermission = true;
return;
case null:
CommonMessages.showError("Requesting clipboard permission failed.", true);
break;
case false:
// CommonMessages.showError("This feature cannot be used without the clipboard permission.", true);
break;
default:
console.error("Unknown value for permissionSuccessful:", permissionSuccessful);
}

optionValue.emojiCopyOnlyFallback = false;
document.getElementById("emojiCopyOnlyFallback").checked = false;

throw new Error("permission request error");
}).finally(() => {
CustomMessages.hideMessage(MESSAGE_EMOJI_COPY_PERMISSION, {animate: true});
});
} else if (clipboardWriteRequestMessageIsShown) {
CustomMessages.hideMessage(MESSAGE_EMOJI_COPY_PERMISSION, {animate: true});
// only needs to be reset here, as it is only about the message with an
// action button
clipboardWriteRequestMessageIsShown = false;
}

return retPromise;
}

/**
* Adjusts the emoji size setting for saving.
*
Expand All @@ -62,7 +151,7 @@ function adjustEmojiSize(param) {
}

/**
* Adjusts the copyEmojiColons setting for saving.
* Adjusts the pickerResult->resultType setting for saving.
*
* @private
* @param {Object} param
Expand All @@ -76,7 +165,7 @@ function adjustEmojiSize(param) {
* always contain a value here.
* @returns {Promise}
*/
function prepareEmojiCopyOptionForInput(param) {
function preparePickerResultTypeOptionForInput(param) {
switch (param.optionValue) {
case "colons":
param.optionValue = true;
Expand All @@ -92,7 +181,7 @@ function prepareEmojiCopyOptionForInput(param) {
}

/**
* Adjusts the copyEmojiColons setting for saving.
* Adjusts the pickerResult->resultType setting for saving.
*
* @private
* @param {Object} param
Expand All @@ -102,11 +191,11 @@ function prepareEmojiCopyOptionForInput(param) {
* previously run safe triggers
* @returns {Promise}
*/
function adjustEmojiCopyOption(param) {
if (param.optionValue) {
param.optionValue = "colons";
function adjustPickerResultTypeOption(param) {
if (param.optionValue.resultType) {
param.optionValue.resultType = "colons";
} else {
param.optionValue = "native";
param.optionValue.resultType = "native";
}

return AutomaticSettings.Trigger.overrideContinue(param.optionValue);
Expand Down Expand Up @@ -201,26 +290,6 @@ function updateEmojiPerLineMaxViaEmojiSize(optionValue, option, event) {
console.log("Caluclated a maximum number of emojis per line of", newMaxValue,
"for emojis of size", `${emojiSizeValue}px,`, "resulting in an estimated with of", `${estimatedWidth}px.`);

// switch (emojiSizeValue) {
// case 16:
// newMaxValue = 50; // theoretically ~800/16=50
// break;
// case 24:
// newMaxValue = 20; // theoretically ~800/24=33
// break;
// case 32:
// newMaxValue = 20; // theoretically ~800/32=25
// break;
// case 40:
// newMaxValue = 20; // theoretically ~800/40=20
// break;
// case 48:
// newMaxValue = 12; // theoretically ~800/48=16
// break;
// default:
// throw new TypeError(`Emoji size value ${emojiSizeValue} is unsupported.`);
// }

// apply new max value
const oldEmojisPerLineValue = elEmojisPerLine.value;
elEmojisPerLine.max = newMaxValue;
Expand Down Expand Up @@ -249,18 +318,28 @@ function updateEmojiPerLineMaxViaEmojiSize(optionValue, option, event) {
* @returns {void}
*/
export function registerTrigger() {
// query permission values, so they can be accessed syncronously
browser.permissions.contains(CLIPBOARD_WRITE_PERMISSION).then((hasPermission) => {
addonHasClipboardWritePermission = hasPermission;
});

// override load/safe behaviour for custom fields
AutomaticSettings.Trigger.addCustomSaveOverride("emojiPicker", saveEmojiSet);
AutomaticSettings.Trigger.addCustomSaveOverride("emojiPicker", adjustEmojiSize);
AutomaticSettings.Trigger.addCustomLoadOverride("copyEmoji", prepareEmojiCopyOptionForInput);
AutomaticSettings.Trigger.addCustomSaveOverride("copyEmoji", adjustEmojiCopyOption);

AutomaticSettings.Trigger.addCustomLoadOverride("resultType", preparePickerResultTypeOptionForInput);
AutomaticSettings.Trigger.addCustomSaveOverride("pickerResult", adjustPickerResultTypeOption);
// loading does not need to be overwritten, as we are fine with an extra string saved

// update slider status
AutomaticSettings.Trigger.registerSave("pickerResult", applyPickerResultPermissions);
AutomaticSettings.Trigger.registerSave("popupIconColored", applyPopupIconColor);
AutomaticSettings.Trigger.registerSave("emojiPicker", updatePerLineStatus);
AutomaticSettings.Trigger.registerSave("emojiPicker", updateEmojiPerLineMaxViaEmojiSize);

// handle loading of options correctly
AutomaticSettings.Trigger.registerAfterLoad(AutomaticSettings.Trigger.RUN_ALL_SAVE_TRIGGER);

// register custom messages
CustomMessages.registerMessageType(MESSAGE_EMOJI_COPY_PERMISSION, document.getElementById("emojiCopyOnlyFallbackPermissionInfo"));
}
12 changes: 10 additions & 2 deletions src/options/options.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ ul {
margin: 0px;
padding: 0px;
}
/* still show padding if ul is used for indentation */
ul ul {
padding-left: 40px;
}
li {
list-style-type: none;
margin-top: 10px;
Expand Down Expand Up @@ -67,8 +71,8 @@ input[type=radio] ~ .helper-text {
margin-left: 28px;
}

/* when a link is used in a helper text, add margin */
.helper-text > a {
/* when a "Learn more" link is used in a helper text, add margin */
.learn-more {
margin-left: 4px;
overflow-wrap: none;
}
Expand All @@ -79,3 +83,7 @@ input[type=radio] ~ .helper-text {
border-radius: 2px; /* looks better on GNOME, at least */
box-shadow: 0 0 0 2px var(--red-60-light-shadow);
}

.message-inside-options {
margin-top: 10px;
}
Loading