src/app/modules/certificate/components/svg-editor/svg-editor.component.ts
OnInit
OnDestroy
selector | app-svg-editor |
styleUrls | ./svg-editor.component.scss |
templateUrl | ./svg-editor.component.html |
constructor(uploadCertificateService: UploadCertificateService, userService: UserService, sanitizer: DomSanitizer, activatedRoute: ActivatedRoute, certRegService: CertRegService, toasterService: ToasterService, resourceService: ResourceService, navigationHelperService: NavigationHelperService, layoutService: LayoutService)
|
||||||||||||||||||||||||||||||
Parameters :
|
assetData | ||||
assetData(data)
|
||||
Parameters :
Returns :
void
|
back |
back()
|
Returns :
void
|
certificateCreation | ||||
certificateCreation(ev)
|
||||
Parameters :
Returns :
void
|
chooseCertificate | ||||
chooseCertificate(certificate)
|
||||
Parameters :
Returns :
void
|
close |
close()
|
Returns :
void
|
closeSaveAndPreview |
closeSaveAndPreview()
|
Returns :
void
|
closeSVGInputModal |
closeSVGInputModal()
|
Returns :
void
|
convertHtml | ||||
convertHtml(tag)
|
||||
Parameters :
Returns :
any
|
createCertTemplate |
createCertTemplate()
|
Returns :
void
|
editSVG | ||||||
editSVG(logosArray, stateLogos)
|
||||||
Parameters :
Returns :
any
|
elementClicked | ||||||
elementClicked(e: any)
|
||||||
Parameters :
Returns :
void
|
getBase64Data | ||||
getBase64Data(ev)
|
||||
Parameters :
Returns :
string
|
getDefaultTemplates |
getDefaultTemplates()
|
Returns :
void
|
getImagePath |
getImagePath()
|
Returns :
any
|
getSVGTemplate |
getSVGTemplate()
|
Returns :
void
|
initializeFormFields |
initializeFormFields()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
openSateLogos | ||||
openSateLogos(type)
|
||||
Parameters :
Returns :
void
|
openSignLogos | ||||
openSignLogos(type)
|
||||
Parameters :
Returns :
void
|
previewAndSave |
previewAndSave()
|
Returns :
void
|
previewCertificate |
previewCertificate()
|
Returns :
void
|
previewUpdatedSVGCertificate |
previewUpdatedSVGCertificate()
|
Returns :
void
|
redoLayout |
redoLayout()
|
Returns :
void
|
removeImage | ||||
removeImage(key)
|
||||
Parameters :
Returns :
void
|
sanitizeHTML | ||||
sanitizeHTML(html)
|
||||
Parameters :
Returns :
any
|
saveUpdatedCertificate |
saveUpdatedCertificate()
|
Returns :
void
|
svgAssetData | ||||
svgAssetData(imageObj)
|
||||
Parameters :
Returns :
void
|
toDataURL | ||||
toDataURL(image)
|
||||
Parameters :
Returns :
any
|
toggleSVGPreview |
toggleSVGPreview()
|
Returns :
void
|
updateSigns | ||||
updateSigns(stateLogos)
|
||||
Parameters :
Returns :
void
|
updateStateLogos | ||||
updateStateLogos(stateLogos)
|
||||
Parameters :
Returns :
void
|
updateSVGInputTag |
updateSVGInputTag()
|
Returns :
void
|
updateTitles |
updateTitles()
|
Returns :
void
|
uploadTemplate | ||||||
uploadTemplate(base64Url, identifier)
|
||||||
Parameters :
Returns :
void
|
urltoFile | ||||||||
urltoFile(url, filename, mimeType)
|
||||||||
Parameters :
Returns :
any
|
validateForm |
validateForm()
|
Returns :
void
|
Public browseImage |
Type : BrowseImagePopupComponent
|
Decorators :
@ViewChild(BrowseImagePopupComponent)
|
center |
Type : number
|
Default value : 275
|
certConfigModalInstance |
Default value : new CertConfigModel()
|
certLogos |
Type : any
|
Default value : []
|
certSigns |
Type : any
|
Default value : []
|
classNames |
Type : object
|
Default value : {
'STATE_LOGOS': 'state-logo',
'STATE_TITLE': 'state-title',
'SIGN_LOGO': ['signatureImg1', 'signatureImg2'],
'CERT_TITLE': 'cert-title',
'DESIGNATIONS_NAMES': ['signatureTitle1', 'signatureTitle2'],
'DESIGNATIONS': ['signatureTitle1a', 'signatureTitle2a']
}
|
createTemplateForm |
Type : UntypedFormGroup
|
defaultCertificates |
Type : []
|
Default value : []
|
disableCreateTemplate |
Default value : true
|
disableSVGImageModal |
Type : boolean
|
Default value : false
|
edit |
Type : Subject<any>
|
Default value : new Subject()
|
finalSVGurl |
Type : any
|
FIRST_PANEL_LAYOUT |
getBase64FromUrl |
Default value : () => {...}
|
images |
Type : object
|
Default value : {
'LOGO1': { 'index': null, 'name' : '' , 'key': '', 'type': '', 'url': ''},
'LOGO2': { 'index': null, 'name' : '' , 'key': '', 'type': '', 'url': ''},
'SIGN1': { 'index': null, 'name' : '' , 'key': '', 'type': '', 'url': ''},
'SIGN2': { 'index': null, 'name' : '' , 'key': '', 'type': '', 'url': ''}
}
|
layoutConfiguration |
Type : any
|
Public layoutService |
Type : LayoutService
|
logoHtml |
logoType |
mode |
Type : any
|
Public navigationHelperService |
Type : NavigationHelperService
|
optionSing |
Type : string
|
Default value : 'SIGN2'
|
previewButton |
Type : string
|
Default value : 'show'
|
previewSvgData |
Type : any
|
queryParams |
Type : any
|
refreshEditor |
Type : Subject<any>
|
Default value : new Subject()
|
Public resourceService |
Type : ResourceService
|
save |
Type : Subject<any>
|
Default value : new Subject()
|
saveAndPreview |
Type : boolean
|
Default value : false
|
SECOND_PANEL_LAYOUT |
selectedCertificate |
Type : any
|
Default value : {}
|
selectedSVGObject |
Type : any
|
Default value : {}
|
selectLanguage |
Type : any
|
selectLanguageOption |
Type : any
|
Default value : []
|
selectState |
Type : any
|
selectStateOption |
Type : any
|
Default value : []
|
showPreviewButton |
Type : boolean
|
Default value : true
|
showSelectImageModal |
showSVGInputModal |
Type : boolean
|
Default value : false
|
showUploadUserModal |
svgData |
Public toasterService |
Type : ToasterService
|
togglePreview |
Type : Subject<any>
|
Default value : new Subject()
|
Public unsubscribe$ |
Default value : new Subject<void>()
|
Public uploadCertificateService |
Type : UploadCertificateService
|
userConsent |
Type : boolean
|
Default value : false
|
Public userService |
Type : UserService
|
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import * as _ from 'lodash-es';
import { UploadCertificateService } from '../../services/upload-certificate/upload-certificate.service';
import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms';
import { UserService, CertRegService } from '@sunbird/core';
import { ToasterService, ResourceService, NavigationHelperService, LayoutService, COLUMN_TYPE } from '@sunbird/shared';
import { DomSanitizer } from '@angular/platform-browser';
import { CertConfigModel } from '../../models/cert-config-model/cert-config-model';
import { BrowseImagePopupComponent } from '../browse-image-popup/browse-image-popup.component';
import {ActivatedRoute} from '@angular/router';
import dayjs from 'dayjs';
@Component({
selector: 'app-svg-editor',
templateUrl: './svg-editor.component.html',
styleUrls: ['./svg-editor.component.scss']
})
export class SvgEditorComponent implements OnInit, OnDestroy {
@ViewChild(BrowseImagePopupComponent)
public browseImage: BrowseImagePopupComponent;
public unsubscribe$ = new Subject<void>();
createTemplateForm: UntypedFormGroup;
selectStateOption: any = [];
selectLanguageOption: any = [];
selectState: any;
selectLanguage: any;
showSelectImageModal;
showUploadUserModal;
certLogos: any = [];
certSigns: any = [];
logoType;
// api call
defaultCertificates = [];
selectedCertificate: any = {};
logoHtml;
svgData;
center = 275;
disableCreateTemplate = true;
certConfigModalInstance = new CertConfigModel();
layoutConfiguration: any;
FIRST_PANEL_LAYOUT;
SECOND_PANEL_LAYOUT;
images = {
'LOGO1': { 'index': null, 'name' : '' , 'key': '', 'type': '', 'url': ''},
'LOGO2': { 'index': null, 'name' : '' , 'key': '', 'type': '', 'url': ''},
'SIGN1': { 'index': null, 'name' : '' , 'key': '', 'type': '', 'url': ''},
'SIGN2': { 'index': null, 'name' : '' , 'key': '', 'type': '', 'url': ''}
};
finalSVGurl: any;
classNames = {
'STATE_LOGOS': 'state-logo',
'STATE_TITLE': 'state-title',
'SIGN_LOGO': ['signatureImg1', 'signatureImg2'],
'CERT_TITLE': 'cert-title',
'DESIGNATIONS_NAMES': ['signatureTitle1', 'signatureTitle2'],
'DESIGNATIONS': ['signatureTitle1a', 'signatureTitle2a']
};
optionSing = 'SIGN2';
queryParams: any;
mode: any;
edit: Subject<any> = new Subject();
refreshEditor: Subject<any> = new Subject();
togglePreview: Subject<any> = new Subject();
save: Subject<any> = new Subject();
showSVGInputModal: boolean = false;
disableSVGImageModal: boolean = false;
selectedSVGObject: any = {};
showPreviewButton: boolean = true;
previewButton: string = 'show';
saveAndPreview: boolean = false;
userConsent: boolean = false;
previewSvgData: any;
constructor(public uploadCertificateService: UploadCertificateService,
public userService: UserService,
private sanitizer: DomSanitizer,
private activatedRoute: ActivatedRoute,
private certRegService: CertRegService,
public toasterService: ToasterService,
public resourceService: ResourceService,
public navigationHelperService: NavigationHelperService,
public layoutService: LayoutService) {
}
ngOnInit() {
this.activatedRoute.queryParams.subscribe((params) => {
this.queryParams = params;
this.mode = _.get(this.queryParams, 'type');
});
this.navigationHelperService.setNavigationUrl();
this.initializeFormFields();
this.getDefaultTemplates();
this.layoutConfiguration = this.layoutService.initlayoutConfig();
this.redoLayout();
}
getDefaultTemplates() {
const request = {
'request': {
'filters': {
'certType': 'cert template layout',
'channel': this.userService.channel,
'mediaType': 'image'
},
'fields': ['identifier', 'name', 'code', 'certType', 'data', 'issuer', 'signatoryList', 'artifactUrl', 'primaryCategory', 'channel'],
'limit': 100
}
};
this.uploadCertificateService.getCertificates(request).subscribe(res => {
this.defaultCertificates = _.get(res, 'result.content');
this.selectedCertificate = _.clone(this.defaultCertificates[0]);
this.getSVGTemplate();
});
}
initializeFormFields() {
this.createTemplateForm = new UntypedFormGroup({
certificateTitle: new UntypedFormControl('', [Validators.required]),
stateName: new UntypedFormControl('', [Validators.required]),
authoritySignature_0: new UntypedFormControl('', [Validators.required]),
authoritySignature_1: new UntypedFormControl(''),
allowPermission: new UntypedFormControl('', [Validators.required])
});
// TODO: Move to a separate component this browse logic;
this.createTemplateForm.valueChanges.subscribe(val => {
this.validateForm();
});
}
validateForm() {
// TODO: Form validation need to improve
const logo = _.get(this.images, 'LOGO1.url');
const sign = _.get(this.images, 'SIGN1.url');
if (this.createTemplateForm.status === 'VALID' && _.get(this.createTemplateForm, 'value.allowPermission')
&& logo && sign) {
this.disableCreateTemplate = false;
} else {
this.disableCreateTemplate = true;
}
}
getSVGTemplate() {
this.uploadCertificateService.getSvg(this.selectedCertificate.artifactUrl).then(res => {
const svgFile = res;
this.logoHtml = this.sanitizeHTML(svgFile);
this.refreshEditor.next({});
this.previewCertificate();
});
}
ngOnDestroy() {
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
createCertTemplate() {
this.validateForm();
// TODO: form validation need to improve
if (this.disableCreateTemplate) {
this.createTemplateForm.controls.certificateTitle.markAsTouched();
this.createTemplateForm.controls.stateName.markAsTouched();
this.createTemplateForm.controls.authoritySignature_0.markAsTouched();
this.createTemplateForm.controls.authoritySignature_1.markAsTouched();
this.createTemplateForm.controls.allowPermission.markAsTouched();
} else {
this.previewCertificate();
setTimeout(() => {
const channel = this.userService.channel;
const request = this.certConfigModalInstance.prepareCreateAssetRequest(_.get(this.createTemplateForm, 'value'), channel, this.selectedCertificate, this.images);
this.disableCreateTemplate = true;
this.uploadCertificateService.createCertTemplate(request).subscribe(response => {
const assetId = _.get(response, 'result.identifier');
this.uploadTemplate(this.finalSVGurl, assetId);
}, error => {
this.toasterService.error('Something went wrong, please try again later');
});
}, 1000);
}
}
uploadTemplate(base64Url, identifier) {
this.uploadCertificateService.storeAsset(base64Url, identifier).subscribe(response => {
this.toasterService.success(_.get(this.resourceService, 'frmelmnts.cert.lbl.certAddSuccess'));
const templateIdentifier = {'identifier': _.get(response , 'result.identifier')};
this.uploadCertificateService.certificate.next(templateIdentifier);
this.navigationHelperService.navigateToLastUrl();
}, error => {
this.toasterService.error('Something went wrong, please try again later');
console.log('error', error);
});
}
assetData(data) {
if (data.key === this.optionSing) {
this.createTemplateForm.get('authoritySignature_1').setValidators([Validators.required]);
this.createTemplateForm.get('authoritySignature_1').updateValueAndValidity();
}
this.images[data.key] = data;
this.validateForm();
}
close() {
this.showSelectImageModal = false;
this.showUploadUserModal = false;
}
removeImage(key) {
if (key === 'SIGN2') {
this.createTemplateForm.get('authoritySignature_1').clearValidators();
this.createTemplateForm.get('authoritySignature_1').updateValueAndValidity();
}
this.images[key] = {};
this.validateForm();
}
openSateLogos(type) {
this.logoType = type;
this.showSelectImageModal = true;
this.browseImage.getAssetList();
}
openSignLogos(type) {
this.logoType = type;
this.showSelectImageModal = false;
this.showUploadUserModal = true;
// this.browseImage.getAssetList();
}
chooseCertificate(certificate) {
this.logoHtml = null;
this.selectedCertificate = _.clone(certificate);
this.getSVGTemplate();
}
convertHtml(tag) {
if (tag) {
const html = tag.toString();
return new DOMParser().parseFromString(html, 'text/html');
}
}
previewCertificate() {
this.svgData = this.convertHtml(this.logoHtml);
const stateLogos = this.svgData.getElementsByClassName(this.classNames.STATE_LOGOS);
const digitalSigns = this.classNames.SIGN_LOGO.map(id => this.svgData.getElementById(id));
// this.updateTitles();
this.updateStateLogos(stateLogos);
this.updateSigns(digitalSigns);
}
previewUpdatedSVGCertificate() {
this.svgData = this.convertHtml(this.sanitizeHTML(document.getElementById('templateSvg').innerHTML));
this.certificateCreation(this.svgData.getElementsByTagName('svg')[0]);
}
updateTitles() {
const certTitle = this.svgData.getElementsByClassName(this.classNames.CERT_TITLE);
certTitle[0].innerHTML = this.createTemplateForm.controls.certificateTitle.value;
const stateTitle = this.svgData.getElementsByClassName(this.classNames.STATE_TITLE);
stateTitle[0].innerHTML = this.createTemplateForm.controls.stateName.value;
this.classNames.DESIGNATIONS_NAMES.forEach((id, index) => {
const designation_html = this.svgData.getElementById(id);
if (designation_html) {
const title = this.createTemplateForm.get(`authoritySignature_${index}`).value;
designation_html.innerHTML = title;
}
});
}
updateStateLogos(stateLogos) {
const logosArray = Object.values(this.images).filter(x => !_.isEmpty(x) && x['type'] === 'LOGO');
this.editSVG(logosArray, stateLogos).then(res => {
this.certificateCreation(this.svgData.getElementsByTagName('svg')[0]);
});
}
updateSigns(stateLogos) {
const logosArray = Object.values(this.images).filter(x => !_.isEmpty(x) && x['type'] === 'SIGN');
this.editSVG(logosArray, stateLogos).then(res => {
//this.certificateCreation(this.svgData.getElementsByTagName('svg')[0]);
});
}
editSVG(logosArray, stateLogos) {
return new Promise<void>(async (resolve, reject) => {
for (let i = 0; i < logosArray.length; i++) {
const logo = logosArray[i];
if (logo) {
const res = await this.toDataURL(logo);
if (res && !_.isEmpty(stateLogos) && stateLogos[i]) {
stateLogos[i].setAttribute('xlink:href', res['url']);
}
if (i === (logosArray.length - 1)) {
resolve();
}
}
}
});
}
toDataURL(image) {
return fetch(image.url, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.blob())
.then(blob => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve({ url: reader.result, type: image.type });
reader.onerror = reject;
reader.readAsDataURL(blob);
}));
}
urltoFile(url, filename, mimeType) {
return (fetch(url)
.then((res) => {
return res.arrayBuffer();
})
.then((buf) => {
return new File([buf], filename, {type: mimeType});
})
);
}
certificateCreation(ev) {
const dataURL = this.getBase64Data(ev);
this.selectedCertificate['artifactUrl'] = this.sanitizer.bypassSecurityTrustResourceUrl(dataURL);
this.urltoFile(dataURL, `certificate_${dayjs().format('YYYY-MM-DD_HH_mm')}.svg`, 'image/svg+xml')
.then((file) => {
this.finalSVGurl = file;
});
}
sanitizeHTML(html) {
return this.sanitizer.bypassSecurityTrustHtml(html);
}
getImagePath() {
if (this.selectedCertificate) {
return this.selectedCertificate.artifactUrl;
}
}
getBase64Data(ev) {
const div = document.createElement('div');
div.appendChild(ev.cloneNode(true));
const b64 = 'data:image/svg+xml;base64,' + window.btoa(div.innerHTML);
return b64;
}
back() {
this.uploadCertificateService.certificate.next(null);
this.navigationHelperService.navigateToLastUrl();
}
redoLayout() {
if (this.layoutConfiguration != null) {
this.FIRST_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(0, this.layoutConfiguration, COLUMN_TYPE.threeToNine);
this.SECOND_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(1, this.layoutConfiguration, COLUMN_TYPE.threeToNine);
} else {
this.FIRST_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(0, null, COLUMN_TYPE.fullLayout);
this.SECOND_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(1, null, COLUMN_TYPE.fullLayout);
}
}
elementClicked(e: any) {
this.selectedSVGObject = {
type: _.get(e, 'type'),
value: _.get(e, 'element.textContent'),
element: e.element
};
if (e.type === 'image') {
this.logoType = {type: 'LOGO', index: 0, key:'LOGO1'};
this.browseImage.getAssetList();
}
this.showSVGInputModal = true;
}
updateSVGInputTag() {
this.showSVGInputModal = false;
this.edit.next({
element: this.selectedSVGObject.element,
type: 'text',
value: this.selectedSVGObject.value
});
this.selectedSVGObject = {};
}
closeSVGInputModal() {
this.showSVGInputModal = false;
}
svgAssetData(imageObj) {
this.getBase64FromUrl(_.get(imageObj, 'url')).then((base64String: string) => {
this.showSVGInputModal = false;
this.edit.next({
element: this.selectedSVGObject.element,
type: 'image',
value: base64String
});
this.selectedSVGObject = {};
});
}
getBase64FromUrl = async (url) => {
const data = await fetch(url);
const blob = await data.blob();
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => {
const base64data = reader.result;
resolve(base64data);
}
});
}
toggleSVGPreview() {
this.previewButton = this.previewButton == 'show' ? 'hide' : 'show';
this.togglePreview.next(this.previewButton);
}
saveUpdatedCertificate() {
const certificateCodeName = _.get(this.queryParams, 'courseId') + '_' + _.get(this.queryParams, 'batchId').toString();
this.svgData = null;
this.save.next('');
this.previewUpdatedSVGCertificate();
setTimeout(() => {
const channel = this.userService.channel;
const request = this.certConfigModalInstance.prepareCreateAssetRequest(_.get(this.createTemplateForm, 'value'), channel, this.selectedCertificate, this.images);
request.request.asset.code = certificateCodeName;
request.request.asset.name = certificateCodeName;
this.uploadCertificateService.createCertTemplate(request).subscribe(response => {
const assetId = _.get(response, 'result.identifier');
this.uploadTemplate(this.finalSVGurl, assetId);
}, error => {
this.toasterService.error('Something went wrong, please try again later');
});
}, 1000);
}
previewAndSave() {
this.toggleSVGPreview();
this.saveAndPreview = true;
this.previewSvgData = this.sanitizeHTML(document.getElementById('templateSvg').innerHTML);
}
closeSaveAndPreview() {
this.toggleSVGPreview();
this.saveAndPreview = false;
this.userConsent = false;
}
}
<!-- @since - release-4.7.0 -->
<!-- SVG Editor for Certificate Creation -->
<!-- New Certificate layout -->
<div [ngClass]="layoutConfiguration ? 'sbt-inside-page-container py-16' : ''">
<div class="sb-bg-color-white py-8 relative9 cc-player__content-header cc-player__border-fix">
<div class="ui container">
<div class="d-flex flex-ai-center flex-jc-space-between">
<button (click)="back()" tabindex="0"
class="sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary sb-left-icon-btn mr-auto" id="goBack"
type="button">
<i class="icon-svg icon-svg--xxs icon-back mr-4">
<svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#arrow-long-left"></use>
</svg></i>
{{resourceService?.frmelmnts?.btn?.back}}
</button>
</div>
</div>
</div>
<div class="certificate-container relative9">
<div class="ui container">
<div class='sb-g mt-16'>
<div class="sb-g-col-xs-12 sb-g-col-md-3 sb-g-col-lg-3 sb-g-col-xxxl-12">
<div class="certificate-content">
<label class="fmedium my-8">{{resourceService?.frmelmnts?.cert?.lbl?.layout}}</label>
<div class="mt-16">
<div *ngFor="let certificate of defaultCertificates" class="cert-img-sb-card"
[ngClass]="selectedCertificate?.identifier === certificate?.identifier ? 'active' : ''">
<div class="cert-img-sb-card__content d-flex flex-ai-center flex-jc-center" alt="certificate template">
<img (click)="chooseCertificate(certificate)" tabindex="0" [src]="certificate?.artifactUrl"
alt="certificate template" />
</div>
</div>
</div>
</div>
</div>
<div class="sb-g-col-xs-12 sb-g-col-md-9 sb-g-col-lg-9 sb-g-col-xxxl-12">
<div>
<div class="d-flex flex-ai-center">
<i class="icon-svg icon-svg--md icon-back mr-16">
<svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#question_on_play"></use>
</svg></i>
<label class="preview-title mb-0 mr-auto">{{resourceService?.frmelmnts?.lbl?.editCertificateTitle}}</label>
<button type="button" (click)="back()" tabindex="0" class="sb-btn sb-btn-normal sb-btn-outline-primary">{{resourceService?.frmelmnts?.btn?.cancel}}</button>
<!-- <button type="button" (click)="saveUpdatedCertificate()" tabindex="0"
class="sb-btn sb-btn-normal sb-btn-primary ml-16">{{resourceService?.frmelmnts?.cert?.btn?.saveAsTemplate}}
</button>
<button type="button" *ngIf="previewButton == 'show'" (click)="toggleSVGPreview()" tabindex="0"
class="sb-btn sb-btn-normal sb-btn-primary ml-16">Preview
</button>
<button type="button" *ngIf="previewButton == 'hide'" (click)="toggleSVGPreview()" tabindex="0"
class="sb-btn sb-btn-normal sb-btn-primary ml-16">Edit
</button> -->
<button type="button" (click)="previewAndSave()" tabindex="0"
class="sb-btn sb-btn-normal sb-btn-primary ml-16">{{resourceService?.frmelmnts?.lbl?.saveAndPreview}}</button>
</div>
<div class="cert-select-card my-16">
<div class="d-flex flex-ai-center flex-dc cert-select-card__content">
<div class="d-flex flex-ai-center flex-jc-center cert-select-card__content__description">
<div class="svgContainer">
<!-- <svg-editor [svgContent]="logoHtml" [save]="save" [togglePreview]="togglePreview"
[edit]="edit" (elementClicked)="elementClicked($event)" [refreshEditor]="refreshEditor"></svg-editor> -->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<app-modal-wrapper *ngIf="showSVGInputModal && showPreviewButton && selectedSVGObject?.type === 'text'" [config]="{disableClose: true, size: 'small'}" (dismiss)="closeSVGInputModal()">
<ng-template sbModalContent>
<div class="sb-modal sb-error">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal transition active visible small">
<button aria-label="close dialog" mat-dialog-close class="mat-close-btn">
<span>×</span>
</button>
<!--Header-->
<div class="sb-modal-header">
{{resourceService?.frmelmnts?.lbl?.updateDetails}}
</div>
<!--/Header-->
<!--Content-->
<div class="sb-modal-content">
<div class="image-tabs px-8">
<!-- Text update -->
<section *ngIf="selectedSVGObject?.type === 'text'" id="content1">
<div class="twelve wide column">
<div class="sb-search-box m-0">
<div class="input-div relative">
<input autofocus class="sb-search-input" [(ngModel)]="selectedSVGObject.value" type="text" maxlength="80" />
</div>
</div>
<small _ngcontent-nit-c26="" class="pl-4 fsmall">
{{80 - selectedSVGObject.value.length}} / 80 {{resourceService?.frmelmnts?.lbl?.characterleft}}
</small>
</div>
</section>
</div>
</div>
<!--/Content-->
<!--Actions-->
<div class="sb-modal-actions">
<button class="sb-btn sb-btn-normal sb-btn-primary" tabindex="0" (click)="updateSVGInputTag()">{{resourceService?.frmelmnts?.btn?.update}}</button>
<button class="sb-btn sb-btn-normal sb-btn-outline-primary" tabindex="0" (click)="closeSVGInputModal()">
{{resourceService.frmelmnts?.btn?.cancel}}
</button>
</div>
<!--/Actions-->
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
<browse-image-popup [enableUploadSignature]="true" (assetData)="svgAssetData($event)" (close)="closeSVGInputModal()" [showUploadUserModal]="disableSVGImageModal" [showSelectImageModal]="showSVGInputModal && showPreviewButton && selectedSVGObject?.type === 'image'" [logoType]="logoType" ></browse-image-popup>
<app-modal-wrapper [config]="{disableClose: true, size: 'large'}" (dismiss)="closeSaveAndPreview()" *ngIf="saveAndPreview">
<ng-template sbModalContent>
<div class="sb-modal sb-error">
<div class="transition ui dimmer page modals active visible">
<div class="ui modal sb-bg-color-white transition active visible large">
<button aria-label="close dialog" mat-dialog-close class="mat-close-btn">
<span>×</span>
</button>
<!--Header-->
<div class="sb-modal-header sb-bg-color-white ">
{{resourceService?.frmelmnts?.lbl?.certPreview}}
</div>
<!--/Header-->
<!--Content-->
<div class="sb-modal-content sb-bg-color-white ">
<div class="image-tabs px-8">
<div [innerHTML]="previewSvgData"></div>
</div>
</div>
<!--/Content-->
<!--Actions-->
<div class="sb-modal-actions sb-bg-color-white ">
<div class='ui stackable d-flex flex-jc-space-between mt-0'>
<!-- <div class="twelve wide column"> -->
<div class="">
<div class="sb-checkbox sb-checkbox-secondary pt-24">
<input [checked]="userConsent" (change)="userConsent = !userConsent" value="true" type="checkbox" id="check2" name="selected">
<label for="check2" class="text-left fsmall">{{resourceService?.frmelmnts?.cert?.intxt?.confrmtion}}</label>
</div>
</div>
<div class="">
<button [disabled]="!userConsent" [ngClass]="{'sb-btn-disabled': !userConsent }" class="sb-btn sb-btn-normal sb-btn-primary" tabindex="0" (click)="saveUpdatedCertificate()">{{resourceService?.frmelmnts?.cert?.btn?.saveAsTemplate}}</button>
</div>
<!-- </div> -->
</div>
</div>
<!--/Actions-->
</div>
</div>
</div>
</ng-template>
</app-modal-wrapper>
./svg-editor.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.certificate-content {
height: 100%;
}
.cert-img-sb-card {
width: 100%;
height: auto;
background-color: var(--white);
border: calculateRem(2px) solid var(--gray-200);
border-radius: .25rem;
cursor: pointer;
position: relative;
overflow: hidden;
margin-bottom: calculateRem(16px);
transition: all 0.3s ease-out;
&:last-child {
margin-bottom: 0;
}
&.active {
.selected-mark {
position: absolute;
right: calculateRem(4px);
top: 0;
display: block;
}
}
&.active,
&:hover {
border: calculateRem(2px) solid var(--primary-color);
}
&__content {
padding: 0.5rem;
overflow: hidden;
position: relative;
.selected-mark {
display: none;
}
img {
width: 100%;
height: 100%;
}
}
}
.select-template-content {
background: var(--white);
height: 100%;
}
.cert-select-card {
width: 100%;
border-radius: 0.5rem;
cursor: pointer;
&__content {
height: 100%;
background: var(--white);
&__description {
width: 100%;
text-align: center;
border-style: dashed;
border-color: var(--gray-100);
.title {
font-size: 1.125rem;
color: var(--gray-100);
}
}
}
}
.cert-select-image {
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
border: calculateRem(1px) solid;
margin-bottom: calculateRem(16px);
}
}
.cert-view-image {
width: 100%;
height: 100%;
img {
width: 100%;
height: 100%;
border: calculateRem(1px) solid;
}
}
.asterik {
color: var(--red-400);
}
.preview-title {
font-size: calculateRem(20px);
}
.state-labels {
color: var(--gray-800);
}
.list-border {
border-bottom: calculateRem(1px) solid var(--gray-200);
}
.sb-browse-btn {
position: relative;
overflow: hidden;
margin-top: calculateRem(3px);
cursor: pointer;
border-radius: calculateRem(24px);
border: calculateRem(2px) solid var(--primary-300);
color: var(--primary-300);
font-weight: bold;
background: var(--primary-100);
}
.svgContainer {
width: 100%;
height: 100%;
}