Commit 9f234866 authored by calamity's avatar calamity Committed by Commit bot

[MD History] Add search for synced devices.

This CL implements a simple search that matches the functionality of the
original history page.

This CL also fixes a bug related to window separators in the synced view
that could cause excess window separators to appear.

BUG=610934
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2022003002
Cr-Commit-Position: refs/heads/master@{#398252}
parent 7b3867c7
...@@ -67,7 +67,8 @@ ...@@ -67,7 +67,8 @@
</template> </template>
<template is="dom-if" if="[[syncedTabsSelected_(selectedPage_)]]"> <template is="dom-if" if="[[syncedTabsSelected_(selectedPage_)]]">
<history-synced-device-manager id="history-synced-device-manager" <history-synced-device-manager id="history-synced-device-manager"
session-list="[[queryState_.sessionList]]"> session-list="[[queryState_.sessionList]]"
searched-term=[[queryState_.info.term]]>
</history-synced-device-manager> </history-synced-device-manager>
</template> </template>
</iron-pages> </iron-pages>
......
...@@ -69,6 +69,8 @@ cr.define('md_history', function() { ...@@ -69,6 +69,8 @@ cr.define('md_history', function() {
* occurrences of the search term in bold. * occurrences of the search term in bold.
* @private * @private
*/ */
// TODO(calamity): Pull this bolding behavior into a separate element for
// synced device search.
setSearchedTextToBold_: function() { setSearchedTextToBold_: function() {
var i = 0; var i = 0;
var titleElem = this.$.title; var titleElem = this.$.title;
......
...@@ -93,9 +93,9 @@ ...@@ -93,9 +93,9 @@
[[tab.title]] [[tab.title]]
</a> </a>
</div> </div>
<template is="dom-if" if="[[tab.needsWindowSeparator]]"> <div id="window-separator"
<div id="window-separator"></div> hidden$="[[!isWindowSeparatorIndex_(index, separatorIndexes)]]">
</template> </div>
</template> </template>
<div class="item-container"> <div class="item-container">
<p on-tap="openAllTabs_" id="open-tabs">$i18n{openAll}</p> <p on-tap="openAllTabs_" id="open-tabs">$i18n{openAll}</p>
......
...@@ -7,16 +7,10 @@ Polymer({ ...@@ -7,16 +7,10 @@ Polymer({
properties: { properties: {
// Name of the synced device. // Name of the synced device.
device: { device: {type: String, value: ''},
type: String,
value: ''
},
// When the device information was last updated. // When the device information was last updated.
lastUpdateTime: { lastUpdateTime: {type: String, value: ''},
type: String,
value: ''
},
/** /**
* The list of tabs open for this device. * The list of tabs open for this device.
...@@ -28,11 +22,16 @@ Polymer({ ...@@ -28,11 +22,16 @@ Polymer({
observer: 'updateIcons_' observer: 'updateIcons_'
}, },
/**
* The indexes where a window separator should be shown. The use of a
* separate array here is necessary for window separators to appear
* correctly in search. See http://crrev.com/2022003002 for more details.
* @type {!Array<number>}
*/
separatorIndexes: Array,
// Whether the card is open. // Whether the card is open.
cardOpen_: { cardOpen_: {type: Boolean, value: true},
type: Boolean,
value: true
},
}, },
/** /**
...@@ -68,5 +67,10 @@ Polymer({ ...@@ -68,5 +67,10 @@ Polymer({
cr.icon.getFaviconImageSet(this.tabs[i].url); cr.icon.getFaviconImageSet(this.tabs[i].url);
} }
}); });
},
/** @private */
isWindowSeparatorIndex_: function(index, separatorIndexes) {
return this.separatorIndexes.indexOf(index) != -1;
} }
}); });
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
<template is="dom-repeat" items="[[syncedDevices_]]" as="syncedDevice"> <template is="dom-repeat" items="[[syncedDevices_]]" as="syncedDevice">
<history-synced-device-card device="[[syncedDevice.device]]" <history-synced-device-card device="[[syncedDevice.device]]"
last-update-time="[[syncedDevice.lastUpdateTime]]" last-update-time="[[syncedDevice.lastUpdateTime]]"
tabs="[[syncedDevice.tabs]]"> tabs="[[syncedDevice.tabs]]"
separator-indexes="[[syncedDevice.separatorIndexes]]">
</history-synced-device-card> </history-synced-device-card>
</template> </template>
</template> </template>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
/** /**
* @typedef {{device: string, * @typedef {{device: string,
* lastUpdateTime: string, * lastUpdateTime: string,
* separatorIndexes: !Array<number>,
* timestamp: number, * timestamp: number,
* tabs: !Array<!ForeignSessionTab>, * tabs: !Array<!ForeignSessionTab>,
* tag: string}} * tag: string}}
...@@ -20,7 +21,12 @@ Polymer({ ...@@ -20,7 +21,12 @@ Polymer({
*/ */
sessionList: { sessionList: {
type: Array, type: Array,
observer: 'setSyncedHistory', observer: 'updateSyncedDevices'
},
searchedTerm: {
type: String,
observer: 'searchTermChanged'
}, },
/** /**
...@@ -39,20 +45,39 @@ Polymer({ ...@@ -39,20 +45,39 @@ Polymer({
*/ */
createInternalDevice_: function(session) { createInternalDevice_: function(session) {
var tabs = []; var tabs = [];
for (var j = 0; j < session.windows.length; j++) { var separatorIndexes = [];
var newTabs = session.windows[j].tabs; for (var i = 0; i < session.windows.length; i++) {
var newTabs = session.windows[i].tabs;
if (newTabs.length == 0) if (newTabs.length == 0)
continue; continue;
tabs = tabs.concat(newTabs);
tabs[tabs.length - 1].needsWindowSeparator = true; if (!this.searchedTerm) {
// Add all the tabs if there is no search term.
tabs = tabs.concat(newTabs);
separatorIndexes.push(tabs.length - 1);
} else {
var searchText = this.searchedTerm.toLowerCase();
var windowAdded = false;
for (var j = 0; j < newTabs.length; j++) {
var tab = newTabs[j];
if (tab.title.toLowerCase().indexOf(searchText) != -1) {
tabs.push(tab);
windowAdded = true;
}
}
if (windowAdded)
separatorIndexes.push(tabs.length - 1);
}
} }
return { return {
device: session.name, device: session.name,
lastUpdateTime: '' + session.modifiedTime, lastUpdateTime: '' + session.modifiedTime,
separatorIndexes: separatorIndexes,
timestamp: session.timestamp, timestamp: session.timestamp,
tabs: tabs, tabs: tabs,
tag: session.tag tag: session.tag,
}; };
}, },
...@@ -62,9 +87,9 @@ Polymer({ ...@@ -62,9 +87,9 @@ Polymer({
* avoid doing extra work in this case. The logic could be more intelligent * avoid doing extra work in this case. The logic could be more intelligent
* about updating individual tabs rather than replacing whole sessions, but * about updating individual tabs rather than replacing whole sessions, but
* this approach seems to have acceptable performance. * this approach seems to have acceptable performance.
* @param {!Array<!ForeignSession>} sessionList * @param {?Array<!ForeignSession>} sessionList
*/ */
setSyncedHistory: function(sessionList) { updateSyncedDevices: function(sessionList) {
if (!sessionList) if (!sessionList)
return; return;
...@@ -83,5 +108,10 @@ Polymer({ ...@@ -83,5 +108,10 @@ Polymer({
for (var i = updateCount; i < sessionList.length; i++) { for (var i = updateCount; i < sessionList.length; i++) {
this.push('syncedDevices_', this.createInternalDevice_(sessionList[i])); this.push('syncedDevices_', this.createInternalDevice_(sessionList[i]));
} }
},
searchTermChanged: function(searchedTerm) {
this.syncedDevices_ = [];
this.updateSyncedDevices(this.sessionList);
} }
}); });
...@@ -31,6 +31,16 @@ cr.define('md_history.history_synced_tabs_test', function() { ...@@ -31,6 +31,16 @@ cr.define('md_history.history_synced_tabs_test', function() {
var app; var app;
var element; var element;
var numWindowSeparators = function(card) {
return Polymer.dom(card.root).
querySelectorAll(':not([hidden])#window-separator').length;
};
var getCards = function() {
return Polymer.dom(element.root).
querySelectorAll('history-synced-device-card');
}
suiteSetup(function() { suiteSetup(function() {
app = $('history-app'); app = $('history-app');
// Not rendered until selected. // Not rendered until selected.
...@@ -65,7 +75,7 @@ cr.define('md_history.history_synced_tabs_test', function() { ...@@ -65,7 +75,7 @@ cr.define('md_history.history_synced_tabs_test', function() {
[createWindow(['http://www.google.com', 'http://example.com'])] [createWindow(['http://www.google.com', 'http://example.com'])]
), ),
createSession( createSession(
'Nexus 5', 'Nexus 6',
[ [
createWindow(['http://test.com']), createWindow(['http://test.com']),
createWindow(['http://www.gmail.com', 'http://badssl.com']) createWindow(['http://www.gmail.com', 'http://badssl.com'])
...@@ -75,19 +85,12 @@ cr.define('md_history.history_synced_tabs_test', function() { ...@@ -75,19 +85,12 @@ cr.define('md_history.history_synced_tabs_test', function() {
setForeignSessions(sessionList, true); setForeignSessions(sessionList, true);
return flush().then(function() { return flush().then(function() {
var cards = Polymer.dom(element.root) var cards = getCards();
.querySelectorAll('history-synced-device-card');
assertEquals(2, cards.length); assertEquals(2, cards.length);
// Ensure separators between windows are added appropriately. // Ensure separators between windows are added appropriately.
assertEquals( assertEquals(1, numWindowSeparators(cards[0]));
1, Polymer.dom(cards[0].root) assertEquals(2, numWindowSeparators(cards[1]));
.querySelectorAll('#window-separator')
.length);
assertEquals(
2, Polymer.dom(cards[1].root)
.querySelectorAll('#window-separator')
.length);
}); });
}); });
...@@ -114,15 +117,11 @@ cr.define('md_history.history_synced_tabs_test', function() { ...@@ -114,15 +117,11 @@ cr.define('md_history.history_synced_tabs_test', function() {
return flush(); return flush();
}).then(function() { }).then(function() {
// There should only be two cards. // There should only be two cards.
var cards = Polymer.dom(element.root) var cards = getCards();
.querySelectorAll('history-synced-device-card');
assertEquals(2, cards.length); assertEquals(2, cards.length);
// There are now 2 windows in the first device. // There are now 2 windows in the first device.
assertEquals( assertEquals(2, numWindowSeparators(cards[0]));
2, Polymer.dom(cards[0].root)
.querySelectorAll('#window-separator')
.length);
// Check that the actual link changes. // Check that the actual link changes.
assertEquals( assertEquals(
...@@ -133,8 +132,50 @@ cr.define('md_history.history_synced_tabs_test', function() { ...@@ -133,8 +132,50 @@ cr.define('md_history.history_synced_tabs_test', function() {
}); });
}); });
test('two cards, multiple windows, search', function() {
var sessionList = [
createSession(
'Nexus 5',
[createWindow(['http://www.google.com', 'http://example.com'])]
),
createSession(
'Nexus 6',
[
createWindow(['http://www.gmail.com', 'http://badssl.com']),
createWindow(['http://test.com']),
createWindow(['http://www.gmail.com', 'http://bagssl.com'])
]
),
];
setForeignSessions(sessionList, true);
return flush().then(function() {
var cards = getCards();
assertEquals(2, cards.length);
// Ensure separators between windows are added appropriately.
assertEquals(1, numWindowSeparators(cards[0]));
assertEquals(3, numWindowSeparators(cards[1]));
element.searchedTerm = 'g';
return flush();
}).then(function() {
var cards = getCards();
assertEquals(1, numWindowSeparators(cards[0]));
assertEquals(1, cards[0].tabs.length);
assertEquals('http://www.google.com', cards[0].tabs[0].title);
assertEquals(2, numWindowSeparators(cards[1]));
assertEquals(3, cards[1].tabs.length);
assertEquals('http://www.gmail.com', cards[1].tabs[0].title);
assertEquals('http://www.gmail.com', cards[1].tabs[1].title);
assertEquals('http://bagssl.com', cards[1].tabs[2].title);
});
});
teardown(function() { teardown(function() {
element.syncedDevices = []; element.syncedDevices = [];
element.searchedTerm = '';
}); });
}); });
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment