Delete submission - backup directory

This commit is contained in:
Teddy-1024
2024-09-17 09:16:22 +01:00
committed by GitHub
parent 40a8406427
commit fa7f1b35ee
12 changed files with 0 additions and 1727 deletions

View File

@@ -1,72 +0,0 @@
# Screen Capture and Image Annotation Project
This project provides two main functionalities:
1. Screen Capture: A pluggable web control to capture the current browser viewport.
2. Image Annotation: A tool to annotate PNG images with arrows, textboxes, and symbols.
## Features
### Screen Capture
- Capture the current browser viewport as a PNG image.
- Exclude sensitive information from inputs and textareas.
- Capture modals and floating elements.
- Save the captured image as a PNG file.
### Image Annotation
- Upload and display PNG images.
- Add arrows, textboxes, and symbols to the image.
- Erase annotated elements.
- Save the annotated image as a Base64 PNG string.
## Installation
1. Clone the repository:
```
git clone https://github.com/your-username/screen-capture-annotation-project.git
```
## Usage
### Screen Capture
Include the necessary files in your HTML:
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script src="plugin_capture_screen.js"></script>
<link rel="stylesheet" href="capture-screen.css">
```
Initialize the plugin on a button:
```javascript
$('.capture-screen').screenshotButton();
```
### Image Annotation
Include the necessary files in your HTML:
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="plugin_display_png.js"></script>
<link rel="stylesheet" href="display-png.css">
```
Initialize the plugin on a container:
```javascript
$('.annotator-png').annotatorPNG();
```
## Testing
To run the tests:
1. Open the test views in your browser.
## Known bugs
- Colour picker button must be clicked to set colour of active canvas object after selecting colour

View File

@@ -1,101 +0,0 @@
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
}
header {
background-color: #333;
color: white;
padding: 1rem;
text-align: center;
}
.content-wrapper {
display: flex;
flex: 1;
}
main {
flex: 3;
padding: 1rem;
}
/* Widgets */
.modal {
position: fixed;
background-color: #f0f0f0;
border: 1px solid #ccc;
border-radius: 5px;
padding: 10px;
/*
display: none;
*/
}
.widget-toggle {
position: fixed;
padding: 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
#notification-widget {
top: 100px;
right: 20px;
width: 250px;
}
#notification-toggle {
top: 100px;
right: 20px;
}
#chat-widget {
bottom: 20px;
right: 20px;
width: 300px;
height: 400px;
}
#chat-toggle {
bottom: 20px;
right: 20px;
}
#settings-widget {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 200px;
}
#settings-toggle {
top: 20px;
left: 20px;
}
.modal:target {
display: block;
}
.is-hidden {
display: none;
}
/* Testing */
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.4);
}
.modal-content {
background-color: #fefefe;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
}

View File

@@ -1,15 +0,0 @@
.annotator-png-container-annotation {
position: relative;
border: 1px solid #ccc;
margin: 20px auto;
}
.annotator-png-canvas-annotation {
border: 1px solid #ccc;
}
.annotator-png-toolbox {
margin-bottom: 10px;
}
button {
margin-right: 5px;
}

View File

