select elements in sequence (by group class name) - javascript

how do I select elements created dinamicamentes by groups? I want to select msgpvtstyleme and work on them. Then select msgpvtstyle again and work on them ... Goal is to get grouped elements and insert them classes .....
I want to simulate chat balloons
result final! Thank you all!

Here is a basic jQuery script which checks each element and detecting the following:
Check current class
If previous sibling has a different class then it will get first
If next sibling is of the same class, it will be middle
If next sibling is of another class, it will be marked as last
If previous and next siblings are of other classes, it will be first middle last
// define your container here
var container = $('.container'),
currentClass = container.children(":first").attr("class");
// run through each child
container.children('li').each(function() {
currentClass = $(this).attr("class");
if ( $(this).prev().attr("class") !== currentClass ) {
$(this).attr("data-order","first"); }
if ( $(this).next().attr("class") === currentClass && $(this).prev().attr("class") === currentClass ) {
$(this).attr("data-order","middle"); }
if ( $(this).next().attr("class") !== currentClass ) {
$(this).attr("data-order","last"); }
if ( $(this).next().attr("class") !== currentClass && $(this).prev().attr("class") !== currentClass ) {
$(this).attr("data-order","first middle last"); }
// debugging only
$(this).text( $(this).attr("class") + ': ' + $(this).attr('data-order') );
});
li[data-order~="first"] {font-weight: bold;}
li[data-order~="last"] {border-bottom:1px solid;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="container">
<li class="class1"></li>
<li class="class1"></li>
<li class="class1"></li>
<li class="class2"></li>
<li class="class2"></li>
<li class="class1"></li>
</ul>
jsFiddle: https://jsfiddle.net/azizn/40trqhn4/
Note: I used data-order attribute instead class as altering the class name will break the checking function (since it all revolves around class name). You can access the elements through the CSS attribute selectors [data-order="first"] for example.

Here is a simple way:
function style_latest_messages() {
var classes = '.msgpvtstyle, .msgpvtstyleme';
$(classes).filter('.first,.middle,.last')
.last().removeClass('first middle last')
.add($(classes).not('.first,.middle,.last')).each(function() {
styleMessage(this);
});
function styleMessage(el) {
var prev = $(el).prevAll(classes).eq(0),
next = $(el).nextAll(classes).eq(0),
is_first = is_me(prev) != is_me(el) || !prev.length,
is_last = is_me(next) != is_me(el) || !next.length;
if(is_first) $(el).addClass('first');
if(is_last) $(el).addClass('last');
if(is_first == is_last) $(el).addClass('middle');
}
}
function is_me(el) { return $(el).hasClass('msgpvtstyleme'); }
Note that $(this).prevAll(classes).eq(0) and $(this).nextAll(classes).eq(0) will allow you to ignore any extra element, such as time. Try the demo to see what I mean.
Demo
style_latest_messages();
function style_latest_messages() {
var classes = '.msgpvtstyle, .msgpvtstyleme';
$(classes).filter('.first,.middle,.last')
.last().removeClass('first middle last')
.add($(classes).not('.first,.middle,.last')).each(function() {
styleMessage(this);
});
function styleMessage(el) {
var prev = $(el).prevAll(classes).eq(0),
next = $(el).nextAll(classes).eq(0),
is_first = is_me(prev) != is_me(el) || !prev.length,
is_last = is_me(next) != is_me(el) || !next.length;
if(is_first) $(el).addClass('first');
if(is_last) $(el).addClass('last');
if(is_first == is_last) $(el).addClass('middle');
}
}
function is_me(el) { return $(el).hasClass('msgpvtstyleme'); }
// Just for testing
var msgs=['<li class="time">17:52</li><li class="msgpvtstyleme">Don\'t forget to unload the dishwasher</li>', '<li class="msgpvtstyleme">Did you finish your homework?</li>', '<li class="msgpvtstyleme">Your grandmother is coming for dinner.</li>', '<li class="msgpvtstyleme">Dad and I decided to buy you a car.</li>', '<li class="time">17:56</li><li class="msgpvtstyle">Did U? OMG thank U!</li>', '<li class="msgpvtstyleme">No I was just making sure you get my texts.</li>', '<li class="msgpvtstyle">That was cruel</li>']; (function add_msg(){if(!msgs.length)return;$('.messagepvt').append(msgs.shift());style_latest_messages();setTimeout(add_msg,(msgs[0] || "").length * 50)})();
.messagepvt{ position: absolute; top: 0; left: 50%; height: 100%; overflow: hidden; margin-left: -35%; list-style: none; font-family: Arial, Helvetica, sans-serif; width: 70%; margin-top: 0; background: #f5f5f5; padding: .5em }body{ overflow: hidden }.messagepvt:after{ content: ""; display: block; clear: both }.time{ text-align: center; clear: both; color: #888; font-size: 10px; margin: .5em }.msgpvtstyle, .msgpvtstyleme { padding: .3em .8em; float: left; clear: both; background: #e6e6ec; color: #000; margin: 1px; font-size: 12px; -webkit-transition: border-radius .25s ease; -moz-transition: border-radius .25s ease; -webkit-animation: deploy .15s ease; -moz-animation: deploy .15s ease; -webkit-transform-origin: top left; -moz-transform-origin: top left }.msgpvtstyle.first { border-radius: 1.5em 1.5em 1.5em .5em }.msgpvtstyle.middle { border-radius: .5em 1.5em 1.5em .5em }.msgpvtstyle.last { border-radius: .5em 1.5em 1.5em 1.5em }.msgpvtstyle.first.middle.last, .msgpvtstyleme.first.middle.last { border-radius: 1.5em 1.5em 1.5em 1.5em }.msgpvtstyleme { float: right; background: #49f; color: #fff; -webkit-transform-origin: top right; -moz-transform-origin: top right}.msgpvtstyleme.first { border-radius: 1.5em 1.5em .5em 1.5em }.msgpvtstyleme.middle { border-radius: 1.5em .5em .5em 1.5em }.msgpvtstyleme.last { border-radius: 1.5em .5em 1.5em 1.5em }#-webkit-keyframes deploy{ from{-webkit-transform: scale(0)}to{-webkit-transform: scale(1)} }#-moz-keyframes deploy{ from{-moz-transform: scale(0)}to{-moz-transform: scale(1)} }
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="messagepvt"></ul>

Try this code to add classes in existing html tags
$('.msgpvtstyle ').each(function() {
$('.msgpvtstyleme:first-child' , $(this)).addClass('first');
$('.msgpvtstyleme:last-child' , $(this)).addClass('last');
$('.msgpvtstyleme:not(:first-child):not(:last-child)' , $(this)).addClass('middle');
});

Related

Question on element alignment and how cursor is able to stay flush with the text in this editable code textarea?

Looking at this codepen, most of it I grok. But a couple of things I don't understand:
How does the <code> element stay perfectly on top of the <textarea>? I would expect it to be below the textarea looking at the HTML code.
How is the cursor staying so well-aligned with the text such that it functions like the type of cursor in a word document? The cursor even aligns well with the text when I copy and paste the text. Is it the emmet dependency that's helping?
Here is the code:
HTML
<div class="editor-holder">
<ul class="toolbar">
<li><i class="fa fa-indent"></i></li>
<li><i class="fa fa-expand"></i></li>
</ul>
<div class="scroller">
<textarea class="editor allow-tabs"><div class="Editable Textarea">
<h1>This is a fully editable textarea which auto highlights syntax.</h1>
<p>Type or paste any code in here...</p>
<div>
<?php
var simple = "coding";
?>
<script>
with = "Tab or double space functionality";
</script></textarea>
<pre><code class="syntax-highight html"></code></pre>
</div>
</div>
(S)CSS
html, body{
margin: 0;
padding: 0;
height: 100%;
width: 100%;
position: relative;
background: rgb(114, 195, 195);
}
.editor-holder{
width: 800px;
height: 500px;
margin-top: 50px;
border-radius: 3px;
position: relative;
top: 0;
margin-left: -400px;
left: 50%;
background: #1f1f1f !important;
overflow: auto;
box-shadow: 5px 5px 10px 0px rgba(0, 0, 0, 0.4);
transition: all 0.5s ease-in-out;
&.fullscreen{
width: 100%;
height: 100%;
margin: 0;
left: 0;
}
.toolbar{
width: 100%;
list-style: none;
position: absolute;
top: -2px;
margin: 0;
left: 0;
z-index: 3;
padding: 8px;
background: #afafaf;
li{
display: inline-block;
}
a{
line-height: 20px;
background: rgba(144, 144, 144, 0.6);
color: grey;
box-shadow: inset -1px -1px 1px 0px rgba(0,0,0,0.28);
display: block;
border-radius: 3px;
cursor: pointer;
&:hover{
background: rgba(144, 144, 144, 0.8);
}
&.active{
background: rgba(144, 144, 144, 0.8);
box-shadow: none;
}
}
i{
color: #565656;
padding: 8px;
}
}
textarea, code{
width: 100%;
height: auto;
min-height: 450px;
font-size: 14px;
border: 0;
margin: 0;
top: 46px;
left: 0;
padding: 20px !important;
line-height: 21px;
position: absolute;
font-family: Consolas,Liberation Mono,Courier,monospace;
overflow: visible;
transition: all 0.5s ease-in-out;
}
textarea{
background: transparent !important;
z-index: 2;
height: auto;
resize: none;
color: #fff;
text-shadow: 0px 0px 0px rgba(0, 0, 0, 0);
text-fill-color: transparent;
-webkit-text-fill-color: transparent;
&::-webkit-input-placeholder{
color: rgba(255, 255, 255, 1);
}
&:focus{
outline: 0;
border: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
}
code{
z-index: 1;
}
}
pre {
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
code{
background: #1f1f1f !important;
color: #adadad;
.hljs {
color: #a9b7c6;
background: #282b2e;
display: block;
overflow-x: auto;
padding: 0.5em
}
.hljs-number,
.hljs-literal,
.hljs-symbol,
.hljs-bullet {
color: #6897BB
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-deletion {
color: #cc7832
}
.hljs-variable,
.hljs-template-variable,
.hljs-link {
color: #629755
}
.hljs-comment,
.hljs-quote {
color: #808080
}
.hljs-meta {
color: #bbb529
}
.hljs-string,
.hljs-attribute,
.hljs-addition {
color: #6A8759
}
.hljs-section,
.hljs-title,
.hljs-type {
color: #ffc66d
}
.hljs-name,
.hljs-selector-id,
.hljs-selector-class {
color: #e8bf6a
}
.hljs-emphasis {
font-style: italic
}
.hljs-strong {
font-weight: bold
}
}
}
JavaScript
var tabCharacter = " ";
var tabOffset = 2;
$(document).on('click', '#indent', function(e){
e.preventDefault();
var self = $(this);
self.toggleClass('active');
if(self.hasClass('active'))
{
tabCharacter = "\t";
tabOffset = 1;
}
else
{
tabCharacter = " ";
tabOffset = 2;
}
})
$(document).on('click', '#fullscreen', function(e){
e.preventDefault();
var self = $(this);
self.toggleClass('active');
self.parents('.editor-holder').toggleClass('fullscreen');
});
/*------------------------------------------
Render existing code
------------------------------------------*/
$(document).on('ready', function(){
hightlightSyntax();
emmet.require('textarea').setup({
pretty_break: true,
use_tab: true
});
});
/*------------------------------------------
Capture text updates
------------------------------------------*/
$(document).on('ready load keyup keydown change', '.editor', function(){
correctTextareaHight(this);
hightlightSyntax();
});
/*------------------------------------------
Resize textarea based on content
------------------------------------------*/
function correctTextareaHight(element)
{
var self = $(element),
outerHeight = self.outerHeight(),
innerHeight = self.prop('scrollHeight'),
borderTop = parseFloat(self.css("borderTopWidth")),
borderBottom = parseFloat(self.css("borderBottomWidth")),
combinedScrollHeight = innerHeight + borderTop + borderBottom;
if(outerHeight < combinedScrollHeight )
{
self.height(combinedScrollHeight);
}
}
// function correctTextareaHight(element){
// while($(element).outerHeight() < element.scrollHeight + parseFloat($(element).css("borderTopWidth")) + parseFloat($(element).css("borderBottomWidth"))) {
// $(element).height($(element).height()+1);
// };
// }
/*------------------------------------------
Run syntax hightlighter
------------------------------------------*/
function hightlightSyntax(){
var me = $('.editor');
var content = me.val();
var codeHolder = $('code');
var escaped = escapeHtml(content);
codeHolder.html(escaped);
$('.syntax-highight').each(function(i, block) {
hljs.highlightBlock(block);
});
}
/*------------------------------------------
String html characters
------------------------------------------*/
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
/*------------------------------------------
Enable tabs in textarea
------------------------------------------*/
$(document).delegate('.allow-tabs', 'keydown', function(e) {
var keyCode = e.keyCode || e.which;
if (keyCode == 9) {
e.preventDefault();
var start = $(this).get(0).selectionStart;
var end = $(this).get(0).selectionEnd;
// set textarea value to: text before caret + tab + text after caret
$(this).val($(this).val().substring(0, start)
+ tabCharacter
+ $(this).val().substring(end));
// put caret at right position again
$(this).get(0).selectionStart =
$(this).get(0).selectionEnd = start + tabOffset;
}
});
How does code and textarea elements stay aligned?
They are aligned because in the CSS they both use the same style which outlines the positioning of both elements. They both use position: absolute and the same top and left properties so stay in the same position.
See here https://www.w3schools.com/css/css_positioning.asp
In terms of the z-axis you can see that code has a z-index of 1 while textarea has 2 so text area stays on top.
How is the cursor staying aligned with the text?
There is no javascript acting on the cursor here. If you were to have any textarea in html the cursor would align with the text.

Unable to achieve 60fps animations

I REALLY want to achieve 60fps animations. Specifically, on my input elements on the focus event. The highest (according to Chrome Developer Tools) fps I can achieve is about 18fps.
I am using everything that is said to be best practice: window.requestAnimationFrame in my JavaScript, will-change in my css, and i'm using transforms for the actual animations. Even with all of these set in place, my animations aren't near 60fps.
var form = {};
function addActive(element) {
element.highlightElement.classList.add("input-highlight-active");
}
function removeActive(element) {
element.highlightElement.classList.remove("input-highlight-active");
}
// loops through the entire object removing "active" class on all elements except fo rthe element that is the target.
function setNewState(element, id, obj) {
for (var key in obj) {
if (id === key) {
window.requestAnimationFrame(() => addActive(element));
} else {
removeActive(obj[key]);
}
}
}
// Captures the event.target.id and corresponding object to be passed to setNewState function
function handleEvent(e) {
var active = form[e.target.id];
var activeId = e.target.id;
setNewState(active, activeId, form);
}
// Adds focus event listener to html elements
function addEvent() {
var inputElements = document.querySelectorAll('.input-wrapper > input');
inputElements = Array.from(inputElements);
inputElements.map(el => el.addEventListener('focus', (e) => handleEvent(e)));
}
// Creates object using input id as object key
function init() {
var temp = {};
var inputElements = document.querySelectorAll('.input-wrapper > input');
for (var i = 0; i < inputElements.length; i++) {
temp[inputElements[i].id] = {
highlightElement: inputElements[i].nextElementSibling,
active: false
};
}
return temp;
}
form = init();
addEvent();
body {
background-color: #121217;
}
.input-wrapper {
position: relative;
width: 60%;
margin: 0px auto 40px;
text-align: left;
}
.input-label {
position: relative;
text-align: left;
font-size: 18px;
font-weight: 300;
letter-spacing: 0.012em;
color: #eee;
}
input {
appearance: none;
-webkit-appearance: none;
position: relative;
width: 100%;
margin: 8px auto 0;
letter-spacing: 0.012em;
font-size: 18px;
color: #fafafa;
background-color: #121217;
border: 0px;
transform-origin: left;
border-bottom: 1px solid #fafafa;
}
input:focus {
outline: none;
}
.input-highlight {
will-change: transform;
position: absolute;
top: 99%;
width: 101%;
height: 2px;
background-color: #006daa;
z-index: 1;
transform-origin: left;
transform: scaleX(0);
transition: all 0.12s linear;
}
.input-highlight-active {
will-change: transform;
transform: scaleX(1);
transition: all 0.12s linear;
}
<div class="input-wrapper">
<div class="input-label">Full name</div>
<input type="text" id="fullName">
<div class="input-highlight"></div>
</div>
At the end of the day, I am sure i'm obsessing over something most won't notice. Ultimately, I just want to understand. Even if you tell me i've done all I can.
In the code you provided, you are using CSS animations, just by applying the extra class. There's no need to call requestAnimationFrame because it's designed to be called multiple times via the callback.
Since you took advantage of CSS animations you only need to add the class that changes the scale ONCE on focus, then you can remove it on blur:
.input-highlight-active {
transform: scaleX(1);
}
Because the input already has a class where the transition value specifies it will animate all properties (that it's able to animate), you only need to specify the property change that's animated.
Demo

Hiding an element in internet explorer leaves artifacts on the screen (IE 10-11)

We use custom selectbox elements for our page (for reasons), but in one specific place and only with IE (in my case version 10 and 11), there is a problem.
When you open the box and close it, sometimes the browser leaves visual artifacts of that element. If there is a button below the element (in the opened state), then those artifacts are still on top of that button UNTIL you hover over the button, then those artifacts disappear at that place.
I think everyone experienced this behaviour at some point in his life with windows or something else. Sorry if my description isn't perfect.
Here are some screenshots (The red boxes are censored text, sorry):
Open state:
Closed state with artifacts:
Hope my description is accurate, I desperately need a fix for this.
I can't reproduce it on my system, but our QA guy can reproduce it consistently. It also changes depending on the size of the browser. On some sizes it doesn't seem to happen at all. It must be some weird rendering glitch of IE.
I don't think it has anything to do with our custom selectbox element, because it happens only in this specific place and in our old design we experienced it in a different place with a completely different element. At that time I thought it's because the DOM is too complicated for IE, but this page has almost no elements.
EDIT: I Just found out that if I minimize the window and maximize it again, the artifacts disappear, which should confirm that this is a rendering glitch, right?
EDIT 2: Here is the code and css of our custom selectbox
HTML:
<div class="input_selectbox">
<label>Title</label>
<div class="input_selectbox__head" data-placeholder="">
<label>
<input type="hidden" name="id" value="5-10909">
Dummy 1
</label>
</div>
<div class="input_selectbox__body">
<label data-value="" class="">
No Option
</label>
<label id="5-10909" data-value="5-10909" class="input_selectbox__option--selected" data-default="true">
Dummy 1
</label>
<label id="5-12568" data-value="5-12568" class="">
Dummy 2
</label>
<label id="5-20001" data-value="5-20001" class="">
Dummy 3
</label>
<label id="5-20002" data-value="5-20002" class="">
Dummy 4
</label>
</div>
</div>
LESS:
.input_combobox, .input_selectbox {
display: block;
font-family: RobotoCondensed-Regular;
font-size: 14px;
width: 100%;
overflow: hidden;
&:focus {
outline: none;
}
label {
cursor: pointer;
}
}
.input_selectbox {
font-family: Roboto-Regular;
}
.input_selectbox__head {
border: 1px solid #colorBorderGrey;
transition: background-color 0.2s, border 0.3s;
overflow-x: hidden;
text-overflow: ellipsis;
display: flex;
background-color: #colorLightestGrey;
padding: 10px;
justify-content: space-between;
&:hover {
cursor: pointer;
border-color: #colorDarkGrey;
&:after {
color: #colorBlue;
}
}
label {
display: flex;
user-select: none;
pointer-events: none;
i {
margin-right: 10px;
}
}
&:after {
content: "\f078";
font-style: normal;
font-variant: normal;
text-rendering: auto;
font-family: "Font Awesome 5 Pro";
font-weight: 900;
pointer-events: none;
transition: color 0.3s, opacity 0.3s, background-color 0.2s;
display: block;
padding-left: 10px;
font-size: 16px;
}
}
.input_combobox--active, .input_selectbox--active {
.input_combobox__head, .input_selectbox__head {
background-color: #colorLightGrey;
&:hover {
border: 1px solid #colorBorderGrey;
&:after {
color: #colorDarkGrey;
}
}
&:after {
background-color: #colorLightGrey;
}
span {
background-color: #colorGreyHover;
}
}
}
.input_combobox__body, .input_selectbox__body {
display: none;
position: fixed;
box-shadow: rgba(0,0,0, 0.05) 0px 2px 5px 0px;
background-color: #colorWhite;
border: 1px solid #colorBorderGrey;
border-top: none;
max-height: 400px;
overflow-y: auto;
width: 100%;
z-index: 499;
label {
font-family: RobotoCondensed-Regular;
font-size: 16px;
display: block;
padding: 10px 20px;
transition: background-color 0.5s, color 0.3s;
border-bottom: 1px solid #colorBorderGrey;
&:hover {
background-color: #colorLightGrey;
}
&:last-child {
border-bottom: none;
}
i {
margin-right: 10px;
}
input[type=checkbox] {
display: none;
}
}
}
.input_combobox__body--top, .input_selectbox__body--top {
box-shadow: rgba(0, 0, 0, 0.1) 0px -2px 5px 0px;
}
.input_combobox__option--inactive, .input_selectbox__option--inactive {
opacity: 0.3;
}
Javascript:
function selectbox()
{
// click
$(document).on("click", ".input_selectbox__head", function ()
{
$(this).trigger("selectbox:toggle");
});
// toggle
$(document).on("selectbox:toggle", ".input_selectbox__head", function ()
{
if ($(this).parent().hasClass("input_selectbox--active"))
{
$(this).trigger("selectbox:close");
}
else
{
$(this).trigger("selectbox:open");
}
});
// open
$(document).on("selectbox:open", ".input_selectbox__head", function ()
{
var selectbox = $(this).closest(".input_selectbox");
if (!selectbox.hasClass("readonly") && !selectbox.hasClass("input--disabled"))
{
$(".input_selectbox--active .input_selectbox__head").trigger("selectbox:close");
// Positionierung
var header = selectbox.find(".input_selectbox__head");
var headerHeight = header.outerHeight();
var selectboxBody = selectbox.find(".input_selectbox__body");
var headerPositionX = header.offset().left;
var headerPositionY = header.offset().top - $(window).scrollTop();
var bodyPositionY = headerPositionY + headerHeight;
selectboxBody.removeClass("input_selectbox__body--top");
selectboxBody.css({
"top": bodyPositionY,
"left": headerPositionX,
"width": selectbox.width(),
"bottom": ""
});
selectbox.addClass("input_selectbox--active");
selectboxBody.show();
// check if offscreen
var isOut = isOutOfViewport(selectboxBody.get(0));
if (isOut.bottom)
{
selectboxBody.addClass("input_selectbox__body--top");
selectboxBody.css({
top: "",
bottom: ($(window).innerHeight() - headerPositionY - 1)
});
}
// close combobox on parent scroll
var scrollParent = getScrollParent(header[0]);
$(scrollParent).one("scroll", function ()
{
header.trigger("selectbox:close");
});
$(document).one("scroll", function ()
{
header.trigger("selectbox:close");
});
$(window).one("resize", function ()
{
header.trigger("selectbox:close");
});
}
});
// close
$(document).on("selectbox:close", ".input_selectbox__head", function ()
{
var selectbox = $(this).closest(".input_selectbox");
selectbox.removeClass("input_selectbox--active");
var selectboxBody = selectbox.find(".input_selectbox__body");
selectboxBody.hide();
});
// change option
$(document).on("click", ".input_selectbox__body > label", function ()
{
var label = $(this);
var value = label.attr("data-value");
var headerLabel = $(this).closest(".input_selectbox__body").siblings(".input_selectbox__head").children("label");
var name = headerLabel.find("input[type=hidden]").attr("name");
label.addClass("input_selectbox__option--selected").siblings().removeClass("input_selectbox__option--selected");
headerLabel.html(label.html());
headerLabel.append('<input type="hidden" name="' + name + '" value="' + value + '" />');
headerLabel.closest(".input_selectbox__head").trigger("selectbox:close");
$(this).closest(".input_selectbox").trigger("selectbox:change").trigger("change");
});
// close selectbox on outside click
$(document).ready(function ()
{
$(document).on("click touchstart", function (event)
{
if ($(event.target).closest('.input_selectbox--active').length == 0)
{
$(".input_selectbox--active .input_selectbox__head").trigger("selectbox:close");
}
});
});
// form reset
$(document).on("reset", "form", function ()
{
var selectboxes = $(this).find(".input_selectbox");
selectboxes.each(function ()
{
$(this).find(".input_selectbox__body").find("label[data-default=true]").click();
});
});
}

Transition event listener doesn't execute

I'm working on transitions by using javascript. But i want to display element to none when the transition is end. I'm using addEventListener on element but function doesn't execute.
var fun;
var transitions = {
'transition':'transitionend',
'OTransition':'oTransitionEnd',
'MozTransition':'transitionend',
'WebkitTransition':'webkitTransitionEnd'
};
(function(){
var i=0,
containterget = document.querySelector('.container');
elementGet = document.querySelector('.Number');
fun = function(){
i++;
elementGet.innerHTML = i;
elementGet.style.transform = 'translateX('+(containterget.offsetWidth - 40 -35)+'px)';
elementGet.addEventListener(transitions,function(event){
console.log("Transition End Execute");
elementGet.style.display='none';
} );
};
})();
*{
margin:0;
padding:0;
box-sizing: border-box;
}
.container{
border:1px solid green;
max-width:85%;
margin: 2em auto 0;
}
button{
background-color:transparent;
padding: 15px;
margin:0;
color:#000;
border:2px solid #F44336;
text-align: center;
outline: 0;
transition: opacity 0.3s;
}
button:hover{
background-color:#F44336;
color: white;
opacity :.75;
}
button:hover{
cursor: pointer;
transition: opacity .4s;
}
span{
display: inline-block;
transition: transform 1.5s ease;
}
.Number{
font-size: 4em;
border:1px solid black;
/*transform: translateX(0);*/
}
.EndBoundry{
float: right;
font-size: 4em;
border:1px solid black;
}
.contain:after{
content: "";
display: table;
clear: both;
}
.btn{
text-align: center;
margin: 2em 0;
}
<div class="container contain">
<span class="Number">1</span>
<span class="EndBoundry">E</span>
</div>
<div class="btn">
<button onclick="fun()">Number Transition Click</button>
</div>
The following Snippet demonstrates the transitionend event. All details are commented in Snippet.
SNIPPET
// Reference the section#area and input#gone
var area = document.getElementById('area');
var chx = document.getElementById('gone');
// Register click event on #area call offON()
area.addEventListener('click', offON, false);
function offON(e) {
// Determine the clicked button
if (e.target !== e.currentTarget) {
var tgt = e.target;
// Switch clicked button classes .on and .off
tgt.classList.toggle('on');
tgt.classList.toggle('off');
}
// If the checkbox is checked call transEND()
if (chx.checked) {
transEND()
}
}
function transEND() {
// Register the transitionend event on #area
area.addEventListener("transitionend", function(e) {
// Determine which button was clicked
if (e.target !== e.currentTarget) {
var tgt = e.target;
// Clicked button will disappear after transition
tgt.style.display = 'none';
}
}, false);
}
/* All buttons will have the same
|| transition. This transition is
|| dependent upon another animatable
|| style to exist.
*/
/* This particular transition says:
|| ALL animatable styles have a
|| duration of 3 seconds,
|| with a timing function: ease,
|| and a delay of 300msec
*/
button {
width: 120px;
height: 40px;
transition: all 3s ease .3s
}
/* Classes .on and .off are "states"
|| to each #id the "states" have a
|| different meaning
*/
#fade.off {
opacity: 1;
}
#fade.on {
opacity: 0;
}
#move.off {
transform: translateY(0);
}
#move.on {
transform: translateY(200px);
}
#shrink.off {
transform: scale(1);
}
#shrink.on {
transform: scale(.3);
}
#gone {
width: 18px;
height: 18px;
}
p {
font-size: 12px;
}
<p>Click each button. Then click them again (the "FADER" is still there and clickable)</p>
<p>Now click the checkbox and push the buttons again. If you can't click the buttons back to original "state", then the event handler on transitionend was successful.</p>
<label for='gone'>Enable "transitionEND" </label>
<input id='gone' type='checkbox'>
<section id='area'>
<button id='fade' class='off'>FADER</button>
<button id='move' class='off'>MOVER</button>
<button id='shrink' class='off'>SHRINKER</button>
</section>
Use "transitionend" without prefixes
elementGet.addEventListener("transitionend", function(){});
You can listen to transitionend event on supported browsers.
I did some reshuffling of your codes and add an id tag to your button.
See snippet below
var fun;
var i = 0,
containterget = document.querySelector('.container');
elementGet = document.querySelector('.Number');
console.log(elementGet)
function execute(event) {
console.log("Transition End Execute");
alert("Transition End Execute");
elementGet.style.display = 'none';
}
fun = function() {
i++;
elementGet.innerHTML = i;
elementGet.style.transform = 'translateX(' + (containterget.offsetWidth - 40 - 35) + 'px)';
elementGet.addEventListener('transitionend', execute);
elementGet.addEventListener('webkitTransitionEnd', execute);
elementGet.addEventListener('mozTransitionEnd', execute);
elementGet.addEventListener('oTransitionEnd', execute);
};
document.getElementById("target").addEventListener("click", fun)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
border: 1px solid green;
max-width: 85%;
margin: 2em auto 0;
}
button {
background-color: transparent;
padding: 15px;
margin: 0;
color: #000;
border: 2px solid #F44336;
text-align: center;
outline: 0;
transition: opacity 0.3s;
}
button:hover {
background-color: #F44336;
color: white;
opacity: .75;
}
button:hover {
cursor: pointer;
transition: opacity .4s;
}
span {
display: inline-block;
transition: transform 1.5s ease;
}
.Number {
font-size: 4em;
border: 1px solid black;
/*transform: translateX(0);*/
}
.EndBoundry {
float: right;
font-size: 4em;
border: 1px solid black;
}
.contain:after {
content: "";
display: table;
clear: both;
}
.btn {
text-align: center;
margin: 2em 0;
}
<div class="container contain">
<span class="Number">1</span>
<span class="EndBoundry">E</span>
</div>
<div class="btn">
<script></script>
<button id="target">Number Transition Click</button>
</div>

