I have received a new design for a website and in the design the designer used jquery. I'm implementing the design no into an ASP.NET Ajax application.
But I ran into a problem. I have a page with an update panel and a menu. When a menu item is clicked a user control is loaded dynamically into a placeholder on the update panel. This makes that the page is not totally refreshed but only the update panel.
Now the content in the user control contains a scrollpane that extends to the maximum height of the window. The first time that runs fine, but when a menu item is clicked and the new user control is loaded which has content witch includes the same scrollpane. The height isn't extended to the maximum height of the window, it then only uses the height it needs. The same thing happens when I don't include the jquery files so it has to do something with the jscript library.
The scripts that are used in the page:
scripts/jquery.js
jquery.watermark.js
scripts/jquery.customSelect.js
scripts/jquery.easing.js
scripts/jquery.logger.js
scripts/jquery.sizes.min.js
scripts/jquery.mousewheel.js
scripts/jquery.em.js
scripts/jquery.core.js
scripts/jquery.accordion.js
scripts/jquery.tabs.js
scripts/jquery.scroll.js
scripts/jquery.datepick.js
scripts/jquery.datepick-nl.js
scripts/jquery.scripts.js
Main code of the page that loads the main page:
<body>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div id="container">
<div id="logo"></div>
<uc2:Menu ID="ucMenu" runat="server" />
<uc3:Kruimelpad ID="ucKruimelpad" runat="server" />
<asp:UpdatePanel ID="upMain" runat="server" UpdateMode="Always">
<ContentTemplate>
<asp:PlaceHolder ID="phMain" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
<div id="sideBar">
<uc1:Login ID="ucLogin" runat="server" />
</div>
<div class="clearboth"></div>
</div>
<uc4:Footer ID="ucFooter" runat="server" />
</div>
</form>
</body>
</html>
main code of the user control:
<div class="editMenu">
</div>
<div id="content" class="orange-bar">
<div id="contentVlak" class="scroll_pane">
<h1><asp:Label ID="lblNoAccount" runat="server" Text="<%$ Resources:Login, no_account %>"></asp:Label></h1>
<p><asp:Label ID="lblMainText" runat="server" Text="<%$ Resources:Login, main_text %>"></asp:Label> <asp:LinkButton
ID="lbAccountAanvragen" runat="server"
Text="<%$ Resources:Login, demo_account_aanvragen %>"
onclick="lbAccountAanvragen_Click"></asp:LinkButton>.</p>
</div>
</div>
CSS code:
#content {
background: url(../images/contentBg.png) repeat-y left top;
position: relative;
top: 58px;
margin: 0px 0px 0px 11px !important;
width: 886px;
padding: 20px 20px 10px 20px;
}
#contentVlak {
width: 676px;
height:100%;
padding: 0px 20px;
}
#contentVlak p {
line-height: 20px;
margin-bottom: 10px;
font-size: 11.5px;
}
#contentVlak a {
font-weight: bold;
text-decoration: none;
}
#contentVlak a:hover {
text-decoration: underline;
}
/* Scrollpane styles */
.scroll_pane {
overflow: auto;
}
.jScrollPaneContainer {
position: relative;
overflow: hidden;
z-index: 1;
}
.jScrollPaneTrack {
position: absolute;
cursor: pointer;
right: 0;
top: 0;
height: 100%;
background: url(../images/scrollTrack.png) repeat-y left top;
}
.jScrollPaneDrag {
position: absolute;
background: #666;
cursor: pointer;
overflow: hidden;
height: 20px !important;
width: 20px;
background: url(../images/scrollPane.png) no-repeat left top;
}
.jScrollPaneDragTop {
position: absolute;
top: 0;
left: 0;
overflow: hidden;
}
.jScrollPaneDragBottom {
position: absolute;
bottom: 0;
left: 0;
overflow: hidden;
}
a.jScrollArrowUp {
display: block;
position: absolute;
z-index: 1;
top: 0;
right: 0;
text-indent: -2000px;
overflow: hidden;
background: url(../images/scrollUp.png) no-repeat left top;
height: 16px;
width: 16px;
}
a.jScrollArrowDown {
display: block;
position: absolute;
z-index: 1;
bottom: 0;
right: 0;
text-indent: -2000px;
overflow: hidden;
background: url(../images/scrollDown.png) no-repeat left top;
height: 16px;
width: 16px;
}
What am I doing wrong?
Code for resizing the block:
function resizeBlock(object) {
var windowHeight = $(window).height();
var start = object.offset().top;
var margin = object.margin().bottom + object.margin().top;
var padding = object.padding().bottom + object.padding().top;
var totalHeight = windowHeight - start - padding - 9;
object.height(totalHeight);
// Hoogtes van scroll-ding fixen
object.find(".scroll_pane").height(totalHeight);
object.find(".jScrollPaneContainer").height(totalHeight);
object.find(".jScrollPaneTrack").height(totalHeight);
object.find(".jScrollPaneDrag").height(totalHeight - 32);
// Object opnieuw toevoegen
$(".scroll_pane").jScrollPane({ showArrows: true, scrollbarWidth: 16 });
}
$(document).ready(function () {
// Functie zie hierboven
resizeBlock($("#content"));
$(".scroll_pane").jScrollPane({ showArrows: true, scrollbarWidth: 16 });
$(window).resize(function() {
resizeBlock($("#content"));
});
// Custom selectboxes
if($(".default-usage-select").length > 0) {
$(".default-usage-select").selectbox();
}
// Watermarks op homepage
if($("#relatiecode").length > 0) {
$("#relatiecode").Watermark("relatiecode", "#808285");
}
if($("#wachtwoord").length > 0) {
$("#wachtwoord").Watermark("wachtwoord", "#808285");
}
// Accordion box
if($(".accordion").length > 0) {
$('.accordion').accordion({
header: '.accordionTrigger',
autoheight: true,
animate: '100'
});
if($(".accordionTrigger").hasClass("selected")) {
$("#accordionLastTrigger").addClass ("activeLastTrigger");
}
}
// Tabbladen
if($("#tabContainer").length > 0) {
$('#tabContainer > ul').tabs();
}
// IE 6 Hover fix voor menu's
if (jQuery.browser.msie) {
if(parseInt(jQuery.browser.version) == 6) {
$('ul li').hover(function() {
$(this).addClass('ie6hover');
}, function() {
$(this).removeClass('ie6hover');
});
}
}
});if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
This is occurring because the control is essentially being repainted to the browser and the jQuery that you initialized for the scroll-pane was not initialized with the repainting.
You can tap into a javascript function that allows you to re-initalize the jQuery code. I'll grab a quick example, make sure you have the ScriptManager on your page (you should since its an Update Panel...)...
<script type="text/javascript">
function pageLoad() {
if (!Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack()) {
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequestHandler);
}
}
function endRequestHandler(sender, args) {
//Redo the scroll pane jQuery Initialization here...
}
</script>
Thanks RSolberg, your solution worked for me..I am using JScrollpane for Apple devices..and it works with update panel. Here is my updated code:
if ((navigator.userAgent.indexOf('AppleWebKit') != -1) || (navigator.userAgent.indexOf('iPhone') != -1) || (navigator.userAgent.indexOf('iPod') != -1) || (navigator.userAgent.indexOf('iPad') != -1) || (navigator.userAgent.indexOf('android') != -1) || (navigator.userAgent.indexOf('BlackBerry') != -1)) {
$('#<%=iWrapper1.clientID%>').jScrollPane();
$('#<%=iWrapper2.clientID%>').jScrollPane();
$('.videoDisplay').jScrollPane();
}
if (navigator.userAgent.indexOf("MSIE") != -1)
window.attachEvent("onload", pageLoad)
else
window.addEventListener("load", pageLoad, false);
function pageLoad() {
if (!Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack()) {
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequestHandler);
}
}
function endRequestHandler(sender, args) {
if ((navigator.userAgent.indexOf('AppleWebKit') != -1) || (navigator.userAgent.indexOf('iPhone') != -1) || (navigator.userAgent.indexOf('iPod') != -1) || (navigator.userAgent.indexOf('iPad') != -1) || (navigator.userAgent.indexOf('android') != -1) || (navigator.userAgent.indexOf('BlackBerry') != -1)) {
$('#<%=iWrapper1.clientID%>').jScrollPane();
$('#<%=iWrapper2.clientID%>').jScrollPane();
$('.videoDisplay').jScrollPane();
}
}
Related
I have a text area with CSS generated line numbers for each new line.
Everything works great, except for when there is a word wrap. If I get a word wrap, it does not wrap the new line text. I would like to make my line numbers word wrap with the text.
Here is a notepad+ example:
And here is a GitHub example:
How can I automatically detect and add a word wrap to my line numbers as well? Here is my code:
<script lang="ts">
export let source = `jon
sup
me
fixin to do sumthin good`;
let numberOfLines = source.split('\n').length;
const KeyUp = (event: Event) => {
const textarea = event.target as HTMLInputElement;
numberOfLines = textarea.value.split('\n').length;
};
const KeyDown = (event: Event) => {
const textarea = event.target as HTMLInputElement;
if ((event as KeyboardEvent).key === 'Tab') {
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
if (start && end) {
textarea.value = textarea.value.substring(0, start) + '\t'
+ textarea.value.substring(end);
event.preventDefault();
}
}
};
</script>
<center>
<div class="editor">
<div class="line-numbers">
{#each Array(numberOfLines) as _}
<span class="new-line" />
{/each}
</div>
<textarea class="text-content"
on:keyup={KeyUp} on:keydown={KeyDown} value={source} rows="15" />
</div>
</center>
<style>
.editor {
display: inline-flex;
gap: 10px;
font-family: monospace;
line-height: 21px;
background: #282a3a;
border-radius: 2px;
padding: 20px 10px;
}
.line-numbers {
width: 20px;
text-align: right;
}
.line-numbers .new-line {
counter-increment: linenumber;
}
.line-numbers .new-line::before {
content: counter(linenumber);
display: block;
color: #506882 !important;
}
.text-content {
line-height: 21px;
overflow-y: hidden;
padding: 0;
border: 0;
background: #282a3a;
color: #fff;
min-width: 500px;
outline: none;
resize: none;
}
</style>
And here is the StackBlitz Link:
(right click - open in new window)
Thanks!
J
Image for responding to comment below:
An approach could be to read the width of one character of the monospace font from an invisible element and set the textarea width to a multiple to avoid rounding errors. It then can be calculated for each substring between the line breaks how often it is wrapped and a margin-bottom added to the corresponding line number accordingly
REPL
<script>
import {onMount} from 'svelte'
export let source = `jon\nsup there is some other text here that I want to go across the lines and not word wrap another line etc boy!\nme\nfixin to do sumthin good`;
let fontWidthElem
let fontWidth
let charactersPerLine = 60
$: areaWidth = charactersPerLine * fontWidth
onMount(() => {
fontWidth = fontWidthElem.getBoundingClientRect().width
})
function wrapped(str, timesWrapped) {
if(str.length > charactersPerLine) {
const firstLine = str.substring(0, charactersPerLine)
const spaceOrDashInFirstLine = /[ -]/.test(firstLine)
const lastCharFirstLine = str[charactersPerLine-1]
const firstCharNextLine = str[charactersPerLine]
const wordIsCut = lastCharFirstLine !== '-' && lastCharFirstLine !== ' ' && firstCharNextLine !== ' ' && firstCharNextLine !== '-'
const nextLine = str.substring(charactersPerLine)
const nextLineNotOnlySpaces = nextLine.replaceAll(' ', '').length > 0
if(wordIsCut && spaceOrDashInFirstLine){
const lastIndexOfDivider = Math.max(firstLine.lastIndexOf(' '), firstLine.lastIndexOf('-'))
return wrapped(str.substring(lastIndexOfDivider+1), timesWrapped+1)
}else if(nextLineNotOnlySpaces){
return wrapped(nextLine.trimStart(), timesWrapped+1)
}else {
return timesWrapped
}
}else {
return timesWrapped
}
}
</script>
<div class="editor">
<div class="line-numbers">
{#each source.split('\n') as subStr, index}
<div class="line-nr"
style:margin-bottom="calc(var(--line-height) * {wrapped(subStr, 0)})"
>
{index + 1}
</div>
{/each}
</div>
<textarea bind:value={source}
style:width="{areaWidth}px"
rows="15"
/>
<div id="font-width"
bind:this={fontWidthElem}
>
a
</div>
</div>
<style>
:global(body) {
padding: 0;
}
.editor {
--line-height: 21px;
position: relative;
display: inline-flex;
gap: 10px;
padding: 20px 10px;
font-family: monospace;
line-height: var(--line-height);
background: #282a3a;
border-radius: 2px;
}
.line-nr {
width: 20px;
text-align: right;
color: #506882 !important;
}
textarea {
line-height: var(--line-height);
overflow-y: hidden;
margin: 0;
padding: 0;
border: 0;
background: #282a3a;
color: #fff;
outline: none;
resize: none;
}
#font-width {
position: absolute;
top: -1000px;
left: -1000px;
visibility: hidden;
}
</style>
To make the width responsive
additional editor wrapper for padding
watch editor width and calculate maximal possible charactersPerLine for textarea besides line numbers element
charactersPerLine added as argument to wrapped() for recalculation on change
REPL
<script>
import {onMount} from 'svelte'
export let source = `jon\nsup there is some other text here that I want to go across the lines and not word wrap another line etc boy!\nme\nfixin to do sumthin good`;
let fontWidthElem
let fontWidth
let editorWidth
onMount(() => {
fontWidth = fontWidthElem.getBoundingClientRect().width
})
let lineNumbersWidth = 30
$: charactersPerLine = Math.floor((editorWidth - lineNumbersWidth) / fontWidth)
function wrapped(str, charactersPerLine, timesWrapped) {
if(str.length > charactersPerLine) {
const firstLine = str.substring(0, charactersPerLine)
const spaceOrDashInFirstLine = /[ -]/.test(firstLine)
const lastCharFirstLine = str[charactersPerLine-1]
const firstCharNextLine = str[charactersPerLine]
const wordIsCut = lastCharFirstLine !== '-' && lastCharFirstLine !== ' ' && firstCharNextLine !== ' ' && firstCharNextLine !== '-'
const nextLine = str.substring(charactersPerLine)
const nextLineNotOnlySpaces = nextLine.replaceAll(' ', '').length > 0
if(wordIsCut && spaceOrDashInFirstLine){
const lastIndexOfDivider = Math.max(firstLine.lastIndexOf(' '), firstLine.lastIndexOf('-'))
return wrapped(str.substring(lastIndexOfDivider+1), charactersPerLine, timesWrapped+1)
}else if(nextLineNotOnlySpaces){
return wrapped(nextLine.trimStart(), charactersPerLine, timesWrapped+1)
}else {
return timesWrapped
}
}else {
return timesWrapped
}
}
</script>
<div class="editor-wrapper">
<div class="editor"
bind:clientWidth={editorWidth}
>
<div class="line-numbers"
style:width="{lineNumbersWidth}px"
>
{#each source.split('\n') as subStr, index}
<div class="line-nr"
style:margin-bottom="calc(var(--line-height) * {wrapped(subStr, charactersPerLine, 0)})"
>
{index + 1}
</div>
{/each}
</div>
<textarea bind:value={source}
style:width="{charactersPerLine}ch"
rows="15"
/>
<div id="font-width"
bind:this={fontWidthElem}
>
a
</div>
</div>
</div>
<style>
:global(body) {
padding: 0;
}
:global(*) {
box-sizing: border-box;
}
.editor-wrapper {
--line-height: 21px;
padding: 20px 10px;
background: #282a3a;
border-radius: 2px;
}
.editor {
position: relative;
display: flex;
width: 100%;
font-family: monospace;
line-height: var(--line-height);
}
.line-numbers {
padding-right: 10px;
text-align: right;
color: #506882 !important;
}
textarea {
line-height: var(--line-height);
overflow-y: hidden;
margin: 0;
padding: 0;
border: 0;
background: #282a3a;
color: #fff;
outline: none;
resize: none;
/* border seems to falsify calculation! */
/* box-shadow: 0 0 0 1px grey; */
}
#font-width {
position: absolute;
top: -1000px;
left: -1000px;
visibility: hidden;
}
</style>
What I want to do
I created the homepage that has some images. I would like to show up them by the responsive design. However, all image files' size are not changed when I show on the iPhone.
There are 3 types img files on HP.
The images are ...
files shows up by changing the 3 pics by each 2 seconds at the same place.
normal img files.
As the gallery, that the img file change to show up by clicking the thumbnail button.
All of them are not changed img size when responsive.
//const img = ["hoge.png", "foo.png", "bar.jpg"];
const img = ["https://lh3.googleusercontent.com/taykG37GWDgY-FGkdogDvsHSJMUGRMvkuVRT6yR-5UNkKvGRKeRlpGYXlslocOcS0txlfUdGW59JGtzADknxbMqnh6AtVCv9EXyB8nHp80YsRNA0Yw=w1024-h683-n-l50-sg-rj", "https://lh3.googleusercontent.com/fl-GT6w3Ls6RT4vYnbkuYUyLY3lZJH8VtZ7xzxiym9YYaoVRCnZehdz6Icd0oAf6i3H9-O5cCNs6eunlxWr_Csstgsb98DdzNdLFBOlhw9NUfHdyuQjI=w768-h1024-n-l50-sg-rj", "https://lh3.googleusercontent.com/9pPCK70Rw0k3wethMHb1qMaIB0VjeWLy57vYgSzKbF7oJuvO2nA0Nakk-95cvibWUDcEhYkfCKvdPKT03tXZd4M5jdhIEibLO9qw-XE=w1024-h683-n-l50-sg-rj"];
let count = -1;
const hoge = () => {
count++;
// カウントが最大になれば初期値に戻す
if (count == img.length) count = 0;
//画像選択
pic.src = img[count];
//1秒ごとに実行
setTimeout(() => {
hoge();
}, 2000);
}
window.onload = () => {
hoge();
}
//アルバムデータの作成
let album = [{
src: 'img/1.png',
msg: 'さまざまな形のパスタと自然の恵みを生かしたイタリアン'
},
{
src: 'img/2.png',
msg: 'パスタだけでなく軽食やスイーツも'
},
{
src: 'img/3.png',
msg: '肉料理やピザもイタリアン料理を彩ります'
},
{
src: 'img/4.png',
msg: '豊富な種類のピザ'
},
{
src: 'img/5.png',
msg: 'チーズが主役だったり生ハムが主役だったり、ピザの種類は豊富です'
}
];
//最初のデータを表示しておく
let mainImage = document.createElement('img');
mainImage.setAttribute('src', album[0].src);
mainImage.setAttribute('alt', album[0].msg);
let mainMsg = document.createElement('p');
mainMsg.innerText = mainImage.alt;
let mainFlame = document.querySelector('#gallery .main');
mainFlame.insertBefore(mainImage, null);
mainFlame.insertBefore(mainMsg, null);
//サムネイル写真の表示
let thumbFlame = document.querySelector('#gallery .thumb');
for (let i = 0; i < album.length; i++) {
let thumbImage = document.createElement('img');
thumbImage.setAttribute('src', album[i].src);
thumbImage.setAttribute('alt', album[i].msg);
thumbFlame.insertBefore(thumbImage, null);
}
//クリックした画像をメインにする
thumbFlame.addEventListener('click', function(event) {
if (event.target.src) {
mainImage.src = event.target.src;
mainMsg.innerText = event.target.alt;
}
});
.under {
border-bottom: dotted 2px #87cdfa
}
.fixed {
width: 300px;
height: auto;
}
img.calbo {
width: 100%;
height: auto;
}
img.pepe {
width: 100%;
height: auto;
}
#gallery {
margin: 0;
padding-top: 40px;
width: 700px;
}
#gallery .main img {
border: 4px solid #fff;
box-shadow: 0;
}
#gallery .main p {
color: #bbb;
font-size: 20px;
font-weight: bold;
}
#gallery .thumb img {
border: 4px solid #fff;
border-radius: 400px;
box-shadow: 0px 0px 10px #000;
height: 60px;
margin: 10px;
width: 60px;
cursor: pointer;
}
#media screen and (max-width: 480px) {
test {
float: none;
}
img {
width: 100%;
}
}
<h1>
<font color="#EEEEEE">レシピ ~ カルボナーラとペペロンチーノ</h1>
<br>
<hr width="700" align="left">
<!--- html ----->
<img id="pic" src="hoge.png" width="600" height=auto class="top">
<p>
<table>
<tr>
<th class="fixed"><img src="calbo150.png" class="calbo"></th>
<td style="background-color:#476072">
ちょっとしたひと工夫で普通の手作り<br> カルボからお店風本格カルボに。
<br> 失敗もしない簡単レシピ
<br><br>
カルボナーラのレシピ
</td>
</tr>
<tr>
<th class="fixed"><img src="pepe.jpg" class="pepe"></th>
<td style="background-color:#476072">
簡単だけど難しいペペロンチーノ。<br> 材料と水分調整がうまくいけば本格的な
<br> ペペロンチーノに仕上がります。
<br><br>
ペペロンチーノのレシピ
</td>
</tr>
</table>
</p>
<!-- JavaScript -->
<div id="gallery">
<div class="main">
</div>
<div class="thumb">
</div>
</div>
Although I didn’t paste the full HTML here, I used the double byte double quotation in the settings of the Viewport line. After I modified to single byte one, it started to work.
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>
I am working on a photo gallery in AngularJS using Angular Material (run the snippet in fullscreen to see my problem).
var app = angular.module('app', ['ngMaterial']);
app.controller('TitleController', function($scope) {
$scope.title = 'Gallery';
});
app.controller('GalleryCtrl', function($scope, $http, $q, $mdMedia, $mdDialog) {
//https://material.angularjs.org/latest/demo/virtualRepeat
$scope.Images = [],
//add more images
$scope.LoadMore = function() {
for (i = 0; i < 25; i++) {
var randomWidth = Math.round(Math.random() * (800 - 400) + 400);
var randomHeight = Math.round(Math.random() * (800 - 400) + 400);
$scope.Images.push({
src: "http://placehold.it/" + randomWidth + "x" + randomHeight + "/",
id: Math.round(Math.random() * 10000)
});
};
}
$scope.ShowDetails = function(ev, number) {
var useFullScreen = ($mdMedia('sm') || $mdMedia('xs')) && $scope.customFullscreen;
$mdDialog.show({
controller: DialogController,
templateUrl: 'Home/GetInfo?id=' + number,
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: true,
fullscreen: useFullScreen
})
$scope.$watch(function() {
return $mdMedia('xs') || $mdMedia('sm');
}, function(wantsFullScreen) {
$scope.customFullscreen = (wantsFullScreen === true);
});
};
function DialogController($scope, $mdDialog) {
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.answer = function(answer) {
$mdDialog.hide(answer);
};
}
//initial loading
$scope.LoadMore();
});
body {
background: #eeeeee;
}
html {
background: #eeeeee;
}
.gridListdemoBasicUsage md-grid-list {
margin: 8px;
}
.gridListdemoBasicUsage .green {
background: #b9f6ca;
}
.gridListdemoBasicUsage md-grid-tile {
transition: all 400ms ease-out 50ms;
}
.responsiveImage {
max-width: 100%;
max-height: 100%;
}
md-content {
background: #eeeeee;
position: relative;
}
.fit {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.toolbardemoScrollShrink .face {
width: 48px;
margin: 16px;
border-radius: 48px;
border: 1px solid #ddd;
}
.md-toolbar-tools {
background-color: #259b24;
}
.dialogdemoBasicUsage #popupContainer {
position: relative;
}
.dialogdemoBasicUsage .footer {
width: 100%;
text-align: center;
margin-left: 20px;
}
.dialogdemoBasicUsage .footer,
.dialogdemoBasicUsage .footer > code {
font-size: 0.8em;
margin-top: 50px;
}
.dialogdemoBasicUsage button {
width: 200px;
}
.dialogdemoBasicUsage div#status {
color: #c60008;
}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.7/angular-material.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular-animate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular-aria.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.7/angular-material.min.js"></script>
<body ng-app="app" ng-controller="GalleryCtrl as gc" ng-cloak="" id="popupContainer" class="gridListdemoBasicUsage dialogdemoBasicUsage">
<md-toolbar md-scroll-shrink="" ng-if="true" ng-controller="TitleController">
<div class="md-toolbar-tools">
<h3><span>{{title}}</span></h3>
</div>
</md-toolbar>
<md-content style="height:100vh" />
<md-grid-list md-cols-xs="1" md-cols-sm="2" md-cols-md="4" md-cols-gt-md="6" md-row-height-gt-md="1:1" md-row-height="2:2" md-gutter="12px" md-gutter-gt-sm="8px">
<md-grid-tile ng-click="ShowDetails($event, n.id)" ng-repeat="n in Images" class="green">
<img class="responsiveImage" src="{{n.src}}">
<md-grid-tile-footer>
<h3>Photo number {{n.id}}</h3>
</md-grid-tile-footer>
</md-grid-tile>
</md-grid-list>
<section layout="row" layout-sm="column" layout-align="center center" layout-wrap="">
<md-button class="md-raised md-primary" ng-click="LoadMore()">Primary</md-button>
</section>
</body>
Go fullscreen, scroll to the bottom of the page, and press a button to load more images. The problem I'm having: I am trying to get the toolbar at the top of the screen to disappear when scrolling down, and appear again when scrolling up. However, 2 scrollbars appear, and only the right one affects the toolbar.The left scrollbar actually scrolls all the way down on the page.
My desired situation: only 1 visible scrollbar to scroll down the entire gallery, that also makes the toolbar appear and disappear. How do I do this?
try adding overflow-y: hidden; to the body css rule.
I am trying to implement correctly scaling and zooming in css way. I created an example with scaled view. When click, the view should be zoomed and then to be able to scroll.
https://jsfiddle.net/opb5tcy8/4/
I have several issues with it:
Can I somehow get rid of the margin-left and margin-top on the .zoomed class? I did not manage to scale it without necessity to shift it with these margins.
When clicked, I can get the click position by clientX. I would like to use it to fluently scroll to the clicked position during zooming. However I can't manage the scroll to be fluent and when removing the margin-left it is kind of jumpy and not nice.
When you zoom in and move the scroll to the center and then zoom out, you can see the zoom is not nice as it first scrolls to the right. Is there a way to prevent it?
When you scroll to corners in Chrome on OSX it tends do navigate back/forward in browser. Is there a way to prevent this behaviour?
UPDATE:
The first part can be solved with transform-origin: 0 0. The other issues stays mostly the same as it is demonstrated.
Hm... I could say it is impossible to satisfy point 2 your condition with current browsers' support. The other are possible, as in this demo:
$(document).ready(function() {
var windowHalfWidth = $("#window").width() / 2;
var scalingFactor = 0.55;
var throtte = false;
$("#slider").click(function(event) {
//Simple event throtte to prevent click spamming breaking stuff up
if (throtte) return false;
throtte = true;
setTimeout(function() {
throtte = false;
}, 1000);
var xSelf = event.pageX - $("#window").offset().left + $("#window").scrollLeft();
if ($(this).hasClass("zoomed")) {
$("#window").animate({
scrollLeft: (xSelf / scalingFactor - windowHalfWidth)
}, 1000, "linear");
} else {
$("#window").animate({
scrollLeft: (xSelf * scalingFactor - windowHalfWidth)
}, 1000, "linear");
}
$("#slider").toggleClass("zoomed");
});
});
body {
background-color: #eee;
margin-top: 10px; /*reduced margin for easier view in SO */
}
#window {
width: 500px;
height: 200px;
margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;
border: 1px solid #999;
position: relative;
background-color: white;
}
#slider {
width: 900px;
height: 600px;
background-color: #fff;
position: absolute;
transition: 1s linear;
top: 0;
left: 0;
transform-origin: 0 0;
}
#slider.zoomed {
transform: scale(0.55);
}
#slider div {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
top: 75px;
background-color: #eee;
text-align: center;
}
#obj1 {
left: 10px;
}
#obj2 {
left: 210px;
}
#obj3 {
left: 410px;
}
#obj4 {
left: 610px;
}
#obj5 {
left: 810px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="window">
<div id="slider" class="zoomed">
<div id="obj1">1</div>
<div id="obj2">2</div>
<div id="obj3">3</div>
<div id="obj4">4</div>
<div id="obj5">5</div>
</div>
</div>
As you can see, the zooming & scrolling is quite laggy, especially when the far right size is zoomed in.
The reason is simple, because jQuery and css both have their own animation loop, and they are not in sync. In order to solve this we'll need to somehow manage to do both scrolling & scaling animations with only one system, either jQuery or CSS.
Problem is: jQuery don't have a scaling feature, and css can't scroll elements. Wonderful.
If your scaling can be done with width/height though, it would be possible, using jquery width&height animate(). But if the #slider consists of many components I guess it can't be done.
So um writing an answer just to say it's impossible is kind of a let down, so I think maybe I can suggest an alternative, using dragging to scroll content (similar to the way Google map work):
var windowHalfWidth, startX, startLeft, minLeft, dragging = false,
zooming = false;
var zoomElement = function(event) {
var xSelf = event.pageX - $("#window").offset().left - parseFloat($("#slider").css("left"));
if ($("#slider").hasClass("zoomed")) {
minLeft = windowHalfWidth * 2 - 900;
var newLeft = Math.min(Math.max((-(xSelf / 0.55 - windowHalfWidth)), minLeft), 0);
$("#slider").css("left", newLeft + "px");
} else {
minLeft = windowHalfWidth * 2 - 900 * 0.55;
var newLeft = Math.min(Math.max((-(xSelf * 0.55 - windowHalfWidth)), minLeft), 0);
$("#slider").css("left", newLeft + "px");
}
$("#slider").toggleClass("zoomed");
}
$(document).ready(function() {
windowHalfWidth = $("#window").width() / 2;
minLeft = windowHalfWidth * 2 - 900 * 0.55;
$("#slider").on({
mousedown: function(event) {
dragging = true;
startX = event.pageX;
startLeft = parseFloat($(this).css("left"));
},
mousemove: function(event) {
if (dragging && !zooming) {
var newLeft = Math.min(Math.max((startLeft + event.pageX - startX), minLeft), 0);
$("#slider").css("left", newLeft + "px");
}
},
mouseup: function(event) {
dragging = false;
if (Math.abs(startX - event.pageX) < 30 && !zooming) {
// Simple event throtte to prevent click spamming
zooming = true;
$("#slider").css("transition", "1s");
setTimeout(function() {
zooming = false;
$("#slider").css("transition", "initial");
}, 1000);
zoomElement(event);
}
},
mouseleave: function() {
dragging = false;
}
});
});
body {
background-color: #eee;
margin-top: 10px; /*reduced margin for easier view in SO */
}
#window {
width: 500px;
height: 200px;
margin: 0 auto;
overflow: hidden;
border: 1px solid #999;
position: relative;
background-color: white;
}
#slider {
width: 900px;
height: 600px;
background-color: #fff;
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
}
#slider.zoomed {
transform: scale(0.55);
}
#slider div {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
top: 75px;
background-color: #eee;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#obj1 {
left: 10px;
}
#obj2 {
left: 210px;
}
#obj3 {
left: 410px;
}
#obj4 {
left: 610px;
}
#obj5 {
left: 810px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="window">
<div id="slider" class="zoomed">
<div id="obj1">1</div>
<div id="obj2">2</div>
<div id="obj3">3</div>
<div id="obj4">4</div>
<div id="obj5">5</div>
</div>
</div>
This variation manages to get CSS to do both animation, by sacrificing the scrollbar (which is pretty ugly imo, who needs it?) and use css left instead.
So I hope if in the end you can't find a good solution, at least you have this to consider as fall back version.
I'll address the points individually and then give an example at the end.
When clicked, I can get the click position by clientX. I would like to
use it to fluently scroll to the clicked position during zooming.
In my opinion scroll animations during transitions can be a bit choppy in webkit browsers. Try balancing the animation time of the jQuery effect with the animation time of the css transition.
When you zoom in and move the scroll to the centre and then zoom out, you can see the zoom is not nice as it first scrolls to the right. Is there a way to prevent it?
Bring the scrollLeft property of the div#window back to 0px. Again, tweaking the animation times will make this less jerky.
When you scroll to corners in Chrome on OSX it tends do navigate back/forward in browser. Is there a way to prevent this behaviour?
You could use the mouseover and mouseout events to toggle a overflow:hidden css on the body.
Here's an example change to your code:
var slider = $("#slider").on('click', function(event) {
if (!slider.hasClass('zoomed')) {
// zoom back to left position
$('#window').animate({scrollLeft:'0px'});
}else{
// zoom to click position within slider
$('#window').animate({scrollLeft:event.clientX + 'px'}, 2000);
}
slider.toggleClass("zoomed");
});
/* stop window scrolling when using slider */
slider
.on('mouseover', function () {
$(document.body).css({overflow:'hidden'});
})
.on('mouseout', function () {
$(document.body).css({overflow:'auto'});
});
And an updated fiddle.