@@ -1,152 +0,0 @@
(function($) {
$.fn.screenshotButton = function(options) {
var settings = $.extend({
buttonText: 'Capture Screen',
fileName: 'screenshot.png',
modalsSelector: '.modal, .popup, .overlay, .dialog, .tooltip, [class*="modal"], [class*="popup"], [class*="overlay"], [class*="dialog"], [class*="tooltip"], [style*="position: fixed"], [style*="position: absolute"], [style*="z-index"]',
}, options);
function exportToBase64String(canvas) {
const dataURL = canvas.toDataURL({
format: 'png',
quality: 1
});
console.log("Base64 string:", dataURL);
return dataURL;
// alert("Image saved as Base64 string. Check the console and Downloads folder for the output.");
}
function exportToBlob(canvas) {
canvas.toBlob(function(blob) {
var url = URL.createObjectURL(blob);
console.log("blob: ", blob);
return url;
});
}
function downloadPNG(url) {
var a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = settings.fileName;
console.log("adding button a: ", a);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
return this.each(function() {
var $button = $(this);
$button.text(settings.buttonText);
$button.removeClass(flagIsHidden);
$button.attr('aria-label', settings.buttonText);
if (!$button.hasClass(flagInitialised)) {
$button.addClass(flagInitialised);
$button.on('click', function() {
if (typeof html2canvas === 'undefined') {
console.error('html2canvas is not loaded. Please include the library.');
return;
}
// Hide button and sensitive information in inputs
// $button.hide();
$button.addClass(flagIsHidden);
$('input').each(function() {
$(this).attr("previousValue", $(this).val());
$(this).val('');
});
$('textarea').each(function() {
$(this).attr("previousValue", $(this).val());
$(this).val('');
});
// set display: block on element for all visible modals and floating elements
// elements not detected by html2canvas with cascaded class-based display style
$(settings.modalsSelector).each(function() {
$(this).css('display', $(this).css('display'));
});
html2canvas(document.body, {
logging: true,
useCORS: true,
allowTaint: true,
}).then(function(canvas) {
let url = exportToBase64String(canvas);
// exportToBlob(canvas);
downloadPNG(url);
URL.revokeObjectURL(url);
// Show button and sensitive information in inputs
// $button.show();
$button.removeClass(flagIsHidden);
$('input').each(function() {
$(this).val($(this).attr("previousValue"));
});
$('textarea').each(function() {
$(this).val($(this).attr("previousValue"));
});
}).catch(function(e) {
console.error(e);
});
});
}
});
};
}(jQuery));
function hookupTestModals() {
let $buttonToggleModalChat = $(idButtonToggleModalChat);
let $modalChat = $(idModalChat);
let $buttonToggleModalNotifications = $(idButtonToggleModalNotifications);
let $modalNotifications = $(idModalNotifications);
let $buttonToggleModalSettings = $(idButtonToggleModalSettings);
let $modalSettings = $(idModalSettings);
if (!$buttonToggleModalChat.hasClass(flagInitialised)) {
$buttonToggleModalChat.addClass(flagInitialised);
$buttonToggleModalChat.on('click', function() {
if ($modalChat.hasClass(flagIsHidden)) {
$modalChat.removeClass(flagIsHidden);
} else {
$modalChat.addClass(flagIsHidden);
}
});
}
if (!$modalChat.hasClass(flagInitialised)) {
$modalChat.addClass(flagInitialised);
$modalChat.addClass(flagIsHidden);
}
if (!$buttonToggleModalNotifications.hasClass(flagInitialised)) {
$buttonToggleModalNotifications.addClass(flagInitialised);
$buttonToggleModalNotifications.on('click', function() {
if ($modalNotifications.hasClass(flagIsHidden)) {
$modalNotifications.removeClass(flagIsHidden);
} else {
$modalNotifications.addClass(flagIsHidden);
}
});
}
if (!$modalNotifications.hasClass(flagInitialised)) {
$modalNotifications.addClass(flagInitialised);
$modalNotifications.addClass(flagIsHidden);
}
if (!$buttonToggleModalSettings.hasClass(flagInitialised)) {
$buttonToggleModalSettings.addClass(flagInitialised);
$buttonToggleModalSettings.on('click', function() {
if ($modalSettings.hasClass(flagIsHidden)) {
$modalSettings.removeClass(flagIsHidden);
} else {
$modalSettings.addClass(flagIsHidden);
}
});
}
if (!$modalSettings.hasClass(flagInitialised)) {
$modalSettings.addClass(flagInitialised);
$modalSettings.addClass(flagIsHidden);
}
}

View File

@@ -1,274 +0,0 @@
(function($) {
$.fn.annotatorPNG = function(options) {
var settings = $.extend({
heightCanvas: "600px",
widthCanvas: "800px",
textButtonSave: "Save Image",
}, options);
function getCanvas() {
let $annotatorPNG = $(document).find("." + flagAnnotatorPNG);
let $canvasAnnotation = $($annotatorPNG.find("canvas." + flagCanvasAnnotation)[0]);
let canvas = $canvasAnnotation.data(keyFabric);
return canvas;
}
function deleteSelectedObjects() {
let canvas = getCanvas();
const activeObject = canvas.getActiveObject();
if (activeObject) {
console.log("active object type:", activeObject.type);
if (activeObject.type === 'activeSelection') {
activeObject.forEachObject(function(obj) {
canvas.remove(obj);
});
canvas.discardActiveObject();
} else {
canvas.remove(activeObject);
}
canvas.requestRenderAll();
}
}
return this.each(function() {
let $annotatorPNG = $(this);
let $toolbox = $annotatorPNG.find("." + flagToolbox);
let $inputUploadImage = $toolbox.find("." + flagUploadImage);
let $buttonAddArrow = $toolbox.find("." + flagAddArrow);
let $buttonAddTextbox = $toolbox.find("." + flagAddTextbox);
let $selectAddSymbol = $toolbox.find("." + flagAddSymbol);
let $inputColourPicker = $toolbox.find("." + flagColourPicker);
let $buttonEraseMode = $toolbox.find("." + flagEraseMode);
let $buttonSaveImage = $toolbox.find("." + flagSaveImage);
let $containerAnnotation = $annotatorPNG.find("." + flagContainerAnnotation);
let $canvasAnnotation = $containerAnnotation.find("." + flagCanvasAnnotation);
// Default values
$inputUploadImage.val('');
const symbols = ['Orange Arrow.png'];
symbols.forEach(symbol => {
$selectAddSymbol.append($("<option>", {
value: symbol,
text: symbol.replace('.png', ''),
}));
});
$inputColourPicker.val('#ff0000');
$buttonEraseMode.textContent = "Erase Mode";
$annotatorPNG.data(keyIsEraseMode, false);
$buttonSaveImage.text(settings.textButtonSave);
$canvasAnnotation.css({
height: settings.heightCanvas,
width: settings.widthCanvas,
});
console.log("canvas: ", $canvasAnnotation[0]);
var canvas = new fabric.Canvas($canvasAnnotation[0], {
// containerClass: flagContainerAnnotation,
});
canvas.clear();
canvas.selection = true;
$canvasAnnotation.data(keyFabric, canvas);
// Triggers
if (!$inputUploadImage.hasClass(flagInitialised)) {
$inputUploadImage.addClass(flagInitialised);
$inputUploadImage.on("change", function(event) {
console.log("File uploaded:", event.target.files[0]);
const file = event.target.files[0];
if (!file) {
return;
}
if (!(file.type == 'image/png')) {
alert("Please upload a PNG file.");
throw new Error("Invalid file type.");
return;
}
const reader = new FileReader();
let canvas = getCanvas();
reader.onload = function(eventReader) {
fabric.Image.fromURL(eventReader.target.result, function(image) {
canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas), {
scaleX: settings.widthCanvas.replace('px', '') / image.width,
scaleY: settings.heightCanvas.replace('px', '') / image.height,
});
});
};
reader.readAsDataURL(file);
});
}
if (!$buttonAddArrow.hasClass(flagInitialised)) {
$buttonAddArrow.addClass(flagInitialised);
$buttonAddArrow.on("click", function() {
console.log("Add Arrow clicked");
let canvas = getCanvas();
const arrow = new fabric.Path('M 0 0 L 200 100', {
fill: $inputColourPicker.val(),
stroke: $inputColourPicker.val(),
strokeWidth: 2,
left: 100,
top: 100,
selectable: true,
});
canvas.add(arrow);
canvas.renderAll();
});
}
if (!$buttonAddTextbox.hasClass(flagInitialised)) {
$buttonAddTextbox.addClass(flagInitialised);
$buttonAddTextbox.on("click", function() {
console.log("Add Textbox clicked");
let canvas = getCanvas();
const textbox = new fabric.Textbox('Type here', {
left: 100,
top: 100,
width: 150,
fontSize: 20,
fill: $inputColourPicker.val(),
selectable: true,
});
canvas.add(textbox);
canvas.renderAll();
});
}
if (!$selectAddSymbol.hasClass(flagInitialised)) {
$selectAddSymbol.addClass(flagInitialised);
$selectAddSymbol.on("change", function() {
console.log("Add Symbol changed:", this.value);
if (this.value) {
let canvas = getCanvas();
fabric.Image.fromURL(`symbols/${this.value}`, function(image) {
image.set({
left: 100,
top: 100,
scaleX: 0.5,
scaleY: 0.5,
});
canvas.add(image);
});
this.value = '';
}
});
}
if (!$inputColourPicker.hasClass(flagInitialised)) {
$inputColourPicker.addClass(flagInitialised);
$inputColourPicker.on("change", function() {
console.log("Colour Picker changed:", this.value);
let canvas = getCanvas();
canvas.renderAll();
const activeObject = canvas.getActiveObject();
if (activeObject) {
if (activeObject.type === 'textbox') {
activeObject.set('fill', this.value);
} else {
activeObject.set('fill', this.value);
activeObject.set('stroke', this.value);
}
canvas.renderAll();
}
});
}
if (!$buttonEraseMode.hasClass(flagInitialised)) {
$buttonEraseMode.addClass(flagInitialised);
$buttonEraseMode.data(keyIsEraseMode, false);
$buttonEraseMode.on("click", function() {
console.log("Erase Mode clicked");
let isEraseMode = $annotatorPNG.data(keyIsEraseMode);
isEraseMode = !isEraseMode;
$annotatorPNG.data(keyIsEraseMode, isEraseMode);
console.log("Erase Mode:", isEraseMode);
this.textContent = isEraseMode ? 'Exit Erase Mode' : 'Erase Mode';
if (isEraseMode) {
deleteSelectedObjects();
canvas.selection = false;
canvas.isDrawingMode = false;
canvas.defaultCursor = 'crosshair';
canvas.hoverCursor = 'crosshair';
} else {
canvas.selection = true;
canvas.defaultCursor = 'default';
canvas.hoverCursor = 'move';
}
});
}
if (!$canvasAnnotation.hasClass(flagInitialised)) {
$canvasAnnotation.addClass(flagInitialised);
// Object selection in erase mode
$canvasAnnotation.on('selection:created', function() {
console.log("Selection created");
let isEraseMode = $annotatorPNG.data(keyIsEraseMode);
if (isEraseMode) {
deleteSelectedObjects();
}
});
// Object click in erase mode
$canvasAnnotation.on('mouse:down', function(event) {
console.log("Canvas mouse down:", event);
let isEraseMode = $annotatorPNG.data(keyIsEraseMode);
if (isEraseMode && event.target) {
let canvas = getCanvas();
canvas.remove(event.target);
canvas.requestRenderAll();
}
});
// Prevent dragging in erase mode
$canvasAnnotation.on('object:moving', function(event) {
console.log("Canvas object moving:", event);
let isEraseMode = $annotatorPNG.data(keyIsEraseMode);
if (isEraseMode) {
let canvas = getCanvas();
event.target.setCoords();
canvas.remove(event.target);
canvas.requestRenderAll();
}
});
}
if (!$buttonSaveImage.hasClass(flagInitialised)) {
$buttonSaveImage.addClass(flagInitialised);
$buttonSaveImage.on("click", function() {
let canvas = getCanvas();
if (window.confirm("Please ensure there is no sensitive information or PII in your annotations. Do you want to proceed with saving?")) {
const dataURL = canvas.toDataURL({
format: 'png',
quality: 1
});
// Output
console.log("Base64 string:", dataURL);
let a = document.createElement('a');
a.style.display = 'none';
a.href = dataURL;
a.download = settings.fileName;
/* Download image
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
*/
alert("Image saved as Base64 string. Check the console for the output.");
}
});
}
});
};
}(jQuery));

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -1,13 +0,0 @@
var flagInitialised = "initialised";
var flagIsHidden = "is-hidden";
var flagIsVisible = "is-visible";
async function waitForClick($element) {
return new Promise((resolve) => {
$element.on('click', function() {
resolve();
});
$element.click();
});
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -1,527 +0,0 @@
describe('Screen Capture Plugin', function() {
var $button, sandbox, originalBodyHTML;
beforeEach(function() {
originalBodyHTML = document.body.innerHTML;
$button = $('.' + flagCaptureScreen);
$button.screenshotButton(defaultOptions);
sandbox = sinon.createSandbox();
});
afterEach(function() {
sandbox.restore();
$button.screenshotButton(defaultOptions);
setTimeout(() => {}, 2000);
});
after(function() {
document.body.innerHTML = originalBodyHTML;
});
describe('1. Initialization and Setup', function() {
afterEach(function() {
setTimeout(() => {}, 2000);
});
it('a. Should initialize correctly on a given DOM element', function() {
expect($button).to.exist;
});
it('b. Should create the button with correct text', function() {
expect($button.text()).to.equal('Capture Screen');
});
it('c. Should make the button visible on the page', function() {
expect($button.is(':visible')).to.be.true;
});
});
describe('2. Button Functionality', function() {
afterEach(function() {
setTimeout(() => {}, 2000);
});
it('a. Should trigger screenshot process on click', function() {
sinon.stub(window, 'html2canvas').resolves(document.createElement('canvas'));
return waitForClick($button)
.then(() => {
expect(html2canvas.called).to.be.true;
expect(html2canvas.callCount).to.equal(1);
html2canvas.restore();
});
});
it('b. Should hide button during screenshot process', function(done) {
sinon.stub(window, 'html2canvas').resolves(document.createElement('canvas'));
$button.click();
expect($button.hasClass(flagIsHidden)).to.be.true;
html2canvas.restore();
done();
}
);
it('c. Should show button after screenshot is taken', function() {
sinon.stub(window, 'html2canvas').resolves(document.createElement('canvas'));
return waitForClick($button)
.then(() => {
expect($button.hasClass(flagIsHidden)).to.be.false;
html2canvas.restore();
});
});
});
describe('3. Input Handling', function() {
let $input, $textarea;
beforeEach(function() {
$input = $('<input type="text" value="test">').appendTo('body');
$textarea = $('<textarea>test</textarea>').appendTo('body');
});
afterEach(function() {
$input.remove();
$textarea.remove();
setTimeout(() => {}, 2000);
});
it('a. Should clear input and textarea values during screenshot', function(done) {
sinon.stub(window, 'html2canvas').resolves(document.createElement('canvas'));
$button.click();
expect($input.val()).to.equal('');
expect($textarea.val()).to.equal('');
html2canvas.restore();
done();
});
it('b. Should restore input and textarea values after screenshot', function() {
sinon.stub(window, 'html2canvas').resolves(document.createElement('canvas'));
return waitForClick($button)
.then(() => {
expect($input.val()).to.equal('test');
expect($textarea.val()).to.equal('test');
html2canvas.restore();
});
});
});
describe('4. Modal and Floating Element Handling', function() {
let $modal;
beforeEach(function() {
$modal = $('<div class="modal">Modal Content</div>').appendTo('body');
});
afterEach(function() {
$modal.remove();
setTimeout(() => {}, 2000);
});
it('a. Should capture visible modals', function(done) {
sinon.stub(window, 'html2canvas').callsFake(function(element) {
expect($(element).find('.modal').length).to.equal(5);
return Promise.resolve(document.createElement('canvas'));
});
$button.click();
html2canvas.restore();
done();
});
});
describe('5. HTML2Canvas Integration', function() {
let html2canvasStub, consoleErrorStub;
afterEach(function() {
if (html2canvasStub && html2canvasStub.restore) {
html2canvasStub.restore();
}
if (consoleErrorStub && consoleErrorStub.restore) {
consoleErrorStub.restore();
}
});
it('a. Should call html2canvas with correct parameters', function() {
html2canvasStub = sinon.stub(window, 'html2canvas').resolves(document.createElement('canvas'));
return waitForClick($button)
.then(() => {
expect(html2canvasStub.calledWith(document.body)).to.be.true;
});
});
it('b. Should handle html2canvas errors gracefully', function() {
html2canvasStub = sinon.stub(window, 'html2canvas').rejects(new Error('Test error'));
consoleErrorStub = sinon.stub(console, 'error');
return waitForClick($button)
.then(() => {
expect(consoleErrorStub.called).to.be.true;
expect(consoleErrorStub.firstCall.args[0]).to.be.an('error');
expect(consoleErrorStub.firstCall.args[0].message).to.equal('Test error');
});
});
});
describe('6. Screenshot Generation', function() {
afterEach(function() {
setTimeout(() => {}, 2000);
});
/* Base64 string used instead of Blob
it('a. Should create a blob from the canvas', function(done) {
const canvas = document.createElement('canvas');
sinon.stub(window, 'html2canvas').resolves(canvas);
sinon.stub(canvas, 'toBlob').callsArgWith(0, new Blob());
$button.click();
html2canvas.restore();
expect(canvas.toBlob.called).to.be.true;
canvas.toBlob.restore();
});
*/
it('b. Should generate a Base64 PNG string when saving is confirmed', function(done) {
const consoleStub = sinon.stub(console, 'log');
$button.click();
setTimeout(() => {
expect(consoleStub.callCount).to.equal(2);
const base64String = consoleStub.getCall(0).args[1];
expect(base64String).to.be.a('string');
expect(base64String).to.match(/^data:image\/png;base64,/);
consoleStub.restore();
done();
}, 1000);
});
});
describe('7. Download Functionality', function() {
let createElementStub, appendChildStub, removeChildStub, html2canvasStub;
let originalJQuery, jQueryStub, eachStub, originalCreateElement;
beforeEach(function() {
originalJQuery = window.$;
originalCreateElement = document.createElement;
jQueryStub = sinon.stub();
eachStub = sinon.stub();
jQueryStub.returns({
each: eachStub,
attr: sinon.stub(),
val: sinon.stub(),
addClass: sinon.stub(),
removeClass: sinon.stub()
});
window.$ = jQueryStub;
html2canvasStub = sinon.stub(window, 'html2canvas').resolves(document.createElement('canvas'));
createElementStub = sinon.stub(document, 'createElement').callsFake(function(tagName) {
if (tagName === 'a') {
return {
style: {},
href: '',
download: '',
click: sinon.spy(),
textContent: ''
};
}
return originalCreateElement.call(document, tagName);
});
appendChildStub = sinon.stub(document.body, 'appendChild');
removeChildStub = sinon.stub(document.body, 'removeChild');
sinon.stub(URL, 'createObjectURL').returns('blob:http://example.com/test');
sinon.stub(URL, 'revokeObjectURL');
});
afterEach(function() {
sinon.restore();
window.$ = originalJQuery;
document.createElement = originalCreateElement;
});
it('a. Should create a temporary anchor element for download', function() {
return waitForClick($button)
.then(() => {
expect(html2canvasStub.calledWith(document.body)).to.be.true;
expect(createElementStub.calledWith('a')).to.be.true;
expect(appendChildStub.calledOnce).to.be.true;
expect(removeChildStub.calledOnce).to.be.true;
const aElement = appendChildStub.getCall(0).args[0];
expect(aElement.href).to.include('data:image/png;base64');
expect(aElement.download).to.equal('screenshot.png');
});
});
it('b. Should click the temporary anchor element programmatically', function() {
return waitForClick($button)
.then(() => {
console.log("createElementStub: ", createElementStub, createElementStub.calledOnce);
expect(createElementStub.calledOnce).to.be.true;
});
});
it('c. Should remove the temporary anchor after download', function(done) {
$button.click();
setTimeout(() => {
expect(removeChildStub.calledOnce).to.be.true;
done();
}, 1000);
});
});
describe('8. Cross-browser Compatibility', function() {
it('a. Should work in Chrome-like environments', function() {
// Assuming we're running tests in a Chrome-like environment
expect(() => $button.screenshotButton()).to.not.throw();
});
// Additional browser-specific tests would go here
// These might need to be run in different environments or with browser mocks
});
describe('9. Performance', function() {
it('a. Should capture and generate screenshot within acceptable time', function(done) {
this.timeout(5000);
const startTime = performance.now();
$button.click();
const endTime = performance.now();
const duration = endTime - startTime;
expect(duration).to.be.below(1000);
done();
});
});
describe('10. Error Handling', function() {
var html2canvasStub, consoleErrorStub;
beforeEach(function() {
consoleErrorStub = sandbox.stub(console, 'error');
setTimeout(() => {}, 2000);
});
afterEach(function() {
if (html2canvasStub && html2canvasStub.restore) {
html2canvasStub.restore();
}
if (consoleErrorStub && consoleErrorStub.restore) {
consoleErrorStub.restore();
}
});
it('a. Should log error when html2canvas is not loaded', function(done) {
const originalHtml2Canvas = window.html2canvas;
delete window.html2canvas;
$button.click();
expect(consoleErrorStub.calledOnce).to.be.true;
expect(consoleErrorStub.args[0][0]).to.include('html2canvas is not loaded');
window.html2canvas = originalHtml2Canvas;
done();
});
it('b. Should handle errors during capture process', function() {
let errorName = 'Capture failed';
html2canvasStub = sinon.stub(window, 'html2canvas').rejects(new Error(errorName));
return waitForClick($button)
.then(() => {
expect(consoleErrorStub.called).to.be.true;
expect(consoleErrorStub.firstCall.args[0]).to.be.an('error');
expect(consoleErrorStub.firstCall.args[0].message).to.equal(errorName);
});
});
});
describe('11. Configuration Options', function() {
beforeEach(function() {
});
afterEach(function() {
sinon.restore();
setTimeout(() => {}, 2000);
});
it('a. Should apply custom button text correctly', function() {
const customText = 'Custom Capture Screen';
$button.screenshotButton({ buttonText: customText });
expect($button.text()).to.equal(customText);
});
it('b. Should use custom filename for the downloaded image', function(done) {
console.log("11.b");
this.timeout(5000);
const customFileName = 'custom-screenshot.png';
$button.screenshotButton({ fileName: customFileName });
const consoleStub = sinon.stub(console, 'log');
$button.click();
setTimeout(() => {
console.log("consoleStub: ", consoleStub);
try {
expect(consoleStub.callCount).to.equal(2);
const call = consoleStub.getCall(1);
console.log("call: ", call);
const a = call.args[1];
console.log("a: ", a);
// expect(consoleLogStub.calledWith("adding button a: ", customFileName)).to.be.true;
} catch (e) {
console.log("error: ", e);
}
consoleStub.restore();
done();
}, 1000);
});
});
describe('12. Accessibility', function() {
it('a. Should have appropriate ARIA attributes', function() {
expect($button.attr('role')).to.equal('button');
expect($button.attr('aria-label')).to.equal(defaultOptions.buttonText);
});
it('b. Should be keyboard accessible', function(done) {
$button.on('keydown', function(e) {
if (e.which === 13) { // Enter key
done();
}
});
const event = new KeyboardEvent('keydown', { 'keyCode': 13 });
$button[0].dispatchEvent(event);
});
});
describe('13. Security', function() {
const inputValue = 'sensitive-info';
const textareaValue = 'confidential-data';
const idInput = 'testInput1';
const idTextarea = 'testInput2';
afterEach(function() {
setTimeout(() => {}, 2000);
});
it('a. Should not capture sensitive information in inputs and textareas', function(done) {
$('<input id="' + idInput + '" type="text" value="' + inputValue + '">').appendTo('body');
$('<textarea id="' + idTextarea + '">' + textareaValue + '</textarea>').appendTo('body');
$button.click();
const inputs = document.querySelectorAll('input, textarea');
inputs.forEach(input => {
expect(input.value).to.be.empty;
});
$('#' + idInput).remove();
$('#' + idTextarea).remove();
done();
});
it('b. Should restore input and textarea values after capture', function() {
$('#' + idInput).remove();
$('#' + idTextarea).remove();
$('<input id="' + idInput + '" type="text" value="' + inputValue + '">').appendTo('body');
$('<textarea id="' + idTextarea + '">' + textareaValue + '</textarea>').appendTo('body');
return waitForClick($button)
.then(() => {
setTimeout(() => {
let $input = $('#' + idInput);
let $textarea = $('#' + idTextarea);
expect($input.val()).to.equal(inputValue);
expect($textarea.val()).to.equal(textareaValue);
$input.remove();
$textarea.remove();
}, 2000);
});
});
});
describe('14. CSS Interaction', function() {
it('a. Should not break existing page styles', function() {
const originalStyles = getComputedStyle(document.body);
const newStyles = getComputedStyle(document.body);
expect(originalStyles.cssText).to.equal(newStyles.cssText);
});
it('b. Should apply correct button styling', function() {
const buttonStyles = getComputedStyle($button[0]);
expect(buttonStyles.display).to.not.equal('none');
// Add more specific style checks as per your plugin's CSS
});
});
describe('15. jQuery Plugin Requirements', function() {
it('a. Should return jQuery object for chaining', function() {
const result = $button.screenshotButton();
expect(result).to.equal($button);
});
it('b. Should initialize plugin on multiple elements', function() {
$('body').append('<div class="test-class"></div><div class="test-class"></div>');
$('.test-class').screenshotButton();
expect($('.test-class').length).to.equal(2);
$('.test-class').remove();
});
});
describe('16. Memory Management', function() {
it('a. Should not leak memory on repeated initialization and destruction', function() {
const initialMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
for (let i = 0; i < 500; i++) {
$button.screenshotButton();
$button.empty();
}
const finalMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
expect(finalMemory - initialMemory).to.be.below(1000000); // 1 MB ish
});
it('b. Should remove all created DOM elements after use', function() {
$button.screenshotButton();
const initialChildCount = $button[0].childElementCount;
return waitForClick($button)
.then(() => {
expect($button[0].childElementCount).to.equal(initialChildCount);
});
});
});
describe('17. Responsiveness', function() {
var html2canvasStub;
beforeEach(function() {
setTimeout(() => {}, 2000);
});
afterEach(function() {
if (html2canvasStub && html2canvasStub.restore) {
html2canvasStub.restore();
}
$button.width(100).height(50);
});
it('a. Should behave correctly on different screen sizes', function() {
const viewports = [
{width: 320, height: 568}, // iPhone 5
{width: 1024, height: 768}, // iPad
{width: 1920, height: 1080} // Full HD
];
viewports.forEach(size => {
$button.width(size.width).height(size.height);
$button.screenshotButton();
expect($button.hasClass(flagIsHidden)).to.be.false;
expect($button.width()).to.be.at.most(size.width);
});
});
it('', function() {});
});
});

View File

@@ -1,376 +0,0 @@
describe('Image Annotation Control', function() {
var $annotatorPNG, $toolbox, $inputUploadImage, $buttonAddArrow, $buttonAddTextbox, $selectAddSymbol, $inputColourPicker, $buttonEraseMode, $buttonSaveImage, $containerAnnotation, $canvasAnnotation;
beforeEach(function() {
$annotatorPNG = $(document).find("." + flagAnnotatorPNG);
$annotatorPNG.annotatorPNG(annotatorSettings);
$toolbox = $annotatorPNG.find("." + flagToolbox);
$inputUploadImage = $toolbox.find("." + flagUploadImage);
$buttonAddArrow = $toolbox.find("." + flagAddArrow);
$buttonAddTextbox = $toolbox.find("." + flagAddTextbox);
$selectAddSymbol = $toolbox.find("." + flagAddSymbol);
$inputColourPicker = $toolbox.find("." + flagColourPicker);
$buttonEraseMode = $toolbox.find("." + flagEraseMode);
$buttonSaveImage = $toolbox.find("." + flagSaveImage);
$containerAnnotation = $annotatorPNG.find("." + flagContainerAnnotation);
$canvasAnnotation = $containerAnnotation.find("." + flagCanvasAnnotation);
});
afterEach(function() {
let canvas = $($containerAnnotation.children()[0].children[0]).clone();
$containerAnnotation.empty();
$containerAnnotation.append(canvas);
});
describe('1. Initialization and Setup', function() {
it('a. Should initialize correctly on a given DOM element', async function() {
expect($annotatorPNG).to.exist;
});
it('b. Should create canvas with correct dimensions', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
expect(canvas.width).to.equal(800);
expect(canvas.height).to.equal(600);
expect($canvasAnnotation.attr('width')).to.equal('800');
expect($canvasAnnotation.attr('height')).to.equal('600');
});
it('c. Should have all UI elements present with correct values after initialization', async function() {
expect($annotatorPNG.find("." + flagToolbox)).to.have.length(1);
expect($annotatorPNG.find("." + flagUploadImage)).to.have.length(1);
expect($annotatorPNG.find("." + flagAddArrow)).to.have.length(1);
expect($annotatorPNG.find("." + flagAddTextbox)).to.have.length(1);
expect($annotatorPNG.find("." + flagAddSymbol)).to.have.length(1);
expect($annotatorPNG.find("." + flagColourPicker)).to.have.length(1);
expect($annotatorPNG.find("." + flagEraseMode)).to.have.length(1);
expect($annotatorPNG.find("." + flagSaveImage)).to.have.length(1);
expect($annotatorPNG.find("." + flagContainerAnnotation)).to.have.length(1);
expect($annotatorPNG.find("." + flagCanvasAnnotation).length > 0).to.be.true;
/*
expect($toolbox).to.exist;
expect($inputUploadImage).to.exist;
expect($buttonAddArrow).to.exist;
expect($buttonAddTextbox).to.exist;
expect($selectAddSymbol).to.exist;
expect($selectAddSymbol.find("option")).to.exist;
expect($inputColourPicker).to.exist;
expect($buttonEraseMode).to.exist;
expect($buttonSaveImage).to.exist;
expect($containerAnnotation).to.exist;
expect($canvasAnnotation).to.exist;
*/
expect($inputUploadImage.val()).to.equal('');
expect($inputColourPicker.val()).to.equal('#ff0000');
expect($buttonSaveImage.text().length > 0).to.be.true; // For unkown settings argument value
expect($buttonSaveImage.text()).to.equal('Save Image');
expect($canvasAnnotation.data(keyFabric)).to.exist;
});
});
describe('2. Image Upload and Display', function() {
it('a. Should successfully upload a PNG file', function(done) {
const file = new File([''], 'screenshot (16).png', { type: 'image/png' });
const fileInput = $inputUploadImage[0];
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
$(fileInput).trigger('change');
setTimeout(() => {
let canvas = $canvasAnnotation.data(keyFabric);
if (canvas) console.log("canvas.backgroundImage: " + canvas.backgroundImage);
expect(canvas.backgroundImage).to.exist;
done();
}, 100);
});
it('b. Should display the uploaded image correctly on the canvas', function(done) {
const file = new File([''], 'screenshot (16).png', { type: 'image/png' });
const fileInput = $inputUploadImage[0];
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
$(fileInput).trigger('change');
setTimeout(() => {
try {
let canvas = $canvasAnnotation.data(keyFabric);
let context = canvas.getContext('2d');
let imageData = context.getImageData(0, 0, canvas.width, canvas.height);
expect(canvas.width).to.equal(800);
expect(canvas.height).to.equal(600);
expect(imageData.data.length).to.equal(800 * 600 * 4);
done();
}
catch (e) {
console.log("Error during canvas initialisation: " + e);
done(e);
}
}, 100);
});
it('d. Should handle invalid file types', async function() {
const file = new File([''], 'test.jpg', { type: 'image/jpeg' });
const fileInput = $inputUploadImage[0];
const confirmStub = sinon.stub(window, 'alert').returns(true);
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
expect(() => $(fileInput).trigger('change')).to.throw();
confirmStub.restore();
});
});
describe('3. Arrow Addition', function() {
it('a. Should create a new arrow on the canvas when "Add Arrow" is clicked', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
console.log("canvas: " + canvas);
await waitForClick($buttonAddArrow);
console.log("canvas after: " + canvas);
expect(canvas.getObjects()).to.have.lengthOf(1);
expect(canvas.getObjects()[0].type).to.equal('path');
});
it('b. Should create arrow with correct default properties', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddArrow);
const arrow = canvas.getObjects()[0];
expect(arrow.fill).to.equal('#ff0000');
expect(arrow.stroke).to.equal('#ff0000');
expect(arrow.strokeWidth).to.equal(2);
});
it('c. Should allow multiple arrows to be added to the canvas', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddArrow);
await waitForClick($buttonAddArrow);
expect(canvas.getObjects()).to.have.lengthOf(2);
});
});
describe('4. Textbox Addition', function() {
it('a. Should create a new textbox on the canvas when "Add Textbox" is clicked', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddTextbox);
expect(canvas.getObjects()).to.have.lengthOf(1);
expect(canvas.getObjects()[0].type).to.equal('textbox');
});
it('b. Should create textbox with correct default properties', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddTextbox);
const textbox = canvas.getObjects()[0];
expect(textbox.fontSize).to.equal(20);
expect(textbox.left).to.equal(100);
expect(textbox.top).to.equal(100);
});
it('c. Should allow text to be entered and edited in the textbox', async function() {
this.timeout(10000);
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddTextbox);
const textbox = canvas.getObjects()[0];
console.log("textbox: " + textbox);
textbox.text = 'New Text';
console.log("textbox: " + textbox);
canvas.renderAll();
await new Promise(resolve => setTimeout(resolve, 50));
expect(textbox.text).to.equal('New Text');
});
it('d. Should allow multiple textboxes to be added to the canvas', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddTextbox);
await waitForClick($buttonAddTextbox);
expect(canvas.getObjects()).to.have.lengthOf(2);
});
});
describe('5. Element Manipulation', function() {
it('a. Should allow arrows to be selected, moved, resized, and rotated', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddArrow);
const arrow = canvas.getObjects()[0];
arrow.set({ left: 150, top: 150, scaleX: 2, angle: 45 });
canvas.renderAll();
expect(arrow.left).to.equal(150);
expect(arrow.top).to.equal(150);
expect(arrow.scaleX).to.equal(2);
expect(arrow.angle).to.equal(45);
});
it('b. Should allow textboxes to be selected, moved, resized, and rotated', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddTextbox);
const textbox = canvas.getObjects()[0];
textbox.set({ left: 150, top: 150, scaleX: 2, angle: 45 });
canvas.renderAll();
expect(textbox.left).to.equal(150);
expect(textbox.top).to.equal(150);
expect(textbox.scaleX).to.equal(2);
expect(textbox.angle).to.equal(45);
});
});
describe('6. Erasing Elements', function() {
afterEach(function() {
setTimeout(() => {}, 2000);
$annotatorPNG.annotatorPNG(annotatorSettings);
});
it('a. Should remove the currently selected arrow when "Erase Element" is clicked', async function() {
let canvas = $canvasAnnotation.data(keyFabric);
await waitForClick($buttonAddArrow);
canvas.setActiveObject(canvas.getObjects()[0]);
await waitForClick($buttonEraseMode);
expect(canvas.getObjects()).to.have.lengthOf(0);
});
it('b. Should remove the currently selected textbox when "Erase Element" is clicked', function(done) {
this.timeout(10000);
let canvas = $canvasAnnotation.data(keyFabric);
waitForClick($buttonAddTextbox).then(() => {
canvas.setActiveObject(canvas.getObjects()[0]);
canvas.renderAll();
waitForClick($buttonEraseMode).then(() => {
canvas.renderAll();
expect(canvas.getObjects()).to.have.lengthOf(0);
done();
});
});
});
it('c. Should not affect other elements on the canvas when erasing', function(done) {
this.timeout(10000);
let canvas = $canvasAnnotation.data(keyFabric);
waitForClick($buttonAddArrow).then(() => {
console.log("canvas.getObjects()[0]: ", canvas.getObjects()[0]);
waitForClick($buttonAddTextbox).then(() => {
canvas.setActiveObject(canvas.getObjects()[0]);
waitForClick($buttonEraseMode).then(() => {
expect(canvas.getObjects()).to.have.lengthOf(1);
console.log("canvas.getObjects()[0]: ", canvas.getObjects()[0]);
expect(canvas.getObjects()[0].text).to.exist;
done();
});
});
});
});
});
describe('7. Saving Functionality', function() {
it('a. Should trigger confirmation dialog when "Save" is clicked', async function() {
const confirmStub = sinon.stub(window, 'confirm').returns(true);
const alertStub = sinon.stub(window, 'alert').returns(true);
await waitForClick($buttonSaveImage);
expect(confirmStub.calledOnce).to.be.true;
confirmStub.restore();
alertStub.restore();
});
it('b. Should prevent saving when confirmation dialog is canceled', async function() {
const confirmStub = sinon.stub(window, 'confirm').returns(false);
const consoleStub = sinon.stub(console, 'log');
await waitForClick($buttonSaveImage);
expect(consoleStub.called).to.be.false;
confirmStub.restore();
consoleStub.restore();
});
it('c. Should generate a Base64 PNG string when saving is confirmed', async function() {
sinon.stub(window, 'confirm').returns(true);
const alertStub = sinon.stub(window, 'alert').returns(true);
const consoleStub = sinon.stub(console, 'log');
await waitForClick($buttonSaveImage);
expect(consoleStub.calledOnce).to.be.true;
const base64String = consoleStub.getCall(0).args[1];
expect(base64String).to.be.a('string');
expect(base64String).to.match(/^data:image\/png;base64,/);
window.confirm.restore();
consoleStub.restore();
alertStub.restore();
});
});
describe('8. Edge Cases and Error Handling', function() {
it('a. Should handle initialization on invalid DOM element', async function() {
expect(() => $('#non-existent-element').imageAnnotator()).to.throw();
});
});
describe('9. Performance', function() {
it('a. Should capture and generate screenshot within acceptable time', function(done) {
this.timeout(5000);
const startTime = performance.now();
const alertStub = sinon.stub(window, 'alert').returns(true);
const confirmStub = sinon.stub(window, 'confirm').returns(true);
$buttonSaveImage.click();
const endTime = performance.now();
const duration = endTime - startTime;
expect(duration).to.be.below(1000);
alertStub.restore();
confirmStub.restore();
done();
});
});
describe('10. Accessibility', function() {
it('a. Should have appropriate ARIA labels for all interactive elements', async function() {
expect($inputUploadImage.attr('aria-label').length > 0).to.be.true;
expect($buttonAddArrow.attr('aria-label').length > 0).to.be.true;
expect($buttonAddTextbox.attr('aria-label').length > 0).to.be.true;
expect($selectAddSymbol.attr('aria-label').length > 0).to.be.true;
expect($inputColourPicker.attr('aria-label').length > 0).to.be.true;
expect($buttonEraseMode.attr('aria-label').length > 0).to.be.true;
expect($buttonSaveImage.attr('aria-label').length > 0).to.be.true;
expect($canvasAnnotation.attr('aria-label').length > 0).to.be.true;
});
});
describe('11. jQuery Plugin Requirements', function() {
it('a. Should return jQuery object for chaining', function() {
const result = $annotatorPNG.annotatorPNG(annotatorSettings);
expect(result).to.equal($annotatorPNG);
});
it('b. Should initialize plugin on multiple elements', function() {
$('body').append('<div class="test-class"></div><div class="test-class"></div>');
$('.test-class').annotatorPNG(annotatorSettings);
expect($('.test-class').length).to.equal(2);
$('.test-class').remove();
});
});
describe('12. Memory Management', function() {
it('a. Should not leak memory on repeated initialization and destruction', function() {
const initialMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
for (let i = 0; i < 500; i++) {
$annotatorPNG.annotatorPNG(annotatorSettings);
$canvasAnnotation.data(keyFabric).dispose();
}
const finalMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
expect(finalMemory - initialMemory).to.be.below(1000000); // 1 MB ish
});
it('b. Should remove all created DOM elements after use', function() {
const initialChildCount = $annotatorPNG[0].childElementCount;
const initialCanvasCount = $containerAnnotation[0].childElementCount;
$annotatorPNG.annotatorPNG(annotatorSettings);
expect($annotatorPNG[0].childElementCount).to.equal(initialChildCount);
expect($containerAnnotation[0].childElementCount).to.equal(initialCanvasCount);
});
});
});

