Webpack and a legacy plugin that takes the real window object as an argument - jquery-plugins

I am migrating an app from Require.js to Webpack. Among the jQuery plugins that the app uses is hc-sticky. The source file of this plugin starts like this:
(function($, window, undefined) {
"use strict";
// console.log shortcut
var log = function(t){console.log(t)};
var $window = $(window),
document = window.document,
$document = $(document);
// detect IE version
var ie = (function(){var undef, v = 3, div = document.createElement('div'),
The module built with Webpack breaks at the last line of the above fragment, because the window that is passed as an argument to the plugin turns out to be an empty object that doesn't have reference to the document.
Could you please advise how to integrate this plugin in the Webpack build? I searched, but failed to find a working solution. An attempt to substitute this for window:
{test: /jquery-hc-sticky/, loader: 'imports?this=>window'}
doesn't work.

Related

Rebuilding Vue.js templates inside Laravel from a bundled App.js

Ok I had a developer I hired a while back to add some features into my app, at time I had never even looked into Vue or how it works. So when he only updated my app.js and not the repos vue files. Thus a year later when we decide to add new features yet again the old ones go * poof * when compiling the bundle. I have rebuilt most of it but ran into this part where it is importing a file that has no extension.
var _underscore = require('underscore');
var _underscore2 = _interopRequireDefault(_underscore);
var _Conversation = require('./Conversation.vue');
var _Conversation2 = _interopRequireDefault(_Conversation);
var _conversation = require('./../../api/conversation');
var _conversation2 = _interopRequireDefault(_conversation);
var _sweetalert = require('sweetalert');
var _sweetalert2 = _interopRequireDefault(_sweetalert);
This part here where it has /api/conversation - now you can see this with underscore and sweet alert.. but very confused about this one.. I dug into the app.js to find the reference for this and it was.
[function(require,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _vue = require('vue');
var _vue2 = _interopRequireDefault(_vue);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.default = {
removeConversation: function removeConversation(website_id, conversation_id) {
return _vue2.default.http.post('/api/chat/' + website_id + '/' + conversation_id + '/remove');
}
};
},{"vue":41}]
So I rebuilt the file in the location it points to the best of my knowledge and and just leave it with no extension and if i leave in an import for vue it then says it has to be a module for import. so if i leave the vue part off it will build but then it doesn't see to do what is intended. If add .vue on the end it adds a lot of extra code on the build and still doesnt' do what is intended. I am think maybe is file has an extension but I just am not familiar enough with Vue to know it. Hoping someone can shine some like on this issue.
ok seems that the app.js can read a .js file without having the extension on the end. so this is the file type that I was missing.

Firefox addon SDK - attaching a stylesheet to a tab triggering an error

I'm trying to add a content script to a tab when the tab loads, but my code is throwing
TypeError: window.QueryInterface is not a function'
when I run the attachTo method.
var attachTo = require('sdk/content/mod').attachTo;
var style = require('sdk/stylesheet/style');
tabs.on('ready', function(tab) {
var worker = tab.attach({
contentScriptFile: ['./content.js']
});
var s = style.Style({
uri: './style.css'
});
attachTo(s, tabs.activeTab.window); <------------ causes the error
array.add(pageWorkers, worker);
mainListener(worker);
});
Any ideas?
The error message suggests that attachTo expects an XPCOM object. activeTab.window returns a wrapper object around the native window. The high level APIs of the sdk generally deal in javascript wrapper objects that hide most of the internals.
You can use modelFor and viewFor to convert between those.

pushState change - equivalent to Chrome Extension onHistoryStateUpdated

I'm porting a Chrome extension to a Firefox extension and due to the nature of the website that it runs on, I need to monitor the pushState.
Chrome Extensions has a handy way to handle this: chrome.webNavigation.onHistoryStateUpdated. The way that I use it in the Chrome extension is as follows:
chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
var tabUrl = details.url;
if (isTabUrlValid(tabUrl)) {
$.get(tabUrl, function(data) {
var videoUrl = $(data).find('meta[itemprop=contentURL]').prop('content');
videoUrl = validateUrl(videoUrl);
videoUrl5k = make5kUrl(videoUrl);
});
}
});
I need to do the same thing for the Firefox Extension, but I haven't found any good answers. I've tried doing the answer mentioned here: How to get notified about changes of the history via history.pushState?
(function(history) {
var pushState = history.pushState;
history.pushState = function(state) {
if (typeof history.onpushstate == "function") {
history.onpushstate({state: state});
}
var tabUrl = tabs.activeTab.url;
console.log("UPDATED TAB URL: " + tabUrl);
if (isTabUrlValid(tabUrl)) {
$.get(tabUrl, function(data) {
var videoUrl = $(data).find('meta[itemprop=contentURL]').prop('content');
videoUrl = validateUrl(videoUrl);
videoUrl5k = make5kUrl(videoUrl);
});
}
return pushState.apply(history, arguments);
};
})(window.history);
The problem is that when I do cfx run it complains that history/window is undefined and therefore never gets detected. I think this is due to it being within the SDK, but I don't know of a good workaround.
Any thoughts?
Edit: I looked at #willma's answer below and I don't think that would work for me. The issue is that the URL is updated via pushState and the DOM is not... Is there any good way replicate what I do in the chrome extension?
Edit: Here's the pageMod portion
pageMod.PageMod({
attachTo: 'top', // Don't attach to iFrames --> http://goo.gl/b6b1Iv
include: [URLs],
contentScriptFile: [data.url("jquery-2.1.1.min.js"),
data.url("csScript.js")],
onAttach: function(worker) {
worker.port.on('url', function(url) {
var videoUrl = validateUrl(url);
videoUrl5k = make5kUrl(videoUrl);
console.log("--5K URL--: " + videoUrl5k);
});
}
});
That history code needs to get injected into a tab using a content script. Right now your logic says when the history event occurs, check to see if the tab URL is valid.
In Firefox, the logic will be the other way around: when a tab is opened, check if its URL is valid, and if so, then attach a script to it that will monitor for the history event. To do so you'll need to use a Page Mod.
Edit: All the code
One key concept you're missing is the difference between a content script and a main/library script. The library scripts are stored in lib and have access to all the SDK modules, but don't have access to the DOM, window object… The content scripts are stored in data, are injected into a page using the PageMod or tabs modules, can access the dom and window objects, but have no access to any SDK modules. Content scripts are essentially like the page scripts you'd attach your standard HTML page (with <script></script>) with the caveats that they can't share variables other page scripts but they can communicate with the main scripts.
The only reason I bring this up is because your initial problem was trying to access the window object from a main script and the problem in your fiddle is that you're trying to access the tabs module inside a content script. It's worth reading the topmost link in this answer if this is still confusing.
main.js
const { PageMod } = require('sdk/page-mod');
var sendXHR = function(url) {
// Do something with the new URL
// See Request Module docs (below) for sending XHRs from main script.
}
const pageMod = PageMod({
attachTo: 'top',
include: '*',
onAttach: function(worker) {
worker.port.on('newURL', sendXHR);
}
});
content.js
var sendNewUrlToMain = function() {
self.port.emit('newURL', location.href);
}
var pushState = window.history.pushState;
window.history.pushState = function(state) {
if (typeof history.onpushstate == "function") {
history.onpushstate({state: state});
}
sendNewUrlToMain();
return pushState.apply(history, arguments);
}
window.addEventListener('hashchange', sendNewUrlToMain);
Here are the request module docs, for making XHRs.
NB: if you don't want to use the request module (the only reason being that you already have standard XHR code for your chrome extension and don't want to take the time to learn/rewrite that code), you can send a standard XHR from the content script, but in doing so, you risk allowing the user to close the tab and thus destroy the script before your XHR callbacks are executed.

Firefox Extension building / SDK, click on a page dom element from within extension

I'm developing a Firefox extension using the latest SDK on FF 31.
In the past (before the SDK was around, years ago), it was possible for the extension to completely manipulate all parts of the page the user was on, for example, change dom elements, etc.
It seems like modifying dom elements is still supported, but I can't seem to be able to fire a "click" even on a DOM element created by the page (not by the extension).
// main.js
var data = require("sdk/self").data;
var pageMod = require("sdk/page-mod");
pageMod.PageMod({
include: "*",
contentScriptFile: [data.url("jquery.js"), data.url("my-addon.js")]
});
//my-addon.js
var z = $('a').filter(function(index) { return $(this).text() === "here"; });
if(z != null && z.length > 0){
alert("FOUND IT");
$(z).click();
}
The code above just looks for a link that has "here" as the exact text and tries to click on it. It finds it just fine, but the click action does not do anything.
Figured it out...
For anyone who has the same problem, add this to the top of your "my-addon.js" script
unsafeWindow.click_object = function(_item) {
_item.click();
}
Then you can call it like this (from the same my-addon.js script):
unsafeWindow.click_object($(z).get(0));

CKEditor editor instance .lang is undefined?

Hi I am trying to make some changes to our implementation of CKEDITOR 3.6.2
by removing all but 2 options in the link target type dropdown that appears in the link dialog's target tab.
I tried to achieve this using the API but I am getting an error in the minified core ckeditor.js file in the dialog() method on this line X=S.lang.dir; where S is the editor.
The .lang property of the editor instance is undefined when doing CKEDITOR.dialog(editor, 'link'), when viewing debugging the "editor" object I don't see a lang object anywhere, so I'm not sure why this is missing? I didn't work on our original implementation but as far as I know we have only added 2 plugins and not changed the ckeditor core.
Here is my code:
for (var i in CKEDITOR.instances) {
var editor = CKEDITOR.instances[i];
var dialogObj = CKEDITOR.dialog(editor, 'link');
var linkDialogTargetField = dialogObj.getContentElement('target', 'linkTargetType');
// API didn't seem to have a more efficient approach than clearing all and re-adding the one we want
linkDialogTargetField.clear();
linkDialogTargetField.add('notSet', '<not set>');
linkDialogTargetField.add('_blank', 'New Window (_blank)');
}
I have managed to make my change without using the API properly by doing the below:
CKEDITOR.on('dialogDefinition', function (ev) {
// Take the dialog name and its definition from the event
// data.
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
// Check if the definition is from the dialog we're
// interested on (the "Link" dialog).
if (dialogName == 'link') {
// Get a reference to the "Link target" tab.
var targetTab = dialogDefinition.getContents('target');
var targetField = targetTab.get('linkTargetType');
// removing everything except the 1st (none set) & 3rd (new window) options from the dropdown
targetField['items'].splice(1, 2);
targetField['items'].splice(2, 3); // the array is reduced by splice, so we have to splice from [2] onwards not from [4]
}
});
but I don't like this approach, does anyone have any ideas? or other ways to achieve the same result using the API?
Using second approach and overwritten the dropdown items instead of splicing.

Resources