Javascript Less Sorter - javascript

Problem:
I want to make a Less-sorting script for myself. When i enter Less Code in the textarea and click the button, p#result should output the sorted Less Code.
The Less Code should be sorted like this:
{
Mixins(They all start with ".mx")
Properties(Sorted in alphabetic Order)
}
Here is what i have got so far:
index.html:
<head>
<script src="jquery.min.js"></script>
</head>
<textarea id="input" style="width: 600px; height: 300px; resize: none;">
</textarea>
<p id="result" style="max-width: 600px; word-wrap: break-word;"></p>
<button>Sort</button>
<script src="jquery.sorter.js"></script>
jquery.sorter.js:
var result = "",
mixins = "",
properties = "";
$("button").on("click", function () {
var textarea = $('#input').val().split('\n');
function checkLine(position) {
var index;
for (index = position; index < textarea.length; ++index) {
var line = textarea[index].trim();
if (line.includes("{") === true)
{
result = result + mixins + "<br>" + properties + line + "<br>";
mixins = "";
properties = "";
checkLine(index + 1);
} else if (line.includes("}") === true)
{
result = result + mixins + properties + line + "<br>";
mixins = "";
properties = "";
break;
} else if (line.includes(".mx") === true)
{
mixins = mixins + line + "<br>";
} else if (line.includes(":") === true)
{
properties = properties + line + "<br>";
} else
{
result = result + "<br>";
}
console.log(index + ": " + mixins + " " + properties);
}
}
checkLine(0);
$("p#result").append(result);
$("button").hide();
});
If i enter this:
.frame {
color: blue;
background-color: white;
.mx-hello(white);
.framesecond {
font-size: 12px;
background: green;
.mx-test(white);
}
}
I should get al least this output: (I didnt think of a sorting mechanism yet... :D)
.frame {
.mx-hello(white);
color: blue;
background-color: white;
.framesecond {
.mx-test(white);
font-size: 12px;
background: green;
}
}
But i get this Output:
.frame {
.mx-hello(white);
color: blue;
background-color: white;
.framesecond {
.mx-test(white);
font-size: 12px;
background: green;
}
.mx-test(white);
font-size: 12px;
background: green;
}
.mx-hello(white);
color: blue;
background-color: white;
.framesecond {
.mx-test(white);
font-size: 12px;
background: green;
}
.mx-test(white);
font-size: 12px;
background: green;
}
Background - Story:
I work for a Web-Development Company. My Less Code always looks a bit messy, but we have guidelines how to format our Code. If im done with a Project i always sit there hour for hour just rearranging Less Code. Then i thought to myself: "There must be an easier solution for my problem!". So i googled and googled and nothing really worked. Then i decided to try it myself and thats why i am here!
I hope you understand my Problem, if something is unclear please let me know so i can edit my Question! (Im not so good at javascript, so any help is appreciated! :D)

I took a look at it to see if I could solve this one. Check this out:
Codepen: https://codepen.io/huppys/pen/VrbxLd?editors=1010
I replaced the string.includes("something") with some regular expressions to be able to filter even for some different kind of less expressions.
Plus: Properties get sorted. After finding a property the string describing the property gets pushed into an array. Before adding the found properties to the output string they get sorted.
Side note: What IDE or editor are you using for writing your LESS code? Probably it could take care of the syntax sorting itself?

Related

How to implement Quill Emoji Blot