View File

@@ -1,113 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Layout Template</title>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script src="shared.js"></script>
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/8.3.2/mocha.min.css">
<link rel="stylesheet" href="capture-screen.css">
</head>
<body>
<header>
<h1>Website Title</h1>
</header>
<div class="content-wrapper">
<main>
<h2>Main Content</h2>
<p>This is where the main content of your page goes. You can add articles, blog posts, or any other primary content here.</p>
<input type="text" value="Test 1" />
<input type="number" value="2" />
<textarea>Test 3</textarea>
<!-- Start of Screen Capture Plugin HTML -->
<button class="capture-screen" role="button">Capture Screen</button>
<!-- End of Screen Capture Plugin HTML -->
<div id="notification-widget" class="modal">
<h3>Notifications</h3>
<p>You have 3 new messages.</p>
</div>
<a href="#notification-widget" id="notification-toggle" class="widget-toggle">Toggle Notifications</a>
<div id="chat-widget" class="modal">
<h3>Chat</h3>
<p>Chat content goes here...</p>
</div>
<a href="#chat-widget" id="chat-toggle" class="widget-toggle">Toggle Chat</a>
<div id="settings-widget" class="modal">
<h3>Quick Settings</h3>
<p>Adjust your settings here...</p>
</div>
<a href="#settings-widget" id="settings-toggle" class="widget-toggle">Toggle Settings</a>
<div id="mocha"></div>
</main>
</div>
<div id="modalTest" class="modal">
<div class="modal-content">
<h2>Test Modal</h2>
<p>This is a test modal.</p>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/8.3.2/mocha.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.3.4/chai.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/10.0.0/sinon.min.js"></script>
<div id="mocha"></div>
<script class="mocha-init">
mocha.setup({
ui: 'bdd',
globals: [
'flagInitialised',
'defaultOptions', 'flagCaptureScreen',
'idModalNotifications', 'idButtonToggleModalNotifications',
'idModalChat', 'idButtonToggleModalChat',
'idModalSettings', 'idButtonToggleModalSettings',
'idModalTest'
]
});
mocha.checkLeaks();
const expect = chai.expect;
</script>
<script src="plugin_capture_screen.js"></script>
<script src="test_plugin_capture_screen_Mocha.js"></script>
<script class="mocha-exec">
mocha.run();
</script>
</body>
<!-- Start of Screen Capture Plugin JavaScript -->
<script>
var defaultOptions = {
buttonText: "Capture Screen",
fileName: "screenshot.png",
};
var flagCaptureScreen = "capture-screen";
var idModalNotifications = "#notification-widget";
var idButtonToggleModalNotifications = "#notification-toggle";
var idModalChat = "#chat-widget";
var idButtonToggleModalChat = "#chat-toggle";
var idModalSettings = "#settings-widget";
var idButtonToggleModalSettings = "#settings-toggle";
var idModalTest = "#modalTest";
$(document).ready(function() {
$(".capture-screen").screenshotButton(defaultOptions);
hookupTestModals();
});
</script>
<!-- End of Screen Capture Plugin JavaScript -->
</html>