JavaScript Flip Counter

I would like to include a flip counter on my site, similar to what Apple was using for their 1 billion app countdown.
Can anyone get their JavaScript to work standalone?
If anyone can provide working code, that would be great.
They're using a combination of CSS and JavaScript. The flip animation is powered by a CSS Sprite-like technique.
First of all, they have a very tall image called filmstrip.png that contains every flip "state" for each number (0 to 9; have a look at a scaled-down detail and you'll see what I mean).
Then, in the HTML, each digit is made up of three nested elements:
The first is a container element, which has its width and height set to the dimensions of a single flip "state", and its overflow set to hidden. This element is positioned relatively.
The second element is positioned absolutely (and because the first element is positioned relatively, this second element is positioned absolutely relative to the first element).
The third element has its background-image set to filmstrip.png, and its width and height set to the dimensions of this image.
The JavaScript then seems to rapidly change the top property of the second element, causing different parts of filmstrip.png to be exposed one after another, thus resulting in a flip animation.
Steve
Here it is, ready to be implemented in your own webpage
http://cnanney.com/journal/code/apple-style-counter-revisited/
I've made a counter that works great with very minimal javascript to give it a little "brain":
function Counter(selector, settings){
this.settings = Object.assign({
digits: 5,
delay: 250, // ms
direction: '' // ltr is default
}, settings||{})
var scopeElm = document.querySelector(selector)
// generate digits markup
var digitsHTML = Array(this.settings.digits + 1).join('<div><b data-value="0"></b></div>')
scopeElm.innerHTML = digitsHTML;
this.DOM = {
scope : scopeElm,
digits : scopeElm.querySelectorAll('b')
}
this.DOM.scope.addEventListener('transitionend', e => {
if (e.pseudoElement === "::before" && e.propertyName == 'margin-top'){
e.target.classList.remove('blur')
}
})
this.count()
}
Counter.prototype.count = function(newVal){
var countTo, className,
settings = this.settings,
digitsElms = this.DOM.digits;
// update instance's value
this.value = newVal || this.DOM.scope.dataset.value|0
if( !this.value ) return;
// convert value into an array of numbers
countTo = (this.value+'').split('')
if(settings.direction == 'rtl'){
countTo = countTo.reverse()
digitsElms = [].slice.call(digitsElms).reverse()
}
// loop on each number element and change it
digitsElms.forEach(function(item, i){
if( +item.dataset.value != countTo[i] && countTo[i] >= 0 )
setTimeout(function(j){
var diff = Math.abs(countTo[j] - +item.dataset.value);
item.dataset.value = countTo[j]
if( diff > 3 )
item.className = 'blur';
}, i * settings.delay, i)
})
}
/////////////// create new counter for this demo ///////////////////////
var counter = new Counter('.numCounter', {direction:'rtl', delay:200, digits:7})
setInterval(randomCount, 3000)
function randomCount(){
counter.count( getRandomNum(0, 9999999))
}
function getRandomNum(min,max){
return Math.floor(Math.random()*(max-min+1) + min)
}
.numCounter {
display: inline-block;
height: 90px;
line-height: 90px;
text-shadow: 0 0 2px #fff;
font-weight: bold;
white-space: normal;
font-size: 50px;
}
.numCounter > div {
display: inline-block;
vertical-align: top;
height: 100%;
}
.numCounter > div > b {
display: inline-block;
width: 40px;
height: 100%;
margin: 0 0.1em;
border-radius: 8px;
text-align: center;
background: white;
overflow: hidden;
}
.numCounter > div > b::before {
content: ' 0 1 2 3 4 5 6 7 8 9 ';
display: block;
word-break: break-all;
-webkit-transition: 0.5s cubic-bezier(0.75, 0.15, 0.6, 1.15), text-shadow 150ms;
transition: 0.5s cubic-bezier(0.75, 0.15, 0.6, 1.15), text-shadow 150ms;
}
.numCounter > div > b.blur {
text-shadow: 2px 1px 3px rgba(0, 0, 0, 0.2),
0 0.1em 2px rgba(255, 255, 255, 0.6),
0 0.3em 3px rgba(255, 255, 255, 0.3),
0 -0.1em 2px rgba(255, 255, 255, 0.6),
0 -0.3em 3px rgba(255, 255, 255, 0.3);
}
.numCounter > div > b[data-value="1"]::before { margin-top: -90px; }
.numCounter > div > b[data-value="2"]::before { margin-top: -180px;}
.numCounter > div > b[data-value="3"]::before { margin-top: -270px;}
.numCounter > div > b[data-value="4"]::before { margin-top: -360px;}
.numCounter > div > b[data-value="5"]::before { margin-top: -450px;}
.numCounter > div > b[data-value="6"]::before { margin-top: -540px;}
.numCounter > div > b[data-value="7"]::before { margin-top: -630px;}
.numCounter > div > b[data-value="8"]::before { margin-top: -720px;}
.numCounter > div > b[data-value="9"]::before { margin-top: -810px;}
.numCounter > div:nth-last-child(3n)::before {
content: ",";
display: inline;
font-size: 1.1em;
opacity: .6;
color: white;
}
html, body {
height: 100%;
}
body {
display: flex;
align-items: center;
justify-content: center;
font-family: Arial;
}
.numCounter {
overflow: hidden;
padding: .4em;
text-align: center;
border-radius: 16px;
background: black;
}
.numCounter b {
color: black;
}
<div class='numCounter' data-value='1839471'></div>
It looks great and performs live very well, and it it count from any number to any number.
While searching for the same thing I found a commercial product offering this functionality: Sprite Countdown Flip.
Note: I'm not affiliated with this product; but it's well done and might be useful to someone.
I recommend the open source variant: FlipclockJS, which probably was created right after this event :)
Github: objectivehtml/FlipClock, available via NPM and Bower (not maintained)

Categories

Resources