Mozilla: openTab fails in recent version - firefox-addon

In a Firefox extension, I open new tabs:
var tab = gBrowser.addTab(url, referrer, null, postData, null, null);
With Firefox 30, this fails, sometimes, after 9 tabs opened:
TypeError: this.selectedItem is null
However, the number of tabs does increase by 1 (checked with gBrowser.browsers.length).
I tried this alternative code, but I get the same error after a while:
var wm = Components.classes["#mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
var my_browser = wm.getMostRecentWindow("navigator:browser").getBrowser();
var tab = my_browser.addTab(url, referrer, null, postData, null, null);

Somehow this was fixed by changing some of the custom CSS used to modify the display of the browser
#navigator-toolbox {
/*display: none;*/ /* causes crashes!!! */
max-height: 0;
overflow: hidden;
}
#TabsToolbar {
/*display: none;*/ /* causes crashes!!! */
max-height: 0;
overflow: hidden;
}

Related

Bullet points and alphabets are missing when converting html to pdf using jsPDF

I try to convert from html to pdf using jsPDF.
I could not get the pdf as the original html.
ordered list and unordered list bullet points are missing in the pdf file.
ordered-list-in-html
ordered-list-in-pdf
unordered-list-in-html
unordered-list-in-pdf
function BlazorDownloadFile(filename, text) {
let parser = new DOMParser();
let doc = parser.parseFromString(text, "text/html");
console.log(doc.body);
const element = doc.body;
var opt = {
margin: 1,
filename: filename,
html2canvas: { scale: 2 },
jsPDF: { unit: "cm", format: "a4", orientation: "portrait" },
};
// Choose the element that our invoice is rendered in.
html2pdf().set(opt).from(element).save();
}
Please help me to fix this issue.
Here is a workaround for bullet points in scss you can use to overcome this issue:
ul li {
list-style-type: none;
&:before {
content: '• ';
margin-left: -1em;
}
}

How to display a huge GeoJSON file to the MapBox?

