Tag: rss

After the article about parsing xml/rss data with jquery’s ajax functions, I would now show you how the editing system for the Useful links repository page has been made.
What it actually does is editing/deleting and creating of rss files and respectively the items in them without a single refresh. The most relevant part of the client-side and the whole part of the server-side would be shown.

A demo of the system is here to be found
Please note that no data would be send to the server-side .php file – the ajax function doing this is commented and will not execute. That’s why when reloading the page you are going to see only the currently available categories and their corresponding items – changes made by you would not affect the files and its contents. Please also note that editing of a category or item, newly created by you would also be not possible, because of the same reason – editing is based on existing files and since the demo page actually does not create or alter anything in the categories folder on the server, it would not work as expected when for example trying to edit item in the category you have just added one to.

The files, used by the system:

– index.php – the admin start page, containing HTML and a bit of PHP to list all the currently existing category files (each category file is a RSS file, all available under the Useful Links Repository page)
– adminProcessesController.js – the client-side code which reads existing files and sends requests about file manipulation to the server-side page below (available from the link above)
– adminProcesses.php – the server-side code, which handles the ajax requests, done by the client-side page above
– RSSDocument.php – a file, containing the ifactnet_RSSDocument class, extending the DOMDocument PHP class.
– ifactnet_util.php – a file, containing some little functions (e.g. obtaining files in a folder by given extension, returning the absolute file name (without the extension) and so on…)
– style.css

The entry point – index.php – contains actually a few lines of code, whose main goal is to create the menu, used for the editing. The menu has the following structure:

Create new category

[Category 1]

Create new item

[Item 1 in Category 1]

[Item 2 in Category 1]

[Category 2]

Create new item

[Item 1 in Category 2]

…etc…

Clicking on each item or category link gives a possibility to edit it or delete it, creating of items and categories is also done by clicking on the corresponding “Create” option. Let’s now have a look at the more interesting files:

adminProcessesController.js

The current file is the most important, and so the biggest from the set above and would be unfortunately not possible to explain it in details, but I will try to cover the most important moments.
AJAX is used in two functions, declared at the very beginning of the file – the first one for reading an item or channel properties from a .xml file and the second one for sending requests to the php page:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

// Find and return the selected item for edit

varloadSelected=function(indexSelected,path){

var$toEdit=null;

$.ajax({

type:"GET",

url:path,

cache:false,

async:false,

dataType:"xml",

success:function(xml){

if(indexSelected!=""){

var$items=$(xml).find('item');

$toEdit=$items.eq(indexSelected-1);

}else{

var$channelProperties=[];

$channelProperties.push($(xml).find("title").eq(0));

$channelProperties.push($(xml).find("description").eq(0));

$channelProperties.push($(xml).find("link").eq(0));

$toEdit=$channelProperties;

}

},

error:function(jqXHR,text,errorMsg){

alert("Error - "+errorMsg);

}

});

return$toEdit;

}

// Create, edit or delete item/category

varcallServerSide=function(properties,path){

varresponce="";

$.ajax({

type:"POST",

url:path,

cache:false,

data:properties,

dataType:"text",

async:false,

success:function(returnedData){

responce=returnedData;

},

error:function(jqXHR,text,errorMsg){

alert("The following error occured: - "+errorMsg);

}

});

returnresponce;

}

loadSelected variable (that is unnamed (anonymous) function, assigned to a variable):
The arguments are pretty much self-explanatory – indexSelected is the index of the selected item (obtained by clicking on its title – that a bit latter) and the second one is the path to the xml files. As already explained in a previous article about ajax – the path should be relative to the root directory of your server – for example, the paths, used in css and javascript files are relative to the .html file, where they are included. A path for ajax call to a file under ‘http://domainName.com/lib/news.rss’ should be “/lib/news.rss”, no matter where the javascript file, making the ajax call, actually is.
The ajax call parameters, used in the current function are to be found on the ajax methods documentation page in jquery’s website. There is, however, an important thing to notice – when returning any data, ‘fetched’ from the call, use async: false, like in the example above.
The success callback function returns the item node or an array of three of the channel’s node children – title, description and link. Its argument is the obtained xml (in this case – the whole xml file).

