Polymer 1.0 iron-media-query call function on query-changed - polymer-1.0

I don't really understand why the following code isn't working. I want iron-media-query to call a function when the query changes. I got it working using query-matches and template if's but that isn't what I want at all. Here is the code I have:
<iron-media-query
query="(max-width:1024px)"
query-matches="{{condensedscreen}}"
query-changed="switchToCondensed">
</iron-media-query>
I want the query-change="switchToCondensed" to be called once this query requirement is met.
The switchedToCondensed function is the following:
switchToCondensed: function(e) {
console.log("Condensed: "+this.condensedscreen);
if(this.condensedscreen === true) {
this.sectionbox = "section-boxes-condensed";
this.setScreenSize = "checkoutBodyMobile";
//this.sectionStyle = "sectionMobile";
this.shippingSectionStyle = "shippingSectionMobile";
this.allCardsStyle = "allCardsMobile";
this.submitBtnStyle = "submitBtnMobile";
this.gotocartStyle = "goToCartMobile";
}
else {
this.sectionbox = "section-boxes";
this.setScreenSize = "checkoutBody";
//this.sectionStyle = "section";
this.shippingSectionStyle = "shippingSection";
this.allCardsStyle = "allCards";
this.submitBtnStyle = "submitBtn";
this.gotocartStyle = "goToCart";
}
}
As you can see I want to use this to change around the CSS on my webpage. What exactly am I doing wrong here?

Did you try to use "on-query-matches-changed" instead of "query-changed"?
<iron-media-query
query="(max-width:1024px)"
query-matches="{{condensedscreen}}"
on-query-matches-changed="switchToCondensed">
</iron-media-query>

So I never got query-changed to work. Honestly that seems completely useless. Anyway, I got it to work by first adding the $ to my class like the following:
<div class$="[[allCardsStyle]]">
After that I removed the query-changed from iron-media-query so it looked like the following:
<iron-media-query
query="(max-width:1024px)"
query-matches="{{condensedscreen}}">
</iron-media-query>
Then back in the JS I added an observer to watch when the boolean variable changes:
condensedscreen:{observer:"switchToCondensed"}
Finally, with that watching the change I had it call my function "switchToCondensed" that actually set the variable to mobile vs not:
switchToCondensed: function() {
if(this.condensedscreen === true) {
this.allCardsStyle = "allCardsMobile";
}
else {
this.allCardsStyle = "allCards";
}
}
Then in my CSS I have two different styles that are call allCards and allCardsMobile.
Hopefully this helps someone that was struggling with this like me.

Related

Cypress while loop [duplicate]

