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

[Discussion] Having this repo (and others) as a single extension? #14

Closed
WorldLanguages opened this issue Jul 14, 2020 · 73 comments
Closed

Comments

@WorldLanguages
Copy link

Finding userscripts and userstyles for Scratch is very hard because of the sharing policy in place. Don't you think there should be an extension similar to 2014's Mega Scratch Userscript? A single extension that lets you toggle different Scratch related extensions (like Griffpatch's developer tools and message manager), userscripts and userstyles (like the ones on this repo).

This is just in my head now, but I don't think it would be super complex to make it easy to scale this extension. What I have in mind is creating a new extension called "Scratch Addons" (or similar) that is basically a userscript manager, but just for Scratch, and only allows you to use the built-in addons approved by us, living inside a folder inside the extension's source code (they couldn't auto update because of Chrome's policy on remote code execution). These addons can run background scripts and userscripts as if they were extensions. Every addon has a pseudo-manifest where it tells the main extension what content scripts (extension's equivalents of userscripts) run for each URL pattern, if it wants to run in the extension's background page, if it has a popup, and maybe even declare permissions (for example, 2 addons might want to use the extension's number badge, so the user will have to choose a single one). Maybe this manifest could declare what user settings these addons have available.
Having said this, I think you notice creating an "addon" and a userscript wouldn't be very different. A userscript could be easily converted into an addon, and an extension with a little more work too. A userstyle is also not as easy (like the one in this repo) but I don't see why the stylus syntax couldn't be converted into CSS, and the moz-document media queries into JavaScript if statements.

What do you think? This is a centralized approach, but because of the policy I think it's a good option. It's a fun project (because of this many addons in an extension architecture) and it would be way easier for new userscripts, userstyles or extensions made by Scratchers to be available immediately to existing extension users.

@WorldLanguages
Copy link
Author

You are free to comment about the extension itself (feedback very welcome, or tell me if you're interested on working on it!) but the main point I want to make here is: how do you convert an existing userstyle or extension into an addon? Manually? It would work because of the small scale, but it would be hard to easily push updates to the userstyle and to the addon at once. It would probably mean manually replicating every change in the user.css file here in the addon, manually.

@Explosion-Scratch
Copy link

@World_Lanuages Wow! That sounds great! There's one for dark mode, this one, and a few others. I can link them…

@WorldLanguages
Copy link
Author

@Explosion-Scratch Sure please collect all the userscripts you can find. Sadly I don't use many so I don't really know about more than a few of them. Don't send them here tho, since this is a little offtopic. Let's see what @mxmou has to say about this idea.

@Explosion-Scratch
Copy link

@World_Languages I made a (unshared) project with several in it.

@Explosion-Scratch
Copy link

Here are some people who make/have made userscripts:
_nix/towerofnix
Maximouse/mxmou
griffpatch/griffpatch
Boomer001/BoomerScratch
apple502j/apple502j
MegaApuTurkUltra/MegaApuTurkUltra
nanalan/unknown

Scratch usernames are first, then github ones.

@Explosion-Scratch
Copy link

nanalan's github username is "nanaian". And there's also these
Sheep_Maker/Sheep_Tester
Nickynouse/unknown

@mxmou mxmou added the needs discussion I'm not yet completely sure about this label Jul 14, 2020
@WorldLanguages
Copy link
Author

@mxmou You can close this issue since it's not directly related to the userstyle. I didn't find a better way to contact you so I made an issue. For obvious reasons, we can't talk about extensions on Scratch

@mxmou
Copy link
Owner

mxmou commented Jul 14, 2020

@mxmou You can close this issue since it's not directly related to the userstyle. I didn't find a better way to contact you so I made an issue. For obvious reasons, we can't talk about extensions on Scratch

I think it's related enough to this repo so I'm going to keep it open for now. I'll explain my opinion later (tomorrow?).

@Explosion-Scratch
Copy link

I'm sure some of the scratchers I mentioned above would be intrested in contributing to this dicussion, should I nofity them?

@WorldLanguages
Copy link
Author

@Explosion-Scratch I already have ways to contact them for most of them. I think we should wait until we have something that works. After that, anyone can contribute and extend existing addons, or create their own.
Thinking a bit more about it, addons might not be as easy to create as I thought. Many ideas (for example, message count in the editor) would depend of another addon, like Scratch Notifier or Griffpatch's messaging ports. Maybe the extension should have a single main addon that frequently checks messages that only works when needed (if none of addons requiring message counts are enabled, or only the messages in editor is enabled, but the user is not editing)

@Explosion-Scratch
Copy link

@World_Languages Okay, that's fine! :) About the second part of your posts, since the userstyles work fine on their own it would be easy to turn them on and off from one place. The complicated part is the messaging part.

@WorldLanguages
Copy link
Author

WorldLanguages commented Jul 14, 2020

I think the best option is to have builtin methods that both background scripts and content scripts can use. For example, getMessageCount(). If the second request to the message count comes less than a few seconds after the first one, instead of requesting the message count again to Scratch, it could reuse the previous value.

builtin methods that both background scripts and content scripts can use

This will be a nice challenge, because it will involve passing data from background pages to addon content scripts. Each addon content script (and background script) is supposed to be isolated with each other to avoid stuff like variable collisions.

@WorldLanguages
Copy link
Author

WorldLanguages commented Jul 14, 2020

Maybe to have userstyles like these one work cleanly, the extension could provide an API for background addon scripts to register a userstyle, by providing the path to the CSS file and the Scratch URL pattern accordingly. This sounds better than doing lots of if statements inside an addon content scripts. (Note: then for this to be ported into an addon, every moz-document media property should be split up into its own CSS file, which doesn't sound very hard to automate tbh, but we could still do it manually. At least we're not mixing JS and CSS with this approach.)

This would mean that addons can have background scripts, content scripts (used for userscripts) or both.
Both of these could have almost identical APIs to get general data about the state of Scratch (is the user authenticated, whats their username, their ID, their message count, events on login/out, etc.), access the settings the user configured the addon with (and listen to settings change events), register userstyles (only background pages), and possibly if both exist, they could talk to each other (but not interfere with other addons that do the same, even if they send the same exact message).
When using window.fetch to make a request to Scratch, it should send cookies and every necessary authentication tokens without the addon author worrying about them.
There should also be a priority system in case we want to always load an addon content script or userstyle before another, so it doesn't break anything. We can do that since we would also maintain the addon library.
Enhancements to the Scratch editor might use some clever tricks to access the Scratch VM's or editor's state, so unless we don't provide an API, we might have trouble having 2 addons working with the Scratch editor, or we might have to merge them.

@mxmou
Copy link
Owner

mxmou commented Jul 15, 2020

I really like this idea.

About converting userscripts and userstyles to addons, I would try to automate it as much as possible. A userscript would just become a single content script, and the conversion seems to be quite straightforward (some parts still need to be changed manually), so only userstyles might be a problem. Some like this one (not really a great example because it isn't Scratch-related but I don't use many userstyles) are just a few lines of plain CSS, but mine is written in Stylus, uses @-moz-document, variables (which can be changed by the user), conditionals and so on which are impossible in CSS, and I don't really want to generate JavaScript for that. One option would be to generate CSS from Stylus code at run time.

Thinking a bit more about it, addons might not be as easy to create as I thought. Many ideas (for example, message count in the editor) would depend of another addon, like Scratch Notifier or Griffpatch's messaging ports. Maybe the extension should have a single main addon that frequently checks messages that only works when needed (if none of addons requiring message counts are enabled, or only the messages in editor is enabled, but the user is not editing)

Using built-in methods for most of the Scratch API (or, alternatively, a single method for accessing the API) would be useful. I don't think having addons which depend on other addons is a good idea.

Enhancements to the Scratch editor might use some clever tricks to access the Scratch VM's or editor's state, so unless we don't provide an API, we might have trouble having 2 addons working with the Scratch editor, or we might have to merge them.

Having an API for that is probably the best idea.

I am interested in helping with this, although I believe you know more about browser extensions than me.

@WorldLanguages
Copy link
Author

WorldLanguages commented Jul 15, 2020

@mxmou Thanks for sharing your thoughts!

I don't think having addons which depend on other addons is a good idea.

Agreed, after we notice 2 addons would duplicate each other's work, we should implement APIs so both can "collaborate". For example, showing message count in the editor in a "project enhancements" addon should use the message count already obtained a few seconds before by the new message notifier. This means the addon API might not ever be finished! As new ideas appear, we might notice something is about to get duplicated.

I am interested in helping with this, although I believe you know more about browser extensions than me.

I see, but after I have a prototype with basic APIs working hopefully you'll understand how it works!

About the userstyle itself:

One option would be to generate CSS from Stylus code at run time.

Eh, that sounds weird... If we already have the code to convert Stylus to CSS, why not run it ourselves? Remember userstyles can't autoupdate (nothing in the addon library can) so we'd have to update the Stylus code in the extension itself anyway.

Also, about this userstyle using variables, I'm not sure how that could be handled. Different css files depending on whether an addon setting is enabled? Pseudocode for the background script for this userstyle as an addon:

addon.userstyles.register({
   styles: "main.css", // Relative to the addon's root folder
   urls: ["https://scratch.mit.edu/*"]
});
addon.userstyles.register({
   styles: "dark.css",
   urls: ["https://scratch.mit.edu/*"],
   if_setting_enabled: "dark_mode" // Making the extension handle this allows already opened tabs to update the userstyles without the addon caring about it (and no refresh needed!)
});

Note: this is regards boolean variables in userstyles (like light or dark mode). If we want to let users choose, for example, a color, that should probably be handled with a CSS variable and we should provide mechanisms for these to be accessed by the userstyles with syntax like var(--addon-settingname).

@Explosion-Scratch
Copy link

@World_Languages, sounds good.

@BoomerScratch
Copy link
Contributor

@Explosion-Scratch Nickynouse's GitHub is Airhogs777, but he left GitHub. He made this userscript. (No longer available)

@WorldLanguages
Copy link
Author

@BoomerScratch Thanks! Please try to get as many userscripts as possible and list them somewhere.

@mxmou I'm working on background scripts and content scripts first, so I won't think a lot about the userstyles API for now, but have any ideas or suggestions? Specially how to handle user choices (like dark mode or not). Split different option choices between different CSS files?

@Explosion-Scratch
Copy link

Let's see we should do these steps to archive/collect userscripts and userstyles:
1: Find the link, e.g. github link to repository or scratch discuss link.
2: Archive that link and the actual code through archive.org
3: Save link and other info as follows:
- Link
- Raw code
- Publish date (if possible)
- Creator
- Description
- Link to scratch forums topic or github for the code.
- Raw code itself.
- We should also frequently archive this issue where we post this information.

@WorldLanguages
Copy link
Author

WorldLanguages commented Jul 19, 2020

Thanks so much for helping out @Explosion-Scratch

In the meanwhile I'm playing with implementing the addon.* APIs. Here's a simplified version of Scratch Notifier running as a background addon script on my machine!!

let msgCount = null;
let mostRecentMsgIds = [];
const emojis = {
    "addcomment": "💬",
    "forumpost": "📚",
    "loveproject": "❤️",
    "favoriteproject": "⭐",
    "followuser": "👤",
    "curatorinvite": "✉️",
    "remixproject": "🔄"
};

checkCount();
setInterval(checkCount, 6000);

async function checkCount() {
    const newCount = await addon.account.getMsgCount();
    console.log(newCount);
    if(msgCount !== newCount) {
        const oldMsgCount = msgCount;
        msgCount = newCount;
        //addon.badge.setText(msgCount);
        if(msgCount !== oldMsgCount) checkMessages();
    }
}

function getMostRecentIds(messagesObj) {
    const arr = [];
    for(const message of messagesObj) {
        arr.push(message.id);
        // We only need a non-comment as a reference, since comments
        // are the only types of messages that could dissapear.
        if(message.type !== "addcomment") break;
    }
    return arr;
}

function newMessage(message) {
    addon.notifications.create("test", {
        type: "basic",
        title: "New message!",
        iconUrl: "/images/icon.png",
        message: message,
        buttons: [{
          title: "Open messages page"
        }, {
          title: "Mark all as read"
        }],
        requireInteraction: true
      });
}

function markAsRead() {
    addon.fetch("https://scratch.mit.edu/site-api/messages/messages-clear/", {method: "POST"});
    //addon.badge.setText("");
}

async function checkMessages() {
    const res = await addon.fetch(`https://api.scratch.mit.edu/users/${addon.auth.username}/messages?limit=40&offset=0`);
    const messages = await res.json();
    if(mostRecentMsgIds.length === 0) mostRecentMsgIds = getMostRecentIds(messages);
    else if(messages[0].id !== mostRecentMsgIds[0]) {
        for(const message of messages) {
            if(mostRecentMsgIds.includes(message.id)) break;
            // We found a new message! No need to notify, we continue...
            let messageType = message.type;
            if(message.type === "addcomment") {
                messageType += "/";
                if(message.comment_type === 0) {
                    // Project comment
                    const replyFor = message.commentee_username;
                    if(replyFor === null) messageType += "ownProjectNewComment";
                    else if(replyFor === addon.auth.username) messageType += "projectReplyToSelf";
                    else messageType += "ownProjectReplyToOther";
                } else if(message.comment_type === 1) {
                    const profile = message.comment_obj_title;
                    const replyFor = message.commentee_username;
                    if(profile === addon.auth.username) {
                        if(replyFor === null) messageType += "ownProfileNewComment";
                        else if(replyFor === addon.auth.username) messageType += "ownProfileReplyToSelf";
                        else messageType += "ownProfileReplyToOther";
                    } else {
                        messageType += "otherProfileReplyToSelf";
                    }
                } else if(message.comment_type === 2) messageType = "studio";
            }
            newMessage(messageType);
            const emoji = emojis[message.type] || "";
        }
        mostRecentMsgIds = getMostRecentIds(messages);
    }
}

image
image
(You're seeing the console logs for newCount)
image
(Every addon has its own "VM" inside Chrome devtools where you can debug them!)

@Explosion-Scratch
Copy link

Also there is the issue of where to store this info, here are a few options:

  • In this issue
    • Pros:
      • All in one place and easy to locate
    • Cons:
      • Conversation shuld be burried by userscript/userstyle entries.
      • Public so we could get our scratch accounts banned if we aren't carefull.
  • Email:
    • Pros
      • Private, we won't get banned.
      • Easy to keep track of, we can also use google docs.
      • Everyone has the email so there is less chance of work being lost.
    • Cons:
      • Everyone has to share each other's (sometimes personal) email adresses, which could lead to security issues or something.
      • Not everyone could see it, meaning less scratchers will stumble across this and want to help.
  • Google docs:
    • I have literally no idea how to use it, tell me if you guys thin it's a good idea.

@Explosion-Scratch
Copy link

@World_Languages That looks AMAZING!! Thanks :) Also I'm going to notify the otjer scratchers I mentioned with the "@person" thing.

@WorldLanguages
Copy link
Author

Lol you always get my username wrong here. GitHub usernames don't support underscores.

@WorldLanguages
Copy link
Author

I'd say you collect userscripts privately for now, we can see how to merge the lists in the future.

@Explosion-Scratch
Copy link

@griffpatch @apple502j @MegaApuTurkUltra @nanaian @towerofnix
Hi there! A few scratchers are working on a userscript/userstyle manager much like one for scratch 2.0 called MegaScratchUsercript. It aims to collect, archive, and share

@WorldLanguages
Copy link
Author

WorldLanguages commented Jul 19, 2020

Ohh that's what you meant by mentioning them lool. I would not disturb them yet but you already did lol so ¯\(ツ)

@Explosion-Scratch
Copy link

(Dang, I hit comment on accdent, continued here)

[…] userscripts and userstyles that many scratchers have worked on for 3.0. Eventually this will become a browser extension meant to improve and customize scratch!

@Explosion-Scratch
Copy link

@WorldLanguages (<-- fixed!) Umm, I guess we can still collect them privately, oh well… XD

@Explosion-Scratch
Copy link

Also could we consider fitting griffpatch's Scratch Developer Tools extension into here, it adds a lot of functionality tok the scratch editor such as searching blocks, copy and pasting them, confirmation before sharing, deleting orphan blocks and a lot more.

@tb148
Copy link
Contributor

tb148 commented Jul 22, 2020

@mxmou, also about the organization thing. How do I become a "member"? ($3.99 a month for a limited time! <-- jk)

  1. Someone who is an owner invites you, and you receive an email.
  2. Accept the invitation in the email and you will become one!

@Explosion-Scratch
Copy link

@tb148 Okay! Thanks :)

@mxmou
Copy link
Owner

mxmou commented Jul 22, 2020

@maximouse I mean, DatOneLefty was IP banned from the API because of Forums.scratchstats.com and World_Languages projects are all NFE'd. Griffpatch's project advertising the Scratch Dev Tools was taken down and I don't know if he was banned for a perios of time or not, but…

(Mentioning maximouse will notify a completely different user, don't forget my GitHub username is mxmou)
DatOneLefty was banned because he made a bot which was accessing the Scratch website, and - well, we aren't going to make Scratch projects advertising this thing so we don't have to worry about them getting taken down.

@Explosion-Scratch
Copy link

@mxmou I guess this is okay then.

@WorldLanguages
Copy link
Author

Yeah I own @ScratchAddons.
Lol this "userscript list" is making me go nuts, @Explosion-Scratch. Just keep them somewhere, privately if you want. Whenever the addon loader code is ready, you simply send a pull request for each one.
I won't post any code until the loader barely works, since I'm doing design decisions "on the go" so starting to write addons now is pointless (I'm writing one to test everything works, tho). Update on progress btw:

Stuff that works already on my machine:
In a nutshell, background scripts (I haven't implemented content scripts, userstyles nor popups yet). There's code that goes into the addon folder and runs every addon background script it sees in each manifest.
Implemented APIs are:
addon.self: allows addons to know information about themselves (id, path)
addon.auth: gives access to auth information (is the user logged in, what's their username, their account ID, their auth token, etc...). You can also register events on it since it inherits EventTarget, so you can do stuff like this (which comes really handy on my Scratch Notifier addon)
image
addon.account: for now, the only available property is a getMsgCount function that returns a promise. More stuff TBD.
addon.fetch: exactly like window.fetch but takes care of auth headers, very handy for writing addons without caring about whether a specific request will require CSRF headers, X-Token headers, Referer header, etc.
addon.browserTabs and addon.browserWindows: give access to addon background scripts to the chrome.tabs and chrome.windows APIs respectively, allowing Scratch Notifier to open new tabs in the browser window, for example. These APIs are also promisified (chrome.* APIs use callbacks) so it's easier to use them.
addon.notifications: requires a "notifications" permission in the manifest, and allows extensions to use the chrome.notifications API. The API is not identical tho. Events are implemented using EventTarget instead of Chrome's implementation to provide a layer of abstraction that will be able to unregister events when the background script neeeds to be killed (more info below). To avoid notification IDs from different addons colliding, addons are not allowed to specify notification IDs. addon.notifications.getAll() returns only the notifications made by the addon calling the function.
addon.badge: requires a "badge" permission, allows an addon background script to use the extension badge and set its color and text. In case more than one addon wants to use the badge, the user can choose which addon uses it. Addons don't have to care whether their badge is actually displayed or not.
addon._kill(): not actually an API, since addons aren't supposed to call this function, but it allows the addon handler to kill background scripts on demand. Let's say you disable Scratch Notifier in addon settings. You don't want any more notifications of it, right? Well, how do you do that without restarting every addon? The addon loader already used eval to run the background script. addon._kill() allows the addon handler to kill specific addon background scripts by clearing all registered timeouts and intervals (ones made with setTimeout and setInterval), as well as unregistering any event targets. This effectively means that addon background script (or scripts) can't run anymore in any way. Because of that, the browser's garbage collector even removes unused variables from RAM, for example Scratch Notifier's msgCount is immediately trashed when the script is killed. This is good because if the garbage collector actually removes variables used by the addon it means the kill implementation is working since no code can execute anymore. If the user enables Scratch Notifier again in the same browser session, it will be executed again "from scratch". This is good for memory (disabling and enabling addons doesn't make RAM usage increase every time) and also allows users to disable addons without requiring a restart. Note this is only necessary for background scripts, since content scripts die when the tab is closed or there's a navigation (e.g. going to a new page inside the tab). Popup scripts also obviously don't need this, since you can't disable an addon while the popup is visible.
global: also not really an API, but in case an addon script is split into many files, they can share state and methods through this object. This means you can have 2 background scripts that use the same variable names, and they won't collide, but if you want to split your script into many, you may have to add global. in some parts of the code so these 2 scripts can share data.

@Explosion-Scratch
Copy link

@WorldLanages. Why don't we stop with the collecting and organizing userscripts for now and I'll just work on that on my own. You and MaxiMouse can work on the coding for the addon itself, once a working addon is in shape we can start adding userscripts and userstyles to it. I'll close the other issue for collescting them for now, we might want to re-open it later when the userscripts are ready to be put into the addon. Also could you invite a few users to ScratchAddons? Me, @mxmou and ask BoomerScratch and tb148 if they want to join as well

@tb148
Copy link
Contributor

tb148 commented Jul 23, 2020

@Explosion-Scratch I do want to join.

@tb148
Copy link
Contributor

tb148 commented Jul 23, 2020

also, @WorldLanguages, who have you invited yet?

@mxmou
Copy link
Owner

mxmou commented Jul 23, 2020

@WorldLanguages Again, great. And yes, please invite me and @Explosion-Scratch to the organization. When the code becomes public this discussion should be moved there.

@Explosion-Scratch
Copy link

@tb148 Thanks for helping! WorldLanguages has not invited me yet and t my knowledge no-one else.

@BoomerScratch
Copy link
Contributor

@WorldLanguages Injecting the userscripts and userstyles is easy. We can use this to get the URLs of all the tabs and the IDs of the tabs (from a StackOverflow question, which I modified):

tabsInfo = [];
chrome.windows.getAll({populate:true},windows => {
  windows.forEach(window => {
    window.tabs.forEach(tab => {
      tabsInfo.push({"url":tab.url,"id":tab.id});
    });
  });
});
tabsInfo.filter(x=>x.url.startsWith("https://scratch.mit.edu"));

Now, inject a script in the tab.
For a userstyle:

tabsInfo.forEach(e => {
   chrome.tabs.executeScript(e.id,{code:'document.body.appendChild(document.createElement("style")).innerText = "USERSTYLE CODE HERE"'});
});

For a userscript:

tabsInfo.forEach(e => {
   chrome.tabs.executeScript(e.id,{code:`element=document.body.appendChild(document.createElement("script"));
element.innerText = "USERSCRIPT CODE HERE";
setTimeout(()=>element.remove());`});
});

Turning off userstyles is easy, but turning off userscripts requires you to reload the page.

@Explosion-Scratch
Copy link

@BoomerScratch. Okay. Thanks for finding that! A "save" button that reloaded wouldn't be to hard would it? Also would you be intrested in joining this collab long term? (Like for the rest of the project)

@WorldLanguages
Copy link
Author

Thanks for the help @BoomerScratch however don't worry, I haven't coded content scripts yet but I have it all in my head lol. I don't think I should go with that approach because Chrome (and other browsers) "sandbox" extension code if you inject it like that. Most uses for content scripts won't care if they are sanboxed or not, however some ones (like griffpatch's developer tools) only work if they aren't sandboxed, and are ran in the same context as the page. So to simplify it I'll just run all content scripts unsandboxed, which might require a bit more work but makes important addons work.

@WorldLanguages
Copy link
Author

I've been kinda lazy lately these last few days but I promise you'll be able to write your own addons by August. However, implementing more complex addons like griffpatch's developer tools might take some more work because of the event listener traps, but most userscripts will just work.
@Explosion-Scratch I'm sorry that you have nothing to play with yet lol.

@WorldLanguages
Copy link
Author

I'll try to move this to the org tomorrow. I'll invite you all. Will create specific issues for each thing. And I might start working on addon APIs documentation. I'll create a specific issue to think how to implement this userstyle so this can be closed by that point.

@Explosion-Scratch
Copy link

@WorldLanguages Sounds great! I'm not doing that much for this amyways exept finding random stuff and posting it here :P I appreciate your help on this project! The final product will be amazing!

@tb148
Copy link
Contributor

tb148 commented Jul 24, 2020

@WorldLanguages Have anyone been invited yet?

@mxmou
Copy link
Owner

mxmou commented Jul 24, 2020

For a userstyle:

tabsInfo.forEach(e => {
   chrome.tabs.executeScript(e.id,{code:'document.body.appendChild(document.createElement("style")).innerText = "USERSTYLE CODE HERE"'});
});

Not all userstyles are plain CSS, and we should also find a not very ugly/complex way to handle @-moz-document and user-configurable variables.

@mxmou
Copy link
Owner

mxmou commented Jul 24, 2020

Have anyone been invited yet?

@tb148 I wasn't.

@Explosion-Scratch
Copy link

@tb148 I was not invited yet either.

@WorldLanguages
Copy link
Author

Invited!
@Explosion-Scratch Please create new issues and add the "new-addon" label. One per each addon you'd like to see implemented. Include the code (with code formatting) and say who did it so we can credit them :)
@mxmou I moved this userstyle-specific discussion into its own issue.
@BoomerScratch I invited you in case you want to help with issues or when the loader exists, add or modify addons.
You were invited to the org so you can make modifications into the master ("main") branch, but let's please use branches and pull requests instead. If you want to contribute code, modify an addon, add an addon, etc. fork the repo inside your userspace then pull request.

@Explosion-Scratch
Copy link

Did you invite @tb148?

@WorldLanguages
Copy link
Author

Yep

@Explosion-Scratch
Copy link

Heh, where it all began lol

@GrahamSH-LLK
Copy link

Heh, where it all began lol

Yeah! I just saw this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants