Currently I can load a web font very easily using Google's Web Font loader:
WebFont.load({
google: {
families: ['Bree Serif']
}
});
However, is it possible to later unload the fonts and added elements from the DOM so they're no longer used on the page?
The documentation on the project's Github doesn't show any options or methods that offer the functionality.
You can simply use a MutationObserver to keep track of the changes made to the DOM and remove the added elements when you so desire.
Below is a simple sample implementation:
(function() {
"use strict";
var addedNodes = [];
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
Array.prototype.forEach.call(mutation.addedNodes, function(node) {
addedNodes.push(node);
});
});
observer.disconnect();
});
loader.addEventListener('click', function() {
observer.observe(document, {
childList: true,
subtree: true,
addedNodes: true
});
//Two loads simply to demonstrate that's not a problem
WebFont.load({
google: {
families: ['Bree Serif']
}
});
WebFont.load({
google: {
families: ['Indie Flower']
}
});
loader.disabled = true;
remover.disabled = false;
});
remover.addEventListener('click', function() {
addedNodes.forEach(function(node) {
node.remove();
});
addedNodes = [];
loader.disabled = false;
remover.disabled = true;
});
}());
body {
text-align: center;
background: aliceblue;
}
h1 {
font-family: 'Indie Flower';
font-size: 3em;
color: cadetblue;
}
p {
font-family: 'Bree Serif';
color: crimson;
}
input[disabled] {
display: none;
}
<script src="//ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js"></script>
<input id="loader" type="button" value="Click to load webfonts" />
<input id="remover" type="button" value="Remove loaded webfonts" disabled="true" />
<h1>Chapter 1</h1>
<p>Grumpy wizards make toxic brew for the evil Queen and Jack.</p>
Related
I am building a world map with am5charts in HTML/JS and I would like that, on clicking a country, it opens the link given in the "description" attribute of that specific country.
For some reason, it seems that after "setAll" the modified countries become deaf and don't listen to the event "click"...
If I define the new attributes after the event.click, then I can't retrieve the new variable in the event.
Below a snippet of my code. Thank you!
PS. I am new in asking questions here so don't hesitate to let me know if I did something wrong!
HTML
<html>
<head>
<title></title>
<link rel="stylesheet" href="css/style.css" media="screen">
</head>
<body>
<!-- <div id="header"></div> -->
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/map.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
<script src="https://cdn.amcharts.com/lib/5/geodata/worldLow.js"></script>
<script src="https://www.amcharts.com/lib/5/geodata/worldHigh.js"></script>
<script src="https://www.amcharts.com/lib/5/geodata/peruHigh.js"></script>
<div id="chartdiv"></div>
<div id="info"></div>
<script src="js/script.js"></script>
<!-- <div id="footer"></div> -->
</body>
</html>
CSS
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#chartdiv {
width: 100%;
height: 95vh;
margin-bottom: 100vh;
}
JS
// Create root and chart
var root = am5.Root.new("chartdiv");
// Set themes
root.setThemes([
am5themes_Animated.new(root)
]);
var chart = root.container.children.push(
am5map.MapChart.new(root, {
panX: "rotateX",
projection: am5map.geoNaturalEarth1(),
wheelY: "none",
maxPanOut: 0.0
})
);
var backgroundSeries = chart.series.unshift(
am5map.MapPolygonSeries.new(root, {})
);
// sea color
backgroundSeries.mapPolygons.template.setAll({
fill: am5.color(0xd4f1f9),
stroke: am5.color(0xd4f1f9),
});
backgroundSeries.data.push({
geometry: am5map.getGeoRectangle(90, 180, -90, -180)
});
chart.events.on("wheel", function (ev) {
if (ev.originalEvent.ctrlKey) {
ev.originalEvent.preventDefault();
chart.set("wheelY", "zoom");
}
else {
chart.set("wheelY", "none");
overlay.show();
overlay.setTimeout(function () {
overlay.hide()
}, 800);
}
});
// Create polygon series
var polygonSeries = chart.series.push(
am5map.MapPolygonSeries.new(root, {
// geoJSON: am5geodata_worldLow,
geoJSON: am5geodata_worldHigh,
// geoJSON: am5geodata_peruHigh,
exclude: ["AQ", "FK", "GS", "TF", "HM"],
fill: am5.color(0x095256)
})
);
// Hover color
polygonSeries.mapPolygons.template.states.create("hover", {
fill: am5.color(0x677935),
});
// Add all blogs URLs
polygonSeries.data.setAll([{
id: "FR",
name: "France",
description: "www.google.com"
}, {
id: "ES",
name: "Spain",
value: 200
}]);
polygonSeries.mapPolygons.template.events.on("click", function (ev) {
var clickedCountry = ev.target.dataItem.get("id");
console.log(clickedCountry);
window.open(ev.target.dataItem.get("description"));
});
I found an answer! Using Promise.all as shown below.
// click event to open link
polygonSeries.mapPolygons.template.events.on("click", (ev) => {
var clickedCountry = ev.target.dataItem.get("id");
var clickedData = polygonSeries.getDataItemById(clickedCountry);
var pageToOpen = clickedData.dataContext.description;
if (pageToOpen in window) { // check if "description" is empty
console.log("Not visited");
} else {
Promise.all([
window.open(pageToOpen)
]);
}
});
...
// list of countries with their links
polygonSeries.data.setAll([
{
id: "FR", description: "https://www.google.com" }
}
So I'm making a gnome shell extension, and I can't figure out how to make one part of my extension normal font weight. Here is my extension.js file:
'use strict';
const { St, Clutter } = imports.gi;
const Main = imports.ui.main;
let _myText;
class Extension {
enable() {
_myText = new St.Label({ text: 'This should be normal font weight.', y_align: Clutter.ActorAlign.CENTER, style_class: 'panel-button', track_hover: false, reactive: false});
Main.panel._leftBox.insert_child_at_index(_myText, 10)
}
disable() {
_myText.destroy();
}
}
function init() {
return new Extension();
}
And here is my stylesheet.css file:
StLabel._myText {
font-weight: normal;
}
What am I doing wrong?
You can't just use arbitrary JavaScript variables in CSS; you need to tell a widget what CSS name and class it's supposed to use:
.my-class {
font-weight: normal;
}
const myLabel = new St.Label({
text: 'My Label',
style_class: 'panel-button my-class',
});
See also:
Anatomy of an Extension at gjs.guide
St Documentation at gjs-docs.gnome.org
While using introjs.js, I am trying to set the position of a tooltip (.introjs-tooltip) but, if I use the onafterchange event, my code runs, and then the position of the tooltip is set by introjs, and my values for top and left are overwritten. How can I make my change AFTER introjs has done it's calculations for the location of the tooltip?
<div>
<div class="divStep step1">
<span>Nothing much going on here</span>
</div>
<div id="step2" class="divStep step2">
<span>This is step 2</span>
</div>
<div id="step3" class="divStep step3">
<span>This is step 3</span>
</div>
</div>
body {
background-color: #00eeee;
}
.divStep {
display: block;
height: 100px;
width: 400px;
background-color: #fff;
margin: 10px;
padding: 10px;
}
.tt-step2 {
top: 0 !important;
left: 0 !important;
background-color: #ff0000;
}
var myIntro = {
tooltipPosition: 'bottom',
steps: [
{
intro: 'Howdy! This is step 1'
},
{
element: '#step2',
intro: 'This is step 2',
onbeforechange: function(){
console.log('onbeforechange step 2');
$('.introjs-tooltip').addClass('tt-step2');
console.log('has class? ' + $('.introjs-tooltip').hasClass('tt-step2'));
},
onchange: function(){
console.log('onchange step 2');
$('.introjs-tooltip').addClass('tt-step2');
console.log('has class? ' + $('.introjs-tooltip').hasClass('tt-step2'));
},
onafterchange: function(){
console.log('onafterchange step 2');
$('.introjs-tooltip').addClass('tt-step2');
console.log('has class? ' + $('.introjs-tooltip').hasClass('tt-step2'));
}
},
{
element: '#step3',
intro: 'This is step 3'
}
]
}
function launchIntro(){
var intro = introJs();
intro.setOptions(myIntro);
intro
.onbeforechange(function(){
currentStep = this._options.steps[this._currentStep];
if(currentStep.onbeforechange) {
currentStep.onbeforechange();
}
})
.onchange(function(){
currentStep = this._options.steps[this._currentStep];
if(currentStep.onchange) {
currentStep.onchange();
}
})
.onafterchange(function(){
currentStep = this._options.steps[this._currentStep];
if(currentStep.onafterchange) {
currentStep.onafterchange();
}
})
.start();
}
launchIntro();
I came across a similar issue. Currently IntroJS library has an open issue on github.
I had an assignment to heavily customize the elements styles and adjust some behavior.
I managed to handle the situation by using MutationObserver
Here's an example snippet:
const observer = new MutationObserver((mutations) => {
const { target } = mutations[0];
document.querySelector('.introjs-tooltip').style.top = `${
document.querySelector('.introjs-helperLayer').clientHeight
- document.querySelector('.introjs-tooltip').clientHeight - 10}px`;
return null; });
observer.observe(
document.querySelector('.introjs-tooltip'),
{ attributes: true, attributeOldValue: true, attributeFilter: ['style'] },
);
Im Searching how to customize the player for live use with dash.js,
as browser player not work wel with live session i trying to delete seekbar and time indicators for now, in the future i will search for a seekbar that can manage live buffer.
But I can't find the correct attribute to set seekBar: false and every time indicator off,
I find this list https://docs.videojs.com/tutorial-components.html but the components seems to not work.
Which are the correct attribute to exclude that controls? Or maybe is a syntax problem?
http://jsbin.com/aheVeCOG/2/edit?js,output
Volume control to false work:
var video = videojs('my_video_1', {
children: {
controlBar: {
children: {
volumeControl: false
}
}
}
});
My try don't work
var video = videojs('my_video_1', {
children: {
controlBar: {
children: {
ProgressControl: false
}
}
}
});
Thanks!
Massimo
Just need to fix typo it works, use lowserCase at first character instead:
progressControl instead of ProgressControl
var video = videojs('my_video_1', {
children: {
controlBar: {
children: {
progressControl: false
}
}
}
});
Working example:
http://jsbin.com/damahev/2/edit?html,js,output
I was instructed to use the CSS side to show/hide any undesirable values.
So, I've been using the top four lines in style defn below for mine:
<style>
.video-js .vjs-current-time { display: block; }
.video-js .vjs-time-divider { display: block; }
.video-js .vjs-duration { display: block; }
.video-js .vjs-remaining-time { display: none; }
#.video-js .vjs-mute-control { display: none; }
#.video-js .vjs-volume-menu-button { display: none; }
#.video-js .vjs-volume-bar { display: none; }
#.video-js .vjs-progress-control { display: none; }
</style>
The bottom-four lines (after removing leading '#' char) should work for you.
(Note that you can peruse the linked file 'video-js.css' for current defns.
This worked for me:
this.video = videojs('some-id', {
bigPlayButton: true,
controlBar: {
fullscreenToggle: false,
pictureInPictureToggle: false,
remainingTimeDisplay: false,
volumePanel: false,
currentTimeDisplay: true,
timeDivider: true,
durationDisplay: true
}
})
To make currentTimeDisplay, timeDivider and durationDisplay to work you also need to add this CSS:
.vjs-current-time {
display: inline-block !important;
}
.vjs-time-divider {
display: inline-block !important;
}
.vjs-duration {
display: inline-block !important;
}
this code works just fine, but the second input field does not show images appearing with the text suggestions. I would appreciate if someone could take a look and let me know what needs to be changed in the js for it to work.
Example queries: clinton, bush
you can see the script here http://predcast.com/include/autoc/jqui/test2.php
<!DOCTYPE html>
<html>
<head>
<title>jQuery UI Autocomplete: Custom HTML in Dropdown</title>
<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/smoothness/jquery-ui.min.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"> </script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
<style>
.loading {
display: none;
width: 16px;
height: 16px;
background-image: url(/img/loading.gif);
vertical-align: text-bottom;
}
#autocomplete.ui-autocomplete-loading ~ .loading {
display: inline-block;
}
.ui-menu-item {
padding:1px;
margin:1px;
}
.ac-m {
height:block;
overflow:auto;
padding:2px 2px 2px 2px;
}
.ac-img {
max-width:30px;
float:left;
margin:2px 2px 2px 2px;
}
.ac-title {
margin:1px;
font-size:14px;
}
.ui-autocomplete {
margin:1px;
}
</style>
</head>
<body>
<form action="http://www.test.com/">
<input class="autocomplete" type="text" placeholder="Option 1" name="e1">
<input class="autocomplete" type="text" placeholder="Option 2" name="e2">
<span class="loading"></span>
</form>
<script>
/*
* jQuery UI Autocomplete: Custom HTML in Dropdown
* http://salman-w.blogspot.com/2013/12/jquery-ui-autocomplete-examples.html
*/
$(function () {
$('.autocomplete').autocomplete({
delay: 500,
minLength: 3,
source: function (request, response) {
$.getJSON("http://predcast.com/include/autoc/jqui/jsond.php", {
q: request.term,
}, function (data) {
var array = data.error ? [] : $.map(data.movies, function (m) {
return {
label: m.title,
year: m.year,
img: m.img,
};
});
response(array);
});
},
focus: function (event, ui) {
event.preventDefault();
},
}).data("ui-autocomplete")._renderItem = function (ul, item) {
var $a = $("<div class='ac-m'></div>");
if (item.img) {
$("<span></span>").addClass(item.icon).appendTo($a).append("<img src='" + item.img + "' border='0' class='ac-img' />");
}
$("<span class='ac-title'></span>").text(item.label).appendTo($a);
return $("<li></li>").append($a).appendTo(ul);
};
});
</script>
</body>
</html>
The problem is related to the way you are defining the _renderItem extension point.
In your code, you are redefining the jquery-ui autocomplete _renderItem function only for your first widget instance, so the _renderItem for your second autocomplete instance is the default one defined in the jquery-ui code.
You are initializating the autocomplete for your 2 inputs with this $('.autocomplete').autocomplete({ ...}) then you get the first widget instance with this instruction .data("ui-autocomplete") and then redefine the _renderItem function for this instance only.
You can define it for all your instances like this:
// Create your widget instances
$('.autocomplete').autocomplete({
delay: 500,
minLength: 3,
source: function (request, response) {
$.getJSON("http://predcast.com/include/autoc/jqui/jsond.php", {
q: request.term,
}, function (data) {
var array = data.error ? [] : $.map(data.movies, function (m) {
return {
label: m.title,
year: m.year,
img: m.img,
};
});
response(array);
});
},
focus: function (event, ui) {
event.preventDefault();
}
});
// Then redefine the _renderItem for each instance
$('.autocomplete').each(function() {
$(this).data('ui-autocomplete')._renderItem = function (ul, item) {
var $a = $("<div class='ac-m'></div>");
if (item.img) {
$("<span></span>").addClass(item.icon).appendTo($a).append("<img src='" + item.img + "' border='0' class='ac-img' />");
}
$("<span class='ac-title'></span>").text(item.label).appendTo($a);
return $("<li></li>").append($a).appendTo(ul);
};
});