How extend select2 adaptor with options checking? - jquery-select2

I want to extend select2 default dropdown adapter. Find this - https://bojanv91.github.io/posts/2017/10/extending-select2-with-adapters-and-decorators - and try to write the same. But problem is this example just include AttachBody, AttachContainer adapters without check the options unlike select2 defaults - https://github.com/select2/select2/blob/develop/src/js/select2/defaults.js. I write the same but stuck into options check:
$.fn.select2.amd.define( 'customDropdownAdapter', [
'select2/utils',
'select2/dropdown',
'select2/dropdown/search',
'select2/dropdown/hidePlaceholder',
'select2/dropdown/infiniteScroll',
'select2/dropdown/attachBody',
'select2/dropdown/minimumResultsForSearch',
'select2/dropdown/selectOnClose',
'select2/dropdown/closeOnSelect',
'select2/dropdown/dropdownCss',
'select2/dropdown/tagsSearchHighlight',
// custom extension
'select2/dropdown/newOption',
],
function(
Utils,
Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
DropdownCSS, TagsSearchHighlight,
NewOption,
) {
// *****************************************
// *** THIS IS HOW SELECT2 DEFAULTS WORK ***
// *****************************************
//
// options = $.extend(true, {}, this.defaults, options);
// if (options.dropdownAdapter == null) {
// if (options.multiple) {
// options.dropdownAdapter = Dropdown;
// } else {
// var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
// options.dropdownAdapter = SearchableDropdown;
// }
// if (options.minimumResultsForSearch !== 0) {
// options.dropdownAdapter = Utils.Decorate(
// options.dropdownAdapter,
// MinimumResultsForSearch
// );
// }
// ...
// }
//
// *****************************************
// *****************************************
// *** HOW CAN I GET OPTIONS? ***
// const options = ?
// *****************************************
let dropdownAdapter = Dropdown;
// TO SET SELECT2 ADAPTERS
if ( options.closeOnSelect ) {
dropdownAdapter = Utils.Decorate(
dropdownAdapter,
CloseOnSelect,
);
};
// TO SET MY CUSTOM ADAPTERS
if ( options.newOption ) {
dropdownAdapter = Utils.Decorate(
dropdownAdapter,
NewOption,
);
};
return dropdownAdapter;
} );

Related