I'm new in MapBox GL Js and I want to call a big GeoJSON file over https and display it to the map.
I think that calling vector Tile is the best way to do that, I found some tutorials that show how to convert your GeoJSON data to Vector Tile but on Server Side or upload it to the MapBox Style but my GeoJSON file is frequently changing. So I found this solution is a new JavaScript library called geojson-vt, describing how to convert a huge GeoJSON files to vector tile on the fly (Client Side) with crazy fast, It's seems like what I'm looking for, BUT !!, How can I integrate it to the MapBox GL JS for calling the layer ??
Blocking on How can I add Layer using Mapbox GL JS with the following result :
var tileIndex = geojsonvt(MyGeoJSON);
var tile = tileIndex.getTile(z, x, y);
... Or I just didn't get it ! Please somebody helps or can propose some other solution for my problem.
You don't need to worry about geojson-vt. Mapbox-GL-JS does that internally. So you can just follow the standard documentation for loading a GeoJSON layer.
If your GeoJSON is really huge, then probably the limiting factor will be network transfer, which means you really need to be serving server-side vector tiles.
I'd recommend using Deck.gl GeoJSON Layer. Here's an example:
<html>
<head>
<title>deck.gl GeoJsonLayer (Polygon) Example</title>
<script src="https://unpkg.com/deck.gl#^8.0.0/dist.min.js"></script>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.4.0/mapbox-gl.js"></script>
<style type="text/css">
body {
width: 100vw;
height: 100vh;
margin: 0;
overflow: hidden;
}
.deck-tooltip {
font-family: Helvetica, Arial, sans-serif;
padding: 6px !important;
margin: 8px;
max-width: 300px;
font-size: 10px;
}
</style>
</head>
<body>
</body>
<script type="text/javascript">
const {DeckGL, GeoJsonLayer} = deck;
const COLOR_SCALE = [
// negative
[65, 182, 196],
[127, 205, 187],
[199, 233, 180],
[237, 248, 177],
// positive
[255, 255, 204],
[255, 237, 160],
[254, 217, 118],
[254, 178, 76],
[253, 141, 60],
[252, 78, 42],
[227, 26, 28],
[189, 0, 38],
[128, 0, 38]
];
const geojsonLayer = new GeoJsonLayer({
data: 'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/geojson/vancouver-blocks.json',
opacity: 0.8,
stroked: false,
filled: true,
extruded: true,
wireframe: true,
getElevation: f => Math.sqrt(f.properties.valuePerSqm) * 10,
getFillColor: f => colorScale(f.properties.growth),
getLineColor: [255, 255, 255],
pickable: true
});
new DeckGL({
mapboxApiAccessToken: '<mapbox-access-token>',
mapStyle: 'mapbox://styles/mapbox/light-v9',
initialViewState: {
latitude: 49.254,
longitude: -123.13,
zoom: 11,
maxZoom: 16,
pitch: 45
},
controller: true,
layers: [geojsonLayer],
getTooltip
});
function colorScale(x) {
const i = Math.round(x * 7) + 4;
if (x < 0) {
return COLOR_SCALE[i] || COLOR_SCALE[0];
}
return COLOR_SCALE[i] || COLOR_SCALE[COLOR_SCALE.length - 1];
}
function getTooltip({object}) {
return object && `Average Property Value
${object.properties.valuePerSqm}
Growth
${Math.round(object.properties.growth * 100)}`;
}
</script>
</html>
Atrribution here.
Oh, man, I've spent 8 days, researching that.
The solution is:
var vtpbf = require('vt-pbf');
var geojsonVt = require('geojson-vt');
var orig = JSON.parse(fs.readFileSync(__dirname + 'myjson.json'))
var tileindex = geojsonVt(orig)
var tile = tileindex.getTile(x, y, z); // mapbox sends automatic request to the server, and give x, y , z
// pass in an object mapping layername -> tile object
var buff = vtpbf.fromGeojsonVt({ 'geojsonLayer': tile });
I've sent the result to the frontend, it works like Mapbox API. For the details check: https://github.com/mapbox/vt-pbf
And from the Mapbox side:
const source = {
type : 'vector',
'tiles' : [ 'http://localhost:1234/county?z={z}&x={x}&y={y}' ],
minzoom : 0,
maxzoom : 14
};
map.addSource('source', source );
map.addLayer({
'id' : 'source',
'type' : 'fill',
'source' : 'source',
'source-layer' : 'tiles-sequences',
'fill-color' : '#00ffff'
});

Azure Media Player on iOS devices

I'm streaming O365 videos using Azure Media Player in a web app that must be used only in mobile devices. It works with WP and Android, but the player stuck on iOS.
This is my code
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + bearer);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync($"{url}/GetPlaybackUrl('1')");
var content = await response.Content.ReadAsStringAsync();
var firstVal = JsonConvert.DeserializeObject<VideoToken>(content);
response = await client.GetAsync($"{url}/GetStreamingKeyAccessToken");
content = await response.Content.ReadAsStringAsync();
var secondVal = JsonConvert.DeserializeObject<VideoToken>(content);
Client Side
<video id="newsVideoAMP" class="azuremediaplayer amp-default-skin amp-big-play-centered" tabindex="0"></video>
var initVideoPlayer = function (playbackUrl, streamingKeyAccessToken) {
try {
var myOptions = {
"nativeControlsForTouch": false,
controls: true,
autoplay: false,
techOrder: ["azureHtml5JS", "flashSS", "html5FairPlayHLS", "silverlightSS", "html5"],
logo: { enabled: false }
}
newsVideoPlayer = amp("newsVideoAMP", myOptions,
function () {
this.addEventListener(amp.eventName.error, function () {
window.alert('error');
console.log('Error: amp init');
var errorDetails = newsVideoPlayer.error();
window.alert(errorDetails);
var code = errorDetails.code;
var message = errorDetails.message;
$("#log").append("<li><span>code: " + code + " - detail: " + message + "</span></li>')");
});
});
newsVideoPlayer.src([
{
"src": playbackUrl,
"type": "application/vnd.ms-sstr+xml",
"protectionInfo": [
{
"type": "AES",
"authenticationToken": streamingKeyAccessToken
}
]
}]);
}
catch (err) {
console.log(err);
}
}
I think the issue is related to video encoding. So I tried to use GetPlaybackUrl('0') (and avoid the next token request), but the player stops to work on WP and Android and still not work on iOS.
The logger in callback function doesn't tell me some useful and I have also tried to change the tech order.
Is there a console to manage video encoding in order to avoid the AES algorithm and the decrypt token? Because this doc explain that iOS works with HTML5 tech will no token request. How can I solve? Thanks
I found a workaround to reproduce videos on iOS devices.
Instead of use REST API I put an iframe element in my page with the video embedded.
Like this (using MVC Razor):
var url = "{YourWebsiteUrl}/portals/hub/_layouts/15/VideoEmbedHost.aspx?chId={YourChannelId}&vId={YourVideoId}&width=853&height=480&autoPlay=false&showInfo=false";
<iframe width=853 height=480 id="videoframe" src="#url" allowfullscreen data-spresponsive style='position: absolute; top: 0; left: 0; right: 0; bottom: 0; height: 100%; max-width: 100%;'></iframe>
I get this code from the popup of "embed" menu in the video page of Office365 Video.
If somebody else knows another (and better) method, please let me know. Thanks

accessing pseudo-element property values through getComputedStyle in dart

I wish to detect what media query is active - I'm using Bootjack, so hence I am using the default breakpoints
I expected to be able to use getComputedStyle() to get hold of the value of the 'content' property in the example below - but I don't seem to get the syntax correct. I can happily get the value of an element - say the font-famly on the body, but not pseudo-elements...
Here's what I am doing:
Given this css..
/* tablets */
#media(min-width:768px){
body::after {
content: 'tablet';
display: none;
}
}
#media(min-width:992px){
body::after {
content: 'desktop';
display: none;
}
}
#media(min-width:1200px){
body::after {
content: 'large-screen';
display: none;
}
}
I have this in my dart file:
String activeMediaQuery = document.body.getComputedStyle('::after').getPropertyValue('content');
but activeMediaQuery is always empty.
I've tried ('after') and (':after') and anything else weird and wonderful but to no avail.
String activeMediaQuery = document.body.getComputedStyle().getPropertyValue('font-family');
sets the variable activeMediaQuery to the value of the font-family that I am using (not much use to me though!)
What should I be doing?
You can also subscribe to MediaQuery change events
for more details see https://github.com/bwu-dart/polymer_elements/blob/master/lib/polymer_media_query/polymer_media_query.dart
There is a bug in Dart and the workaround uses dart-js-interop.
This is the code from the polymer-media-query element. I don't know if the comments not suppored in Dart yet are still valid. It's a few months since I tried it.
Here is an example page that shows how to use the element.
https://github.com/bwu-dart/polymer_elements/blob/master/example/polymer_media_query.html
var _mqHandler;
var _mq;
init() {
this._mqHandler = queryHandler;
mqueryChanged(null);
if (_mq != null) {
if(context['matchMedia'] != null) {
_mq.callMethod('removeListener', [_mqHandler]);
}
// TODO not supported in Dart yet (#84)
//this._mq.removeListener(this._mqHandler);
}
if (mquery == null || mquery.isEmpty) {
return;
}
if(context['matchMedia'] != null) {
_mq = context.callMethod('matchMedia', ['(${mquery})']);
_mq.callMethod('addListener', [_mqHandler]);
queryHandler(this._mq);
}
// TODO not supported in Dart yet (#84)
// Listener hast to be as MediaQueryListListener but this is and abstract
// class and therefor it's not possible to create a listner
// _mq = window.matchMedia(q);
// _mq.addListener(queryHandler);
// queryHandler(this._mq);
}
void queryHandler(mq) {
queryMatches = mq['matches'];
//fire('polymer-mediachange', detail: mq);
}
This worked for me with the CSS you provided in your question but only when the window was wider than 768 px. You might miss a rule with max-width: 768px
import 'dart:html' as dom;
void main () {
dom.window.onResize.listen((e) {
var gcs = dom.document.body.getComputedStyle('::after');
print(gcs.content);
});
}

Can I make a bookmarklet put some text into the clipboard?

