Custom buttons in new Google Sites - javascript

I tried to implement customized buttons on my website lately, using Google Sites, just to do a basic function: scroll to a section or to top. Didn't know that it would be so difficult...
I had to use Embed code to add my buttons (can't customize them otherwise) but this makes them displayed in an iframe.
An onclick with window.top didn't seem to work at all (or maybe I did it wrong).
My temporary solution is the following but it opens a new tab before scrolling so it's not so great :
.button-test {
background-color: #0078d0;
border: 0;
border-radius: 56px;
color: #fff;
cursor: pointer;
display: inline-block;
font-family: system-ui, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif;
font-size: 18px;
font-weight: 600;
outline: 0;
padding: 16px 21px;
position: relative;
text-align: center;
text-decoration: none;
transition: all .3s;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.button-test:before {
background-color: initial;
background-image: linear-gradient(#fff 0, rgba(255, 255, 255, 0) 100%);
border-radius: 125px;
content: "";
height: 50%;
left: 4%;
opacity: .5;
position: absolute;
top: 0;
transition: all .3s;
width: 92%;
}
.button-test:hover {
box-shadow: rgba(255, 255, 255, .2) 0 3px 15px inset, rgba(0, 0, 0, .1) 0 3px 5px, rgba(0, 0, 0, .1) 0 10px 13px;
transform: scale(1.05);
}
#media (min-width: 768px) {
.button-test {
padding: 16px 48px;
}
}
<a href="http://test.com/en#h.2f00a9eddc84963_56">
<button class="button-test" role="button">Test Button</button>
</a>
Couldn't find a function or script that makes the main/top window refresh without opening a new tab to scroll to the section.
Has anyone found a solution for this?
I really hope so... I don't understand why Google Sites is so limited.
Here's an example: sites.google.com/view/testcustombutton
From my understanding, it has something to do with the sandbox iframe automatically generated not having the allow-top-navigation option.
Is there a way to change or bypass that?

Suggestion #1 - iframes and messaging
Since your buttons are within an iframe, you need to pass the data to the parent, and you need to do it in a specific way, to avoid CORS issues (more on that later). Now, depending on how deep your iframe-inception goes, this might turn unwieldy very soon (one iframe has an iframe for a parent, which is itself a child of another iframe, and so on, up the family tree, until we reach the parent document).
In the simplest case (iframe having only one parent), this might do. Be advised, however, that is not the most advisable way to go about it, for security reasons.
In the iframe:
const myBtn = document.getElementById("myBtn");
myBtn.on("click",handleScroll);
// This is the part which communicates with the main / parent window
function handleScroll() {
window.parent.postMessage({message: <your_message>, secret: "trustMeBro"}, "*");
}
Some explanations for things done so far:
we use window.parent.postMessage to avoid cross-origin issues, and to let the info flow back to the parent document from its iframe. We couldn't allow the button click from within the iframe to have any effect on the parent document otherwise
first argument (JSON) of window.parent.postMessage(...) is a JSON, which contains both the message (message key and its value), and the secret (secret key and its value). The message is what the name suggests - an actual message for our parent document. In your case, this would be the anchored link you want your document to scroll to. The secret is your way of identifying yourself to your parent. This is not the best way to go about it, since someone could inject various nonsense to your parent page. For a better way of doing it, refer to the MDN documentation
the previous ties in with the last argument - "*" . This is the origin of the message. As the MDN documentation states:
Always provide a specific targetOrigin, not *, if you know where the other window's document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site.
Why did I set it to "*", then? Because my test cases were in localhost. For your specific case, you would set the origin to the URL of your actual location of your iframe file.
Moving on to the parent. Your main page / parent page should have this, in order to be able work with what we already have in your iframe *.html file.
window.addEventListener("message", function(event) {
// let's see what we're getting
console.log(event);
console.log(event.origin);
console.log(event.originalTarget);
console.log(event.explicitOriginalTarget);
if(event.data.secret === "trustMeBro") {
// do stuff, scroll, change HTML in the parent document, etc
console.log(event.data.message);
// do more stuff
}
});
If we're expecting messages from the outside, we need to attach an event listener for that. Before you do anything based on the received data, you should first have only console.logging of the information you received when the message event was triggered. Based on that (and experimentation) you'll build your later logic.
If you have a relay of iframes, all passing data between one another, until the message reaches the parent window, you're not doing things right.
Suggestion #2 - cookies and setInterval
Another way of handling the issue you're having is by employing cookies. This has its own problems - depending on where you are, you might have to give the users the opt-out when it comes to cookie use, and then this solution breaks the functionality of your website.
That being said, here's the code for the iframe. The entire suggestion assumes that all of your *.html files are in the same directory on your website.
const myBtn = document.getElementById("myBtn");
myBtn.on("click",setCookie);
// This is the part which communicates with the main / parent window
function setCookie() {
var cookieName = <cookie_name>;
var cookieValue = <your_message_to_parent>;
var expiresSeconds = <cookie_expiration_in_seconds>;
var d = new Date();
d.setTime(d.getTime() + (expiresSeconds*24*60*60*1000));
var expires = "expires="+ d.toUTCString();
document.cookie =
cookieName + "="
+ cookieValue + ";"
+ expires
+ ";path=/;secure;httponly;domain=<your_domain>;SameSite=Strict";
}
Explanations:
when your iframe button is clicked, this will set a cookie with a specific name - for example, btnscroll (or any other, you can name it whatever you like)
the value of the cookie should be your message to the parent window - what should it do. In your case, that would be scrolling, if that particular button was clicked
the cookie also needs to have an expiration date - if you're just handling simple things, like scrolling the parent, then the cookie should not be set to expire 10 years from now
for everything else in the document.cookie part (path, secure, etc), please refer to the MDN documentation
Let's see what we need to change in the parent.
var scrollInterval = setInterval(function() {
let cookieVal = checkForCookie(<cookie_name>); // the name that was set in your iframe
// do stuff based on what the cookieVal is
},500);
function checkForCookie(cookie) {
// let's get all of the cookies
let cookies = document.cookie;
// let's see what we have
console.log(cookies);
// ah, so the semicolon can be used
// to split this long string into an array
let cookieArray = cookies.split(';');
// let's check the array
console.log(cookieArray);
// good, now we just have to loop through
// but let's eliminate the empty spaces around
// cookie=value elements of our array
cookieArray.map(function(a) {
return a.trim();
});
for(let i = 0; i < cookieArray.length; i++) {
if(cookieArray[i].indexOf(cookie + '=') > -1) {
let ourCookieArr = cookieArray[i].split(cookie + '=');
// let's see what we have
console.log(ourCookieArr);
// ok, let's get the second element, and clear the cookie
deleteCookie(cookie);
return ourCookieArr[1];
}
}
// no cookie found
return false;
}
function deleteCookie(cookie) {
// we're setting it to an empty string
// which expires in the past
document.cookie =
cookie + "="
+ ";"
+ "Expires=Thu, 01 Jan 1970 00:00:01 GMT;"
+ "path=/;secure;httponly;domain=<your_domain>;SameSite=Strict";
}
This solution isn't the greatest, as well, because you're the constantly running the background checks if the cookie is set, and by doing that you're pestering the client's browser to check for something that happens occasionally (button click for scrolling).
The takeaway - there are ways to do what you need, but, when possible, you should avoid working with iframes. Organize your content differently, or change hosts / platforms, if that's not possible.

Related

How to convert html,css,script into a javascript

I am created a custom web chat widget using html,css,javascript and ajax calls.I want to convert or generate into a script that script is placed in any other websites or webpages that widget is loaded in their websites.for example some 3rd parties provide some widgets so we want those widgets we simply copy the script and paste into your website the widget is visible at a particular position in the website and it is worked.
I am new to this type of concepts.I don't know how to create that type of scripts.can any one tell me how to create external script links like i above mentioned in the example?
Even i don't know how to called those scripting links.
how can we generate that type of script? what type of code,software or tools are used to create that type of script links? how to write code for creating script?
There are many ways to do it. It also depends on if you use a framework or not, and on the type of widget you want to create. But below is a basic example which shows you how to create a button in the lower right corner of the page, and make it open a modal.
When you make such a script, which will be used on websites you don't own, there are rules you should follow. Here are some:
Always wrap your JS code inside an anonymous function and declare your variables with var, to avoid polluting the global scope.
Your HTML elements and CSS styles are shared with the page. Always prefix them with something specific to you, like my-widget-* to avoid breaking the page.
The people who use your widget might (not intentionally) insert your script multiple times, in multiple places. Always check whether that is the case before adding anything to the page, for example by setting one specifically named global variable as a flag (eg. myWidget).
You don't know which CSS is already on the page or not. If you want your widget to always look the same, use a CSS reset, but ONLY on your elements.
... I'm certainly forgetting other important rules. Feel free to add some. The key part is to avoid breaking other parts of the page you don't own, and making sure your widget works the same across different sites
You can try the example below by copying the code, opening your browser's JS console (F12) and pasting it in there. You should see a blue button appear in the lower right:
// When your code is executed on pages you don't own,
// always wrap your code like this so that your variables
// don't pollute the global scope of the page.
// Their name might collide with something and break the page.
(function() {
// Check whether this script has already been added to the page
// This is your ONLY global variable, name it something specific
if (typeof window.myWidget !== 'undefined') {
return; // Script already added, exit
} else {
window.myWidget = true;
}
// Inject your CSS
injectStyles();
// Inject your HTML
injectButton();
var modal = injectModal();
function injectStyles() {
// If you use an external stylesheet
/*
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://example-widget-domain.com/styles.css';
document.head.appendChild(link);
*/
// Otherwise something like this
var styles = document.createElement('style');
styles.innerHTML =
'.my-widget-btn { position: fixed; bottom: 1em; right: 1em; width: 5rem; height: 5rem; background: #0095ff; border-radius: 3rem; box-shadow: 1px 1px 3px rgba(0,0,0,.5); color: #fff; font-size: 2em; line-height: 5rem; text-align: center; cursor: pointer; } .my-widget-btn:hover { background: #0085dd; } .my-widget-hidden { display: none; } .my-widget-backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,149,255,.8); z-index: 9999; } .my-widget-modal { position: fixed; top: 4em; left: 50%; margin-left: -200px; width: 400px; background: #fff; padding: 1em; border-radius: 3px; box-shadow: 1px 1px 3px rgba(0,0,0,.2); }';
document.head.appendChild(styles);
}
function injectButton() {
var btn = document.createElement('div');
// Give it a class for styling
btn.className = 'my-widget-btn';
// Add content to it
btn.innerHTML = '#';
// Give it an event listener for clicks
btn.addEventListener('click', openWidgetModal);
// Append it to the body
document.body.appendChild(btn);
// Return it
return btn;
}
function injectModal() {
var backdrop = document.createElement('div');
backdrop.className = 'my-widget-backdrop my-widget-hidden';
backdrop.addEventListener('click', closeWidgetModal);
document.body.appendChild(backdrop);
var modal = document.createElement('div');
modal.className = 'my-widget-modal';
modal.innerHTML = '<h2>Hello world!</h2>';
backdrop.appendChild(modal);
return backdrop;
}
function openWidgetModal() {
modal.classList.remove('my-widget-hidden');
}
function closeWidgetModal() {
modal.classList.add('my-widget-hidden');
}
})();
Note: It would be too long to describe every property or function used in this example or every other possible alternatives.
If there are functions you don't know in the code above, search them individually on Google or StackOverflow to fully understand what they do, and eventually alternative ways to do these things.
Once you know these basics, you'll have knowledge about which keywords are important when searching for further info, tutorials and tools.

Get font css property shorthand from an element [duplicate]

window.getComputedStyle give the style's value in Chrome, but in firefox and Microsoft Edge it gives an empty string and in Internet Explorer, it say that it doesn't support that method. Here is my code.
Whenever the Upvote image is clicked it fires the upDownVote() function, passing two arguments. This is the HTML.
<div id="upvote" title="Click to UpVote" onClick="upDownVote('increment',<?php echo $id; ?>);"></div>
<div id="downvote" title="Click to DownVote" onClick="upDownVote('decrement',<?php echo $id; ?>);"></div>
I passed three variables to my php script through ajax; Id, type, applicable.
Type can store one value, either increment or decrement.
I wanted, even upvote button is clicked. Vote value is increase by 1 and background of button is changed. Same for the button downvote, but here is decrease in vote value. I handle this with type variable.
When upvote is clicked again (or double clicked by the user), then there must be decrement in vote value not increment. I handled this with a nested if condition inside the if condition (when type is increment). In that condition I checked if applicable is greater than one. If it is, I changed the type to decrement and applicable to 0, also the background to its original image.
But what if when user clicked the upvote button after the clicking the downvote button. In that condition applicable value is more than 1. And then must change the type to decrement. That should not happen. for this In my that nested if condition I add check the background of downvote button also. It must be the same as before when the page load.
when applicable value is more than 1 (when user clicked upvote before clicking the downvote). In my php script I increase the vote value by two.
Same logic for the downvote button.
and here is the JavaScript.
var applicable = 0; // determine applicable to vote or not.
var upvote = document.getElementById("upvote");
var downvote = document.getElementById("downvote");
var upvoteBlack = window.getComputedStyle(upvote).getPropertyValue("background");
var downvoteBlack = window.getComputedStyle(downvote).getPropertyValue("background");
function upDownVote(x, id) {
debugger;
var type = x; // determine the type(increment or decrement).
if (type === "increment") {
upvote.style.background = "url(img/image-sprite-1.jpg) 0px -40px";
applicable++; // increment in the applicable.
if (applicable > 1 && window.getComputedStyle(downvote).getPropertyValue("background") === downvoteBlack) {
type = "decrement";
applicable = 0;
upvote.style.background = "url(img/image-sprite-1.jpg) 0px 0px";
}
downvote.style.background = "url(img/image-sprite-1.jpg) -40px 0px";
} else {
downvote.style.background = "url(img/image-sprite-1.jpg) -40px -40px";
applicable++;
if(applicable > 1 && window.getComputedStyle(upvote).getPropertyValue("background") === upvoteBlack) {
type = "increment";
applicable = 0;
downvote.style.background = "url(img/image-sprite-1.jpg) -40px 0px";
}
upvote.style.background = "url(img/image-sprite-1.jpg) 0px 0px";
}
// Ajax started here.
}
CSS of upvote and downvote.
div#upvote {
width: 40px;
height: 40px;
background: url(../img/image-sprite-1.jpg);
background-position: 0px 0px;
margin: 0px auto;
margin-top: 10px;
cursor: pointer;
}
div#downvote {
width: 40px;
height: 40px;
background: url(../img/image-sprite-1.jpg) -40px 0px;
background-position: -40px 0px;
margin: 0px auto;
cursor: pointer;
}
Everything works fine but now I'm stuck. How to get the background value of buttons as window.getComputedStyle not working fine all the browsers.
I want to know is there any other property by which I can have the background property.
Also, I want to know how can I do the same thing with different logic. If I can't have the solution for window.getComputedStyle.
The shorthand property problem
background is a shorthand property, a combination of background related properties. When you set a background of pink, it is actually setting a number of background properties, just one of which is backgroundColor. For instance, it is probably actually doing the equivalent of rgb(255, 165, 0) none repeat scroll 0% 0% / auto padding-box border-box.
getComputedStyle will not return the value of shorthand properties, except in Chrome as you've discovered.
To get the computed style, look for the value of primitive properties such as backgroundColor, not that of shorthand properties such as background.
A different approach?
However, this is not really how you want to be doing things. Instead of setting styles on your elements directly, you're going to find your code to be much cleaner if you add and remove classes from your elements, and then define the rules for the classes. As you've found, setting styles directly on elements may require you to then go back and query the style, whereas with classes, you can easily query the existing class with elt.classList.has(), or toggle with .toggle(), or add, or remove.
More on getComputedStyle
getComputedStyle is a rather specialized API that should only be necessary in special situations.
For more on the issue of getComputedStyle and shorthand properties, see this question. A bug was reported against FF and you can find it here.
See this MDN page. It says that CSSStyleDeclaration (which is what is returned by getComputedStyle) has a getPropertyCSSValue method which
returns ... null for Shorthand properties.

