how do we add url parameters? (EJS + Node + Express) - node.js

I understood how we parse the url parameters in express routes, as in the example
How to get GET (query string) variables in Express.js on Node.js?
But where do the url parameters come from in the first place?
EDIT:
Apparently, I can build such a query with jquery (i.e $.get). I can append params to this query object. It s cool, but still i m trying to understand how we achieve this in the query that renders the page as a whole.
An example : when i choose the oldest tab below, how does SO add ?answertab=oldest to the url so it becomes :
https://stackoverflow.com/questions/30516497/how-do-we-add-url-parameters-ejs-node-express?answertab=oldest#tab-top

The string you're looking at is a serialization of the values of a form, or some other such method of inputing data. To get a sense of this, have a look at jQuery's built in .serialize() method.
You can construct that string manually as well, and that's pretty straight forward as well. The format is just ?var1=data1&var2=data2 etc. If you have a JSON object {"name": "Tim", "age": 22} then you could write a very simple function to serialize this object:
function serializeObject(obj) {
var str = "?";
for(var i = 0; i < Object.keys(obj).length; i++) {
key = Object.keys(obj)[i];
if (i === Object.keys(obj).length - 1)
str += encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]);
else
str += encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]) + "&";
}
return str;
}
Running seralizeObject({"name": "Tim", "age": 22}) will output '?name=Tim&age=22'. This could be used to generate a link or whatnot.

The page author writes them so. This is how they "come in the first place". The authors of an HTML page decide (or are told by website designers) where to take the user when he clicks on a particular anchor element on it. If they want users to GET a page with some query parameters (which their server handles), they simply add query string of their choice to the link's href attribute.
Take a look at the href attribute of the oldest tab you clicked:
<a
class="youarehere"
href="/questions/30516497/how-do-we-add-url-parameters-ejs-node-express?answertab=oldest#tab-top"
title="Answers in the order they were provided"
>
oldest
</a>
When you clicked it, the browser simply took you to path indicated in href attribute /questions/30516497/how-do-we-add-url-parameters-ejs-node-express?answertab=oldest#tab-top relative to the base URL http://stackoverflow.com. So the address bar changed.
stackoverflow.com may have its own system of generating dynamic HTML pages. Their administrators and page authors have configured their server to handle particular query parameters and have put in place their own methods to make sure that links on their pages point to the URL(including query string) they wish.
You need to provide URIs with query strings of your choice (you can build them using url.format and querystring.stringify) to your template system to render. Then make your express routes process them and generate pages depending on their value.

Related

Getting value of key from Web Content Display Portlet

I got a requirement. I have added two text fields Value and Key from structure in Web Content Display portlet.
right now in the portlet i am getting value from hard code like below.
BasicModel model = (BasicModel)requestContext.getFlowScope().get("BasicModel");
if(model == null){
model = new BasicModel();
}
model.setEmployeeId("AB1223344S");
model.setHireDate("01-Jan-2000");
model.setNiNumber("AB123456S");
model.setDateOfBirth("12-Dec-1980");
model.setBasicForm(new BasicDetailsForm());
}
but what i want is to get the value of each attribute from web content. Like, If i have given lfr.intel.empid as key and ABSD1822D as value in the added web content structure field like this.
and we can fetch the value of key like this.
model.setEmployeeId(lfr.intel.empid);
You can write a custom function for this which passes the key to that function, now that function will use the JournalArticleLocalServiceUtil API to get respective value from the DB.
Now you need to find How to fetch values from JournalArticleLocalServiceUtil, which you can google or this link can help you.
Thanks.
Try this, assuming that you could get the JournalArticle object, I've done it using the resourcePrimKey
long resourcePrimKey = 12345; //hard coded the resourcePrimKey
JournalArticle article = JournalArticleLocalServiceUtil.getLatestArticle(resourcePrimKey);
com.liferay.portal.kernel.xml.Document document = SAXReaderUtil.read(article.getContentByLocale("en_US"));
Node keyNode = document.selectSingleNode("/root/dynamic-element[#name='Key']/dynamic-content");
String key = keyNode.getStringValue();
Node valueNode = document.selectSingleNode("/root/dynamic-element[#name='Value']/dynamic-content");
String value = valueNode .getStringValue();

Correct way to handle pagination with form submission?

