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.
Related
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.
I'm looking for a way to easily change one of variable's value. There's a chat in a browser game that I want to make taller. Changing height in dev tools does the work:
<div class="tsbchat" style="position: relative; width: 100%; height: 160px; margin-bottom: 20px;">
But can I make i.e. a script and put it in bookmarks that will allow me to change this value with one click? How would it look like? I know it's a trivial question but I'm a noob, you can remove the question and I will find help somewhere else. Thanks in advance!
The simplest solution is to type
document.getElementsByClassName('tsbchat')[0].style.height='600px'
in your console.
Remember to add [0], because getElementsByClassName returns an array
Another way is using jQuery
function handleClick(){
$(".tsbchat").css("height", "100px"); //choose the amount you want
}
.tsbchat{
position : relative;
width : 100%;
height : 160px;
margin-bottom: 20px;
border: 1px solid black;
}
<body>
<div class="tsbchat" onclick="handleClick()">Hello</div>
</body>
This way you can make bigger your div but only once
Use this script instead if you need to use several times:
function handleClick(){
$(".tsbchat").css("height", function(){
return $(".tsbchat").css() + 100;
});
}
Note: not sure if this way you have to specify the "px" but i'm quite sure this works
For using a javascript function as bookmark you need to use bookmarklet.You can read up more here about it Bookmarklet.
For example.
javascript:( alert(' Hello i am clicked from bookmark '));
Add this to destination of bookmark. so as soon as you click on bookmark you will see a Hello i am clicked from bookmark alert.
You can do it like this
Here handleClick is a function which will be called when you click on div.Than we select the element by class name and change it's style.
function handleClick(){
let element = document.getElementsByClassName('tsbchat');
element[0].style.height = "1000px"; //chnage to amount you want
}
.tsbchat{
position : relative;
width : 100%;
height : 160px;
margin-bottom: 20px;
border: 1px solid black;
}
<body>
<div class="tsbchat" onclick="handleClick()">Hello</div>
</body>
I am creating an window with a significant initialization process and I would like to keep the window hidden until init finishes. Right now at the beginning of my js code I hide the window right after it is created and then show it when init is complete. But this creates a less than pleasing flash when the app is launched as the window appears, disappears and then re-appears.
Is there a way to keep the window invisible while the init runs?
My best guess, without seeing your code, is that you need to hide the application window using CSS in the head section of your page. This way it is hidden before the browser ever renders the page. Trying to hide the window with Javascript won't work as nicely. That's because the script can't hide the window until after the browser creates it. So, depending on conditions, the user might see it flash on start.
The snippet below shows how to do this using the CSS visibility attribute. Alternatively, you may also use the display attribute.
Show and then run the snippet to try.
setTimeout(function() {
// some long init process here
// make visible on ready
window.spinner.style.display = 'none';
window.app.style.visibility = 'visible';
}, 3000);
#app {
height: 10em;
visibility: hidden;
background-color: white;
}
h3,
h4 {
margin: 0;
padding: 4px;
color: white;
background-color: steelblue;
}
#spinner {
height: 100px;
position: absolute;
}
body {
background-color: lightgray;
}
<h3>Header</h3>
<div id="content">
<img id="spinner" src="http://i.stack.imgur.com/kOnzy.gif">
<div id="app">APPLICATION READY</div>
</div>
<h4>footer</h4>
I agree with #jeff about providing some sort of progress indicator. However, the standard way to create a window that's hidden by default in Electron is to use the show option when creating the browser window:
const myWindow = new BrowserWindow({ show: false });
Then when loading/processing is finished you can make the window visible:
// this code runs in the renderer process
import { remote } from 'electron';
remote.getCurrentWindow().show();
Hide it first with CSS. display: none or visibility:hidden.
Then show with javascript by changing display or visibility after init.
I have started using AngularJS with some code that was already written and need to get it to play nice together.
So I have
<html ng-app="MainPage">
<head>
...Some JS includes
</head>
<body>
<div id="divDropDownMenu" class="DropDownMenu">
....AngularJS stuff in here
</div>
</body>
I'm using this code to append a button at the end of "divDropDownMenu" and when the button is clicked slide the up and down to reveal the menu items.
var divPanel = $("<div class='slide-panel'>");
var divContent = $("<div class='content'>");
(function ($, $scope) {
$.fn.slideBox = function(params){
var content = $(this).html();
var defaults = {
width: "100%",
height: "500px",
position: "top" // Possible values : "top", "bottom"
}
// extending the function
if(params) $.extend(defaults, params);
$(divContent).html(content);
$(divPanel).addClass(defaults.position);
$(divPanel).css("width", defaults.width);
// centering the slide panel
$(divPanel).css("left", (100 - parseInt(defaults.width))/2 + "%");
// if position is top we're adding
if(defaults.position == "top")
$(divPanel).append($(divContent));
// adding buttons
$(divPanel).append("<div class='slide-button'>Open Menu</div>");
$(divPanel).append("<div style='display: none' id='close-button' class='slide-button'>Close Menu</div>");
if(defaults.position == "bottom")
$(divPanel).append($(divContent));
//$(this).replaceWith($(divPanel));
// Buttons action
$(".slide-button").click(function(){
if($(this).attr("id") == "close-button")
$(divContent).animate({height: "0px"}, 1000);
else
$(divContent).animate({height: defaults.height}, 1000);
$(".slide-button").toggle();
});
};
})(jQuery);
function SlidePanelExpandCollapse(ExpandCollapse)
{
if (ExpandCollapse == "Expand") {
$(divContent).animate({ height: defaults.height }, 1000);
}
else {
$(divContent).animate({ height: "0px" }, 1000);
}
$(".slide-button").toggle();
}
The problem is that any angular inside the targeted div does not fire when using the above code.
this is the CSS that goes with the above JS menu slider
/* #override
http://samuelgarneau.com/slidebox.css
http://samuelgarneau.com/lab/validator/slidebox.css
http://samuelgarneau.com/lab/slidebox.css
http://samuelgarneau.com/lab/slidebox/style/slidebox.css
*/
body {
margin: 0;
padding: 75px 0 0;
}
.slide-panel {
z-index: 9999;
width: 5px;
position:absolute;
}
.bottom {
bottom: 0;
}
.right {
}
.left {
position: absolute;
left: 0;
}
.top {
top: 0;
}
.content {
margin-left: auto;
margin-right: auto;
z-index: 10;
overflow: hidden;
text-align: left;
background-color: #343434;
height: 0;
width: 100%;
color: #fff;
}
.slide-button {
background: none repeat scroll 0 0 gray;
margin-left: auto;
margin-right: auto;
position:relative;
width: 150px;
z-index: 20;
cursor: pointer;
height: 30px;
padding-top: 10px;
text-align: center;
}
.slide-button:hover {
color: #ffffff;
}
I don't see any actual use of AngularJS in your example at all. The only thing which reminded me of AngularJS was the mention of $scope in your function definition. Now while AngularJS appears to work magically in some areas this still won't do anything.
Also it might appear tempting to keep existing code and just add some AngularJS parts. However seeing your example I would recommend that you rewrite this functionality using the means of AngularJS. Showing and Hiding stuff can be easily done with ng:hide or ng:show. The animation stuff you do can be done with ng:animate. And if you need to dynamically show data, put it into a model (in your scope) and use that with functions like ng:repeat.
It appears that what you are doing in your example would boil down to only a couple of lines using the AngularJS functionality, so the result would be better and easier to read and maintain. Do yourself a favor and get familiar with what AngularJS can provide you with and stop bothering with direct DOM manipulation. It is a bad pattern. DOM manipulation is pesky, complicated and prone to break. It is also usually an unmaintable mess. And the best: If you are using AngularJS anyway, it is complete superflous because everything can be achieved much easier by having a model triggering conditional logic in your HTML.
Some impressive fact from the talk of the AngularJS creator at Google I/O 2013: He used AngularJS in its beginning to rewrite a internal project of Google. The result was that 14000 lines of code were reduced to 1500.
I recognize that this does not really count as an answer to your problem but I really believe that you would be better off stopping this approach right here and now and instead of wasting time to get this working rewrite it in AngularJS. This seriously should not take longer than half an hour even if you have to read up all the details still.
Edit/Addendum: The talk I mentioned is "Google I/O 2013 - Design Decisions in AngularJS" at http://www.youtube.com/watch?v=HCR7i5F5L8c I highly recommend watching this video even to people who have already experience with AngularJS. It gives good insight to the AngularJS way and its points come handy when trying to convince someone else in trying AngularJS :)
Edit/Addendum2: As Sprottenwels helpfully mentioned above, there is another question here on stackoverflow which gives a much more thorough explanation of what I boiled down above, so please give it a read: "Thinking in AngularJS" if I have a jQuery background?
Edit/Addendum3: As again Sprottenwels helpfully mentioned: The videos at http://www.egghead.io/lessons are a great resource. I personally found them sometime a little hard to understand (you might need to stop the video and read up in the documentation of AngularJS which thankfully is nowadays much better than it used to be).
Oh and on a personal note: While I did web development since about 1997, I was never a friend of doing application like stuff in JavaScript because all those frameworks are so complicated with lots of boilerplate and you are doing stuff which feels like a waste of time. AngularJS really did wonders to my motivation doing such stuff because it finally is totally logical and its magically like inner workings totally freed me from doing stuff I hated like synchronisation of data and view.
I am totally thankful to the AngularJS people and I absolutely believe that this is the only real future of doing web application programming. Right now AngularJS can be a problem performance-wise because of doing "bad" stuff like dirty-checking but this is going to change with new browser features like Object.observe. So I really think that choosing to use AngularJS to its full extent is a wise and future-safe move.
In my backbone.js application, I'm trying to fade in the view element after it's been appended. However it doesn't work.
Live example here: http://metropolis.pagodabox.com
var itemRender = view.render().el;
$('#items-list').append(itemRender);
$(itemRender).addClass('show');
However if I add a small setTimeout function, it works.
var itemRender = view.render().el;
$('#items-list').append(itemRender);
setTimeout(function(){
$(itemRender).addClass('show');
},10);
Using fadeIn() also works but I prefer to use straight CSS for the transition as it's more efficient, and prefer not to use any setTimeout "hacks" to force it to work. Is there a callback I can use for append? Or any suggestions? The full code is below:
itemRender: function (item) {
var view = new app.ItemView({ model: item }),
itemName = item.get('name'),
itemRender = view.render().el;
$('#items-list').append(itemRender);
$(itemRender).addClass('show');
app.itemExists(itemName);
}
CSS/LESS:
#items-list li {
padding: 0 10px;
margin: 0 10px 10px;
border: 1px solid #black;
.border-radius(10px);
position: relative;
.opacity(0);
.transition(opacity)
}
#items-list li.show {.opacity(1)}
This "hack" you mention (or some variant of it) is occasionally necessary for web development, simply due to the nature of how browsers render pages.
(NOTE: This is all from memory, so while the overall idea is right please take any details with a small grain of salt.)
Let's say you do the following:
$('#someElement').css('backgroundColor', 'red');
$('#someElement').css('backgroundColor', 'blue');
You might expect to see the background color of #someElement flash red for a brief moment, then turn blue right? However, that won't happen, because browsers try to optimize rendering performance by only rendering the final state at the end of the JS execution. As a result, the red background will never even appear on the page; all you'll ever see is the blue.
Similarly here, the difference between:
append
set class
and:
append
wait 1ms for the JS execution to finish
set class
Is that the latter allows the element to enter the page and AFTER the JS is executed have its style change, while the former just applies the style change before the element gets shown.
So while in general window.setTimeout should be avoided, when you need to deal with these ... complications of browser rendeering, it's really the only way to go. Personally I like using the Underscore library's defer function:
var itemRender = view.render().el;
$('#items-list').append(itemRender);
_(function(){
$(itemRender).addClass('show');
}).defer();
It's the same darn thing, but because it's encapsulated in a library function it feels less dirty to me :-) (and if the "post-render" logic is more than a line or two I can factor it in to a Backbone View method and do _(this.postRender).defer() inside my render method).
You can use CSS animations
#keyframes show {
0% { opacity: 0; }
100% { opacity: 1; }
}
#items-list li {
padding: 0 10px;
margin: 0 10px 10px;
border: 1px solid #black;
.border-radius(10px);
position: relative;
}
#items-list li.show {
animation: show 1s;
}