I am trying to implement an Emoji Blot to Quill Editor,
But I have some issues with the cursor on editor.
In order to solve this I added a space after the emoji insertion, but when I try to remove them is needed two backspaces to remove the emoji. On the first time the cursor stops at the beginning of the emoji, and on the second time the emoji is removed.
Does anyone already did something similar to this? How can I get this code to work properly?
Thanks in any advance.
const Embed = Quill.import("blots/embed");
class EmojiBlot extends Embed {
static create(classes) {
let node = super.create();
classes.split(" ").forEach(iconClass => {
node.classList.add(iconClass);
});
return node;
}
static formats(node) {
let format = {};
if (node.hasAttribute("class")) {
format.class = node.getAttribute("class");
}
return format;
}
static value(node) {
return node.getAttribute("class");
}
format(name, value) {
if (name === "class") {
if (value) {
this.domNode.setAttribute(name, value);
} else {
this.domNode.removeAttribute(name, value);
}
} else {
super.format(name, value);
}
}
}
EmojiBlot.blotName = "emoji";
EmojiBlot.tagName = "span";
Quill.register({
"formats/emoji": EmojiBlot
});
var myEditor = new Quill("#editor-container", {
modules: {
toolbar: document.getElementById("toolbar")
},
placeholder: "Compose an epic...",
theme: "snow" // or 'bubble'
});
const insertEmoji = function() {
let editorSelection = myEditor.getSelection();
const cursorPosition = editorSelection && editorSelection.index ? editorSelection.index : 0;
myEditor.insertEmbed(cursorPosition, "emoji", 'icon icon-smiley');
myEditor.insertText(cursorPosition + 1, ' ')
myEditor.setSelection(cursorPosition + 2)
};
document.querySelector(".emojiButton").addEventListener("click", insertEmoji);
#editor-container {
height: 200px;
}
.icon {
display: inline-block;
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
background-repeat: no-repeat;
background-position: center center;
background-size: 1em 1em;
font-size: 20px;
}
.icon-smiley {
background-image: url("https://twemoji.maxcdn.com/2/svg/1f603.svg");
}
<link href="//cdn.quilljs.com/1.3.5/quill.snow.css" rel="stylesheet"/>
<script src="//cdn.quilljs.com/1.3.5/quill.js"></script>
<div
id="editor-container"
></div>
<div id="toolbar">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="emojiButton">:D</button>
</div>
I changed the emoji tag from a span to an img and also replaced:
myEditor.insertText(cursorPosition + 1, ' ')
myEditor.setSelection(cursorPosition + 2)
With
myEditor.setSelection(cursorPosition + 1);
This solves the issue. See an example here: https://jsfiddle.net/nadavrt/Ldgfp5pa/
As to what is causing the span the misbehave, my guess is that Quill fails to register your Blot's width correctly due to an error in Quill itself. I would recommend that you open a bug issue on the project's GitHub page.

Two recursive functions try to execute at the same time when only one should run