I have a form for doing a search on a search page:
<form action="{{ url_for('searchresults') }}" method="get" name="noname" id="theform">
{{ form2.page(id="hiddenpage") }}
... some form inputs
<button id = "mybutton" type = "submit" >Apply</button>
</form>
The form is a SearchForm, where
class SearchForm(Form):
page = HiddenField()
categories = SelectMultipleField(u'Text', validators=[Optional()])
# some other stuff...
The view for searchresults handles the form:
#app.route('/searchresults', methods=['GET'])
def searchresults():
form = SearchForm()
# handle the form and get the search results using pagination
page = int(request.args.getlist('page')[0])
results = models.Product.query....paginate(page, 10, False)
return render_template('searchresults.html', form=form, results=results, curpage=page)
The results in render_template will be the first 10 results of my query. In searchresults.html I display the results, along with a next and previous link for the other results. This page also contains the same search form which I re-instate as per the initial submission. Currently I'm handling the next and previous links using
Next
So the next link re-submits the same initial form, but with the page value increased. I'm not really happy with this approach because when I hover over the next link I don't see the actual page I will be directed to. It also is starting to feel like a bit of a hack. Is there a more natural way to do this? When the form is initially submitted I could use it to create a long string of the desired parameters and use that string in the rendered page as href=" {{ url_for('searchresults') }}?mystring", but this also seems unnatural. How should I handle this?
You have your form configured to submit as a GET request, so you don't really need to force a re-submission through Javascript, you can achieve the same result by setting the next and prev links to URLs that include all the parameters in your form with the page modified to the correct next and previous page numbers.
This is really easy to do with url_for(). Any argument you add that do not match route components will be added to the query string, so you can do something like this:
Next
One thing to keep in mind is CSRF. If you have it enabled in your form, then your next/prev URLs will also need to have a valid token. Or you can disable CSRF, which for a search form might be okay.
Take advantage of the fact that your form arguments are already present in the URL and use request.args to pass the URL parameters into your form:
form = SearchForm(request.args)
Then, if you make your page field an IntegerField with a HiddenInput widget instead of a string field:
from wtforms.widgets import HiddenInput
class SearchForm(Form):
page = HiddenField(widget=HiddenInput, default=1)
you can increment page before you pass the form off to your search results page:
form.page.data += 1
And then, in your page, you simply create the link to the next page:
Next

Customize the search portlet in Plone for specific content types