textarea immitation is not working well. any replacements?

I have this html and css: http://jsfiddle.net/b7rDL/6/
HTML:
<div class="text-block" contenteditable="true" spellcheck="false">Some Text</div>
css:
.text-block {
resize: none;
font-size:40px;
border: none;
line-height: 1;
-moz-appearance: textfield-multiline;
-webkit-appearance: textarea;
min-width: 30px;
overflow: visible;
white-space: nowrap;
display: inline-block;
}
This code allows me to write text with no width limit or height limit. It displays no scroll bar and it grows with the text. Those are basically the features I need.
How can I convert this to regular textarea that will act the same? I want this to work on browser that doesn't implemented "contenteditable". Therefore I want to replace the div with textarea or other basiv element. How can I do it? (I don't mind using JavaScript).
How can I disable the spellchecker? spellcheck=false doesn't work. In the example, when I focus on the text box, I get that buggy red line. I am using Firefox.
How can I get rid of the border when I am focused? - SOLVED
I don't mind using JavaScript to solve those issues.
Any answer for those questions will help me.
Thanks
UPDATES:
#Oylex helped me with 3
#1
Working fiddle is here: http://jsfiddle.net/d9H9w/11/ (tested in IE8, Chrome and Firefox)
What you need is to set the width and height attributes as a user is typing within a text box.
Height
This is pretty straightforward:
Get the content of the textarea
Match for newline characters
Set the height to total number of newline characters(plus one for the first line and 1.5 for wiggle room) in em's.
Setting the height in em's makes this font-size agnostic, so it'll work with multiple font-sizes.
function getNewlines(){
// get the value(text) of the textarea
var content = textEl.value;
//use regex to find all the newline characters
var newLines = content.match(/\n/g);
// use the count of newlines(+1 for the first line + 1 for a buffer)
// to set the height of the textarea.
textEl.style.height = ((newLines && newLines.length || 0)+2.5)+'em';
};
Width
This is fairly easy, too, with one gotcha.
Get the content of the textarea
Split on newline characters to get an array consisting of lines of the textarea
Sort to get the longest line
Set the width to the length of the longest string in em's, multiplied by about .6(emRatio in my code), plus 2 ems for buffer space.
That last part is the kicker. The 'em' measurement is supposed to be a square representing the width and height that a single character takes up. This doesn't take kerning into account, so the height of a char is usually accurate, but the width is dependent on the chars around it. So, by guess and check, I figured that .6 em is about the average width of a character after kerning. .6 is pretty close, so I add 2 ems to the width for a bit of buffer space.
var emRatio = .6;
function longestLine(){
// get the value(text) of the textarea
var content = textEl.value;
// split on newline's. this creates an array, where each item in
// the array is the text of one line
var a = content.split('\n');
// use a sorting function to order the items in the array:
// longest string to shortest string
a.sort(function(a,b){return b.length - a.length});
// use the longest string * the emRatio to set the width
// Due to kerning, the letters aren't ever really 1em x 1em
// So I'm multiplying by an approximate ratio here (guess and check)
textEl.style.width = (a[0].length * emRatio + 2)+ 'em';
};
Existing problems with this implementation
To support resizing during long-held key presses, an onkeydown handler has to be included as well(this is not optimal for all cases that don't include long key presses)
All things considered, I think this fits what you need.
EDITS
Instead of having emRatio be .7, I changed it to .6 and added a buffer of 2 ems to the width. This addresses both issues #Naor mentioned in his comments.
I've updated the fiddle link and the Width section to reflect the changes.
EDIT 0
Request #1 Update
Working Solution: http://jsfiddle.net/7aeU2/
JQuery
$(function() {
// changes mouse cursor when highlighting loawer right of box
$("textarea").mousemove(function(e) {
var myPos = $(this).offset();
myPos.bottom = $(this).offset().top + $(this).outerHeight();
myPos.right = $(this).offset().left + $(this).outerWidth();
if (myPos.bottom > e.pageY && e.pageY > myPos.bottom - 16 && myPos.right > e.pageX && e.pageX > myPos.right - 16) {
$(this).css({ cursor: "nw-resize" });
}
else {
$(this).css({ cursor: "" });
}
})
// the following simple make the textbox "Auto-Expand" as it is typed in
.keyup(function(e) {
// the following will help the text expand as typing takes place
while($(this).outerHeight() < this.scrollHeight + parseFloat($(this).css("borderTopWidth")) + parseFloat($(this).css("borderBottomWidth"))) {
$(this).height($(this).height()+1);
};
});
});​
Request #2 Update
Also, here's a good explanation of why you can't outright disable spell check.
This does not belong to the realm of CSS (which is optional
presentational suggestions). It is not about stylistic features of
rendering data but about processing data interactively.
On browsers that support “spell checking” (which may involve grammar
and style checks), the HTML attribute spellcheck or the corresponding
IDL (DOM) attribute, settable in JavaScript, is effective.
In practice, those browsers tend to have “spelling checking” enabled
by default for textareas only, and as textareas normally contain human
language texts, turning it off does not sound useful. It is in any
case user-controllable (the user can switch it off or select
language).
via https://stackoverflow.com/a/9209791/1085891
Request #1
Simple Solution is pretty straight forward.
Working example: http://jsfiddle.net/b7rDL/12/
JQuery
$("#Solution0").keyup(function(e) {
while($(this).outerHeight() < this.scrollHeight) {
$(this).width($(this).width()+50);
};
});
HTML
<textarea id="Solution0" rows="1" style="height: 1.2em;"></textarea>
Fancier solution that will require some updating if you want the
width, rather than the height, to expand. Still, it's pretty nice.
http://jsfiddle.net/edelman/HrnHb/
https://github.com/ultimatedelman/autogrow
Other solutions - I know these all expand height. Let me know if you need width implementation of one of the below solutions.
http://bgrins.github.com/ExpandingTextareas/
http://blogs.sitepointstatic.com/examples/tech/textarea-expander/index.html
http://code.google.com/p/xautoresize-jquery/downloads/list
http://www.impressivewebs.com/textarea-auto-resize/
http://www.technoreply.com/autogrow-textarea-plugin-3-0/
Request #2
spellcheck="true" should work as described in the Mozilla docs: Controlling spell checking in HTML forms. It works for me in my first simple example running in Firefox 13.0.1. What version are you running?
for #3, the css option you are looking for is: outline: none;
I was having trouble figuring out the bounds of the textarea's content, so with this approach I'm copying the content of the textarea into a similarly styled p element, which is set to float: left; and then resizing the textarea based on the size of the p. This handles both width and height.
I've tested on Mac 10.8.1 FF 18.0, Safari 6.0, Chrome 25.0.1362.0 canary, iOS Safari 6.0.1 and iOS Simulator 5.1 (272.21). I don't have a PC or IE handy.
http://jsfiddle.net/b7rDL/34/
HTML
<textarea id="tx" class="text-block" spellcheck="false"></textarea>
<p id="dupe" class="text-block"></p>
CSS
.text-block {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
resize: none;
font-size:14px;
border: none;
line-height: 1;
min-width: 30px;
overflow: hidden;
white-space: pre;
display: block;
outline: none;
width: 30px;
height: auto;
border: 1px solid #ddd;
background-color: #f7f7f7;
}
#dupe {
float: left;
display: none;
width: auto;
height: auto;
}
I added a background and border so I could see what's going on.
JavaScript
// no `var` so they are global and easier to work
// with in the inspector when using jsFiddle
$tx = $('#tx');
$dupe = $('#dupe');
lineH = Number($tx.css('line-height').replace('px',''));
update();
$tx.on('keydown', function() {
setTimeout(update, 0);
});
$tx.on('propertychange input keyup change', update);
function update() {
$dupe.text($tx.val());
$tx.css({
width: $dupe.width() + 7,
height: $dupe.height() + lineH
});
}
// not sure if this is needed, leaving it because
// I don't have many browsers to test on
$tx.on('scroll', function() {
tx.scrollLeft = 0;
tx.scrollTop = 0;
});
I'm adding extra space on the right and at the bottom because it seems to perform more consistently that way. Also, in the HTML, the wrap="off" is necessary for the version of Firefox, I'm using.
I got some good tips from this blog post.
Request #2
Working Demo
<body spellcheck="false">
<div class="text-block" contenteditable="true">
Some Text SpellCheck</div>
Hi Naor, The only problem with this thing is it will disable the spellcheck for all the elements in the <body> tag. If it doesn't matter you then you can go with it.
Your question is really interesting and challenging really liked it. I hope this may help you..!!
Best efficient way which was worked for me while I did something very close in the past was creating hidden out of flow div with the same exactly styles as the textarea has. And than setting out the timeout to update its html source based on information from textarea. This sounds bit scary but yet, after some testing and playing around nothing was better, that was already suggested, so just my variant.
http://jsfiddle.net/f2gAD/16/
and jQuery based script:
var textarea = $('textarea'),
textBlock = $('div.text-block'),
interval, value, freq = 10,
doTextAreaAdjust = function(){
textarea.css({
height: textBlock.outerHeight(),
width: textBlock.outerWidth()
});
};
doTextAreaAdjust();
textarea
.focus(function(){
interval = window.setInterval(
function() {
value = textarea.val().replace(/(\r\n|\n|\r)/gm, '[rnnr]');
value = value.replace(/</gm, '||'); // break html tags
value = value.replace(/\[rnnr\]/gm, '<br>');
value = value + '|'; // or <span>|</span> for better pixel perfect
textBlock.html(value);
doTextAreaAdjust();
}, freq
);console.log(interval);
})
.blur(function(){
window.clearInterval(interval);
});
​
For performance wise did it as self starting/stopping timeout on focus/blur, though here is yet some workaround is required. While testing in Chrome noted that interval not properly stopped if you made blur by clicking on another tab. So probably replacement for self calling function into the setTimeout will be better.
It works more or less fine in IE 7-8 which suppose the main targets but still some text jumps time to time occur, while for others it is okay, but guess you will use editable feature for modern browsers. Would recommend use modernizer for its detection.
Working here
http://jsfiddle.net/H2GSx/
Code here:
HTML:
<div style="overflow: scroll; width: 200px; height: 100px;">
<div class="text-block" contenteditable="true" spellcheck="false">Some Text</div>
</div>​
CSS:
.text-block {
resize: none;
font-size:40px;
border: none;
line-height: 1;
-moz-appearance: textfield-multiline;
-webkit-appearance: textarea;
min-width: 30px;
overflow: visible;
white-space: nowrap;
display: inline-block;
}
​

