Skip to content

Loading…

Portability #360

Merged
merged 46 commits into from

2 participants

@Deathamns

Main goals

  • Encapsulate extension APIs into a common API
  • Support Safari
  • Provide a build script for packaging extension files

Structure

├─ dist/
│  └─ build         # created when running the build script
│     └─ #.#.#.#    # [version number] contains the built files
├─ doc/             # extension documentation
├─ meta/            # configuration and vendor specific files
│  ├─ crx/          # Chromium related files
│  ├─ safariextz/   # Safari related files
│  ├─ xpi/          # Firefox related files
│  └─ config.json   # extension metadata (name, version, author...)
├─ src/             # source code
├─ tmp/             # temp directory, exists when the building is in progress
├─ tools/           # build scripts
└─ other files...   # README, LICENSE...

vendor API (vAPI)

The following files are responsible for the extension API encapsulation.

/src/js/vapi-appifo.js contains some common informations about the extension (like name, version string, homepage). It can be included where it's needed.
The reason for this is that not every browser provides an easy way to access these informations (Chrome does, Safari doesn't, Firefox gives an asynchronous method).
The content of this file is automatically updated when building.

/src/js/vapi-background.js included only in the background process.
It encloses the "privileged" APIs (like net request, tabs), that can run only in the background process.

/src/js/vapi-common.js it can be included in background process and extension pages (e.g., settings or pop-up), and it holds common APIs that could be used in both places (i18n for example).

/src/js/vapi-client.js this also holds common APIs, but it can be included into extension pages and as content-scripts.
Currently it handles messaging, and contains extra code for specific vendors (if needed - see Safari).

Note that this API is not an extensive framework, only implements code that are needed for the extension to work properly.

The files contain all the vendor specific code. Which part will run is determined by simple browser detection, but when building, only the correct code pieces are included into the corresponding extension files.

Basically these are the only js files which are different across browsers (if we don't count the extra files for Firefox (2) and Safari (1)).

Metadata

These informations are used when building.

In order to keep extension data in one place, instead of updating all the vendor specific files (manifest.json, Info.plist...), the /meta/config.json keeps these common informations (such as name, version, author...), also contains vendor specific informations (extension IDs, path to private key which is used when building).

Installing

The source code can be found under the src directory, and since all the manifest files and locales are not cleared when building (intentional), the extension can be installed for all browsers from this directory without building or configuring anything first.

Chromium based browsers

Go to the Extensions page (chrome://extensions), and drag n' drop the src folder onto the browser window.

Safari

First you need to create a developer account and request a certificate from Apple, which you have to install on your machine. More info.

After you have your certificate installed...

Create a link named uBlock.safariextension for the src directory, open the Extension Builder in Safari, click Add Extension, and select the created link.

In Windows a Directory Junction needs to be created:

mklink /H /D /J uBlock.safariextension src

Building (optional)

Dependecy

  • Python3
  • Unix enviroment or cygwin for Windows with the following commands available
    • 7z (Chrome, Firefox)
    • openssl (Chrome)
    • xar (packaging for Safari)

Safari needs a few extra steps first, which are listed here (step 1,2,3).


The building will:

  • update manifest files with the data from /meta/config.json
  • generate and copy necessary files for specific browser (e.g., locales)
  • separate browser specific code from vapi-*.js files
  • create update-files
  • pack the code into installable or publishable extension files

The result files are placed into /dist/build/#.#.#.# (version) folder. If the same folder already exists, first it will be removed with its content.

To build everything, run the following command:

$ python tools/build.py

To refresh only the language and manifest files (note the optional meta argument):

$ python tools/build.py meta
Deathamns added some commits
@Deathamns Deathamns Work on vendor API abstraction, and near complete Safari support 5b79bf3
@Deathamns Deathamns Alphabetical order for keys in Safari's Info.plist 723fc60
@Deathamns Deathamns Minor changes
- Update assets from gorhill/uBlock/master
- Remove whitespace from element-picker.js
- Simplify code in profiler.js (btw, Date is still needed as fallback
  for older browsers)
- Clarification for Safari's storage where the QUOTA_BYTES came from
4278121
@Deathamns Deathamns Add .jshintrc, and use the "use strict" directive
.jshintrc's otion-set is a personal choice, merely a suggestion.
Beside that, it includes some common globals for specific browsers, so
there's no need to set the globals in every .js file.

In order to force strict coding, "use strict" directive was added into
every .js file.
0886f7e
@Deathamns Deathamns Safari shows integers only over the toolbar icon 7af9805
@Deathamns Deathamns Remove storage change-event listener from Safari
Earlier, a technique was used to open the extension's Options page when
the user clicked a checkbox input at Safari's extension settings. The method was removed because:
- the Options page can be opened via the extension's toolbar button (which
  cannot be disabled in Safari, so it will be there all the time);
- involved more clicks than opening from the toolbar button;
- the string beside the checkbox couldn't be localized.
1716195
@Deathamns Deathamns Move vAPI into .jshintrc as a global 1a83d1a
@Deathamns Deathamns Fix "invalid token" exception in Safari
Seems like in older versions the const keyword doesn't play well with the "use strict" directive
775f51a
@Deathamns Deathamns Implement popup autoresizing for Safari
By default, Safari doesn't resize the popup to its content, but it's
possible to set the size pragmatically.
The popup will be resized every time when a change happens in the DOM tree.
f9602fa
@Deathamns Deathamns element-picker fixes, changes
- Include latest changes from gorhill/uBlock/master
- Append the pickerRoot container to document.documentElement instead
  of document.body ("body > div" type CSS selectors are more common, so
  they could overwrite the extension's styling with higher probability)
- Request localized strings from the background script instead of using
  the i18n API in content scripts
- Fuse element-picker.js' message handling into contentscript-end.js', since
  only one messaging channel can live at a time in a content script
88a7910
@Deathamns Deathamns Script injection, element picker, messaging
- Add script injection to vAPI, plus a raw implementation for Safari
  (element-picker.js requires it)
- Tweak element picker to work with Safari
- Revert a change from previous commit: element-picker.js' background
  message handler (since actually it can have its own messaging channel)
- Don't send "undefined" reponses from background to content
d38ca13
@Deathamns Deathamns Use extension API to open links from the popup
Safari doesn't seem to follow links embedded in the popup window (not even
with target="_blank").
7dba1f7
@Deathamns Deathamns Remove unnecessary comments ab12c8d
@Deathamns Deathamns Set default dimensions for Safari's popup 2e787d8
@Deathamns Deathamns Use HTML5 download instead of extension API
Benefits:
- Cross browser solution (however only for relatively new browsers)
- Doesn't need extra permission in Chrome

If the browser doesn't suppor the download attribute, then a new tab will
be opened with the exported data.

Other changes:
- Start the download only if the data is not empty (previously the
  download started anyway)
- Reorder code in vapi-client.js for Safari, so unnecessary code doesn't
  run on extension pages
fbffc5b
@Deathamns Deathamns Use a dedicated file for storing extension info
Chrome has getManifest(), Safari doesn't have anything, Firefox has an
asynchronous API...
So, instead of using extension APIs, store the common informations
(extension name, version, homepage url) in a file (vapi-appinfo.js), which
can be included when it's needed (its data will be available at vAPI.app.____).
The file's content is updated each time the extension is being built, so
it shouldn't be modified manually.
749b6f1
@Deathamns Deathamns Fix download URL for the fallback method 5e99ead
@Deathamns Deathamns Workaround for a messaging bug in Safari 5e587aa
@Deathamns Deathamns Use utf-8 for data: URIs when downloading 86222cb
@Deathamns Deathamns Avoid using Chrome's @@bidi_* type i18n messages
... for the sake of portability.

When including vapi-common.js in an HTML file, then the body element there
will have a "dir" attribute filled with the current locale's direction
(ltr or rtl).

The following languages are considered right-to-left: ar, he, fa, ps, ur.
Everything else is left-to-right.

After the "dir" attribute is set, we can decide in CSS which elements
should have different styling for rtl languages (e.g., body[dir=rtl] #id).
6d49ef0
@Deathamns Deathamns Element picker tweaks
- Indentation whitespace fixes.
- Use built-in getBoundingClientRect() function instead of self-made.
- Use built-in DOM API for manipulating the class attributes instead of
  altering the className property.
- Add pointer-events: none to the svgRoot when using
  document.elementFromPoint(), but if the browser (older Safari for
  example) doesn't take the pointer-events into account, then fall back to
  display: none.
- Initiate every part of the picker at the same time; when the message is
  received from the background. This way the selected element will have
  the red overlay immediately, instead of showing first the black overlay,
  then a few milliseconds later the red.
cc27193
@Deathamns Deathamns "Purge all caches" button seemingly didn't work ac272af
@Deathamns Deathamns Implement pop-up blocking for Safari
It works similarly to the xhr intercepting, except here the window.open
global function is being overridden.
Note that it could only work if the site's Content Security Policy allows
inline scripts, and the script on the webpage doesn't have a copy of the
original window.open function (it can happen only if the page has an
inline script in its head element, where the reference to the original
function can be obtained - likely this cannot be prevented in Safari).
f6f85ec
@Deathamns Deathamns Building Info.plist was missing 54749b3
@Deathamns Deathamns input[type="file"].click() didn't work in Safari
Click couldn't be initiated with JavaScript in Safari if the input was
hidden with display: none. Using visibility: hidden or opacity: 0 solves
the problem.

Alternative solution would be to hide (opacity: 0) the input and slide it
(position: absolute; top: 0; left: 0; width: 100%; height: 100%) over the
button, which would work in all browsers, and wouldn't require JavaScript.
99d8f43
@Deathamns Deathamns Remove unwanted bottom padding from Chrome's popup 56be0b6
@Deathamns Deathamns Badge number sometimes disappeared in Safari 64c37cc
@Deathamns Deathamns Add dummy MutationObserver shim for older browsers bccf3d6
@Deathamns Deathamns document.head isn't always available in Safari 7f57684
@Deathamns Deathamns Fix toolbar icons for Safari e6e3f67
@Deathamns Deathamns Site-patching possibility for Safari
Safari's extension API doesn't provide a way to intercept requests
initiated by plugins, so those cases need special care (or at least the
popular sites).

This commit adds a new JS file (sitepatch-safari.js), which will store the
patches (if it's possible to create one) for specific sites.

As an example, this commit includes a technique for removing in-video ads
from YouTube videos.
d114bf2
@Deathamns Deathamns Use different page navigation detection for Safari
The beforeNavigate event wasn't reliable (sometimes didn't fire, sometimes
fired unnecessary when opening a link with the middle click - which had a
workaround previously, but that's also removed by this commit).

When the event didn't fire, the bindTabToPageStats method didn't run,
and the requests related to the tab weren't blocked.
ba0b11a
@Deathamns Deathamns Drop js-loader, updates from gorhill/uBlock/master d98a816
@Deathamns Deathamns Messaging fixes
Checking the message name (and connectorId) is mandatory for Safari,
because when the background page sends a response back to a document,
then all the frames in its owner tab will receive the exact same
message, which could confuse the script in some cases.
e36c702
@Deathamns Deathamns Preferences button for Safari
Brings back the possibility to click a checkbox which opens the extension
settings from Safari's Preferences/Extensions.
6f2e449
@Deathamns Deathamns Fix messaging for Safari 30ef97a
@Deathamns Deathamns Fix double definition of `length` property in uDom
The `length` property of `DOMList` couldn't be re-defined, because earlier
an Object.defineProperty was used on the object without a setter.
4bf6664
@Deathamns Deathamns Building extension files
Adds possibility to build extension files (Chrome and Safari) from
command line.

To run from the project directory:
python tools/build.py [meta]

If the optional `meta` argument is set, then only the manifest and
language files are uptated.
Without that everything is being built (extension files too) into the
`dist/build/version_number` folder.

For Chrome there will be two files, a crx, and a .zip file which
includes the key.pem private key (so this must not be shared,
it's just a bit help for publishing it to the Chrome Web Store).

Beside the extension files, update-files are generated too (for self
hosting - Safari needs it).
0d9d285
@Deathamns Deathamns Add .gitignore 4c9f2b8
@Deathamns

Sorry for the quality of the description, my English is preventing me to do better.

Deathamns added some commits
@Deathamns Deathamns Remove unnecessary messaging workaround
A better fix was introduced in e36c702 for this issue.

The actual problem was that Safari when sends a message from the
background to content, then it passes to all the frames in the target tab,
but it doesn't make copies, it passes only references to the same object,
so if one frame modifies the message, then other frames would have
received the modified message.
fb0cacb
@Deathamns Deathamns Building missed a file for Safari 41ae0c0
@Deathamns Deathamns Fix wrong fix in 4bf6664 2024ba1
@Deathamns Deathamns Only top window should have type `main_frame` 8edb628
@Deathamns Deathamns Call XHR.open even if the request will be blocked
Without calling it an error may be thrown if other XHR parameters are set.
812da09
@Deathamns Deathamns Respect `defer` attribute when mirroring 36ad23a
@Deathamns Deathamns Move MutationObserver shim
Since it will be used only for older Safari versions, move it to Safari
related code, so it doesn't pollute the content scripts.
8f0b3cf
@gorhill gorhill merged commit 54a91b9 into chrisaljoudi:master
@gorhill gorhill referenced this pull request in gorhill/uMatrix
Closed

make-chromium.sh #38

@gorhill

Ok so finally I'm trying to go through the portability code to regain back the mental picture of the project. I will go through and review carefully all the files.

First thing, one thing I see right away is that I would like that each platform get its custom vapi-*.js files, regardless whether they are very similar or not. Benefit is to eliminate the large if-else code inside it -- something I highly dislike, and also since I can't test on Safari, it is a good thing to restrict changes to one platform, so that I don't have to test other platforms.

My question, where should the platform-specific versions of vapi-*.js be? In ./meta/{vendor}?

There is a Settings.plist in the root folder of the project. Can I removed it, since there is a copy in ./meta/safariextz?

@Deathamns

You could simply just create clones of that file and name them vapi-client-vendor_ext.js.
But, whatever you choose, separating those vapi files can cause a few problems.
Since each of them will have a unique URI (for example meta/vendor_ext/vapi-client.js if they go to meta, or src/js/vapi-client-vendor_ext.js if they stay in src/js), the possibility for installing the extension from the same src folder for different vendors would break, because all the files that reference the vapi files must have their own versions too, which you could achieve by building for a specific vendor (after that the src folder could be installed onto only one browser, until it's not build for another one) or by duplicating those files (so there would be dashboard-crx.html and dashboard-xpi.html files, which would reference the corresponding vapi file).

meta files are copied/updated to the src folder when the build.py is called, and they stay there, so someone can install it immediately from that folder. It just happens that Settings.plist doesn't has variables in it (so it won't differ form the file in meta), but it is the same category as manifest.json or Info.plist.

@gorhill

Ok, I went ahead and saw your answer after I pushed some of the changes.

separating those vapi files can cause a few problems

With uMatrix, I create a paltform-specific folder in dist, and use the result as a release. I would prefer to do this here too. Installing directly from the src folder is not really a big deal, I could/would never guarantee that it would work anyway, as it does happen that I commit changes while in the middle of larger changes. The releases at https://github.com/gorhill/uBlock/releases is where all working releases will go.

I really want to separate completely the code shared by all platforms versus the code specific to a single platform, even if it means there will be some duplication because one platform is somewhat close to another.

Also, I would prefer a zipped release for Chromium-based browser. My understanding is that crx is no longer the preferred way to go, as the extension will be force-removed from Chrome/Windows as per the new Chrome policy which forces extensions to be installed from the store. Manually installing through zip at most results in an annoying warning at start for Chrome/Windows users.

@gorhill

Couple more questions:

What is the reason for having the content of vapi-appinfo.js not inside vapi-common.js?

I see that the port management background page-side now uses closures upon connection. There was care to avoid overhead for connection stuff, in order to perform well for such stress test as the vim-color pages, in which each embedded frame results in a connection to the background page.

I was also using a method to avoid any potential port name collision by having the background page pick the port name, rather than having the client play lottery to pick a port name. I used to use the lottery approach originally, but the thought of some difficult-to-track bug surfacing because of a collision in port name caused me to rewrite to be 100% sure there were no collisions.

Is there a problem in Safari with having the background page rename the port on its side to ensure uniqueness? If there is no problem, then I could put back the code for port naming, and this will then open the door to get rid of the closures when a connection occurs.

@Deathamns

So, basically you don't want to use the build script I made. In that case, you can even remove it, because it's not tied to anything, and use the script you used before.
You can move Info.plist, Settings.plist, js/sitepatch-safari.js and locales.json to meta/safariextz, and manifest.json to meta/crx from the src folder, if you don't want to see platform specific files there.

Just for the record, the meta folder was intended to hold metadata, but now if you put code and filled manifest files there, then maybe it could be renamed to something more related, like vendor or platform.

vapi-appinfo.js not inside vapi-common.js

Because that file is generated (so only that file was touched) and can be included even as a content script. However, if you know that you won't use as a content script, you can move it to vapi-common.js.

closures

I just tried the latest stable and the dev version of the extension with a recent Chromium build on that vim style-preview site, and I didn't notice any difference. Nor in loading the page, nor in memory usage (I got around 34Mb for each version).

ports

Ports are Chrome specific, so basically I tried to recreate a simple sendMessage for Chrome too, but with ports (since you used those, and saw that you mentioned a crbug about a memory leak - however I always used sendMessage, and never experienced problems with it).
Most websites use just a few frames most, so the generating unique ids should be more than enough.

@Deathamns Deathamns deleted the unknown repository branch
@gorhill

I just saw that in vapi-client.js now a single connection is reused for multiple channels -- while before it was one connection per channel. I like this, I like your concept of channels.

So, basically you don't want to use the build script I made

I am not against the idea of build.py, it's just that I have a hard time with the idea of having code for multiple platforms in one single JS file. If they are clearly separated into their own file, this is easier to maintain IMO, as long as we all agree about what goes into vAPI. And this simplifies building as we don't need a parser based on custom markers, and this does simplify my job as maintainer of this project: copying files is easier then writing Python code to parse/extract information. Maybe it will be unavoidable to do so, but surely we don't have to do everything with it.

However, if you know that you won't use as a content script, you can move it to vapi-common.js.

Ok I had in mind vapi-common.js was also for content scripts. I think I understand now: vapi-client.js is for extension pages + content scripts, while vapi-common.js is for background page + extension pages.

Re. overhead: if it can be avoided without overcomplicating, I rather avoid it. sendMessage will create and destroy a port each time a message is send last time I checked (stepping with debugger).

Take Tweetdeck, you will find that uBlock's mutation observer is working hard, causing a lot of back and forth messaging. It makes me feel better to know that whatever overhead could be avoided is actually avoided. Once the code has been written, we can forget about it knowing it can't be pushed further.

It's not because with a quick test we can't notice that there is an overhead, we should not try to avoid it. Just having some ideas of what is going on behind the scene is reason enough for me. Creating two new functions + associated closure for each port connection surely there is a cost, and in this case is avoidable without over-complication of the code.

It's caring about countless if these "unnoticeable" overheads that made this project what it is, I want to stick to this.

@gorhill gorhill added a commit that referenced this pull request
@gorhill gorhill use "platform" as suggested in #360 a430e52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 9, 2014
  1. @Deathamns
  2. @Deathamns
  3. @Deathamns

    Minor changes

    Deathamns committed
    - Update assets from gorhill/uBlock/master
    - Remove whitespace from element-picker.js
    - Simplify code in profiler.js (btw, Date is still needed as fallback
      for older browsers)
    - Clarification for Safari's storage where the QUOTA_BYTES came from
  4. @Deathamns

    Add .jshintrc, and use the "use strict" directive

    Deathamns committed
    .jshintrc's otion-set is a personal choice, merely a suggestion.
    Beside that, it includes some common globals for specific browsers, so
    there's no need to set the globals in every .js file.
    
    In order to force strict coding, "use strict" directive was added into
    every .js file.
  5. @Deathamns
  6. @Deathamns

    Remove storage change-event listener from Safari

    Deathamns committed
    Earlier, a technique was used to open the extension's Options page when
    the user clicked a checkbox input at Safari's extension settings. The method was removed because:
    - the Options page can be opened via the extension's toolbar button (which
      cannot be disabled in Safari, so it will be there all the time);
    - involved more clicks than opening from the toolbar button;
    - the string beside the checkbox couldn't be localized.
  7. @Deathamns
  8. @Deathamns

    Fix "invalid token" exception in Safari

    Deathamns committed
    Seems like in older versions the const keyword doesn't play well with the "use strict" directive
  9. @Deathamns

    Implement popup autoresizing for Safari

    Deathamns committed
    By default, Safari doesn't resize the popup to its content, but it's
    possible to set the size pragmatically.
    The popup will be resized every time when a change happens in the DOM tree.
  10. @Deathamns

    element-picker fixes, changes

    Deathamns committed
    - Include latest changes from gorhill/uBlock/master
    - Append the pickerRoot container to document.documentElement instead
      of document.body ("body > div" type CSS selectors are more common, so
      they could overwrite the extension's styling with higher probability)
    - Request localized strings from the background script instead of using
      the i18n API in content scripts
    - Fuse element-picker.js' message handling into contentscript-end.js', since
      only one messaging channel can live at a time in a content script
  11. @Deathamns

    Script injection, element picker, messaging

    Deathamns committed
    - Add script injection to vAPI, plus a raw implementation for Safari
      (element-picker.js requires it)
    - Tweak element picker to work with Safari
    - Revert a change from previous commit: element-picker.js' background
      message handler (since actually it can have its own messaging channel)
    - Don't send "undefined" reponses from background to content
  12. @Deathamns

    Use extension API to open links from the popup

    Deathamns committed
    Safari doesn't seem to follow links embedded in the popup window (not even
    with target="_blank").
  13. @Deathamns

    Remove unnecessary comments

    Deathamns committed
  14. @Deathamns
  15. @Deathamns

    Use HTML5 download instead of extension API

    Deathamns committed
    Benefits:
    - Cross browser solution (however only for relatively new browsers)
    - Doesn't need extra permission in Chrome
    
    If the browser doesn't suppor the download attribute, then a new tab will
    be opened with the exported data.
    
    Other changes:
    - Start the download only if the data is not empty (previously the
      download started anyway)
    - Reorder code in vapi-client.js for Safari, so unnecessary code doesn't
      run on extension pages
  16. @Deathamns

    Use a dedicated file for storing extension info

    Deathamns committed
    Chrome has getManifest(), Safari doesn't have anything, Firefox has an
    asynchronous API...
    So, instead of using extension APIs, store the common informations
    (extension name, version, homepage url) in a file (vapi-appinfo.js), which
    can be included when it's needed (its data will be available at vAPI.app.____).
    The file's content is updated each time the extension is being built, so
    it shouldn't be modified manually.
  17. @Deathamns
  18. @Deathamns
  19. @Deathamns
  20. @Deathamns

    Avoid using Chrome's @@bidi_* type i18n messages

    Deathamns committed
    ... for the sake of portability.
    
    When including vapi-common.js in an HTML file, then the body element there
    will have a "dir" attribute filled with the current locale's direction
    (ltr or rtl).
    
    The following languages are considered right-to-left: ar, he, fa, ps, ur.
    Everything else is left-to-right.
    
    After the "dir" attribute is set, we can decide in CSS which elements
    should have different styling for rtl languages (e.g., body[dir=rtl] #id).
  21. @Deathamns

    Element picker tweaks

    Deathamns committed
    - Indentation whitespace fixes.
    - Use built-in getBoundingClientRect() function instead of self-made.
    - Use built-in DOM API for manipulating the class attributes instead of
      altering the className property.
    - Add pointer-events: none to the svgRoot when using
      document.elementFromPoint(), but if the browser (older Safari for
      example) doesn't take the pointer-events into account, then fall back to
      display: none.
    - Initiate every part of the picker at the same time; when the message is
      received from the background. This way the selected element will have
      the red overlay immediately, instead of showing first the black overlay,
      then a few milliseconds later the red.
  22. @Deathamns
  23. @Deathamns

    Implement pop-up blocking for Safari

    Deathamns committed
    It works similarly to the xhr intercepting, except here the window.open
    global function is being overridden.
    Note that it could only work if the site's Content Security Policy allows
    inline scripts, and the script on the webpage doesn't have a copy of the
    original window.open function (it can happen only if the page has an
    inline script in its head element, where the reference to the original
    function can be obtained - likely this cannot be prevented in Safari).
  24. @Deathamns
  25. @Deathamns

    input[type="file"].click() didn't work in Safari

    Deathamns committed
    Click couldn't be initiated with JavaScript in Safari if the input was
    hidden with display: none. Using visibility: hidden or opacity: 0 solves
    the problem.
    
    Alternative solution would be to hide (opacity: 0) the input and slide it
    (position: absolute; top: 0; left: 0; width: 100%; height: 100%) over the
    button, which would work in all browsers, and wouldn't require JavaScript.
  26. @Deathamns
  27. @Deathamns
  28. @Deathamns
  29. @Deathamns
  30. @Deathamns

    Fix toolbar icons for Safari

    Deathamns committed
  31. @Deathamns

    Site-patching possibility for Safari

    Deathamns committed
    Safari's extension API doesn't provide a way to intercept requests
    initiated by plugins, so those cases need special care (or at least the
    popular sites).
    
    This commit adds a new JS file (sitepatch-safari.js), which will store the
    patches (if it's possible to create one) for specific sites.
    
    As an example, this commit includes a technique for removing in-video ads
    from YouTube videos.
  32. @Deathamns

    Use different page navigation detection for Safari

    Deathamns committed
    The beforeNavigate event wasn't reliable (sometimes didn't fire, sometimes
    fired unnecessary when opening a link with the middle click - which had a
    workaround previously, but that's also removed by this commit).
    
    When the event didn't fire, the bindTabToPageStats method didn't run,
    and the requests related to the tab weren't blocked.
  33. @Deathamns
  34. @Deathamns

    Messaging fixes

    Deathamns committed
    Checking the message name (and connectorId) is mandatory for Safari,
    because when the background page sends a response back to a document,
    then all the frames in its owner tab will receive the exact same
    message, which could confuse the script in some cases.
  35. @Deathamns

    Preferences button for Safari

    Deathamns committed
    Brings back the possibility to click a checkbox which opens the extension
    settings from Safari's Preferences/Extensions.
  36. @Deathamns

    Fix messaging for Safari

    Deathamns committed
  37. @Deathamns

    Fix double definition of `length` property in uDom

    Deathamns committed
    The `length` property of `DOMList` couldn't be re-defined, because earlier
    an Object.defineProperty was used on the object without a setter.
  38. @Deathamns

    Building extension files

    Deathamns committed
    Adds possibility to build extension files (Chrome and Safari) from
    command line.
    
    To run from the project directory:
    python tools/build.py [meta]
    
    If the optional `meta` argument is set, then only the manifest and
    language files are uptated.
    Without that everything is being built (extension files too) into the
    `dist/build/version_number` folder.
    
    For Chrome there will be two files, a crx, and a .zip file which
    includes the key.pem private key (so this must not be shared,
    it's just a bit help for publishing it to the Chrome Web Store).
    
    Beside the extension files, update-files are generated too (for self
    hosting - Safari needs it).
  39. @Deathamns

    Add .gitignore

    Deathamns committed
Commits on Nov 10, 2014
  1. @Deathamns

    Remove unnecessary messaging workaround

    Deathamns committed
    A better fix was introduced in e36c702 for this issue.
    
    The actual problem was that Safari when sends a message from the
    background to content, then it passes to all the frames in the target tab,
    but it doesn't make copies, it passes only references to the same object,
    so if one frame modifies the message, then other frames would have
    received the modified message.
  2. @Deathamns
  3. @Deathamns

    Fix wrong fix in 4bf6664

    Deathamns committed
Commits on Nov 11, 2014
  1. @Deathamns
  2. @Deathamns

    Call XHR.open even if the request will be blocked

    Deathamns committed
    Without calling it an error may be thrown if other XHR parameters are set.
  3. @Deathamns
Commits on Nov 12, 2014
  1. @Deathamns

    Move MutationObserver shim

    Deathamns committed
    Since it will be used only for older Safari versions, move it to Safari
    related code, so it doesn't pollute the content scripts.
Something went wrong with that request. Please try again.