I'm using the search portlet in certain areas of my website, but I'd like to restrict the results to only search for a specific content type: for example only search the news items, or only show Faculty Staff Directory profiles.
I know you can do this after you get to the ##search form through that "filter" list, but is there a way to start with the filter on, so that the "Live Search" results only show the relevant results (i.e. only news items or only profiles).
I suspect you know it already, but just to be sure: You can globally define which types should be allowed to show up in searchresults in the navigations-settings of the controlpanel, and then export and include the relevant parts to your product's GS-profile-propertiestool.xml.
However, if you would like to have some types excluded only in certain sections, you can customize Products.CMFPlone/skins/plone_scripts/livesearch_reply, which already filters the types, to only show "friendly_types" around line 38 (version 4.3.1) and add a condition like this:
Edit:
I removed the solution to check for the absolute_url of the context, because the context is actually the livesearch_reply in this case, not the current section-location. Instead the statement checks now, if the referer is our section:
REQUEST = context.REQUEST
current_location = REQUEST['HTTP_REFERER']
location_to_filter = '/fullpath/relative/to/siteroot/sectionId'
url_to_filter = str(portal_url) + location_to_filter
types_to_filter = ['Event', 'News Item']
if current_location.find(url_to_filter) != -1 or current_location.endswith(url_to_filter):
friendly_types = types_to_filter
else:
friendly_types = ploneUtils.getUserFriendlyTypes()
Yet, this leaves the case open, if the user hits the Return- or Enter-key or the 'Advanced search...'-link, landing on a different result-page than the liveresults have.
Update:
An opportunity to apply the filtering to the ##search-template can be to register a Javascript with the following content:
(function($) {
$(document).ready(function() {
// Let's see, if we are coming from our special section:
if (document.referrer.indexOf('/fullpath/relative/to/siteroot/sectionId') != -1) {
// Yes, we have the button to toggle portal_type-filter:
if ($('#pt_toggle').length>0) {
// If it's checked we uncheck it:
if ($('#pt_toggle').is(':checked')) {
$('#pt_toggle').click();
}
// If for any reason it's not checked, we check and uncheck it,
// which results in NO types to filter, for now:
else {
$('#pt_toggle').click();
$('#pt_toggle').click();
}
// Then we check types we want to filter:
$("input[value='Event']").click();
$("input[value='News Item']").click();
}
}
})
})(jQuery);
Also, the different user-actions result in different, inconsistent behaviours:
Livesearch accepts terms which are not sharp, whereas the ##search-view only accepts sharp terms or requires the user to know, that you can append an asterix for unsharp results.
When hitting the Enter/Return-key in the livesearch-input, the searchterm will be transmitted to the landing-page's (##search) input-element, whilst when clicking on 'Advanced search...' the searchterm gets lost.
Update:
To overcome the sharp results, you can add this to the JS right after the if-statement:
// Get search-term and add an asterix for blurry results:
var searchterm = decodeURI(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURI('SearchableText').replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1")) + '*';
// Insert new searchterm in input-text-field:
$('input[name=SearchableText]').val(searchterm);
Update2:
In this related quest, Eric Brehault provides a better solution for passing the asterix during submit: Customize Plone search
Of course you can also customize the target of advanced-search-link in livesearch_reply, respectively in the JS for ##search, yet this link is rather superfluous UI-wise, imho.
Also, if you're still with Archetypes and have more use-cases for pre-filtered searchresults depending on the context, I can recommend to have a look at collective.formcriteria, which allows to define search-criteria via the UI. I love it for it's generic and straightforward plone-ish approach: catalogued indizi and collections. In contradiction to eea.facetednavigation it doesn't break accessibility and can be enhanced progressively with some live-search-js-magic with a little bit of effort, too. Kudos to Ross Patterson here! Simply turn a collection (old-style) into a searchform by changing it's view and it can be displayed as a collection-portlet, as well. And you can decide which criteria the user should be able to change or not (f.e. you hide the type-filter and offer a textsearch-input).
Watch how the query string changes when you use the filter mechanism on the ##search page. You're simply adding/subtracting catalog query criteria.
You may any of those queries in hidden fields in a search form. For example:
<form ...>
....
<input type="hidden" name="portal_type" value="Document" />
</form>
The form on the query string when you use filter is complicated a bit by its record mechanism, which allows for some min/max queries. Simple filters are much easier.

Extracting all text from a website to build a concordance

How can I grab all the text in a website, and I don't just mean ctrl+a/c. I'd like to be able to extract all the text from a website (and all the pages associated) and use it to build a concordance of words from that site. Any ideas?
I was intrigued by this so I've written the first part of a solution to this.
The code is written in PHP because of the convenient strip_tags function. It's also rough and procedural but I feel in demonstrates my ideas.
<?php
$url = "http://www.stackoverflow.com";
//To use this you'll need to get a key for the Readabilty Parser API http://readability.com/developers/api/parser
$token = "";
//I make a HTTP GET request to the readabilty API and then decode the returned JSON
$parserResponse = json_decode(file_get_contents("http://www.readability.com/api/content/v1/parser?url=$url&token=$token"));
//I'm only interested in the content string in the json object
$content = $parserResponse->content;
//I strip the HTML tags for the article content
$wordsOnPage = strip_tags($content);
$wordCounter = array();
$wordSplit = explode(" ", $wordsOnPage);
//I then loop through each word in the article keeping count of how many times I've seen the word
foreach($wordSplit as $word)
{
incrementWordCounter($word);
}
//Then I sort the array so the most frequent words are at the end
asort($wordCounter);
//And dump the array
var_dump($wordCounter);
function incrementWordCounter($word)
{
global $wordCounter;
if(isset($wordCounter[$word]))
{
$wordCounter[$word] = $wordCounter[$word] + 1;
}
else
{
$wordCounter[$word] = 1;
}
}
?>
I needed to do this to configure PHP for the SSL the readability API uses.
The next step in the solution would be too search for links in the page and call this recursively in an intelligent way to hance the associated pages requirement.
Also the code above just gives the raw data of a word-count you would want to process it some more to make it meaningful.

url segments based redirect in modx Evo

let's say you have a url like this entered in modx Evo
www.zipit.com.org/reference/toamovie/
if I have a page called toamovie whose parent is called reference
but when someone enters that url I want it to do the equivalent of this
www.zipit.com.org/reference.html?myvar=toamovie
additionally, or more importantly,
I'd like the result to be more like this, where 12 wouls be the id of a document
`www.zipit.com.org/reference.html?myid=12'
I'm wondering if this is at all possible with modx Evolution.I'm thinking that this should be possible to do with some htaccess magic, well the first part anyway. How could I get a value that the document? This would be quite inaccessible with htaccess, so there would need to be another part to it that could plug into the database and get that value.
It should be possible with a custom plugin called on the "OnPageNotFound" event.
<?php
$url = $_SERVER['REQUEST_URI']; //get the url
//split the url into pieces and remove empty values
$pieces = array_filter(explode('/', $url));
//reset the array keys
$temp = array();
foreach ($pieces as $piece) {
$temp[] = $piece;
}
$pieces = $temp;
//basic checking of the url
if (count($pieces) == 2) {
$modx->sendRedirect('http://www.zipit.org/' . $pieces[0] .".html?myid=" . $pieces[1]);
}
?>
remember that plugins aren't wrapped in php tags.
also that this script will pass any incorrect urls to zipit.org. Some error handling is probably desireable.

Resources