Introduction Part 1 describes how to use Sajax, PHP, and JavaScript to develop basic albums. In the process of creating a history stack for a program, we will attach the client technique and associate it directly with Part 1 of the code. This article assumes that
Introduction
Part 1 describes how to use Sajax, PHP, and JavaScript to develop basic albums. In the process of creating a history stack for a program, we will attach the client technique and associate it directly with Part 1 of the code. This article assumes that the reader understands JavaScript and browser cookies.
Retained in the browser
When surfing the Internet, it is always from one page to another, from one site to another. In this process, the Web browser faithfully records the historical records of where you were, and creates a breadcrumbs digital track, along this track, we can return to the starting point step by step. The back button allows you to return to your position before the previous action. In this sense, it is the undo button on the Web.
Web is a page-based media. The back and forward buttons in the browser toolbar direct the browser from one page to another. When Macromedia Flash went viral, developers and users found that Rich Internet Application (RIA) broke this pattern. Users can browse on several sites, and then log on to a Flash-based website to spend several minutes on it. When you click the back button, the game is over. The user did not return to the previous Flash site and did not know what the site was.
This is also the case for the complete Ajax-based website-RIA. A: websites that use users to interact with a page for multiple times are easily troubled by the back button or any history button (in this case ). The title of the forward and reload buttons is the same as that of the back button. The built-in internal history record mechanism of Web browsers is an unavoidable title. For security reasons, developers cannot modify browser history or any related buttons. There is also the availability title. Imagine how confusing the user might be if the back button suddenly prompts a mysterious warning or the user is sent to a new website.
Build a history stack
Although the browser history cannot be changed, you can build a historical record for the application in RIA by yourself. Obviously, it should be removed from the browser's standard navigation tool to some extent, but as mentioned above, the rich utility program deviated from the Web page to the page's scale mode to a certain extent.
We will create a stack to manage historical event records of the exploitation program, that is, store a list and add elements at the end of the table. Stack is used to store data in the order of backward first-in-first-out (LIFO. Although the data at the top of the stack is not deleted during rollback, this model is very similar to our needs. In JavaScript, stacks can be managed using arrays.
There is also a pointer together with the stack, which allows us to determine the current position in the stack. When we click in the exploitation program, the new event is pressed into the top of the stack, and the pointer points to the last added element. When you click the back and forward buttons of the exploitation program, a new event is not added to the stack, but a pointer to the stack is moved. Think about what will happen in the history stack when the app moves back: The browser returns to the last page viewed, and the previously unavailable forward button suddenly becomes available. When you browse a new page, the forward button turns gray again. The elements retained later in the browser history will pop up the stack, and new events will be pushed to the top of the stack. We will reproduce this action in our own history stack.
Our goal is to create a set of available history buttons: back, forward, and refresh, as shown in 1.
Figure 1. the back, forward, and refresh history buttons are displayed on the left, and the unavailable status is displayed on the right.
Reusable design
JavaScript applications use very loose methods to create objects and classes, but still can build reusable code. First, list the functions required by the history stack, and then use JavaScript to create a stack model. Before you integrate the history stack into the album exploitation program, you must first create a simple page to test its efficacy. This has two benefits: the test page helps to focus on the core functions of the development and test classes, and the establishment of a separate test page can avoid the effect of mixing the history stack and album, this ensures reusability.
Buffer with cookies
We need to use the history of the program to exist in all browser sessions. As long as the user is still viewing the album page, the history stack object will always exist. Each time a change is made, this class copies all history records to the browser cookie. If the user leaves the page in the same browser session and returns again, the user will return the same position that the user leaves the exploitation program.
Writing class
Let's take a look at the data or attributes that need to be stored in the history stack. The stack (array) and pointer have been discussed earlier. The stack_limit attribute prevents cookie overflow caused by excessive data (see listing 1 ). In practice, we hope that 40-50 events can be stored before the oldest record is deleted. For testing purpose, we set this value to 15.
Listing 1. history stack structure, including class attributes
Function HistoryStack ()
{
This. stack = new Array ();
This. current =-1;
This. stack_limit = 15;
}
In addition to these three attributes, this class also requires some methods to add elements, retrieve stack data, and retain stack data in browser cookies. First, let's take a look at the addResource () method, which is used to press the record to the top of the stack of the history stack (see listing 2 ). Note that if the stack length exceeds stack_limit, the oldest record will be removed from the stack.
List 2. addResource () method to add records to the top of the history stack
HistoryStack. prototype. addResource = function (resource)
{
If (this. stack. length> 0 ){
This. stack = this. stack. slice (0, this. current 1 );
}
This. stack. push (resource );
While (this. stack. length> this. stack_limit ){
This. stack. shift ();
}
This. current = this. stack. length-1;
This. save ();
};
The following three methods are added to the history stack to obtain information from this class (see listing 3 ). GetCurrent () returns the stack pointer pointing to the current record, which is useful for navigation in the stack. The hasPrev () and hasNext () methods return Boolean values, indicating whether there are any records before or after the current record, or instigating us to reach the top or end of the stack. These methods are simple, but they are useful when determining the status of the backward and forward buttons.
Listing 3. methods for defining history stacks
HistoryStack. prototype. addResource = function (resource)
HistoryStack. prototype. getCurrent = function ()
{
Return this. stack [this. current];
};
HistoryStack. prototype. hasPrev = function ()
{
Return (this. current> 0 );
};
HistoryStack. prototype. hasNext = function ()
{
Return (this. current <this. stack. length-1 & this. current>-1 );
};
Now you can add a record to the history stack and determine its position. However, you still cannot navigate in the stack. The go () method defined in listing 4 promises to move back and forth in the stack. You can move forward or backward in the stack by passing positive or negative increments. This is similar to the location. go () method built in JavaScript. Since it imitates the built-in functions, why not build models based on these existing methods?
In addition, we can use this method to achieve the refreshing effect. You can navigate the stack by passing positive or negative parameters. If the value is zero, the current page is refreshed.
Listing 4. go () method of history stack
HistoryStack. prototype. go = function (increment)
{
// Go back...
If (increment <0 ){
This. current = Math. max (0, this. current increment );
// Go forward...
} Else if (increment> 0 ){
This. current = Math. min (this. stack. length-1, this. current increment );
// Reload...
} Else {
Location. reload ();
}
This. save ();
};
So far, as long as the HistoryStack object exists in the current document, the newly created class can work normally. We have discussed the title that will cause data loss when refreshing the page, and we will solve it now. In listing 5, you have added the method of setting and visiting data in the browser cookie. All you need to do is set the name-value pairs for each cookie. Because you only need to keep the cookie in the browser session, you do not need to set the validity period. To simplify the example, we do not consider other parameters, such as secure, domain, and path.
Note: If this type requires complex processing of cookies, it is wise to apply a complete and independent cookie classification class. Creating and reading cookies is a little different from the history stack. If JavaScript promises to specify the scope of the method and attribute visit, you can also set these methods to private.
Listing 5. Creating and visiting browser cookies
HistoryStack. prototype. setCookie = function (name, value)
{
Var cookie_str = name' = 'escape (value );
Document. cookie = cookie_str;
};
HistoryStack. prototype. getCookie = function (name)
{
If (! Name) return '';
Var raw_cookies, tmp, I;
Var cookies = new Array ();
Raw_cookies = document. cookie. split (';');
For (I = 0; I <raw_cookies.length; I ){
Tmp = raw_cookies [I]. split ('= ');
Cookies [tmp [0] = unescape (tmp [1]);
}
If (cookies [name]! = Null ){
Return cookies [name];
} Else {
Return '';
}
};
After defining a method to govern any cookie, you can write two other classes that specifically process the history stack. The save () method converts the stack into a string and keeps it in the cookie. load () parses the string into an array used to govern the history stack (see listing 6 ).
Listing 6. save () and load () methods
HistoryStack. prototype. save = function ()
{
This. setCookie ('chstack', this. stack. toString ());
This. setCookie ('chcurrent', this. current );
};
HistoryStack. prototype. load = function ()
{
Var tmp_stack = this. getCookie ('chstack ');
If (tmp_stack! = ''){
This. stack = tmp_stack.split (',');
}
Var tmp_current = parseInt (this. getCookie ('chcurrent '));
If (tmp_current> =-1 ){
This. current = tmp_current;
}
};
Test class
You can use simple HTML pages and some JavaScript to test the completed classes. The test page displays the history button above. only the motion button is highlighted and can be clicked. We have not created a complex test exploitation program. this page only generates random numbers each time a link is clicked. These numbers are events recorded in the history stack. The stack is also displayed on the page, and the pointer flag displays the current record in bold.
Listing 7. brief HTML page of the test history stack
<Html>
<Head>
<Title> </title>
</Head>
<Body>
<Div id = 'historybuttons'> </div>
<Div>
<A href = '# 'onclick = 'do _ add (); return false;'> Add Random
Resource </a>
</Div>
<Div id = 'output' style = 'margin-top: 40px; '> </div>
</Body>
</Html>
Add the JavaScript code shown in listing 8 to the header of the HTML page. This code first instantiates a new history stack object and loads all the data that may have been stored in the browser cookie.
We have defined four do _ * () functions. These event handlers will be added to the link of the back, forward, and refresh buttons, and the Add Random Resource link, as shown in listing 7.
The display () function checks whether the historical record object is in the current state and generates HTML for the History button. It also contains a list of projects stored in the historical records.
Listing 8. integrate the history record class and the JavaScript code on the test page
<Script type = 'text/javascript 'src = 'history. js'> </script>
<Script type = 'text/javascript '>
Var myHistory = new HistoryStack ();
MyHistory. load ();
Function do_add ()
{
Var num = Math. round (Math. random () * 1000 );
MyHistory. addResource (num );
Display ();
Return false;
}
Function do_back ()
{
MyHistory. go (-1 );
Display ();
}
Function do_forward ()
{
MyHistory. go (1 );
Display ();
}
Function do_reload ()
{
MyHistory. go (0 );
}
Function display ()
{
// Display history buttons
Var str = '';
If (myHistory. hasPrev ()){
Str = '<a href =' # 'onclick = 'do _ back (); return false; '>'
'/> </A> ';
} Else {
Str = ' ';
}
If (myHistory. hasNext ()){
Str = '<a href =' # 'onclick = 'do _ forward (); return false; '>'
''
'</A> ';
} Else {
Str = ' ';
}
Str = '<a href =' # 'onclick = 'do _ reload (); return false; '>'
'/> </A> ';
Document. getElementById ('historybuttons'). innerHTML = str;
// Display the current history stack, highlighting the current
// Position.
Var str = '<div> History: </div> ';
For (I = 0; I <myHistory. stack. length; I ){
If (I = myHistory. current ){
Str = '<div> <B>' myHistory. stack [I]
'</B> </div> ';
} Else {
Str = '<div> 'myhistory. stack [I]' </div> ';
}
}
Document. getElementById ('output'). innerHTML = str;
}
Window. onload = function (){
Display ();
};
</Script>
On the Run test page, you can see that the history Button reflects the status of the history stack (see figure 2 ). For example, the buttons are gray when the page is loaded for the first time. After adding some records to the stack, the back button is moved. If you roll back in the stack, the forward button is highlighted. Note that if you click back several times and then click Add, a part of the stack will be truncated, and new events will be pushed to the top of the shortened stack.
Figure 2. test page of history stack
After testing this class, you can enter the most exciting stage.
Integrated History object and album
We will start with the title left in Part 1 and call the history stack directly from the album page. You do not need to modify any PHP files.
First, you need to add a div tag to store the History button. As shown in listing 7.
<Div id = 'historybuttons'> </div>
The history stack code is retained to a. js file, which is linked to the album page.
<Script type = 'text/javascript 'src = 'history. js'> </script>
History stack objects need to be instantiated and loaded from the buffer. These controls can be added to the front of an existing script on the album page.
Var myHistory = new HistoryStack ();
MyHistory. load ();
In the test exploitation program for history stacks, only random numbers are stored as events. We can store any required information in the history, but remember that when you click the back button of the exploitation program, you also need to determine what the content in the history stack is. The program has only two actions related to the x_get_table () and x_get_image () functions. Therefore, for each table link, you can store the table name and the start and step values as event identifiers, such as table-10-5. Similarly, you can store the name image and the index of the image to be viewed, such as image-20. In Part 2, each link in the album is created by the get_table_link () and get_image_link () functions. By compiling these functions, you can let the function call the history stack before calling the Sajax function. Listing 9 shows these changes in bold.
Listing 9. updated versions of the get_table_link () and get_image_link () functions
Function get_table_link ($ title, $ start, $ step ){
$ Link = 'myhistory. addResource ('table-$ start-$ step ');'
. 'X _ get_table ($ start, $ step, to_window );'
. 'Return false ;';
Return '<a href =' # 'onclick = ''. $ link.''> '. $ title.' </a> ';
}
Function get_image_link ($ title, $ index ){
$ Link = 'myhistory. addResource ('image-$ index ');'
. 'X _ get_image ($ index, to_window );'
. 'Return false ;';
Return '<a href =' # 'onclick = ''. $ link.''> '. $ title.' </a> ';
}
When using the program for Sajax calling, to_window () serves as the callback function to re-generate HTML on the page. In the test exploitation program, we used the function display () (listing 8) to complete two tasks: update the status of the page output and update history buttons. Now the following function calls will be added to the existing to_window () function body:
Display_history_buttons ();
The function is defined in listing 10.
Listing 10. display_history_buttons () function
Function display_history_buttons ()
{
Var str = '';
If (myHistory. hasPrev ()){
Str = '<a href =' # 'onclick = 'do _ back (); return false; '>
</a> ';
} Else {
Str = ' ';
}
If (myHistory. hasNext ()){
Str = '<a href =' # 'onclick = 'do _ forward (); return false; '>
</a> ';
} Else {
Str = ' ';
}
Str = '<a href =' # 'onclick = 'do _ reload (); return false; '>
</a> ';
Document. getElementById ('historybuttons'). innerHTML = str;
}
Before tracking the history of the album exploitation program, you only need to call the x_get_table () function during page loading. In this way, you can call the initial table displayed through Sajax.
Now we have a history stack, but we don't expect to start from scratch every time we open the exploitation program. On the contrary, we look forward to seeing the beginning of departure. Therefore, you need to add the load_current () function to expand the exploitation program. This function is called when the page is loaded. When you add a back and forward button handler, you will also call this function to update the page based on the event ID retained in the history stack.
Listing 11. load_current () function
Function load_current ()
{
// No existing history.
If (myHistory. stack. length = 0 ){
X_get_table (to_window );
MyHistory. addResource ('table-0-5 ');
// Load from history.
} Else {
Var current = myHistory. getCurrent ();
Var params = current. split ('-');
If (params [0] = 'table '){
X_get_table (params [1], params [2], to_window );
} Else if (params [0] = 'image '){
X_get_image (params [1], to_window );
}
}
}
The onload handler must be corrected accordingly:
Window. onload = function (){
Load_current ();
};
Finally, add the history button processing routine in listing 12. Pay attention to the similarities between the processing program and the test exploitation program.
List 12. History button event handler
Function do_back ()
{
MyHistory. go (-1 );
Load_current ();
}
Function do_forward ()
{
MyHistory. go (1 );
Load_current ();
}
Function do_reload ()
{
MyHistory. go (0 );
}
This completes the integration of the history stack to the album exploitation program. Product 3 after completion is shown in.
Figure 3. History button associated with the album exploitation program
Open the exploitation program and click the link to view the history stack and pointer stored in the browser cookie.
CHCurrent = 4
CHStack = table-0-5, image-1, image-2, image-3, table-3-5
If you are running Mozilla Firefox and downloaded the Web Developer Toolbar extension, these controls are easily implemented.
Conclusion
We first introduced how to create a custom history stack to track events in Ajax exploitation programs. You can add common back, forward, and refresh buttons on the Web browser in the application to navigate to the custom history stack.
To solve this problem, we determined the title and created a reusable solution that benefits other exploitation programs. Instead of creating a history stack directly in the album exploitation program, we use a simple page to test this class. This helps establish a solution that is not strictly bound to a specific exploitation program, which can be used by other Ajax exploitation programs to address the same title.