253 lines
6.7 KiB
JavaScript
253 lines
6.7 KiB
JavaScript
//
|
|
// Jala Project [http://opensvn.csie.org/traccgi/jala]
|
|
//
|
|
// Copyright 2004 ORF Online und Teletext GmbH
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
// $Revision$
|
|
// $LastChangedBy$
|
|
// $LastChangedDate$
|
|
// $HeadURL$
|
|
//
|
|
|
|
|
|
/**
|
|
* @fileoverview Fields and methods of the jala.History class.
|
|
*/
|
|
|
|
|
|
// Define the global namespace for Jala modules
|
|
if (!global.jala) {
|
|
global.jala = {};
|
|
}
|
|
|
|
|
|
/**
|
|
* Constructs a new History object.
|
|
* @class This class is an implementation of a Browser-like history
|
|
* stack suitable to use in any Helma application. The difference
|
|
* to a Browser's history is that this implementation ignores
|
|
* POST requests and checks if Urls in the stack are still valid to
|
|
* prevent eg. redirections to a HopObject's url that has been deleted.
|
|
* Plus it is capable to create new "intermediate" history-stacks
|
|
* and this way maintain a "history of histories" which is needed for
|
|
* eg. editing sessions in a popup window that should use their own
|
|
* request history without interfering with the history of the
|
|
* main window.
|
|
* @constructor
|
|
*/
|
|
jala.History = function() {
|
|
var MAX = 40;
|
|
|
|
/**
|
|
* Stack constructor
|
|
* @private
|
|
*/
|
|
var Stack = function(id) {
|
|
this.items = [];
|
|
this.id = id;
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Returns the current url including query string
|
|
* @private
|
|
*/
|
|
var getUrl = function() {
|
|
var query;
|
|
var url = path.href(req.action);
|
|
try {
|
|
if (query = req.getServletRequest().getQueryString())
|
|
url += "?" + query;
|
|
} catch (e) {
|
|
// ignore
|
|
}
|
|
return url;
|
|
}
|
|
|
|
/**
|
|
* Checks if a request is valid for being added
|
|
* to the history stack. This method returns false
|
|
* for all POST-requests or requests whose action name
|
|
* contains a dot (to prevent requests for external stylesheets
|
|
* or the like from being recorded).
|
|
* @private
|
|
* @type Boolean
|
|
*/
|
|
var isValid = function() {
|
|
// FIXME: we should check for mimetype of response instead
|
|
// of assuming that requests containing a dot aren't worth
|
|
// being put into history stack ...
|
|
if (req.isPost() || (req.action && req.action.contains(".")))
|
|
return false;
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* returns a single Stack instance
|
|
* @private
|
|
*/
|
|
var getStack = function() {
|
|
if (history.length < 1)
|
|
history.push(new Stack(getUrl()));
|
|
return history[history.length -1];
|
|
};
|
|
|
|
/**
|
|
* Variable containing the history-stacks
|
|
* @private
|
|
*/
|
|
var history = [];
|
|
|
|
/**
|
|
* Initializes a new history stack, adds
|
|
* it to the array of stacks (which makes it
|
|
* the default one to use for further requests)
|
|
* and records the current request Url.
|
|
*/
|
|
this.add = function() {
|
|
if (!isValid())
|
|
return;
|
|
var url = getUrl();
|
|
if (getStack().id != url) {
|
|
history.push(new Stack(url));
|
|
this.push();
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Removes the current history stack
|
|
*/
|
|
this.remove = function() {
|
|
history.pop();
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Records a request Url in the currently active
|
|
* history stack.
|
|
*/
|
|
this.push = function() {
|
|
if (isValid()) {
|
|
var obj = path[path.length-1];
|
|
var url = getUrl();
|
|
var stack = getStack();
|
|
if (stack.items.length < 1 || stack.items[stack.items.length -1].url != url) {
|
|
if (stack.items.length >= MAX)
|
|
stack.items.shift();
|
|
stack.items.push({
|
|
url: url,
|
|
path: path.href().substring(root.href().length).replace(/\+/g, " ")
|
|
});
|
|
}
|
|
}
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Clears the currently active history stack
|
|
*/
|
|
this.clear = function() {
|
|
getStack().items.length = 0;
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Redirects the client back to the first valid
|
|
* request in history. Please mind that searching for
|
|
* a valid Url starts at <em>history.length - 2</em>.
|
|
* @param {Number} offset The index position in the stack to start
|
|
* searching at
|
|
*/
|
|
this.redirect = function(offset) {
|
|
res.redirect(this.pop(offset));
|
|
return;
|
|
};
|
|
|
|
/**
|
|
* Retrieves the first valid request Url in history
|
|
* stack starting with a given offset. The default offset is 1.
|
|
* Any valid Url found is removed from the stack, therefor
|
|
* this method <em>alters the contents of the history stack</em>.
|
|
* @param {Number} offset The index position in history stack to start
|
|
* searching at
|
|
* @return The Url of the request
|
|
* @type String
|
|
*/
|
|
this.pop = function(offset) {
|
|
/**
|
|
* checks if a referrer is stil valid
|
|
* @private
|
|
*/
|
|
var isValidPath = function(p) {
|
|
var arr = p.split("/");
|
|
var obj = root;
|
|
for (var i=0;i<arr.length -1;i++) {
|
|
if (!(obj = obj.get(unescape(arr[i]))) || obj.__node__.getState() == 3)
|
|
return false;
|
|
}
|
|
return true;
|
|
};
|
|
|
|
var obj;
|
|
var cut = offset != null ? offset : 1;
|
|
var stack = getStack();
|
|
if (stack.items.length > 0) {
|
|
while (cut-- > 0) {
|
|
obj = stack.items.pop();
|
|
}
|
|
}
|
|
while (stack.items.length > 0) {
|
|
obj = stack.items.pop();
|
|
// check if url is valid
|
|
if (isValidPath(obj.path)) {
|
|
return obj.url;
|
|
}
|
|
}
|
|
return path.href();
|
|
};
|
|
|
|
/**
|
|
* Retrieves the request Url at the given position
|
|
* in the current history stack. If no offset is given
|
|
* the last Url in the stack is returned. This method
|
|
* <em>does not alter the stack contents</em>!
|
|
* @param {Number} offset The index position in history stack to start
|
|
* searching at
|
|
* @return The Url of the request
|
|
* @type String
|
|
*/
|
|
this.peek = function(offset) {
|
|
var stack = getStack();
|
|
return stack.items[stack.items.length - (offset != null ? offset : 1)];
|
|
};
|
|
|
|
/**
|
|
* Returns the contents of all history stacks
|
|
* as string
|
|
* @return The history stacks as string
|
|
* @type String
|
|
*/
|
|
this.dump = function() {
|
|
return history.toSource();
|
|
};
|
|
|
|
/** @ignore */
|
|
this.toString = function() {
|
|
return "[History " + getStack().toSource() + "]";
|
|
};
|
|
|
|
return this;
|
|
}
|