Tampermonkey/greasemonkey youtube redirect script from /shorts/* to /watch?v=*

No idea how to code, but the title should explain what I'm after.
If I go to https://www.youtube.com/shorts/zUy4y2CqCV0 I would like to automatically be redirected to the full youtube player version which is https://www.youtube.com/watch?v=zUy4y2CqCV0
Thanks in advance.
This here can do it:
https://greasyfork.org/en/scripts/439993-youtube-shorts-redirect
The content of the script in case the link breaks.
// ==UserScript==
// #name Youtube shorts redirect
// #namespace http://tampermonkey.net/
// #version 0.3
// #description Youtuebe shorts > watch redirect
// #author Fuim
// #match *://*.youtube.com/*
// #icon https://www.google.com/s2/favicons?domain=youtube.com
// #grant none
// #run-at document-start
// #license GNU GPLv2
// ==/UserScript==
var oldHref = document.location.href;
if (window.location.href.indexOf('youtube.com/shorts') > -1) {
window.location.replace(window.location.toString().replace('/shorts/', '/watch?v='));
}
window.onload = function() {
var bodyList = document.querySelector("body")
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (oldHref != document.location.href) {
oldHref = document.location.href;
console.log('location changed!');
if (window.location.href.indexOf('youtube.com/shorts') > -1) {
window.location.replace(window.location.toString().replace('/shorts/', '/watch?v='));
}
}
});
});
var config = {
childList: true,
subtree: true
};
observer.observe(bodyList, config);
};

Scorm files, Ruby on Rails

I have implemented a scorm api in my platform (LMS), for this I have used Ruby on rails, the Scorm gem and the javascript api.
Everything works correctly and the scorm contents are displayed with satisfaction. I do not have much experience in Scorm content, but there is a zip file that they sent me of type scorm, which when it is uploaded to the platform that I am using, it takes a long time to load and execute. when I test this file on Scorm cloud, the content runs normally. The problem is that the platform does not generate any error.
why can this happen?
bugs in my code? or optimization of the Scorm zip file?
The other scorm contents work normally, but this specific one, I have no idea why. I can not think of anything
any ideas? Thank you
this is de api js:
<html>
<head>
<title>VS SCORM - RTE API</title>
<script language="javascript">
function createRequest() {
// this is the object that we're going to (try to) create
var request;
// does the browser have native support for
// the XMLHttpRequest object
try {
request = new XMLHttpRequest();
}
// it failed so it's likely to be Internet Explorer which
// uses a different way to do this
catch (tryIE) {
// try to see if it's a newer version of Internet Explorer
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
}
// that didn't work so ...
catch (tryOlderIE) {
// maybe it's an older version of Internet Explorer
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
}
// even that didn't work (sigh)
catch (failed) {
alert("Error creating XMLHttpRequest");
}
}
}
return request;
}
//var debug = true;
var debug = false;
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
// ------------------------------------------
// SCORM RTE Functions - Initialization
// ------------------------------------------
function LMSInitialize(dummyString) {
// create request object
var req = createRequest();
// code to prevent caching
var d = new Date();
// set up request parameters - uses GET method
req.open('GET','/scorm/initializesco?code='+d.getTime(),false);
// submit to the server for processing
req.send(null);
// process returned data - error condition
if (req.status != 200) {
alert('Problem with Request');
return "";
}
// process returned data - OK
else {
return "true";
}
}
// ------------------------------------------
// SCORM RTE Functions - Getting and Setting Values
// ------------------------------------------
//function LMSGetValue(varname) {
// if (debug) {
// alert('*** LMSGetValue varname='+varname
// +' varvalue=value ***');
// }
// return "value";
//}
function LMSGetValue(varname) {
// create request object
var req = createRequest();
// set up request parameters - uses GET method
req.open('GET','/scorm/getValue?varname='+urlencode(varname)
+'&code='+Math.random(),false);
// submit to the server for processing
req.send(null);
//alert('LMSGetValue() - ' + req.responseText);
// process returned data - error condition
if (req.status != 200) {
alert('LMSGetValue() - Problem with Request');
return "";
}
// process returned data - OK
else {
return req.responseText.replace("\n","");
}
}
/*
function LMSSetValue(varname,varvalue) {
if (debug) {
alert('*** LMSSetValue varname='+varname
+' varvalue='+varvalue+' ***');
}
return "true";
}
*/
function LMSSetValue(varname,varvalue) {
// create request object
var req = createRequest();
// set up request parameters - uses combined GET and POST
//req.open('POST','nav/setValue?varname='+urlencode(varname)
// +'&code='+Math.random(),false);
// set up request parameters - uses combined GET and POST
req.open('POST','/scorm/setValue?varname='+urlencode(varname)
+'&code='+Math.random(),false);
// send header information along with the POST data
var params = 'varvalue='+urlencode(varvalue);
req.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
//req.setRequestHeader("Content-length", params.length);
//req.setRequestHeader("Connection", "close");
// submit to the server for processing
req.send(params);
// process returned data - error condition
if (req.status != 200) {
alert('LMSSetValue() - Problem with Request');
return "false";
}
// process returned data - OK
else {
return "true";
}
}
function LMSCommit(dummyString) {
LMSGetValue('');
if (debug)
{
//alert('*** LMSCommit ***');
}
return "true";
}
function LMSFinish(dummyString) {
// create request object
var req = createRequest();
// code to prevent caching
var d = new Date();
// set up request parameters - uses GET method
req.open('GET','/scorm/finishsco?code='+d.getTime(),false);
// submit to the server for processing
req.send(null);
// process returned data - error condition
if (req.status != 200) {
alert('Problem with Request');
return "";
}
// process returned data - OK
else {
return "true";
}
}
// ------------------------------------------
// SCORM RTE Functions - Error Handling
// ------------------------------------------
function LMSGetLastError() {
if (debug) { alert('*** LMSGetLastError ***'); }
sleep(1000);
return 0;
}
function LMSGetDiagnostic(errorCode) {
if (debug) {
alert('*** LMSGetDiagnostic errorCode='+errorCode+' ***');
}
return "diagnostic string";
}
function LMSGetErrorString(errorCode) {
if (debug) {
alert('*** LMSGetErrorString errorCode='+errorCode+' ***');
}
return "error string";
}
function urlencode( str ) {
//
// Ref: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_urlencode/
//
var histogram = {}, unicodeStr='', hexEscStr='';
var ret = (str+'').toString();
var replacer = function(search, replace, str) {
var tmp_arr = [];
tmp_arr = str.split(search);
return tmp_arr.join(replace);
};
// The histogram is identical to the one in urldecode.
histogram["'"] = '%27';
histogram['('] = '%28';
histogram[')'] = '%29';
histogram['*'] = '%2A';
histogram['~'] = '%7E';
histogram['!'] = '%21';
histogram['%20'] = '+';
histogram['\u00DC'] = '%DC';
histogram['\u00FC'] = '%FC';
histogram['\u00C4'] = '%D4';
histogram['\u00E4'] = '%E4';
histogram['\u00D6'] = '%D6';
histogram['\u00F6'] = '%F6';
histogram['\u00DF'] = '%DF';
histogram['\u20AC'] = '%80';
histogram['\u0081'] = '%81';
histogram['\u201A'] = '%82';
histogram['\u0192'] = '%83';
histogram['\u201E'] = '%84';
histogram['\u2026'] = '%85';
histogram['\u2020'] = '%86';
histogram['\u2021'] = '%87';
histogram['\u02C6'] = '%88';
histogram['\u2030'] = '%89';
histogram['\u0160'] = '%8A';
histogram['\u2039'] = '%8B';
histogram['\u0152'] = '%8C';
histogram['\u008D'] = '%8D';
histogram['\u017D'] = '%8E';
histogram['\u008F'] = '%8F';
histogram['\u0090'] = '%90';
histogram['\u2018'] = '%91';
histogram['\u2019'] = '%92';
histogram['\u201C'] = '%93';
histogram['\u201D'] = '%94';
histogram['\u2022'] = '%95';
histogram['\u2013'] = '%96';
histogram['\u2014'] = '%97';
histogram['\u02DC'] = '%98';
histogram['\u2122'] = '%99';
histogram['\u0161'] = '%9A';
histogram['\u203A'] = '%9B';
histogram['\u0153'] = '%9C';
histogram['\u009D'] = '%9D';
histogram['\u017E'] = '%9E';
histogram['\u0178'] = '%9F';
// Begin with encodeURIComponent, which most resembles PHP's encoding functions
ret = encodeURIComponent(ret);
for (unicodeStr in histogram) {
hexEscStr = histogram[unicodeStr];
ret = replacer(unicodeStr, hexEscStr, ret); // Custom replace. No regexing
}
// Uppercase for full PHP compatibility
return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
return "%"+m2.toUpperCase();
});
}
</script>
</head>
<body>
<p>
</body>
</html>
You're using blocking GET/SET requests (XHR async=false) to your backend for every LMSGetValue call. Some courses are much more aggressive about how many things they get and set at launch/initialization time. Most SCORM implementations do the heavy lifting in JS (all GET value processing never touches a server, most commonly) and only go to the backend for user state storage, often at a commit or some storage frequency. If that's the issue, there's no way to fix it that doesn't involve rewriting your interface to do all the SCORM logic client-side instead of server-side, as you can't switch to using async GET calls since LMSGetValue expects the return to be the value needed.

