Commit 0eca0b0d authored by rbpotter's avatar rbpotter Committed by Commit Bot

Web UI: Add cr-splitter and use to replace cr.ui.splitter in Bookmarks

Add a new cr-splitter Polymer element and use this to replace
cr.ui.Splitter in the bookmarks page. cr.ui.splitter depends on
cr.ui.define(), which will not be migrated to Polymer 3.

Also generate Polymer 3 versions of the new cr-splitter and its tests.

Fixed: 1023002
Change-Id: Ie8360353c1e67fa5fc8d2fcf3d09002621d71ba4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1910701
Commit-Queue: Rebekah Potter <rbpotter@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#714811}
parent 255b9598
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<link rel="import" href="chrome://resources/cr_components/managed_footnote/managed_footnote.html"> <link rel="import" href="chrome://resources/cr_components/managed_footnote/managed_footnote.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html"> <link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html">
<link rel="import" href="chrome://resources/html/cr/ui/splitter.html"> <link rel="import" href="chrome://resources/cr_elements/cr_splitter/cr_splitter.html">
<link rel="import" href="chrome://resources/html/find_shortcut_behavior.html"> <link rel="import" href="chrome://resources/html/find_shortcut_behavior.html">
<link rel="import" href="api_listener.html"> <link rel="import" href="api_listener.html">
<link rel="import" href="command_manager.html"> <link rel="import" href="command_manager.html">
...@@ -96,7 +96,7 @@ ...@@ -96,7 +96,7 @@
<bookmarks-folder-node item-id="0" depth="-1"></bookmarks-folder-node> <bookmarks-folder-node item-id="0" depth="-1"></bookmarks-folder-node>
<managed-footnote></managed-footnote> <managed-footnote></managed-footnote>
</div> </div>
<div id="splitter"></div> <cr-splitter id="splitter"></cr-splitter>
<bookmarks-list></bookmarks-list> <bookmarks-list></bookmarks-list>
</div> </div>
<bookmarks-router></bookmarks-router> <bookmarks-router></bookmarks-router>
......
...@@ -90,7 +90,6 @@ Polymer({ ...@@ -90,7 +90,6 @@ Polymer({
*/ */
initializeSplitter_: function() { initializeSplitter_: function() {
const splitter = this.$.splitter; const splitter = this.$.splitter;
cr.ui.Splitter.decorate(splitter);
const splitterTarget = this.$.sidebar; const splitterTarget = this.$.sidebar;
// The splitter persists the size of the left component in the local store. // The splitter persists the size of the left component in the local store.
......
...@@ -188,6 +188,7 @@ js2gtest("browser_tests_js_webui") { ...@@ -188,6 +188,7 @@ js2gtest("browser_tests_js_webui") {
"$root_gen_dir/chrome/test/data/webui/cr_elements/cr_radio_button_test.m.js", "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_radio_button_test.m.js",
"$root_gen_dir/chrome/test/data/webui/cr_elements/cr_radio_group_test.m.js", "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_radio_group_test.m.js",
"$root_gen_dir/chrome/test/data/webui/cr_elements/cr_search_field_tests.m.js", "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_search_field_tests.m.js",
"$root_gen_dir/chrome/test/data/webui/cr_elements/cr_splitter_test.m.js",
"$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_test.m.js", "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_test.m.js",
"$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_manager_test.m.js", "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_manager_test.m.js",
"$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.m.js", "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.m.js",
......
...@@ -22,6 +22,7 @@ js_modulizer("modulize") { ...@@ -22,6 +22,7 @@ js_modulizer("modulize") {
"cr_radio_button_test.js", "cr_radio_button_test.js",
"cr_radio_group_test.js", "cr_radio_group_test.js",
"cr_search_field_tests.js", "cr_search_field_tests.js",
"cr_splitter_test.js",
"cr_toolbar_search_field_tests.js", "cr_toolbar_search_field_tests.js",
"cr_tabs_test.js", "cr_tabs_test.js",
"cr_toast_test.js", "cr_toast_test.js",
......
...@@ -408,6 +408,28 @@ TEST_F('CrElementsSliderTest', 'All', function() { ...@@ -408,6 +408,28 @@ TEST_F('CrElementsSliderTest', 'All', function() {
mocha.run(); mocha.run();
}); });
/**
* @constructor
* @extends {CrElementsBrowserTest}
*/
function CrElementsSplitterTest() {}
CrElementsSplitterTest.prototype = {
__proto__: CrElementsBrowserTest.prototype,
/** @override */
browsePreload: 'chrome://resources/cr_elements/cr_splitter/cr_splitter.html',
/** @override */
extraLibraries: CrElementsBrowserTest.prototype.extraLibraries.concat([
'cr_splitter_test.js',
]),
};
TEST_F('CrElementsSplitterTest', 'All', function() {
mocha.run();
});
/** /**
* @constructor * @constructor
* @extends {CrElementsBrowserTest} * @extends {CrElementsBrowserTest}
......
...@@ -184,6 +184,18 @@ TEST_F('CrElementsSearchFieldV3Test', 'All', function() { ...@@ -184,6 +184,18 @@ TEST_F('CrElementsSearchFieldV3Test', 'All', function() {
mocha.run(); mocha.run();
}); });
// eslint-disable-next-line no-var
var CrElementsSplitterV3Test = class extends CrElementsV3BrowserTest {
/** @override */
get browsePreload() {
return 'chrome://test?module=cr_elements/cr_splitter_test.m.js';
}
};
TEST_F('CrElementsSplitterV3Test', 'All', function() {
mocha.run();
});
// eslint-disable-next-line no-var // eslint-disable-next-line no-var
var CrElementsToastV3Test = class extends CrElementsV3BrowserTest { var CrElementsToastV3Test = class extends CrElementsV3BrowserTest {
/** @override */ /** @override */
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// clang-format off
// #import 'chrome://resources/cr_elements/cr_splitter/cr_splitter.m.js';
// clang-format on
suite('cr-splitter', function() {
let crSplitter;
setup(function() {
PolymerTest.clearBody();
document.body.innerHTML = `
<div id="previous"></div>
<cr-splitter id="splitter"></cr-splitter>
<div id="next"></div>`;
crSplitter = document.querySelector('#splitter');
});
test('ignores right mouse', function() {
const downRight =
new MouseEvent('mousedown', {button: 1, cancelable: true});
assertTrue(crSplitter.dispatchEvent(downRight));
assertFalse(downRight.defaultPrevented);
const downLeft = new MouseEvent('mousedown', {button: 0, cancelable: true});
assertFalse(crSplitter.dispatchEvent(downLeft));
assertTrue(downLeft.defaultPrevented);
});
test('resize previous element', function() {
crSplitter.resizeNextElement = false;
const previousElement = document.getElementById('previous');
previousElement.style.width = '0px';
const beforeWidth = previousElement.getBoundingClientRect().width;
const down =
new MouseEvent('mousedown', {button: 0, cancelable: true, clientX: 0});
crSplitter.dispatchEvent(down);
let move =
new MouseEvent('mousemove', {button: 0, cancelable: true, clientX: 50});
crSplitter.dispatchEvent(move);
move = new MouseEvent(
'mousemove', {button: 0, cancelable: true, clientX: 100});
crSplitter.dispatchEvent(move);
const up =
new MouseEvent('mouseup', {button: 0, cancelable: true, clientX: 100});
crSplitter.dispatchEvent(up);
const afterWidth = previousElement.getBoundingClientRect().width;
assertEquals(100, afterWidth - beforeWidth);
});
test('resize next element', function() {
crSplitter.resizeNextElement = true;
const nextElement = document.getElementById('next');
nextElement.style.width = '0px';
const beforeWidth = nextElement.getBoundingClientRect().width;
const down = new MouseEvent(
'mousedown', {button: 0, cancelable: true, clientX: 100});
crSplitter.dispatchEvent(down);
let move =
new MouseEvent('mousemove', {button: 0, cancelable: true, clientX: 50});
crSplitter.dispatchEvent(move);
move =
new MouseEvent('mousemove', {button: 0, cancelable: true, clientX: 0});
crSplitter.dispatchEvent(move);
const up =
new MouseEvent('mouseup', {button: 0, cancelable: true, clientX: 0});
crSplitter.dispatchEvent(up);
const afterWidth = nextElement.getBoundingClientRect().width;
assertEquals(100, afterWidth - beforeWidth);
});
});
...@@ -24,6 +24,7 @@ group("closure_compile") { ...@@ -24,6 +24,7 @@ group("closure_compile") {
"cr_radio_group:closure_compile", "cr_radio_group:closure_compile",
"cr_search_field:closure_compile", "cr_search_field:closure_compile",
"cr_slider:closure_compile", "cr_slider:closure_compile",
"cr_splitter:closure_compile",
"cr_tabs:closure_compile", "cr_tabs:closure_compile",
"cr_toast:closure_compile", "cr_toast:closure_compile",
"cr_toggle:closure_compile", "cr_toggle:closure_compile",
...@@ -45,6 +46,7 @@ group("closure_compile") { ...@@ -45,6 +46,7 @@ group("closure_compile") {
"cr_radio_button:closure_compile_module", "cr_radio_button:closure_compile_module",
"cr_radio_group:closure_compile_module", "cr_radio_group:closure_compile_module",
"cr_search_field:closure_compile_module", "cr_search_field:closure_compile_module",
"cr_splitter:closure_compile_module",
"cr_tabs:closure_compile_module", "cr_tabs:closure_compile_module",
"cr_toast:closure_compile_module", "cr_toast:closure_compile_module",
"cr_toggle:closure_compile_module", "cr_toggle:closure_compile_module",
...@@ -173,6 +175,7 @@ group("polymer3_elements") { ...@@ -173,6 +175,7 @@ group("polymer3_elements") {
"cr_radio_group:cr_radio_group_module", "cr_radio_group:cr_radio_group_module",
"cr_search_field:cr_search_field_module", "cr_search_field:cr_search_field_module",
"cr_search_field:modulize", "cr_search_field:modulize",
"cr_splitter:cr_splitter_module",
"cr_tabs:cr_tabs_module", "cr_tabs:cr_tabs_module",
"cr_toast:cr_toast_manager_module", "cr_toast:cr_toast_manager_module",
"cr_toast:cr_toast_module", "cr_toast:cr_toast_module",
......
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
import("//tools/polymer/polymer.gni")
js_type_check("closure_compile") {
deps = [
":cr_splitter",
]
}
js_library("cr_splitter") {
}
polymer_modulizer("cr_splitter") {
js_file = "cr_splitter.js"
html_file = "cr_splitter.html"
html_type = "dom-module"
}
js_type_check("closure_compile_module") {
is_polymer3 = true
deps = [
":cr_splitter.m",
]
}
js_library("cr_splitter.m") {
sources = [
"$root_gen_dir/ui/webui/resources/cr_elements/cr_splitter/cr_splitter.m.js",
]
deps = [
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
]
extra_deps = [ ":cr_splitter_module" ]
}
<link rel="import" href="../../html/polymer.html">
<dom-module id="cr-splitter">
<template>
</template>
<script src="cr_splitter.js"></script>
</dom-module>
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
(function() {
// TODO(arv): Currently this only supports horizontal layout.
// TODO(arv): This ignores min-width and max-width of the elements to the
// right of the splitter.
/**
* Returns the computed style width of an element.
* @param {!Element} el The element to get the width of.
* @return {number} The width in pixels.
*/
function getComputedWidth(el) {
return parseFloat(el.ownerDocument.defaultView.getComputedStyle(el).width) /
getZoomFactor(el.ownerDocument);
}
/**
* This uses a WebKit bug to work around the same bug. getComputedStyle does
* not take the page zoom into account so it returns the physical pixels
* instead of the logical pixel size.
* @param {!Document} doc The document to get the page zoom factor for.
* @return {number} The zoom factor of the document.
*/
function getZoomFactor(doc) {
const dummyElement = doc.createElement('div');
dummyElement.style.cssText = 'position:absolute;width:100px;height:100px;' +
'top:-1000px;overflow:hidden';
doc.body.appendChild(dummyElement);
const cs = doc.defaultView.getComputedStyle(dummyElement);
const rect = dummyElement.getBoundingClientRect();
const zoomFactor = parseFloat(cs.width) / 100;
doc.body.removeChild(dummyElement);
return zoomFactor;
}
Polymer({
is: 'cr-splitter',
properties: {
resizeNextElement: {
type: Boolean,
value: false,
},
},
listeners: {
'mousedown': 'onMouseDown_',
'touchstart': 'onTouchStart_',
},
/** @private {?Map<string, !Function>} */
handlers_: null,
/** @private {number} */
startX_: 0,
/** @override */
attached: function() {
this.handlers_ = new Map();
},
/** @override */
detached: function() {
this.removeAllHandlers_();
this.handlers_ = null;
},
/**
* Starts the dragging of the splitter. Adds listeners for mouse or touch
* events and calls splitter drag start handler.
* @param {number} clientX X position of the mouse or touch event that
* started the drag.
* @param {boolean} isTouchEvent True if the drag started by touch event.
*/
startDrag: function(clientX, isTouchEvent) {
if (this.handlers_) {
// Concurrent drags
this.endDrag_();
}
if (isTouchEvent) {
const endDragBound = this.endDrag_.bind(this);
this.handlers_.set('touchmove', this.handleTouchMove_.bind(this));
this.handlers_.set('touchend', endDragBound);
this.handlers_.set('touchcancel', endDragBound);
// Another touch start (we somehow missed touchend or touchcancel).
this.handlers_.set('touchstart', endDragBound);
} else {
this.handlers_.set('mousemove', this.handleMouseMove_.bind(this));
this.handlers_.set('mouseup', this.handleMouseUp_.bind(this));
}
const doc = this.ownerDocument;
// Use capturing events on the document to get events when the mouse
// leaves the document.
for (const [eventType, handler] of this.handlers_) {
doc.addEventListener(
/** @type {string} */ (eventType),
/** @type {Function} */ (handler), true);
}
this.startX_ = clientX;
this.handleSplitterDragStart_();
},
/** @private */
removeAllHandlers_: function() {
const doc = this.ownerDocument;
const handlers = /** @type {!Map<string, !Function>} */ (this.handlers_);
for (const [eventType, handler] of handlers) {
doc.removeEventListener(
/** @type {string} */ (eventType),
/** @type {Function} */ (handler), true);
}
this.handlers_.clear();
},
/**
* Ends the dragging of the splitter. Removes listeners set in startDrag
* and calls splitter drag end handler.
* @private
*/
endDrag_: function() {
this.removeAllHandlers_();
this.handleSplitterDragEnd_();
},
/**
* @return {Element}
* @private
*/
getResizeTarget_: function() {
return this.resizeNextElement ? this.nextElementSibling :
this.previousElementSibling;
},
/**
* Calculate width to resize target element.
* @param {number} deltaX horizontal drag amount
* @return {number}
* @private
*/
calcDeltaX_: function(deltaX) {
return this.resizeNextElement ? -deltaX : deltaX;
},
/**
* Handles the mousedown event which starts the dragging of the splitter.
* @param {!Event} e The mouse event.
* @private
*/
onMouseDown_: function(e) {
e = /** @type {!MouseEvent} */ (e);
if (e.button) {
return;
}
this.startDrag(e.clientX, false);
// Default action is to start selection and to move focus.
e.preventDefault();
},
/**
* Handles the touchstart event which starts the dragging of the splitter.
* @param {!Event} e The touch event.
* @private
*/
onTouchStart_: function(e) {
e = /** @type {!TouchEvent} */ (e);
if (e.touches.length == 1) {
this.startDrag(e.touches[0].clientX, true);
e.preventDefault();
}
},
/**
* Handles the mousemove event which moves the splitter as the user moves
* the mouse.
* @param {!MouseEvent} e The mouse event.
* @private
*/
handleMouseMove_: function(e) {
this.handleMove_(e.clientX);
},
/**
* Handles the touch move event.
* @param {!TouchEvent} e The touch event.
*/
handleTouchMove_: function(e) {
if (e.touches.length == 1) {
this.handleMove_(e.touches[0].clientX);
}
},
/**
* Common part of handling mousemove and touchmove. Calls splitter drag
* move handler.
* @param {number} clientX X position of the mouse or touch event.
* @private
*/
handleMove_: function(clientX) {
const deltaX = this.matches(':host-context([dir=rtl]) cr-splitter') ?
this.startX_ - clientX :
clientX - this.startX_;
this.handleSplitterDragMove_(deltaX);
},
/**
* Handles the mouse up event which ends the dragging of the splitter.
* @param {!MouseEvent} e The mouse event.
* @private
*/
handleMouseUp_: function(e) {
this.endDrag_();
},
/**
* Handles start of the splitter dragging. Saves current width of the
* element being resized.
* @private
*/
handleSplitterDragStart_: function() {
// Use the computed width style as the base so that we can ignore what
// box sizing the element has. Add the difference between offset and
// client widths to account for any scrollbars.
const targetElement = this.getResizeTarget_();
const doc = targetElement.ownerDocument;
this.startWidth_ =
parseFloat(doc.defaultView.getComputedStyle(targetElement).width) +
targetElement.offsetWidth - targetElement.clientWidth;
this.classList.add('splitter-active');
},
/**
* Handles splitter moves. Updates width of the element being resized.
* @param {number} deltaX The change of splitter horizontal position.
* @private
*/
handleSplitterDragMove_: function(deltaX) {
const targetElement = this.getResizeTarget_();
const newWidth = this.startWidth_ + this.calcDeltaX_(deltaX);
targetElement.style.width = newWidth + 'px';
this.dispatchEvent(new CustomEvent('dragmove'));
},
/**
* Handles end of the splitter dragging. This fires a 'resize' event if the
* size changed.
* @private
*/
handleSplitterDragEnd_: function() {
// Check if the size changed.
const targetElement = this.getResizeTarget_();
const doc = targetElement.ownerDocument;
const computedWidth =
parseFloat(doc.defaultView.getComputedStyle(targetElement).width);
if (this.startWidth_ != computedWidth) {
this.dispatchEvent(new CustomEvent('resize'));
}
this.classList.remove('splitter-active');
},
});
})();
...@@ -154,6 +154,14 @@ ...@@ -154,6 +154,14 @@
file="cr_elements/cr_slider/cr_slider.js" file="cr_elements/cr_slider/cr_slider.js"
type="chrome_html" type="chrome_html"
compress="gzip" /> compress="gzip" />
<structure name="IDR_CR_ELEMENTS_CR_SPLITTER_HTML"
file="cr_elements/cr_splitter/cr_splitter.html"
type="chrome_html"
compress="gzip" />
<structure name="IDR_CR_ELEMENTS_CR_SPLITTER_JS"
file="cr_elements/cr_splitter/cr_splitter.js"
type="chrome_html"
compress="gzip" />
<if expr="chromeos"> <if expr="chromeos">
<structure name="IDR_CR_ELEMENTS_CR_SEARCHABLE_DROP_DOWN_HTML" <structure name="IDR_CR_ELEMENTS_CR_SEARCHABLE_DROP_DOWN_HTML"
file="cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html" file="cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.html"
......
...@@ -116,6 +116,11 @@ ...@@ -116,6 +116,11 @@
use_base_dir="false" use_base_dir="false"
type="BINDATA" type="BINDATA"
compress="gzip" /> compress="gzip" />
<include name="IDR_CR_ELEMENTS_CR_SPLITTER_M_JS"
file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_splitter/cr_splitter.m.js"
use_base_dir="false"
type="BINDATA"
compress="gzip" />
<include name="IDR_CR_ELEMENTS_CR_TABS_M_JS" <include name="IDR_CR_ELEMENTS_CR_TABS_M_JS"
file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.m.js" file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.m.js"
use_base_dir="false" use_base_dir="false"
......
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