Merge pull request #2667 from alecmerdler/no-flash-clipboard
Copy-to-Clipboard Without Flash
This commit is contained in:
commit
f759784262
13 changed files with 186 additions and 74 deletions
|
@ -23,10 +23,6 @@ angular.module('quay').directive('buildLogsView', function () {
|
|||
repoStatusApiCall = ApiService.getRepoBuildStatusSuperUser;
|
||||
repoLogApiCall = ApiService.getRepoBuildLogsSuperUserAsResource;
|
||||
}
|
||||
var result = $element.find('#copyButton').clipboardCopy();
|
||||
if (!result) {
|
||||
$element.find('#copyButton').hide();
|
||||
}
|
||||
|
||||
$scope.logEntries = null;
|
||||
$scope.currentParentEntry = null;
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
import { ClipboardCopyDirective } from './clipboard-copy.directive';
|
||||
import * as Clipboard from 'clipboard';
|
||||
import { Mock } from 'ts-mocks';
|
||||
import Spy = jasmine.Spy;
|
||||
|
||||
|
||||
describe("ClipboardCopyDirective", () => {
|
||||
var directive: ClipboardCopyDirective;
|
||||
var $elementMock: any;
|
||||
var $timeoutMock: any;
|
||||
var $documentMock: any;
|
||||
var clipboardFactory: any;
|
||||
var clipboardMock: Mock<Clipboard>;
|
||||
|
||||
beforeEach(() => {
|
||||
$elementMock = new Mock<ng.IAugmentedJQuery>();
|
||||
$timeoutMock = jasmine.createSpy('$timeoutSpy').and.callFake((fn: () => void, delay) => fn());
|
||||
$documentMock = new Mock<ng.IDocumentService>();
|
||||
clipboardMock = new Mock<Clipboard>();
|
||||
clipboardMock.setup(mock => mock.on).is((eventName: string, callback: (event) => void) => {});
|
||||
clipboardFactory = jasmine.createSpy('clipboardFactory').and.returnValue(clipboardMock.Object);
|
||||
directive = new ClipboardCopyDirective(<any>[$elementMock.Object],
|
||||
$timeoutMock,
|
||||
<any>[$documentMock.Object],
|
||||
clipboardFactory);
|
||||
directive.copyTargetSelector = "#copy-input-box-0";
|
||||
});
|
||||
|
||||
describe("ngAfterContentInit", () => {
|
||||
|
||||
it("initializes new Clipboard instance", () => {
|
||||
const target = new Mock<ng.IAugmentedJQuery>();
|
||||
$documentMock.setup(mock => mock.querySelector).is(selector => target.Object);
|
||||
directive.ngAfterContentInit();
|
||||
|
||||
expect(clipboardFactory).toHaveBeenCalled();
|
||||
expect((<Spy>clipboardFactory.calls.argsFor(0)[0])).toEqual($elementMock.Object);
|
||||
expect((<Spy>clipboardFactory.calls.argsFor(0)[1]['target']())).toEqual(target.Object);
|
||||
});
|
||||
|
||||
it("sets error callback for Clipboard instance", () => {
|
||||
directive.ngAfterContentInit();
|
||||
|
||||
expect((<Spy>clipboardMock.Object.on.calls.argsFor(0)[0])).toEqual('error');
|
||||
expect((<Spy>clipboardMock.Object.on.calls.argsFor(0)[1])).toBeDefined();
|
||||
});
|
||||
|
||||
it("sets success callback for Clipboard instance", (done) => {
|
||||
directive.ngAfterContentInit();
|
||||
|
||||
expect((<Spy>clipboardMock.Object.on.calls.argsFor(1)[0])).toEqual('success');
|
||||
expect((<Spy>clipboardMock.Object.on.calls.argsFor(1)[1])).toBeDefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe("ngOnDestroy", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
clipboardMock.setup(mock => mock.destroy).is(() => null);
|
||||
});
|
||||
|
||||
it("calls method to destroy Clipboard instance if set", (done) => {
|
||||
directive.ngAfterContentInit();
|
||||
directive.ngOnDestroy();
|
||||
|
||||
expect((<Spy>clipboardMock.Object.destroy)).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
it("does not call method to destroy Clipboard instance if not set", () => {
|
||||
directive.ngOnDestroy();
|
||||
|
||||
expect((<Spy>clipboardMock.Object.destroy)).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,63 @@
|
|||
import { Directive, Inject, Input, AfterContentInit, OnDestroy } from 'ng-metadata/core';
|
||||
import * as Clipboard from 'clipboard';
|
||||
|
||||
|
||||
@Directive({
|
||||
selector: '[clipboardCopy]'
|
||||
})
|
||||
export class ClipboardCopyDirective implements AfterContentInit, OnDestroy {
|
||||
|
||||
@Input('@clipboardCopy') public copyTargetSelector: string;
|
||||
|
||||
private clipboard: Clipboard;
|
||||
|
||||
constructor(@Inject('$element') private $element: ng.IAugmentedJQuery,
|
||||
@Inject('$timeout') private $timeout: ng.ITimeoutService,
|
||||
@Inject('$document') private $document: ng.IDocumentService,
|
||||
@Inject('clipboardFactory') private clipboardFactory: (elem, options) => Clipboard) {
|
||||
|
||||
}
|
||||
|
||||
public ngAfterContentInit(): void {
|
||||
// FIXME: Need to wait for DOM to render to find target element
|
||||
this.$timeout(() => {
|
||||
this.clipboard = this.clipboardFactory(this.$element[0], {target: (trigger) => {
|
||||
return this.$document[0].querySelector(this.copyTargetSelector);
|
||||
}});
|
||||
|
||||
this.clipboard.on("error", (e) => {
|
||||
console.error(e);
|
||||
});
|
||||
|
||||
this.clipboard.on('success', (e) => {
|
||||
const container = e.trigger.parentNode.parentNode.parentNode;
|
||||
const messageElem = container.querySelector('.clipboard-copied-message');
|
||||
if (!messageElem) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resets the animation.
|
||||
var elem = messageElem;
|
||||
elem.style.display = 'none';
|
||||
elem.classList.remove('animated');
|
||||
|
||||
// Show the notification.
|
||||
setTimeout(() => {
|
||||
elem.style.display = 'inline-block';
|
||||
elem.classList.add('animated');
|
||||
}, 10);
|
||||
|
||||
// Reset the notification.
|
||||
setTimeout(() => {
|
||||
elem.style.display = 'none';
|
||||
}, 5000);
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
if (this.clipboard) {
|
||||
this.clipboard.destroy();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,49 +1,5 @@
|
|||
$.fn.clipboardCopy = function() {
|
||||
if (__zeroClipboardSupported) {
|
||||
(new ZeroClipboard($(this)));
|
||||
return true;
|
||||
}
|
||||
|
||||
this.hide();
|
||||
return false;
|
||||
};
|
||||
|
||||
// Initialize the clipboard system.
|
||||
(function () {
|
||||
__zeroClipboardSupported = true;
|
||||
|
||||
ZeroClipboard.on("error", function(e) {
|
||||
__zeroClipboardSupported = false;
|
||||
});
|
||||
|
||||
ZeroClipboard.on('aftercopy', function(e) {
|
||||
var container = e.target.parentNode.parentNode.parentNode;
|
||||
var message = $(container).find('.clipboard-copied-message')[0];
|
||||
if (!message) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resets the animation.
|
||||
var elem = message;
|
||||
elem.style.display = 'none';
|
||||
elem.classList.remove('animated');
|
||||
|
||||
// Show the notification.
|
||||
setTimeout(function() {
|
||||
elem.style.display = 'inline-block';
|
||||
elem.classList.add('animated');
|
||||
}, 10);
|
||||
|
||||
// Reset the notification.
|
||||
setTimeout(function() {
|
||||
elem.style.display = 'none';
|
||||
}, 5000);
|
||||
});
|
||||
})();
|
||||
|
||||
/**
|
||||
* An element which displays a textfield with a "Copy to Clipboard" icon next to it. Note
|
||||
* that this method depends on the clipboard copying library in the lib/ folder.
|
||||
* An element which displays a textfield with a "Copy to Clipboard" icon next to it.
|
||||
*/
|
||||
angular.module('quay').directive('copyBox', function () {
|
||||
var directiveDefinitionObject = {
|
||||
|
@ -62,13 +18,6 @@ angular.module('quay').directive('copyBox', function () {
|
|||
var number = $rootScope.__copyBoxIdCounter || 0;
|
||||
$rootScope.__copyBoxIdCounter = number + 1;
|
||||
$scope.inputId = "copy-box-input-" + number;
|
||||
|
||||
var button = $($element).find('.copy-icon');
|
||||
var input = $($element).find('input');
|
||||
|
||||
input.attr('id', $scope.inputId);
|
||||
button.attr('data-clipboard-target', $scope.inputId);
|
||||
$scope.disabled = !button.clipboardCopy();
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
|
|
|
@ -125,7 +125,6 @@ angular.module('quay').directive('fetchTagDialog', function () {
|
|||
|
||||
updateFormats();
|
||||
|
||||
$element.find('#copyClipboard').clipboardCopy();
|
||||
$element.find('#fetchTagDialog').modal({});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -36,7 +36,9 @@ import { MarkdownToolbarComponent } from './directives/ui/markdown/markdown-tool
|
|||
import { MarkdownEditorComponent } from './directives/ui/markdown/markdown-editor.component';
|
||||
import { BrowserPlatform, browserPlatform } from './constants/platform.constant';
|
||||
import { ManageTriggerComponent } from './directives/ui/manage-trigger/manage-trigger.component';
|
||||
import { ClipboardCopyDirective } from './directives/ui/clipboard-copy/clipboard-copy.directive';
|
||||
import { Converter, ConverterOptions } from 'showdown';
|
||||
import * as Clipboard from 'clipboard';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -75,6 +77,7 @@ import { Converter, ConverterOptions } from 'showdown';
|
|||
CorTabComponent,
|
||||
CorTabPaneComponent,
|
||||
ManageTriggerComponent,
|
||||
ClipboardCopyDirective,
|
||||
],
|
||||
providers: [
|
||||
ViewArrayImpl,
|
||||
|
@ -86,6 +89,7 @@ import { Converter, ConverterOptions } from 'showdown';
|
|||
{provide: 'markdownConverterFactory', useValue: (options?: ConverterOptions) => new Converter(options)},
|
||||
{provide: 'BrowserPlatform', useValue: browserPlatform},
|
||||
{provide: 'CorTabCurrentHandlerFactory', useValue: CorTabCurrentHandlerFactory},
|
||||
{provide: 'clipboardFactory', useValue: (trigger, options) => new Clipboard(trigger, options)},
|
||||
],
|
||||
})
|
||||
export class QuayModule {
|
||||
|
|
Reference in a new issue