In the picture, the width of option is larger than the select box. I want to set width of those options as same as select box & for those larger options set text-overflow as ellipsis. Any help would be appreciated.
Here is what I tried:
Html
<select>
<option>Select your University</option>
<option>Bangladesh University of Engineering and Technology</option>
<option>Mawlana Bhashani Science and Technology University</option>
</select>
Css
select, option {
width: 250px;
}
option {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
Fiddle: https://jsfiddle.net/3bsbcqfz/
I tried to find a solution from CSS. But I failed to do it. Doesn't matter, I have written a simple javascript code for it. This is can do it something for it.
function shortString(selector) {
const elements = document.querySelectorAll(selector);
const tail = '...';
if (elements && elements.length) {
for (const element of elements) {
let text = element.innerText;
if (element.hasAttribute('data-limit')) {
if (text.length > element.dataset.limit) {
element.innerText = `${text.substring(0, element.dataset.limit - tail.length).trim()}${tail}`;
}
} else {
throw Error('Cannot find attribute \'data-limit\'');
}
}
}
}
window.onload = function() {
shortString('.short');
};
select {
width: 250px;
}
option {
width: 250px;
}
<select name="select" id="select">
<option class='short' data-limit='37' value="Select your University">Select your University</option>
<option class='short' data-limit='37' value="Bangladesh University of Engineering and Technology">Bangladesh University of Engineering and Technology</option>
<option class='short' data-limit='37' value="Mawlana Bhashani Science and Technology University">Mawlana Bhashani Science and Technology University</option>
</select>
You can use javascript to make the length of the option text to be less so as that it matches the length of the option. I found no solution for only using css
var e=document.querySelectorAll('option')
e.forEach(x=>{
if(x.textContent.length>20)
x.textContent=x.textContent.substring(0,20)+'...';
})
select
{
width:160px;
}
<select>
<option>fwefwefwefwe</option>
<option>fwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwefwe</option>
</select>
Another simple jquery solution is to rewrite the option's length manually to get the wanted size as follow :
$('option').each(function() {
var optionText = this.text;
var newOption = optionText.substring(0, 36);
$(this).text(newOption + '...');
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<select style="width:250px">
<option>Select your University</option>
<option>Bangladesh University of Engineering and Technology</option>
<option>Mawlana Bhashani Science and Technology University</option>
</select>
At last, I come up with the solution by creating Custom Drop-down using ul, li. Here is the solution:
FIDDLE DEMO
HTML
$(document).ready(function (){
$("div.selected").on("click", function () {
var hasActiveClass = $("div.select-box").hasClass("active");
if (hasActiveClass === false) {
var windowHeight = $(window).outerHeight();
var dropdownPosition = $(this).offset().top;
var dropdownHeight = 95; // dropdown height
if (dropdownPosition + dropdownHeight + 50 > windowHeight) {
$("div.select-box").addClass("drop-up");
}
else {
$("div.select-box").removeClass("drop-up");
}
var currentUniversity = $(this).find('text').text().trim();
$.each($("ul.select-list li"), function () {
var university = $(this).text().trim();
if (university === currentUniversity)
$(this).addClass("active");
else
$(this).removeClass("active");
});
}
$("div.select-box").toggleClass("active");
});
$("ul.select-list li").on("click", function () {
var university = $(this).html();
$("span.text").html(university);
$("div.select-box").removeClass("active");
});
$("ul.select-list li").hover(function () {
$("ul.select-list li").removeClass("active");
});
$(document).click(function (event) {
if ($(event.target).closest("div.custom-select").length < 1) {
$("div.select-box").removeClass("active");
}
});
});
div.custom-select
{
height: 40px;
width: 400px;
position: relative;
background-color: #F2F2F2;
border: 1px solid #E4E4E4;
}
div.selected
{
width: inherit;
cursor: pointer;
line-height: 20px;
display: inline-block;
}
div.selected > .text
{
padding: 10px;
display: block;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
div.select-box
{
display: none;
width: 100%;
z-index: 10029;
position: absolute;
border-radius: 3px;
box-shadow: 0 8px 20px #000000;
box-shadow: 0 8px 20px rgba(0,0,0,.35)
}
div.select-box.active
{
display: block;
}
div.select-box.drop-up
{
top: auto;
bottom: 100%;
}
ul.select-list
{
margin: 0;
padding: 10px;
list-style-type: none;
}
ul.select-list li
{
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
ul.select-list li:hover,
ul.select-list li.active
{
background-color: #999999;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='custom-select'>
<div class="selected">
<span class='text'>Select</span>
</div>
<div class='select-box'>
<ul class='select-list'>
<li data-row='0' data-value=''>
Select
</li>
<li data-row='1' data-value='BUET'>
Bangladesh University of Engineering and Technology
</li>
<li data-row='2' data-value='MBSTU'>
Mawlana Bhashani Science and Technology University
</li>
</ul>
</div>
</div>
If you don't mind using jQuery, here is a simple solution. Just run it at the beginning of your code and it's applicable to every select
$('select').change(function(){
var text = $(this).find('option:selected').text()
var $aux = $('<select/>').append($('<option/>').text(text))
$(this).after($aux)
$(this).width($aux.width())
$aux.remove()
}).change()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select>
<option>Select your University</option>
<option>Bangladesh University of Engineering and Technology</option>
<option>Mawlana Bhashani Science and Technology University</option>
</select>
This may be a little late, but I found that using CodeIgniter's word_limiter() function may do what you need, for example:
<option><?php echo word_limiter("Bangladesh University of Engineering and Technology",1); ?></option>
If you're not using CodeIgniter, you may just look up the function.
Hope this helps!
Related
This "R code" works fine in Jupyter but not in lab:
library(IRdisplay)
display_html(
'
<script>
code_show=true;
function code_toggle() {
if (code_show){
$(\'div.input\').hide();
} else {
$(\'div.input\').show();
}
code_show = !code_show
}
$( document ).ready(code_toggle);
</script>
<form action="javascript:code_toggle()">
<input type="submit" value="Code On/Off">
</form>
<style type="text/css">
.container { width:80% !important; }
.main-container {
max-width: 2000px;
margin-left: 100px;
margin-right: 10px;
}
/*body{font-family: Lucida Sans Unicode} */
.nav>li>a {
position: relative;
display: block;
padding: 10px 15px;
color: #004F59;
}
.nav-pills>li.active>a, .nav-pills>li.active>a:hover, .nav-pills>li.active>a:focus {
color: #ffffff;
background-color: #004F59;
}
.list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover {
background-color: #004F59;
}
</style>
'
)
I also tried to use display_html in other contexts. Is there a reason why this does not work in lab? Can it easily be fixed? Thanks.
The IRdisplay::display_html() works fine in JupyterLab, as does the callback to your function. The only differences between Notebook v6 and JupyterLab are:
jQuery is not available by default in JupyterLab (as it is no longer needed in 2020's), so the selection by $(\'div.input\').hide(); will not work - use standard document.querySelectorAll() instead
CSS classes are different so styles (and selectors need to be adjusted); it is not clear what you wanted to achieve but for hiding input areas you can achieve the same effect with standard JS in JupyterLab:
IRdisplay::display_html('
<script type="text/javascript">
let code_show = true;
function code_toggle() {
if (code_show) {
document.querySelectorAll(".jp-Cell-inputArea").forEach(function(inputArea) {
inputArea.style.display = "none";
});
} else {
document.querySelectorAll(".jp-Cell-inputArea").forEach(function(inputArea) {
inputArea.style.display = "";
});
}
code_show = !code_show;
}
</script>
<form action="javascript:code_toggle()">
<input type="submit" value="Code On/Off">
</form>
')
Our videos use the lower third of the page for introductions, etc. much like TV News stations do. When captions are on, they're blocking all of that, thus creating a LOT of complaints from the communities that need the captions. I've tried tinkering with the CSS, but with a responsive layout, resizing the player wreaks havoc, often putting them out of sight altogether.
Is there a setting that can be changed, or technique to use, that will keep the captions at the top and in view when resized, OR in an external container?
Problem: the JW player 608 live captions are not formatted cleanly.
To solve this, disable the JW caption display and format our own window, named "ccbuffer"
<style type="text/css">
.jw-captions {
display: none !important;
}
#ccbuffer {
border: 2px solid white !important;
border-radius: 4px;
background-color: black !important;
display: flex;
height: 120px;
margin-top: 6px;
font: 22px bold arial, sans-serif;
color: white;
justify-content: center;
align-items: center;
}
</style>
Here is where I show the player, and ccbuffer is a div right below it
<div id="myPlayer">
<p style="color: #FFFFFF; font-weight: bold; font-size: x-large; border-style: solid; border-color: #E2AA4F">
Loading video...
</p>
</div>
<div id="ccbuffer" />
DOMSubtreeModified is deprecated. Use MutationObserver, which is less stressful on the client.
Let's hook the 'captionsChanged' event from JW. if track is 0 then no captions are selected and we disconnect the observer. If captions are selected, then we use jquery to pull the text out of the jw-text-track-cue element, and format it into a nice 3 line display in our ccbuffer window.
<script>
var observer;
jwplayer().on('captionsChanged', function (event) {
if (event.track == 0) {
observer.disconnect();
$('#ccbuffer').hide('slow');
}
else {
$('#ccbuffer').show('slow');
// select the target node
var target = document.querySelector('.jw-captions');
// create an observer instance
observer = new MutationObserver(function(mutations) {
$('.jw-text-track-cue').each(function(i) {
if (i == 0)
$('#ccbuffer').html( $(this).text() );
else
$('#ccbuffer').append("<br/>" + $(this).text() );
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config);
}
});
$(document).ready(function () {
$('#ccbuffer').hide();
});
</script>
So when the user enables captions, the ccbuffer window will slide open and display a clean 3 line representation of the CC text.
Final Solution: External Captions that are draggable/resizable
All credit to #Basildane, I worked out how to extenalize the captions with VOD, and to make them draggable and resizable, with CSS experimentation for ADA consideration:
<!DOCTYPE html>
<html>
<head>
<title>JW External Captions</title>
<meta http-equiv="Expires" content="Fri, Jan 01 1900 00:00:00 GMT">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Lang" content="en">
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="/jwplayer/v8.10/jwplayer.js"></script>
<style type="text/css">
#myPlayer {
margin-bottom:5px;
}
.jw-captions {
display: none !important;
}
#ccbuffer {
color: white;
background-color: black;
opacity:.7;
font: 22px bold san-serif;
width: 100%;
padding: 15px;
height: 100%;
position:relative;
}
.night {
color:silver !important;
background-color: black !important;
opacity:1 !important;
border-color:silver !important;
}
.highcontrast {
color:white ! important;
background-color: black !important;
opacity:1 !important;
border-color:white !important;
}
.highcontrast2 {
color:black !important;
background-color: yellow !important;
opacity:1 !important;
border-color:black !important;
}
.highcontrast3 {
color:yellow !important;
background-color: black !important;
opacity:1 !important;
border-color:yellow !important;
}
#ccContainer {
position: absolute;
z-index: 9;
border: 1px solid inherit;
overflow: hidden;
resize: both;
width: 640px;
height: 180px;
min-width: 120px;
min-height: 90px;
max-width: 960px;
max-height: 300px;
}
#ccContainerheader {
padding: 3px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
border:1px solid;
}
</style>
</head>
<body>
<h3>JW Draggable Captions Container</h3>
<div id="PlayerContainer" style="width:401px;">
<div id="myPlayer">Loading video...</div>
</div>
<div id="ccContainer">
<!-- Include a header DIV with the same name as the draggable DIV, followed by "header" -->
<div style="float:right;">
<form id="myform">
<select id="ccFontFamily">
<option value="sans-serif">Default Font</option>
<option value="serif">Serif</option>
<option value="monospace">Monospace</option>
<option value="cursive">Cursive </option>
</select>
<select id="ccFontSize" style="">
<option value="22">Default Size</option>
<option value="14">14</option>
<option value="18">18</option>
<option value="24">24</option>
<option value="32">32</option>
</select>
<select id="ccContrast" style="">
<option value="ccdefault">Default Contrast</option>
<option value="night">Night</option>
<option value="highcontrast">High Contrast</option>
<option value="highcontrast2">Black/Yellow</option>
<option value="highcontrast3">Yellow/Black</option>
</select>
<button id="ccFontReset">Reset</button>
</form>
</div>
<div id="ccContainerheader">
Captions (click to move)
</div>
<div id="ccbuffer"></div>
</div>
<script type="text/javascript">
$(document).ready(function() {
jwplayer.key = 'xxxxxxxxxxxxxxxxxxx';
jwplayer('myPlayer').setup({
width: '100%', aspectratio: '16:9', repeat: 'false', autostart: 'false',
playlist: [{
sources: [ { file: 'https:www.example.com/video.mp4'}],
tracks: [ { file: 'https:www.example.com/video-captions.vtt', kind: 'captions', label: 'English', 'default': true } ]
}]
})
// External CC Container
$('#ccContainer').hide();
var position = $('#myPlayer').position();
var width = $('#PlayerContainer').outerWidth();
ccTop = position.top;
ccLeft = (width+50)+'px'
$('#ccContainer').css({'top':ccTop, left:ccLeft });
var observer;
jwplayer().on('captionsList', function (event) {
ccObserver(event);
});
jwplayer().on('captionsChanged', function (event) {
ccObserver(event);
});
videoplayer.on('fullscreen', function(event){
if(event.fullscreen){
$('.jw-captions').css('display','block');
}else{
$('.jw-captions').css('display','none');
}
});
$("#ccFontFamily").change(function() {
$('#ccbuffer').css("font-family", $(this).val());
});
$("#ccFontSize").change(function() {
$('#ccbuffer').css("font-size", $(this).val() + "px");
});
$("#ccContrast").change(function() {
$('#ccContainer').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccContainerheader').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccbuffer').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('select').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccFontReset').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
});
$('#ccFontReset').click(function() {
ccFontReset();
});
function ccFontReset(){
$("#ccFontFamily").val($("#ccFontFamily option:first").val()).trigger('change');
$("#ccFontSize").val($("#ccFontSize option:first").val()).trigger('change');
$("#ccContrast").val($("#ccContrast option:first").val()).trigger('change');
}
ccFontReset();
});
function ccObserver(event){
if (event.track == 0) {
$('#ccContainer').hide('slow');
$('.jw-captions').css('display','block'); // VERY important
if (observer != null){
observer.disconnect();
}
}
else {
$('#ccContainer').show('slow');
$('.jw-captions').css('display','none'); // VERY important
var target = document.querySelector('.jw-captions');
observer = new MutationObserver(function(mutations) {
$('.jw-text-track-cue').each(function(i) {
if (i == 0)
$('#ccbuffer').html( $(this).text() );
else
$('#ccbuffer').append("<br/>" + $(this).text() );
});
});
var config = { attributes: true, childList: true, characterData: true }
observer.observe(target, config);
}
}
// External CC Container - Make the DIV element draggable:
dragElement(document.getElementById("ccContainer"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
}
}
</script>
</body>
</html>
I'm trying to add a feature that user can select a date after clicking an clock icon. I implement it by using jqueryui datepicker() component. The problem I met is that I cannot change the background color of the date input area. it is supposed one grey color, then white, then grey etc.
Here is my code:
html
<ul>
<li><span class="deltbtn"><i class="far fa-trash-alt"></i></span>set deadline<input type="text" class="datepicker"></li>
<li><span class="deltbtn"><i class="far fa-trash-alt"></i></span>bbbbbbb<input type="text" class="datepicker"></li>
<li><span class="deltbtn"><i class="far fa-trash-alt"></i></span>ccccccc<input type="text" class="datepicker"></li>
</ul>
javascript
var getinput = (function () {
//grab text from input form
var inputtext = $('#inputText').val();
//empty the input form
$('#inputText').val("");
//create a new li and add it to the ul
$('ul').append('<li><span class="deltbtn"><i class="far fa-trash-alt"></i></span>' + inputtext + '<input type="text" class="datepicker"></li>')
//create deadline by using jQueryui.datepicker() component
$(function () {
$(".datepicker").datepicker({ minDate: new Date() });
});
$.datepicker.setDefaults({
showOn: "both",
buttonImageOnly: true,
buttonImage: "deadlineicon.svg",
buttonText: "Set Deadline"
});
$('ul').on('click', '.datepicker', function (event) {
event.stopPropagation();
})
});
CSS
.datepicker{
background: #fff;
width: 25%;
float: right;
display: block;
cursor: pointer;
padding: 0.5rem 0.5rem 0.6rem 0.5rem;
}
.ui-datepicker-trigger {
position:relative;
float: right;
top:13px;
right:-170px ;
height:20px
}
input:nth-of-type(2n){
background: #f7f7f7;
}
any help would be grateful.
Your html structure is different then you think:
Instead of
input:nth-of-type(2n){
background: #f7f7f7;
}
try
li:nth-child(2n) input{
background: red;
}
I prepared example of image slider what I need.
I encounter with styling issue when using images with various dimensions. When element leaving the array, its location is set as absolute value, what is necessary for smooth transition, tho, but the image is also moved up.
I would like to have nice vertical align into middle even leave or enter the array, but could not get on any way.
Another issue, what I would like to solve is when left the window and then went back after a while. The animation running all cycles at once to reach current state instead just stop animation and run after. Maybe it is my responsibility, but browsers doesn't offer nice event to catch blur window or am I wrong?
According to this discussion
Thank you for any ideas.
let numbers = [{key:1},{key:2},{key:3},{key:4},{key:5},{key:6},{key:7}]
let images = [
{ key:1,
src:"http://lorempixel.com/50/100/sports/"},
{ key:2,
src:"http://lorempixel.com/50/50/sports/"},
{ key:3,
src:"http://lorempixel.com/100/50/sports/"},
{ key:4,
src:"http://lorempixel.com/20/30/sports/"},
{ key:5,
src:"http://lorempixel.com/80/20/sports/"},
{ key:6,
src:"http://lorempixel.com/20/80/sports/"},
{ key:7,
src:"http://lorempixel.com/100/100/sports/"}
]
new Vue({
el: '#rotator',
data: {
items: images,
lastKey: 7,
direction: false
},
mounted () {
setInterval(() => {
if (this.direction) { this.prevr() } else { this.nextr() }
}, 1000)
},
methods: {
nextr () {
let it = this.items.shift()
it.key = ++this.lastKey
this.items.push(it)
},
prevr () {
let it = this.items.pop()
it.key = ++this.lastKey
this.items.unshift(it)
}
}
})
.litem {
transition: all 1s;
display: inline-block;
margin-right: 10px;
border: 1px solid green;
background-color: lightgreen;
padding: 10px 10px 10px 10px;
height: 100px;
}
.innerDiv {
border: 1px solid red;
}
.container {
overflow: hidden;
white-space: nowrap;
height: 250px;
border: 1px solid blue;
background-color: lightblue;
}
.list-enter {
opacity: 0;
transform: translateX(40px);
}
.list-leave-to {
opacity: 0;
transform: translateX(-40px);
}
.list-leave-active {
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.js"></script>
<div id="rotator">
<button #click="direction = !direction">
change direction
</button>
<transition-group
name="list"
tag="div"
class="container">
<div
v-for="item in items"
:key="item.key" class="litem">
<!--
<div
class='innerDiv'>
{{ item.key }}
</div>
-->
<div class='innerDiv'>
<img :src='item.src'>
</div>
</div>
</transition-group>
</div>
It tooks a while but on the end I think that I have got better result for sliding animation with changing direction feature.
One annoying think is when I swithing the sliding direction so animation is for a 'microsecond' changed to next state and than return to correct one, after it the animation continue as expected. It is happening only in one direction and I don't know how to fix it. Also last box behave differently too only once. No clue at all.
So just 98% solution :-)
let images = [
{key:1, domKey:1, src:"http://lorempixel.com/50/100/sports/" },
{key:2, domKey:2, src:"http://lorempixel.com/50/50/sports/" },
{key:3, domKey:3, src:"http://lorempixel.com/100/50/sports/" },
{key:4, domKey:4, src:"http://lorempixel.com/20/30/sports/" },
{key:5, domKey:5, src:"http://lorempixel.com/80/20/sports/" },
{key:6, domKey:6, src:"http://lorempixel.com/20/80/sports/" },
{key:7, domKey:7, src:"http://lorempixel.com/100/100/sports/" }
]
let setPositionRelative = el => el.style.position = "relative"
new Vue({
el: '#rotator',
data: {
items: images,
lastKey: 7,
direction: true,
changeDirectionRequest: false
},
mounted () {
Array.from(this.$el.querySelectorAll("div[data-key]")).map(setPositionRelative)
setInterval(() => {
if(this.changeDirectionRequest) {
this.changeDirectionRequest = false
this.direction = !this.direction
if (this.direction)
Array.from(this.$el.querySelectorAll("div[data-key]")).map(setPositionRelative)
else
Array.from(this.$el.querySelectorAll("div[data-key]")).map(el => el.style.position = "")
}
if (this.direction) this.prevr()
else this.nextr()
}, 1000)
},
methods: {
nextr () {
let it = this.items.shift()
it.key = ++this.lastKey
this.items.push(it)
},
prevr () {
let it = this.items.pop()
it.key = ++this.lastKey
this.items.unshift(it)
setPositionRelative(this.$el.querySelector("div[data-domkey='"+it.domKey+"']"))
}
}
})
.container {
overflow: hidden;
white-space: nowrap;
height: 200px;
border: 1px solid blue;
background-color: lightblue;
display: flex;
align-items: center;
}
.innerDiv {
border: 1px solid red;
width: auto;
height: auto;
display:-moz-box;
-moz-box-pack:center;
-moz-box-align:center;
display:-webkit-box;
-webkit-box-pack:center;
-webkit-box-align:center;
display:box;
box-pack:center;
box-align:center;
}
.litem {
transition: all 1s;
margin-right: 10px;
border: 1px solid green;
background-color: lightgreen;
padding: 10px 10px 10px 10px;
}
.list2-enter, .list-enter {
opacity: 0;
transform: translateX(40px);
}
.list2-leave-to, .list-leave-to {
opacity: 0;
transform: translateX(-40px);
}
.list-leave-active {
position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.11/vue.js"></script>
<div id="rotator">
<button #click="changeDirectionRequest = true">change direction</button>
<transition-group name="list" tag="div" class="container">
<div v-for="item in items"
:key="item.key"
:data-domkey="item.domKey"
class="litem">
<div class='innerDiv'>
<img :src='item.src'>
</div>
</div>
</transition-group>
</div>
I have created a basic to-do list. I want to add the option to color code, similar to Google Keep (this is an exercise). I have tried simply putting one HTML select in, as you can see in my jsfiddle but this changes the background of that entire section.
<p display="none">
<section class="main" style="display: block;" >
<div data-bind="visible:todos().length>0">
<input id="toggle-all" type="checkbox" data-bind="checked:markAll"/>
<label for="toggle-all">Mark all as complete</label>
<br /><br />
<select id="colorOptions" id="toggle-all"></select>
</div>
<ul id="mycell" class="todo-list" data-bind="template:{ name:'item-template',foreach: todos}">
</ul>
</section>
</p>
Question: How do I add an option to individually color code the to-do items?
Ok, I did it using the templates. First I added the selection for the colors inside the template in the li, so that every entry has a selection. Then I added an id for every selection (which is the order variable, the first <select> has the id="0" the second has the id="1" and so on) in order to differentiate them and to make each of them have different functions onchange. I also made the addColorsOptions function which adds the options on every selection when it is created using its unique id.
$(function(){
var Todo = function(id, title, done, order,callback) {
var self = this;
self.id = ko.observable(id);
self.title = ko.observable(title);
self.done = ko.observable(done);
self.order = order;
self.updateCallback = ko.computed(function(){
callback(self);
return true;
});
}
var viewModel = function(){
var self = this;
self.todos = ko.observableArray([]);
self.inputTitle = ko.observable("");
self.doneTodos = ko.observable(0);
self.markAll = ko.observable(false);
self.addOne = function() {
var order = self.todos().length;
var t = new Todo(order, self.inputTitle(),false,order,self.countUpdate);
self.todos.push(t);
self.addColorsOptions(order);
};
self.createOnEnter = function(item,event){
if (event.keyCode == 13 && self.inputTitle()){
self.addOne();
self.inputTitle("");
}else{
return true;
};
}
self.toggleEditMode = function(item,event){
$(event.target).closest('li').toggleClass('editing');
}
self.editOnEnter = function(item,event){
if (event.keyCode == 13 && item.title){
item.updateCallback();
self.toggleEditMode(item,event);
}else{
return true;
};
}
self.markAll.subscribe(function(newValue){
ko.utils.arrayForEach(self.todos(), function(item) {
return item.done(newValue);
});
});
self.countUpdate = function(item){
var doneArray = ko.utils.arrayFilter(self.todos(), function(it) {
return it.done();
});
self.doneTodos(doneArray.length);
return true;
};
self.countDoneText = function(bool){
var cntAll = self.todos().length;
var cnt = (bool ? self.doneTodos() : cntAll - self.doneTodos());
var text = "<span class='count'>" + cnt.toString() + "</span>";
text += (bool ? " completed" : " remaining");
text += (self.doneTodos() > 1 ? " items" : " item");
return text;
}
self.clear = function(){
self.todos.remove(function(item){ return item.done(); });
}
self.addColorsOptions = function(id){
var colors = [{
display: "light yellow",
value: "ffffcc"
}, {
display: "light blue",
value: "ccffff"
}, {
display: "light green",
value: "ccffcc"
}, {
display: "gray",
value: "cccccc"
}, {
display: "white",
value: "ffffff"
}];
var options = ['<option value="">Select color</option>'];
for(var i = 0; i < colors.length; i++){
options.push('<option value="');
options.push(colors[i].value);
options.push('">');
options.push(colors[i].display);
options.push('</option>');
}
$("#" + id).html(options.join('')).change(function(){
var val = $(this).val();
if(val){
$("#" + id).closest('li').css('backgroundColor', '#' + val);
}
});
}
};
ko.applyBindings(new viewModel());
})
body {
font-size: 14px;
background-color: #3c6dc5;
color: #333333;
width: 520px;
margin: 0 auto;
}
#todoapp {
background-color: #3c6dc4;
padding: 20px;
margin-bottom: 40px;
}
#todoapp h1 {
font-size: 36px;
text-align: center;
color:white;
}
#todoapp input[type="text"] {
width: 466px;
font-size: 24px;
line-height: 1.4em;
padding: 6px;
color:#000033;
}
.main {
display: none;
}
.todo-list {
margin: 10px 0;
padding: 0;
list-style: none;
color: #E0E0EF;
}
.todo-list li {
padding: 18px 20px 18px 0;
position: relative;
font-size: 24px;
border-bottom: 1px solid #cccccc;
}
.todo-list li:last-child {
border-bottom: none;
}
.todo-list li .edit {
display: none;
}
.todo-list li.editing {
border-bottom: 1px solid #778899;
}
.todo-list li.editing .view {
display: none;
}
.todo-list li.editing .edit {
display: block;
width: 444px;
padding: 13px 15px 14px 20px;
margin: 0;
}
.todo-list li.done label {
color: #777777;
text-decoration: line-through;
}
.todo-list .destroy {
position: absolute;
right: 5px;
top: 20px;
display: none;
cursor: pointer;
width: 20px;
height: 20px;
}
#todoapp footer {
display: none;
margin: 0 -20px -20px -20px;
overflow: hidden;
color: #555555;
background: #f4fce8;
border-top: 1px solid #ededed;
padding: 0 20px;
line-height: 37px;
}
.todo-count {
float:left;
}
.todo-count .count{
font-weight:bold;
}
#clear-completed {
float: right;
line-height: 20px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
color: #555555;
font-size: 11px;
margin-top: 8px;
margin-bottom: 8px;
padding: 0 10px 1px;
cursor: pointer;
}
label{color:white;}
<script src="http://knockoutjs.com/downloads/knockout-2.3.0.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="todoapp">
<header>
<h1>Fun To Do!</h1>
<input id="new-todo" type="text" placeholder="Finish Homework..." data-bind="value:inputTitle,event: { keyup: createOnEnter}"/>
</header>
<section class="main" style="display: block;" >
<div data-bind="visible:todos().length>0">
<input id="toggle-all" type="checkbox" data-bind="checked:markAll"/>
<label for="toggle-all">Mark all as complete</label> <br /><br />
</div>
<ul id="mycell" class="todo-list" data-bind="template:{ name:'item-template',foreach: todos}">
</ul>
</section>
<footer style="display: block;">
<div data-bind="visible:todos().length>0">
<div class="todo-count"><b data-bind="text:todos().length"></b> items left</div>
<!-- ko if: doneTodos() > 0 -->
<a id="clear-completed" data-bind="click:clear">
Clear <span data-bind="html:countDoneText(true)"></span>.
</a>
<!-- /ko -->
<br style="clear:both"/>
</div>
</footer>
</div>
<script type="text/template" id="item-template">
<li data-bind="event:{ dblclick :$root.toggleEditMode},css : {done:done() }">
<div class="view" >
<input class="toggle" type="checkbox" data-bind="checked:done"/>
<label data-bind="text:title"></label>
<a class="destroy"></a>
</div>
<input class="edit" type="text" data-bind="value:title,event: { keyup: $root.editOnEnter}" />
<select data-bind="attr: {'id': id}"></select>
</li>
</script>
You can also see the JSFiddle here.
For any question feel free to comment. I hope this was helpful :)
EDIT
See this JSFiddle for the <input type="color"> addition.
I tested your fiddle code. There is some unwanted code (that i did not find) that fade out your div databind="..... So to remove this problem you can add this at the end of jquery codes before last }); to see some thing like this:
$('div').show(); //adding code
});
Now the select works and you can see the changes in page inspector, But you can not see that here because your ul is empty. To see the result change that ul with an static data ul like this:
<ul id="mycell" class="todo-list">
<li>first</li>
<li>second</li>
</ul>