Deprecate Gerrit.css() and provide a replacement
Gerrit.css doesn't work with ShadowDom, because it adds styles to a document. This fix provides a replacement for Gerrit.css. The replacement allows to apply the same styles to any element inside document. Bug: Issue 11298 Change-Id: Ide325a889a69bd267382a9664ed6f8d25ed67a3b
This commit is contained in:
parent
54ca082f42
commit
941ee630d8
@ -713,10 +713,12 @@ accessed through this name.
|
||||
|
||||
[[Gerrit_css]]
|
||||
=== Gerrit.css()
|
||||
[WARNING]
|
||||
This method is deprecated. It doesn't work with Shadow DOM and
|
||||
will be removed in the future. Please, use link:pg-plugin-dev.html#plugin-styles[plugin.styles] instead.
|
||||
|
||||
Creates a new unique CSS class and injects it into the document.
|
||||
The name of the class is returned and can be used by the plugin.
|
||||
See link:#Gerrit_html[`Gerrit.html()`] for an easy way to use
|
||||
generated class names.
|
||||
|
||||
Classes created with this function should be created once at install
|
||||
time and reused throughout the plugin. Repeatedly creating the same
|
||||
@ -814,112 +816,6 @@ If the URL passed matches `http://...`, `https://...`, or `//...`
|
||||
the current browser window will navigate to the non-Gerrit URL.
|
||||
The user can return to Gerrit with the back button.
|
||||
|
||||
[[Gerrit_html]]
|
||||
=== Gerrit.html()
|
||||
Parses an HTML fragment after performing template replacements. If
|
||||
the HTML has a single root element or node that node is returned,
|
||||
otherwise it is wrapped inside a `<div>` and the div is returned.
|
||||
|
||||
.Signature
|
||||
[source,javascript]
|
||||
----
|
||||
Gerrit.html(htmlText, options, wantElements);
|
||||
----
|
||||
|
||||
* htmlText: string of HTML to be parsed. A new unattached `<div>` is
|
||||
created in the browser's document and the innerHTML property is
|
||||
assigned to the passed string, after performing replacements. If
|
||||
the div has exactly one child, that child will be returned instead
|
||||
of the div.
|
||||
|
||||
* options: optional object reference supplying replacements for any
|
||||
`{name}` references in htmlText. Navigation through objects is
|
||||
supported permitting `{style.bar}` to be replaced with `"foo"` if
|
||||
options was `{style: {bar: "foo"}}`. Value replacements are HTML
|
||||
escaped before being inserted into the document fragment.
|
||||
|
||||
* wantElements: if options is given and wantElements is also true
|
||||
an object consisting of `{root: parsedElement, elements: {...}}` is
|
||||
returned instead of the parsed element. The elements object contains
|
||||
a property for each element using `id={name}` in htmlText.
|
||||
|
||||
.Example
|
||||
[source,javascript]
|
||||
----
|
||||
var style = {bar: Gerrit.css('background: yellow')};
|
||||
Gerrit.html(
|
||||
'<span class="{style.bar}">Hello {name}!</span>',
|
||||
{style: style, name: "World"});
|
||||
----
|
||||
|
||||
Event handlers can be automatically attached to elements referenced
|
||||
through an attribute id. Object navigation is not supported for ids,
|
||||
and the parser strips the id attribute before returning the result.
|
||||
Handler functions must begin with `on` and be a function to be
|
||||
installed on the element. This approach is useful for onclick and
|
||||
other handlers that do not want to create circular references that
|
||||
will eventually leak browser memory.
|
||||
|
||||
.Example
|
||||
[source,javascript]
|
||||
----
|
||||
var options = {
|
||||
link: {
|
||||
onclick: function(e) { window.close() },
|
||||
},
|
||||
};
|
||||
Gerrit.html('<a href="javascript:;" id="{link}">Close</a>', options);
|
||||
----
|
||||
|
||||
When using options to install handlers care must be taken to not
|
||||
accidentally include the returned element into the event handler's
|
||||
closure. This is why options is built before calling `Gerrit.html()`
|
||||
and not inline as a shown above with "Hello World".
|
||||
|
||||
DOM nodes can optionally be returned, allowing handlers to access the
|
||||
elements identified by `id={name}` at a later point in time.
|
||||
|
||||
.Example
|
||||
[source,javascript]
|
||||
----
|
||||
var w = Gerrit.html(
|
||||
'<div>Name: <input type="text" id="{name}"></div>'
|
||||
+ '<div>Age: <input type="text" id="{age}"></div>'
|
||||
+ '<button id="{submit}"><div>Save</div></button>',
|
||||
{
|
||||
submit: {
|
||||
onclick: function(s) {
|
||||
var e = w.elements;
|
||||
window.alert(e.name.value + " is " + e.age.value);
|
||||
},
|
||||
},
|
||||
}, true);
|
||||
----
|
||||
|
||||
To prevent memory leaks `w.root` and `w.elements` should be set to
|
||||
null when the elements are no longer necessary. Screens can use
|
||||
link:#screen_onUnload[screen.onUnload()] to define a callback function
|
||||
to perform this cleanup:
|
||||
|
||||
[source,javascript]
|
||||
----
|
||||
var w = Gerrit.html(...);
|
||||
screen.body.appendElement(w.root);
|
||||
screen.onUnload(function() { w.clear() });
|
||||
----
|
||||
|
||||
[[Gerrit_injectCss]]
|
||||
=== Gerrit.injectCss()
|
||||
Injects CSS rules into the document by appending onto the end of the
|
||||
existing rule list. CSS rules are global to the entire application
|
||||
and must be manually scoped by each plugin. For an automatic scoping
|
||||
alternative see link:#Gerrit_css[`css()`].
|
||||
|
||||
[source,javascript]
|
||||
----
|
||||
Gerrit.injectCss('.myplugin_bg {background: #000}');
|
||||
----
|
||||
|
||||
[[Gerrit_install]]
|
||||
=== Gerrit.install()
|
||||
Registers a new plugin by invoking the supplied initialization
|
||||
|
@ -360,6 +360,16 @@ screen.
|
||||
|
||||
Deprecated. Use link:#plugin-settings[`plugin.settings()`] instead.
|
||||
|
||||
[[plugin-styles]]
|
||||
=== styles
|
||||
`plugin.styles()`
|
||||
|
||||
.Params:
|
||||
- none
|
||||
|
||||
.Returns:
|
||||
- Instance of link:pg-plugin-styles-api.html[GrStylesApi]
|
||||
|
||||
=== changeMetadata
|
||||
`plugin.changeMetadata()`
|
||||
|
||||
@ -372,6 +382,7 @@ Deprecated. Use link:#plugin-settings[`plugin.settings()`] instead.
|
||||
=== theme
|
||||
`plugin.theme()`
|
||||
|
||||
|
||||
Note: TODO
|
||||
|
||||
=== url
|
||||
|
33
Documentation/pg-plugin-style-object.txt
Normal file
33
Documentation/pg-plugin-style-object.txt
Normal file
@ -0,0 +1,33 @@
|
||||
= Gerrit Code Review - GrStyleObject
|
||||
|
||||
Store information about css style properties. You can't create this object
|
||||
directly. Instead you should use the link:pg-plugin-styles-api.html#css[css] method.
|
||||
This object allows to apply style correctly to elements within different shadow
|
||||
subtree.
|
||||
|
||||
[[get-class-name]]
|
||||
== getClassName
|
||||
`styleObject.getClassName(element)`
|
||||
|
||||
.Params
|
||||
- `element` - an HTMLElement.
|
||||
|
||||
.Returns
|
||||
- `string` - class name. The class name is valid only within the shadow root of `element`.
|
||||
|
||||
Creates a new unique CSS class and injects it into the appropriate place
|
||||
in DOM (it can be document or shadow root for element). This class can be later
|
||||
added to the element or to any other element in the same shadow root. It is guarantee,
|
||||
that method adds CSS class only once for each shadow root.
|
||||
|
||||
== apply
|
||||
`styleObject.apply(element)`
|
||||
|
||||
.Params
|
||||
- `element` - element to apply style.
|
||||
|
||||
Create a new unique CSS class (see link:#get-class-name[getClassName]) and
|
||||
adds class to the element.
|
||||
|
||||
|
||||
|
29
Documentation/pg-plugin-styles-api.txt
Normal file
29
Documentation/pg-plugin-styles-api.txt
Normal file
@ -0,0 +1,29 @@
|
||||
= Gerrit Code Review - Plugin styles API
|
||||
|
||||
This API is provided by link:pg-plugin-dev.html#plugin-styles[plugin.styles()]
|
||||
and provides a way to apply dynamically created styles to elements in a
|
||||
document.
|
||||
|
||||
[[css]]
|
||||
== css
|
||||
`styles.css(rulesStr)`
|
||||
|
||||
.Params
|
||||
- `*string* rulesStr` string with CSS styling declarations.
|
||||
|
||||
Example:
|
||||
----
|
||||
const styleObject = plugin.styles().css('background: black; color: white;');
|
||||
...
|
||||
const className = styleObject.getClassName(element)
|
||||
...
|
||||
element.classList.add(className);
|
||||
...
|
||||
styleObject.apply(someOtherElement);
|
||||
----
|
||||
|
||||
.Returns
|
||||
- Instance of link:pg-plugin-style-object.html[GrStyleObject].
|
||||
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
<!--
|
||||
@license
|
||||
Copyright (C) 2019 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<script src="gr-styles-api.js"></script>
|
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
// Prevent redefinition.
|
||||
if (window.GrStylesApi) { return; }
|
||||
|
||||
let styleObjectCount = 0;
|
||||
|
||||
function GrStyleObject(rulesStr) {
|
||||
this._rulesStr = rulesStr;
|
||||
this._className = `__pg_js_api_class_${styleObjectCount}`;
|
||||
styleObjectCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new unique CSS class and injects it in a root node of the element
|
||||
* if it hasn't been added yet. A root node is an document or is the
|
||||
* associated shadowRoot. This class can be added to any element with the same
|
||||
* root node.
|
||||
* @param {HTMLElement} element The element to get class name for.
|
||||
* @return {string} Appropriate class name for the element is returned
|
||||
*/
|
||||
GrStyleObject.prototype.getClassName = function(element) {
|
||||
const rootNode = Polymer.Settings.useShadow
|
||||
? element.getRootNode() : document.body;
|
||||
if (!rootNode.__pg_js_api_style_tags) {
|
||||
rootNode.__pg_js_api_style_tags = {};
|
||||
}
|
||||
if (!rootNode.__pg_js_api_style_tags[this._className]) {
|
||||
const styleTag = document.createElement('style');
|
||||
styleTag.innerHTML = `.${this._className} { ${this._rulesStr} }`;
|
||||
rootNode.appendChild(styleTag);
|
||||
rootNode.__pg_js_api_style_tags[this._className] = true;
|
||||
}
|
||||
return this._className;
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply shared style to the element.
|
||||
* @param {HTMLElement} element The element to apply style for
|
||||
*/
|
||||
GrStyleObject.prototype.apply = function(element) {
|
||||
element.classList.add(this.getClassName(element));
|
||||
};
|
||||
|
||||
|
||||
function GrStylesApi() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new GrStyleObject with specified style properties.
|
||||
* @param {string} String with style properties.
|
||||
* @return {GrStyleObject}
|
||||
*/
|
||||
GrStylesApi.prototype.css = function(ruleStr) {
|
||||
return new GrStyleObject(ruleStr);
|
||||
};
|
||||
|
||||
|
||||
window.GrStylesApi = GrStylesApi;
|
||||
})(window);
|
@ -0,0 +1,182 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
@license
|
||||
Copyright (C) 2019 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||
<title>gr-admin-api</title>
|
||||
<script src="/test/common-test-setup.js"></script>
|
||||
<script src="/bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script>
|
||||
|
||||
<script src="/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
|
||||
<script src="/bower_components/web-component-tester/browser.js"></script>
|
||||
<link rel="import" href="../../../test/common-test-setup.html"/>
|
||||
<link rel="import" href="../../shared/gr-js-api-interface/gr-js-api-interface.html">
|
||||
<link rel="import" href="gr-styles-api.html">
|
||||
|
||||
<script>void(0);</script>
|
||||
|
||||
<dom-module id="gr-style-test-element">
|
||||
<template>
|
||||
<div id="wrapper"></div>
|
||||
</template>
|
||||
<script>Polymer({is: 'gr-style-test-element'});</script>
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
suite('gr-styles-api tests', () => {
|
||||
let sandbox;
|
||||
let stylesApi;
|
||||
|
||||
setup(() => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
let plugin;
|
||||
Gerrit.install(p => { plugin = p; }, '0.1',
|
||||
'http://test.com/plugins/testplugin/static/test.js');
|
||||
sandbox.stub(Gerrit, '_arePluginsLoaded').returns(true);
|
||||
stylesApi = plugin.styles();
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
stylesApi = null;
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
test('exists', () => {
|
||||
assert.isOk(stylesApi);
|
||||
});
|
||||
|
||||
test('css', () => {
|
||||
const styleObject = stylesApi.css('background: red');
|
||||
assert.isDefined(styleObject);
|
||||
});
|
||||
});
|
||||
|
||||
suite('GrStyleObject tests', () => {
|
||||
let sandbox;
|
||||
let stylesApi;
|
||||
let displayInlineStyle;
|
||||
let displayNoneStyle;
|
||||
|
||||
setup(() => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
let plugin;
|
||||
Gerrit.install(p => { plugin = p; }, '0.1',
|
||||
'http://test.com/plugins/testplugin/static/test.js');
|
||||
sandbox.stub(Gerrit, '_arePluginsLoaded').returns(true);
|
||||
stylesApi = plugin.styles();
|
||||
displayInlineStyle = stylesApi.css('display: inline');
|
||||
displayNoneStyle = stylesApi.css('display: none');
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
displayInlineStyle = null;
|
||||
displayNoneStyle = null;
|
||||
stylesApi = null;
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
function createNestedElements(parentElement) {
|
||||
/* parentElement
|
||||
* |--- element1
|
||||
* |--- element2
|
||||
* |--- element3
|
||||
**/
|
||||
const element1 = document.createElement('div');
|
||||
const element2 = document.createElement('div');
|
||||
const element3 = document.createElement('div');
|
||||
Polymer.dom(parentElement).appendChild(element1);
|
||||
Polymer.dom(parentElement).appendChild(element2);
|
||||
Polymer.dom(element2).appendChild(element3);
|
||||
|
||||
return [element1, element2, element3];
|
||||
}
|
||||
|
||||
|
||||
test('getClassName - body level elements', () => {
|
||||
const bodyLevelElements = createNestedElements(document.body);
|
||||
|
||||
testGetClassName(bodyLevelElements);
|
||||
});
|
||||
|
||||
test('getClassName - elements inside polymer element', () => {
|
||||
const polymerElement = document.createElement('gr-style-test-element');
|
||||
Polymer.dom(document.body).appendChild(polymerElement);
|
||||
const contentElements = createNestedElements(polymerElement.$.wrapper);
|
||||
|
||||
testGetClassName(contentElements);
|
||||
});
|
||||
|
||||
function testGetClassName(elements) {
|
||||
assertAllElementsHaveDefaultStyle(elements);
|
||||
|
||||
const className1 = displayInlineStyle.getClassName(elements[0]);
|
||||
const className2 = displayNoneStyle.getClassName(elements[1]);
|
||||
const className3 = displayInlineStyle.getClassName(elements[2]);
|
||||
|
||||
assert.notEqual(className2, className1);
|
||||
assert.equal(className3, className1);
|
||||
|
||||
assertAllElementsHaveDefaultStyle(elements);
|
||||
|
||||
elements[0].classList.add(className1);
|
||||
elements[1].classList.add(className2);
|
||||
elements[2].classList.add(className1);
|
||||
|
||||
assertDisplayPropertyValues(elements, ['inline', 'none', 'inline']);
|
||||
}
|
||||
|
||||
test('apply - body level elements', () => {
|
||||
const bodyLevelElements = createNestedElements(document.body);
|
||||
|
||||
testApply(bodyLevelElements);
|
||||
});
|
||||
|
||||
test('apply - elements inside polymer element', () => {
|
||||
const polymerElement = document.createElement('gr-style-test-element');
|
||||
Polymer.dom(document.body).appendChild(polymerElement);
|
||||
const contentElements = createNestedElements(polymerElement.$.wrapper);
|
||||
|
||||
testApply(contentElements);
|
||||
});
|
||||
|
||||
function testApply(elements) {
|
||||
assertAllElementsHaveDefaultStyle(elements);
|
||||
displayInlineStyle.apply(elements[0]);
|
||||
displayNoneStyle.apply(elements[1]);
|
||||
displayInlineStyle.apply(elements[2]);
|
||||
assertDisplayPropertyValues(elements, ['inline', 'none', 'inline']);
|
||||
}
|
||||
|
||||
|
||||
function assertAllElementsHaveDefaultStyle(elements) {
|
||||
for (const element of elements) {
|
||||
assert.equal(getComputedStyle(element).getPropertyValue('display'),
|
||||
'block');
|
||||
}
|
||||
}
|
||||
|
||||
function assertDisplayPropertyValues(elements, expectedDisplayValues) {
|
||||
for (const key in elements) {
|
||||
if (elements.hasOwnProperty(key)) {
|
||||
assert.equal(
|
||||
getComputedStyle(elements[key]).getPropertyValue('display'),
|
||||
expectedDisplayValues[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
@ -43,25 +43,26 @@
|
||||
* Method to add annotations to a content line.
|
||||
* @param {number} offset The char offset where the update starts.
|
||||
* @param {number} length The number of chars that the update covers.
|
||||
* @param {string} cssClass The name of a CSS class created using Gerrit.css.
|
||||
* @param {GrStyleObject} styleObject The style object for the range.
|
||||
* @param {string} side The side of the update. ('left' or 'right')
|
||||
*/
|
||||
GrAnnotationActionsContext.prototype.annotateRange = function(
|
||||
offset, length, cssClass, side) {
|
||||
offset, length, styleObject, side) {
|
||||
if (this._contentEl && this._contentEl.getAttribute('data-side') == side) {
|
||||
GrAnnotation.annotateElement(this._contentEl, offset, length, cssClass);
|
||||
GrAnnotation.annotateElement(this._contentEl, offset, length,
|
||||
styleObject.getClassName(this._contentEl));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Method to add a CSS class to the line number TD element.
|
||||
* @param {string} cssClass The name of a CSS class created using Gerrit.css.
|
||||
* @param {GrStyleObject} styleObject The style object for the range.
|
||||
* @param {string} side The side of the update. ('left' or 'right')
|
||||
*/
|
||||
GrAnnotationActionsContext.prototype.annotateLineNumber = function(
|
||||
cssClass, side) {
|
||||
styleObject, side) {
|
||||
if (this._lineNumberEl && this._lineNumberEl.classList.contains(side)) {
|
||||
this._lineNumberEl.classList.add(cssClass);
|
||||
styleObject.apply(this._lineNumberEl);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -42,9 +42,13 @@ limitations under the License.
|
||||
let sandbox;
|
||||
let el;
|
||||
let lineNumberEl;
|
||||
let plugin;
|
||||
|
||||
setup(() => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
Gerrit.install(p => { plugin = p; }, '0.1',
|
||||
'http://test.com/plugins/testplugin/static/test.js');
|
||||
|
||||
const str = 'lorem ipsum blah blah';
|
||||
const line = {text: str};
|
||||
el = document.createElement('div');
|
||||
@ -64,32 +68,34 @@ limitations under the License.
|
||||
annotateElementSpy = sandbox.spy(GrAnnotation, 'annotateElement');
|
||||
const start = 0;
|
||||
const end = 100;
|
||||
const cssClass = Gerrit.css('background-color: #000000');
|
||||
const cssStyleObject = plugin.styles().css('background-color: #000000');
|
||||
|
||||
// Assert annotateElement is not called when side is different.
|
||||
instance.annotateRange(start, end, cssClass, 'left');
|
||||
instance.annotateRange(start, end, cssStyleObject, 'left');
|
||||
assert.equal(annotateElementSpy.callCount, 0);
|
||||
|
||||
// Assert annotateElement is called once when side is the same.
|
||||
instance.annotateRange(start, end, cssClass, 'right');
|
||||
instance.annotateRange(start, end, cssStyleObject, 'right');
|
||||
assert.equal(annotateElementSpy.callCount, 1);
|
||||
const args = annotateElementSpy.getCalls()[0].args;
|
||||
assert.equal(args[0], el);
|
||||
assert.equal(args[1], start);
|
||||
assert.equal(args[2], end);
|
||||
assert.equal(args[3], cssClass);
|
||||
assert.equal(args[3], cssStyleObject.getClassName(el));
|
||||
});
|
||||
|
||||
test('test annotateLineNumber', () => {
|
||||
const cssClass = Gerrit.css('background-color: #000000');
|
||||
const cssStyleObject = plugin.styles().css('background-color: #000000');
|
||||
|
||||
const className = cssStyleObject.getClassName(lineNumberEl);
|
||||
|
||||
// Assert that css class is *not* applied when side is different.
|
||||
instance.annotateLineNumber(cssClass, 'left');
|
||||
assert.isFalse(lineNumberEl.classList.contains(cssClass));
|
||||
instance.annotateLineNumber(cssStyleObject, 'left');
|
||||
assert.isFalse(lineNumberEl.classList.contains(className));
|
||||
|
||||
// Assert that css class is applied when side is the same.
|
||||
instance.annotateLineNumber(cssClass, 'right');
|
||||
assert.isTrue(lineNumberEl.classList.contains(cssClass));
|
||||
instance.annotateLineNumber(cssStyleObject, 'right');
|
||||
assert.isTrue(lineNumberEl.classList.contains(className));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@ -26,6 +26,7 @@ limitations under the License.
|
||||
<link rel="import" href="../../plugins/gr-popup-interface/gr-popup-interface.html">
|
||||
<link rel="import" href="../../plugins/gr-repo-api/gr-repo-api.html">
|
||||
<link rel="import" href="../../plugins/gr-settings-api/gr-settings-api.html">
|
||||
<link rel="import" href="../../plugins/gr-styles-api/gr-styles-api.html">
|
||||
<link rel="import" href="../../plugins/gr-theme-api/gr-theme-api.html">
|
||||
<link rel="import" href="../gr-rest-api-interface/gr-rest-api-interface.html">
|
||||
|
||||
|
@ -319,6 +319,10 @@
|
||||
return new GrSettingsApi(this);
|
||||
};
|
||||
|
||||
Plugin.prototype.styles = function() {
|
||||
return new GrStylesApi();
|
||||
};
|
||||
|
||||
/**
|
||||
* To make REST requests for plugin-provided endpoints, use
|
||||
* @example
|
||||
@ -511,7 +515,13 @@
|
||||
'Please use plugin.getPluginName() instead.');
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Use plugin.styles().css(rulesStr) instead. Please, consult
|
||||
* the documentation how to replace it accordingly.
|
||||
*/
|
||||
Gerrit.css = function(rulesStr) {
|
||||
console.warn('Gerrit.css(rulesStr) is deprecated!',
|
||||
'Use plugin.styles().css(rulesStr)');
|
||||
if (!Gerrit._customStyleSheet) {
|
||||
const styleEl = document.createElement('style');
|
||||
document.head.appendChild(styleEl);
|
||||
|
@ -32,6 +32,11 @@
|
||||
const coverageData = {};
|
||||
let displayCoverage = false;
|
||||
const annotationApi = plugin.annotationApi();
|
||||
const styleApi = plugin.styles();
|
||||
|
||||
const coverageStyle = styleApi.css('background-color: #EF9B9B !important');
|
||||
const emptyStyle = styleApi.css('');
|
||||
|
||||
annotationApi.addLayer(context => {
|
||||
if (Object.keys(coverageData).length === 0) {
|
||||
// Coverage data is not ready yet.
|
||||
@ -41,16 +46,16 @@
|
||||
const line = context.line;
|
||||
// Highlight lines missing coverage with this background color if
|
||||
// coverage should be displayed, else do nothing.
|
||||
const cssClass = displayCoverage
|
||||
? Gerrit.css('background-color: #EF9B9B')
|
||||
: Gerrit.css('');
|
||||
const annotationStyle = displayCoverage
|
||||
? coverageStyle
|
||||
: emptyStyle;
|
||||
if (coverageData[path] &&
|
||||
coverageData[path].changeNum === context.changeNum &&
|
||||
coverageData[path].patchNum === context.patchNum) {
|
||||
const linesMissingCoverage = coverageData[path].linesMissingCoverage;
|
||||
if (linesMissingCoverage.includes(line.afterNumber)) {
|
||||
context.annotateRange(0, line.text.length, cssClass, 'right');
|
||||
context.annotateLineNumber(cssClass, 'right');
|
||||
context.annotateRange(0, line.text.length, annotationStyle, 'right');
|
||||
context.annotateLineNumber(annotationStyle, 'right');
|
||||
}
|
||||
}
|
||||
}).enableToggleCheckbox('Display Coverage', checkbox => {
|
||||
|
@ -125,6 +125,7 @@ limitations under the License.
|
||||
'edit/gr-edit-file-controls/gr-edit-file-controls_test.html',
|
||||
'edit/gr-editor-view/gr-editor-view_test.html',
|
||||
'plugins/gr-admin-api/gr-admin-api_test.html',
|
||||
'plugins/gr-styles-api/gr-styles-api_test.html',
|
||||
'plugins/gr-attribute-helper/gr-attribute-helper_test.html',
|
||||
'plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.html',
|
||||
'plugins/gr-event-helper/gr-event-helper_test.html',
|
||||
|
Loading…
Reference in New Issue
Block a user