Basically I have an angular project that is based on bootstrap 3 for media queries resize.
What I intend to do is allow user to change between desktop mode (laptop full screen width) or mobile mode (media width < 667px).
I have see a lot of theme preview sites have this feature. As it is quite a common feature, I expect that it can be done this way but not sure how it could be implemented exactly.
Note: I am not expecting to change any part of existing CSS.
My opinion on how to implement this.
<html ng-viewport="deviceWidth">
<button ng-click="changeDeviceWidth()">
</html>
// initial
$scope.deviceWidth = getDeviceWidthFunction();
$scope.changeDeviceWidth = function (deviceWidth) {
$scope.deviceWidth = deviceWidth;
}
First: Give id to you viewport meta
<meta id="viewport" name="viewport" content="width=device-width, initial-scale=1">
Second: Create selector buttons
<div id="selecter">
<button onclick="toDesktop()"> Desktop</button>
<button onclick="toTablet()"> Tablet</button>
<button onclick="toMobile()"> Mobile</button>
</div>
Third: Add iframe as content viewer
<iframe id="mycontent" src="http://www.majali.net"></iframe>
Fourth: Add JS functions to set viewport,content width and height
<script>
function toDesktop() {
document.getElementById("viewport").setAttribute("content", "width=1200");
document.getElementById("mycontent").style.width='100%';
document.getElementById("mycontent").style.height='600px';
}
function toMobile() {
document.getElementById("viewport").setAttribute("content", "width=340");
document.getElementById("mycontent").style.width='320px';
document.getElementById("mycontent").style.height='480px';
}
function toTablet() {
document.getElementById("viewport").setAttribute("content", "width=767");
document.getElementById("mycontent").style.width='767px';
document.getElementById("mycontent").style.height='600px';
}
</script>
Related
I'd like to know where I should add the <script></script> provided by Google Adsense.
They say to add it into the <head></head>, but in Gatsby you have Helmet as <head>.
I tried also to add the script inside an html.js file where it's located a <head> tag with {``} to escape the <script> tag, but it outputs at the top of the website the script content.
TL;DR: What is the optimal way to add Adsense to a website built with GatsbyJS?
I've tried to use the react adsense package but I do not understand how to use it with Gatsby.
I have tried to add the <script> tag to html.js and it doesn't compile.
If you escape it with {``} you get the script as is, on top of the website.
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
{this.props.headComponents}
{`<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>`}
{` <script>
(adsbygoogle = window.adsbygoogle || []).push({
google_ad_client: "ca-pub-1540853335472527",
enable_page_level_ads: true
});
</script>
`}
</head>
source: html.js
The website should get detected by the Google crawlers.
Thanks to an answer given on Github, finally the problem is solved:
If you want to add Adsense:
cp .cache/default-html.js src/html.js
Add the script but everything inside should be escaped -> {<some-js-code-here>}
In my situation and as an example:
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<script>
{`
(adsbygoogle = window.adsbygoogle || []).push({
google_ad_client: "ca-pub-1540853335472527",
enable_page_level_ads: true
});
`}
</script>
if you are using services like Netlify to deploy your website, you can use snippet injection functionality to make this work without touching your source code.
settings -> build & deploy -> post processing -> snippet injection -> add snippet
then you can select where you want to add the snippet (script tag). For the Adsense this should be before the </head>. hope it helps. :)
You can find here a nice tutorial on how to add Google AdSense in Gatsby.
Basically, the suggested way is to implement a Google AdSense Banner using React and including the Google AdSense code in the gatsby-ssr.js file.
gatsby-ssr.js file:
const React = require('react')
const HeadComponents = [
<script
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXX"
crossOrigin="anonymous"
async
/>,
]
exports.onRenderBody = ({ setHeadComponents }, pluginOptions) => {
setHeadComponents(HeadComponents)
}
AdSense Banner component:
const Banner: React.FC<BannerProps> = ({
className,
style,
layout,
format,
client = 'ca-pub-XXXX',
slot,
responsive,
layoutKey,
}) => {
useEffect(() => {
try {
const adsbygoogle = window.adsbygoogle || []
adsbygoogle.push({})
} catch (e) {
console.error(e)
}
}, [])
return (
<div className={clx(container, className)}>
<ins
className="adsbygoogle"
style={style}
data-ad-layout={layout}
data-ad-format={format}
data-ad-client={client}
data-ad-slot={slot}
data-ad-layout-key={layoutKey}
data-full-width-responsive={responsive}
/>
</div>
)
}
Don't use the gatsby-adsense plugin, it's deprecated.
Full article here.
To set up Adsense, place the <script> tag (without template literals {``} just before your closing </body> tag in your html.js, like this:
<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
</body>
Then, to place an ad unit, you can either use a pre-built component like react-adsense on npm, as you mentioned, or build it yourself.
This is a useful article that covers both the setup and the placing of ad units with a component.
Let me know if this works for you or if something isn't clear!
To add Google Adsence in Gatsby you need these three packages
react-adsense rehype-react gatsby-transformer-remark
and if you want to know how to implement these packages in your site then checkout this tutorial
Essentially, I would like to know the best way to toggle between two img or div on a user click. So, first the play image is visible and when user clicks, play image is hidden and pause image is shown. When user clicks pause image, pause image is hidden and play image is shown.
I tried using an ng-show but I could only figure out how to show both images without hiding the other. So, a play image would be next to the pause image, which is not ideal.
Thanks in advance :)
Code I have tried that does not work:
HTML
<button ng-click="changeStatus" ng-show="checkStatus">Play</button>
<button ng-click="changeStatusAgain" ng-hide="checkStatus">Pause</button>
Controller:
$scope.changeStatus=function(){
$scope.checkStatus = false;
}
$scope.changeStatusAgain=function(){
$scope.checkStatus = true;
}
https://jsfiddle.net/n8nnwtte/
Use the same expression for both and negate it according to your logic.
HTML
<button class="play" ng-show="!song.playing" ng-click="song.togglePlay()">
<button class="pause" ng-show="song.playing" ng-click="song.togglePlay()">
JS
var $scope.song = {
playing: false, // Set the initial state
togglePlay: function() {
$scope.song.playing = !$scope.song.playing; // This would alternate the state each time
// Do something with the song
if ($scope.song.playing) { /*..*/ } else { /*..*/ }
}
};
This assumes you have a song object defined in your scope and that it has a boolean property called playing. So if song.playing is falsy we show the play button and if it's truthy we show the pause button.
The togglePlay() method defined can then be used to alternate the state of song.playing in addition to its role of actually controlling the playback.
JavaScript Toggle (Play/Pause) Sound on Click Event of DOM Element
his post shows how to toggle (play/pause) sound by JavaScript manipulation of onclick event of a DOM element. Browser support of HTML5 audio tag is a must in this example.
https://siongui.github.io/code/javascript-sound/toggle.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript Toggle (Play/Pause) Sound on Click Event of DOM Element</title>
</head>
<body>
<button id="player" type="button"
onclick="javascript:toggleSound();">
Click to Toggle Sound
</button>
<audio id="audio">
<source src="Wat_Metta_Buddha_Qualities.mp3" type="audio/mpeg">
Your browser does not support this audio format.
</audio>
<script type="text/javascript">
function toggleSound() {
var audioElem = document.getElementById('audio');
if (audioElem.paused)
audioElem.play();
else
audioElem.pause();
}
</script>
</body>
</html>
I am using the Chrome toolbar from http://wave.webaim.org/extension/ to check the ADA compliance of my React-Bootstrap app.
When I use a Popover within an OverlayTrigger without an ID, it warns me in the console:
Warning: Failed propType: The prop 'id' is required to make 'Popover' accessible for users using assistive technologies such as screen readers
Problem is, when I add an ID to the Popover, I then get the following error on my accessibility scan:
Broken ARIA reference: An element has an aria-labelledby or aria-describedby value that does not match the id attribute value of another element in the page.
I am guessing it's happening because the element with that ID doesn't exist until the button is clicked. Am I missing something, or is this element not ADA compliant? Or, is this just a problem with the scan, and there's a better tool I should be using to prove my site is compliant?
Here is the code for an example site that demonstrates the issue. I have thrown it in a Fiddle, but it won't do you much good because if you run the accessibility tool on that, it will give you JSFiddle's errors rather than the ones for the relevant code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>React-Bootstrap Popover Accessibility</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.5/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.5/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-bootstrap/0.28.1/react-bootstrap.js"></script>
<link type="text/css" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"/>
</head>
<body>
<div id="container"></div>
<script type="text/babel">
var Button = ReactBootstrap.Button;
var OverlayTrigger = ReactBootstrap.OverlayTrigger;
var Popover = ReactBootstrap.Popover;
var Overlay = React.createClass({
render: function() {
return (
<OverlayTrigger trigger="click" placement="right" overlay={
<Popover title="Popover" id="popover-id">Here's the contents of the popover</Popover>
}>
<Button bsStyle="primary">Click to see Popover</Button>
</OverlayTrigger>
);
}
});
ReactDOM.render(
<Overlay />,
document.getElementById('container')
);
</script>
</body>
</html>
I can confirm that the code is not compliant. You can double-check whether this code validates by:
Inspecting this element in the developer console (before the button is clicked)
Copying the rendered HTML to the clipboard
Loading http://validator.nu and selecting the ‘Textfield’ option
Pasting your HTML between the <body></body>tags
Clicking ‘Validate’
As you’ll see, the code does not validate, because, as oobgam mentioned, the target ID is not initially present in the DOM.
There are a number of different approaches to fixing this. Once I understand which design pattern you’re trying to accessibly support, I can provide more concrete advice.
Can you please provide more information about why you chose this implementation? How do you see desktop and mobile users interacting with this, and to what end?
Quora has a good list of related patterns at What's the difference between a modal, a popover and a popup?
I'm trying to set a tab as active through the markup. For some reason when I set the active attribute on a tab it seems to mangle the state of the tabs. The page loads up fine and the tab that was set as active will be deactivated when clicking another tab. When I click back on the tag that was set with active="true" the previously selected tab will not be deselected.
...
<tab heading="Dynamic Title 1" active="true">Some Title 1</tab>
...
http://plnkr.co/edit/xzDbezXgkSMr6wokov6g?p=info
I switched to creating a variable that is set to true at init and plopped that into the active attribute. I'm hoping there's a better way to this though.
<tabset ng-init="startActive = true">
...
<tab heading="Dynamic Title 1" active="startActive">Some Title 1</tab>
...
</tabset>
http://plnkr.co/edit/mt5MQSZEl730fsMuMxg8
I don't want to define the tabs in js because this is a project that uses webforms and piping data from that to js might be worse than what I'm doing here. I change the page to be completely built with angular in which case piping data like the tab to be selected could be part of some config endpoint that would be hit on the controller's init. I'd rather not have to redesign a complete page to make this change but it seems like the most correct way to go. Any thoughts and tips would be appreciated.
I know this is quite old, but after wasting hours of my life, I came up with a super dirty hack, that does the trick (assuming I understood your question correctly and you have the same issue as me).
Problem Statement
Using UI Bootstrap Tabs, dynamically adding tabs based on list data and maintaining the active state outside of this data.
When using the Tabs of UI Bootstrap and generating tabs like this:
<tab ng-repeat="item in page.data.list" active="item.active">
UI Bootstrap will use the binding of the item to store the active state. If we omit the active attribute, UI Bootstrap will maintain it internally but then it becomes impossible to manipulate the active state from the outside, except for accessing it via one of these: $$ (which are the untouchables!)
Solution (The Hack)
Maintain the active state in another list:
<div ng-controller="parasample-tabs">
{{activeState}}
<tabset ng-show="page.data.list.length">
<tab ng-repeat="item in page.data.list" active="activeState[$index]">
<tab-heading>
<i style="cursor: pointer" class="glyphicon glyphicon-remove" ng-click="delTab($index)" prevent-default></i>
Item {{$index +1}}
</tab-heading>
{{item.text}} - {{item.transcript}} - {{item.active}}
</tab>
</tabset>
<!--
For me this problem arose because I like to use self-contained, self-managing data
from factories, hence I call addItem not on a controller
-->
<button ng-click="page.addItem()">Add Item</button>
</div>
Now for the controller, that is wrapped around that tabs and manages them, and their active state instead of writing it into my data:
app.controller('parasample-tabs', function ($scope) {
$scope.maxItems = 5;
$scope.activeState = [];
$scope.delTab = function (idx) {
var list = $scope.page.data.list;
if (list.length > 0) {
$scope.page.delItem(idx);
$scope.activeState.splice(idx, 1);
}
};
$scope.$watch(
"page.data.list.length",
function (newLen, oldLen) {
if (!newLen) return;
// new item => new tab, make active
if (newLen > oldLen)
$scope.activeState.push("true");
}
);
});
Now UI Bootstrap will access the array activeState and store the active state there. There is no need for initialisation, as that is taken care of.
When a new item is added to our data list, the watch will set the new tab as the active tab (thats my preference) and the rest of the list will be updated by UI Bootstrap.
When deleting however, it is not easily possible to determine which item was removed, so I had to wrap my page.delItem into the controller's delTab method.
Here is a fiddle to play with, too.
Let's hope that UI Bootstrap will allow for a different way to maintain the active state instead of having a two way binding in the active attribute. I like having an "active ID" variable.
Disclaimer: I am aware of how dirty this is and I only tested it in Chrome so far and it works nicely.
You're missing quite a few here. Here's a more extensible way:
var app = angular.module('myApp',[]);
app.controller('MyController', ['$scope',function($scope){
$scope.tab = 0;
$scope.changeTab = function(newTab){
$scope.tab = newTab;
};
$scope.isActiveTab = function(tab){
return $scope.tab === tab;
};
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE HTML>
<html ng-app="myApp">
<head>
<style type="text/css">
.active{
background-color:red;
}
</style>
</head>
<body ng-controller="MyController">
<div>
<div ng-class="{'active':isActiveTab(0)}" ng-click="changeTab(0)">Some Title 1</div>
<div ng-class="{'active':isActiveTab(1)}" ng-click="changeTab(1)">Some Title 2</div>
</div>
<br/>
<div ng-show="isActiveTab(0)">tab1</div>
<div ng-show="isActiveTab(1)">tab2</div>
<script type="text/javascript" src="js/angular-1.2.24.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
Initialization should always be in the controller.
Change the values using a controller function. Here, defined as 'changeTab()'
For checking active tabs, create a controller function to compare if the current value of $scope.tab is equal to the current tab.
I also added a bit of styling to impose which tab is active.
I'm trying to use dojo's dialog box in a page in my application but having some problems with the page in IE7 (or in IE 8 in some cases, when the page is viewed in compatibility mode).
Following is a rough skeleton structure of the page i'm trying to write.
<head>
<style type="text/css">
body, html { font-family:helvetica,arial,sans-serif; font-size:90%; }
</style>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js"
djConfig="parseOnLoad: true">
</script>
<script type="text/javascript">
dojo.require("dijit.Dialog");
var secondDlg;
dojo.addOnLoad(function() {
var foo = new dijit.Dialog({id:'testDialog', title: "test dialog", content: "test content" }, dojo.byId('dialog1Container'));
foo.startup();
var foo2 = new dijit.Dialog({id:'testDialog2', title: "test dialog 2", content: "test content 2" }, dojo.byId('dialog2Container'));
foo2.startup();
});
wrapper = function() {
dijit.byId('testDialog').show();
}
</script>
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.5/dijit/themes/claro/claro.css"
/>
</head>
<body class=" claro ">
<p>
When pressing this button the dialog will popup. Notice this time there
is no DOM node with content for the dialog:
</p>
<a onClick="wrapper();"> Show the test dialog</a>
<br />
<a onClick="dijit.byId('testDialog2').show();"> Show the test dialog</a>
<div id="dialog1Container"></div>
<div id="dialog2Container"></div>
</body>
In IE7, the page just hangs when it tries to display the dialog box from the 1st link.
Here are some symptoms of the malady ailing this page:
It breaks if there are more than 1 Dijit.dialog in the dom. If there is only 1, then it works fine
If there are more than 1 dialogs instances in the dom, only the last one works correctly. All previous ones end up freezing the browser.
The work around i'm using is to dynamically create an instance of dijit.Dialog in my js and insert it into the dom container and hitch a custom method to hide it. And when i'm hiding it i also call destroy on the dialog so it removes the dialog from the dom. This allows me to have multiple places in my page which can use the dialog, but only 1 will be displayed and be present in the dom at any point of time
And some extra info:
The html doc type i'm using is DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd
It works fine in FF, Chrome and IE 8, only breaks in IE 7
I'm using dojo 1.5 (not the one from google's site, but a copy from my server, but i cant put that in the sample code)
Anybody have any idea about dojo's dialog having problems in IE 7?
Turns out this wasn't a problem with the dijit Dialogs itself, there was an event handler (not connected to dojo at all) which was causing the error, which is why it wasn't reproducible in a standalone page.