accessing pseudo-element property values through getComputedStyle in dart - 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);
});
}

Related

Printing using ngx-extended-pdf-viewer on iOS and Mobile Safari or Chrome

I have an Angular 7 app that is using ngx-extended-pdf-viewer to render a PDF that I get as a byte array from the web.api. I have no issues rendering the PDF or even printing it from any desktop application. ngx-extended-pdf-viewer as a print button built right in. However, when trying to print from Safari on an iPhone (iOS 12) it only prints a blank page with the url at the bottom. The actual PDF does not print. With Chrome on iOS it doesn't do anything that I can see. I am pretty new to Angular and actually to mobile web development, so perhaps lack of knowledge is getting me. The PDF viewer is in a mat-tab, so not sure if maybe that is causing some issues??
I have tried other packages, but they all seem to be based on the same pdf.js code from Mozilla. Also this is the only one I've found so far that has a print. I was thinking about perhaps trying pdf.js outside of an npm package, but so far have not found solid directions on getting this to work in Angular. I'm sure it will, but all directions I have found seem to omit details. Such as, put this code in your app. They just fail to say where in the app.
From the web.api:
[HttpPost("GetPdfBytes/{PdfId}")]
public ActionResult<byte[]> GetPdfBytesId([FromBody]int id)
{
string exactPath = string.Empty;
if (id == 1)
{
exactPath = Path.GetFullPath("pdf-test.pdf");
}
else if (id == 2)
{
exactPath = Path.GetFullPath("DPP.pdf");
}
else if (id == 3)
{
exactPath = Path.GetFullPath("Request.pdf");
}
else
{
exactPath = Path.GetFullPath("Emergency Issue.pdf");
}
byte[] bytes = System.IO.File.ReadAllBytes(exactPath);
return Ok(bytes);
}
The HTML:
<mat-tab label="PDF">
<ng-template matTabContent>
<ngx-extended-pdf-viewer *ngIf="visible[2]" id="pdf3" [src]="pdfSrc3" useBrowserLocale="true" delayFirstView="1000" showSidebarButton="false"
showOpenFileButton="false" >
</ngx-extended-pdf-viewer>
</ng-template>
</mat-tab>
TypeScript:
getPDFBytesId(id: string) {
this.getPDFFromServicePdfBytesId(Number(id)).subscribe(
(data: any) => {
this.pdfSrc3 = this.convertDataURIToBinary(data);
},
error => {
console.log(error);
}
);
}
// hits the web.api
getPDFFromServicePdfBytesId(id: number): Observable<any> {
const body = id;
return this.http.post<any>('http://localhost:5000/api/values/GetPdfBytes/' + id, body);
}
// converts what we got back to a Uint8Array which is used by the viewer
convertDataURIToBinary(dataURI: string) {
const raw = window.atob(dataURI);
const rawLength = raw.length;
const array = new Uint8Array(new ArrayBuffer(rawLength));
for (let i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}

Dart Polymer bind property

I want to switch pages using neon-animated-pages
So my code is simple:
<dom-module id="auth-view">
<template>
<style>
</style>
<neon-animated-pages class="neon-container" selected="[[selected]]">
<login-page></login-page>
<pwd-reset-page></pwd-reset-page>
</neon-animated-pages>
</template>
</dom-module>
And in dart code:
#property
int selected = 0;
StreamSubscription _clickSubscription;
attached() {
_clickSubscription = this.on['showPwdReset'].listen((e) {
e = convertToDart(e);
// Read things from `e`.
print("Got show Event!");
selected = 1;
});
}
So, I catch the event - I can see that in console. But page does not change.
I still can change it manually with adding selected in shadow-dom.
What's the problem?
The pageitems should be wrapped with <neon-animatable>
like:
<neon-animatable><login-page></login-page></neon-animatable>
<neon-animatable><pwd-reset-page></pwd-reset-page></neon-animatable>
For more info https://www.webcomponents.org/element/PolymerElements/neon-animation/neon-animatable

Hide selected items in select2

I'm trying to use select2 jQuery plugin to enhance a select element in HTML app. The select allow to choose multiple items.
I'll like to remove the items that are currently selected from the dropdown. I didn't find explicit solution in the docs.
The current solution I've found was to use templateResult option and have the template function return null if the item is selected. This cause Results.prototype.template function to set container.style.display = 'none' but this has the side-effect of causing the keyboard to still select those items even though they are not visible.
Just apply this CSS.
.select2-results__option[aria-selected=true] { display: none;}
Small Update for recent versions :
.select2-results__option--selected { display: none;}
Source
Check out the answer provided here, provided by Hakam Fostok.
I've reproduced his answer below here for completeness:
my solution was modified the select2.js (the core, version 4.0.3) in the line #3158. Add the following verification :
if ($option[0].selected == true) {
return;
}
With this verification, we can exclude from the dropdown list, the selected ones. And if you write the name of a selected option, appear the text of option "noResult" .
Here the complete code:
SelectAdapter.prototype.query = function (params, callback) {
var data = [];
var self = this;`
var $options = this.$element.children();`
$options.each(function () {
var $option = $(this);
if (!$option.is('option') && !$option.is('optgroup') ) {
return;
}
if ($option[0].selected == true) {
return;
}
var option = self.item($option);
var matches = self.matches(params, option);
if (matches !== null) {
data.push(matches);
}
});
callback({
results: data
});
};
For my purposes, I was using the select2.js file, so I made the change at line 3195.
For versions 4 and 4.1
.select2-container--default .select2-results__option[aria-selected=true] {
display: none !important;
}
Works fine!
In addition to #Satheez answer, this script will let you maintain the placeholder after hiding all the selected items.
$('.selector').select2().on("change", function (e) {
$('.select2-search__field').attr('placeholder', 'Here is your placeholder');
});

Rails 4 and Foundation 5 - Sticky Footer?

So I was using static pages until I decided to migrate over to Rails for use in my web app.
I was able to effectively create a sticky footer with the following codePen:
http://codepen.io/aetles/pen/jAdzw
$(function(){ $(document).foundation(); });
window.onload = function() {
stickyFooter();
};
function checkForDOMChange() {
stickyFooter();
}
//check for resize event if not IE 9 or greater
window.onresize = function() {
stickyFooter();
}
//lets get the marginTop for the <footer>
function getCSS(element, property) {
var elem = document.getElementsByTagName(element)[0];
var css = null;
if (elem.currentStyle) {
css = elem.currentStyle[property];
} else if (window.getComputedStyle) {
css = document.defaultView.getComputedStyle(elem, null).
getPropertyValue(property);
}
return css;
}
function stickyFooter() {
console.log("sticky footer is firing");
if (document.getElementsByTagName("footer")[0].getAttribute("style") != null) {
document.getElementsByTagName("footer")[0].removeAttribute("style");
}
if (window.innerHeight != document.body.offsetHeight) {
var offset = window.innerHeight - document.body.offsetHeight;
var current = getCSS("footer", "margin-top");
if (isNaN(current) == true) {
document.getElementsByTagName("footer")[0].setAttribute("style","margin-top:0px;");
current = 0;
} else {
current = parseInt(current);
}
if (current+offset > parseInt(getCSS("footer", "margin-top"))) {
document.getElementsByTagName("footer")[0].setAttribute("style","margin-top:"+(current+offset)+"px;");
}
}
}
However, when I deploy it into a real-time application utilizing Rails, the event itself is getting fired (I tested with console.log messages) but it doesn't actually edit the position of the footer.
(view console in the following page)
https://still-plains-7660.herokuapp.com/
Because I'm using a partial for the footer itself, could it be that Rails doesn't know what to actually move? The source code on the rendered page looks as it should.
Is there a more elegant gem or solution I can utilize to have a sticky footer that does not have a fixed height? (I need it responsive).
Considering it works fine on a static page, I'm sure there is something I can just tweak but I can't seem to figure out why it won't stick in a Rails deployment.
I cannot remember what exactly I did when I created sticky footer using Foundation. But I think I found some solution for you.
https://github.com/coreysyms/foundationStickyFooter
http://foundation.zurb.com/forum/posts/629-sticky-footer

Unable to target ID after navigating back to first page from second page in jQuery Mobile Single Page Model

I am just beginning with jquery mobile but have experience in jquery and javascript and I seem to be experiencing difficulties with things being refreshed, not loaded, or loaded in the DOM.
Basically I have a 2 page document that have binded tap and change events to each. On both page 1 and page 2 a tap event calls the same function which is already loaded in the head of the document. I am not having issues with the function not being called yet my issue lies within the function and it appears to relate to the loaded DOM.
Here is the function:
function changeStatus(e) {
fstatus=$("#"+e).prop('title');
sID=$("#"+e).attr('rel');
if (fstatus == 'Pass') {
fstatus = 'Fail';
$("#studentColor_"+sID).css("background-color","#FCD1C5").css("border-color","#900");
$("#studentList"+sID+"_link").css("background-color","#FCD1C5");
} else if (fstatus == '') {
fstatus = 'Pass';
$("#studentColor_"+sID).css("background-color","#C5FCC5").css("border-color","#248703");
$("#studentList"+sID+"_link").css("background-color","#C5FCC5");
} else if (fstatus == 'Fail') {
fstatus = '';
$("#studentColor_"+sID).css("background-color","#FFF").css("border-color","#FFF");
$("#studentList"+sID+"_link").css("background-color","#FFF");
}
$("#studentList"+sID+"_link").prop("title",fstatus);
$("#studentColor_"+sID).prop("title",fstatus);
}
Upon entering page 1 for the first time the tap event fires as normal and all the css styles are changed correctly. Moving to page 2 the event fires however none of the css styles work, yet it sets the title correctly. Move back to page 1 and now it behaves as it did on page 2.
So from what I understand.. on initial page load of 1, page 2 is not in the DOM so $("#studentList"+sID+"_link") does not exist yet the function works completely fine. Upon moving to page 2 $("#studentList"+sID+"_link") does exist and is visible, and $("#studentColor_"+sID) which was loaded in page 1 is still in the DOM. (this is not a single page app)
Is this correct?
If the error is occurring because one of those elements don't exist anymore then wouldn't it make sense that the function would not work correctly even on the initial page load of page 1? (since the element on page 2 hasn't ever been loaded)
Also it works completely fine on a browser yet when put on mobile is when the styles stop working.
It seems that the only thing that is messing up in the function is the css() call. I hope my explanation makes sense as it baffles me..
Thanks for any help.
Additional info as requested:
It is 2 HTML documents. Both generated with a bit of php.
Here is how the elements are generated on page 1: (of course I cut out the sql calls etc)
while($row = mysql_fetch_array($result))
{
if ($row['passFail'] == '') {
$completionStatus='';
} else if ($row['passFail'] == 'P') {
$completionStatus='Pass';
} else if ($row['passFail'] == 'F') {
$completionStatus='Fail';
}
if ($completionStatus=='Pass') {
$bordercolor="#248703";
$backgroundcolor='#C5FCC5';
} else if ($completionStatus=='Fail') {
$bordercolor="#900";
$backgroundcolor='#FCD1C5';
} else if ($completionStatus == '') {
$bordercolor="#CCC";
$backgroundcolor='#FFF';
}
echo '<div class="draggable" style="text-align:center; width:50px; position:relative; font-size:.7em; top:'.$row['studentY'].'px; left:'.$row['studentX'].'px;" title="'.$completionStatus.'" rel="'.$row['ID'].'" id="student_'.$row['ID'].'"><div class="round shadow draggable_student" id="studentColor_'.$row['ID'].'" style="position: relative; background-color:'.$backgroundcolor.'; border:1px solid '.$bordercolor.'; margin-left:auto; margin-right:auto; margin-bottom:3px; width:40px; height:35px; padding:0px; font-weight:bold; text-align:center; padding-top:5px; vertical-align:middle; cursor:pointer;" title="'.$completionStatus.'"></div>'.$row[$_SESSION['student_identifier']].'</div>';
}
Here is how they are loaded into page 2:
while($row = mysql_fetch_array($result))
{
if ($row['passFail'] == '') {
$completionStatus='';
} else if ($row['passFail'] == 'P') {
$completionStatus='Pass';
} else if ($row['passFail'] == 'F') {
$completionStatus='Fail';
}
if ($completionStatus=='Pass') {
$bordercolor="#248703";
$backgroundcolor='background-color:#C5FCC5;';
} else if ($completionStatus=='Fail') {
$bordercolor="#900";
$backgroundcolor='background-color:#FCD1C5;';
} else if ($completionStatus == '') {
$bordercolor="#CCC";
$backgroundcolor='background-color:#FFF;';
}
if ($completionStatus == '') {
$readonly=' readonly';
} else {
$readonly='';
}
if ($row['asID']=='') {
$cc++;
$row['asID']=time()+$cc;
}
echo '<li><table cellpadding="0" cellspacing="0" width="100%"><tr><td class="student_infoLink" id="student'.$row['ID'].'_td" title="'.$completionStatus.'" rel="'.$row['ID'].'">'.$row['student_firstName'].' '.$row['student_lastName'].'</td><td align="right" width="10%"><input type="text" placeholder="Score" rel="'.$row['asID'].'" id="student'.$row['ID'].'_score" value="'.$row['score'].'" class="updateOnChange"'.$readonly.'><div style="padding:13px; text-align:center; display:none;"><img src="preloader.gif" width="56" height="21" border="0" /></div></td></tr></table>Edit Student</li>';
}
Please disregard all the inline styles as most will be removed once I get this fixed up.
Listeners being bound:
$(document).on('pageinit', function () {
$(function () {
function tapHandler(event) {
changeStatus($(this).attr("id"));
}
$(".student_infoLink").unbind("tap");
$(".draggable").unbind("tap");
$(".draggable").bind("tap", tapHandler);
$(".student_infoLink").bind("tap", tapHandler);
});
});
Workaround:
I am able to work around this issue with the following... by removing the call to the ID and searching off class. See below. I still would be appreciative of any help as to why the ID calls would not work. Much thanks to Omar for the help!
function changeStatus(e) {
fstatus=$(e).prop('title');
sID=$(e).attr('rel');
if (fstatus == 'Pass') {
fstatus = 'Fail';
$(e).find(".draggable_student").css("background-color","#FCD1C5").css("border-color","#900");
$("#studentList"+sID+"_link").css("background-color","#FCD1C5");
} else if (fstatus == '') {
fstatus = 'Pass';
$(e).find(".draggable_student").css("background-color","#C5FCC5").css("border-color","#248703");
$("#studentList"+sID+"_link").css("background-color","#C5FCC5");
} else if (fstatus == 'Fail') {
fstatus = '';
$(e).find(".draggable_student").css("background-color","#FFF").css("border-color","#FFF");
$("#studentList"+sID+"_link").css("background-color","#FFF");
}
$("#student"+sID+"_td").prop("title",fstatus);
$(e).prop("title",fstatus);
}
$(document).on('pageinit', function(e) {
console.log("pageinit is fired");
var pagecreated = e.target;
function tapHandler( event ){
changeStatus($(this));
}
$(".student_infoLink", pagecreated).unbind("tap");
$(".draggable", pagecreated).unbind("tap");
$(".draggable", pagecreated).bind("tap", tapHandler);
$(".student_infoLink", pagecreated).bind("tap", tapHandler);
});
I assume now that this works that the calling the ID was the issue... Any reasons why?
Quick, short answer... use classes instead of id when targeting an element. With the DOM loading multiple pages, selecting on an ID can get a bit whacky. See workaround above in edited post.

Resources