Essentially, I am trying to create a webpage that has 2 buttons; one will cause the screen to flash randomly, and the other will cause it to slowly change colours. I want to be able to switch between these two (if you press the first button it starts flashing and then if you press the second button it slowly changes without any kind of cancel button).
The buttons each call a function which sets the 'running' variable of the other function to false and it's own 'running' variable to true. It then calls a recursive function (recursive in that it just calls itself over and over). These recursive functions only execute their code when their 'running' variable is true.
If you run the snippet you can see that the program is very inconsistent (you may need to play with it for a bit to see the issue since it sometimes seems to work). Sometimes it refuses to change function and other times the two functions seem to both be active and they both try to execute (it almost looks as if they are fighting for control). I don't understand how this is happening since, I believe, only one of the 'running' variables can be true at any time.
var runningDisco = false;
var runningColours = false;
function startColours() {
if (runningDisco == true); //Is disco running?
{
runningDisco = false; //If yes, stop it
}
runningColours = true; //Indicate we are running
window.setTimeout(Colours, 100, 0); //Run
}
function startDisco() {
if (runningColours == true); {
runningColours = false;
}
runningDisco = true;
window.setTimeout(Disco, 100);
}
function Disco() {
if (runningDisco == true); {
hex = "#";
for (discoCount = 0; discoCount < 6; discoCount++) {
hex = hex.concat((Math.floor(Math.random() * 17)).toString(16));
}
document.body.style.background = hex;
window.setTimeout(Disco, 10);
}
}
function Colours(colourCount) {
if (runningColours == true); {
if (colourCount > 359) {
colourCount -= 359;
}
document.body.style.background = "hsl(" + colourCount + ", 50%, 50%)";
window.setTimeout(Colours, 10, colourCount + 1);
}
}
input {
font-family: 'Roboto', sans-serif;
text-align: center;
background-color: #dd1021;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
}
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<input id="clickMe" type="button" value="Start Disco" onclick="startDisco();" />
<input id="clickMe" type="button" value="Start Colours" onclick="startColours();" />
The semicolons after your if-statements are causing a problem
For example, replace:
if (runningColours == true); {
if (runningDisco == true); {
with
if (runningColours == true) {
if (runningDisco == true) {
Here it is fixed in jsfiddle.
You have semicolons in the wrong place
If you need to run a single animation you need to use a single global variable to hold the timeout handler and clear it when starting a new one.
Like this:
var running;
function startColours() {
clearTimeout(running);
running = setTimeout(Colours, 100, 0); //Run
}
function startDisco() {
clearTimeout(running);
running = setTimeout(Disco, 100);
}
function Disco() {
var hex = "#";
for (discoCount = 0; discoCount < 6; discoCount++) {
hex = hex.concat((Math.floor(Math.random() * 17)).toString(16));
}
document.body.style.background = hex;
running = setTimeout(Disco, 10);
}
function Colours(colourCount) {
if (colourCount > 359) {
colourCount -= 359;
}
document.body.style.background = "hsl(" + colourCount + ", 50%, 50%)";
running = setTimeout(Colours, 10, colourCount + 1);
}
input {
font-family: 'Roboto', sans-serif;
text-align: center;
background-color: #dd1021;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
}
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<input id="clickMe" type="button" value="Start Disco" onclick="startDisco();" />
<input id="clickMe" type="button" value="Start Colours" onclick="startColours();" />
The real problem is the semicolons after the if statements inside the Disco and Colours functions:
if (runningDisco == true); {
document.body.style.background = …
}
will execute as
if (runningDisco == true)
;
{
document.body.style.background = …
}
which runs the content regardless of the boolean variable. Why does it work at all sometimes? I guess when the two setTimeout callbacks run close enough to each other that only the latter is rendered at all it feels consistent. Of course that is very unstable - they are indeed fighting each other for screen time.
You made a common mistake to those new to JavaScript - including a semi-colon after you if header. This creates an if statement with no body that is followed by a block containing the single statement runningColours = false, which will not execute correctly. The below should fix this:
if (runningColours == true)
{
runningColours = false;
}
The following JSFiddle link should have a working version of your script:
https://jsfiddle.net/4qhmtnhe/
I hope it starts working, and you continue to learn JavaScript.

Display image is not showing up in safari, however in works fine in IE11

Background
I currently have a test webpage which I will need to work on both Windows and Mac OS environments. Currently I have a block of code which works on IE however when tested on a Mac it does not work.
Problem
This code is meant to dynamically create the following div's dynamically and then populate the img tag with the base64 results that I am getting from a call out to a service. The issue is it never displays in safari, however it displays on IE.
Code
$("#listView").kendoPanelBar({
expandMode: "single",
select: function (e) {
var retrievedContent = dataSource._data;
for (var x = 0; x < retrievedContent.length; x++) {
if (e.item.dataset.uid === retrievedContent[x].uid) {
selectedContent = retrievedContent[x];
$.when(GetImgB64(selectedContent.ServerRelativeUrl)).done(function (imageB64) {
if (imageB64) {
var formattedB64 = "data:image/jpeg;base64," + imageB64;
$(".destroyWaiting").remove();
$(e.item, ".topTabPanel").append('<div class="destroy"> Content : <button type="button" class="insertButton k-primary" id="button1" style="border: 2px none; border-radius: 25px; margin-left: 15px; margin-top: 5px;">Insert</button></div>');
$(e.item).append('<div class="destroy" style="margin-top: 5px; border: 1px solid darkgray;"><p></p><img class="img-responsive" src="' + formattedB64 + '" /></div>');
$(".insertButton").each(function (e) {
$(this).click(function (d) {
insertImages(imageB64);
});
});
}
else {
FeedBackMessage("No Result For Criteria");
}
});
}
}
else {
$(e.item).find(".destroy").remove();
}
},
collapse: function (e) {
$(e.item).find(".destroy").remove();
}
});
Safari requires a base64 string that has a character count divisible by 4.
Use this:
if (imageB64) {
while (imageB64.length % 4 > 0) {
imageB64 += '=';
}
var formattedB64 = "data:image/jpeg;base64," + imageB64;
$(".destroyWaiting").remove();
$(e.item, ".topTabPanel").append('<div class="destroy"> Content : <button type="button" class="insertButton k-primary" id="button1" style="border: 2px none; border-radius: 25px; margin-left: 15px; margin-top: 5px;">Insert</button></div>');
$(e.item).append('<div class="destroy" style="margin-top: 5px; border: 1px solid darkgray;"><p></p><img class="img-responsive" src="' + formattedB64 + '" /></div>');
$(".insertButton").each(function (e) {
$(this).click(function (d) {
insertImages(imageB64);
});
});
}
Source: Base64 image tag in safari did not showed up
My solution was different. Images returned as base64 string from a REST service worked everywhere except on Safari desktop or mobile.
After a day of research and experimentation, I found that the IMG SRC attribute must apply the prefix "data:image/jpeg;base64," as so:
document.getElementById("targetImg").src = "data:image/jpeg;base64," + defaultAvatarBase64String;
That is, something like this failed:
var imageSrc = "data:image/jpeg;base64," + defaultAvatarBase64String;
document.getElementById("targetImg").src = imageSrc
Turns out the REST service applied the "data:image/jpeg;base64," prefix. REST service had to be revised to return only the base64 image string.
Hope this helps...

How to save the sort order?

I have created Demo by using packery and draggabilly where I have five grids.I can sort them using the draggable.After I make my sort.I need to save the sorted grid.Here the grids are not moving when I inspect in dev only the position is changing not the grid exactly.
As I've passed ids,but of no use.Due to the issue mentioned above.
Is there any way of saving the sort order ? I don't want to use localStorage
My code follows
HTML
<h1>Image sort</h1>
<div class="packery">
<div class="item w2 h2 i1" tabindex="0">A</div>
<div class="item w2 h2 i2" tabindex="1">B</div>
<div class="item w2 h2 i3" tabindex="2">C</div>
<div class="item w2 h2 i4" tabindex="3">D</div>
<div class="item w2 h2 i5" tabindex="4">E</div>
</div>
JS
// http://packery.metafizzy.co/packery.pkgd.js and
// http://draggabilly.desandro.com/draggabilly.pkgd.js added as external resource
// ----- text helper ----- //
$(function() {
var $container = $('.packery').packery({
columnWidth: 100,
rowHeight: 180,
// disable initial layout
isInitLayout: false
});
var pckry = $container.data('packery');
// ----- packery setup ----- //
// trigger initial layout
$container.packery();
var itemElems = $container.packery('getItemElements');
// for each item element
$( itemElems ).each( function( i, itemElem ) {
// make element draggable with Draggabilly
var draggie = new Draggabilly( itemElem );
// bind Draggabilly events to Packery
$container.packery( 'bindDraggabillyEvents', draggie );
});
CSS
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body { font-family: sans-serif; }
.packery {
background: #FDD;
background: hsla(45, 100%, 40%, 0.2);
max-width: 460px;
}
/* clearfix */
.packery:after {
content: ' ';
display: block;
clear: both;
}
.item {
width: 240px;
height: 140px;
float: left;
background: #C09;
border: 4px solid #333;
border-color: hsla(0, 0%, 0%, 0.3);
font-size: 20px;
color: white;
padding: 10px;
}
.item:hover {
border-color: white;
cursor: move;
}
.item.w2 { width: 400px; }
.item.h2 { height: 140px; }
.item.w2.i1 { background: #ffff00; }
.item.w2.i2 { background: #ff6633; }
.item.w2.i3 { background: #00c6d7; }
.item.w2.i4 { background: #990099; }
.item.w2.i5 { background: #EEEEEE; }
.item.is-dragging,
.item.is-positioning-post-drag {
border-color: white;
background: #09F;
z-index: 2;
}
Well 'save' can mean two things.
Saving the values temporarily like localStorage/Cookies as you mentioned in the question. The thing is that, it will solve your problem of saving the order in the client, even if the user refreshes the page and comes back, he/she can check these values and reorder them accordingly. Disadvantage is that, if the user deletes his/her cache and history, the data might not be there when he/she revisits the page.
And the other alternative would be to use traditional approach, that is, to use a Ajax call and send data to a back-end script(PHP or Nodejs) that will save the values to a DB. This way, if there exists a login system of sorts, you can just post the values to a database and proceed in that manner.
Here is a simple code to give you an idea (using PHP):
JS
$.ajax({
url: 'test.php',
type: 'POST',
data: {order : sortOrder},
success: function(result){
// do something
}
});
test.php
$order = $_REQUEST['order'];
echo $order;
// Do something here that will store the values to the database
For Nodejs, you can do something similar to this: How to send array of ids correctly in express
Hope it helps...
Found this codepen which seems very similar to your example.
Packery.prototype.sortItems = function( keys, getSortKey ) {
// copy items
//var _items = this.items.slice(0);
var itemsBySortKey = {};
var key, item;
for ( var i=0, len = this.items.length; i < len; i++ ) {
item = this.items[i];
key = getSortKey( item );
itemsBySortKey[ key ] = item;
}
i=0;
len = keys.length;
var sortedItems = [];
for ( ; i < len; i++ ) {
key = keys[i];
item = itemsBySortKey[ key ];
this.items[i] = item;
}
};
var storedSortOrder = localStorage.getItem('sortOrder')
if ( storedSortOrder ) {
storedSortOrder = JSON.parse( storedSortOrder );
pckry.sortItems( storedSortOrder, function( item ) {
return item.element.getAttribute('tabindex');
});
}
It might not be a full answer, but might be helpful, you could create a function from it
var saved_order = {};
Object.keys(object_to_sort)
.sort()
.forEach(function(key, i) {
console.log('new order: ' + key, ':', object_to_sort[key]);
saved_order[key] = object_to_sort[key];
});

Inline JavaScript throwing "not defined" (it IS!) - WordPress related maybe?

<style>
#flamingo-picture-2 {
border-width: 15px;
border-style: solid;
border-color: red;
}
</style>
<script>
function changeBorderColor(){
var img = document.getElementById('flamingo-picture-2');
if ( img.style.border-color == 'red' ) {
img.style.border-color = 'blue';
} else {
img.style.border-color = 'red';
}
}
</script>
<img id="flamingo-picture-2" src="/wp-content/uploads/flamingo.jpg" onclick="changeBorderColor()">
This is inside a WordPress post content. (I know -- bad practice. But it is just a little demo/example.)
Console shows an error that changeBorderColor is not defined. I keep staring at it. I feel like I defined it. Did I miss a brace or a semi-colon or something? Is it possible WordPress is doing something? (I don't think it is, as I've looked at the output page source, but you never know...)
Instead of img.style.border-color you need img.style.borderColor It works here:
function changeBorderColor(){
var img = document.getElementById('flamingo-picture-2');
if ( img.style.borderColor == 'red' ) {
img.style.borderColor = 'blue';
} else {
img.style.borderColor = 'red';
}
}
#flamingo-picture-2 {
border-width: 15px;
border-style: solid;
border-color: red;
}
<img id="flamingo-picture-2" src="/wp-content/uploads/flamingo.jpg" onclick="changeBorderColor()">

Categories