Closing popup if user doesn't provide any response

I have a session time out functionality implemented, in which user is presented with pop-up window (that your session is about to expire) in case no activity is done for 30-mins.
Need help on:
When this pop up opens up and let say user has locked his desktop and doesn't provide input. Then what I want is that - if user doesn't provide any input in 1 min then this pop-up will close and new popup will display that "Session is exprired"
Can anyone please help.
Should be fairly easy to implement. Use the action listeners to detect the user action.
var userActionDetected = false;
var x = document.getElementById('yourID');
x.onclick = function (){
// some more stuff you wanna do
userActionDetected = true;
};
setTimeout(
function() {
if(!userActionDetected){
//close popups etc.
}
},
60000
)
if the popup has been created by window.open, then you can can just use .close() method like this:
var popup = window.open('some url', 'name_of_the_window');
setTimeout(function(){
popup.close();
}, 60000);
here I am just closing popup after 1 minute without any checks of input, so you need to somehow check the input.
If the question is about how to check inputs, I can provide another answer.
You can't do this with plain alert() boxes, however there are at least two options:
Show an alert, with a note that the session will expire one minute after it showed up (maybe show the exact time it will expire). If the user clicks "OK" after the time is up, it will come back and say "Sorry, your session expired."
Custom alert boxes. This can be achieved very easily by having an element cover the screen and another show the information:
Example:
<div id="mask"><div id="alert">Your session will expire soon</div></div>
CSS:
#mask {
position: fixed;
left: 0; right: 0; top: 0; bottom: 0;
/* fallback for browsers that don't support rgba() */
background: #cccccc;
background: rgba(255,255,255,0.75);
}
#alert {
position: fixed;
left: 50%;
width: 200px;
margin-left: -100px; /* half the width */
top: 20%;
background: white;
color: black;
}
You can of course customise this further with buttons and so on. jQuery provides some libraries for this, but I made a fully-customisable box (unlimited buttons with custom text and callbacks) in just 40 lines of raw JavaScript. To each his own...

