@ckeditor/ckeditor5-widget
Advanced tools
Comparing version 1.0.0-alpha.2 to 1.0.0-beta.1
Changelog | ||
========= | ||
## [1.0.0-beta.1](https://github.com/ckeditor/ckeditor5-widget/compare/v1.0.0-alpha.2...v1.0.0-beta.1) (2018-03-15) | ||
### Other changes | ||
* Aligned feature class naming to the new scheme. ([23991a4](https://github.com/ckeditor/ckeditor5-widget/commit/23991a4)) | ||
* Migrated package styles to PostCSS. Moved visual styles to `@ckeditor/ckeditor5-theme-lark` (see [ckeditor/ckeditor5-ui#144](https://github.com/ckeditor/ckeditor5-ui/issues/144)). ([857d6d4](https://github.com/ckeditor/ckeditor5-widget/commit/857d6d4)) | ||
* Switched to handling deletion around widgets by using the `delete` event instead of listening directly on key events. Closes [#29](https://github.com/ckeditor/ckeditor5-widget/issues/29). ([ee6cc95](https://github.com/ckeditor/ckeditor5-widget/commit/ee6cc95)) | ||
## [1.0.0-alpha.2](https://github.com/ckeditor/ckeditor5-widget/compare/v1.0.0-alpha.1...v1.0.0-alpha.2) (2017-11-14) | ||
@@ -5,0 +14,0 @@ |
@@ -5,3 +5,3 @@ Software License Agreement | ||
**CKEditor 5 widget API** – https://github.com/ckeditor/ckeditor5-image <br> | ||
Copyright (c) 2003-2017, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved. | ||
Copyright (c) 2003-2018, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved. | ||
@@ -8,0 +8,0 @@ Licensed under the terms of any of the following licenses at your choice: |
{ | ||
"name": "@ckeditor/ckeditor5-widget", | ||
"version": "1.0.0-alpha.2", | ||
"version": "1.0.0-beta.1", | ||
"description": "Widget API for CKEditor 5.", | ||
@@ -10,12 +10,13 @@ "keywords": [ | ||
"dependencies": { | ||
"@ckeditor/ckeditor5-core": "^1.0.0-alpha.2", | ||
"@ckeditor/ckeditor5-engine": "^1.0.0-alpha.2", | ||
"@ckeditor/ckeditor5-utils": "^1.0.0-alpha.2", | ||
"@ckeditor/ckeditor5-theme-lark": "^1.0.0-alpha.2" | ||
"@ckeditor/ckeditor5-core": "^1.0.0-beta.1", | ||
"@ckeditor/ckeditor5-engine": "^1.0.0-beta.1", | ||
"@ckeditor/ckeditor5-utils": "^1.0.0-beta.1", | ||
"@ckeditor/ckeditor5-theme-lark": "^1.0.0-beta.1" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^4.8.0", | ||
"eslint-config-ckeditor5": "^1.0.6", | ||
"@ckeditor/ckeditor5-typing": "^1.0.0-beta.1", | ||
"eslint": "^4.15.0", | ||
"eslint-config-ckeditor5": "^1.0.7", | ||
"husky": "^0.14.3", | ||
"lint-staged": "^4.2.3" | ||
"lint-staged": "^6.0.0" | ||
}, | ||
@@ -22,0 +23,0 @@ "engines": { |
@@ -7,3 +7,5 @@ CKEditor 5 widget API | ||
[![Build Status](https://travis-ci.org/ckeditor/ckeditor5-widget.svg)](https://travis-ci.org/ckeditor/ckeditor5-widget) | ||
[![Test Coverage](https://codeclimate.com/github/ckeditor/ckeditor5-widget/badges/coverage.svg)](https://codeclimate.com/github/ckeditor/ckeditor5-widget/coverage) | ||
[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=d3hvenZqQVZERFQ5d09FWXdyT0ozVXhLaVltRFRjTTUyZGpvQWNmWVhUUT0tLUZqNlJ1YWRUd0RvdEVOaEptM1B2Q0E9PQ==--c9d3dee40b9b4471ff3fb516d9ecf8d09292c7e0)](https://www.browserstack.com/automate/public-build/d3hvenZqQVZERFQ5d09FWXdyT0ozVXhLaVltRFRjTTUyZGpvQWNmWVhUUT0tLUZqNlJ1YWRUd0RvdEVOaEptM1B2Q0E9PQ==--c9d3dee40b9b4471ff3fb516d9ecf8d09292c7e0) | ||
[![Coverage Status](https://coveralls.io/repos/github/ckeditor/ckeditor5-widget/badge.svg?branch=master)](https://coveralls.io/github/ckeditor/ckeditor5-widget?branch=master) | ||
<br> | ||
[![Dependency Status](https://david-dm.org/ckeditor/ckeditor5-widget/status.svg)](https://david-dm.org/ckeditor/ckeditor5-widget) | ||
@@ -10,0 +12,0 @@ [![devDependency Status](https://david-dm.org/ckeditor/ckeditor5-widget/dev-status.svg)](https://david-dm.org/ckeditor/ckeditor5-widget?type=dev) |
/** | ||
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md. | ||
@@ -14,8 +14,10 @@ */ | ||
/** | ||
* Class used to handle correct order of | ||
* {@link module:engine/conversion/buildmodelconverter~ModelConverterBuilder#toHighlight highlights} on | ||
* elements. When different highlights are applied to same element correct order should be preserved: | ||
* Class used to handle correct order of highlights on elements. | ||
* | ||
* When different highlights are applied to same element correct order should be preserved: | ||
* | ||
* * highlight with highest priority should be applied, | ||
* * if two highlights have same priority - sort by CSS class provided in | ||
* {@link module:engine/conversion/model-to-view-converters~HighlightDescriptor}. | ||
* {@link module:engine/conversion/downcast-converters~HighlightDescriptor}. | ||
* | ||
* This way, highlight will be applied with the same rules it is applied on texts. | ||
@@ -35,5 +37,6 @@ */ | ||
* @fires change:top | ||
* @param {module:engine/conversion/model-to-view-converters~HighlightDescriptor} descriptor | ||
* @param {module:engine/conversion/downcast-converters~HighlightDescriptor} descriptor | ||
* @param {module:engine/view/writer~Writer} writer | ||
*/ | ||
add( descriptor ) { | ||
add( descriptor, writer ) { | ||
const stack = this._stack; | ||
@@ -50,3 +53,4 @@ | ||
oldDescriptor: oldTop, | ||
newDescriptor: newTop | ||
newDescriptor: newTop, | ||
writer | ||
} ); | ||
@@ -61,4 +65,5 @@ } | ||
* @param {String} id Id of the descriptor to remove. | ||
* @param {module:engine/view/writer~Writer} writer | ||
*/ | ||
remove( id ) { | ||
remove( id, writer ) { | ||
const stack = this._stack; | ||
@@ -74,3 +79,4 @@ | ||
oldDescriptor: oldTop, | ||
newDescriptor: newTop | ||
newDescriptor: newTop, | ||
writer | ||
} ); | ||
@@ -85,3 +91,3 @@ } | ||
* @private | ||
* @param {module:engine/conversion/model-to-view-converters~HighlightDescriptor} descriptor | ||
* @param {module:engine/conversion/downcast-converters~HighlightDescriptor} descriptor | ||
*/ | ||
@@ -134,4 +140,4 @@ _insertDescriptor( descriptor ) { | ||
// | ||
// @param {module:engine/conversion/model-to-view-converters~HighlightDescriptor} a | ||
// @param {module:engine/conversion/model-to-view-converters~HighlightDescriptor} b | ||
// @param {module:engine/conversion/downcast-converters~HighlightDescriptor} a | ||
// @param {module:engine/conversion/downcast-converters~HighlightDescriptor} b | ||
// @returns {Boolean} Returns true if both descriptors are defined and have same priority and classes. | ||
@@ -144,4 +150,4 @@ function compareDescriptors( a, b ) { | ||
// | ||
// @param {module:engine/conversion/model-to-view-converters~HighlightDescriptor} a | ||
// @param {module:engine/conversion/model-to-view-converters~HighlightDescriptor} b | ||
// @param {module:engine/conversion/downcast-converters~HighlightDescriptor} a | ||
// @param {module:engine/conversion/downcast-converters~HighlightDescriptor} b | ||
// @returns {Boolean} | ||
@@ -159,3 +165,3 @@ function shouldABeBeforeB( a, b ) { | ||
// Converts CSS classes passed with {@link module:engine/conversion/model-to-view-converters~HighlightDescriptor} to | ||
// Converts CSS classes passed with {@link module:engine/conversion/downcast-converters~HighlightDescriptor} to | ||
// sorted string. | ||
@@ -174,6 +180,7 @@ // | ||
* @param {Object} data Additional information about the change. | ||
* @param {module:engine/conversion/model-to-view-converters~HighlightDescriptor} [data.newDescriptor] New highlight | ||
* @param {module:engine/conversion/downcast-converters~HighlightDescriptor} [data.newDescriptor] New highlight | ||
* descriptor. It will be `undefined` when last descriptor is removed from the stack. | ||
* @param {module:engine/conversion/model-to-view-converters~HighlightDescriptor} [data.oldDescriptor] Old highlight | ||
* @param {module:engine/conversion/downcast-converters~HighlightDescriptor} [data.oldDescriptor] Old highlight | ||
* descriptor. It will be `undefined` when first descriptor is added to the stack. | ||
* @param {module:engine/view/writer~Writer} writer View writer that can be used to modify element. | ||
*/ |
/** | ||
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md. | ||
@@ -48,2 +48,3 @@ */ | ||
* @param {module:engine/view/element~Element} element | ||
* @param {module:engine/view/writer~Writer} writer | ||
* @param {Object} [options={}] | ||
@@ -54,10 +55,10 @@ * @param {String|Function} [options.label] Element's label provided to {@link ~setLabel} function. It can be passed as | ||
*/ | ||
export function toWidget( element, options = {} ) { | ||
element.setAttribute( 'contenteditable', 'false' ); | ||
export function toWidget( element, writer, options = {} ) { | ||
writer.setAttribute( 'contenteditable', 'false', element ); | ||
writer.addClass( WIDGET_CLASS_NAME, element ); | ||
writer.setCustomProperty( widgetSymbol, true, element ); | ||
element.getFillerOffset = getFillerOffset; | ||
element.addClass( WIDGET_CLASS_NAME ); | ||
element.setCustomProperty( widgetSymbol, true ); | ||
if ( options.label ) { | ||
setLabel( element, options.label ); | ||
setLabel( element, options.label, writer ); | ||
} | ||
@@ -67,4 +68,5 @@ | ||
element, | ||
( element, descriptor ) => element.addClass( ...normalizeToArray( descriptor.class ) ), | ||
( element, descriptor ) => element.removeClass( ...normalizeToArray( descriptor.class ) ) | ||
writer, | ||
( element, descriptor, writer ) => writer.addClass( normalizeToArray( descriptor.class ), element ), | ||
( element, descriptor, writer ) => writer.removeClass( normalizeToArray( descriptor.class ), element ) | ||
); | ||
@@ -85,6 +87,7 @@ | ||
* @param {module:engine/view/element~Element} element | ||
* @param {module:engine/view/writer~Writer} writer | ||
* @param {Function} add | ||
* @param {Function} remove | ||
*/ | ||
export function setHighlightHandling( element, add, remove ) { | ||
export function setHighlightHandling( element, writer, add, remove ) { | ||
const stack = new HighlightStack(); | ||
@@ -94,12 +97,12 @@ | ||
if ( data.oldDescriptor ) { | ||
remove( element, data.oldDescriptor ); | ||
remove( element, data.oldDescriptor, data.writer ); | ||
} | ||
if ( data.newDescriptor ) { | ||
add( element, data.newDescriptor ); | ||
add( element, data.newDescriptor, data.writer ); | ||
} | ||
} ); | ||
element.setCustomProperty( 'addHighlight', ( element, descriptor ) => stack.add( descriptor ) ); | ||
element.setCustomProperty( 'removeHighlight', ( element, id ) => stack.remove( id ) ); | ||
writer.setCustomProperty( 'addHighlight', ( element, descriptor, writer ) => stack.add( descriptor, writer ), element ); | ||
writer.setCustomProperty( 'removeHighlight', ( element, id, writer ) => stack.remove( id, writer ), element ); | ||
} | ||
@@ -114,5 +117,6 @@ | ||
* @param {String|Function} labelOrCreator | ||
* * @param {module:engine/view/writer~Writer} writer | ||
*/ | ||
export function setLabel( element, labelOrCreator ) { | ||
element.setCustomProperty( labelSymbol, labelOrCreator ); | ||
export function setLabel( element, labelOrCreator, writer ) { | ||
writer.setCustomProperty( labelSymbol, labelOrCreator, element ); | ||
} | ||
@@ -146,11 +150,11 @@ | ||
*/ | ||
export function toWidgetEditable( editable ) { | ||
editable.addClass( 'ck-editable' ); | ||
export function toWidgetEditable( editable, writer ) { | ||
writer.addClass( 'ck-editable', editable ); | ||
// Set initial contenteditable value. | ||
editable.setAttribute( 'contenteditable', editable.isReadOnly ? 'false' : 'true' ); | ||
writer.setAttribute( 'contenteditable', editable.isReadOnly ? 'false' : 'true', editable ); | ||
// Bind contenteditable property to element#isReadOnly. | ||
editable.on( 'change:isReadOnly', ( evt, property, is ) => { | ||
editable.setAttribute( 'contenteditable', is ? 'false' : 'true' ); | ||
writer.setAttribute( 'contenteditable', is ? 'false' : 'true', editable ); | ||
} ); | ||
@@ -160,5 +164,5 @@ | ||
if ( is ) { | ||
editable.addClass( 'ck-editable_focused' ); | ||
writer.addClass( 'ck-editable_focused', editable ); | ||
} else { | ||
editable.removeClass( 'ck-editable_focused' ); | ||
writer.removeClass( 'ck-editable_focused', editable ); | ||
} | ||
@@ -165,0 +169,0 @@ } ); |
/** | ||
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. | ||
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved. | ||
* For licensing, see LICENSE.md. | ||
@@ -20,3 +20,3 @@ */ | ||
import '../theme/theme.scss'; | ||
import '../theme/widget.css'; | ||
@@ -46,3 +46,4 @@ const selectAllKeystrokeCode = parseKeystroke( 'Ctrl+A' ); | ||
init() { | ||
const viewDocument = this.editor.editing.view; | ||
const view = this.editor.editing.view; | ||
const viewDocument = view.document; | ||
@@ -59,7 +60,8 @@ /** | ||
// Converts selection placed over widget element to fake selection | ||
this.editor.editing.modelToView.on( 'selection', ( evt, data, consumable, conversionApi ) => { | ||
this.editor.editing.downcastDispatcher.on( 'selection', ( evt, data, conversionApi ) => { | ||
// Remove selected class from previously selected widgets. | ||
this._clearPreviouslySelectedWidgets(); | ||
this._clearPreviouslySelectedWidgets( conversionApi.writer ); | ||
const viewSelection = conversionApi.viewSelection; | ||
const viewWriter = conversionApi.writer; | ||
const viewSelection = viewWriter.document.selection; | ||
const selectedElement = viewSelection.getSelectedElement(); | ||
@@ -72,3 +74,3 @@ | ||
if ( node.is( 'element' ) && isWidget( node ) ) { | ||
node.addClass( WIDGET_SELECTED_CLASS_NAME ); | ||
viewWriter.addClass( WIDGET_SELECTED_CLASS_NAME, node ); | ||
this._previouslySelected.add( node ); | ||
@@ -78,3 +80,3 @@ | ||
if ( node == selectedElement ) { | ||
viewSelection.setFake( true, { label: getLabel( selectedElement ) } ); | ||
viewWriter.setSelection( viewSelection.getRanges(), { fake: true, label: getLabel( selectedElement ) } ); | ||
} | ||
@@ -87,3 +89,3 @@ } | ||
// If mouse down is pressed on widget - create selection over whole widget. | ||
viewDocument.addObserver( MouseObserver ); | ||
view.addObserver( MouseObserver ); | ||
this.listenTo( viewDocument, 'mousedown', ( ...args ) => this._onMousedown( ...args ) ); | ||
@@ -93,2 +95,10 @@ | ||
this.listenTo( viewDocument, 'keydown', ( ...args ) => this._onKeydown( ...args ), { priority: 'high' } ); | ||
// Handle custom delete behaviour. | ||
this.listenTo( viewDocument, 'delete', ( evt, data ) => { | ||
if ( this._handleDelete( data.direction == 'forward' ) ) { | ||
data.preventDefault(); | ||
evt.stop(); | ||
} | ||
}, { priority: 'high' } ); | ||
} | ||
@@ -105,3 +115,4 @@ | ||
const editor = this.editor; | ||
const viewDocument = editor.editing.view; | ||
const view = editor.editing.view; | ||
const viewDocument = view.document; | ||
let element = domEventData.target; | ||
@@ -127,3 +138,3 @@ | ||
if ( !viewDocument.isFocused ) { | ||
viewDocument.focus(); | ||
view.focus(); | ||
} | ||
@@ -134,3 +145,3 @@ | ||
editor.document.enqueueChanges( ( ) => { | ||
editor.model.change( () => { | ||
this._setSelectionOverElement( modelElement ); | ||
@@ -154,5 +165,3 @@ } ); | ||
// the propagation. | ||
if ( isDeleteKeyCode( keyCode ) ) { | ||
wasHandled = this._handleDelete( isForward ); | ||
} else if ( isArrowKeyCode( keyCode ) ) { | ||
if ( isArrowKeyCode( keyCode ) ) { | ||
wasHandled = this._handleArrowKeys( isForward ); | ||
@@ -182,3 +191,3 @@ } else if ( isSelectAllKeyCode( domEventData ) ) { | ||
const modelDocument = this.editor.document; | ||
const modelDocument = this.editor.model.document; | ||
const modelSelection = modelDocument.selection; | ||
@@ -194,4 +203,3 @@ | ||
if ( objectElement ) { | ||
modelDocument.enqueueChanges( () => { | ||
const batch = modelDocument.batch(); | ||
this.editor.model.change( writer => { | ||
let previousNode = modelSelection.anchor.parent; | ||
@@ -204,3 +212,3 @@ | ||
batch.remove( nodeToRemove ); | ||
writer.remove( nodeToRemove ); | ||
} | ||
@@ -222,15 +230,16 @@ | ||
_handleArrowKeys( isForward ) { | ||
const modelDocument = this.editor.document; | ||
const schema = modelDocument.schema; | ||
const model = this.editor.model; | ||
const schema = model.schema; | ||
const modelDocument = model.document; | ||
const modelSelection = modelDocument.selection; | ||
const objectElement = modelSelection.getSelectedElement(); | ||
// if object element is selected. | ||
if ( objectElement && schema.objects.has( objectElement.name ) ) { | ||
// If object element is selected. | ||
if ( objectElement && schema.isObject( objectElement ) ) { | ||
const position = isForward ? modelSelection.getLastPosition() : modelSelection.getFirstPosition(); | ||
const newRange = modelDocument.getNearestSelectionRange( position, isForward ? 'forward' : 'backward' ); | ||
const newRange = schema.getNearestSelectionRange( position, isForward ? 'forward' : 'backward' ); | ||
if ( newRange ) { | ||
modelDocument.enqueueChanges( () => { | ||
modelSelection.setRanges( [ newRange ] ); | ||
model.change( writer => { | ||
writer.setSelection( newRange ); | ||
} ); | ||
@@ -250,4 +259,4 @@ } | ||
if ( objectElement2 instanceof ModelElement && modelDocument.schema.objects.has( objectElement2.name ) ) { | ||
modelDocument.enqueueChanges( () => { | ||
if ( objectElement2 instanceof ModelElement && schema.isObject( objectElement2 ) ) { | ||
model.change( () => { | ||
this._setSelectionOverElement( objectElement2 ); | ||
@@ -269,13 +278,12 @@ } ); | ||
_selectAllNestedEditableContent() { | ||
const modelDocument = this.editor.document; | ||
const modelSelection = modelDocument.selection; | ||
const schema = modelDocument.schema; | ||
const limitElement = schema.getLimitElement( modelSelection ); | ||
const model = this.editor.model; | ||
const documentSelection = model.document.selection; | ||
const limitElement = model.schema.getLimitElement( documentSelection ); | ||
if ( modelSelection.getFirstRange().root == limitElement ) { | ||
if ( documentSelection.getFirstRange().root == limitElement ) { | ||
return false; | ||
} | ||
modelDocument.enqueueChanges( () => { | ||
modelSelection.setIn( limitElement ); | ||
model.change( writer => { | ||
writer.setSelection( ModelRange.createIn( limitElement ) ); | ||
} ); | ||
@@ -293,6 +301,6 @@ | ||
_selectAllContent() { | ||
const modelDocument = this.editor.document; | ||
const modelSelection = modelDocument.selection; | ||
const model = this.editor.model; | ||
const editing = this.editor.editing; | ||
const viewDocument = editing.view; | ||
const view = editing.view; | ||
const viewDocument = view.document; | ||
const viewSelection = viewDocument.selection; | ||
@@ -307,4 +315,4 @@ | ||
modelDocument.enqueueChanges( () => { | ||
modelSelection.setRanges( [ ModelRange.createIn( widgetParent ) ] ); | ||
model.change( writer => { | ||
writer.setSelection( ModelRange.createIn( widgetParent ) ); | ||
} ); | ||
@@ -325,3 +333,5 @@ | ||
_setSelectionOverElement( element ) { | ||
this.editor.document.selection.setRanges( [ ModelRange.createOn( element ) ] ); | ||
this.editor.model.change( writer => { | ||
writer.setSelection( ModelRange.createOn( element ) ); | ||
} ); | ||
} | ||
@@ -339,14 +349,13 @@ | ||
_getObjectElementNextToSelection( forward ) { | ||
const modelDocument = this.editor.document; | ||
const schema = modelDocument.schema; | ||
const modelSelection = modelDocument.selection; | ||
const dataController = this.editor.data; | ||
const model = this.editor.model; | ||
const schema = model.schema; | ||
const modelSelection = model.document.selection; | ||
// Clone current selection to use it as a probe. We must leave default selection as it is so it can return | ||
// to its current state after undo. | ||
const probe = ModelSelection.createFromSelection( modelSelection ); | ||
dataController.modifySelection( probe, { direction: forward ? 'forward' : 'backward' } ); | ||
const probe = new ModelSelection( modelSelection ); | ||
model.modifySelection( probe, { direction: forward ? 'forward' : 'backward' } ); | ||
const objectElement = forward ? probe.focus.nodeBefore : probe.focus.nodeAfter; | ||
if ( objectElement instanceof ModelElement && schema.objects.has( objectElement.name ) ) { | ||
if ( objectElement instanceof ModelElement && schema.isObject( objectElement ) ) { | ||
return objectElement; | ||
@@ -360,7 +369,9 @@ } | ||
* Removes CSS class from previously selected widgets. | ||
* | ||
* @private | ||
* @param {module:engine/view/writer~Writer} writer | ||
*/ | ||
_clearPreviouslySelectedWidgets() { | ||
_clearPreviouslySelectedWidgets( writer ) { | ||
for ( const widget of this._previouslySelected ) { | ||
widget.removeClass( WIDGET_SELECTED_CLASS_NAME ); | ||
writer.removeClass( WIDGET_SELECTED_CLASS_NAME, widget ); | ||
} | ||
@@ -383,10 +394,2 @@ | ||
// Returns 'true' if provided key code represents one of the delete keys: delete or backspace. | ||
// | ||
// @param {Number} keyCode | ||
// @returns {Boolean} | ||
function isDeleteKeyCode( keyCode ) { | ||
return keyCode == keyCodes.delete || keyCode == keyCodes.backspace; | ||
} | ||
// Returns 'true' if provided (DOM) key event data corresponds with the Ctrl+A keystroke. | ||
@@ -393,0 +396,0 @@ // |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
32116
637
22
5