callServerSide variable (again unnamed (anonymous) function, assigned to a variable):
The function uses POST method to send the properties argument to the server side page, the path to which is assigned to path argument.data property of the ajax function should point to the data, which we are about to send. As you would see later – the data is a regular POST string with the form key1=”value1″&key2=”value2″. dataType is the type of data, expected as answer from the server-side script – in this case it is a plain text, as what the current server-side script returns is either “true” or “false”. The data, returned from the server is passed to the first argument of the success callback function – in our case that be returnedData. Of course, you can name the argument differently.

What the file does further:
It ‘splits’ the different links from the menu by purpose – item editing/deleting, item creating, or category editing/deleting and creating, assigning different anchor sets (depending on the anchors’ classes) to different variables (shown below).
Each set of anchors (for item editing/deleting or item creating, etc…) is handled a little differently on click. Basically, the handling procedures could be categorized as Creating and Editing/Deleting ones.
The creating procedures are a bit tricky, as the newly created item/category titles should be prepended to the menu on the go – as you remember, the menu is created in the index.php with a php code. However, as the aim is to accomplish all the tasks without reloading, the newly created items should be created in both the corresponding file (this is done by the php script) AND in the menu itself. Analogically – newly created categories demand creating of both the category file and the category ‘entry’ in the menu.
Editing procedures edit the content of the item/category in both the files and the menu entries.
When each of the procedures is started (by clicking on the corresponding menu entry(anchor)), a form is shown – with blank fields for creating procedure and populated ones for editing. Both are explained few lines below.
The form submission is the part, where the server-side script is called and the editing/deleting and creating processes are actually handled.

Let’s already come back to the code and especially the different kinds of menu entries:

1

2

3

4

5

6

7

8

9

...

var$navigation=$("#navigation");

var$navigationItems=$navigation.find("ul li a");

var$addCategory=$navigationItems.parent().children("a#addCategory");

var$addItem=$navigationItems.parent().children("a.addItem");

var$editCategory=$navigationItems.parent().find("a.category");

// An alternative way of traversing - parent().siblings() returns all the top-level <li> elements

What is omitted is the initialization of another variables, needed for the current implementation of the admin system. As the aim of the article is only pointing out the sole idea behind the ajax calls and the server side script, executed on their request, these are not included in the code. The dollar sign ($) at the beginning of each variable only denotes that the variable holds/points to jQuery object/set of objects.
The variables above are used as follows:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

$($navigationItems).live('click',function(e){

e.preventDefault();

var$clicked=$(this);

$(".activeInMenu").removeClass("activeInMenu");

$clicked.addClass("activeInMenu");// colours the clicked item in red - only cosmetic

An important part here is the use of “live” – it binds the click event not only to the anchors, already created, but also to these, which are appended to the menu on the go – when an item or category is newly created.

What was omitted here (but shown a couple of rows below) is the call of the loadSelected() function. By item/category editing procedure, a form is created on the go and eventually appended to the main div in index.php. Its fields are populated with the data, returned from loadSelected() and a Delete button is added as well.
By creation process, the corresponding forms are shown with blank fields (these forms are already present in the index.php. They are, of course, hidden, until a creation link is clicked on).
Have a look at the code, handling item editing procedure, but have in mind that there are few functions and variables used, whose implementation and declaration are not shown. However, the functions are self-explanatory and all the variables represent different html elements. The only thing which could be of interest here, is the hideTheseNodeValues array – it contains all the item values, which are not to be edited – currently only the pudDate, actually.

...//notify on success or failure and edit the current category title in the menu

}

});

The serialize() function is the one, creating the POST string – as mentioned at the beginning of the article – it holds key-value pairs, where the keys are the form input names and values are the strings, typed in the corresponding input fields.
The creation processes are pretty much the same, as these shown above, except that they handle the additional appending of items to the menu – that is: [Item N in category M] menu entry for an item or
-[New category name]
– Create new item in [New category name]
menu entries for a whole new category.The issue: items are created in category files by the php script, categories are created as new files by the same php file, but all that results in different menu structure, which should be handled by the javascript, if no reloading is needed. The alternative of the on-the-go appending of menu entries is a simple refresh of the page – then index.php would list all the existing files and its contents. (I have written about that in the very beginning of the article). However, this refresh would make the whole ajax processing useless – each form action could call the adminProcesses.php file directly, which would handle the request accordingly and eventually reopen the index.php for further item/category processing from user’s side.

The last part of the file:

1

2

3

$deleteButton.live('click',function(){

...

});

handles the deleting of both item and category and removing its menu entries respectively. callServerSide function is called again, only with different parameters, of course.

adminProcesses.php

Finally, the complete server-side code:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

<?php

