I'm trying to create a custom glimpse plugin that shows us some information from our server.
When I open the page I get all the data I need but I want to be able to update this data once every 20 seconds(or when i click on a button in the tab) without having to refresh the entire page.
I've managed to add my JavaScript to the page and subscribe to the render and shown events, but i don't know how to update the tab content when something happens.
This is my tab
public class EagleTab : AspNetTab
{
private readonly IGlimpseInterventionService _glimpseInterventionService;
public EagleTab()
:this(new GlimpseInterventionService()){}
public EagleTab(IGlimpseInterventionService glimpseInterventionService)
{
_glimpseInterventionService = glimpseInterventionService;
}
public override object GetData(ITabContext context)
{
var interventionSection = new TabSection("Last modification", "Last Message","Time since last modification","CSE","DPS", "Start Date","End date");
var now = DateTime.Now;
var twoHoursThresshold = new TimeSpan(1,0,0);
foreach(var inv in _glimpseInterventionService.GetActiveInterventions()){
var timeSinceLastMod = now - inv.LastModification;
interventionSection.AddRow()
.Column(inv.LastModification)
.Column(inv.LastMessage)
.Column(timeSinceLastMod.ToString("c"))
.Column(inv.CSEName)
.Column(inv.DPSName)
.Column(inv.StartDate)
.Column(inv.EndDate).WarnIf(timeSinceLastMod<twoHoursThresshold);
}
var plugin = Plugin.Create("Section", "Data");
plugin.AddRow().Column("Active interventions").Column(interventionSection);
return plugin;
}
public override string Name
{
get { return "Eagle Tab"; }
}
}
And this is the JavaScript
(function ($, pubsub, tab, render) {
'use strict';
function refreshTabContent(){
//what am I supposed to do here
}
pubsub.subscribe('action.panel.rendering.eagle_glimpse_plugins_eagletab', function (args) {
});
pubsub.subscribe('action.panel.showed.eagle_glimpse_plugins_eagletab', function (args) {
setTimeout(refreshTabContent,30000);
});
})(jQueryGlimpse, glimpse.pubsub, glimpse.tab, glimpse.render);
As you can see in the js there is a function called refreshTab i want there to update the content of the tab.
I know that i could make an Ajax call to a controller of mine get the data and then try updating the panel using jQuery but that just seams a bit wrong and i'm hoping there's a better way.
Any tutorial or documentation about glimpse client side extensibility would be welcomed as well.
You have gotten a fairly large amount of the way towards your goal. Unfortunately though there isn't really a way of getting data from a tab outside of a request. That said, there is a "Glimpse" way of getting data from the server. This is small semantic difference, but it has to do with server data, vs request data.
If I was you, I would probably write this as a client side only tab and not implement AspNetTab. Here are some examples of how this can be done. Next I would implement a Resource. Unfortunately its not very well documented but fortunately its not very hard to work with.
This repo has some examples of how to work with client tabs back to resources. Specifically the Inventory tab is a tab that lets people mouse over products in the site and have the tab show stock levels. Here is the resource and here is the client code that interacts with the resource (given what you have so far, this should be fairly easy to adapt. Lastly, as a bonus, if you haven't seen it already, here is how to include your script into your page. Note, the commits on that repo are the step by step guid to how things come together.
Let me know if that helps.
Related
Ok so im messing around with Backbone for the first time. I think I've pretty much covered all the basics of frontend logic, but i have never really been any good at backend logic and coding.
I'm working with wordpress and creating a theme using backbone. My understanding is as long as i set up a template page that has the correct containers that my backbone code will render views in, the fact that it's a wordpress theme instead of it's own app shouldn't really change anything on the frontend side.
I'm at the stage where i want to save a model so that i can fetch it in my routes to link to my view to render.
I'm unsure about the whole process of saving data. I know i need to give the model attribute 'urlRoot' a string but i don't know what that string should be, and what happens after that.
Can someone explain the whole process, especially in terms of how to do it with Wordpress. (i did stumble upon the WP REST API plugin that i think helps, although i don't exactly know how.)
EDIT
OK so in the end i presume my problem was something to do with authentication when trying to access the database as the textResponse was just returning the entire HTML for the current page i was on, probably due to the fact it wasn't getting through to the database and being redirected back to the page.
After googling around for a while i came across this. Rather than reinventing the wheel I installed this plugin and followed the setup instructions and low and behold it worked pretty much out of the box. If your trying to build a Backbone theme i suggest using the WP-API Client JS plugin with the WP REST API plugin. Seems to cover everything.
How to expose a WordPress blog's content through an API?
WP REST API seems like a good way to start. There are a lot of options and it exposes everything you need.
Note that it is named WordPress REST API (Version 2) in the wordpress.org plugin directory.
You can test that the plugin works by navigating to:
http://www.example.com/wp-json/wp/v2/
It should output all the information on the blog as a big JSON dump.
You can also test that it works for other endpoints, like post:
http://www.example.com/wp-json/wp/v2/posts
There's a Backbone plugin for the WP REST API that works out of the box.
How to communicate with the API?
This is a simple example using Backbone without any plugin. If you want to know how to use the plugin, see the documentation for it.
Since it offers a lot of arguments that can be passed in the URL, I made a small collection and an example of how it could be used.
var API_ROOT = '/wp-json/wp/v2/',
DEFAULT_API_ARGS = ['context' /* etc. */ ];
var WordPressCollection = Backbone.Collection.extend({
constructor: function(models, options) {
options = options || {};
this.apiArgs = _.union(DEFAULT_API_ARGS, this.apiArgs, options.apiArgs);
this.args = _.extend({}, this.args, this.getApiArgs(options));
WordPressCollection.__super__.constructor.apply(this, arguments);
},
getApiArgs: function(obj) {
return _.pick(obj, this.apiArgs);
},
fetch: function(options) {
options = options || {};
options.data = _.extend({}, this.args, this.getApiArgs(options), options.data);
return WordPressCollection.__super__.fetch.call(this, options);
},
});
And to use it:
var CommentCollection = WordPressCollection.extend({
url: API_ROOT + 'comments',
// all the arguments to look for in the passed options
apiArgs: ['page', 'per_page', 'post' /* etc. */ ],
});
var myPostComments = new CommentCollection(null, {
post: 23 // id
});
console.log(myPostComments.url());
myPostComments.fetch({ page: 2 });
The fetch should make a GET request to:
/wp-json/wp/v2/comments?post=23&page=2
And from that point, the WP REST API plugin takes control. It returns a new JSON encoded array of comment objects in the body of the response.
It should looks something like this:
Backbone automatically parses the JSON received, so you don't need to worry about that and you just have to go on and use it:
myPostComments.each(function(comment) {
console.log(comment.get('author_name'));
});
Then, saving a new comment is a matter of calling:
// check the doc for the comment object details
myPostComments.create({
post: 23,
content: "my new comment",
/* etc. */
});
And this would make a POST request to /wp-json/wp/v2/comments.
Hello I have a small website where data is passed between pages over URL.
My question is can someone break into it and make it pass the same data always?
For example let say, when you click button one, page below is loaded.
example.com?clicked=5
Then at that page I take value 5 and get some more data from user through a form. Then pass all the data to a third page. In this page data is entered to a database. While I observe collected data I saw some unusual combinations of records. How can I verify this?
yes. as javascript is open on the website, everyone can hack it.
you will need to write some code on you backend to validade it.
always think that you user/costumer will try to hack you sytem.
so take precautions like, check if user is the user of the session, if he is logged, if he can do what he is trying to do. check if the record that he is trying get exists.
if u are using a stand alone site, that u made the entire code from the ashes, you will need to implement this things by yourself.
like using the standard php session, making the data validation etc.
or you can find some classes that other people have made, you can find a lot o this on google. as it is a common problem of web programing.
if u are using a backed framework that isnt from another world, probably already has one. sp, go check its documentation.
html:
<a id = 'button-one' name = '5'> Button One </a>
javascript:
window.onload = function() {
document.getElementById('button-one').onclick = function() {
changeURL(this.attributes.name.value);
};
};
function changeURL(data) {
location.hash = data;
}
Lots of time spent with other language/templating-engine combinations, however fairly new to JSF and have the "pleasure" of taking over a legacy JSF 1.1 project that uses a basic Sun JSF lib and for political reasons can not be updated to something more modern like JSF 2.2 with PrimeFaces or IceFaces, which I'd personally like to do after reading up on the capabilities of those.
The setup is a simple web app with landing page plus two tabs (Person & Address), each powered by their own Backing Beans and JSF pages. Six total navigation states as each tab starts with a "Search Form" page which leads to a "Search Results" page on submit and then a "View" page onmousedown (click action) of an individual result; for each of Person & Address data. The "Search Form" pages are session-scoped, and designed to pass search parameters around to each other in a header box entitled "User's Search Query". It does this because the "Search Results" page for Address searches is really an overloaded Person search result with Address thrown in for "Search for People by Address". Yes this could all probably be accomplished from a single page with some optional search params, but its not, and for whatever reason I'm not permitted to change the core page structure, just tasked to bug fix.
There's a long-standing bug I've been asked to fix, where one page (Person) always shows search parameters from the other (Address) when both are set, because of some incomplete logic (inside the panelGrid where the search query parameters are displayed):
<h:outputText value="Coverage Type:"/>
<h:outputText value="#{addressSearchUI.searchParameters.coverageType}"
rendered="#{empty personSearchUI.searchParameters.coverageType}"/>
<h:outputText value="#{personSearchUI.searchParameters.coverageType}"
rendered="#{!empty personSearchUI.searchParameters.coverageType}"/>
A little too overly simplistic; if a Person search's Coverage Type was set, use that, but if not, try to use the Address coverageType search parameter. Works great when only one or the other were set.
PROBLEM CASES:
Since they are session scoped, what if both of them were set in separate searches and we're on the Address page? The value from the old Person search displays (and vice versa; this is the main problem). What if neither of them are set yet? It should show a default value of ALL COVERAGE, easy enough to add but doesn't address that main problem.
SOLUTION:
Thought this would be an easy fix but I've hit a major wall trying to do either one of the following two simple things that I think would solve my problem:
A) get the session-scoped value of one page's search parameter and reset it or set to empty string (then that naiive presentation logic could be left as is)
B) call the reset button of one page programmatically from Java when backing bean init() method gets called as we switch tabs (I can call the method but am not sure how to get the original session instance rather than creating a new one, which will fire to a non-existent page UI-wise)
Here's what I've tried so far:
A) Adding an actionListener attribute to the submit button itself and trying to forcibly reset values from the other Search Form.
<h:commandButton
id="personReset"
styleClass="submitButton"
value="Reset"
action="#{transactionSearchUI.resetSearch}"/>
<h:commandButton
id="personSearch"
styleClass="searchButton"
value="Search"
rendered="#{personSearchUI.canDo['performSearch']}"
actionListener="#{addressSearchUI.resetSearch}"
action="#{personSearchUI.performSearch}"/>
B) In the backing bean of each search, try to invoke the reset button of the other:
/* utility method */
private UIComponent findComponent(String id, UIComponent where) {
if (where == null) {
return null;
}
else if (where.getId().equals(id)) {
return where;
}
else {
List<UIComponent> childrenList = where.getChildren();
if (childrenList == null || childrenList.isEmpty()) {
return null;
}
for (UIComponent child : childrenList) {
UIComponent result = null;
result = findComponent(id, child);
if(result != null) {
return result;
}
}
return null;
}
}
//... then inside init() method that is called when Person tab loads
FacesContext facesContext = FacesContext.getCurrentInstance();
UIViewRoot root = facesContext.getViewRoot();
HtmlCommandButton button = (HtmlCommandButton) findComponent("addressReset", root);
ActionEvent actionEvent = new ActionEvent(button);
actionEvent.queue();
Fails with NullPointerException, so clearly can't access one tab from the other's backing bean in this way (unless I'm missing something).
C) JavaScript approach to reset values from one tab to the other:
<script type="text/javascript">
function clearAddressSearchParams() {
document.getElementById('AddressSearch:addressSearch:addressReset').click();
document.forms['AddressSearch:addressSearch'].reset();
return false;
}
window.onload = clearStats;
</script>
Neither of those client-side methods of trying to fire the "Reset" button action are going to work, since again, the "Person" and "Address" Search Forms were setup as two totally separate beans and pages (even though one ultimately extends the other), one won't be active (or available in the DOM) so it won't find the elements.
At this point, I know there is clearly a simpler solution, but I'm at my wits end and probably coming at this from the wrong angle, so I don't know what else to do but put up a bounty for some of the JSF geniuses here. But if anyone can suggest a fix (given my limitations of older JSF technology, no adding external libs and maintaining same basic code structure), you'll get the bounty and tons of appreciation.
EDIT: To summarize all this into a single question, can anyone suggest a reliable (legacy-JSF 1.1 compatible) way to flush a session variable or reset it, independently of its page where it gets set being active?
i developed a simply.js app that fetches bus arrival time from a webservice, problem is that as of now it work only for one stop.
i want to create a configuration page with a multiselect where i could choose multiple stops , sending them to the pebble as an array and at the press of up/down buttons i want to cycle the array to show different bus stops.
Im not good in C, i prefere javascript thats because i used simply.js.
id like to know and learn how to do it, because i think online there isnt much documentation and examples.
Found a similar question/ issue at simply.js github page https://github.com/Meiguro/simplyjs/issues/11. The code example below comes from Meiguros first answer. The code sends the user to your configuration website, which you should configure to send json back.
You can probably copy the code example for enabling the configuration window and paste it in the begining of your main pebble app.js file. Do not forget to add "capabilities": [ "configurable" ], in your appinfo.json file. If you are using cloudpebble you should go to the settings page of your app and make sure the configurable box is checked.
var initialized = false;
Pebble.addEventListener("ready", function() {
console.log("ready called!");
initialized = true;
});
Pebble.addEventListener("showConfiguration", function() {
console.log("showing configuration");
//change this url to yours
Pebble.openURL('http://assets.getpebble.com.s3-website-us-east-1.amazonaws.com/pebble-js/configurable.html');
});
Pebble.addEventListener("webviewclosed", function(e) {
console.log("configuration closed");
// webview closed
var options = JSON.parse(decodeURIComponent(e.response));
console.log("Options = " + JSON.stringify(options));
});
(https:// github.com/pebble-hacks/js-configure-demo/blob/master/src/js/pebble-js-app.js - remove space after https://)
To then push the settings back to the pebble i think you need to add
Pebble.sendAppMessage(options);
just before
console.log("configuration closed");
// webview closed
I found this out at the last post on this pebble forum thread http://forums.getpebble.com/discussion/12854/appmessage-inbox-handlers-not-getting-triggered-by-javascript-configuration-data
You can aslo find a configuration website example named configurable.html in the same git as the code example at https:// github.com/pebble-hacks/js-configure-demo remove space after https://
Hope this helps a bit on the way to achieving your goal
So the configuration page is a web page, and you can host it and provide your URL as mentioned by Ankan above.
Like this:
Pebble.openURL('http://assets.getpebble.com.s3-website-us-east-1.amazonaws.com/pebble-js/configurable.html');
Lets say you decide to take the name and age of the user in the configuration page, you would have two text fields for them to enter their information, then you would have a submit button. For the submit button write a javascript function which uses jQuery to take the values of the text fields onclick, then save those values to a variable, and use JSON to send them to the phone. Here is an example of a fully created configuration web page: https://github.com/pebble-hacks/js-configure-demo
Enjoy.
Im building a site at the moment.
On the layout there are 3 flags for different countries.
Im wondering how i would go about displaying content based on what the user selects, and keeping that selection each time they come back to the site.
Obviously the first time they come to the site the default english will be shown, but once they click on a flag it would change.
Im taking im going to have to use javascript and cookies, i have been looking around and cant seem to find any examples, im wondering if someone could show me how to go about this.
Thanks
Cookies seems like the right idea:
http://www.google.co.uk/search?q=javascript+cookies
There are (probably) only two ways of doing this:
Cookies (i.e. mostly anonymous users)
Registration and getting users to login
For your needs, it sounds as though cookies would be enough.
http://www.quirksmode.org/js/cookies.html is absolutely worth reading from beginning to end.
I am giving a abstract idea of how i might do it..
In the html you write, put a javascript function which sets the flag's id in the browser cookie when you click the flag and then submit the request..
function setCookie(flag_id) //call this when the flag is clicked
{
var allcookies = document.cookie;
if(allcookies)
{
document.cookie += ';flagId=' + flag_id;
}
else
{
document.cookie='flagId=' + flag_id;
}
/*submit the form or whatever you would like to do when the flag is clicked*/
}
Thats it on the client part. You can specify the expiration time for the cookie as well.. for details you can refer the w3schools website. The cookie will stay in the browser and sent to the server on every request.
Now, on the server side, if you are using servlets, just use the following code to get the cookie in the doPost or doGet (in your case when the first request comes from the client).
.....
Cookies[] cookies = request.getCookies();
String flagId = null;
if(cookies != null)
{
for(String cookie:cookies)
{
if(cookie.getName().equals("flagId"))
{
flagId = cookie.getValue();
}
}
}
//use the flag id to decide your content here..
....
Hope this answers your question.