View File

@@ -1,84 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Annotation Control</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/8.3.2/mocha.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.3.4/chai.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sinon.js/10.0.1/sinon.min.js"></script>
<script src="shared.js"></script>
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mocha/8.3.2/mocha.min.css">
<link rel="stylesheet" href="display-png.css">
</head>
<body>
<!-- Start of PNG Annotation HTML -->
<div class="annotator-png">
<div class="annotator-png-toolbox">
<input type="file" class="annotator-png-upload-image" accept="image/png" aria-label="Upload image">
<button class="annotator-png-add-arrow" aria-label="Add arrow">Add Arrow</button>
<button class="annotator-png-add-textbox" aria-label="Add textbox">Add Textbox</button>
<select class="annotator-png-add-symbol" aria-label="Select and add symbol">
<option value="">Select Symbol</option>
</select>
<input type="color" class="annotator-png-colour-picker" value="#ff0000" aria-label="Colour picker">
<button class="annotator-png-erase-mode" aria-label="Toggle erase mode">Erase Mode</button>
<button class="annotator-png-save-image" aria-label="Save annotated image">Save Image</button>
</div>
<div class="annotator-png-container-annotation" style="height: 600px; width: 800px;">
<canvas class="annotator-png-canvas-annotation" height="600px" width="800px" aria-label="Image canvas"></canvas>
</div>
</div>
<!-- End of PNG Annnotation HTML -->
<div id="mocha"></div>
<script class="mocha-init">
mocha.setup({
ui: 'bdd',
globals: [
'flagAnnotatorPNG', 'flagToolbox', 'flagContainer', 'flagContainerAnnotation',
'flagUploadImage', 'flagAddArrow', 'flagAddTextbox', 'flagAddSymbol',
'flagColourPicker', 'flagEraseMode', 'flagSaveImage', 'flagCanvasAnnotation',
'keyFabric', 'keyIsEraseMode', 'annotatorSettings', 'flagInitialised'
]
});
mocha.checkLeaks();
const expect = chai.expect;
</script>
<script src="plugin_display_png,js"></script>
<script src="test_plugin_display_png_Mocha.js"></script>
<script class="mocha-exec">
// mocha.run();
</script>
</body>
<!-- Start of PNG Annotation JavaScript -->
<script>
var flagAnnotatorPNG = "annotator-png";
var flagToolbox = "annotator-png-toolbox";
var flagContainer = "annotator-png-container";
var flagContainerAnnotation = "annotator-png-container-annotation";
var flagUploadImage = "annotator-png-upload-image";
var flagAddArrow = "annotator-png-add-arrow";
var flagAddTextbox = "annotator-png-add-textbox";
var flagAddSymbol = "annotator-png-add-symbol";
var flagColourPicker = "annotator-png-colour-picker";
var flagEraseMode = "annotator-png-erase-mode";
var flagSaveImage = "annotator-png-save-image";
var flagCanvasAnnotation = "annotator-png-canvas-annotation";
var keyFabric = "fabric";
var keyIsEraseMode = "isEraseMode";
var annotatorSettings = {};
$(document).ready(function() {
$("." + flagAnnotatorPNG).annotatorPNG(annotatorSettings);
});
</script>
<!-- End of PNG Annotation JavaScript -->
</html>