require_once"RSSDocument.php";

require_once"ifactnet_util.php";

$categoriesPath=realpath("../categories/");

$allCategories=getAllFiles($categoriesPath,"xml");

if(isset($_POST['action'])&&isset($_POST['category'])){

$action=$_POST['action'];

$category=$_POST['category'];

$filePath=$categoriesPath."/".$category.".xml";

$updates=array();

$index="";

switch($action){

case"editItem":{

foreach($_POSTas$nodeName=>$nodeValue){

if($nodeName!="category"&&$nodeName!="index"){

$updates[$nodeName]=$nodeValue;

}elseif($nodeName=="index"){

$index=$nodeValue;

}

}

$rss=newifactnet_RSSDocument();

$rss->load($filePath);

$rss->updateItem($index,$updates);

$rss->save($filePath);

echo"true";

break;

}

case"createItem":{

$title=$_POST['title'];

$description=$_POST['description'];

$link=$_POST['link'];

$rss=newifactnet_RSSDocument();

$rss->load($filePath);

$rss->addItem($title,$description,$link);

$rss->save($filePath);

echo"true";

break;

}

case"editCategory":{

$title=$_POST['title'];

$description=$_POST['description'];

$link=$_POST['link'];

$rss=newifactnet_RSSDocument();

if(isset($_POST['newCategoryName'])){

$oldFilePath=$filePath;

$filePath=$categoriesPath."/".$_POST['newCategoryName'].".xml";

rename($oldFilePath,$filePath);

}

$rss->load($filePath);

$rss->title($title);

$rss->description($description);

$rss->link($link);

$rss->save($filePath);

echo"true";

break;

}

case"createCategory":{

$title=$_POST['title'];

$description=$_POST['description'];

$link=$_POST['link'];

$rss=newifactnet_RSSDocument();

$rss->channelProperties($title,$description,$link);

$rss->save($filePath);

echo"true";

break;

}

case"deleteItem":{

$rss=newifactnet_RSSDocument();

$rss->load($filePath);

$rss->deleteItem($_POST['index']);

$rss->save($filePath);

echo"true";

break;

}

case"deleteCategory":{

unlink($filePath);

echo"true";

break;

}

default:echo"false";

}

}else{

echo"false";

}

?>

The file uses couple of functions from the ifactnet_util.php, mentioned at the beginning of the article, which, I hope, are self-explanatory. The ifactnet_RSSDocument class is going to be included in another post for free use.

What adminProcessing.php actually does is to either edit, delete or create an item or a category, using a controlling variable – $action. As a response for each task, it simply echoes true on success, or false on failure, thus ‘sending’ it to the AJAX call (callServerSide()), which returns it to a certain variable (already in the javascript file – adminProcessesController.js). According to the answer, returned from the server side, either an error or success message message is shown.
The adminProcessing.php uses the POST request, sent from the AJAX call in its $_POST variable – take for example the following POST string – item=item1&title=title1, which would result in a $_POST array with two pairs key=>value – $_POST[‘item’] would give ‘item1’ and $_POST[‘title’] would give title1.

Conclusion

What AJAX enables us to do is to send either GET or POST requests to be (PUT and DELETE are available as well – refer to the ajax() manual in the jQuery website) processed by the server (in our case the server processing is actualy the adminProcesses.php file) without reloading the page.
Data sent to the server via POST method for example is available in the php $_POST array. The data is processed by the server and when needed is ‘returned’ to the same ajax call with a simple echo statement. When expecting data from the server-side, it is good to set the dataType property of the ajax function to the data type you are waiting – e.g. text, json or xml. However, not doing so would simply result in the so called “intelligent guess” – the jQuery would try to guess what type the received data is.
I hope that the article was of use for you, though its length and the fairly big amount of code not shown here, but taking part in the whole script.

As you already probably know, AJAX is a javascript technology providing us with an easy way of reading and/or parsing data from the server without using even a single line of server-side language in most of the cases, or as w3schools says – “AJAX is the art of exchanging data with a server, and update parts of a web page – without reloading the whole page.“. Although it can freely be used without any library, when using jQuery in our project, why not trying its AJAX functions as well?

What is shown in the current post is RSS file data parsing with the jQuery.ajax() method. As a sample XML I am using a RSS file, used in my Useful links repository. As the file is with ever changing (let’s hope expanding) content, I would not show its contents here, but instead – in the demo page.
Let’s start first with the code I am actually using in the page where I am editing the content of the RSS Feeds in the Useful links repository.

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

