How do a add prefers-color-scheme media query - color-scheme

Hello I have this code:
<script>
function storageAvailable(type) {
try {
var storage = window[type],
x = '__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);
return true;
}
catch(e) {
return e instanceof DOMException && (
// everything except Firefox
e.code === 22 ||
// Firefox
e.code === 1014 ||
// test name field too, because code might not be present
// everything except Firefox
e.name === 'QuotaExceededError' ||
// Firefox
e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
// acknowledge QuotaExceededError only if there's something already stored
storage.length !== 0;
}
}
jQuery(document).ready(function($) {
var storageAvailable = window.storageAvailable('sessionStorage');
$(".et-dark-toggle").click(function() {
$(".et-dark-mode-capable,body").toggleClass("et-dark-mode");
if ( storageAvailable ) {
$("body").hasClass("et-dark-mode") ?
sessionStorage.setItem('etDarkModeEnabled','1'):
sessionStorage.removeItem('etDarkModeEnabled');
}
});
if (storageAvailable) {
'1' == sessionStorage.getItem('etDarkModeEnabled') ?
$(".et-dark-mode-capable,body").addClass("et-dark-mode"):
$(".et-dark-mode-capable,body").removeClass("et-dark-mode");
}
});
</script>
How can i add prefers-color-scheme media query to autoenable the created dark mode when user has dark mode enabled in browser ?
Can you please help me

Sorry for the late response. A quick code to integrate (p.s. not tested):
jQuery(document).ready(function($) {
var storageAvailable = window.storageAvailable('sessionStorage');
if(window.matchMedia)
{
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event =>
{
if (event.matches && !$("body").hasClass("et-dark-mode"))
{
$(".et-dark-mode-capable,body").addClass("et-dark-mode");
if ( storageAvailable )
{
sessionStorage.setItem('etDarkModeEnabled','1'):
}
}
else
{
$(".et-dark-mode-capable,body").removeClass("et-dark-mode");
if ( storageAvailable )
{
sessionStorage.removeItem('etDarkModeEnabled');
}
}
}
);
}
$(".et-dark-toggle").click(function() {
$(".et-dark-mode-capable,body").toggleClass("et-dark-mode");
if ( storageAvailable ) {
$("body").hasClass("et-dark-mode") ?
sessionStorage.setItem('etDarkModeEnabled','1'):
sessionStorage.removeItem('etDarkModeEnabled');
}
});
if (storageAvailable) {
'1' == sessionStorage.getItem('etDarkModeEnabled') ?
$(".et-dark-mode-capable,body").addClass("et-dark-mode"):
$(".et-dark-mode-capable,body").removeClass("et-dark-mode");
}
});
In short it checks if the browser supports window.matchMedia and then it reads it and sets the theme based on that preference. In the end it is the same as your code to allow the user to toggle the dark and light mode (maybe a button, or a checkbox).
For more info you can search some dev blogs on the subject and after a quick search I would say that this one might closely match your needs (p.s. not my blog :) )

Related

Modern 7.0 ComboBox fires 'select' event on every value change

