OLD | NEW |
1 <!DOCTYPE HTML> | 1 <!DOCTYPE HTML> |
2 <html id="t"> | 2 <html id="t"> |
3 <head> | 3 <head> |
4 <meta charset="utf-8"> | 4 <meta charset="utf-8"> |
5 <title jscontent="title"></title> | 5 <title jscontent="title"></title> |
6 <script type="text/javascript"> | 6 <script type="text/javascript"> |
7 /////////////////////////////////////////////////////////////////////////////// | 7 /////////////////////////////////////////////////////////////////////////////// |
8 // Globals: | 8 // Globals: |
9 var RESULTS_PER_PAGE = 150; | 9 var RESULTS_PER_PAGE = 150; |
10 var MAX_SEARCH_DEPTH_MONTHS = 18; | 10 var MAX_SEARCH_DEPTH_MONTHS = 18; |
11 | 11 |
12 // Amount of time between pageviews that we consider a 'break' in browsing, | 12 // Amount of time between pageviews that we consider a 'break' in browsing, |
13 // measured in milliseconds. | 13 // measured in milliseconds. |
14 var BROWSING_GAP_TIME = 15 * 60 * 1000; | 14 var BROWSING_GAP_TIME = 15 * 60 * 1000; |
15 | 15 |
16 function $(o) {return document.getElementById(o);} | 16 function $(o) {return document.getElementById(o);} |
17 | 17 |
18 // TODO(glen): Get rid of these global references, replace with a controller | 18 // TODO(glen): Get rid of these global references, replace with a controller |
19 // or just make the classes own more of the page. | 19 // or just make the classes own more of the page. |
20 var historyModel; | 20 var historyModel; |
21 var historyView; | 21 var historyView; |
22 var localStrings; | 22 var localStrings; |
23 var pageState; | 23 var pageState; |
24 | 24 |
25 /////////////////////////////////////////////////////////////////////////////// | 25 /////////////////////////////////////////////////////////////////////////////// |
26 // localStrings: | 26 // localStrings: |
27 /** | 27 /** |
28 * We get strings into the page by using JSTemplate to populate some elements | 28 * We get strings into the page by using JSTemplate to populate some elements |
29 * with localized content, then reading the content of those elements into | 29 * with localized content, then reading the content of those elements into |
30 * this global strings object. | 30 * this global strings object. |
31 * @param {Node} node The DOM node containing all our strings. | 31 * @param {Node} node The DOM node containing all our strings. |
32 */ | 32 */ |
33 function LocalStrings(node) { | 33 function LocalStrings(node) { |
34 this.strings_ = {}; | 34 this.strings_ = {}; |
35 | 35 |
36 var children = node.childNodes; | 36 var children = node.childNodes; |
37 for (var i = 0, child; child = children[i]; i++) { | 37 for (var i = 0, child; child = children[i]; i++) { |
38 var id = child.id; | 38 var id = child.id; |
39 if (id) { | 39 if (id) { |
40 this.strings_[id] = child.innerHTML; | 40 this.strings_[id] = child.innerHTML; |
41 } | 41 } |
42 } | 42 } |
43 } | 43 } |
44 | 44 |
45 /** | 45 /** |
46 * Gets a localized string by its id. | 46 * Gets a localized string by its id. |
47 * @param {string} s The id of the string we want | 47 * @param {string} s The id of the string we want |
48 * @return {string} The localized string | 48 * @return {string} The localized string |
49 */ | 49 */ |
50 LocalStrings.prototype.getString = function(s) { | 50 LocalStrings.prototype.getString = function(s) { |
51 return (s in this.strings_) ? this.strings_[s] : ''; | 51 return (s in this.strings_) ? this.strings_[s] : ''; |
52 } | 52 } |
53 | 53 |
54 /** | 54 /** |
55 * Returns a formatted localized string (where all %s contents are replaced | 55 * Returns a formatted localized string (where all %s contents are replaced |
56 * by the second argument). | 56 * by the second argument). |
57 * @param {string} s The id of the string we want | 57 * @param {string} s The id of the string we want |
58 * @param {string} d The string to include in the formatted string | 58 * @param {string} d The string to include in the formatted string |
59 * @return {string} The formatted string. | 59 * @return {string} The formatted string. |
60 */ | 60 */ |
61 LocalStrings.prototype.formatString = function(s, d) { | 61 LocalStrings.prototype.formatString = function(s, d) { |
62 return (s in this.strings_) ? this.strings_[s].replace(/\%s/, d) : ''; | 62 return (s in this.strings_) ? this.strings_[s].replace(/\%s/, d) : ''; |
63 } | 63 } |
64 | 64 |
65 /////////////////////////////////////////////////////////////////////////////// | 65 /////////////////////////////////////////////////////////////////////////////// |
66 // Page: | 66 // Page: |
67 /** | 67 /** |
68 * Class to hold all the information about an entry in our model. | 68 * Class to hold all the information about an entry in our model. |
69 * @param {Object} result An object containing the page's data. | 69 * @param {Object} result An object containing the page's data. |
70 * @param {boolean} continued Whether this page is on the same day as the | 70 * @param {boolean} continued Whether this page is on the same day as the |
71 * page before it | 71 * page before it |
72 */ | 72 */ |
73 function Page(result, continued, model) { | 73 function Page(result, continued, model) { |
74 this.model_ = model; | 74 this.model_ = model; |
75 this.title_ = result.title; | 75 this.title_ = result.title; |
76 this.url_ = result.url; | 76 this.url_ = result.url; |
77 this.snippet_ = result.snippet || ""; | 77 this.snippet_ = result.snippet || ""; |
78 | 78 |
| 79 this.changed = false; |
| 80 |
79 // All the date information is public so that owners can compare properties of | 81 // All the date information is public so that owners can compare properties of |
80 // two items easily. | 82 // two items easily. |
81 | 83 |
82 // We get the time in seconds, but we want it in milliseconds. | 84 // We get the time in seconds, but we want it in milliseconds. |
83 this.time = new Date(result.time * 1000); | 85 this.time = new Date(result.time * 1000); |
84 | 86 |
85 // See comment in BrowsingHistoryHandler::QueryComplete - we won't always | 87 // See comment in BrowsingHistoryHandler::QueryComplete - we won't always |
86 // get all of these. | 88 // get all of these. |
87 this.dateRelativeDay = result.dateRelativeDay || ""; | 89 this.dateRelativeDay = result.dateRelativeDay || ""; |
88 this.dateTimeOfDay = result.dateTimeOfDay || ""; | 90 this.dateTimeOfDay = result.dateTimeOfDay || ""; |
89 this.dateShort = result.dateShort || ""; | 91 this.dateShort = result.dateShort || ""; |
90 | 92 |
91 // Whether this is the continuation of a previous day. | 93 // Whether this is the continuation of a previous day. |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 var oldLength = this.pages_.length; | 267 var oldLength = this.pages_.length; |
266 if (oldLength) { | 268 if (oldLength) { |
267 var oldPage = this.pages_[oldLength - 1]; | 269 var oldPage = this.pages_[oldLength - 1]; |
268 lastURL = oldPage.url; | 270 lastURL = oldPage.url; |
269 lastDay = oldPage.dateRelativeDay; | 271 lastDay = oldPage.dateRelativeDay; |
270 } | 272 } |
271 | 273 |
272 for (var i = 0, thisResult; thisResult = results[i]; i++) { | 274 for (var i = 0, thisResult; thisResult = results[i]; i++) { |
273 var thisURL = thisResult.url; | 275 var thisURL = thisResult.url; |
274 var thisDay = thisResult.dateRelativeDay; | 276 var thisDay = thisResult.dateRelativeDay; |
275 | 277 |
276 // Remove adjacent duplicates. | 278 // Remove adjacent duplicates. |
277 if (!lastURL || lastURL != thisURL) { | 279 if (!lastURL || lastURL != thisURL) { |
278 // Figure out if this page is in the same day as the previous page, | 280 // Figure out if this page is in the same day as the previous page, |
279 // this is used to determine how day headers should be drawn. | 281 // this is used to determine how day headers should be drawn. |
280 this.pages_.push(new Page(thisResult, thisDay == lastDay, this)); | 282 this.pages_.push(new Page(thisResult, thisDay == lastDay, this)); |
281 lastDay = thisDay; | 283 lastDay = thisDay; |
282 lastURL = thisURL; | 284 lastURL = thisURL; |
283 } | 285 } |
284 } | 286 } |
285 } | 287 } |
| 288 if (results.length) |
| 289 this.changed = true; |
286 | 290 |
287 this.updateSearch_(); | 291 this.updateSearch_(); |
288 } | 292 } |
289 | 293 |
290 /** | 294 /** |
291 * @return {Number} The number of pages in the model. | 295 * @return {Number} The number of pages in the model. |
292 */ | 296 */ |
293 HistoryModel.prototype.getSize = function() { | 297 HistoryModel.prototype.getSize = function() { |
294 return this.pages_.length; | 298 return this.pages_.length; |
295 } | 299 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
334 /** | 338 /** |
335 * Figure out if we need to do more searches to fill the currently requested | 339 * Figure out if we need to do more searches to fill the currently requested |
336 * page. If we think we can fill the page, call the view and let it know | 340 * page. If we think we can fill the page, call the view and let it know |
337 * we're ready to show something. | 341 * we're ready to show something. |
338 */ | 342 */ |
339 HistoryModel.prototype.updateSearch_ = function() { | 343 HistoryModel.prototype.updateSearch_ = function() { |
340 if (this.searchText_ && this.searchDepth_ >= MAX_SEARCH_DEPTH_MONTHS) { | 344 if (this.searchText_ && this.searchDepth_ >= MAX_SEARCH_DEPTH_MONTHS) { |
341 // We have maxed out. There will be no more data. | 345 // We have maxed out. There will be no more data. |
342 this.complete_ = true; | 346 this.complete_ = true; |
343 this.view_.onModelReady(); | 347 this.view_.onModelReady(); |
| 348 this.changed = false; |
344 } else { | 349 } else { |
345 // If we can't fill the requested page, ask for more data unless a request | 350 // If we can't fill the requested page, ask for more data unless a request |
346 // is still in-flight. | 351 // is still in-flight. |
347 if (!this.canFillPage_(this.requestedPage_) && !this.inFlight_) { | 352 if (!this.canFillPage_(this.requestedPage_) && !this.inFlight_) { |
348 this.getSearchResults_(this.searchDepth_ + 1); | 353 this.getSearchResults_(this.searchDepth_ + 1); |
349 } | 354 } |
350 | 355 |
351 // If we have any data for the requested page, show it. | 356 // If we have any data for the requested page, show it. |
352 if (this.haveDataForPage_(this.requestedPage_)) { | 357 if (this.changed && this.haveDataForPage_(this.requestedPage_)) { |
353 this.view_.onModelReady(); | 358 this.view_.onModelReady(); |
| 359 this.changed = false; |
354 } | 360 } |
355 } | 361 } |
356 } | 362 } |
357 | 363 |
358 /** | 364 /** |
359 * Get search results for a selected depth. Our history system is optimized | 365 * Get search results for a selected depth. Our history system is optimized |
360 * for queries that don't cross month boundaries, but an entire month's | 366 * for queries that don't cross month boundaries, but an entire month's |
361 * worth of data is huge. When we're in browse mode (searchText is empty) | 367 * worth of data is huge. When we're in browse mode (searchText is empty) |
362 * we request the data a day at a time. When we're searching, a month is | 368 * we request the data a day at a time. When we're searching, a month is |
363 * used. | 369 * used. |
364 * | 370 * |
365 * TODO: Fix this for when the user's clock goes across month boundaries. | 371 * TODO: Fix this for when the user's clock goes across month boundaries. |
366 * @param {number} opt_day How many days back to do the search. | 372 * @param {number} opt_day How many days back to do the search. |
367 */ | 373 */ |
368 HistoryModel.prototype.getSearchResults_ = function(depth) { | 374 HistoryModel.prototype.getSearchResults_ = function(depth) { |
369 this.searchDepth_ = depth || 0; | 375 this.searchDepth_ = depth || 0; |
370 | 376 |
371 if (this.searchText_ == "") { | 377 if (this.searchText_ == "") { |
372 chrome.send('getHistory', | 378 chrome.send('getHistory', |
373 [String(this.searchDepth_)]); | 379 [String(this.searchDepth_)]); |
374 } else { | 380 } else { |
375 chrome.send('searchHistory', | 381 chrome.send('searchHistory', |
376 [this.searchText_, String(this.searchDepth_)]); | 382 [this.searchText_, String(this.searchDepth_)]); |
377 } | 383 } |
378 | 384 |
379 this.inFlight_ = true; | 385 this.inFlight_ = true; |
380 } | 386 } |
381 | 387 |
382 /** | 388 /** |
383 * Check to see if we have data for a given page. | 389 * Check to see if we have data for a given page. |
384 * @param {number} page The page number | 390 * @param {number} page The page number |
385 * @return {boolean} Whether we have any data for the given page. | 391 * @return {boolean} Whether we have any data for the given page. |
386 */ | 392 */ |
387 HistoryModel.prototype.haveDataForPage_ = function(page) { | 393 HistoryModel.prototype.haveDataForPage_ = function(page) { |
388 return (page * RESULTS_PER_PAGE < this.getSize()); | 394 return (page * RESULTS_PER_PAGE < this.getSize()); |
(...skipping 16 matching lines...) Expand all Loading... |
405 * getting called externally. | 411 * getting called externally. |
406 * @param {HistoryModel} model The model backing this view. | 412 * @param {HistoryModel} model The model backing this view. |
407 */ | 413 */ |
408 function HistoryView(model) { | 414 function HistoryView(model) { |
409 this.summaryDiv_ = $('results-summary'); | 415 this.summaryDiv_ = $('results-summary'); |
410 this.summaryDiv_.innerHTML = localStrings.getString('loading'); | 416 this.summaryDiv_.innerHTML = localStrings.getString('loading'); |
411 this.resultDiv_ = $('results-display'); | 417 this.resultDiv_ = $('results-display'); |
412 this.pageDiv_ = $('results-pagination'); | 418 this.pageDiv_ = $('results-pagination'); |
413 this.model_ = model | 419 this.model_ = model |
414 this.pageIndex_ = 0; | 420 this.pageIndex_ = 0; |
415 | 421 this.lastDisplayed_ = []; |
| 422 |
416 this.model_.setView(this); | 423 this.model_.setView(this); |
417 } | 424 } |
418 | 425 |
419 // HistoryView, public: ------------------------------------------------------- | 426 // HistoryView, public: ------------------------------------------------------- |
420 /** | 427 /** |
421 * Do a search and optionally view a certain page. | 428 * Do a search and optionally view a certain page. |
422 * @param {string} term The string to search for. | 429 * @param {string} term The string to search for. |
423 * @param {number} opt_page The page we wish to view, only use this for | 430 * @param {number} opt_page The page we wish to view, only use this for |
424 * setting up initial views, as this triggers a search. | 431 * setting up initial views, as this triggers a search. |
425 */ | 432 */ |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
479 'cellpadding="0" border="0">'); | 486 'cellpadding="0" border="0">'); |
480 for (var i = 0, page; page = results[i]; i++) { | 487 for (var i = 0, page; page = results[i]; i++) { |
481 output.push(page.getSearchResultHTML()); | 488 output.push(page.getSearchResultHTML()); |
482 } | 489 } |
483 output.push('</table>'); | 490 output.push('</table>'); |
484 } else { | 491 } else { |
485 var lastTime = Math.infinity; | 492 var lastTime = Math.infinity; |
486 for (var i = 0, page; page = results[i]; i++) { | 493 for (var i = 0, page; page = results[i]; i++) { |
487 // Break across day boundaries and insert gaps for browsing pauses. | 494 // Break across day boundaries and insert gaps for browsing pauses. |
488 var thisTime = page.time.getTime(); | 495 var thisTime = page.time.getTime(); |
489 | 496 |
490 if ((i == 0 && page.continued) || !page.continued) { | 497 if ((i == 0 && page.continued) || !page.continued) { |
491 output.push('<div class="day">' + page.dateRelativeDay); | 498 output.push('<div class="day">' + page.dateRelativeDay); |
492 | 499 |
493 if (i == 0 && page.continued) | 500 if (i == 0 && page.continued) |
494 output.push(' ' + localStrings.getString('cont')); | 501 output.push(' ' + localStrings.getString('cont')); |
495 | 502 |
496 output.push('<a href="#" class="delete-day" ' + | 503 output.push('<a href="#" class="delete-day" ' + |
497 'onclick="return deleteDay(\'' + | 504 'onclick="return deleteDay(\'' + |
498 page.time.toString() + '\');">' + | 505 page.time.toString() + '\');">' + |
499 localStrings.getString("deleteday") + '</a>'); | 506 localStrings.getString("deleteday") + '</a>'); |
500 output.push('</div>'); | 507 output.push('</div>'); |
501 } else if (lastTime - thisTime > BROWSING_GAP_TIME) { | 508 } else if (lastTime - thisTime > BROWSING_GAP_TIME) { |
502 output.push('<div class="gap"></div>'); | 509 output.push('<div class="gap"></div>'); |
503 } | 510 } |
504 lastTime = thisTime; | 511 lastTime = thisTime; |
505 | 512 |
506 // Draw entry. | 513 // Draw entry. |
507 output.push(page.getBrowseResultHTML()); | 514 output.push(page.getBrowseResultHTML()); |
508 } | 515 } |
509 } | 516 } |
510 this.resultDiv_.innerHTML = output.join(""); | 517 this.resultDiv_.innerHTML = output.join(""); |
511 this.displaySummaryBar_(); | 518 this.displaySummaryBar_(); |
512 this.displayNavBar_(); | 519 this.displayNavBar_(); |
513 } | 520 } |
(...skipping 11 matching lines...) Expand all Loading... |
525 } | 532 } |
526 } | 533 } |
527 | 534 |
528 /** | 535 /** |
529 * Update the pagination tools. | 536 * Update the pagination tools. |
530 */ | 537 */ |
531 HistoryView.prototype.displayNavBar_ = function() { | 538 HistoryView.prototype.displayNavBar_ = function() { |
532 var navOutput = ''; | 539 var navOutput = ''; |
533 if (this.pageIndex_ > 0) { | 540 if (this.pageIndex_ > 0) { |
534 navOutput += this.createPageNavHTML_(0, localStrings.getString('newest')); | 541 navOutput += this.createPageNavHTML_(0, localStrings.getString('newest')); |
535 navOutput += this.createPageNavHTML_(this.pageIndex_ - 1, | 542 navOutput += this.createPageNavHTML_(this.pageIndex_ - 1, |
536 localStrings.getString('newer')); | 543 localStrings.getString('newer')); |
537 } | 544 } |
538 if (this.model_.getSize() > (this.pageIndex_ + 1) * RESULTS_PER_PAGE) { | 545 if (this.model_.getSize() > (this.pageIndex_ + 1) * RESULTS_PER_PAGE) { |
539 navOutput += this.createPageNavHTML_(this.pageIndex_ + 1, | 546 navOutput += this.createPageNavHTML_(this.pageIndex_ + 1, |
540 localStrings.getString('older')); | 547 localStrings.getString('older')); |
541 } | 548 } |
542 this.pageDiv_.innerHTML = navOutput; | 549 this.pageDiv_.innerHTML = navOutput; |
543 } | 550 } |
544 | 551 |
545 /** | 552 /** |
546 * Get the HTML representation of a page navigation link. | 553 * Get the HTML representation of a page navigation link. |
547 * @param {number} page The page index the navigation element should link to | 554 * @param {number} page The page index the navigation element should link to |
548 * @param {string} name The text content of the link | 555 * @param {string} name The text content of the link |
549 * @return {string} HTML representation of the pagination link | 556 * @return {string} HTML representation of the pagination link |
(...skipping 13 matching lines...) Expand all Loading... |
563 /** | 570 /** |
564 * An 'AJAX-history' implementation. | 571 * An 'AJAX-history' implementation. |
565 * @param {HistoryModel} model The model we're representing | 572 * @param {HistoryModel} model The model we're representing |
566 * @param {HistoryView} view The view we're representing | 573 * @param {HistoryView} view The view we're representing |
567 */ | 574 */ |
568 function PageState(model, view) { | 575 function PageState(model, view) { |
569 // Enforce a singleton. | 576 // Enforce a singleton. |
570 if (PageState.instance) { | 577 if (PageState.instance) { |
571 return PageState.instance; | 578 return PageState.instance; |
572 } | 579 } |
573 | 580 |
574 this.model = model; | 581 this.model = model; |
575 this.view = view; | 582 this.view = view; |
576 | 583 |
577 if (typeof this.checker_ != 'undefined' && this.checker_) { | 584 if (typeof this.checker_ != 'undefined' && this.checker_) { |
578 clearInterval(this.checker_); | 585 clearInterval(this.checker_); |
579 } | 586 } |
580 | 587 |
581 // TODO(glen): Replace this with a bound method so we don't need | 588 // TODO(glen): Replace this with a bound method so we don't need |
582 // public model and view. | 589 // public model and view. |
583 this.checker_ = setInterval((function(state_obj) { | 590 this.checker_ = setInterval((function(state_obj) { |
584 var hashData = state_obj.getHashData(); | 591 var hashData = state_obj.getHashData(); |
585 | 592 |
586 if (hashData.q != state_obj.model.getSearchText(term)) { | 593 if (hashData.q != state_obj.model.getSearchText(term)) { |
587 state_obj.view.setSearch(hashData.q, parseInt(hashData.p, 10)); | 594 state_obj.view.setSearch(hashData.q, parseInt(hashData.p, 10)); |
588 } else if (parseInt(hashData.p, 10) != state_obj.view.getPage()) { | 595 } else if (parseInt(hashData.p, 10) != state_obj.view.getPage()) { |
589 state_obj.view.setPage(hashData.p); | 596 state_obj.view.setPage(hashData.p); |
590 } | 597 } |
591 }), 50, this); | 598 }), 50, this); |
592 } | 599 } |
593 | 600 |
594 PageState.instance = null; | 601 PageState.instance = null; |
595 | 602 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
649 newHash.push("p=" + page); | 656 newHash.push("p=" + page); |
650 } | 657 } |
651 | 658 |
652 return newHash.join("&"); | 659 return newHash.join("&"); |
653 } | 660 } |
654 | 661 |
655 /////////////////////////////////////////////////////////////////////////////// | 662 /////////////////////////////////////////////////////////////////////////////// |
656 // Document Functions: | 663 // Document Functions: |
657 /** | 664 /** |
658 * Window onload handler, sets up the page. | 665 * Window onload handler, sets up the page. |
659 */ | 666 */ |
660 function load() { | 667 function load() { |
661 localStrings = new LocalStrings($('l10n')); | 668 localStrings = new LocalStrings($('l10n')); |
662 historyModel = new HistoryModel(); | 669 historyModel = new HistoryModel(); |
663 historyView = new HistoryView(historyModel); | 670 historyView = new HistoryView(historyModel); |
664 pageState = new PageState(historyModel, historyView); | 671 pageState = new PageState(historyModel, historyView); |
665 | 672 |
666 // Create default view. | 673 // Create default view. |
667 var hashData = pageState.getHashData(); | 674 var hashData = pageState.getHashData(); |
668 historyView.setSearch(hashData.q, hashData.p); | 675 historyView.setSearch(hashData.q, hashData.p); |
669 } | 676 } |
670 | 677 |
671 /** | 678 /** |
672 * TODO(glen): Get rid of this function. | 679 * TODO(glen): Get rid of this function. |
673 * Set the history view to a specified page. | 680 * Set the history view to a specified page. |
674 * @param {String} term The string to search for | 681 * @param {String} term The string to search for |
675 */ | 682 */ |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
838 <span id="searchresultsfor" jscontent="searchresultsfor">Search results for '%
s'</span> | 845 <span id="searchresultsfor" jscontent="searchresultsfor">Search results for '%
s'</span> |
839 <span id="history" jscontent="history">History</span> | 846 <span id="history" jscontent="history">History</span> |
840 <span id="cont" jscontent="cont">(cont.)</span> | 847 <span id="cont" jscontent="cont">(cont.)</span> |
841 <span id="noresults" jscontent="noresults">No results</span> | 848 <span id="noresults" jscontent="noresults">No results</span> |
842 <span id="noitems" jscontent="noitems">No items</span> | 849 <span id="noitems" jscontent="noitems">No items</span> |
843 <span id="deleteday" jscontent="deleteday">Delete history for this day</span> | 850 <span id="deleteday" jscontent="deleteday">Delete history for this day</span> |
844 <span id="deletedaywarning" jscontent="deletedaywarning">Are you sure you want
to delete this day?</span> | 851 <span id="deletedaywarning" jscontent="deletedaywarning">Are you sure you want
to delete this day?</span> |
845 </div> | 852 </div> |
846 </body> | 853 </body> |
847 </html> | 854 </html> |
OLD | NEW |