Say I wanted to have bit of text (actually 4 different addresses) that I'd like to be able to easily (and frequently) paste. Is there a way I can make a bookmarklet that will put those addresses into the clipboard?
I'd like to be able to click the appropriate one, then right click + Paste.
Yes it's possible, have a look at zeroclipboard (note: requires flash). Also see this previous question.
Try building a Firefox extension instead of a bookmarklet. Mozilla XUL (extension language) lets you do copy-paste. Another option is a Java Applet.
http://brooknovak.wordpress.com/2009/07/28/accessing-the-system-clipboard-with-javascript/
Method with no third-party libraries
While zeroclipboard could potentially work, this method will allow you to visually select an element and automatically copy the inner text to your clipboard without having to download any third-party libraries. It is based on this function by Arne Hartherz and modified to work both in HTTPS and HTTP contexts.
Readable version:
var overlay = document.createElement('div');
Object.assign(overlay.style, {
position: 'fixed',
top: 0,
left: 0,
width: '100vw',
height: '100vh',
zIndex: 99999999,
background: 'transparent',
cursor: 'crosshair'
});
document.body.append(overlay);
function copyToClipboard(textToCopy) {
// navigator clipboard api needs a secure context (https)
if (navigator.clipboard && window.isSecureContext) {
// navigator clipboard api method'
return navigator.clipboard.writeText(textToCopy);
} else {
// text area method
let textArea = document.createElement("textarea");
textArea.value = textToCopy;
// make the textarea out of viewport
textArea.style.position = "fixed";
textArea.style.left = "-999999px";
textArea.style.top = "-999999px";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
return new Promise((res, rej) => {
// here the magic happens
document.execCommand('copy') ? res() : rej();
textArea.remove();
});
}
};
function getElement(event) {
overlay.style.pointerEvents = 'none';
var element = document.elementFromPoint(event.clientX, event.clientY);
overlay.style.pointerEvents = 'auto';
return element;
}
document.addEventListener('mousemove', function(event) {
var element = getElement(event);
if (!element) return;
var position = element.getBoundingClientRect();
Object.assign(overlay.style, {
background: 'rgba(0, 128, 255, 0.25)',
outline: '1px solid rgba(0, 128, 255, 0.5)',
top: '' + position.top + 'px',
left: '' + position.left + 'px',
width: '' + position.width + 'px',
height: '' + position.height + 'px'
});
});
overlay.addEventListener('click', function(event) {
var element = getElement(event);
var text = element.textContent || element.value;
text = text.replace(/\n[ \n]+\n/g, "\n").replace(/\n\n+/g, "\n\n").replace(/^\n+|\n+$/g, '');
if (!text.match("\n")) text = text.replace(/^ +| +$/, '')
copyToClipboard(text);
document.body.removeChild(overlay);
});
Minified version for use in bookmarklet:
javascript:void function(){function a(a){if(navigator.clipboard&&window.isSecureContext)return navigator.clipboard.writeText(a);else{let b=document.createElement("textarea");return b.value=a,b.style.position="fixed",b.style.left="-999999px",b.style.top="-999999px",document.body.appendChild(b),b.focus(),b.select(),new Promise((a,c)=>{document.execCommand("copy")?a():c(),b.remove()})}}function b(a){c.style.pointerEvents="none";var b=document.elementFromPoint(a.clientX,a.clientY);return c.style.pointerEvents="auto",b}var c=document.createElement("div");Object.assign(c.style,{position:"fixed",top:0,left:0,width:"100vw",height:"100vh",zIndex:99999999,background:"transparent",cursor:"crosshair"}),document.body.append(c);document.addEventListener("mousemove",function(a){var d=b(a);if(d){var e=d.getBoundingClientRect();Object.assign(c.style,{background:"rgba(0, 128, 255, 0.25)",outline:"1px solid rgba(0, 128, 255, 0.5)",top:""+e.top+"px",left:""+e.left+"px",width:""+e.width+"px",height:""+e.height+"px"})}}),c.addEventListener("click",function(d){var e=b(d),f=e.textContent||e.value;f=f.replace(/\n[ \n]+\n/g,"\n").replace(/\n\n+/g,"\n\n").replace(/^\n+|\n+$/g,""),f.match("\n")||(f=f.replace(/^ +| +$/,"")),a(f),document.body.removeChild(c)})}();

Resources