I have 15 buttons on a page. I need to test each button.
I tried a simple for loop, like
for (var i = 1; i < 15; i++) {
cy.get("[=buttonid=" + i + "]").click()
}
But Cypress didn't like this. How would I write for loops in Cypress?
To force an arbitrary loop, I create an array with the indices I want, and then call cy.wrap
var genArr = Array.from({length:15},(v,k)=>k+1)
cy.wrap(genArr).each((index) => {
cy.get("#button-" + index).click()
})
Lodash is bundled with Cypress and methods are used with Cypress._ prefix.
For this instance, you'll be using the _.times. So your code will look something like this:
Cypress._.times(15, (k) => {
cy.get("[=buttonid=" + k + "]").click()
})
You can achieve something similar to a "for loop" by using recursion.
I just posted a solution here: How to use a while loop in cypress? The control of is NOT entering the loop when running this spec file? The way I am polling the task is correct?
Add this to your custom commands:
Cypress.Commands.add('recursionLoop', {times: 'optional'}, function (fn, times) {
if (typeof times === 'undefined') {
times = 0;
}
cy.then(() => {
const result = fn(++times);
if (result !== false) {
cy.recursionLoop(fn, times);
}
});
});
Then you can use it by creating a function that returns false when you want to stop iterating.
cy.recursionLoop(times => {
cy.wait(1000);
console.log(`Iteration: ${times}`);
console.log('Here goes your code.');
return times < 5;
});
While cy.wrap().each() will work (one of the answers given for this question), I wanted to give an alternate way that worked for me. cy.wrap().each() will work, but regular while/for loops will not work with cypress because of the async nature of cypress. Cypress doesn't wait for everything to complete in the loop before starting the loop again. You can however do recursive functions instead and that waits for everything to complete before it hits the method/function again.
Here is a simple example to explain this. You could check to see if a button is visible, if it is visible you click it, then check again to see if it is still visible, and if it is visible you click it again, but if it isn't visible it won't click it. This will repeat, the button will continue to be clicked until the button is no longer visible. Basically the method/function is called over and over until the conditional is no longer met, which accomplishes the same thing as a for/while loop, but actually works with cypress.
clickVisibleButton = () => {
cy.get( 'body' ).then( $mainContainer => {
const isVisible = $mainContainer.find( '#idOfElement' ).is( ':visible' );
if ( isVisible ) {
cy.get( '#idOfElement' ).click();
this.clickVisibleButton();
}
} );
}
Then obviously call the this.clickVisibleButton() in your test. I'm using typescript and this method is setup in a class, but you could do this as a regular function as well.
// waits 2 seconds for each attempt
refreshQuote(attempts) {
let arry = []
for (let i = 0; i < attempts; i++) { arry.push(i) }
cy.wrap(arry).each(() => {
cy.get('.quote-wrapper').then(function($quoteBlock) {
if($quoteBlock.text().includes('Here is your quote')) {
}
else {
cy.get('#refreshQuoteButton').click()
cy.wait(2000)
}
})
})
}
Try template literals using backticks:
for(let i = 0; i < 3; i++){
cy.get(`ul li:nth-child(`${i}`)).click();
}

Ace-Editor Ignore/whitelist some tag/string

Is there any way to avoid Ace-Editor to raise an error if I use some tag like <#input "asd">?? Like a whitelist to suggest AceEditor to ignore it... Anyway, It's an internal key and I cannot avoid using it.
I'm using react.
Thanks
I'm thinking of two ways to solve the issue:
1) Maybe you can bind the ">", get the last entered values and then clear the errors:
editor.commands.addCommand({
name: "dotCommand1",
bindKey: { win: ".", mac: "."},
exec: function () {
var pos = editor.selection.getCursor();
var session = editor.session;
var curLine = (session.getDocument().getLine(pos.row)).trim();
var curTokens = curLine.slice(0, pos.column).split(/\s+/);
//You can build a logic using the curTokens array and then when you find <#input "asd"> clear the errors.
// If we assume curTokens[0] to have the value
if(curTokens[0] === '<#input "asd">') {
editor.session.setAnnotations([]); // This would remove the being shown error
}
}
});
2) Use the on change event and use the above similar logic and then clear the error
editor.getSession().on('change', function () {
// same logic as above
})

Compiling string htmlusing angular compile not working having ng-repeat in it

Sorry for bad question format before. Changing this now
I have a html string which uses the ngrepeat to render the required div..
var templateHTML = "<div ng-repeat='entity in createCtrl.finalCCList'>\
<span>{{entity.name}}</span>\
</div>";
Here "createCtrl.finalCCList" has list of entity object which has name and id properties in it.
Now when I try to compile this using -
var compiledTemplateHTML = $compile(templateHTML)($scope);
if (compiledTemplateHTML && compiledTemplateHTML[0]) {
return compiledTemplateHTML[0].outerHTML;
}
else {
return "";
}
I get nothing. Whereas i checked and $scope.createCtrl.finalCCList does have the required values.
Am I missing anything here.
Ok. After lot of research I figured issue was the DOM rendered by ng-repeat inside the string html after compiles takes time and I am assigning it before it complete. If i uses the assignment in timeout it works fine.
So instead of this-
var compiledTemplateHTML = $compile(templateHTML)($scope);
if (compiledTemplateHTML && compiledTemplateHTML[0]) {
return compiledTemplateHTML[0].outerHTML;
}
else {
return "";
}
I am not returning but assigning to scope in $timeout
var compiledTemplateHTML = $compile(templateHTML)($scope);
if (compiledTemplateHTML && compiledTemplateHTML[0]) {
$timeout(function () {
createCtrl.isHeaderContent = compiledTemplateHTML[0].outerHTML;
}, 0);
}
Thanks.

Convert Quill Delta to HTML

How do I convert Deltas to pure HTML? I'm using Quill as a rich text editor, but I'm not sure how I would display the existing Deltas in a HTML context. Creating multiple Quill instances wouldn't be reasonable, but I couldn't come up with anything better yet.
I did my research, and I didn't find any way to do this.
Not very elegant, but this is how I had to do it.
function quillGetHTML(inputDelta) {
var tempCont = document.createElement("div");
(new Quill(tempCont)).setContents(inputDelta);
return tempCont.getElementsByClassName("ql-editor")[0].innerHTML;
}
Obviously this needs quill.js.
I guess you want the HTML inside it. Its fairly simple.
quill.root.innerHTML
If I've understood you correctly, there's a quill thread of discussion here, with the key information you're after.
I've quoted what should be of most value to you below:
Quill has always used Deltas as a more consistent and easier to use (no parsing)
data structure. There's no reason for Quill to reimplement DOM APIs in
addition to this. quill.root.innerHTML or document.querySelector(".ql-editor").innerHTML works just fine (quill.container.firstChild.innerHTML is a bit more brittle as it depends on child ordering) and the previous getHTML implementation did little more than this.
Simple, solution is here:
https://www.scalablepath.com/blog/using-quill-js-build-wysiwyg-editor-website/
The main code is:
console.log(quill.root.innerHTML);
This is a very common confusion when it comes to Quilljs. The thing is you should NOT retrieve your html just to display it. You should render and display your Quill container just the same way you do when it is an editor. This is one of the major advantages to Quilljs and the ONLY thing you need to do is:
$conf.readOnly = true;
This will remove the toolbar and make the content not editable.
I have accomplished it in the backend using php.
My input is json encoded delta and my output is the html string.
here is the code , if it is of any help to you.This function is still to handle lists though and some other formats but you can always extend those in operate function.
function formatAnswer($answer){
$formattedAnswer = '';
$answer = json_decode($answer,true);
foreach($answer['ops'] as $key=>$element){
if(empty($element['insert']['image'])){
$result = $element['insert'];
if(!empty($element['attributes'])){
foreach($element['attributes'] as $key=>$attribute){
$result = operate($result,$key,$attribute);
}
}
}else{
$image = $element['insert']['image'];
// if you are getting the image as url
if(strpos($image,'http://') !== false || strpos($image,'https://') !== false){
$result = "<img src='".$image."' />";
}else{
//if the image is uploaded
//saving the image somewhere and replacing it with its url
$imageUrl = getImageUrl($image);
$result = "<img src='".$imageUrl."' />";
}
}
$formattedAnswer = $formattedAnswer.$result;
}
return nl2br($formattedAnswer);
}
function operate($text,$ops,$attribute){
$operatedText = null;
switch($ops){
case 'bold':
$operatedText = '<strong>'.$text.'</strong>';
break;
case 'italic':
$operatedText = '<i>'.$text.'</i>';
break;
case 'strike':
$operatedText = '<s>'.$text.'</s>';
break;
case 'underline':
$operatedText = '<u>'.$text.'</u>';
break;
case 'link':
$operatedText = ''.$text.'';
break;
default:
$operatedText = $text;
}
return $operatedText;
}
Here's a full function using quill.root.innerHTML, as the others didn't quite cover the complete usage of it:
function quillGetHTML(inputDelta) {
var tempQuill=new Quill(document.createElement("div"));
tempQuill.setContents(inputDelta);
return tempQuill.root.innerHTML;
}
This is just a slight different variation of km6 's answer.
For Quill version 1.3.6, just use:
quill.root.innerHTML;
Try it online: https://jsfiddle.net/Imabot/86dtuhap/
Detailed explaination on my blog
This link if you have to post the Quill HTML content in a form
quill.root.innerHTML on the quill object works perfectly.
$scope.setTerm = function (form) {
var contents = JSON.stringify(quill.root.innerHTML)
$("#note").val(contents)
$scope.main.submitFrm(form)
}
I put together a node package to convert html or plain text to and from a Quill Delta.
My team used it to update our data model to include both Quill's Delta and HTML. This allows us to render on the client without an instance of Quill.
See node-quill-converter.
It features the following functions:
- convertTextToDelta
- convertHtmlToDelta
- convertDeltaToHtml
Behind the scenes it uses an instance of JSDOM. This may make it best suited for migration scripts as performance has not been tested in a typical app request lifecycle.
Try
console.log ( $('.ql-editor').html() );
Here is how I did it, for you Express folks. It seems to have worked very well in conjunction with express-sanitizer.
app.js
import expressSanitizer from 'express-sanitizer'
app.use(expressSanitizer())
app.post('/route', async (req, res) => {
const title = req.body.article.title
const content = req.sanitize(req.body.article.content)
// Do stuff with content
})
new.ejs
<head>
<link href="https://cdn.quilljs.com/1.3.2/quill.snow.css" rel="stylesheet">
</head>
...
<form action="/route" method="POST">
<input type="text" name="article[title]" placeholder="Enter Title">
<div id="editor"></div>
<input type="submit" onclick="return quillContents()" />
</form>
...
<script src="https://cdn.quilljs.com/1.3.2/quill.js"></script>
<script>
const quill = new Quill('#editor', {
theme: 'snow'
})
const quillContents = () => {
const form = document.forms[0]
const editor = document.createElement('input')
editor.type = 'hidden'
editor.name = 'article[content]'
editor.value = document.querySelector('.ql-editor').innerHTML
form.appendChild(editor)
return form.submit()
}
</script>
express-sanitizer (https://www.npmjs.com/package/express-sanitizer)
document.forms (https://developer.mozilla.org/en-US/docs/Web/API/Document/forms)
My view only has one form, so I used document.forms[0], but if you have multiple or may extend your view in the future to have multiple forms, check out the MDN reference.
What we are doing here is creating a hidden form input that we assign the contents of the Quill Div, and then we bootleg the form submit and pass it through our function to finish it off.
Now, to test it, make a post with <script>alert()</script> in it, and you won't have to worry about injection exploits.
That's all there is to it.
Here is a proper way to do it.
var QuillDeltaToHtmlConverter = require('quill-delta-to-html').QuillDeltaToHtmlConverter;
// TypeScript / ES6:
// import { QuillDeltaToHtmlConverter } from 'quill-delta-to-html';
var deltaOps = [
{insert: "Hello\n"},
{insert: "This is colorful", attributes: {color: '#f00'}}
];
var cfg = {};
var converter = new QuillDeltaToHtmlConverter(deltaOps, cfg);
var html = converter.convert();
Refer https://github.com/nozer/quill-delta-to-html
For a jQuery-style solution that allows getting and setting the Quill value I am doing the following:
Quill.prototype.val = function(newVal) {
if (newVal) {
this.container.querySelector('.ql-editor').innerHTML = newVal;
} else {
return this.container.querySelector('.ql-editor').innerHTML;
}
};
let editor = new Quill( ... );
//set the value
editor.val('<h3>My new editor value</h3>');
//get the value
let theValue = editor.val();
quill-render looks like it's what you want. From the docs:
var render = require('quill-render');
render([
{
"attributes": {
"bold": true
},
"insert": "Hi mom"
}
]);
// => '<b>Hi mom</b>'
If you want to render quill using nodejs, there is a package quite simple based on jsdom, usefull to render backside (only one file & last update 18 days from now) render quill delta to html string on server
Just use this clean library to convert from delta from/to text/html
node-quill-converter
example:
const { convertDeltaToHtml } = require('node-quill-converter');
let html = convertDeltaToHtml(delta);
console.log(html) ; // '<p>hello, <strong>world</strong></p>'

Angular dirPaginate custom directive - get last page value in my controller

I need to read the value of the lastPage property (which exists in the custom directove below) from inside my controller.
https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination
function generatePagination() {
if (paginationService.isRegistered(paginationId)) {
var page = parseInt(paginationService.getCurrentPage(paginationId)) || 1;
scope.pages = generatePagesArray(page, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
scope.pagination.current = page;
scope.pagination.last = scope.pages[scope.pages.length - 1];
// ** here is the code I added that I would like to work **
parent.scope.lastPage = scope.pagination.last;
if (scope.pagination.last < scope.pagination.current) {
scope.setCurrent(scope.pagination.last);
} else {
updateRangeValues();
}
}
}
This is the author's function above in the directive. It has a property called: scope.pagination.last that I would like to access from my controller. I tried to do add something like this line:
parent.scope.lastPage = scope.pagination.last;
but that does not work, or I do not know how to inject parent, etc.
As Ori Price points out, this is not a best practice as it will make this directive dependent on the parent scope ... but maybe you already know that and just need a solution - in that case. $rootScope is what you're looking for.
3 things you need to do:
1.) add it as a dependency to the directive.
.directive('dirPaginationControls', ['paginationService', 'paginationTemplate','$rootScope', dirPaginationControlsDirective])
2.) actually pass it into the directive function:
function dirPaginationControlsDirective(paginationService, paginationTemplate, $rootScope) { ...
3.) Use it wherever you want in the directive... for you it would look something like this:
function generatePagination() {
if (paginationService.isRegistered(paginationId)) {
var page = parseInt(paginationService.getCurrentPage(paginationId)) || 1;
scope.pages = generatePagesArray(page, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
scope.pagination.current = page;
scope.pagination.last = scope.pages[scope.pages.length - 1];
$rootScope.lastPage = scope.pagination.last;
if (scope.pagination.last < scope.pagination.current) {
scope.setCurrent(scope.pagination.last);
} else {
updateRangeValues();
}
}
}
You may need to do $rootScope.$parent.lastPage = scope.pagination.last I can't remember off the top of my head so do a console.log($rootScope) just to look at all of the options you have access to.

Resources