The combobox in modern fires the "select" event every time the input changes. This is very different from classic. With it doing this there is no way to differentiate between a user making a selection and pragmatically setting the value of the field.
This was reported as a bug in the Sencha forums:
https://www.sencha.com/forum/showthread.php?468730-Modern-6-5-2-ComboBox-fires-select-event-on-every-value-change
The link above also contains a fiddler to demonstrate the issue.
Has anyone run into this as an issue, and how did you overcome it?
forceSelection: true will help to solve this problem but will not cancel the bug in cases when forced selection is not needed
Edit:
This behavior is due to method syncValue (search in this source - method is private and hasn't documentation)
I don’t understand why the component developer chose to create a record even if it isn’t exist.
Comment from source file:
Either user has typed something (isInput), or we've had a setValue to a value which has no match in the store, and we are not forceSelection: true. We create a new record.
I propose to fix this behavior using the following override:
fiddle
Ext.define('Ext.field.SelectOverride', {
override: 'Ext.field.Select',
autoCreateRecord: false,
syncValue: function() {
var me = this,
store = me.getStore(),
forceSelection = me.getForceSelection(),
valueNotFoundText = me.getValueNotFoundText(),
is, isCleared, isInput, value, matchedRecord;
if (me.reconcilingValue || !store || !store.isLoaded() || store.hasPendingLoad()) {
return;
}
me.reconcilingValue = true;
me.getSelection(); // make sure selection config is flushed
is = {};
is[me.syncMode] = true;
value = ((isInput = is.input || is.filter)) ? me.getInputValue() : me.getValue();
isCleared = value == null || value === '';
if (!isCleared) {
if (me.getMultiSelect()) {
return me.syncMultiValues(Ext.Array.from(value));
}
matchedRecord = (isInput ? store.byText : store.byValue).get(value);
if (matchedRecord) {
if (!matchedRecord.isEntity) {
matchedRecord = matchedRecord[0];
}
}
else if (!forceSelection) {
matchedRecord = me.findRecordByValue(value);
}
}
// Either user has typed something (isInput), or we've had a setValue
// to a value which has no match in the store, and we are not forceSelection: true.
// We create a new record.
if (!isCleared && !matchedRecord && !forceSelection && me.autoCreateRecord) {
matchedRecord = me.createEnteredRecord(value);
}
else {
if (isInput || is.store) {
if (!matchedRecord && forceSelection) {
me.setValue(null);
me.setSelection(null);
if (!is.filter) {
me.setFieldDisplay();
}
}
} else {
if (isCleared) {
if (me.mustAutoSelect()) {
matchedRecord = store.first();
if (me.getAutoSelect() === 'initial') {
me.setAutoSelect(false);
}
}
else {
me.setSelection(null);
}
}
else if (!matchedRecord && valueNotFoundText) {
me.setError(valueNotFoundText);
}
}
}
if (matchedRecord) {
me.setSelection(matchedRecord);
}
me.reconcilingValue = false;
}
});

Can I render warning message if user's browser is not supported?

I am working on a react application and customers want it to show a special message if user's old browser does not support (e.g. IE 9).
So long I tried to detect some "popular" old browsers, using react-device-detect package.
src/index.js
import { browserName, browserVersion } from "react-device-detect";
const render = Component => {
if (browserName === "IE" && browserVersion < 10) {
ReactDOM.render(<UnsupportedBrowser />, document.getElementById("root"));
} else {
ReactDOM.render(
<AppContainer>
<Component store={store} history={history} />
</AppContainer>,
document.getElementById("root")
);
}
};
And putting conditional comments:
public/index.html
<!--[if lte IE 9]>
Please upgrade your browser
<![endif]-->
But I have a suspicion, that there are better ways of doing it, which I could not find searching the web.
I found a lot of JS scripts to detect user's browser name and version, so I had to mix them to get exactly what I want
public/index.html
<script type="text/javascript">
function get_browser() {
var ua = navigator.userAgent, tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if (/trident/i.test(M[1])) {
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return { name: 'IE', version: (tem[1] || '') };
}
if (M[1] === 'Chrome') {
tem = ua.match(/\bOPR\/(\d+)/)
if (tem != null) { return { name: 'Opera', version: tem[1] }; }
}
if (window.navigator.userAgent.indexOf("Edge") > -1) {
tem = ua.match(/\Edge\/(\d+)/)
if (tem != null) { return { name: 'Edge', version: tem[1] }; }
}
M = M[2] ? [M[1], M[2]] : [navigator.appName, navigator.appVersion, '-?'];
if ((tem = ua.match(/version\/(\d+)/i)) != null) { M.splice(1, 1, tem[1]); }
return {
name: M[0],
version: +M[1]
};
}
var browser = get_browser()
var isSupported = isSupported(browser);
function isSupported(browser) {
var supported = false;
if (browser.name === "Chrome" && browser.version >= 48) {
supported = true;
} else if ((browser.name === "MSIE" || browser.name === "IE") && browser.version >= 10) {
supported = true;
} else if (browser.name === "Edge") {
supported = true;
}
return supported;
}
if (!isSupported) {
document.write(<h1>My message</h1>)
}
</script>
This script allows users to proceed if their browser is chrome >= 48 or ie >= 10 or any version of edge. Otherwise it shows a special message asking user to update or change his browser.
You can also customize this script to your needs, modifying isSupported() function.
I think the best and most user-friendly alternative is to redirect the user to an exclusive ie.html page, where you can show instructions about how to download other browsers and just care about all IE stuff in that page only.
This way you don't need to do anything with React, just add the lines below to your index.html:
<script type="application/javascript">
if (/MSIE|Trident/.test(window.navigator.userAgent)) window.location.href = '/ie.html';
</script>
You have detect browser package on npm that may help you
Well what you can do is, you have to check the browser version, like in my case I was dealing with the Internet Explorer Version older than 11. So detect the browser. There is no need to add an extra package, just few lines of code and then make two ReactDOm.renders, one for Success/Supported and the other for Unsupported Version.
Here is how I did it, maybe that will help you:
// get the Version of Browser, older than '11'
const getIEVersion = () => {
const ua = window.navigator.userAgent;
const msie = ua.indexOf('MSIE ');
if (msie > 0) {
// IE 10 or older => return version number
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
}
const trident = ua.indexOf('Trident/');
if (trident > 0) {
// IE 11 => return version number
const rv = ua.indexOf('rv:');
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
}
const edge = ua.indexOf('Edge/');
if (edge > 0) {
// Edge (IE 12+) => return version number
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
}
// other browser
return false;
};
// Method for Rendering of Unsupported Version
const UnsupportedBrowserPage = () => (
<div>
<p>Test Page For Versions lower then 11 on IE</p>
</div>
);
const iEVersion = getIEVersion();
if (iEVersion && iEVersion < 11) {
ReactDOM.render(<UnsupportedBrowserPage />, document.getElementById('root'));
} else {
ReactDOM.render(
<SupportedApp />, document.getElementById('root')
);
}

typescript filter array on 2 parameters

In order to filter an array on possibly 2 parameters I have written the following code:
filterStudies(searchString?: string) {
if (searchString && !this.selectedModalityType) {
this.studies = this.fullStudyList.filter(function (study) {
return (study.Code.toUpperCase().includes(searchString.toUpperCase())) ||
(study.Description.toUpperCase().includes(searchString.toUpperCase()));
})
} else if (!searchString && this.selectedModalityType) {
console.log(this.selectedModalityType)
this.studies = this.fullStudyList.filter(function (study) {
return (study.ModalityType.Code.toUpperCase() === this.selectedModalityType.toUpperCase())
})
} else if (searchString && this.selectedModalityType) {
this.studies = this.fullStudyList.filter(function (study) {
return (study.Code.toUpperCase().includes(searchString.toUpperCase())) ||
(study.Description.toUpperCase().includes(searchString.toUpperCase())) &&
(study.ModalityType.Code.toUpperCase() === this.selectedModalityType.toUpperCase())
})
}
}
filterStudies(searchString?: string) is called when typing in a textbox that.
The other way of filtering could be by selecting a value from a dropdown box. Achieved by this code:
handleSelection(value:any){
this.selectedModalityType = value;
console.log(value)
this.filterStudies()
}
All works fine until this code is hit:
this.studies = this.fullStudyList.filter(function (study) {
return (study.ModalityType.Code.toUpperCase() === this.selectedModalityType.toUpperCase())
})
Error message : ERROR TypeError: Cannot read property 'selectedModalityType' of undefined, I see it is actually logged in the line before.
What am I missing??
Thanks,
In your funtcion, this is not the same this as the line before.
This will work:
let self = this;
this.studies = this.fullStudyList.filter(function (study) {
return (study.ModalityType.Code.toUpperCase() === self.selectedModalityType.toUpperCase())
})
You can read this to learn more: https://github.com/Microsoft/TypeScript/wiki/%27this%27-in-TypeScript
The this keyword in JavaScript (and thus TypeScript) behaves differently than it does in many other languages. This can be very surprising, especially for users of other languages that have certain intuitions about how this should work.
(...)
Typical symptoms of a lost this context include:
A class field (this.foo) is undefined when some other value was expected

Audio Tracks are not playing when phone is on vibrate/silent

I'm using ngAudio to control audio tracks (spotify 30 seconds previews) on an ionic app. It all works swell in the browser. However, in both ionic view and the actual demo app, the tracks will only stream when I have the phone vibrate toggle turned to not silent/ring mode. If it's in vibrate mode, the user hears nothing. I've dug all over and can't seem to solve this riddle.
Here's my service:
.factory('PlayerService', function(ngAudio) {
var _play = function(show) {
if (typeof audioObject === "undefined") {
audioObject = ngAudio.load(show.track1_preview);
console.log(audioObject);
audioObject.play();
audioObject.playing = show.id;
return audioObject;
} else if (audioObject.paused) {
audioObject = ngAudio.load(show.track1_preview);
audioObject.play();
audioObject.playing = show.id;
return audioObject;
} else {
audioObject.stop();
audioObject = ngAudio.load(show.track1_preview);
audioObject.play();
audioObject.playing = show.id;
return audioObject;
}
}
var _pause = function(show) {
audioObject.stop();
audioObject.playing = '';
}
return {
play: _play,
pause: _pause
};
Here's the controller:
$scope.playStream = function(show) {
PlayerService.play(show);
$scope.audioObject = audioObject; // this allow for styling the play/pause icons
}
$scope.pauseStream = function(show) {
PlayerService.pause(show);
$scope.audioObject = audioObject; // this allow for styling the play/pause icons
//console.log($scope.audioObject);
}
$scope.togglePlayPause = function(show) {
if (!$scope.audioObject || $scope.audioObject.paused) {
$scope.playStream(show);
} else if (show.track1_preview !== $scope.audioObject.id) {
$scope.playStream(show);
} else {
$scope.pauseStream(show);
}
}
Obviously, it's a bit of a crap user experience if someone has to put the phone off vibrate to hear the tracks.
I'm wondering if this is related to asyncronous stuff and mobile. I just don't know. Giving up after 4 hours of messing with it.

Remove aggregation menu items from angularjs ui-grid menu

The ui-grid example on the official website ( http://ui-grid.info/docs/#/tutorial/209_grouping ) presents a grouping feature, which looks like this:
I would like to have the Grouping menu item, but not have the Aggregate ones (count, sum, max, min, avg) in the column menu and I couldn't find a way around removing them.
A solution I've tried was overriding the uiGridGroupingService, by providing a decorator for the groupingColumnBuilder, but the service is not resolved at all and I can't help but wonder if there is a simpler way of achieving this.
Is anyone aware of any solution for this problem?
It's set to true by default so you need to specify it in your columnDefs
groupingShowAggregationMenu: false
There is a suppress aggregation option! Set groupingShowAggregationMenu to false.
The decorator approach is probably the best approach in this case. There are no config option to remove this from the column menu.
PS: The decorator is only shown to remove the aggregate items.
Here is a working plnkr with the decorator approach.
http://plnkr.co/edit/nzBeqbmEVUwmZF0qgyd6?p=preview
app.config(function($provide){
$provide.decorator('uiGridGroupingService', function ($delegate,i18nService,gridUtil) {
$delegate.groupingColumnBuilder = function (colDef, col, gridOptions) {
if (colDef.enableGrouping === false){
return;
}
if ( typeof(col.grouping) === 'undefined' && typeof(colDef.grouping) !== 'undefined') {
col.grouping = angular.copy(colDef.grouping);
} else if (typeof(col.grouping) === 'undefined'){
col.grouping = {};
}
if (typeof(col.grouping) !== 'undefined' && typeof(col.grouping.groupPriority) !== undefined && col.grouping.groupPriority >= 0){
col.suppressRemoveSort = true;
}
col.groupingSuppressAggregationText = colDef.groupingSuppressAggregationText === true;
var groupColumn = {
name: 'ui.grid.grouping.group',
title: i18nService.get().grouping.group,
icon: 'ui-grid-icon-indent-right',
shown: function () {
return typeof(this.context.col.grouping) === 'undefined' ||
typeof(this.context.col.grouping.groupPriority) === 'undefined' ||
this.context.col.grouping.groupPriority < 0;
},
action: function () {
service.groupColumn( this.context.col.grid, this.context.col );
}
};
var ungroupColumn = {
name: 'ui.grid.grouping.ungroup',
title: i18nService.get().grouping.ungroup,
icon: 'ui-grid-icon-indent-left',
shown: function () {
return typeof(this.context.col.grouping) !== 'undefined' &&
typeof(this.context.col.grouping.groupPriority) !== 'undefined' &&
this.context.col.grouping.groupPriority >= 0;
},
action: function () {
service.ungroupColumn( this.context.col.grid, this.context.col );
}
};
if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.grouping.group')) {
col.menuItems.push(groupColumn);
}
if (!gridUtil.arrayContainsObjectWithProperty(col.menuItems, 'name', 'ui.grid.grouping.ungroup')) {
col.menuItems.push(ungroupColumn);
}
}
return $delegate;
})
});

Resources