Making a DOS-style window in ASP.net

I'm trying emulate the MS-DOS command prompt on my website. I don't need to accept keystrokes, but I'd like to append data at the bottom and optionally scroll upwards.
At first I looked at the asp:TextBox and asp:Label, but the flicker of using postbacks seemed to be too much. I'm now considering DIV tags and Javascript where I simply update the InnerHTML property, but there too I get flicker, and have issues with scrolling.
What solution would you recommend in this situation? Essentially I'm trying to count to infinity, with a 1 sec delay, only need the most current 300 or so entries, with the most current entry at the bottom of the screen.
Is this even possible with JS/CSS?
Do you wish to make it a little more stylous ? :)
see this page...
http://www.klaus.dk/Some_unknown_page
or this one
http://www.harryovers.com/404.html?aspxerrorpath=/Account/LoginPartial
here is the javascript source code.
http://code.google.com/p/c64-404-page/
With a little change, you can append your text on this code :)
I just built something very similar using jQuery. You can use the append method to add content to the bottom of your DIV. You can then set the scrollTop attribute to keep things scrolled to the bottom as follows:
$("#someDiv").attr({ scrollTop: $("#someDiv").attr("scrollHeight") });
I think "DOS-style window" is a bit misleading considering all you want to do is append text to a div and make sure it stays scrolled to the bottom.
function addLine(text) {
var box = document.getElementById('DOSBox') //teehee
var line = document.createElement('p');
line.innerHTML = text;
box.appendChild(line);
box.scrollTop = box.scrollHeight;
}
And style it as such
#DOSBox {
overflow: auto;
display: block;
height: 400px; width: 500px; /* or whatever */
/* and if you want it to look DOS-like */
background: #000;
color: rgb(192, 192, 192);
font-family: fixedsys;
}
#DOSBox p {
margin: 0;
}

Categories