vargetXMLElement=function(url,element){

$.ajax({

type:"GET",

url:url,

cache:false;

dataType:"xml",

success:function(xml){

$(xml).find('item title').each(function(){

if($.trim(element)==$.trim($(this).text())){

varnodeToEdit=$(this).parent();

vartitle=element;

vardescription=nodeToEdit.find('description').text();

varlink=nodeToEdit.find('link').text();

$("#title").val(title);

$("#description").val(description);

$("#link").val(link);

}

});

},

error:function(jqXHR,text,errorMsg){

alert("Error opening file - "+errorMsg);

}

});

}

About the Ajax primer above

The function above takes url and element as arguments, where url is the path to the file, which we are about to open for parsing and would be passed to url parameter of the jQuery.ajax() method. The element is used for searching a string in the parsed file, but have in mind that the logic behind my search is a bit weak, as it would not work correctly if there are two or more equal “title” strings in the “item” nodes.

A bit over the RSS files

The obligatory nodes (tags) of a RSS file are title, link, description and at least one item for the actual content, where each item should have the title, link and description tags itself as well. More about the structure of a RSS file and other optional elements could easily be found on google. Now let’s go back to the Ajax calls.

The url parameters

What you need to know when opening files with Ajax is that the path for the URL parameter of each method is relative to the root of your server, no matter where the HTML or Javascript files actually are. Actually, you won’t be able to make an Ajax call to any other (web) server. Let’s observe for example the following structure: http://myDomainName.net/library/mainFeed.xml. To pass a relative path to the xml file as argument, you should use “/library/mainFeed.xml”.

jQuery.ajax() method parameters used in the first example

The other jQuery.ajax() parameters are type – the default one is “GET”, when also “POST”, “PUT” and “DELETE” are available, but the latter two are not supported by all the browser, according to the jquery ajax() documentation page. Setting cache parameter to false would force the browse not to cache the page and the dataType tells us how the returned data would be formatted. Success is a parameter, expecting a callback function to be executed by successful load, while callback “linked” to the error parameter would be executed by any errors loading the data. Both the functions could get data, textStatus and jqXHR as arguments, in the case above – xml argument passed to success represents the data, fetched from the file as xml object (because of the dataType: “xml”).

Traversing over XML-formatted data

Now, that was pretty much the basics, the actual parsing of the data depends entirely on you, I would only give you a few (let’s hope useful) examples. When formatted as xml, the returned data could be traversed with jQuery.find() method, as you can see from the example above. Using it with the current “items title” argument would give us a set of title tags, children of the item tags. Iterating over find(“title”) would give us pretty much the same, only with the channel tag’s title. As you can see, when formatted as xml, the data returned by the ajax call would be easily manipulated like any other proper DOM Object.

If we need to return the data, fetched by the ajax call, instead of processing it in a callback function, according to my research on the matter, one thing is obligatory, namely:

JavaScript

1

2

3

4

5

$.ajax()({

...

async:false,

...

;});

Now, lets substitute the dots above with the actual code from the demo page:

// Optional line - closes all the tags, but fucks up the formatting. (the indent should be somehow splitted)

//$("body").append("[\\"+node.get(0).nodeName+"]<br />");

}

$(document).ready(function(){

varlink="/faddap/categories/javascript.xml";

varxmlDoc=getXML(link);

// Procesing by known structure

xmlDoc.find('item').each(function(){

$(this).children().each(function(){

// this refers to xmlElement, while $(this) is a jQuery object

$("#processing").append(this.nodeName+" - "+$(this).text()+"<br />");

});

});

// Simple recursive printing of all the nodeNames and nodeValues.

write(xmlDoc);

});

First have a look at the link variable on line 41 – the relative path used there is actually almost the same as the absolute one, which it corresponds to – “http://if-act.net/faddap/categories/javascript.xml”.

The getXML function

Now let’s go to getXML – the function which returns the fetched data, using the xmlDoc variable. Have in mind that $(xml) on line 9, is a jQuery object, representing the xml data. As everything else in the Ajax call here is pretty much the same as the code used in the Ajax code in the first primer, let’s go a bit down the code. Already having the XML Object, hold by the xmlDoc variable on line 42, we can traverse it using standard jQuery functions for traversing DOM elements.

The recursive write function

The recursive function write, shown above is just a basic primer for iterating over RSS document with unknown structure and does not cover namespaces, additional tag attributes and so on.