From b49948c68195774e0ec231f0e04444458e4b3af1 Mon Sep 17 00:00:00 2001 From: leebeomjun Date: Mon, 31 Jul 2023 16:12:52 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=20=EC=88=98=EC=A0=95=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WEB-INF/jsp/fims/sprt/sprt03020-main.jsp | 64 +-- .../js/fims/framework/cmm/xitPaintwebUtil.js | 81 +++ .../biz/paintweb/extensions/colormixer.js | 1 + .../fims/biz/paintweb/extensions/moodle.js | 363 ------------- .../fims/biz/paintweb/extensions/mousekeys.js | 1 + .../default/script.js => guiScript.js} | 5 + .../lib/fims/biz/paintweb/includes/debug.js | 451 ----------------- .../lib/fims/biz/paintweb/includes/json2.js | 478 ------------------ .../biz/paintweb/{lang/ko.js => korean.js} | 4 +- .../default/layout.xhtml => layout.js} | 11 +- .../lib/fims/biz/paintweb/paintweb-config.js | 41 +- .../lib/fims/biz/paintweb/paintweb.js | 331 ++---------- .../paintweb/{includes/lib.js => pwlib.js} | 0 .../default => style}/icons/bcurve.png | Bin .../default => style}/icons/cbucket.png | Bin .../icons/clipboardPaste.png | Bin .../default => style}/icons/cpicker.png | Bin .../default => style}/icons/ellipse.png | Bin .../default => style}/icons/eraser.png | Bin .../default => style}/icons/hand.png | Bin .../default => style}/icons/help.png | Bin .../default => style}/icons/historyRedo.png | Bin .../default => style}/icons/historyUndo.png | Bin .../default => style}/icons/i_addPhoto.png | Bin .../default => style}/icons/i_block.png | Bin .../default => style}/icons/i_cancel.png | Bin .../biz/paintweb/style/icons/i_carnumber.png | Bin 0 -> 41493 bytes .../default => style}/icons/i_centerAlign.png | Bin .../default => style}/icons/i_colorfill.png | Bin .../default => style}/icons/i_copy.png | Bin .../default => style}/icons/i_crop.png | Bin .../default => style}/icons/i_cut.png | Bin .../default => style}/icons/i_delete.png | Bin .../default => style}/icons/i_fontBold.png | Bin .../default => style}/icons/i_fontItalic.png | Bin .../default => style}/icons/i_fontSize.png | Bin .../default => style}/icons/i_leftAlign.png | Bin .../default => style}/icons/i_paste.png | Bin .../default => style}/icons/i_pinch.png | Bin .../default => style}/icons/i_replay.png | Bin .../default => style}/icons/i_rightAlign.png | Bin .../default => style}/icons/i_rotation.png | Bin .../default => style}/icons/i_save.png | Bin .../default => style}/icons/i_select.png | Bin .../default => style}/icons/i_square.png | Bin .../default => style}/icons/imageClear.png | Bin .../default => style}/icons/imageRotate.png | Bin .../default => style}/icons/imageSave.png | Bin .../default => style}/icons/insertimg.png | Bin .../default => style}/icons/line-cap-butt.png | Bin .../icons/line-cap-round.png | Bin .../icons/line-cap-square.png | Bin .../icons/line-join-bevel.png | Bin .../icons/line-join-miter.png | Bin .../icons/line-join-round.png | Bin .../default => style}/icons/line.png | Bin .../default => style}/icons/paintweb.png | Bin .../default => style}/icons/pencil.png | Bin .../default => style}/icons/polygon.png | Bin .../default => style}/icons/rectangle.png | Bin .../default => style}/icons/selection.png | Bin .../default => style}/icons/selectionCopy.png | Bin .../default => style}/icons/selectionCrop.png | Bin .../default => style}/icons/selectionCut.png | Bin .../icons/selectionDelete.png | Bin .../default => style}/icons/selectionFill.png | Bin .../icons/shapeType-both.png | Bin .../icons/shapeType-fill.png | Bin .../icons/shapeType-stroke.png | Bin .../icons/text-align-center.png | Bin .../icons/text-align-left.png | Bin .../icons/text-align-right.png | Bin .../default => style}/icons/text-bold.png | Bin .../default => style}/icons/text-italic.png | Bin .../default => style}/icons/text-size.png | Bin .../default => style}/icons/text.png | Bin .../default => style}/icons/zoom.png | Bin .../default => style}/images/button.png | Bin .../default => style}/images/checkers-big.png | Bin .../default => style}/images/checkers.png | Bin .../images/floatingPanel-close.png | Bin .../images/floatingPanel-minimize.png | Bin .../images/floatingPanel-restore.png | Bin .../images/floatingPanel-title.png | Bin .../images/paintweb-logo.png | Bin .../images/toolbar-colors.png | Bin .../{interfaces/default => style}/style.css | 17 +- .../lib/fims/biz/paintweb/tools/selection.js | 59 ++- 88 files changed, 243 insertions(+), 1664 deletions(-) create mode 100644 src/main/webapp/resources/js/fims/framework/cmm/xitPaintwebUtil.js delete mode 100644 src/main/webapp/resources/lib/fims/biz/paintweb/extensions/moodle.js rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default/script.js => guiScript.js} (99%) delete mode 100644 src/main/webapp/resources/lib/fims/biz/paintweb/includes/debug.js delete mode 100644 src/main/webapp/resources/lib/fims/biz/paintweb/includes/json2.js rename src/main/webapp/resources/lib/fims/biz/paintweb/{lang/ko.js => korean.js} (99%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default/layout.xhtml => layout.js} (98%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{includes/lib.js => pwlib.js} (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/bcurve.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/cbucket.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/clipboardPaste.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/cpicker.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/ellipse.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/eraser.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/hand.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/help.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/historyRedo.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/historyUndo.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_addPhoto.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_block.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_cancel.png (100%) create mode 100644 src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_carnumber.png rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_centerAlign.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_colorfill.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_copy.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_crop.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_cut.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_delete.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_fontBold.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_fontItalic.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_fontSize.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_leftAlign.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_paste.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_pinch.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_replay.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_rightAlign.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_rotation.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_save.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_select.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/i_square.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/imageClear.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/imageRotate.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/imageSave.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/insertimg.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/line-cap-butt.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/line-cap-round.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/line-cap-square.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/line-join-bevel.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/line-join-miter.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/line-join-round.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/line.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/paintweb.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/pencil.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/polygon.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/rectangle.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/selection.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/selectionCopy.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/selectionCrop.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/selectionCut.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/selectionDelete.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/selectionFill.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/shapeType-both.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/shapeType-fill.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/shapeType-stroke.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/text-align-center.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/text-align-left.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/text-align-right.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/text-bold.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/text-italic.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/text-size.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/text.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/icons/zoom.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/button.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/checkers-big.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/checkers.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/floatingPanel-close.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/floatingPanel-minimize.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/floatingPanel-restore.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/floatingPanel-title.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/paintweb-logo.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/images/toolbar-colors.png (100%) rename src/main/webapp/resources/lib/fims/biz/paintweb/{interfaces/default => style}/style.css (98%) diff --git a/src/main/webapp/WEB-INF/jsp/fims/sprt/sprt03020-main.jsp b/src/main/webapp/WEB-INF/jsp/fims/sprt/sprt03020-main.jsp index a1cddf2a..082e1c85 100644 --- a/src/main/webapp/WEB-INF/jsp/fims/sprt/sprt03020-main.jsp +++ b/src/main/webapp/WEB-INF/jsp/fims/sprt/sprt03020-main.jsp @@ -39,6 +39,7 @@ " /> " /> + ?${ver}" /> 사진 편집 @@ -61,9 +62,14 @@ - - + + + + + + + @@ -74,14 +80,14 @@ //FIXME: pw instance 변수명 변경시 paintweb.js의 imageSaveTo() 내의 2564 line if(pw.image.modified) 변경 필요 var pw; var originalInfomation = {}; - let editableImage = null; - + var editableImage = null; + var isNumberPlate = false; + const initEditor = () => { pw = new PaintWeb(); pw.config.imageLoad = editableImage; pw.config.guiPlaceholder = document.getElementById('paintWebTarget'); - pw.config.configFile = 'paintweb-config.json?${ver}'; pw.config.imageSave = fnImageSaveTo; pw.config.afterImageSave = fnAfterImageSave; @@ -92,11 +98,9 @@ console.log(doc); console.log(_self); - - const isDelete = imgWidth === 0; - if(isDelete){ - if(!confirm('단속이미지를 정말로 삭제 하시겠습니까?')) return; + if(isNumberPlate){ + if(!confirm('번호판 이미지를 추가하시겠습니까?')) return; }else{ if(!confirm('편집한 단속이미지를 저장하시겠습니까?')) return; } @@ -105,42 +109,24 @@ // var param = originalInfomation 파일아이디,단속아이디,inpoType.. - // 삭제일때 - if(isDelete){ + // 번호판일때 + if(isNumberPlate){ - //cmmAjax({ - // url: '/somePath/removeFile.do', - // data: $.param(param), - // success: (res) => { - // window.opener.callbackReloadImage(); - // window.close(); - // } - //}) + return true; - } - - // 저장일때 - const formData = new FormData(); - //formData.append('fileId', fileId); - //formData.append('file', file); - - //cmmAjax({ - // type: 'post', - // url: '/somePath/save.do', - // processData: false, - // contentType: false, - // data: formData, - // success: (res) => { - // window.opener.callbackReloadImage(); - // window.close(); - // } - //}); - return true; + } else { + // 저장일때 + const formData = new FormData(); + //formData.append('fileId', fileId); + //formData.append('file', file); + return true; + + }; function fnAfterImageSave(){ - console.log('after...'); + window.close(); }; diff --git a/src/main/webapp/resources/js/fims/framework/cmm/xitPaintwebUtil.js b/src/main/webapp/resources/js/fims/framework/cmm/xitPaintwebUtil.js new file mode 100644 index 00000000..8a457308 --- /dev/null +++ b/src/main/webapp/resources/js/fims/framework/cmm/xitPaintwebUtil.js @@ -0,0 +1,81 @@ +/** + * 전달받은 이미지를 base64로 인코딩한다 + * @param file - 이미지 파일 또는 이미지 URL + * @param maxWidth - 인코딩 시의 이미지 max width 사이즈 + * @returns {Promise} + */ +var readImage = () => { + let image = this.$refs.image.src + this.toBlob(image) + .then(res => { + console.log(res) + this.image = { + filename: res.name, + size: res.size, + type: res.type, + lastModified: res.lastModified + } + }) +}; + +/** + * 이미지 url을 blob 파일로 변환하여 전달한다 + * @param url + * @returns {Promise} + */ +var toBlob = (url) => { + return new Promise((resolve, reject) => { + this.base64Encode(url) + .then(res => { + let byteString = atob(res.dataUrl) + let ab = new ArrayBuffer(byteString.length) + let ia = new Uint8Array(ab) + + for (let i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i) + } + + // write the array buffer to blob + let blob = new Blob([ab], {type: 'image/' + res.type}) + + let formData = new FormData() + formData.append('file', blob, res.name) + resolve(formData.get('file')) + }) + }) +}; + +/** + * 전달받은 이미지를 base64로 인코딩한다 + */ +var base64Encode = (url) => { + const re = new RegExp('.(gif|jpg|jpeg|tiff|png|ico)$', 'i') + let name = (/[^(/|\\)]*$/).exec(url)[0] + let type = re.test(name) ? re.exec(name)[0].replace('.', '') : 'jpg' + + return new Promise((resolve, reject) => { + let image = new Image() + + image.onload = function (event) { + let canvas = document.createElement('canvas') + // draw canvas + canvas.width = image.naturalWidth + canvas.height = image.naturalHeight + canvas.getContext('2d').drawImage(image, 0, 0) + + let dataUrl = canvas.toDataURL('image/' + type) + resolve({ + name: name, + type: type, + dataUrl: dataUrl.split(',')[1] + }) + } + image.onerror = function () { + let msg = `"${file}"을 로딩하는 데 오류가 발생하였습니다. 이미지 파일을 확인해주세요.` + alert(msg) + console.error(msg) + } + image.crossOrigin = 'anonymous'; + image.src = url + }) +} \ No newline at end of file diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/colormixer.js b/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/colormixer.js index c6933c40..c003ad86 100644 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/colormixer.js +++ b/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/colormixer.js @@ -35,6 +35,7 @@ * @param {PaintWeb} app Reference to the main paint application object. */ pwlib.extensions.colormixer = function (app) { + var _self = this, config = app.config.colormixer, doc = app.doc, diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/moodle.js b/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/moodle.js deleted file mode 100644 index e9d3b71b..00000000 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/moodle.js +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (C) 2009 Mihai Şucan - * - * This file is part of PaintWeb. - * - * PaintWeb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * PaintWeb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with PaintWeb. If not, see . - * - * $URL: http://code.google.com/p/paintweb $ - * $Date: 2009-10-29 19:05:49 +0200 $ - */ - -/** - * @author Mihai Şucan - * @fileOverview Holds the integration code for PaintWeb inside Moodle. - */ - -/** - * @class The Moodle extension for PaintWeb. This extension handles the Moodle - * integration inside the PaintWeb code. - * - *

Note: This extension is supposed to work with Moodle 1.9 - * and Moodle 2.0. - * - * @param {PaintWeb} app Reference to the main paint application object. - */ -pwlib.extensions.moodle = function (app) { - var _self = this, - appEvent = pwlib.appEvent, - config = app.config, - gui = app.gui, - lang = app.lang.moodle, - moodleServer = config.moodleServer, - tinymceEditor = null, - qfErrorShown = false; - - // Holds information related to Moodle. - var moodleInfo = { - // Holds the URL of the image the user is saving. - imageURL: null, - - // The class name for the element which holds the textarea buttons (toggle - // on/off). - // This element exists only in Moodle 1.9. - textareaButtons: 'textareaicons', - - // The image save handler script on the server-side. The path is relative to - // the PaintWeb base folder. - // This used with Moodle 2.0. - imageSaveHandler20: '../ext/moodle/imagesave20.php', - - // The image save handler script for Moodle 1.9. - imageSaveHandler19: '../ext/moodle/imagesave19.php', - - // This holds the release version of Moodle being used. This should be 1.9 - // or 2.0. - release: 0, - - // Moodle 2.0 draft item ID used for file storage. - draftitemid: null - }; - - /** - * The extensionRegister event handler. Setup event listeners, - * determine Moodle version, and more. - * - * @returns {Boolean} True if the extension initialized successfully, or false - * if not. - */ - this.extensionRegister = function () { - // Register application events. - app.events.add('guiShow', this.guiShow); - app.events.add('guiHide', this.guiHide); - app.events.add('imageSave', this.imageSave); - - if (moodleServer && moodleServer.release) { - var matches = moodleServer.release.match(/^\s*(\d+\.\d+)/); - if (matches && matches[1]) { - moodleInfo.release = parseFloat(matches[1]); - } - } - - if (typeof window.qf_errorHandler === 'function' && config.tinymce && - !config.tinymce.onSubmitUnsaved) { - config.tinymce.onSubmitUnsaved = this.onSubmitUnsaved; - } - - return true; - }; - - /** - * The submit event handler for the form to which the PaintWeb - * instance is attached to. This method is invoked by the TinyMCE plugin when - * the form is submitted while the user edits an image with unsaved changes. - * @private - */ - this.onSubmitUnsaved = function () { - var tmce = config.tinymceEditor, - textarea = tmce ? tmce.getElement() : null, - guiPlaceholder = config.guiPlaceholder, - prevSibling = guiPlaceholder.previousSibling; - - if (tmce && textarea && window.qf_errorHandler) { - try { - qf_errorHandler(textarea, "\n - " + lang.errorSubmitUnsaved); - } catch (err) { - return; - } - - qfErrorShown = true; - - // Due to the styling of the error shown by Moodle, PaintWeb must have - // clear:right. - if (prevSibling && prevSibling.className && - prevSibling.className.indexOf('paintweb_tinymce_status') !== -1) { - prevSibling.style.clear = 'right'; - } else { - guiPlaceholder.style.clear = 'right'; - } - } - }; - - /** - * The imageSave application event handler. When the user - * attempts to save an image, this extension handles the event by sending the - * image data to the Moodle server, to perform the actual save operation. - * - * @private - * @param {pwlib.appEvent.imageSave} ev The application event object. - */ - this.imageSave = function (ev) { - if (!ev.dataURL) { - return; - } - - ev.preventDefault(); - - moodleInfo.imageURL = config.imageLoad.src; - if (!moodleInfo.imageURL || moodleInfo.imageURL.substr(0, 5) === 'data:') { - moodleInfo.imageURL = '-'; - } - - if (config.moodleSaveMethod === 'dataURL') { - app.events.dispatch(new appEvent.imageSaveResult(true, - moodleInfo.imageURL, ev.dataURL)); - - } else { - var handlerURL = PaintWeb.baseFolder, - send = 'url=' + encodeURIComponent(moodleInfo.imageURL) + - '&dataURL=' + encodeURIComponent(ev.dataURL), - headers = {'Content-Type': 'application/x-www-form-urlencoded'}; - - // In Moodle 2.0 we include the context ID and the draft item ID, such - // that the image save script can properly save the new image inside the - // current draft area of the current textarea element. - if (moodleInfo.release >= 2) { - handlerURL += moodleInfo.imageSaveHandler20; - if (moodleServer.contextid) { - send += '&contextid=' + encodeURIComponent(moodleServer.contextid); - } - if (moodleInfo.draftitemid) { - send += '&draftitemid=' + encodeURIComponent(moodleInfo.draftitemid); - } - - } else { - handlerURL += moodleInfo.imageSaveHandler19; - } - - pwlib.xhrLoad(handlerURL, imageSaveReady, 'POST', send, headers); - } - }; - - /** - * The image save onreadystatechange event handler for the - * XMLHttpRequest which performs the image save. This function - * uses the reply to determine if the image save operation is successful or - * not. - * - *

The {@link pwlib.appEvent.imageSaveResult} application event is - * dispatched. - * - *

The server-side script must reply with a JSON object with the following - * properties: - * - *

    - *
  • successful which tells if the image save operation was - * successful or not; - * - *
  • url which must tell the same URL as the image we just - * saved (sanity/security check); - * - *
  • urlNew is optional. This allows the server-side script to - * change the image URL; - * - *
  • errorMessage is optional. When the image save was not - * successful, an error message can be displayed. - *
- * - * @private - * @param {XMLHttpRequest} xhr The XMLHttpRequest object. - */ - function imageSaveReady (xhr) { - if (!xhr || xhr.readyState !== 4) { - return; - } - - var result = {successful: false, url: moodleInfo.imageURL}; - - if ((xhr.status !== 304 && xhr.status !== 200) || !xhr.responseText) { - alert(lang.xhrRequestFailed); - - app.events.dispatch(new appEvent.imageSaveResult(false, result.url, null, - lang.xhrRequestFailed)); - - return; - } - - try { - result = JSON.parse(xhr.responseText); - } catch (err) { - result.errorMessage = lang.jsonParseFailed + "\n" + err; - alert(result.errorMessage); - } - - if (result.successful) { - if (result.url !== moodleInfo.imageURL) { - alert(pwlib.strf(lang.urlMismatch, { - url: moodleInfo.imageURL, - urlServer: result.url || 'null'})); - } - } else { - if (result.errorMessage) { - alert(lang.imageSaveFailed + "\n" + result.errorMessage); - } else { - alert(lang.imageSaveFailed); - } - } - - app.events.dispatch(new appEvent.imageSaveResult(result.successful, - result.url, result.urlNew, result.errorMessage)); - }; - - /** - * The guiShow application event handler. When the PaintWeb GUI - * is shown, we must hide the textarea icons for the current textarea element, - * inside a Moodle page. - * @private - */ - this.guiShow = function () { - var pNode = config.guiPlaceholder.parentNode, - textareaButtons - = pNode.getElementsByClassName(moodleInfo.textareaButtons)[0]; - - // These show in Moodle 1.9. - if (textareaButtons) { - textareaButtons.style.display = 'none'; - } - - qfErrorShown = false; - - // For Moodle 2.0 we must determine the draft item ID in order to properly - // perform the image save operation into the current draft area. - if (moodleInfo.release < 2) { - return; - } - - // Typically the TinyMCE editor instance is attached to a textarea element - // which has a name=whatever[text] or similar form. In the same form as the - // textarea, there must be a hidden input element with the - // name=whatever[itemid]. The value of that input holds the draft item ID. - var tmce = config.tinymceEditor, - textarea = tmce ? tmce.getElement() : null, - frm = textarea ? textarea.form : null; - - if (!tmce || !textarea || !textarea.name || !frm) { - return; - } - - var fieldname = textarea.name.replace(/\[text\]$/, ''); - if (!fieldname) { - return; - } - - var draftitemid = frm.elements.namedItem(fieldname + '[itemid]'), - format = frm.elements.namedItem(fieldname + '[format]'); - - if (draftitemid) { - moodleInfo.draftitemid = draftitemid.value; - } - - if (format) { - format.style.display = 'none'; - } - }; - - /** - * The guiHide application event handler. When the PaintWeb GUI - * is hidden, we must show again the textarea icons for the current textarea - * element, inside a Moodle page. - * @private - */ - this.guiHide = function () { - var guiPlaceholder = config.guiPlaceholder, - prevSibling = guiPlaceholder.previousSibling; - pNode = guiPlaceholder.parentNode, - textareaButtons - = pNode.getElementsByClassName(moodleInfo.textareaButtons)[0]; - - // These show in Moodle 1.9. - if (textareaButtons) { - textareaButtons.style.display = ''; - } - - var tmce = config.tinymceEditor, - textarea = tmce ? tmce.getElement() : null, - frm = textarea ? textarea.form : null; - - if (!tmce || !textarea || !textarea.name || !frm) { - return; - } - - if (qfErrorShown) { - if (window.qf_errorHandler) { - qf_errorHandler(textarea, ''); - } - - if (prevSibling && prevSibling.className && - prevSibling.className.indexOf('paintweb_tinymce_status') !== -1) { - prevSibling.style.clear = ''; - } else { - guiPlaceholder.style.clear = ''; - } - } - - // The format input element only shows in Moodle 2.0. - if (moodleInfo.release >= 2) { - var fieldname = textarea.name.replace(/\[text\]$/, ''); - if (!fieldname) { - return; - } - - var format = frm.elements.namedItem(fieldname + '[format]'); - - if (format) { - format.style.display = ''; - } - } - }; -}; - -// vim:set spell spl=en fo=wan1croqlt tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix: - diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/mousekeys.js b/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/mousekeys.js index fca2e836..4466b457 100644 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/mousekeys.js +++ b/src/main/webapp/resources/lib/fims/biz/paintweb/extensions/mousekeys.js @@ -32,6 +32,7 @@ * @param {PaintWeb} app Reference to the main paint application object. */ pwlib.extensions.mousekeys = function (app) { + var _self = this, canvas = app.buffer.canvas, config = app.config, diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/script.js b/src/main/webapp/resources/lib/fims/biz/paintweb/guiScript.js similarity index 99% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/script.js rename to src/main/webapp/resources/lib/fims/biz/paintweb/guiScript.js index 86050415..6aa6a6ea 100644 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/script.js +++ b/src/main/webapp/resources/lib/fims/biz/paintweb/guiScript.js @@ -872,10 +872,12 @@ pwlib.gui = function (app) { var selCrop = this.commands.selectionCrop, selFill = this.commands.selectionFill, + selForNumPlt = this.commands.selectionForNumberPlate, selDelete = this.commands.selectionDelete; selCrop.className += classDisabled; selFill.className += classDisabled; + selForNumPlt.className += classDisabled; selDelete.className += classDisabled; return true; @@ -1000,6 +1002,9 @@ pwlib.gui = function (app) { placeholder.focus(); } catch (err) { } + + this.toolActivate("selection"); //영역 선택 + app.events.dispatch(new appEvent.guiShow()); }; diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/includes/debug.js b/src/main/webapp/resources/lib/fims/biz/paintweb/includes/debug.js deleted file mode 100644 index 810e2c6b..00000000 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/includes/debug.js +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright (C) 2008, 2009 Mihai Şucan - * - * This file is part of PaintWeb. - * - * PaintWeb is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * PaintWeb is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with PaintWeb. If not, see . - * - * $URL: http://code.google.com/p/paintweb $ - * $Date: 2009-05-11 19:37:56 +0300 $ - */ - -/** - * @author Mihai Şucan - * @fileOverview Minimal code used for aiding debugging PaintWeb. - */ - -// Opera compatibility -if (!window.console) { - /** - * @namespace Holds a simple method used for debugging. Opera doesn't have the - * window.console API like Firefox+Firebug has. - */ - window.console = {}; -} - -if (!window.console.log) { - /** - * Display a message in the debugger. If available, opera.postError is used, - * otherwise no message is displayed. - * - * @param {mixed} mixed Any number of arguments, each one is displayed in the - * debugger. - */ - window.console.log = function () { - var msg = ''; - - for (var i = 0, n = arguments.length; i < n; i++) { - msg += arguments[i] + ' '; - } - - if (window.opera && window.opera.postError) { - opera.postError(msg); - } - }; -} - -if (!window.console.warn) { - /** - * Display a message in the debugger. If available, opera.postError is used, - * otherwise no warning is displayed. - * - * @param {mixed} mixed Any number of arguments, each one is displayed in the - * debugger. - */ - window.console.warn = function () { - console.log.apply(null, arguments); - }; -} - -/** - * JavaScript code performance profiler. - *

Nested timers are accounted for - see the example below. - * - * @example - * // To profile your code just do: - * var profiler = new $.profiler(); - * - * profiler.start('long test'); - * // ... more code ... - * profiler.start('function 1'); - * // ... more code ... - * profiler.stop('function 1'); - * // ... more code ... - * profiler.start('function 2'); - * // ... more code ... - * profiler.stop('function 2'); - * // ... more code ... - * profiler.stop('long test'); - * - * // To see the results do: - * profiler.reportText(); - * // or .. - * profiler.reportData(); - * - * @class JavaScript code performance profiler. - */ -var libProfiler = function () { - /** - * @ignore - * @class Function timer. This is the constructor used for instancing a single - * timer object created by the profiler. - * - * @private - * @param {String} name_ The timer name. - * @param {Boolean} [independent_=false] Tells if the timer is independent. - * Means this timer will not affect the timers execution stack. - */ - function fnTimer (name_, independent_) { - this.avgOwnTimePerCall = 0; - this.avgRunTimePerCall = 0; - this.calls = 0; - this.maxOwnTimePerCall = 0; - this.maxRunTimePerCall = 0; - this.minOwnTimePerCall = 0; - this.minRunTimePerCall = 0; - this.name = name_; - this.ownTimeTotal = 0; - this.runTimeTotal = 0; - this.state = fnTimer.STATE_NONE; - this.independent = independent_; - - var startTime_ = 0, - subTimerStart_ = 0, - subTime_ = 0, - stack_ = 0; - - /* - * Start timing function execution. - */ - this.start = function () { - if (this.state == fnTimer.STATE_START || - this.state == fnTimer.STATE_SUB) { - stack_++; - return; - } - - startTime_ = (new Date ()).getTime(); - this.state = fnTimer.STATE_START; - }; - - /* - * Stop timing function execution. - */ - this.stop = function () { - if (this.state == fnTimer.STATE_SUB) { - this.subTimerEnd(); - } - - if (this.state != fnTimer.STATE_START) { - return; - } - - this.calls++; - - if (stack_) { - stack_--; - return; - } - - var runTime = (new Date ()).getTime() - startTime_; - var ownTime = runTime - subTime_; - subTime_ = 0; - - this.runTimeTotal += runTime; - this.ownTimeTotal += ownTime; - - this.avgRunTimePerCall = this.runTimeTotal / this.calls; - this.avgOwnTimePerCall = this.ownTimeTotal / this.calls; - - if (runTime < this.minRunTimePerCall) { - this.minRunTimePerCall = runTime; - } - - if (runTime > this.maxRunTimePerCall) { - this.maxRunTimePerCall = runTime; - } - - if (ownTime < this.minOwnTimePerCall) { - this.minOwnTimePerCall = ownTime; - } - - if (ownTime > this.maxOwnTimePerCall) { - this.maxOwnTimePerCall = ownTime; - } - - this.state = fnTimer.STATE_STOP; - }; - - /* - * Start timing sub-function execution. The sub-function execution timer is - * used for calculating the ownTime (runTime - sub-function execution time). - */ - this.subTimerStart = function () { - if (this.independent || this.state != fnTimer.STATE_START) { - return; - } - - subTimerStart_ = (new Date()).getTime(); - - this.state = fnTimer.STATE_SUB; - }; - - /* - * Stop timing sub-function execution. - */ - this.subTimerEnd = function () { - if (this.independent || this.state != fnTimer.STATE_SUB) { - return; - } - - subTime_ += (new Date()).getTime() - subTimerStart_; - this.state = fnTimer.STATE_START; - }; - }; - - fnTimer.STATE_NONE = 0; - fnTimer.STATE_START = 1; - fnTimer.STATE_SUB = 2; - fnTimer.STATE_STOP = 3; - - /** - * Holds the timer objects. - */ - this.timers = {}; - - var activeTimer_ = null, - timersStack_ = []; - - /** - * Start/create a function timer. - * - * @param {String} name The timer name. - * @param {Boolean} [independent=false] Tells if the timer should be - * independent or not. This means that this new function timer is not be - * considered affecting the execution time of existing function timers in the - * call stack. - */ - this.start = function (name, independent) { - var timer = this.timers[name]; - if (!timer) { - timer = this.timers[name] = new fnTimer(name, independent); - } - - if (!timer.independent && activeTimer_ != name) { - var activeTimer = activeTimer_ ? this.timers[activeTimer_] : null; - - if (activeTimer && activeTimer.state == fnTimer.STATE_START) { - timersStack_.push(activeTimer_); - activeTimer.subTimerStart(); - } - - activeTimer_ = name; - } - - timer.start(); - }; - - /** - * Stop a function timer. - */ - this.stop = function (name) { - var timer = this.timers[name]; - if (!timer) { - return; - } - - timer.stop(); - - if (timer.independent || name != activeTimer_ || - name == activeTimer_ && timer.state == fnTimer.STATE_START) { - return; - } - - if (timersStack_.length > 0) { - activeTimer_ = timersStack_.pop(); - - var activeTimer = this.timers[activeTimer_]; - activeTimer.subTimerEnd(); - - } else { - activeTimer_ = null; - } - }; - - /** - * Generate timers report data. - * - * @returns {Object} Holds all the information gathered by the timers. - */ - this.reportData = function () { - var name, timer, timerDetails, - data = { - avgCallsPerTimer: 0, - avgOwnTimePerCall: 0, - avgOwnTimePerTimer: 0, - avgRunTimePerCall: 0, - avgRunTimePerTimer: 0, - callsTotal: 0, - maxCallsPerTimer: 0, - maxCallsPerTimerName: '', - maxOwnTimePerCall: 0, - maxOwnTimePerCallName: '', - maxRunTimePerCall: 0, - maxRunTimePerCallName: '', - minCallsPerTimer: 0, - minCallsPerTimerName: '', - minOwnTimePerCall: 0, - minOwnTimePerCallName: '', - minRunTimePerCall: 0, - minRunTimePerCallName: '', - ownTimeTotal: 0, - runTimeTotal: 0, - timers: 0, - timerDetails: [] - }; - - for (name in this.timers) { - timer = this.timers[name]; - if (timer.state != fnTimer.STATE_STOP) { - continue; - } - - timerDetails = { - name: name, - avgOwnTimePerCall: timer.avgOwnTimePerCall, - avgRunTimePerCall: timer.avgRunTimePerCall, - calls: timer.calls, - maxOwnTimePerCall: timer.maxOwnTimePerCall, - maxRunTimePerCall: timer.maxRunTimePerCall, - minOwnTimePerCall: timer.minOwnTimePerCall, - minRunTimePerCall: timer.minRunTimePerCall, - runTimeTotal: timer.runTimeTotal, - ownTimeTotal: timer.ownTimeTotal - }; - data.timerDetails.push(timerDetails); - - if (timer.calls > data.maxCallsPerTimer || !data.timers) { - data.maxCallsPerTimer = timer.calls; - data.maxCallsPerTimerName = name; - } - - if (timer.maxOwnTimePerCall > data.maxOwnTimePerCall || !data.timers) { - data.maxOwnTimePerCall = timer.maxOwnTimePerCall; - data.maxOwnTimePerCallName = name; - } - - if (timer.maxRunTimePerCall > data.maxRunTimePerCall || !data.timers) { - data.maxRunTimePerCall = timer.maxRunTimePerCall; - data.maxRunTimePerCallName = name; - } - - if (timer.calls < data.minCallsPerTimer || !data.timers) { - data.minCallsPerTimer = timer.calls; - data.minCallsPerTimerName = name; - } - - if (timer.minOwnTimePerCall < data.minOwnTimePerCall || !data.timers) { - data.minOwnTimePerCall = timer.minOwnTimePerCall; - data.minOwnTimePerCallName = name; - } - - if (timer.minRunTimePerCall < data.minRunTimePerCall || !data.timers) { - data.minRunTimePerCall = timer.minRunTimePerCall; - data.minRunTimePerCallName = name; - } - - data.runTimeTotal += timer.runTimeTotal; - data.ownTimeTotal += timer.ownTimeTotal; - data.callsTotal += timer.calls; - data.timers++; - } - - if (data.timers == 0) { - return data; - } - - data.avgCallsPerTimer = data.callsTotal / data.timers; - data.avgOwnTimePerCall = data.ownTimeTotal / data.callsTotal; - data.avgOwnTimePerTimer = data.ownTimeTotal / data.timers; - data.avgRunTimePerCall = data.runTimeTotal / data.callsTotal; - data.avgRunTimePerTimer = data.runTimeTotal / data.timers; - - return data; - }; - - /** - * Generate a report in text format. - * - * @returns {String} All the information gathered by the timers, as text. - */ - this.reportText = function () { - var data = this.reportData(), - timer, result = ''; - - if (!data.timers) { - return ''; - } - - for (var i = 0; i < data.timers; i++) { - timer = data.timerDetails[i]; - result += timer.name + ":\n" + - ' Avg ownTime / call: ' + timer.avgOwnTimePerCall + " ms\n" + - ' Avg runTime / call: ' + timer.avgRunTimePerCall + " ms\n" + - ' Calls: ' + timer.calls + "\n"+ - ' Max ownTime / call: ' + timer.maxOwnTimePerCall + " ms\n" + - ' Max runTime / call: ' + timer.maxRunTimePerCall + " ms\n" + - ' Min ownTime / call: ' + timer.minOwnTimePerCall + " ms\n" + - ' Min runTime / call: ' + timer.minRunTimePerCall + " ms\n" + - ' runTime: ' + timer.runTimeTotal + " ms\n" + - ' ownTime: ' + timer.ownTimeTotal + " ms\n\n"; - } - - result += "Overview info:\n" + - ' Avg calls / timer: ' + data.avgCallsPerTimer + "\n" + - ' Avg ownTime / call: ' + data.avgOwnTimePerCall + " ms\n" + - ' Avg ownTime / timer: ' + data.avgOwnTimePerTimer + " ms\n" + - ' Avg runTime / call: ' + data.avgRunTimePerCall + " ms\n" + - ' Avg runTime / timer: ' + data.avgRunTimePerTimer + " ms\n" + - ' Calls total: ' + data.callsTotal + "\n" + - ' Max calls / timer: ' + data.maxCallsPerTimer + ' (' + - data.maxCallsPerTimerName + ")\n" + - ' Max ownTime / call: ' + data.maxOwnTimePerCall + ' ms (' + - data.maxOwnTimePerCallName + ")\n" + - ' Max runTime / call: ' + data.maxRunTimePerCall + ' ms (' + - data.maxRunTimePerCallName + ")\n" + - ' Min calls / timer: ' + data.minCallsPerTimer + ' (' + - data.minCallsPerTimerName + ")\n" + - ' Min ownTime / call: ' + data.minOwnTimePerCall + ' ms (' + - data.minOwnTimePerCallName + ")\n" + - ' Min runTime / call: ' + data.minRunTimePerCall + ' ms (' + - data.minRunTimePerCallName + ")\n" + - ' Accumulated ownTime: ' + data.ownTimeTotal + " ms\n" + - ' Accumulated runTime: ' + data.runTimeTotal + " ms\n" + - ' Timers: ' + data.timers; - - return result; - }; - - /** - * Reset/clear all the timers. - */ - this.reset = function () { - this.timers = {}; - activeTimer_ = null; - timersStack_ = []; - }; -}; - -// vim:set spell spl=en fo=wan1croqlt tw=80 ts=2 sw=2 sts=2 sta et ai cin fenc=utf-8 ff=unix: - diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/includes/json2.js b/src/main/webapp/resources/lib/fims/biz/paintweb/includes/json2.js deleted file mode 100644 index 7e27df51..00000000 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/includes/json2.js +++ /dev/null @@ -1,478 +0,0 @@ -/* - http://www.JSON.org/json2.js - 2009-04-16 - - Public Domain. - - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - - See http://www.JSON.org/js.html - - This file creates a global JSON object containing two methods: stringify - and parse. - - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. - - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. - - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. - - This method produces a JSON text from a JavaScript value. - - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the object holding the key. - - For example, this would serialize Dates as ISO strings. - - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. - - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. - - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. - - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. - - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. - - Example: - - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' - - - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' - - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' - - - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. - - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. - - Example: - - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. - - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); - - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); - - - This is a reference implementation. You are free to copy, modify, or - redistribute. - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. -*/ - -/*jslint evil: true */ - -/*global JSON */ - -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ - -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. - -if (!this.JSON) { - JSON = {}; -} -(function () { - - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - if (typeof Date.prototype.toJSON !== 'function') { - - Date.prototype.toJSON = function (key) { - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function (key) { - return this.valueOf(); - }; - } - - var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - gap, - indent, - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }, - rep; - - - function quote(string) { - -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0; - return escapable.test(string) ? - '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' ? c : - '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : - '"' + string + '"'; - } - - - function str(key, holder) { - -// Produce a string from holder[key]. - - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; - -// If the value has a toJSON method, call it to obtain a replacement value. - - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } - -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. - - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } - -// What happens next depends on the value's type. - - switch (typeof value) { - case 'string': - return quote(value); - - case 'number': - -// JSON numbers must be finite. Encode non-finite numbers as null. - - return isFinite(value) ? String(value) : 'null'; - - case 'boolean': - case 'null': - -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - - return String(value); - -// If the type is 'object', we might be dealing with an object or an array or -// null. - - case 'object': - -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. - - if (!value) { - return 'null'; - } - -// Make an array to hold the partial results of stringifying this object value. - - gap += indent; - partial = []; - -// Is the value an array? - - if (Object.prototype.toString.apply(value) === '[object Array]') { - -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. - - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } - -// Join all of the elements together, separated with commas, and wrap them in -// brackets. - - v = partial.length === 0 ? '[]' : - gap ? '[\n' + gap + - partial.join(',\n' + gap) + '\n' + - mind + ']' : - '[' + partial.join(',') + ']'; - gap = mind; - return v; - } - -// If the replacer is an array, use it to select the members to be stringified. - - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - k = rep[i]; - if (typeof k === 'string') { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { - -// Otherwise, iterate through all of the keys in the object. - - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } - -// Join all of the member texts together, separated with commas, -// and wrap them in braces. - - v = partial.length === 0 ? '{}' : - gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + - mind + '}' : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } - -// If the JSON object does not yet have a stringify method, give it one. - - if (typeof JSON.stringify !== 'function') { - JSON.stringify = function (value, replacer, space) { - -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - if (/^[\],:{}\s]*$/. -test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). -replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). -replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - - j = eval('(' + text + ')'); - -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. - - return typeof reviver === 'function' ? - walk({'': j}, '') : j; - } - -// If the text is not JSON parseable, then a SyntaxError is thrown. - - throw new SyntaxError('JSON.parse'); - }; - } -}()); diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/lang/ko.js b/src/main/webapp/resources/lib/fims/biz/paintweb/korean.js similarity index 99% rename from src/main/webapp/resources/lib/fims/biz/paintweb/lang/ko.js rename to src/main/webapp/resources/lib/fims/biz/paintweb/korean.js index 6509a375..51c00c31 100644 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/lang/ko.js +++ b/src/main/webapp/resources/lib/fims/biz/paintweb/korean.js @@ -114,7 +114,9 @@ let lang_ko = { "selectionCrop": "자르기", "selectionFill": "가림막", - "selectionCopy": "번호판", + "selectionForNumberPlate": "번호판", + + "selectionCopy": "선택영역 복사", "selectionCut": "선택영역 잘라내기", "selectionDelete": "선택영역 삭제" }, diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/layout.xhtml b/src/main/webapp/resources/lib/fims/biz/paintweb/layout.js similarity index 98% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/layout.xhtml rename to src/main/webapp/resources/lib/fims/biz/paintweb/layout.js index 872ce4f4..b75f91f1 100644 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/layout.xhtml +++ b/src/main/webapp/resources/lib/fims/biz/paintweb/layout.js @@ -1,4 +1,4 @@ -

+let xhtml = `

PaintWeb

@@ -27,7 +27,7 @@
  •  
  • -
  • Selection
  • + @@ -36,7 +36,8 @@
  • 자르기
  • 가림막
  • -
  • 번호판
  • +
  • 번호판
  • + -
    +
    `; diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/paintweb-config.js b/src/main/webapp/resources/lib/fims/biz/paintweb/paintweb-config.js index b2979447..e8a77465 100644 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/paintweb-config.js +++ b/src/main/webapp/resources/lib/fims/biz/paintweb/paintweb-config.js @@ -7,14 +7,6 @@ let paintweb_config = { "lang": "ko", - "langFolder": "lang", - - /* - The graphical user interface you want to use. - @type String - @default "default" - */ - "gui": "default", /** * The folder contains all the interfaces. @@ -24,29 +16,6 @@ let paintweb_config = { */ "interfacesFolder": "interfaces", - /** - * The interface markup file. The file must be an XHTML valid document. - * - * @type String - * @default "layout.xhtml" - */ - "guiMarkup": "layout.xhtml", - - /** - * The interface style file. - * - * @type String - * @default "style.css" - */ - "guiStyle": "style.css", - - /** - * The interface script file. - * - * @type String - * @default script.js - */ - "guiScript": "script.js", /** * The image viewport width. Make sure the value is a CSS length, like "50%", @@ -69,7 +38,7 @@ let paintweb_config = { * @default "400px" * 672px */ - "viewportHeight": "82%", + "viewportHeight": "100%", /** * Image save quality for the JPEG format. @@ -77,7 +46,7 @@ let paintweb_config = { * @type Number * @default 0.9 */ - "jpegSaveQuality": 0.9, + "jpegSaveQuality": 1.0, /** * The default image width. @@ -611,14 +580,14 @@ let paintweb_config = { "Control Z": { "command": "historyUndo" }, "Control Y": { "command": "historyRedo" }, - // "Control N": { "command": "imageClear" }, + "Control N": { "command": "imageClear" }, //"Control A": { "command": "selectAll" }, //"Control X": { "command": "selectionCut" }, //"Shift Delete": { "command": "selectionCut" }, - //"Control C": { "command": "selectionCopy" }, - //"Control V": { "command": "clipboardPaste" }, + "Control C": { "command": "selectionCopy" }, + "Control V": { "command": "clipboardPaste" }, "Control S": { "command": "imageSave" } // Use "toolActivate": "id" to activate the tool with the given ID. diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/paintweb.js b/src/main/webapp/resources/lib/fims/biz/paintweb/paintweb.js index 3bcd4f37..d25057c5 100644 --- a/src/main/webapp/resources/lib/fims/biz/paintweb/paintweb.js +++ b/src/main/webapp/resources/lib/fims/biz/paintweb/paintweb.js @@ -503,29 +503,6 @@ function PaintWeb (win, doc) { temp_.onInit = handler; - // Check Canvas support. - if (!doc.createElement('canvas').getContext) { - this.initError(lang.noCanvasSupport); - return false; - } - - // Basic functionality used within the Web application. - if (!window.getComputedStyle) { - try { - if (!win.getComputedStyle(doc.createElement('div'), null)) { - this.initError(lang.noComputedStyle); - return false; - } - } catch (err) { - this.initError(lang.noComputedStyle); - return false; - } - } - - if (!window.XMLHttpRequest) { - this.initError(lang.noXMLHttpRequest); - return false; - } if (typeof this.config.guiPlaceholder !== 'object' || this.config.guiPlaceholder.nodeType !== this.ELEMENT_NODE) { @@ -540,42 +517,36 @@ function PaintWeb (win, doc) { } // JSON parser and serializer. - if (!window.JSON) { - this.scriptLoad(PaintWeb.baseFolder + 'includes/json2.js', - this.jsonlibReady); - } else { - this.jsonlibReady(); + pwlib = window.pwlib; + appEvent = pwlib.appEvent; + + // Create the custom application events object. + _self.events = new pwlib.appEvents(_self); + + + pwlib.extend(_self.config, paintweb_config); + + pwlib.extend(_self.lang, lang_ko); + + if (!(_self.initCanvas() && _self.initContext())) { + _self.initError(lang.errorInitCanvas); + return; } - return true; - }; - /** - * The load event handler for the JSON library script. - * @private - */ - this.jsonlibReady = function () { - if (window.pwlib) { - _self.pwlibReady(); - } else { - _self.scriptLoad(PaintWeb.baseFolder + 'includes/lib.js', - _self.pwlibReady); + _self.gui = new pwlib.gui(_self); + + if (!_self.gui.init(xhtml)) { + _self.initError(lang.errorInitGUI); + return; } - }; - /** - * The load event handler for the PaintWeb library script. - * @private - */ - this.pwlibReady = function () { - pwlib = window.pwlib; - appEvent = pwlib.appEvent; + _self.initTools(); - // Create the custom application events object. - _self.events = new pwlib.appEvents(_self); - _self.configLoad(); + return true; }; + /** * Report an initialization error. * @@ -622,84 +593,12 @@ function PaintWeb (win, doc) { } }; - /** - * Asynchronously load the configuration file. This method issues an - * XMLHttpRequest to load the JSON file. - * - * @private - * - * @see PaintWeb.config.configFile The configuration file. - * @see pwlib.xhrLoad The library function being used for creating the - * XMLHttpRequest object. - */ - this.configLoad = function () { - this.configReady(); - }; - - /** - * The configuration reader. This is the event handler for the XMLHttpRequest - * object, for the onreadystatechange event. - * - * @private - * - * @param {XMLHttpRequest} xhr The XMLHttpRequest object being handled. - * - * @see PaintWeb#configLoad The method which issues the XMLHttpRequest request - * for loading the configuration file. - */ - this.configReady = function (xhr) { - /* - * readyState values: - * 0 UNINITIALIZED open() has not been called yet. - * 1 LOADING send() has not been called yet. - * 2 LOADED send() has been called, headers and status are available. - * 3 INTERACTIVE Downloading, responseText holds the partial data. - * 4 COMPLETED Finished with all operations. - */ - var config = paintweb_config; - pwlib.extend(_self.config, config); - _self.langLoad(); - }; - /** - * Asynchronously load the language file. This method issues an XMLHttpRequest - * to load the JSON file. - * - * @private - * - * @see PaintWeb.config.lang The language you want for the PaintWeb user - * interface. - * @see pwlib.xhrLoad The library function being used for creating the - * XMLHttpRequest object. - */ - this.langLoad = function () { - this.langReady(); - }; - /** - * The language file reader. This is the event handler for the XMLHttpRequest - * object, for the onreadystatechange event. - * - * @private - * - * @param {XMLHttpRequest} xhr The XMLHttpRequest object being handled. - * - * @see PaintWeb#langLoad The method which issues the XMLHttpRequest request - * for loading the language file. - */ - this.langReady = function () { - pwlib.extend(_self.lang, lang_ko); - if (_self.initCanvas() && _self.initContext()) { - // Start GUI load now. - _self.guiLoad(); - } else { - _self.initError(lang.errorInitCanvas); - } - }; /** * Initialize the PaintWeb commands. @@ -711,21 +610,24 @@ function PaintWeb (win, doc) { this.initCommands = function () { if (this.commandRegister('historyUndo', this.historyUndo) && this.commandRegister('historyRedo', this.historyRedo) && - this.commandRegister('selectAll', this.selectAll) && - this.commandRegister('selectionCrop', this.selectionCrop) && + this.commandRegister('selectionCrop', this.selectionCrop) && this.commandRegister('selectionFill', this.selectionFill) && - //this.commandRegister('selectionCut', this.selectionCut) && - this.commandRegister('selectionCopy', this.selectionCopy) && - //this.commandRegister('clipboardPaste', this.clipboardPaste) && - this.commandRegister('imageSave', this.imageSave) && - this.commandRegister('imageRotate', this.imageRotate) && + this.commandRegister('selectionForNumberPlate', this.selectionForNumberPlate) && + this.commandRegister('imageRotate', this.imageRotate) && this.commandRegister('imageBright', this.imageBright) && this.commandRegister('imageDark', this.imageDark) && - //this.commandRegister('imageClear', this.imageClear) && - this.commandRegister('swapFillStroke', this.swapFillStroke) && - this.commandRegister('imageZoomIn', this.imageZoomIn) && + this.commandRegister('imageSave', this.imageSave) && + + this.commandRegister('imageZoomIn', this.imageZoomIn) && this.commandRegister('imageZoomOut', this.imageZoomOut) && - this.commandRegister('imageZoomReset', this.imageZoomReset)) { + this.commandRegister('imageZoomReset', this.imageZoomReset) && + + this.commandRegister('selectAll', this.selectAll) && + this.commandRegister('selectionCut', this.selectionCut) && + this.commandRegister('selectionCopy', this.selectionCopy) && + this.commandRegister('clipboardPaste', this.clipboardPaste) && + this.commandRegister('imageClear', this.imageClear) && + this.commandRegister('swapFillStroke', this.swapFillStroke)) { return true; } else { this.initError(lang.errorInitCommands); @@ -733,103 +635,8 @@ function PaintWeb (win, doc) { } }; - /** - * Load th PaintWeb GUI. This method loads the GUI markup file, the stylesheet - * and the script. - * - * @private - * - * @see PaintWeb.config.guiStyle The interface style file. - * @see PaintWeb.config.guiScript The interface script file. - * @see pwlib.gui The interface object. - */ - this.guiLoad = function () { - var cfg = this.config, - gui = this.config.gui, - base = PaintWeb.baseFolder + cfg.interfacesFolder + '/' + gui + '/', - style = base + cfg.guiStyle, - script = base + cfg.guiScript; - - this.styleLoad(gui + 'style', style); - - if (pwlib.gui) { - this.guiScriptReady(); - } else { - this.scriptLoad(script, this.guiScriptReady); - } - }; - - /** - * The load event handler for the PaintWeb GUI script. This - * method creates an instance of the GUI object that just loaded and starts - * loading the GUI markup. - * - * @private - * - * @see PaintWeb.config.guiScript The interface script file. - * @see PaintWeb.config.guiMarkup The interface markup file. - * @see pwlib.gui The interface object. - * @see pwlib.xhrLoad The library function being used for creating the - * XMLHttpRequest object. - */ - this.guiScriptReady = function () { - var cfg = _self.config, - gui = _self.config.gui, - base = cfg.interfacesFolder + '/' + gui + '/', - markup = base + cfg.guiMarkup; - - _self.gui = new pwlib.gui(_self); - - // Check if the interface markup is cached already. - if (markup in pwlib.fileCache) { - if (_self.gui.init(pwlib.fileCache[markup])) { - _self.initTools(); - } else { - _self.initError(lang.errorInitGUI); - } - - } else { - pwlib.xhrLoad(PaintWeb.baseFolder + markup, _self.guiMarkupReady); - } - }; - - /** - * The GUI markup reader. This is the event handler for the XMLHttpRequest - * object, for the onreadystatechange event. - * - * @private - * - * @param {XMLHttpRequest} xhr The XMLHttpRequest object being handled. - * - * @see PaintWeb#guiScriptReady The method which issues the XMLHttpRequest - * request for loading the interface markup file. - */ - this.guiMarkupReady = function (xhr) { - if (!xhr || xhr.readyState !== 4) { - return; - } - - if (xhr.status !== 304 && xhr.status !== 200) { - _self.initError(lang.failedMarkupLoad); - return; - } - var param; - /*if (xhr.responseXML && xhr.responseXML.documentElement) { // by gu - param = xhr.responseXML; - } else */if (xhr.responseText) { - param = xhr.responseText; - } else { - _self.initError(lang.failedMarkupLoad); - return; - } - if (_self.gui.init(param)) { - _self.initTools(); - } else { - _self.initError(lang.errorInitGUI); - } - }; /** * Initialize the Canvas elements. This method creates the elements and @@ -1084,8 +891,11 @@ function PaintWeb (win, doc) { } this.initialized = PaintWeb.INIT_DONE; - + + //this.toolActivate("selection"); + this.events.dispatch(new appEvent.appInit(this.initialized)); + }; /** @@ -2424,41 +2234,6 @@ function PaintWeb (win, doc) { xhr.send(''); }; - /** - * Insert a stylesheet into the document. - * - * @param {String} id The stylesheet ID. This is used to avoid inserting the - * same style in the document. - * @param {String} url The URL of the stylesheet you want to insert. - * @param {String} [media='screen, projection'] The media attribute. - * @param {Function} [handler] The load event handler. - */ - this.styleLoad = function (id, url, media, handler) { - id = 'paintweb_style_' + id; - - var elem = doc.getElementById(id); - if (elem) { - return; - } - - if (!media) { - media = 'screen, projection'; - } - - elem = doc.createElement('link'); - - if (handler) { - elem.addEventListener('load', handler, false); - } - - elem.id = id; - elem.rel = 'stylesheet'; - elem.type = 'text/css'; - elem.media = media; - elem.href = url; - - this.elems.head.appendChild(elem); - }; /** * Perform action undo. @@ -2740,8 +2515,9 @@ function PaintWeb (win, doc) { bufferCanvas = _self.buffer.canvas, bufferCtx = _self.buffer.context, img = _self.image; - var bufferStyle = _self.buffer.canvas.style, - layerStyle = layerCanvas.style; + + var bufferStyle = _self.buffer.canvas.style; + var layerStyle = layerCanvas.style; var srcCanvas = doc.createElement('canvas'); @@ -2766,16 +2542,11 @@ function PaintWeb (win, doc) { img.width = layerCanvas.width; img.height = layerCanvas.height; - _self.events.dispatch(new appEvent.imageSizeChange(layerCanvas.width, layerCanvas.height)); - bufferStyle.width = layerStyle.width = layerCanvas.width + 'px'; - bufferStyle.height = layerStyle.height = layerCanvas.height + 'px'; - - _self.events.dispatch(new appEvent.canvasSizeChange(layerCanvas.width, layerCanvas.height, img.canvasScale)); - - var zoom = _self.image.zoom; - _self.image.zoom=1; - _self.imageZoomTo(zoom); + bufferStyle.width = layerStyle.width = (layerCanvas.width * img.canvasScale) + 'px'; + bufferStyle.height = layerStyle.height = (layerCanvas.height * img.canvasScale) + 'px'; + + _self.events.dispatch(new appEvent.canvasSizeChange(bufferCanvas.width * img.canvasScale, bufferCanvas.height * img.canvasScale, img.canvasScale)); return true; }; @@ -2965,6 +2736,14 @@ function PaintWeb (win, doc) { } }; + this.selectionForNumberPlate = function (ev) { + if (!_self.tool || _self.tool._id !== 'selection') { + return false; + } else { + return _self.tool.selectionForNumberPlate(ev); + } + }; + /** * Paste the current clipboard image. This only works when some ImageData is * available in {@link PaintWeb#clipboard}. diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/includes/lib.js b/src/main/webapp/resources/lib/fims/biz/paintweb/pwlib.js similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/includes/lib.js rename to src/main/webapp/resources/lib/fims/biz/paintweb/pwlib.js diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/bcurve.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/bcurve.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/bcurve.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/bcurve.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/cbucket.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/cbucket.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/cbucket.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/cbucket.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/clipboardPaste.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/clipboardPaste.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/clipboardPaste.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/clipboardPaste.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/cpicker.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/cpicker.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/cpicker.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/cpicker.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/ellipse.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/ellipse.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/ellipse.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/ellipse.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/eraser.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/eraser.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/eraser.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/eraser.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/hand.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/hand.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/hand.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/hand.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/help.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/help.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/help.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/help.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/historyRedo.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/historyRedo.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/historyRedo.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/historyRedo.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/historyUndo.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/historyUndo.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/historyUndo.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/historyUndo.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/i_addPhoto.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_addPhoto.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/i_addPhoto.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_addPhoto.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/i_block.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_block.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/i_block.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_block.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/i_cancel.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_cancel.png similarity index 100% rename from src/main/webapp/resources/lib/fims/biz/paintweb/interfaces/default/icons/i_cancel.png rename to src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_cancel.png diff --git a/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_carnumber.png b/src/main/webapp/resources/lib/fims/biz/paintweb/style/icons/i_carnumber.png new file mode 100644 index 0000000000000000000000000000000000000000..f89e8bcd9c0af116f87a3e29cae8f7139b61dd16 GIT binary patch literal 41493 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 p|MK&gp$ab2R$W{pbbW_Ig7pE$s$vThis method invokes the {@link this#selectionMerge} and {@link + * PaintWeb#imageCrop} methods. + * + * @returns {Boolean} True if the operation was successful, or false if not. + */ + this.selectionForNumberPlate = function () { + if (_self.state !== _self.STATE_SELECTED) { + return false; + } + + _self.selectionMerge(); + + var w = sel.width, + h = sel.height, + sumX = sel.x + w, + sumY = sel.y + h; + + if (sumX > image.width) { + w -= sumX - image.width; + } + if (sumY > image.height) { + h -= sumY - image.height; + } + + app.imageCrop(sel.x, sel.y, w, h); + + isNumberPlate = true; + return true; }; @@ -1426,16 +1468,13 @@ pwlib.tools.selection = function (app) { case config.keys.selectionCrop: return _self.selectionCrop(ev); + case config.keys.selectionFill: + return _self.selectionFill(ev); case config.keys.selectionDelete: return _self.selectionDelete(ev); - case config.keys.selectionDrop: return _self.selectionDrop(ev); - - case config.keys.selectionFill: - return _self.selectionFill(ev); - default: return false; }