How to set the templateUrl in a component in Angular2?

How can I set the templateUrl in code? E.g., if I have
#Component({
selector: 'search-load',
templateUrl: '/loads/search'
})
I want:
#Component({
selector: 'search-load',
templateUrl: this.language+ 'loads/search'
})
where templateUrl is a mvc path.
Thank you.
You cannot this in component declaration like this since its outside of component's scope but this is how I do something like this
In my component:
#Component({
selector: 'live-auction-stats',
templateUrl: BaseConfigurations.baseTemplatePath + '/auction-stats.html',
})
And In my BaseConfigurations.ts file, I have
export abstract class BaseConfigurations
{
public baseTemplatePath: string = location.origin + '/app/templates'; //you can configure here
....
//other base configurations..
....
}
After a long searching i found that node_modules\#angular\platform-browser-dynamic\bundles\platform-browser-dynamic.umd.js is the responsible for loading template by url
so i can add some params to url dynamically like this :
var lang = JSON.parse(localStorage.getItem("Accept-Language"));
xhr.open('GET', lang+url, true);
then the final file will be :
(function(System, SystemJS) {/**
* #license Angular v2.2.3
* (c) 2010-2016 Google, Inc. https://angular.io/
* License: MIT
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('#angular/compiler'), require('#angular/core'), require('#angular/platform-browser')) :
typeof define === 'function' && define.amd ? define(['exports', '#angular/compiler', '#angular/core', '#angular/platform-browser'], factory) :
(factory((global.ng = global.ng || {}, global.ng.platformBrowserDynamic = global.ng.platformBrowserDynamic || {}),global.ng.compiler,global.ng.core,global.ng.platformBrowser));
}(this, function (exports,_angular_compiler,_angular_core,_angular_platformBrowser) { 'use strict';
var INTERNAL_BROWSER_PLATFORM_PROVIDERS = _angular_platformBrowser.__platform_browser_private__.INTERNAL_BROWSER_PLATFORM_PROVIDERS;
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var ResourceLoaderImpl = (function (_super) {
__extends(ResourceLoaderImpl, _super);
function ResourceLoaderImpl() {
_super.apply(this, arguments);
}
ResourceLoaderImpl.prototype.get = function (url) {
var resolve;
var reject;
var promise = new Promise(function (res, rej) {
resolve = res;
reject = rej;
});
var xhr = new XMLHttpRequest();
var lang = JSON.parse(localStorage.getItem("Accept-Language"));
xhr.open('GET', lang+url, true);
xhr.responseType = 'text';
xhr.onload = function () {
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
// response/responseType properties were introduced in ResourceLoader Level2 spec (supported
// by IE10)
var response = xhr.response || xhr.responseText;
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
var status = xhr.status === 1223 ? 204 : xhr.status;
// fix status code when it is 0 (0 status is undocumented).
// Occurs when accessing file resources or on Android 4.1 stock browser
// while retrieving files from application cache.
if (status === 0) {
status = response ? 200 : 0;
}
if (200 <= status && status <= 300) {
resolve(response);
}
else {
reject("Failed to load " + url);
}
};
xhr.onerror = function () { reject("Failed to load " + url); };
xhr.send();
return promise;
};
ResourceLoaderImpl.decorators = [
{ type: _angular_core.Injectable },
];
/** #nocollapse */
ResourceLoaderImpl.ctorParameters = [];
return ResourceLoaderImpl;
}(_angular_compiler.ResourceLoader));
var INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS = [
INTERNAL_BROWSER_PLATFORM_PROVIDERS,
{
provide: _angular_core.COMPILER_OPTIONS,
useValue: { providers: [{ provide: _angular_compiler.ResourceLoader, useClass: ResourceLoaderImpl }] },
multi: true
},
];
/**
* #license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
var globalScope;
if (typeof window === 'undefined') {
if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
// TODO: Replace any with WorkerGlobalScope from lib.webworker.d.ts #3492
globalScope = self;
}
else {
globalScope = global;
}
}
else {
globalScope = window;
}
// Need to declare a new variable for global here since TypeScript
// exports the original value of the symbol.
var _global = globalScope;
// TODO: remove calls to assert in production environment
// Note: Can't just export this and import in in other files
// as `assert` is a reserved keyword in Dart
_global.assert = function assert(condition) {
// TODO: to be fixed properly via #2830, noop for now
};
/**
* #license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
var __extends$1 = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
/**
* An implementation of ResourceLoader that uses a template cache to avoid doing an actual
* ResourceLoader.
*
* The template cache needs to be built and loaded into window.$templateCache
* via a separate mechanism.
*/
var CachedResourceLoader = (function (_super) {
__extends$1(CachedResourceLoader, _super);
function CachedResourceLoader() {
_super.call(this);
this._cache = _global.$templateCache;
if (this._cache == null) {
throw new Error('CachedResourceLoader: Template cache was not found in $templateCache.');
}
}
CachedResourceLoader.prototype.get = function (url) {
if (this._cache.hasOwnProperty(url)) {
return Promise.resolve(this._cache[url]);
}
else {
return Promise.reject('CachedResourceLoader: Did not find cached template for ' + url);
}
};
return CachedResourceLoader;
}(_angular_compiler.ResourceLoader));
var __platform_browser_dynamic_private__ = {
INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
ResourceLoaderImpl: ResourceLoaderImpl
};
/**
* #experimental
*/
var RESOURCE_CACHE_PROVIDER = [{ provide: _angular_compiler.ResourceLoader, useClass: CachedResourceLoader }];
/**
* #stable
*/
var platformBrowserDynamic = _angular_core.createPlatformFactory(_angular_compiler.platformCoreDynamic, 'browserDynamic', INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS);
exports.RESOURCE_CACHE_PROVIDER = RESOURCE_CACHE_PROVIDER;
exports.platformBrowserDynamic = platformBrowserDynamic;
exports.__platform_browser_dynamic_private__ = __platform_browser_dynamic_private__;
}));
})(System, System);

Cordova: iOS: not calling pushPlugin.register, window.onNotificaiton.APN

The pushPlugin.register function is getting called for Android, but not iOS. Here is the code I have.
this.initialize is getting called and I see the first alert there -- alert('PushNotifications:initialize');
Any ideas? why pushPlugin.register and window.onNotificationAPN function don't seem to get called?. At one brief point it was working, IIRC. I'm not sure what changed.
Here's my config setup:
https://gist.github.com/adaptivedev/d33f38cd3d6cf10be9dc
Thanks!
.service('PushNotifications', function(Utility, $cordovaToast, $rootScope) {
alert('PushNotifications');
var pushPlugin = null;
/*
this.deviceRegId = function() {
$rootScope.getFDeviceId();
}
*/
this.initialize = function() {
alert('PushNotifications:initialize');
document.addEventListener('deviceready', function() {
//alert('PushNotifications:initialize:deviceready:device='+JSON.stringify(device));
pushPlugin = window.plugins.pushNotification;
if ( device.platform == 'android' || device.platform == 'Android' || device.platform == "amazon-fireos" ){
pushPlugin.register(
function(result) {
console.log('PushNotifications:initialize:1:result='+result);
},
function(result) {
alert('PushNotifications:initialize:2:result='+result);
console.log(JSON.stringify(result));
},
{
"senderID":"123",
"ecb":"onNotificationGCM"
});
} else {
pushPlugin.register(
function(result) {
alert('PushNotifications:initialize:1:result='+result);
//$rootScope.setDeviceId(result)
},
function(result) {
alert('PushNotifications:initialize:2:result='+result);
console.log(JSON.stringify(result));
},
{
"badge":"true",
"sound":"true",
"alert":"true",
"ecb":"onNotificationAPN"
});
}
});
// notifications for Android
window.onNotificationGCM = function(e) {
alert('onNotificationGCM:e='+JSON.stringify(e));
window.boosterNotification = e;
switch( e.event )
{
case 'registered':
if ( e.regid.length > 0 )
{
$rootScope.setDeviceId(e.regid);
}
break;
case 'message':
// if this flag is set, this notification happened while we were in the foreground.
// you might want to play a sound to get the user's attention, throw up a dialog, etc.
if ( e.foreground )
{
// on Android soundname is outside the payload.
// On Amazon FireOS all custom attributes are contained within payload
var soundfile = e.soundname || e.payload.sound;
// if the notification contains a soundname, play it.
//var my_media = new Media("/android_asset/www/"+ soundfile);
//my_media.play();
}
else
{ // otherwise we were launched because the user touched a notification in the notification tray.
if ( e.coldstart )
{
//
}
else
{
//
}
}
var msg = e.payload.message.replace(/<b>/g, "")
msg = msg.replace(/<\/b>/g, "");
$cordovaToast.showShortCenter(msg).then(function(success) {
//$state.go('app.upcoming');
$rootScope.updateNotifications();
}, function (error) {
// error
}
);
//alert(e.payload.message);
//Only works for GCM
// e.payload.msgcnt + '</li>');
//Only works on Amazon Fire OS
// e.payload.timeStamp
break;
case 'error':
//e.msg
break;
default:
// Unknown
break;
}
};
// notifications for iOS
window.onNotificationAPN = function(result) {
alert('onNotificationAPN:result:1:='+JSON.stringify(result));
if ( event.alert )
{
//navigator.notification.alert(event.alert);
}
if ( event.sound )
{
//var snd = new Media(event.sound);
//snd.play();
}
if ( event.badge )
{
//.setApplicationIconBadgeNumber(successHandler, errorHandler, event.badge);
}
console.log('onNotificationAPN:result='+JSON.stringify(result));
window.boosterNotification = result;
};
};
});
I solved it! In Xcode, select the file (PushPlugin.m) and on right side check "Target Membership"

