We have an instant-messaging chat system of sort on our site. It's just basically an embedded box that lists the text with a bar at the bottom to submit new text that gets written to a file.
Currently when you submit a new message you have to refresh the page in order for it and others to show up. How do I make it so when there's a new message it automatically refreshes or displays the message?
<!-- BEGIN CHAT -->
<div id='categories' class='ipsLayout_content clearfix'>
<div id='' class='brown_box_forum brown_box_stack'>
<table class="forum_group">
<tbody>
<tr>
<td style="background: -webkit-gradient(linear, left top, left bottom, from(#412E0E), to(#513A13));
background: -moz-linear-gradient(top, #412E0E, #513A13);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#412E0E', endColorstr='#513A13');
-ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#412E0E', endColorstr='#513A13');padding-top: 1px;
font-size: 14px; font-weight:bold;" align="center">
<div id="toggleBoardStats" class="groupname" style="text-align:center;cursor:pointer;">RuneMechanics Chat</div>
</td>
</tr>
</tbody>
</table>
<table class="forum_group" id="">
<tbody>
<tr class="spacer"><td colspan="5"></td></tr>
<tr>
<td>
<div style="height: 165px; width: 100%;">
<div id="" style="height:11px; overflow-y: auto; word-wrap: break-word; text-align: left; padding: 0px; font-style:none; font-size:12px; padding-bottom:7px; padding-left: 6px;">[00:00:00] GLOBAL: <i>There is a slight delay when sending messages, please be patient. | Chatbox Feedback: Here</i></div>
<div id="ChatStream" style="height: 110px; overflow-y: auto; word-wrap: break-word; text-align: left; padding: 5px; scrollbar-face-color: #3B3B3B;"></div>
<div style="bottom: 5px; width: 100%; margin-top: 5px; padding-bottom: 5px;">
<form id="Messenger" method="POST">
<span style="padding: 5px; padding-left: 3px;">
<input id="messageText" type="text" style="width: 99%; background:#4D3F27; border: none; color: #D6C6AB;" name="message" placeholder="Message..." autocomplete="off" />
</span>
<button id="sendMessage" style="height:0; width:0; background: #392c14; border:none;">Send</button>
</form>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<script type="text/javascript">
var chatFrozen = false;
var chatOpen = true;
jQuery(function($) {
$('#ChatStream').load('../libs/Chat/chatContent.file', function(){
$('#ChatStream').animate({ scrollTop: $('#ChatStream')[0].scrollHeight }, 500);
});
window.setInterval(function(){
if ( !chatFrozen && chatOpen )
{
if ( $('#ChatStream').scrollTop() >= ( $('#ChatStream')[0].scrollHeight ) )
{
$('#ChatStream').animate({ scrollTop: $('#ChatStream')[0].scrollHeight }, 500);
}
}
}, 200);
$('#sendMessage').click(function(e) {
e.preventDefault();
$.post('../libs/Chat/Message.php', $('#Messenger').serialize(), function( data ) {
$('#ChatStream').animate({ scrollTop: $('#ChatStream')[0].scrollHeight }, 500);
});
$('#messageText').val('');
if ( $('#ChatStream').scrollTop() >= ( $('#ChatStream')[0].scrollHeight - 200 ) )
{
$('#ChatStream').animate({ scrollTop: $('#ChatStream')[0].scrollHeight}, 500);
}
});
});
</script>
<!-- END CHAT -->
You want to push information to a client instead of the client requesting it. If the client is going to request the information, he should do a request every X seconds just to check if there is some new message. That is not very scalable and gives a delay of at least a couple of seconds.
The problem is, PHP is a language that is very much intended to be used for serving data when a request is made. If you have no other languages available I would strongly advise to use an external service like Pusher.com or Pubnub.com to create real-time applications.
These services provide you with a client-side Javascript library and a server-side PHP library. You send a push message in your PHP script and it is instantly received by the clients subscribed to a channel. Great for chat applications like yours.
You can also consider using Websocket in PHP such as http://socketo.me/ to create real time, bi-directional applications between clients and servers. I believe Pusher uses the same techology.
Related
I have placed the complete code here. can you please help why the URL in the browser is pointing to a local file (file:///C:/xampp/htdocs/api/currency-converter.html) instead of it being like (http://localhost/api/currency-converter.html). Also, help me to understand why I am not able to call the public API (currency converter API) to get the JSON response. I have replaced the API key with XXXX here.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Currency Converter</title>
<style>
* {
font-family: cursive;
}
#container {
height: 150px;
margin: 0px auto;
}
h2 {
font-size: 60px;
text-align: center;
}
table {
margin: 0px auto;
}
span {
font-size: 30px;
}
input {
font-size: 30px;
border: 2px solid black;
border-radius: 10px;
text-align: center;
}
select {
font-size: 30px;
border: 2px solid black;
border-radius: 10px;
}
#result {
text-align: center;
font-size: 50px;
border-style: dashed;
}
</style>
<script>
function CurrencyConversion() {
var fromvalue = document.getElementbyID("From").value;
var tovalue = document.getElementbyID("To").value;
var xmlhttp = new XMLHttpRequest();
var url =
"http://api.exchangeratesapi.io/v1/latest?access_key=xxxxxxxxx&symbols=" +
fromvalue +
"," +
tovalue;
xmlhttp.open("GET", url, true);
xmlhttp.send();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
var result = xmlhttp.responseText;
alert(result);
}
};
}
</script>
</head>
<body onload="CurrencyConversion();">
<div id="container">
<h2>Currency Converter</h2>
<table>
<tr>
<th><span>Amount</span></th>
<th><span>From Currency</span></th>
<th><span>To Currency</span></th>
</tr>
<tr>
<td>
<input
type="Number"
id="FrmAmt"
value="1"
onkeyup="CurrencyConversion();"
/>
</td>
<td>
<select id="From" onchange="CurrencyConversion()">
<option value="USD" selected>US Dollar</option>
<option value="INR">Indian Rupee</option>
</select>
</td>
<td>
<select id="To" onchange="CurrencyConversion();">
<option value="USD">US Dollar</option>
<option value="INR" selected>Indian Rupee</option>
</select>
</td>
</tr>
<tr>
<td colspan="3">
<div id="result"></div>
</td>
</tr>
</table>
</div>
</body>
</html>
The reason why it points to a local file is because the html file is not being hosted on localhost, but rather as a file you are opening on the browser locally. If you want the file to be hosted on localhost, you can use the serve module on npm, or if you are using an IDE there are probably extensions you can install to serve your project on localhost (eg. Live Server on vscode.)
As to why the API does not work, it is really hard of someone to read your code if its formatted so poorly. Please paste it so that the code is readable. However, I have a feeling it might have something to do with your CORS configuration.
Side note: you should sanitize user input before using it, your current configuration is trivially easy to execute a XSS attack on.
I'm writing a page that has angular in it that responds to ajax requests and loads various data into a table. The angular works as expected when I type in the address, but if I use a link ( link ) to get to the page, the controller fails to load (but the html shows up). There are no page errors in the console except a resource not loaded for an image because the url is not being loaded by the angular. Here is my code:
<h1 style="text-align: center;">Product Search</h1>
<input type="text" class="form-control" placeholder="Search (Ex. ea-004, Christmas)..." id="search" style="margin-left: auto; margin-right: auto; margin-bottom: 15px;">
<div ng-app="search_results" style="text-align: center; margin-left: 0px; margin-right: 0px;">
<div ng-controller="search_results_ctl" style="text-align: center; margin-left: 0px; margin-right: 0px;">
product{{JSON.stringify(product)}}
<style>
.product:hover{
background-color: #DDDDDD;
cursor: pointer;
border:0px solid grey;
border-radius: 5px;
}
.product-selector:hover {
color: black;
}
</style>
<script>
var app = angular.module("search_results", ['angularUtils.directives.dirPagination']);
app.controller("search_results_ctl", ['$scope', function($scope){
console.log("Angular loaded...");
$scope.results = "";
$('#search').keypress(function(ev){
if(ev.which != 13){//do not add enter to search text, just submit query again
s_term = $('#search').val() + String.fromCharCode(ev.which);//append last character typed
}else{
s_term = $('#search').val();
}
$.ajax({
url: "/query",
data: {s_term: s_term},
success: function(data){
//console.log("products: " + data);
$scope.products = JSON.parse(data);
$scope.$apply();
}
});
});
}]);
</script>
<span ng-if="products != null">
<div style="width: 80%; margin: auto !important;
" dir-paginate="product in products | itemsPerPage: 10" class="row product">
<a href="/orders/new?product_id={{product.id}}" class="product-selector">
<div class="col-md-3 col-sm-3">{{product.title}}</div><div class="col-md-6 col-sm-6">{{product.description}}</div><div class="col-md-3 col-sm-3" style="text-align: center"><img src='{{product.image}}' width="50px" height="50px" style="margin-top: auto; margin-bottom: auto;"></div></a>
</div>
</span>
<span ng-if="products == null" >
<div style="background-color: #DDDDDD; border: 0px solid grey; border-radius: 5px;">
<h3 style="text-align: center;">Creating an Order</h3>
<p><strong>To start</strong>, type in the product code from the website or a key word like "christmas" or "sports". Click the product you would like to order, and it will take you to the order page.</p>
</div>
</span>
<dir-pagination-controls></dir-pagination-controls>
</div>
</div>
the link that is directing my to the page uses an href of "/products/search", which is the correct route.
Any help would be most appreciated!
Turns out after some further reading turbolinks was causing the problem. Turbolinks does not allow a full page reload, so angular never got fully bootstrapped. Here is a more thorough post on the issue: Using angularjs with turbolinks
I am a Bit new on this ..I am Replicating this Demo Example on my Local Server
http://www.bibeault.org/jqia2/chapter4/dvds/dvds.html
In Live Example Resulting data gets properly loaded ..But Not on My Machine ..My Code and css are exactly same ,
Update : Recently Tracked error :
>POST http://localhost:1701/applyFilters 405 Method Not Allowed<br/>
The HTTP verb POST used to access path '/applyFilters' is not allowed.
it is on .Net Server.... resulting data comes from this Page http://www.bibeault.org/jqia2/chapter4/dvds/applyFilters ... Do I need to completely recreate this page on My server also ?..Need some guidence
My Code:
<!DOCTYPE html>
<html>
<head>
<title>DVD Ambassador — Disc Locator</title>
<link rel="stylesheet" type="text/css" href="Styles/dvds.css">
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.js"></script>
<script type="text/javascript">
var filterCount = 0;
$(function () {
$('#addFilterButton').click(function () {
var filterItem = $('<div>')
.addClass('filterItem')
.appendTo('#filterPane')
.data('suffix', '.' + (filterCount++));
$('div.template.filterChooser')
.children().clone().appendTo(filterItem)
.trigger('adjustName');
});
$('select.filterChooser').live('change', function () {
var filterType = $(':selected', this).attr('data-filter-type');
var filterItem = $(this).closest('.filterItem');
$('.qualifier', filterItem).remove();
$('div.template.' + filterType)
.children().clone().addClass('qualifier')
.appendTo(filterItem)
.trigger('adjustName');
$('option[value=""]', this).remove();
});
$('button.filterRemover').live('click', function () {
$(this).closest('div.filterItem').remove();
});
$('.filterItem [name]').live('adjustName', function () {
var suffix = $(this).closest('.filterItem').data('suffix');
if (/(\w)+\.(\d)+$/.test($(this).attr('name'))) return;
$(this).attr('name', $(this).attr('name') + suffix);
});
$('#addFilterButton').click();
$('#filtersForm').submit(function () {
$('#resultsPane').load('applyFilters', $('#filtersForm').serializeArray());
return false;
});
/* bonus exercise code -- uncomment to enable
$('input.numeric').live('keypress',function(event){
if (event.which < 48 || event.which > 57) return false;
});
*/
});
</script>
</head>
<body>
<div id="pageContent">
<h1>DVD Ambassador</h1>
<h2>Disc Locator</h2>
<form id="filtersForm" action="/fetchFilteredResults" method="post">
<fieldset id="filtersPane">
<legend>Filters</legend>
<div id="filterPane"></div>
<div class="buttonBar">
<button type="button" id="addFilterButton">Add Filter</button>
<button type="submit" id="applyFilterButton">Apply Filters</button>
</div>
</fieldset>
<div id="resultsPane"><span class="none">No results displayed</span></div>
</form>
</div>
<!-- hidden templates -->
<div id="templates">
<div class="template filterChooser">
<button type="button" class="filterRemover" title="Remove this filter">X</button>
<select name="filter" class="filterChooser" title="Select a property to filter">
<option value="" data-filter-type="" selected="selected">-- choose a filter --</option>
<option value="title" data-filter-type="stringMatch">DVD Title</option>
<option value="category" data-filter-type="stringMatch">Category</option>
<option value="binder" data-filter-type="numberRange">Binder</option>
<option value="release" data-filter-type="dateRange">Release Date</option>
<option value="viewed" data-filter-type="boolean">Viewed?</option>
</select>
</div>
<div class="template stringMatch">
<select name="stringMatchType">
<option value="*">contains</option>
<option value="^">starts with</option>
<option value="$">ends with</option>
<option value="=">is exactly</option>
</select>
<input type="text" name="term"/>
</div>
<div class="template numberRange">
<input type="text" name="numberRange1" class="numeric"/> <span>through</span>
<input type="text" name="numberRange2" class="numeric"/>
</div>
<div class="template dateRange">
<input type="text" name="dateRange1" class="dateValue"/> <span>through</span>
<input type="text" name="dateRange2" class="dateValue"/>
</div>
<div class="template boolean">
<input type="radio" name="booleanFilter" value="true" checked="checked"/> <span>Yes</span>
<input type="radio" name="booleanFilter" value="false"/> <span>No</span>
</div>
</div>
</body>
</html>
My Css:
body {
background-image: url(backg.jpg);
}
body,td,th {
font-family: Verdana,sans-serif;
font-size: 10pt;
}
#templates {
display:none;
}
#pageContent {
width: 720px;
background-color: white;
color: #444444;
border: 2px ridge #888888;
margin: 32px auto;
padding: 8px 32px;
}
h1,h2 {
text-align: center;
}
h1,h2,h3 {
margin: 0;
}
fieldset,legend {
border: 2px ridge silver;
}
fieldset {
padding-top: 12px;
}
legend {
padding: 3px 12px;
background-color: silver;
font-weight: bold;
}
#filterPane {
margin-bottom: 16px;
}
.filterItem * {
margin-right: 4px;
margin-bottom: 4px;
}
#resultsPane {
margin-top: 14px;
}
#resultsPane span.none{
color: silver;
font-style: italic;
}
#resultsPane table {
background-color: #444444;
width: 100%;
margin-top: 12px;
}
#resultsPane th {
background-color: silver;
border: 2px outset silver;
font-size: 0.9em;
}
#resultsPane td {
background-color: white;
padding: 1px 12px;
font-size: 0.8em;
text-align: center;
}
#resultsPane td:first-child {
text-align: left;
}
input.numeric {
width: 48px;
}
input.dateValue {
width: 64px;
}
Solved
This was just needed to add in web.config for IIS7
<?xml version="1.0"?>
<configuration>
<system.webServer>
<handlers>
<add name="htm" path="*.htm" verb="*" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" resourceType="Either" />
</handlers>
</system.webServer>
</configuration>
Everybody suggestion and this post helped:
http://zhongchenzhou.wordpress.com/2011/12/05/iis-7-7-5-allow-post-requests-to-html-files/
Basically that demo is running on an Apache server, not under IIS. The dvd list at http://www.bibeault.org/jqia2/chapter4/dvds/applyFilters is only a file with no extension.
if you browser one level above http://www.bibeault.org/jqia2/chapter4/dvds/ you can see the file list.
The quick fix is to rename it to a applyFilters.html on your local version and change the load reference.
The alternative is to allow files without extensions to be loaded under IIS (which is off by default for security reasons).
Assuming you are running some kind of development server: The server does not allow POST requests. Try to deploy your code on a real server and it should work.
Someone had similar problems and it was the VisualStudio Development server which caused the problem (http://www.mojoportal.com/Forums/Thread.aspx?pageid=5&t=6383~-1).
At the moment applyFilters is accessed on your local server. You could try:
$('#resultsPane').load('http://url.to.other.server/applyFilters', $('#filtersForm').serializeArray());
But then you have cross-site scripting. You should use a local version of applyFilters (and allow POST requests).
It seems like IIS does not allow POST requests on HTML files: https://serverfault.com/a/349193/133535
I am working on a website and I have a div which is hidden when the page loads, but keeps a small gap between the top header element, and a form.
Under a certain condition, javascript is used to add a class the message div and show a message to the user, after a 5 second timer, the message is then faded out and the classes removed, with another class added to keep the gap between the header element and the form, however, this isn't working, instead when the message div is faded out, the form jumps to the position of where the message was.
Below is my StyleSheet
#message
{
height: 50px;
}
.messageBlank
{
width: 800px;
height: 50px;
background-color: transparent;
border: none;
margin-left: auto;
margin-right: auto;
}
.messageError
{
width: 800px;
height: 50px;
background-color: #ff5555;
border: solid red thin;
margin-left: auto;
margin-right: auto;
}
Below is my javascript which controls showing and hiding the message box
var timer = null;
var MessageTypeEnum = {"error":1, "workingOrComplete":2}
function showMessage(persistent, message, type)
{
clearTimeout(timer);
//$('#message').css({
// position:'absolute',
// padding: '10px',
// left: ($(window).width() - $('#message').outerWidth(true))/2
//});
$("#message")
.hide()
.html(message);
//if (type == "error")
if (type === MessageTypeEnum.error)
{
$("#message").addClass("messageError");
}
//else if (type == "workingComplete")
else if (type === MessageTypeEnum.workingOrComplete)
{
$("#message").addClass("messageWorkingComplete");
}
$("#message").fadeIn("slow");
if (!persistent)
{
timer = setTimeout("hideMessage()", 5000);
}
}
function hideMessage()
{
$("#message")
.fadeOut("slow", function()
{
$("#message").removeClass("messageError");
$("#message").removeClass("messageWorkingComplete");
$("#message").addClass("messageBlank");
});
}
Below is my HTML
<body>
<div id="container">
<header>
<img src="../images/header.png" alt="header" />
<span style="font-weight: bold; padding-left: 50px; color: white; top: 0px; position: absolute;">Boardies Bug Reporter</span>
</header>
<div id="content">
<div id="errorToolbox"> </div>
<div id="message" class="messageBlank"> </div>
<form action="javascript:validate();" novalidate>
<table>
<tr>
<td>Username: </td>
<td>
<input type="text" id="txtUsername" name="txtUsername" autofocus required placeholder="Username" />
</td>
</tr>
<tr>
<td>Password: </td>
<td>
<input type="password" id="txtPassword" name="txtPassword" required placeholder="Password"
</td>
</tr>
<tr>
<td> </td>
<td class="buttonGroup">
<input type="submit" value="Submit" />
<input type="reset" value="Reset" />
</td>
</tr>
</table>
</form>
</div>
If you want to keep a gap you should use fadeTo() method. For example to hidde element you can do:
$("#message").fadeTo( 200, 0, function()...
and to show
$("#message").fadeTo( 200, 1);
Where 200 is time in ms of how fast your animation should work.
This method will just change opacity of element and will keep it original height
This should have been pretty straightforward using the DOM but I seem to be getting undefined errors.
Basically, I'm trying to say, when a user clicks a button hide one form and replace it with another. Hiding it should have been as simple as setting style.display : none; but it seems style is constantly undefined.
Here's the script
function hideTextForm()
{
var textForm = document.getElementsByClassName("my-text-form");
//var formContent = textForm.contentDocument;
console.log(formContent);
//textForm.visibility='false';
//textForm.visible(false);
//textForm.style.visibility = "hidden";
//formContent.display = "none";
formContent.style.display = "none";
console.log(textForm);
/*this returns:
<div class="my-list-form">
<form id="list-form" class="list-form" name="list-form">
<label>list form here</label>
</form>
</div>*/
console.log("Text form should be hidden");
}
This is only half the different attempts. My gut tells me that the way I'm calling the element is wrong with getElementsByClassName. I'm either calling the wrong element or trying to display it wrong.
Heres the HTML:
<div class="analysis">
<div class="analysis-columns">
<div class="analysis-static">
<table align = "left" border ="1" id="static-column-table" class="my-columns" >
<tr id="tr-static">
<th id="table-comment-head">
<b>Comments</b>
</th>
</tr>
<tr><td><button class="column-button" value="Page Description">Page Description</button></td></tr>
<tr><td><button class="column-button" value="Keywords">Keywords</button></td></tr>
<tr><td><button class="column-button" value="Files">Files</button></td></tr>
<tr><td><button class="column-button" value="Internal Links">Internal Links</button></td></tr>
<tr><td><button class="column-button" value="External Links">External Links</button></td> </tr>
</table>
</div>
<div class="analysis-custom">
<table border ="1" align="right" id="custom-column-table" class="my-columns" >
<tr id="tr-custom">
<th>Custom</th>
</tr>
<tr><td><button class="column-button" value="Page Description">Page Description</button></td></tr>
<tr><td><button class="column-button" value="Keywords">Keywords</button></td></tr>
<tr><td><button value="Add">Add New Field+</button></td></tr>
</table>
</div>
</div>
<div class="analysis-form">
<input type="radio" name="type-of-row" value="List" title="List" onclick="hideTextForm();"/> List</br>
<input type="radio" name="type-of-row" value="Text" title="Text" onclick="hideListForm();"/> Text</br>
<select>
<optgroup label="Type of Row">
<option>List</option>
<option>TextBox</option>
</optgroup>
</select>
</br>
<div class="my-list-form">
<form name ="list-form" class = "list-form" id="list-form">
<label>list form here</label>
</form>
</div>
<div class="my-text-form">
<form name="text-form" class = "text-form" id="text-form">
<label>text form here</label>
<!--<textarea cols="30" rows="2">Enter the name of your new Row here...</textarea>
<button value="Page Description" onclick="addRow()">New TextField</button>-->
</form>
</div>
</div>
</div>
And finally relevant CSS:
div.analysis
{
padding: 1px;
width: 100%;
border: .2em solid #ffcc00;
}
div.analysis-columns
{
/* border-style: solid;*/
border: .2em solid #900;
float: left;
width:55%;
/*border: 5;
border-color: #8a2be2;*/
display: inline;
}
div.analysis-static
{
margin: auto;
padding: 1px;
width:47%;
float:left;
border: .2em solid #0000ff;
/*border: 3;
border-color: #0000FF;*/
/*border-collapse:collapse;*/
font-family: Century Gothic, sans-serif;
}
div.analysis-custom
{
margin: auto;
border: .2em dotted #FFFFDD;
padding: 1px;
float: right;
width:47%;
}
div.analysis-form
{
margin: auto;
width:43%;
border: .2em ridge #b22222;
float: right;
}
div.my-list-form
{
display: inherit;
}
div.my-text-form
{
display: inherit;
}
If anyone is having trouble visualizing it or running it, basically I have a small panel called analysis. Within this panel, is 2 tables (left) and one changing form on the right.
my-list-form and my-text-form should be the only css to worry about.
I'm convinced I'm calling the element wrong so please take a look at document.getElem("my-text-form") and what it returns.
getElmentsbyclassname returns an array
check below link
https://developer.mozilla.org/en/DOM/document.getElementsByClassName
Have a look at the method you're calling -- getElementsByClassName. Look at what it returns. It is not a DOM element -- it is something called a NodeList. This is an object a bit like an array (though technically not an array) that contains all the elements with that class name. A NodeList doesn't have a style property, so you can't set it.
You need to get the first element in the NodeList (using the array notation [0]) and set the style property of that.
var textForm = document.getElementsByClassName("my-text-form")[0];
textForm.style.display = 'none';
formContent[0].style.display = "none".
If you are working with getElementsByClassName, you're always returned an array, so you want to use the first element of that array