/** * @license * Copyright (C) 2017 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'; function GrAnnotationActionsInterface(plugin) { this.plugin = plugin; // Return this instance when there is an annotatediff event. plugin.on('annotatediff', this); // Collect all annotation layers instantiated by getLayer. Will be used when // notifying their listeners in the notify function. this._annotationLayers = []; // Default impl is a no-op. this._addLayerFunc = annotationActionsContext => {}; } /** * Register a function to call to apply annotations. Plugins should use * GrAnnotationActionsContext.annotateRange to apply a CSS class to a range * within a line. * @param {Function} addLayerFunc The function * that will be called when the AnnotationLayer is ready to annotate. */ GrAnnotationActionsInterface.prototype.addLayer = function(addLayerFunc) { this._addLayerFunc = addLayerFunc; return this; }; /** * The specified function will be called with a notify function for the plugin * to call when it has all required data for annotation. Optional. * @param {Function>} notifyFunc See * doc of the notify function below to see what it does. */ GrAnnotationActionsInterface.prototype.addNotifier = function(notifyFunc) { // Register the notify function with the plugin's function. notifyFunc(this.notify.bind(this)); return this; }; /** * Returns a checkbox HTMLElement that can be used to toggle annotations * on/off. The checkbox will be initially disabled. Plugins should enable it * when data is ready and should add a click handler to toggle CSS on/off. * * Note1: Calling this method from multiple plugins will only work for the * 1st call. It will print an error message for all subsequent calls * and will not invoke their onAttached functions. * Note2: This method will be deprecated and eventually removed when * https://bugs.chromium.org/p/gerrit/issues/detail?id=8077 is * implemented. * * @param {String} checkboxLabel Will be used as the label for the checkbox. * Optional. "Enable" is used if this is not specified. * @param {Function} onAttached The function that will be called * when the checkbox is attached to the page. */ GrAnnotationActionsInterface.prototype.enableToggleCheckbox = function( checkboxLabel, onAttached) { this.plugin.hook('annotation-toggler').onAttached(element => { if (!element.content.hidden) { console.error( element.content.id + ' is already enabled. Cannot re-enable.'); return; } element.content.removeAttribute('hidden'); const label = element.content.querySelector('#annotation-label'); if (checkboxLabel) { label.textContent = checkboxLabel; } else { label.textContent = 'Enable'; } const checkbox = element.content.querySelector('#annotation-checkbox'); onAttached(checkbox); }); return this; }; /** * The notify function will call the listeners of all required annotation * layers. Intended to be called by the plugin when all required data for * annotation is available. * @param {String} path The file path whose listeners should be notified. * @param {Number} start The line where the update starts. * @param {Number} end The line where the update ends. * @param {String} side The side of the update ('left' or 'right'). */ GrAnnotationActionsInterface.prototype.notify = function( path, startRange, endRange, side) { for (const annotationLayer of this._annotationLayers) { // Notify only the annotation layer that is associated with the specified // path. if (annotationLayer._path === path) { annotationLayer.notifyListeners(startRange, endRange, side); break; } } }; /** * Should be called to register annotation layers by the framework. Not * intended to be called by plugins. * @param {String} path The file path (eg: /COMMIT_MSG'). * @param {String} changeNum The Gerrit change number. * @param {String} patchNum The Gerrit patch number. */ GrAnnotationActionsInterface.prototype.getLayer = function( path, changeNum, patchNum) { const annotationLayer = new AnnotationLayer(path, changeNum, patchNum, this._addLayerFunc); this._annotationLayers.push(annotationLayer); return annotationLayer; }; /** * Used to create an instance of the Annotation Layer interface. * @param {String} path The file path (eg: /COMMIT_MSG'). * @param {String} changeNum The Gerrit change number. * @param {String} patchNum The Gerrit patch number. * @param {Function} addLayerFunc The function * that will be called when the AnnotationLayer is ready to annotate. */ function AnnotationLayer(path, changeNum, patchNum, addLayerFunc) { this._path = path; this._changeNum = changeNum; this._patchNum = patchNum; this._addLayerFunc = addLayerFunc; this._listeners = []; } /** * Register a listener for layer updates. * @param {Function} fn The update handler function. * Should accept as arguments the line numbers for the start and end of * the update and the side as a string. */ AnnotationLayer.prototype.addListener = function(fn) { this._listeners.push(fn); }; /** * Layer method to add annotations to a line. * @param {HTMLElement} el The DIV.contentText element to apply the * annotation to. * @param {GrDiffLine} line The line object. */ AnnotationLayer.prototype.annotate = function(el, line) { const annotationActionsContext = new GrAnnotationActionsContext( el, line, this._path, this._changeNum, this._patchNum); this._addLayerFunc(annotationActionsContext); }; /** * Notify Layer listeners of changes to annotations. * @param {Number} start The line where the update starts. * @param {Number} end The line where the update ends. * @param {String} side The side of the update. ('left' or 'right') */ AnnotationLayer.prototype.notifyListeners = function( startRange, endRange, side) { for (const listener of this._listeners) { listener(startRange, endRange, side); } }; window.GrAnnotationActionsInterface = GrAnnotationActionsInterface; })(window);