| Index: chrome/browser/resources/history.html
|
| ===================================================================
|
| --- chrome/browser/resources/history.html (revision 0)
|
| +++ chrome/browser/resources/history.html (revision 0)
|
| @@ -0,0 +1,790 @@
|
| +<!DOCTYPE HTML>
|
| +<html id="t">
|
| +<head>
|
| +<meta charset="utf-8">
|
| +<title jscontent="title"></title>
|
| +<script type="text/javascript">
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// Globals:
|
| +var RESULTS_PER_PAGE = 60;
|
| +var MAX_SEARCH_DEPTH = 18;
|
| +
|
| +// Amount of time between pageviews that we consider a 'break' in browsing,
|
| +// measured in milliseconds.
|
| +var BROWSING_GAP_TIME = 15 * 60 * 1000;
|
| +
|
| +function $(o) {return document.getElementById(o);}
|
| +
|
| +// TODO(glen): Get rid of these global references, replace with a controller
|
| +// or just make the classes own more of the page.
|
| +var historyModel;
|
| +var historyView;
|
| +var localStrings;
|
| +var pageState;
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// localStrings:
|
| +/**
|
| + * We get strings into the page by using JSTemplate to populate some elements
|
| + * with localized content, then reading the content of those elements into
|
| + * this global strings object.
|
| + * @param {Node} node The DOM node containing all our strings.
|
| + */
|
| +function LocalStrings(node) {
|
| + this.strings_ = {};
|
| +
|
| + var children = node.childNodes;
|
| + for (var i = 0, child; child = children[i]; i++) {
|
| + var id = child.id;
|
| + if (id) {
|
| + this.strings_[id] = child.innerHTML;
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Gets a localized string by its id.
|
| + * @param {string} s The id of the string we want
|
| + * @return {string} The localized string
|
| + */
|
| +LocalStrings.prototype.getString = function(s) {
|
| + return (s in this.strings_) ? this.strings_[s] : '';
|
| +}
|
| +
|
| +/**
|
| + * Returns a formatted localized string (where all %s contents are replaced
|
| + * by the second argument).
|
| + * @param {string} s The id of the string we want
|
| + * @param {string} d The string to include in the formatted string
|
| + * @return {string} The formatted string.
|
| + */
|
| +LocalStrings.prototype.formatString = function(s, d) {
|
| + return (s in this.strings_) ? this.strings_[s].replace(/\%s/, d) : '';
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// Page:
|
| +/**
|
| + * Class to hold all the information about an entry in our model.
|
| + * @param {Object} result An object containing the page's data.
|
| + * @param {boolean} continued Whether this page is on the same day as the
|
| + * page before it
|
| + */
|
| +function Page(result, continued, model) {
|
| + this.model_ = model;
|
| + this.title_ = result.title;
|
| + this.url_ = result.url;
|
| + this.snippet_ = result.snippet || "";
|
| +
|
| + // All the date information is public so that owners can compare properties of
|
| + // two items easily.
|
| +
|
| + // We get the time in seconds, but we want it in milliseconds.
|
| + this.time = new Date(result.time * 1000);
|
| +
|
| + // See comment in BrowsingHistoryHandler::QueryComplete - we won't always
|
| + // get all of these.
|
| + this.dateRelativeDay = result.dateRelativeDay || "";
|
| + this.dateTimeOfDay = result.dateTimeOfDay || "";
|
| + this.dateShort = result.dateShort || "";
|
| +
|
| + // Whether this is the continuation of a previous day.
|
| + this.continued = continued;
|
| +}
|
| +
|
| +// Page, Public: --------------------------------------------------------------
|
| +/**
|
| + * @return {string} Gets the HTML representation of the page
|
| + * for use in browse results.
|
| + */
|
| +Page.prototype.getBrowseResultHTML = function() {
|
| + return '<div class="entry">' +
|
| + '<div class="time">' +
|
| + this.dateTimeOfDay +
|
| + '</div>' +
|
| + this.getTitleHTML_() +
|
| + '</div>';
|
| +}
|
| +
|
| +/**
|
| + * @return {string} Gets the HTML representation of the page for
|
| + * use in search results.
|
| + */
|
| +Page.prototype.getSearchResultHTML = function() {
|
| + return ['<tr class="entry"><td valign="top">',
|
| + '<div class="time">',
|
| + this.dateShort,
|
| + '</div>',
|
| + '</td><td valign="top">',
|
| + this.getTitleHTML_(),
|
| + '<div class="snippet">',
|
| + this.getHighlightedSnippet_(),
|
| + '</div>',
|
| + '</td></tr>'].join("");
|
| +}
|
| +
|
| +// Page, private: -------------------------------------------------------------
|
| +/**
|
| + * @return {string} The page's snippet highlighted with the model's
|
| + * current search term.
|
| + */
|
| +Page.prototype.getHighlightedSnippet_ = function() {
|
| + return Page.getHighlightedText_(this.snippet_, this.model_.getSearchText());
|
| +}
|
| +
|
| +/**
|
| + * @return {string} Gets the page's title highlighted with the
|
| + * model's current search term.
|
| + */
|
| +Page.prototype.getHighlightedTitle_ = function() {
|
| + return Page.getHighlightedText_(this.title_, this.model_.getSearchText());
|
| +}
|
| +
|
| +/**
|
| + * @return {string} HTML for the title block.
|
| + */
|
| +Page.prototype.getTitleHTML_ = function() {
|
| + return '<div class="title">' +
|
| + '<a ' +
|
| + 'href="' + this.url_ + '" ' +
|
| + 'style="background-image:url(chrome://favicon/' +
|
| + this.url_ + ')" ' +
|
| + '>' +
|
| + this.getHighlightedTitle_() +
|
| + '</a>' +
|
| + '</div>';
|
| +}
|
| +
|
| +// Page, private, static: -----------------------------------------------------
|
| +/**
|
| + * Case-insensitively highlights a string.
|
| + * @param {string} str The source string
|
| + * @param {string} opt_highlight The string to highlight with
|
| + * @return {string} The highlighted string
|
| + */
|
| +Page.getHighlightedText_ = function(str, opt_highlight ) {
|
| + if (!opt_highlight) return str;
|
| +
|
| + var r = new RegExp(Page.pregQuote_(opt_highlight), 'gim');
|
| + return str.replace(r, "<b>\$&</b>");
|
| +}
|
| +
|
| +/**
|
| + * Quote a string so it can be used in a regular expression.
|
| + * @param {string} str The source string
|
| + * @return {string} The escaped string
|
| + */
|
| +Page.pregQuote_ = function(str) {
|
| + return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// HistoryModel:
|
| +/**
|
| + * Global container for history data. Future optimizations might include
|
| + * allowing the creation of a HistoryModel for each search string, allowing
|
| + * quick flips back and forth between results.
|
| + *
|
| + * The history model is based around pages, and only fetching the data to
|
| + * fill the currently requested page. This is somewhat dependent on the view,
|
| + * and so future work may wish to change history model to operate on
|
| + * timeframe (day or week) based containers.
|
| + */
|
| +function HistoryModel() {
|
| + this.clearModel_();
|
| + this.view_;
|
| +}
|
| +
|
| +// HistoryModel, Public: ------------------------------------------------------
|
| +/**
|
| + * Sets our current view that is called when the history model changes.
|
| + * @param {HistoryView} view The view to set our current view to.
|
| + */
|
| +HistoryModel.prototype.setView = function(view) {
|
| + this.view_ = view;
|
| +}
|
| +
|
| +/**
|
| + * Start a new search - this will clear out our model.
|
| + * @param {String} searchText The text to search for
|
| + * @param {Number} opt_page The page to view - this is mostly used when setting
|
| + * up an initial view, use #requestPage otherwise.
|
| + */
|
| +HistoryModel.prototype.setSearchText = function(searchText, opt_page) {
|
| + this.clearModel_();
|
| + this.searchText_ = searchText;
|
| + this.requestedPage_ = opt_page ? opt_page : 0;
|
| + this.getSearchResults_();
|
| +}
|
| +
|
| +/**
|
| + * @return {String} The current search text.
|
| + */
|
| +HistoryModel.prototype.getSearchText = function() {
|
| + return this.searchText_;
|
| +}
|
| +
|
| +/**
|
| + * Tell the model that the view will want to see the current page. When
|
| + * the data becomes available, the model will call the view back.
|
| + * @page {Number} page The page we want to view.
|
| + */
|
| +HistoryModel.prototype.requestPage = function(page) {
|
| + this.requestedPage_ = page;
|
| + this.updateSearch_();
|
| +}
|
| +
|
| +/**
|
| + * Receiver for history query.
|
| + * @param {String} term The search term that the results are for.
|
| + * @param {Array} results A list of results
|
| + */
|
| +HistoryModel.prototype.addResults = function(term, results) {
|
| + this.inFlight_ = false;
|
| + if (term != this.searchText_) {
|
| + // If our results aren't for our current search term, they're rubbish.
|
| + return;
|
| + }
|
| +
|
| + // Currently we assume we're getting things in date order. This needs to
|
| + // be updated if that ever changes.
|
| + if (results) {
|
| + var lastURL, lastDay;
|
| + var oldLength = this.pages_.length;
|
| + if (oldLength) {
|
| + var oldPage = this.pages_[oldLength - 1];
|
| + lastURL = oldPage.url;
|
| + lastDay = oldPage.dateRelativeDay;
|
| + }
|
| +
|
| + for (var i = 0, thisResult; thisResult = results[i]; i++) {
|
| + var thisURL = thisResult.url;
|
| + var thisDay = thisResult.dateRelativeDay;
|
| +
|
| + // Remove adjacent duplicates.
|
| + if (!lastURL || lastURL != thisURL) {
|
| + // Figure out if this page is in the same day as the previous page,
|
| + // this is used to determine how day headers should be drawn.
|
| + this.pages_.push(new Page(thisResult, thisDay == lastDay, this));
|
| + lastDay = thisDay;
|
| + lastURL = thisURL;
|
| + }
|
| + }
|
| + }
|
| +
|
| + this.updateSearch_();
|
| +}
|
| +
|
| +/**
|
| + * @return {Number} The number of pages in the model.
|
| + */
|
| +HistoryModel.prototype.getSize = function() {
|
| + return this.pages_.length;
|
| +}
|
| +
|
| +/**
|
| + * @return {boolean} Whether our history query has covered all of
|
| + * the user's history
|
| + */
|
| +HistoryModel.prototype.isComplete = function() {
|
| + return this.complete_;
|
| +}
|
| +
|
| +/**
|
| + * Get a list of pages between specified index positions.
|
| + * @param {Number} start The start index
|
| + * @param {Number} end The end index
|
| + * @return {Array} A list of pages
|
| + */
|
| +HistoryModel.prototype.getNumberedRange = function(start, end) {
|
| + if (start >= this.getSize())
|
| + return [];
|
| +
|
| + var end = end > this.getSize() ? this.getSize() : end;
|
| + return this.pages_.slice(start, end);
|
| +}
|
| +
|
| +// HistoryModel, Private: -----------------------------------------------------
|
| +HistoryModel.prototype.clearModel_ = function() {
|
| + this.inFlight_ = false; // Whether a query is inflight.
|
| + this.searchText_ = '';
|
| + this.searchMonth_ = 0;
|
| + this.pages_ = []; // Date-sorted list of pages.
|
| +
|
| + // The page that the view wants to see - we only fetch slightly past this
|
| + // point. If the view requests a page that we don't have data for, we try
|
| + // to fetch it and call back when we're done.
|
| + this.requestedPage_ = 0;
|
| +
|
| + this.complete_ = false;
|
| +}
|
| +
|
| +/**
|
| + * Figure out if we need to do more searches to fill the currently requested
|
| + * page. If we think we can fill the page, call the view and let it know
|
| + * we're ready to show something.
|
| + */
|
| +HistoryModel.prototype.updateSearch_ = function() {
|
| + if (this.searchMonth_ >= MAX_SEARCH_DEPTH) {
|
| + // We have maxed out. There will be no more data.
|
| + this.complete_ = true;
|
| + this.view_.onModelReady();
|
| + } else {
|
| + // If we can't fill the requested page, ask for more data unless a request
|
| + // is still in-flight.
|
| + if (!this.canFillPage_(this.requestedPage_) && !this.inFlight_) {
|
| + this.getSearchResults_(this.searchMonth_ + 1);
|
| + }
|
| +
|
| + // If we have any data for the requested page, show it.
|
| + if (this.haveDataForPage_(this.requestedPage_)) {
|
| + this.view_.onModelReady();
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Get search results for a selected month. Our history system is optimized
|
| + * for queries that don't cross month boundaries.
|
| + *
|
| + * TODO: Fix this for when the user's clock goes across month boundaries.
|
| + * @param {number} opt_month How many months back to do the search.
|
| + */
|
| +HistoryModel.prototype.getSearchResults_ = function(opt_month) {
|
| + this.searchMonth_ = opt_month || 0;
|
| + chrome.send('getHistory',
|
| + [this.searchText_, String(this.searchMonth_)]);
|
| + this.inFlight_ = true;
|
| +}
|
| +
|
| +/**
|
| + * Check to see if we have data for a given page.
|
| + * @param {number} page The page number
|
| + * @return {boolean} Whether we have any data for the given page.
|
| + */
|
| +HistoryModel.prototype.haveDataForPage_ = function(page) {
|
| + return (page * RESULTS_PER_PAGE < this.getSize());
|
| +}
|
| +
|
| +/**
|
| + * Check to see if we have data to fill a page.
|
| + * @param {number} page The page number.
|
| + * @return {boolean} Whether we have data to fill the page.
|
| + */
|
| +HistoryModel.prototype.canFillPage_ = function(page) {
|
| + return ((page + 1) * RESULTS_PER_PAGE <= this.getSize());
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// HistoryView:
|
| +/**
|
| + * Functions and state for populating the page with HTML. This should one-day
|
| + * contain the view and use event handlers, rather than pushing HTML out and
|
| + * getting called externally.
|
| + * @param {HistoryModel} model The model backing this view.
|
| + */
|
| +function HistoryView(model) {
|
| + this.summaryDiv_ = $('results-summary');
|
| + this.summaryDiv_.innerHTML = localStrings.getString('loading');
|
| + this.resultDiv_ = $('results-display');
|
| + this.pageDiv_ = $('results-pagination');
|
| + this.model_ = model
|
| + this.pageIndex_ = 0;
|
| +
|
| + this.model_.setView(this);
|
| +}
|
| +
|
| +// HistoryView, public: -------------------------------------------------------
|
| +/**
|
| + * Do a search and optionally view a certain page.
|
| + * @param {string} term The string to search for.
|
| + * @param {number} opt_page The page we wish to view, only use this for
|
| + * setting up initial views, as this triggers a search.
|
| + */
|
| +HistoryView.prototype.setSearch = function(term, opt_page) {
|
| + this.pageIndex_ = parseInt(opt_page || 0, 10);
|
| + window.scrollTo(0, 0);
|
| + this.model_.setSearchText(term, this.pageIndex_);
|
| + pageState.setUIState(term, this.pageIndex_);
|
| +}
|
| +
|
| +/**
|
| + * Switch to a specified page.
|
| + * @param {string} term The string to search for.
|
| + * @param {number} opt_page The page we wish to view.
|
| + */
|
| +HistoryView.prototype.setPage = function(page) {
|
| + this.pageIndex_ = parseInt(page);
|
| + window.scrollTo(0, 0);
|
| + this.model_.requestPage(page);
|
| + pageState.setUIState(this.model_.getSearchText(), this.pageIndex_);
|
| +}
|
| +
|
| +/**
|
| + * @return {number} The page number being viewed.
|
| + */
|
| +HistoryView.prototype.getPage = function() {
|
| + return this.pageIndex_;
|
| +}
|
| +
|
| +/**
|
| + * Callback for the history model to let it know that it has data ready for us
|
| + * to view.
|
| + */
|
| +HistoryView.prototype.onModelReady = function() {
|
| + this.displayResults_();
|
| +}
|
| +
|
| +// HistoryView, private: ------------------------------------------------------
|
| +/**
|
| + * Update the page with results.
|
| + */
|
| +HistoryView.prototype.displayResults_ = function() {
|
| + var output = [];
|
| + var results = this.model_.getNumberedRange(
|
| + this.pageIndex_ * RESULTS_PER_PAGE,
|
| + this.pageIndex_ * RESULTS_PER_PAGE + RESULTS_PER_PAGE);
|
| +
|
| + if (this.model_.getSearchText()) {
|
| + output.push('<table class="results" cellspacing="0" ',
|
| + 'cellpadding="0" border="0">');
|
| + for (var i = 0, page; page = results[i]; i++) {
|
| + output.push(page.getSearchResultHTML());
|
| + }
|
| + output.push('</table>');
|
| + } else {
|
| + var lastTime = Math.infinity;
|
| + for (var i = 0, page; page = results[i]; i++) {
|
| + // Break across day boundaries and insert gaps for browsing pauses.
|
| + var thisTime = page.time.getTime();
|
| + if (page.continued && i == 0) {
|
| + output.push('<div class="day">' + page.dateRelativeDay + ' ' +
|
| + localStrings.getString('cont') + '</div>');
|
| + } else if (!page.continued) {
|
| + output.push('<div class="day">' + page.dateRelativeDay + '</div>');
|
| + } else if (lastTime - thisTime > BROWSING_GAP_TIME) {
|
| + output.push('<div class="gap"></div>');
|
| + }
|
| + lastTime = thisTime;
|
| +
|
| + // Draw entry.
|
| + output.push(page.getBrowseResultHTML());
|
| + }
|
| + }
|
| + this.resultDiv_.innerHTML = output.join("");
|
| +
|
| + this.displaySummaryBar_();
|
| + this.displayNavBar_();
|
| +}
|
| +
|
| +/**
|
| + * Update the summary bar with descriptive text.
|
| + */
|
| +HistoryView.prototype.displaySummaryBar_ = function() {
|
| + var searchText = this.model_.getSearchText();
|
| + if (searchText != '') {
|
| + this.summaryDiv_.innerHTML = localStrings.formatString('searchresultsfor',
|
| + searchText);
|
| + } else {
|
| + this.summaryDiv_.innerHTML = localStrings.getString('history');
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Update the pagination tools.
|
| + */
|
| +HistoryView.prototype.displayNavBar_ = function() {
|
| + var navOutput = [];
|
| + if (this.pageIndex_ > 0) {
|
| + navOutput.push(this.createPageNavHTML_(0,
|
| + localStrings.getString('newest')));
|
| + navOutput.push(this.createPageNavHTML_(
|
| + this.pageIndex_ - 1, localStrings.getString('newer')));
|
| + }
|
| + if (this.model_.getSize() > (this.pageIndex_ + 1) * RESULTS_PER_PAGE) {
|
| + navOutput.push(this.createPageNavHTML_(
|
| + this.pageIndex_ + 1, localStrings.getString('older')));
|
| + }
|
| + this.pageDiv_.innerHTML = navOutput.join("");
|
| +}
|
| +
|
| +/**
|
| + * Get the HTML representation of a page navigation link.
|
| + * @param {number} page The page index the navigation element should link to
|
| + * @param {string} name The text content of the link
|
| + * @return {string} HTML representation of the pagination link
|
| + */
|
| +HistoryView.prototype.createPageNavHTML_ = function(page, name) {
|
| + var hashString = PageState.getHashString(this.model_.getSearchText(), page);
|
| + return '<a href="chrome://history/' +
|
| + (hashString ? '#' + hashString : '') +
|
| + '"' +
|
| + 'class="page-navigation"' +
|
| + 'onclick="setPage(' + page + '); return false;"' +
|
| + '>' + name + '</a>';
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// State object:
|
| +/**
|
| + * An 'AJAX-history' implementation.
|
| + * @param {HistoryModel} model The model we're representing
|
| + * @param {HistoryView} view The view we're representing
|
| + */
|
| +function PageState(model, view) {
|
| + // Enforce a singleton.
|
| + if (PageState.instance) {
|
| + return PageState.instance;
|
| + }
|
| +
|
| + this.model = model;
|
| + this.view = view;
|
| +
|
| + if (typeof this.checker_ != 'undefined' && this.checker_) {
|
| + clearInterval(this.checker_);
|
| + }
|
| +
|
| + // TODO(glen): Replace this with a bound method so we don't need
|
| + // public model and view.
|
| + this.checker_ = setInterval((function(state_obj) {
|
| + var hashData = state_obj.getHashData();
|
| +
|
| + if (hashData.q != state_obj.model.getSearchText(term)) {
|
| + state_obj.view.setSearch(hashData.q, parseInt(hashData.p));
|
| + } else if (parseInt(hashData.p) != state_obj.view.getPage()) {
|
| + state_obj.view.setPage(hashData.p);
|
| + }
|
| + }), 50, this);
|
| +}
|
| +
|
| +PageState.instance = null;
|
| +
|
| +/**
|
| + * @return {Object} An object containing parameters from our window hash.
|
| + */
|
| +PageState.prototype.getHashData = function() {
|
| + var result = {
|
| + q : '',
|
| + p : 0
|
| + };
|
| +
|
| + if (!window.location.hash) {
|
| + return result;
|
| + }
|
| +
|
| + var hashSplit = window.location.hash.substr(1).split("&");
|
| + for (var i = 0; i < hashSplit.length; i++) {
|
| + var pair = hashSplit[i].split("=");
|
| + if (pair.length > 1) {
|
| + result[pair[0]] = unescape(pair[1]);
|
| + }
|
| + }
|
| +
|
| + return result;
|
| +}
|
| +
|
| +/**
|
| + * Set the hash to a specified state, this will create an entry in the
|
| + * session history so the back button cycles through hash states, which
|
| + * are then picked up by our listener.
|
| + * @param {string} term The current search string.
|
| + * @param {string} page The page currently being viewed.
|
| + */
|
| +PageState.prototype.setUIState = function(term, page) {
|
| + // Make sure the form looks pretty.
|
| + document.forms[0].term.value = term;
|
| +
|
| + var hash = PageState.getHashString(term, page);
|
| + if (window.location.hash.substr(1) != hash) {
|
| + window.location.hash = hash;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Static method to get the hash string for a specified state
|
| + * @param {string} term The current search string.
|
| + * @param {string} page The page currently being viewed.
|
| + * @return {string} The string to be used in a hash.
|
| + */
|
| +PageState.getHashString = function(term, page) {
|
| + var newHash = [];
|
| + if (term) {
|
| + newHash.push("q=" + escape(term));
|
| + }
|
| + if (page) {
|
| + newHash.push("p=" + page);
|
| + }
|
| +
|
| + return newHash.join("&");
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// Document Functions:
|
| +/**
|
| + * Window onload handler, sets up the page.
|
| + */
|
| + function load() {
|
| + localStrings = new LocalStrings($('l10n'));
|
| + historyModel = new HistoryModel();
|
| + historyView = new HistoryView(historyModel);
|
| + pageState = new PageState(historyModel, historyView);
|
| +
|
| + // Create default view.
|
| + var hashData = pageState.getHashData();
|
| + historyView.setSearch(hashData.q, hashData.p);
|
| +}
|
| +
|
| +/**
|
| + * TODO(glen): Get rid of this function.
|
| + * Set the history view to a specified page.
|
| + * @param {String} term The string to search for
|
| + */
|
| +function setSearch(term) {
|
| + if (historyView) {
|
| + historyView.setSearch(term);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * TODO(glen): Get rid of this function.
|
| + * Set the history view to a specified page.
|
| + * @param {number} page The page to set the view to.
|
| + */
|
| +function setPage(page) {
|
| + if (historyView) {
|
| + historyView.setPage(page);
|
| + }
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// Chrome callbacks:
|
| +/**
|
| + * Our history system calls this function with results from searches.
|
| + */
|
| +function historyResult(term, results) {
|
| + historyModel.addResults(term, results);
|
| +}
|
| +</script>
|
| +<style type="text/css">
|
| +body {
|
| + font-family:arial;
|
| + background-color:white;
|
| + color:black;
|
| + font-size:84%;
|
| + margin:10px;
|
| +}
|
| +.header {
|
| + overflow:auto;
|
| + clear:both;
|
| +}
|
| +.header .logo {
|
| + float:left;
|
| +}
|
| +.header .form {
|
| + float:left;
|
| + margin-top:22px;
|
| + margin-left:12px;
|
| +}
|
| +#results-summary {
|
| + margin-top:12px;
|
| + border-top:1px solid #9cc2ef;
|
| + background-color:#ebeff9;
|
| + font-weight:bold;
|
| + padding:3px;
|
| + margin-bottom:-8px;
|
| +}
|
| +#results-display {
|
| + max-width:740px;
|
| +}
|
| +.day {
|
| + margin-top:18px;
|
| + margin-left:3px;
|
| +}
|
| +.gap {
|
| + margin-left:18px;
|
| + width:15px;
|
| + border-right:1px solid #ddd;
|
| + height:14px;
|
| +}
|
| +.entry {
|
| + margin-left:18px;
|
| + margin-top:6px;
|
| + overflow:auto;
|
| +}
|
| +table.results {
|
| + margin-left:4px;
|
| +}
|
| +.entry .time {
|
| + color:#888;
|
| + float:left;
|
| + min-width:56px;
|
| + margin-right:5px;
|
| + padding-top:1px;
|
| +}
|
| +.entry .title {
|
| + max-width:600px;
|
| + overflow: hidden;
|
| + white-space: nowrap;
|
| + text-overflow: ellipsis;
|
| +}
|
| +.results .time, .results .title {
|
| + margin-top:18px;
|
| +}
|
| +.entry .title a {
|
| + background-repeat:no-repeat;
|
| + background-size:16px;
|
| + background-position:0px 1px;
|
| + padding:1px 0px 4px 22px;
|
| +}
|
| +html[dir='rtl'] .entry .title a {
|
| + background-position:right;
|
| + padding-left:0px;
|
| + padding-right:22px;
|
| +}
|
| +#results-pagination {
|
| + padding-top:24px;
|
| + margin-left:18px;
|
| +}
|
| +.page-navigation {
|
| + padding:8px;
|
| + background-color:#ebeff9;
|
| + margin-right:4px;
|
| +}
|
| +.footer {
|
| + height:24px;
|
| +}
|
| +</style>
|
| +</head>
|
| +<body onload="load();">
|
| +<div class="header">
|
| + <a href="" onclick="setSearch(''); return false;">
|
| + <img src="../../app/theme/history_section.png"
|
| + width="67" height="67" class="logo" border="0" /></a>
|
| + <form method="post" action=""
|
| + onsubmit="setSearch(this.term.value); return false;"
|
| + class="form">
|
| + <input type="text" name="term" id="term" />
|
| + <input type="submit" name="submit" jsvalues="value:searchbutton" />
|
| + </form>
|
| +</div>
|
| +<div class="main">
|
| + <div id="results-summary"></div>
|
| + <div id="results-display"></div>
|
| + <div id="results-pagination"></div>
|
| +</div>
|
| +<div class="footer">
|
| +</div>
|
| +<div id="l10n" style="display:none;">
|
| + <span id="loading" jscontent="loading">Loading...</span>
|
| + <span id="newest" jscontent="newest">« Newest</span>
|
| + <span id="newer" jscontent="newer">‹ Newer</span>
|
| + <span id="older" jscontent="older">Older ›</span>
|
| + <span id="searchresultsfor" jscontent="searchresultsfor">Search results for '%s'</span>
|
| + <span id="history" jscontent="history">History</span>
|
| + <span id="cont" jscontent="cont">(cont.)</span>
|
| + <span id="noresults" jscontent="noresults">No results</span>
|
| + <span id="noitems" jscontent="noitems">No items</span>
|
| + <span id="delete" jscontent="delete">delete</span>
|
| +</div>
|
| +</body>
|
| +</html>
|
|
|