Setting Context Item position in Firefox addons SDK

I'm writing an extension that involving adding an item to Firefox's context menu, but it appends to the end of the menu and I couldn't find any pointers customizing item's position using Addon SDK (insertBefore/insertAfter), I know how this can be done using XUL, but I'm trying to do it using Addon SDK or some sort of Addon SDK/XUL combination
This is the code snippet related to context menu
main.js
var pageMod = require("sdk/page-mod");
var data = require("sdk/self").data;
var tabs = require("sdk/tabs");
var cm = require("sdk/context-menu");
pageMod.PageMod({
include: "*.youtube.com",
contentScriptFile: data.url("page.js"),
onAttach: function (worker) {
worker.port.emit('link', data.url('convertbutton.png'));
}});
cm.Item({
label: "Convert File",
image: data.url("bighdconverterlogo128png.png"),
context: [
cm.URLContext(["*.youtube.com"]),
cm.PageContext()
],
contentScriptFile: data.url("menu.js"),
onMessage: function(vUrl){
tabs.open(vUrl);
}
});
data/menu.js
self.on("click", function(){
self.postMessage('http://hdconverter.co/' + 'c.php?url=' + window.location.href);
});
Thanks
i dont know about sdk but for non-sdk addons its easy. but because you dont have the boiler plate setup its going to look long. add this code to your addon at the bottom:
var positionToInsertMenu = 0; //set the position you want it at here
var myLabelText = 'Convert File';
const {interfaces: Ci,utils: Cu} = Components;
Cu.import('resource://gre/modules/Services.jsm');
/*start - windowlistener*/
var windowListener = {
//DO NOT EDIT HERE
onOpenWindow: function (aXULWindow) {
// Wait for the window to finish loading
let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
aDOMWindow.addEventListener("load", function () {
aDOMWindow.removeEventListener("load", arguments.callee, false);
windowListener.loadIntoWindow(aDOMWindow, aXULWindow);
}, false);
},
onCloseWindow: function (aXULWindow) {},
onWindowTitleChange: function (aXULWindow, aNewTitle) {},
register: function () {
// Load into any existing windows
let XULWindows = Services.wm.getXULWindowEnumerator(null);
while (XULWindows.hasMoreElements()) {
let aXULWindow = XULWindows.getNext();
let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
windowListener.loadIntoWindow(aDOMWindow, aXULWindow);
}
// Listen to new windows
Services.wm.addListener(windowListener);
},
unregister: function () {
// Unload from any existing windows
let XULWindows = Services.wm.getXULWindowEnumerator(null);
while (XULWindows.hasMoreElements()) {
let aXULWindow = XULWindows.getNext();
let aDOMWindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
windowListener.unloadFromWindow(aDOMWindow, aXULWindow);
}
//Stop listening so future added windows dont get this attached
Services.wm.removeListener(windowListener);
},
//END - DO NOT EDIT HERE
loadIntoWindow: function (aDOMWindow, aXULWindow) {
if (!aDOMWindow) {
return;
}
var contentAreaContextMenu = aDOMWindow.document.getElementById('contentAreaContextMenu');
var myMenuItem;
if (contentAreaContextMenu) {
var menuItems = contentAreaContextMenu.querySelector('menuitem');
[].forEach.call(menuItems, function(item) {
if (item.getAttribute('label') == myLabelText) {
myMenuItem = item;
}
});
contentAreaContextMenu.removeChild(myMenuItem);
if (contentAreaContextMenu.childNodes.length >= positionToInsertMenu) { //position is greater then number of childNodes so append to end
contentAreaContextMenu.appendChild(myMenuItem);
} else {
contentAreaContextMenu.insertBefore(myMenuItem, contentAreaContextMenu.childNodes[thePosition]);
}
}
},
unloadFromWindow: function (aDOMWindow, aXULWindow) {
if (!aDOMWindow) {
return;
}
var myMenuItem = aDOMWindow.document.getElementById('myMenuItem');
if (myMenuItem) {
myMenuItem.parentNode.removeChild(myMenuItem);
}
}
};
windowListener.register();
on unload of your addon add this:
windowListener.unregister();
i copied pasted from a template and modded it real fast. for position to be accurate you probably have to consider which menuitems are hidden and which are not

Resources