mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
32 changed files with 517 additions and 333 deletions
@ -1,6 +1,66 @@ |
|||||
@import 'mixins'; |
@import 'mixins'; |
||||
@import 'vars'; |
@import 'vars'; |
||||
|
|
||||
|
:host ::ng-deep { |
||||
|
.modal-body { |
||||
|
background-color: $color-background; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
form { |
||||
|
width: 100%; |
||||
|
} |
||||
|
|
||||
textarea { |
textarea { |
||||
height: 300px; |
height: 300px; |
||||
|
} |
||||
|
|
||||
|
.flex-reverse { |
||||
|
flex-direction: row-reverse; |
||||
|
} |
||||
|
|
||||
|
.bubble { |
||||
|
background-color: $color-white; |
||||
|
border: 0; |
||||
|
border-radius: $border-radius; |
||||
|
padding: 1rem; |
||||
|
position: relative; |
||||
|
|
||||
|
&-right { |
||||
|
&::before { |
||||
|
@include caret-left($color-white, 10px); |
||||
|
@include absolute(.5rem, null, null, -18px); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&-left { |
||||
|
&::before { |
||||
|
@include caret-right($color-white, 10px); |
||||
|
@include absolute(.5rem, -18px); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@keyframes blink { |
||||
|
50% { |
||||
|
fill: transparent |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.dot { |
||||
|
animation: 1s blink infinite; |
||||
|
} |
||||
|
|
||||
|
svg { |
||||
|
.dot { |
||||
|
fill: $color-border; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.dot:nth-child(2) { |
||||
|
animation-delay: 250ms; |
||||
|
} |
||||
|
|
||||
|
.dot:nth-child(3) { |
||||
|
animation-delay: 500ms; |
||||
} |
} |
||||
@ -1,7 +1,7 @@ |
|||||
<div class="copy-container"> |
<div class="code-container"> |
||||
<button type="button" class="code-copy" [sqxCopy]="codeBlock"> |
<button type="button" class="code-copy" [attr.copy]="id"> |
||||
<i class="icon-copy"></i> |
<i class="icon-copy"></i> |
||||
</button> |
</button> |
||||
|
|
||||
<pre class="code" #codeBlock><ng-content></ng-content></pre> |
<pre class="code" [attr.id]="id"><ng-content></ng-content></pre> |
||||
</div> |
</div> |
||||
@ -1,34 +1,2 @@ |
|||||
@import 'mixins'; |
@import 'mixins'; |
||||
@import 'vars'; |
@import 'vars'; |
||||
|
|
||||
.code { |
|
||||
background: $color-code-background; |
|
||||
margin: .25rem 0; |
|
||||
padding-left: .5rem; |
|
||||
padding-right: 3rem; |
|
||||
} |
|
||||
|
|
||||
.code, |
|
||||
.code-copy { |
|
||||
@include text-code; |
|
||||
min-height: 27px; |
|
||||
padding-bottom: .25rem; |
|
||||
padding-top: .25rem; |
|
||||
} |
|
||||
|
|
||||
.copy-container { |
|
||||
position: relative; |
|
||||
} |
|
||||
|
|
||||
.code-copy { |
|
||||
@include absolute(0, 0, auto, auto); |
|
||||
background: darken($color-border-dark, 30%); |
|
||||
border: 0; |
|
||||
color: $color-white; |
|
||||
padding-left: .375rem; |
|
||||
padding-right: .375rem; |
|
||||
|
|
||||
&:focus { |
|
||||
background: darken($color-border-dark, 40%); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,91 @@ |
|||||
|
/* |
||||
|
* Squidex Headless CMS |
||||
|
* |
||||
|
* @license |
||||
|
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
||||
|
*/ |
||||
|
|
||||
|
import { Directive, HostListener, Renderer2 } from '@angular/core'; |
||||
|
import { DialogService, Types } from '@app/framework/internal'; |
||||
|
|
||||
|
@Directive({ |
||||
|
selector: '[sqxCopyGlobal]', |
||||
|
}) |
||||
|
export class CopyGlobalDirective { |
||||
|
constructor( |
||||
|
private readonly dialogs: DialogService, |
||||
|
private readonly renderer: Renderer2, |
||||
|
) { |
||||
|
} |
||||
|
|
||||
|
@HostListener('document:click', ['$event']) |
||||
|
public onClick(event: MouseEvent) { |
||||
|
function findElement(target: HTMLElement | null): string | null { |
||||
|
if (!target) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
const id = target.getAttribute('copy')!; |
||||
|
|
||||
|
if (id) { |
||||
|
return id; |
||||
|
} |
||||
|
|
||||
|
return findElement(target.parentElement); |
||||
|
} |
||||
|
|
||||
|
const toCopy = document.getElementById(findElement(event.target as any)!); |
||||
|
|
||||
|
if (!toCopy) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.copyToClipbord(toCopy); |
||||
|
} |
||||
|
|
||||
|
private copyToClipbord(element: HTMLElement) { |
||||
|
if (Types.is(element, HTMLInputElement) || Types.is(element, HTMLTextAreaElement)) { |
||||
|
const currentFocus: any = document.activeElement; |
||||
|
|
||||
|
const prevSelectionStart = element.selectionStart; |
||||
|
const prevSelectionEnd = element.selectionEnd; |
||||
|
|
||||
|
element.focus(); |
||||
|
element.setSelectionRange(0, element.value.length); |
||||
|
|
||||
|
this.copy(); |
||||
|
|
||||
|
element.setSelectionRange(prevSelectionStart!, prevSelectionEnd!); |
||||
|
|
||||
|
if (currentFocus && Types.isFunction(currentFocus.focus)) { |
||||
|
currentFocus.focus(); |
||||
|
} |
||||
|
} else { |
||||
|
const input = this.renderer.createElement('textarea'); |
||||
|
|
||||
|
this.renderer.setStyle(input, 'position', 'absolute'); |
||||
|
this.renderer.setStyle(input, 'right', '-1000px'); |
||||
|
this.renderer.appendChild(document.body, input); |
||||
|
|
||||
|
input.value = element.innerText; |
||||
|
input.select(); |
||||
|
|
||||
|
this.copy(); |
||||
|
|
||||
|
this.renderer.removeChild(document.body, input); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private copy() { |
||||
|
try { |
||||
|
// eslint-disable-next-line deprecation/deprecation
|
||||
|
document.execCommand('copy'); |
||||
|
|
||||
|
this.dialogs.notifyInfo('i18n:common.clipboardAdded'); |
||||
|
|
||||
|
return true; |
||||
|
} catch (e) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue