diff --git a/plugin/editor/cheditor5/cheditor.js b/plugin/editor/cheditor5/cheditor.js
index 7321de001..9e39e3408 100644
--- a/plugin/editor/cheditor5/cheditor.js
+++ b/plugin/editor/cheditor5/cheditor.js
@@ -1,9 +1,9 @@
// ================================================================
-// CHEditor 5.1.9.3
+// CHEditor 5.1.9.3-p4
// ----------------------------------------------------------------
// Homepage: http://www.chcode.com
// EMail: support@chcode.com
-// Copyright (c) 1997-2016 CHSOFT
+// Copyright (c) 1997-2020 CHSOFT
// ================================================================
var GB = {
colors: ['#000000','#313131','#434343','#535353','#666666','#999999','#a0a0a0','#b5b5b5','#c0c0c0','#dcdcdc','#eeeeee','#ffffff',
@@ -517,7 +517,7 @@ function setConfig() {
useModifyTable : true,
useMap : true,
useTextBlock : true,
- useFullScreen : true,
+ useFullScreen : false,
usePageBreak : false
},
base, elem, i, editorUri, locationAbs;
@@ -557,9 +557,9 @@ function setConfig() {
this.currentRS = {};
this.resizeEditor = {};
this.setFullScreenMode = false;
- this.modalElementZIndex = 1001;
+ this.modalElementZIndex = 10001;
this.config = config;
- this.templateFile = 'template.xml';
+ this.templateFile = this.undefined(this.browser.mobile) ? 'template.xml' : 'template-mobile.xml';
this.templatePath = config.editorPath + this.templateFile;
this.W3CRange = !(this.undefined(window.getSelection));
this.inputForm = 'textAreaId';
@@ -1082,31 +1082,10 @@ cheditor.prototype = {
showError('현재 브라우저에서 ' + self.templateFile + ' 파일을 사용할 수 없습니다.');
}
},
-/*
- getCDATASection : function (node) {
- var elem, data;
- if (node.hasChildNodes()) {
- elem = node.firstChild;
- while (elem && elem.nodeType !== GB.node.cdata_section) {
- elem = elem.nextSibling;
- }
- if (elem && elem.nodeType === GB.node.cdata_section) {
- data = elem.data;
- data = data.replace(/\n/g, '');
- data = data.replace(/(\s+?)<([^>]*)>/g, '<$2>');
- data = this.trimSpace(data);
- return data;
- }
- }
- return null;
- },
-*/
+
getCDATASection : function (node) {
var text = node.textContent || node.text;
- text = text.replace(/\n/g, '');
- text = text.replace(/(\s+?)<([^>]*)>/g, '<$2>');
- text = this.trimSpace(text);
- return text;
+ return this.trimSpace(text.replace(/\n/g, '').replace(/(\s+?)<([^>]*)>/g, '<$2>'));
},
setToolbarBgPosition : function (elem, attr) {
@@ -2044,7 +2023,7 @@ cheditor.prototype = {
container.style.width = self.config.editorWidth;
self.cheditor.container = container;
},
-/*
+
loadTemplate : function (xmlDoc) {
var self = this,
tmpl = xmlDoc.getElementsByTagName('Template').item(0),
@@ -2091,55 +2070,6 @@ cheditor.prototype = {
self.cheditor.htmlEditable.style.visibility = 'hidden';
container.appendChild(self.cheditor.htmlEditable);
},
-*/
-
- loadTemplate : function (xmlDoc) {
- var cdata, container, dragHandle, html, modalFrame, popupWindow, tmpDiv, tmpl, toolbar;
- tmpl = xmlDoc.getElementsByTagName('Template').item(0);
- if (!tmpl) {
- throw 'Template 노드를 설정할 수 없습니다.';
- }
- cdata = tmpl.getElementsByTagName('Container').item(0).getElementsByTagName('Html').item(0);
- if (!cdata) {
- throw 'XML CDATA 오류';
- }
- html = this.getCDATASection(cdata);
- tmpDiv = document.createElement('div');
- tmpDiv.innerHTML = html;
- container = tmpDiv.firstChild;
-
- toolbar = tmpl.getElementsByTagName('Toolbar').item(0);
- this.createEditorElement(container, toolbar);
-
- cdata = tmpl.getElementsByTagName('PopupWindow').item(0).getElementsByTagName('Html').item(0);
- if (!cdata) {
- throw 'XML CDATA 오류';
- }
- html = this.getCDATASection(cdata);
- tmpDiv.innerHTML = html;
- popupWindow = tmpDiv.firstChild;
- this.cheditor.popupElem = popupWindow;
-
- dragHandle = popupWindow.firstChild;
- this.cheditor.dragHandle = dragHandle;
- this.cheditor.popupTitle = dragHandle.getElementsByTagName('label')[0];
- this.cheditor.popupFrameWrapper = dragHandle.nextSibling;
- container.appendChild(popupWindow);
-
- modalFrame = document.createElement('div');
- modalFrame.className = 'cheditor-modalPopupTransparent';
- this.cheditor.modalBackground = modalFrame;
- this.cheditor.modalBackground.id = 'popupModalBackground';
- this.cheditor.modalBackground.className = 'cheditor-popupModalBackground';
- container.parentNode.insertBefore(modalFrame, container);
-
- this.cheditor.htmlEditable = document.createElement('iframe');
- this.cheditor.htmlEditable.style.display = 'none';
- this.cheditor.htmlEditable.style.width = '1px';
- this.cheditor.htmlEditable.style.height = '1px';
- this.cheditor.htmlEditable.style.visibility = 'hidden';
- container.appendChild(this.cheditor.htmlEditable);
- },
imageEvent : function (img, action) {
var self = this,
@@ -5063,7 +4993,12 @@ cheditor.prototype = {
if (!(this.undefined(GB.popupWindow[popupName]))) {
var popup = GB.popupWindow[popupName];
if (popupName === 'ImageUpload' && window.File && window.FileReader && window.FileList && window.Blob) {
- popup.tmpl = 'image.html5.html';
+ if (this.browser.mobile) {
+ popup.tmpl = 'image.html5.m.html';
+ popup.width = 450; // 팝업 윈도우 가로 폭 크기(px)
+ } else {
+ popup.tmpl = 'image.html5.html';
+ }
}
this.popupWinLoad(popup);
} else {
diff --git a/plugin/editor/cheditor5/css/imageupload.css b/plugin/editor/cheditor5/css/imageupload.css
index 0589dd629..6efb56a84 100644
--- a/plugin/editor/cheditor5/css/imageupload.css
+++ b/plugin/editor/cheditor5/css/imageupload.css
@@ -133,4 +133,15 @@ body {
line-height: 1em;
font-family: 'Malgun Gothic', gulim, tahoma, helvetica;
font-size: 12px;
+}
+
+.webgl_logo_wrapper {
+ text-align: center;
+ margin-top: 40px;
+ border-top: #cccccc 1px solid;
+}
+.webgl_logo_wrapper img {
+ width: 50px;
+ height: 50px;
+ vertical-align: middle;
}
\ No newline at end of file
diff --git a/plugin/editor/cheditor5/css/imageupload.m.css b/plugin/editor/cheditor5/css/imageupload.m.css
new file mode 100644
index 000000000..11d2ed5b8
--- /dev/null
+++ b/plugin/editor/cheditor5/css/imageupload.m.css
@@ -0,0 +1,136 @@
+#uploadWindow {
+ display: none;
+}
+
+.clear { clear: both; }
+
+#container {
+ padding: 0;
+}
+
+.imageListWrapperHtml5, .imageListWrapper, .dragOver {
+ background-color: #fff;
+ position: absolute;
+ height: 250px;
+ width: 255px;
+ overflow-y: scroll;
+ border-radius: 4px;
+ border: 2px #66b2ff solid;
+}
+/* .imageListWrapperHtml5 {
+ border: 2px #66b2ff dashed;
+} */
+.imageListWrapper {
+ border: 1px #aaa solid;
+ box-shadow: 0 0 3px #aaa;
+}
+.dragOver {
+ border: 2px #ff3399 dashed;
+}
+#imageInfoBox {
+ position: absolute;
+ left: 300px;
+}
+.imageInfoTitle {
+ text-align: center;
+ background-color: #e0e0e0;
+ width: 130px;
+ font-family: "Malgun Gothic",gulim;
+ font-weight: bold;
+ font-size: 12px;
+}
+.imageInfoTitle span {
+ display: inline-block;
+ margin-top: -1px;
+ line-height: 22px;
+}
+.remove-button {
+ width: 93px;
+ height: 22px;
+ cursor: pointer;
+ vertical-align: middle;
+}
+.imageBox, .imageBoxHighlighted {
+ width: 120px;
+ height: 90px;
+ margin: 3px 3px;
+ float: left;
+}
+.imageBox_theImage,.imageBox_theImage_over {
+ width: 100%;
+ height: 100%;
+ position: relative;
+ display: block;
+ background-color: #fff;
+}
+.imageBox .imageBox_theImage{
+ border: 1px solid #e0e0e0;
+ background-image: url('../icons/dot.gif');
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.imageBox .imageBox_theImage_over {
+ border: 1px solid #a0a0a0;
+ background-image: url('../icons/dot.gif');
+ background-position: center center;
+ background-repeat: no-repeat;
+ cursor: pointer;
+}
+.imageBoxHighlighted .imageBox_theImage {
+ border: 1px solid #ff6600;
+}
+.imageBoxHighlighted .imageBox_theImage_over {
+ border: 1px solid #ff6600;
+ background-image: url('../icons/dot.gif');
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+
+.removeButton, .removeButton_over {
+ display: none;
+ position: absolute;
+ cursor: pointer;
+ background-image: url(../icons/imageUpload/cross-small.png);
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+.removeButton {
+ border: 1px solid #a0a0a0;
+}
+.removeButton_over {
+ border: 1px solid #808080;
+}
+#insertionMarker {
+ height: 102px;
+ width: 6px;
+ position: absolute;
+ display: none;
+}
+
+#insertionMarker img {
+ float: left;
+}
+
+#dragDropContent{
+ position: absolute;
+ z-index: 10;
+ display: none;
+}
+
+.button {
+ width: 64px;
+ height: 22px;
+ margin: 0 2px;
+ cursor: pointer;
+ vertical-align: middle;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ background-color: #fff;
+ line-height: 1em;
+ font-family: 'Malgun Gothic', gulim, tahoma, helvetica;
+ font-size: 12px;
+}
\ No newline at end of file
diff --git a/plugin/editor/cheditor5/css/ui.css b/plugin/editor/cheditor5/css/ui.css
index 2273f4034..060335500 100644
--- a/plugin/editor/cheditor5/css/ui.css
+++ b/plugin/editor/cheditor5/css/ui.css
@@ -14,6 +14,8 @@ a.cheditor-tag-path-elem:hover {
border-top: 1px #ccc solid;
position: relative;
text-align: left;
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box;
}
.cheditor-tb-wrapper {
border-right: 1px #ccc solid;
@@ -21,11 +23,10 @@ a.cheditor-tag-path-elem:hover {
border-bottom: 1px #ccc solid;
position: relative;
display: block;
+ -webkit-box-sizing: inherit;
+ box-sizing: inherit;
background-color: #f0f0f0;
- zoom:1;
- height:auto ! important;
}
-.cheditor-tb-wrapper:after{display:block;visibility:hidden;clear:both;content:""}
.cheditor-tb-wrapper-readonly {
border-right: 1px #ccc solid;
border-left: 1px #ccc solid;
@@ -423,6 +424,8 @@ a.cheditor-tag-path-elem:hover {
box-shadow: 0 0 10px #bbb;
padding: 0;
overflow: hidden;
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box;
}
.cheditor-popup-cmd-button {
width: 64px;
@@ -437,6 +440,8 @@ a.cheditor-tag-path-elem:hover {
padding: 10px;
border: none;
text-align: center;
+ -webkit-box-sizing: content-box;
+ box-sizing: content-box;
}
.cheditor-popup-cframe iframe {
diff --git a/plugin/editor/cheditor5/icons/imageUpload/webgl-off.png b/plugin/editor/cheditor5/icons/imageUpload/webgl-off.png
new file mode 100644
index 000000000..71adb4872
Binary files /dev/null and b/plugin/editor/cheditor5/icons/imageUpload/webgl-off.png differ
diff --git a/plugin/editor/cheditor5/icons/imageUpload/webgl.png b/plugin/editor/cheditor5/icons/imageUpload/webgl.png
new file mode 100644
index 000000000..a5501de9a
Binary files /dev/null and b/plugin/editor/cheditor5/icons/imageUpload/webgl.png differ
diff --git a/plugin/editor/cheditor5/popup/image.html5.html b/plugin/editor/cheditor5/popup/image.html5.html
index c5f0f9b85..ed91fd34e 100644
--- a/plugin/editor/cheditor5/popup/image.html5.html
+++ b/plugin/editor/cheditor5/popup/image.html5.html
@@ -6,7 +6,7 @@
-
+
@@ -65,9 +65,7 @@
사진 여백 넣기
-
- (전체 사진에 적용됨)
-
+
diff --git a/plugin/editor/cheditor5/popup/image.html5.m.html b/plugin/editor/cheditor5/popup/image.html5.m.html
new file mode 100644
index 000000000..0e88dd423
--- /dev/null
+++ b/plugin/editor/cheditor5/popup/image.html5.m.html
@@ -0,0 +1,78 @@
+
+
+
+ CHEditor
+
+
+
+
+
+
+
+
+
+
+

+
+

+
0장 / 최대 장 사진
+
+
+
+
+
크기 줄이기
+
+
+
가로:
+
+
픽셀
+
+ 입력:
+
+ 픽셀
+
+
+
사진 높이는 자동으로 설정됩니다.
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugin/editor/cheditor5/popup/js/fragment-shader.glsl b/plugin/editor/cheditor5/popup/js/fragment-shader.glsl
new file mode 100644
index 000000000..b344ffd17
--- /dev/null
+++ b/plugin/editor/cheditor5/popup/js/fragment-shader.glsl
@@ -0,0 +1,75 @@
+// -------------------------------------------------------
+// CHEditor WebGL Fragment Shader
+// -------------------------------------------------------
+precision highp float;
+
+uniform sampler2D u_image;
+uniform vec2 u_resolution;
+uniform vec2 u_srcResolution;
+
+vec4 getTextureColor(vec2 loc) {
+ return texture2D(u_image, loc / u_srcResolution);
+}
+
+void main() {
+ vec2 ratio = u_srcResolution / u_resolution;
+ vec2 ratioHalf = ceil(ratio / 1.0);
+ vec2 loc = gl_FragCoord.xy;
+
+ loc.y = u_resolution.y - loc.y;
+
+ float weight = 0.0;
+ float weights = 0.0;
+ float weights_alpha = 0.0;
+ vec3 gx_rgb = vec3(0.0);
+ float gx_a = 0.0;
+ float center_y = (loc.y + 0.5) * ratio.y;
+
+ float y = floor(loc.y * ratio.y);
+ float y_length = (loc.y + 1.0) * ratio.y;
+
+ for (int i = 0; i < 5000; i++) {
+ if (y >= y_length) {
+ break;
+ }
+ float dy = abs(center_y - (y + 0.5)) / ratioHalf.y;
+ float center_x = (loc.x + 0.5) * ratio.x;
+ float part_w = dy * dy;
+ float x = floor(loc.x * ratio.x);
+ float x_length = (loc.x + 1.0) * ratio.x;
+
+ for (int j = 0; j < 5000; j++) {
+ if (x >= x_length) {
+ break;
+ }
+
+ float dx = abs(center_x - (x + 0.5)) / ratioHalf.x;
+ float w = sqrt(part_w + dx * dx);
+
+ if (w >= -1.0 && w <= 1.0) {
+ // Hermite 필터
+ weight = 2.0 * w * w * w - 3.0 * w * w + 1.0;
+ if (weight > 0.0) {
+ vec4 pixel = getTextureColor(vec2(x, y)) * 255.0;
+
+ // 알파 채널
+ gx_a += weight * pixel.a;
+ weights_alpha += weight;
+
+ if (pixel.a < 255.0) {
+ weight = weight * pixel.a / 250.0;
+ }
+ gx_rgb += weight * pixel.rgb;
+ weights += weight;
+ }
+ }
+ x++;
+ }
+ y++;
+ }
+
+ gx_rgb = (gx_rgb / weights) / 255.0;
+ gx_a = (gx_a / weights_alpha) / 255.0;
+
+ gl_FragColor = vec4(gx_rgb, gx_a);
+}
diff --git a/plugin/editor/cheditor5/popup/js/image.html5.js b/plugin/editor/cheditor5/popup/js/image.html5.js
index fc97d6cd0..37b9a4559 100644
--- a/plugin/editor/cheditor5/popup/js/image.html5.js
+++ b/plugin/editor/cheditor5/popup/js/image.html5.js
@@ -1,6 +1,7 @@
// ================================================================
// CHEditor 5
// ================================================================
+
var activeImage = null,
browser = null,
button,
@@ -29,14 +30,160 @@ var activeImage = null,
offsetX_marker = -3,
offsetY_marker = -3,
readyToMove = false,
- selectedFilesNum = 0,
showThumbnailSize = { width: 120, height: 90 },
tmpLeft = 0,
tmpTop = 0,
uploadImagePath = '',
uploadMaxNumber = 12,
- uploadScript;
-// deleteScript;
+ uploadScript,
+ useWebGL = false;
+
+if (ArrayBuffer && !ArrayBuffer.prototype.slice) {
+ ArrayBuffer.prototype.slice = function (start, end) {
+ var len = this.byteLength;
+ start || isFinite(start) && 0 < start && start < len || (start = 0);
+ end || (isFinite(end && start < end && end < len) || (end = len - 1));
+ return new DataView(this, start, end).buffer;
+ };
+}
+
+function GLScale(options) {
+ if (!(this instanceof GLScale)) {
+ return new GLScale(options);
+ }
+ this.precompile(options);
+ return this.scale.bind(this);
+}
+
+GLScale.prototype.precompile = function (options) {
+ var ctxOptions, vertex, fragment, resolutionLocation, positionLocation;
+
+ this.canvas = document.createElement('canvas');
+ this.canvas.width = options.width;
+ this.canvas.height = options.height;
+
+ ctxOptions = {preserveDrawingBuffer: true};
+ this.gl = this.canvas.getContext('webgl', ctxOptions) || this.canvas.getContext('experimental-webgl', ctxOptions);
+
+ if (!this.gl) {
+ throw new Error('Could not initialize webgl context');
+ }
+
+ vertex = GLScale.compileShader(this.gl, GLScale.Hermite.vertex, this.gl.VERTEX_SHADER);
+ fragment = GLScale.compileShader(this.gl, GLScale.Hermite.fragment, this.gl.FRAGMENT_SHADER);
+
+ this.program = GLScale.createProgram(this.gl, vertex, fragment);
+ this.gl.useProgram(this.program);
+
+ this.gl.bindTexture(this.gl.TEXTURE_2D, this.gl.createTexture());
+
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
+
+ resolutionLocation = this.gl.getUniformLocation(this.program, 'u_resolution');
+ this.gl.uniform2f(resolutionLocation, options.width, options.height);
+
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.gl.createBuffer());
+ positionLocation = this.gl.getAttribLocation(this.program, 'a_position');
+ this.gl.enableVertexAttribArray(positionLocation);
+ this.gl.vertexAttribPointer(positionLocation, 2, this.gl.FLOAT, false, 0, 0);
+};
+
+GLScale.prototype.scale = function (image, cb) {
+ var srcResolutionLocation;
+ if (typeof image === 'string') {
+ return this.loadImage(image, function (err, image) {
+ if (!err) {
+ return this.scale(image, cb);
+ }
+ });
+ }
+
+ this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);
+
+ srcResolutionLocation = this.gl.getUniformLocation(this.program, 'u_srcResolution');
+ this.gl.uniform2f(srcResolutionLocation, image.width, image.height);
+
+ this.setRectangle(0, 0, image.width, image.height);
+ this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
+ this.gl.finish();
+
+ if (cb) {
+ cb(this.canvas);
+ }
+ return this;
+};
+
+GLScale.prototype.setRectangle = function (x, y, width, height) {
+ var x1 = x,
+ x2 = x + width,
+ y1 = y,
+ y2 = y + height;
+
+ this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
+ x1, y1,
+ x2, y1,
+ x1, y2,
+ x1, y2,
+ x2, y1,
+ x2, y2
+ ]), this.gl.STATIC_DRAW);
+};
+
+GLScale.loadImage = function (url, cb) {
+ var image = new Image();
+ image.onload = cb.bind(this, null, image);
+ image.onerror = cb.bind(this);
+ image.src = url;
+ return this;
+};
+GLScale.prototype.loadImage = GLScale.loadImage;
+
+GLScale.toBlob = (function toBlob() {
+ var CanvasPrototype = window.HTMLCanvasElement.prototype;
+
+ if (CanvasPrototype.toBlob) {
+ return CanvasPrototype.toBlob;
+ }
+
+ return function (callback, type, quality) {
+ var binStr = atob(this.toDataURL(type, quality).split(',')[1]),
+ len = binStr.length,
+ arr = new Uint8Array(len), i = 0;
+
+ for (; i < len; i++) {
+ arr[i] = binStr.charCodeAt(i);
+ }
+ callback(new Blob([arr], {type: type || 'image/png'}));
+ };
+})();
+
+GLScale.compileShader = function (gl, shaderSource, shaderType) {
+ var shader = gl.createShader(shaderType);
+
+ gl.shaderSource(shader, shaderSource);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ throw new Error('Could not compile shader: ' + gl.getShaderInfoLog(shader));
+ }
+ return shader;
+};
+
+GLScale.createProgram = function (gl, vertexShader, fragmentShader) {
+ var program = gl.createProgram();
+
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ gl.linkProgram(program);
+
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ throw new Error('Program failed to link: ' + gl.getProgramInfoLog (program));
+ }
+ return program;
+};
function createInsertionMaker() {
var wrapper = document.getElementById('insertionMarker'),
@@ -76,7 +223,7 @@ function showContents() {
spacerNo = 1, i, imgBox, theImg, lastSpacer;
for (i = 0; i < uploadMaxNumber; i++) {
- if (i > 0 && ((i % 4) === 0)) {
+ if (i > 0 && i % 4 === 0) {
imageListWrapper.appendChild(spacer(spacerNo++));
}
@@ -89,7 +236,7 @@ function showContents() {
imgBox.appendChild(theImg);
imageListWrapper.appendChild(imgBox);
- if (i === (uploadMaxNumber - 1)) {
+ if (i === uploadMaxNumber - 1) {
lastSpacer = spacer(spacerNo);
lastSpacer.style.height = "7px";
imageListWrapper.appendChild(lastSpacer);
@@ -130,7 +277,7 @@ function getTopPos(inputObj) {
inputObj = inputObj.offsetParent;
while (inputObj) {
if (inputObj.tagName.toLowerCase() !== 'html') {
- returnValue += (inputObj.offsetTop - inputObj.scrollTop);
+ returnValue += inputObj.offsetTop - inputObj.scrollTop;
if (browser.msie) {
returnValue += inputObj.clientTop;
}
@@ -182,7 +329,7 @@ function reOrder() {
imgBox[i].className = 'imageBox';
imgBox[i].firstChild.className = 'imageBox_theImage';
- if (imgNum > 0 && (imgNum % 4) === 0) {
+ if (imgNum > 0 && imgNum % 4 === 0) {
breakline.push(imgBox[i].id);
}
@@ -199,28 +346,6 @@ function reOrder() {
}
}
-function img_delete_post(el){
- if( el.firstChild.tagName.toLowerCase() === 'img' ){
- var src = el.firstChild.getAttribute('src'),
- filesrc = src.replace(/^.*[\\\/]/, ''),
- data = "filesrc="+filesrc;
-
- var xhr = new XMLHttpRequest();
- xhr.open('POST', deleteScript, true);
- //Send the proper header information along with the request
- xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
-
- xhr.addEventListener("error", function (evt) {
- try {
- console.log("파일 전송 중 오류: " + evt.target.error.code);
- } catch(ex) {
- }
- }, false);
-
- xhr.send(data);
- }
-}
-
function showDelete() {
var self = this, btn;
@@ -231,7 +356,7 @@ function showDelete() {
getDivCoordinates();
self.className = 'imageBox_theImage_over';
btn = document.getElementById('removeImageButton');
- btn.style.left = (showThumbnailSize.width - parseInt(btn.style.width, 10) - 1) + 'px';
+ btn.style.left = showThumbnailSize.width - parseInt(btn.style.width, 10) - 1 + 'px';
btn.style.top = '-1px';
self.appendChild(btn);
@@ -250,7 +375,6 @@ function showDelete() {
var images = self.getElementsByTagName('img'), i, moveobj, target;
for (i = 0; i < images.length; i++) {
- img_delete_post(self);
self.removeChild(images[i]);
}
@@ -279,6 +403,7 @@ function showDelete() {
this.style.display = 'none';
document.body.appendChild(ev.target);
oEditor.removeEvent(self, 'mouseover', showDelete);
+ self.removeAttribute('title');
};
}
@@ -318,16 +443,16 @@ function imgComplete(img, imgSize, boxId) {
if (imgSize.width > showThumbnailSize.width || imgSize.height > showThumbnailSize.height) {
if (imgSize.width > imgSize.height) {
- resizeW = (imgSize.width > showThumbnailSize.width) ? showThumbnailSize.width : imgSize.width;
- resizeH = Math.round((imgSize.height * resizeW) / imgSize.width);
+ resizeW = imgSize.width > showThumbnailSize.width ? showThumbnailSize.width : imgSize.width;
+ resizeH = Math.round(imgSize.height * resizeW / imgSize.width);
} else {
- resizeH = (imgSize.height > showThumbnailSize.height) ? showThumbnailSize.height : imgSize.height;
- resizeW = Math.round((imgSize.width * resizeH) / imgSize.height);
+ resizeH = imgSize.height > showThumbnailSize.height ? showThumbnailSize.height : imgSize.height;
+ resizeW = Math.round(imgSize.width * resizeH / imgSize.height);
}
if (resizeH > showThumbnailSize.height) {
- resizeH = (imgSize.height > showThumbnailSize.height) ? showThumbnailSize.height : imgSize.height;
- resizeW = Math.round((imgSize.width * resizeH) / imgSize.height);
+ resizeH = imgSize.height > showThumbnailSize.height ? showThumbnailSize.height : imgSize.height;
+ resizeW = Math.round(imgSize.width * resizeH / imgSize.height);
}
} else {
@@ -357,6 +482,7 @@ function imgComplete(img, imgSize, boxId) {
}
elem.style.backgroundImage = "url('" + uploadImagePath + "/dot.gif')";
+ setElemTitle(elem, imgSize.width, imgSize.height);
oEditor.addEvent(elem, 'mouseover', showDelete);
elem.onmouseout = function () {
this.className = 'imageBox_theImage';
@@ -366,26 +492,30 @@ function imgComplete(img, imgSize, boxId) {
setImageCount();
}
+function setElemTitle(elem, width, height) {
+ elem.setAttribute('title', 'Width: ' + width + 'px, Height: ' + height + 'px');
+}
+
function showUploadWindow() {
// ----------------------------------------------------------------------------------
var uploadWindow = document.getElementById("uploadWindow"),
uploadWindowWidth = 700,
winWidth, el, i, j, imgBox, img;
- if (!(oEditor.undefined(window.innerWidth))) {
+ if (!oEditor.undefined(window.innerWidth)) {
winWidth = window.innerWidth;
} else if (document.documentElement &&
- (!(oEditor.undefined(document.documentElement.clientWidth))) &&
+ !oEditor.undefined(document.documentElement.clientWidth) &&
document.documentElement.clientWidth !== 0) {
winWidth = document.documentElement.clientWidth;
- } else if (document.body && (!(oEditor.undefined(document.body.clientWidth)))) {
+ } else if (document.body && !oEditor.undefined(document.body.clientWidth)) {
winWidth = document.body.clientWidth;
} else {
alert('현재 브라우저를 지원하지 않습니다.');
return;
}
- uploadWindow.style.left = winWidth / 2 - (uploadWindowWidth / 2) + 'px';
+ uploadWindow.style.left = winWidth / 2 - uploadWindowWidth / 2 + 'px';
uploadWindow.style.display = "block";
uploadWindow.style.width = uploadWindowWidth + 'px';
@@ -401,11 +531,9 @@ function showUploadWindow() {
if (imgBox.className !== 'imageBox_theImage') {
continue;
}
-
- if (imgBox.firstChild && (imgBox.firstChild.src === modifyImages[i])) {
+ if (imgBox.firstChild && imgBox.firstChild.src === modifyImages[i]) {
break;
}
-
if (imgBox.firstChild === null) {
img = new Image();
img.src = modifyImages[i];
@@ -439,11 +567,11 @@ function removeImages() {
remove = img.getElementsByTagName('img');
for (j = 0; j < remove.length; j++) {
- img_delete_post(img);
img.removeChild(remove[j]);
}
img.parentNode.className = 'imageBox';
+ img.removeAttribute('title');
oEditor.removeEvent(img, 'mouseover', showDelete);
}
}
@@ -491,7 +619,7 @@ function startMoveTimer() {
if (moveTimer >= 0 && moveTimer < 10) {
moveTimer++;
- setTimeout('startMoveTimer()', 8);
+ setTimeout(startMoveTimer(), 8);
}
if (moveTimer === 5) {
@@ -524,7 +652,7 @@ function getMouseButtn(e) {
if (code) {
if (browser.msie && browser.version < 9) {
- code = code === 1 ? 0 : (code === 4 ? 1 : code);
+ code = code === 1 ? 0 : code === 4 ? 1 : code;
}
}
@@ -644,9 +772,9 @@ function dragDropMove(e) {
}
if (divXPositions[prop] < leftPos &&
- (divXPositions[prop] + divWidth[prop] * 0.7) > leftPos &&
+ divXPositions[prop] + divWidth[prop] * 0.7 > leftPos &&
divYPositions[prop] < topPos &&
- (divYPositions[prop] + divWidth[prop]) > topPos) {
+ divYPositions[prop] + divWidth[prop] > topPos) {
if (browser.msie) {
offsetX = offsetX_marker;
offsetY = offsetY_marker;
@@ -912,8 +1040,8 @@ DoUpload.prototype = {
offset += 2;
for (i = 0; i < tags; i++) {
- if (view.getUint16(offset + (i * 12), little) === 0x0112) {
- return view.getUint16(offset + (i * 12) + 8, little);
+ if (view.getUint16(offset + i * 12, little) === 0x0112) {
+ return view.getUint16(offset + i * 12 + 8, little);
}
}
} else if ((marker & 0xff00) !== 0xff00) {
@@ -951,62 +1079,140 @@ DoUpload.prototype = {
},
imageResize : function (image, filetype, resizeWidth, orientation, addWaterMark) {
- var canvas = document.createElement("canvas"),
- width = image.width,
- height = image.height,
- bitmapData, ctx, rotateImg, rotateW, rotateH, angle, step, offcanvas, offctx, dHeight, dWidth;
-
-
-
- // 카메라를 돌려서 찍은 경우, 높이를 가로 사이즈로 정한 다음 리사이징 처리. 이 경우, 파일 크기와 처리 속도가
- // 증가한다.
-
- // if (orientation === 6 || orientation === 8) {
- // var ratio = resizeWidth / height;
- // dHeight = height * ratio;
- // dWidth = width * ratio;
- // } else {
- dHeight = Math.ceil(resizeWidth / width * height);
- dWidth = resizeWidth;
- // }
-
- canvas.width = dWidth;
- canvas.height = dHeight;
- ctx = canvas.getContext("2d");
-
- step = Math.ceil(Math.log(image.width / resizeWidth) / Math.log(2));
-
- if (step > 1) {
- offcanvas = document.createElement('canvas');
- offctx = offcanvas.getContext('2d');
- offcanvas.width = width / 2;
- offcanvas.height = height / 2;
-
- offctx.drawImage(image, 0, 0, offcanvas.width, offcanvas.height);
- offctx.drawImage(offcanvas, 0, 0, offcanvas.width / 2, offcanvas.height / 2);
- ctx.drawImage(offcanvas, 0, 0, offcanvas.width / 2, offcanvas.height / 2, 0, 0, dWidth, dHeight);
- } else {
- ctx.drawImage(image, 0, 0, dWidth, dHeight);
- }
-
- if (orientation === 6 || orientation === 8 || orientation === 3) {
- angle = orientation === 6 ? Math.PI / 2 : (orientation === 8 ? -Math.PI / 2 : 180 * Math.PI / 2);
- bitmapData = canvas.toDataURL(filetype, oEditor.config.imgJpegQuality);
-
- rotateImg = new Image();
- rotateImg.src = bitmapData;
- rotateW = orientation !== 3 ? dHeight : dWidth;
- rotateH = orientation !== 3 ? dWidth : dHeight;
-
- canvas.width = rotateW;
- canvas.height = rotateH;
+ var canvas, source_w = image.width, source_h = image.height,
+ resize_h, resize_w, ratio_w, ratio_h, ratio_w_half, ratio_h_half,
+ source_img, resize_img, source_data, resize_data, j, i,
+ x2, weight, weights, weights_alpha, gx_a, gx_b, gx_g, gx_r, center_x, center_y, x_start, x_stop,
+ y_start, y_stop, y, dy, part_w, x, dx, w, pos_x,
+ ctx, gl, imageData = null;
+ // 카메라 로테이션 보정
+ if (orientation > 0) {
+ canvas = document.createElement("canvas");
+ canvas.width = source_w;
+ canvas.height = source_h;
+ ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
- ctx.translate(canvas.width / 2, canvas.height / 2);
- ctx.rotate(angle);
- ctx.drawImage(rotateImg, -dWidth / 2, -dHeight / 2);
+
+ switch (orientation) {
+ case 2 :
+ ctx.translate(-1, 0, 0, 1, canvas.width, 0); break;
+ case 3 :
+ ctx.translate(-1, 0, 0, -1, canvas.width, canvas.height); break;
+ case 4 :
+ ctx.translate(1, 0, 0, -1, 0, canvas.height); break;
+ case 5 :
+ ctx.translate(0, 1, 1, 0, 0, 0); break;
+ case 6 :
+ ctx.translate(0, 1, -1, 0, canvas.height, 0); break;
+ case 7 :
+ ctx.translate(0, -1, -1, 0, canvas.height, canvas.width); break;
+ case 8 :
+ ctx.translate(0, -1, 1, 0, 0, canvas.width); break;
+ default: break;
+ }
+
+ ctx.drawImage(image, 0, 0);
+ imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
ctx.restore();
+ source_w = canvas.width;
+ source_h = canvas.height;
+ }
+
+ if (source_w > resizeWidth) {
+ resize_w = resizeWidth;
+ resize_h = Math.ceil(resize_w / source_w * source_h);
+
+ try {
+ gl = GLScale({
+ width: resize_w, height: resize_h
+ });
+ gl(imageData || image, function (gl_canvas) {
+ canvas = gl_canvas;
+ });
+ } catch (ignore) {
+ canvas = document.createElement("canvas");
+ ctx = canvas.getContext("2d");
+ canvas.width = source_w;
+ canvas.height = source_h;
+
+ if (imageData) {
+ ctx.putImageData(imageData, 0, 0);
+ } else {
+ ctx.drawImage(image, 0, 0);
+ }
+
+ ratio_w = source_w / resize_w;
+ ratio_h = source_h / resize_h;
+ ratio_w_half = Math.ceil(ratio_w / 2);
+ ratio_h_half = Math.ceil(ratio_h / 2);
+ source_img = ctx.getImageData(0, 0, source_w, source_h);
+ resize_img = ctx.createImageData(resize_w, resize_h);
+ source_data = source_img.data;
+ resize_data = resize_img.data;
+
+ for (j = 0; j < resize_h; j++) {
+ for (i = 0; i < resize_w; i++) {
+ x2 = (i + j * resize_w) * 4;
+ weight = weights = weights_alpha = 0;
+ gx_r = gx_g = gx_b = gx_a = 0;
+ center_y = (j + 0.5) * ratio_h;
+
+ x_start = Math.floor(i * ratio_w);
+ x_stop = Math.ceil((i + 1) * ratio_w);
+ y_start = Math.floor(j * ratio_h);
+ y_stop = Math.ceil((j + 1) * ratio_h);
+
+ x_stop = Math.min(x_stop, source_w);
+ y_stop = Math.min(y_stop, source_h);
+
+ for (y = y_start; y < y_stop; y++) {
+ dy = Math.abs(center_y - (y + 0.5)) / ratio_h_half;
+ center_x = (i + 0.5) * ratio_w;
+ part_w = dy * dy;
+
+ for (x = x_start; x < x_stop; x++) {
+ dx = Math.abs(center_x - (x + 0.5)) / ratio_w_half;
+ w = Math.sqrt(part_w + dx * dx);
+ if (w >= 1) {
+ continue;
+ }
+ // Hermite 필터
+ weight = 2 * w * w * w - 3 * w * w + 1;
+ pos_x = 4 * (x + y * source_w);
+ // 알파 채널
+ gx_a += weight * source_data[pos_x + 3];
+ weights_alpha += weight;
+
+ if (source_data[pos_x + 3] < 255) {
+ weight = weight * source_data[pos_x + 3] / 250;
+ }
+
+ gx_r += weight * source_data[pos_x];
+ gx_g += weight * source_data[pos_x + 1];
+ gx_b += weight * source_data[pos_x + 2];
+ weights += weight;
+ }
+ }
+ resize_data[x2] = gx_r / weights;
+ resize_data[x2 + 1] = gx_g / weights;
+ resize_data[x2 + 2] = gx_b / weights;
+ resize_data[x2 + 3] = gx_a / weights_alpha;
+ }
+ }
+ canvas.width = resize_w;
+ canvas.height = resize_h;
+ ctx.putImageData(resize_img, 0, 0);
+ }
+
+ } else {
+ canvas = document.createElement("canvas"),
+ canvas.width = source_w; canvas.height = source_h;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(image, 0, 0);
+ resize_h = source_h;
+ resize_w = source_w;
}
if (this.reader.watermark && addWaterMark) {
@@ -1014,14 +1220,15 @@ DoUpload.prototype = {
ctx.drawImage(this.reader.watermark,
canvas.width - this.reader.watermark.width, canvas.height - this.reader.watermark.height);
}
+
return canvas.toDataURL(filetype, oEditor.config.imgJpegQuality);
},
canvasToBlob : function (bitmapData, mimetype) {
- var raw = atob(bitmapData.split(',')[1]),
+ var i = 0,
intArray = [],
len = bitmapData.length,
- i = 0;
+ raw = atob(bitmapData.split(',')[1]);
for (; i < len; i++) {
intArray.push(raw.charCodeAt(i));
@@ -1030,8 +1237,7 @@ DoUpload.prototype = {
},
makeThumbnail : function (image, type, name, orientation) {
- var canvas = document.createElement("canvas"),
- width,
+ var width,
xhr = new XMLHttpRequest(),
data = new FormData(),
bitmapData, file;
@@ -1041,11 +1247,10 @@ DoUpload.prototype = {
bitmapData = this.imageResize(image, type, width, orientation);
file = this.canvasToBlob(bitmapData, type);
-
data.append(inputFileName, file, 'thumb_' + name); // RFC Level 2
xhr.addEventListener("loadend", function () {
-
+ // loadend
}, false);
xhr.addEventListener("error", function () {
@@ -1060,20 +1265,19 @@ DoUpload.prototype = {
filename = evt.target.file.name,
filetype = evt.target.file.type,
file = evt.target.file,
- blob, image, orientation = 1;
+ blob, image, orientation = 1, slice = 64 * 1024;
+
+ if (slice > file.size - 1) {
+ slice = file.size;
+ }
if (evt.target.readyState === FileReader.DONE) {
blob = new self.MyBlob(self.NewBlob(evt.target.result, filetype));
- try {
- orientation = self.getOrientation(evt.target.result.slice(0, 64 * 1024));
- } catch(err) {
+ orientation = self.getOrientation(evt.target.result.slice(0, slice));
- }
image = new Image();
-
image.onload = function () {
var bitmapData = null,
- canvas = document.createElement("canvas"),
data = new FormData(),
fileFormat,
imgBox = file.boxElem,
@@ -1083,7 +1287,7 @@ DoUpload.prototype = {
xhr.open('POST', uploadScript, true);
- if (imageResizeWidth > 0 && this.width > imageResizeWidth) {
+ if (imageResizeWidth > 0) {
bitmapData = self.imageResize(this, filetype, imageResizeWidth, orientation, true);
file = self.canvasToBlob(bitmapData, filetype);
}
@@ -1099,7 +1303,7 @@ DoUpload.prototype = {
}
xhr.addEventListener("error", function (evt) {
- alert("파일 전송 중 오류: " + evt.target.error.code);
+ alert("파일 전송 중 오류: " + evt.toString());
}, false);
xhr.addEventListener("loadend", function onLoadendImageHandler(xhrevt) {
@@ -1132,7 +1336,6 @@ DoUpload.prototype = {
height: img.height,
width: img.width
};
-
imageCompletedList[imgBox.id] = imgInfo;
imgComplete(this, imgInfo, imgBox.id);
imgBox.appendChild(img);
@@ -1263,13 +1466,14 @@ function setResizeWidth() {
imageResizeWidth = value;
} else {
imageResizeInput.value = '';
+ imageResizeWidth = oEditor.config.imgMaxWidth;
imageResizeInput.setAttribute('placeholder', oEditor.config.imgMaxWidth.toString());
}
}
}
function init(dialog) {
- var dlg, i, elem, input, select, value, name;
+ var dlg, i, elem, input, select, value, name, xhr_f, xhr_v, tmpcanvas, glicon;
oEditor = this;
oEditor.dialog = dialog;
@@ -1279,14 +1483,12 @@ function init(dialog) {
uploadImagePath = oEditor.config.iconPath + 'imageUpload';
uploadMaxNumber = oEditor.config.imgUploadNumber;
uploadScript = oEditor.config.editorPath + 'imageUpload/upload.php';
- deleteScript = oEditor.config.editorPath + 'imageUpload/delete.php';
imageListWrapper = document.getElementById("imageListWrapper");
-
- imageResizeWidth = oEditor.config.imgMaxWidth;
imageResizeInput = document.getElementById('idResizeWidth');
select = document.getElementById('idResizeSelectBox');
- if (imageResizeWidth > 0) {
+ if (oEditor.config.imgMaxWidth > 0) {
+ imageResizeWidth = oEditor.config.imgMaxWidth;
for (i = 0; i < oEditor.config.imgResizeValue.length; i++) {
name = value = oEditor.config.imgResizeValue[i];
if (value > oEditor.config.imgMaxWidth) {
@@ -1300,6 +1502,9 @@ function init(dialog) {
select.onchange = function () {
if (this.value < 0) {
document.getElementById('idUserInputWrapper').style.display = '';
+ imageResizeInput.value = '';
+ imageResizeWidth = oEditor.config.imgMaxWidth;
+ imageResizeInput.focus();
} else {
document.getElementById('idUserInputWrapper').style.display = 'none';
imageResizeWidth = this.value;
@@ -1326,7 +1531,6 @@ function init(dialog) {
initGallery();
showUploadWindow();
createInsertionMaker();
- selectedFilesNum = 0;
oEditor.addEvent(imageListWrapper, 'dragover', dragOver);
oEditor.addEvent(imageListWrapper, 'dragleave', dragOut);
@@ -1343,6 +1547,38 @@ function init(dialog) {
if (browser.mobile) {
input = document.getElementById('inputImageUpload');
- input.setAttribute('capture', 'gallery');
+ input.setAttribute('capture', 'filesystem');
}
+
+ tmpcanvas = document.createElement('canvas');
+ if (tmpcanvas.getContext('webgl', {preserveDrawingBuffer: true}) ||
+ tmpcanvas.getContext('experimental-webgl', {preserveDrawingBuffer: true}))
+ {
+ useWebGL = true;
+ GLScale.Hermite = { vertex: '', fragment: '' };
+ xhr_v = new XMLHttpRequest();
+ xhr_f = new XMLHttpRequest();
+ xhr_f.open('POST', 'js/fragment-shader.glsl', true);
+ xhr_f.addEventListener("load", function (evt) {
+ if (evt.target.status === 200) {
+ GLScale.Hermite.fragment = this.responseText;
+ } else {
+ useWebGL = false;
+ }
+ });
+ xhr_v.open('POST', 'js/vertex-shader.glsl', true);
+ xhr_v.addEventListener("load", function (evt) {
+ if (evt.target.status === 200) {
+ GLScale.Hermite.vertex = this.responseText;
+ } else {
+ useWebGL = false;
+ }
+ });
+ xhr_f.send();
+ xhr_v.send();
+ }
+ glicon = new Image();
+ glicon.className = 'webgl_logo';
+ glicon.src = uploadImagePath + (useWebGL ? "/webgl.png" : "/webgl-off.png");
+ document.getElementById('webgl_logo_wrapper').appendChild(glicon);
}
diff --git a/plugin/editor/cheditor5/popup/js/image.html5.m.js b/plugin/editor/cheditor5/popup/js/image.html5.m.js
new file mode 100644
index 000000000..67cedbf5d
--- /dev/null
+++ b/plugin/editor/cheditor5/popup/js/image.html5.m.js
@@ -0,0 +1,1584 @@
+// ================================================================
+// CHEditor 5
+// ================================================================
+
+var activeImage = null,
+ browser = null,
+ button,
+ debug = false,
+ destinationObject = null,
+ divHeight = [],
+ divWidth = [],
+ divXPositions = [],
+ divYPositions = [],
+ dragDropDiv,
+ eventDiff_x = 0,
+ eventDiff_y = 0,
+ fileTypeRe = /^image\/(png|jpeg|gif)$/i,
+ geckoOffsetX_marker = -3,
+ geckoOffsetY_marker = -1,
+ imageCompleted = 0,
+ imageCompletedList = [],
+ imageListWrapper,
+ imageResizeInput,
+ imageResizeWidth = 0,
+ insertionMarker,
+ inputFileName = 'file',
+ modifyImages = [],
+ moveTimer = -1,
+ oEditor = null,
+ offsetX_marker = -3,
+ offsetY_marker = -3,
+ readyToMove = false,
+ showThumbnailSize = { width: 120, height: 90 },
+ tmpLeft = 0,
+ tmpTop = 0,
+ uploadImagePath = '',
+ uploadMaxNumber = 12,
+ uploadScript;
+ useWebGL = false;
+
+if (ArrayBuffer && !ArrayBuffer.prototype.slice) {
+ ArrayBuffer.prototype.slice = function (start, end) {
+ var len = this.byteLength;
+ start || isFinite(start) && 0 < start && start < len || (start = 0);
+ end || (isFinite(end && start < end && end < len) || (end = len - 1));
+ return new DataView(this, start, end).buffer;
+ };
+}
+
+function GLScale(options) {
+ if (!(this instanceof GLScale)) {
+ return new GLScale(options);
+ }
+ this.precompile(options);
+ return this.scale.bind(this);
+}
+
+GLScale.prototype.precompile = function (options) {
+ var ctxOptions, vertex, fragment, resolutionLocation, positionLocation;
+
+ this.canvas = document.createElement('canvas');
+ this.canvas.width = options.width;
+ this.canvas.height = options.height;
+
+ ctxOptions = {preserveDrawingBuffer: true};
+ this.gl = this.canvas.getContext('webgl', ctxOptions) || this.canvas.getContext('experimental-webgl', ctxOptions);
+
+ if (!this.gl) {
+ throw new Error('Could not initialize webgl context');
+ }
+
+ vertex = GLScale.compileShader(this.gl, GLScale.Hermite.vertex, this.gl.VERTEX_SHADER);
+ fragment = GLScale.compileShader(this.gl, GLScale.Hermite.fragment, this.gl.FRAGMENT_SHADER);
+
+ this.program = GLScale.createProgram(this.gl, vertex, fragment);
+ this.gl.useProgram(this.program);
+
+ this.gl.bindTexture(this.gl.TEXTURE_2D, this.gl.createTexture());
+
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
+
+ resolutionLocation = this.gl.getUniformLocation(this.program, 'u_resolution');
+ this.gl.uniform2f(resolutionLocation, options.width, options.height);
+
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.gl.createBuffer());
+ positionLocation = this.gl.getAttribLocation(this.program, 'a_position');
+ this.gl.enableVertexAttribArray(positionLocation);
+ this.gl.vertexAttribPointer(positionLocation, 2, this.gl.FLOAT, false, 0, 0);
+};
+
+GLScale.prototype.scale = function (image, cb) {
+ var srcResolutionLocation;
+ if (typeof image === 'string') {
+ return this.loadImage(image, function (err, image) {
+ if (!err) {
+ return this.scale(image, cb);
+ }
+ });
+ }
+
+ this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, image);
+
+ srcResolutionLocation = this.gl.getUniformLocation(this.program, 'u_srcResolution');
+ this.gl.uniform2f(srcResolutionLocation, image.width, image.height);
+
+ this.setRectangle(0, 0, image.width, image.height);
+ this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
+ this.gl.finish();
+
+ if (cb) {
+ cb(this.canvas);
+ }
+ return this;
+};
+
+GLScale.prototype.setRectangle = function (x, y, width, height) {
+ var x1 = x,
+ x2 = x + width,
+ y1 = y,
+ y2 = y + height;
+
+ this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
+ x1, y1,
+ x2, y1,
+ x1, y2,
+ x1, y2,
+ x2, y1,
+ x2, y2
+ ]), this.gl.STATIC_DRAW);
+};
+
+GLScale.loadImage = function (url, cb) {
+ var image = new Image();
+ image.onload = cb.bind(this, null, image);
+ image.onerror = cb.bind(this);
+ image.src = url;
+ return this;
+};
+GLScale.prototype.loadImage = GLScale.loadImage;
+
+GLScale.toBlob = (function toBlob() {
+ var CanvasPrototype = window.HTMLCanvasElement.prototype;
+
+ if (CanvasPrototype.toBlob) {
+ return CanvasPrototype.toBlob;
+ }
+
+ return function (callback, type, quality) {
+ var binStr = atob(this.toDataURL(type, quality).split(',')[1]),
+ len = binStr.length,
+ arr = new Uint8Array(len), i = 0;
+
+ for (; i < len; i++) {
+ arr[i] = binStr.charCodeAt(i);
+ }
+ callback(new Blob([arr], {type: type || 'image/png'}));
+ };
+})();
+
+GLScale.compileShader = function (gl, shaderSource, shaderType) {
+ var shader = gl.createShader(shaderType);
+
+ gl.shaderSource(shader, shaderSource);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ throw new Error('Could not compile shader: ' + gl.getShaderInfoLog(shader));
+ }
+ return shader;
+};
+
+GLScale.createProgram = function (gl, vertexShader, fragmentShader) {
+ var program = gl.createProgram();
+
+ gl.attachShader(program, vertexShader);
+ gl.attachShader(program, fragmentShader);
+ gl.linkProgram(program);
+
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
+ throw new Error('Program failed to link: ' + gl.getProgramInfoLog (program));
+ }
+ return program;
+};
+
+function createInsertionMaker() {
+ var wrapper = document.getElementById('insertionMarker'),
+ topIco = new Image(),
+ middleIco = new Image(),
+ bottomIco = new Image();
+
+ topIco.src = uploadImagePath + '/marker_top.gif';
+ topIco.style.width = '6px';
+ topIco.style.height = '1px';
+ wrapper.appendChild(topIco);
+
+ middleIco.src = uploadImagePath + '/marker_middle.gif';
+ middleIco.style.height = '96px';
+ middleIco.style.width = '6px';
+ wrapper.appendChild(middleIco);
+
+ bottomIco.src = uploadImagePath + '/marker_bottom.gif';
+ bottomIco.style.width = '6px';
+ bottomIco.style.height = '1px';
+ wrapper.appendChild(bottomIco);
+}
+
+function popupClose() {
+ oEditor.popupWinCancel();
+}
+
+function showContents() {
+ var spacer = function (id) {
+ var clear = document.createElement('div');
+ clear.style.height = '0px';
+ clear.style.width = '0px';
+ clear.className = 'clear';
+ clear.id = 'spacer' + id;
+ return clear;
+ },
+ spacerNo = 1, i, imgBox, theImg, lastSpacer;
+
+ for (i = 0; i < uploadMaxNumber; i++) {
+ if (i > 0 && i % 2 === 0) {
+ imageListWrapper.appendChild(spacer(spacerNo++));
+ }
+
+ imgBox = document.createElement('div');
+ imgBox.id = 'imgBox' + i;
+ imgBox.className = 'imageBox';
+ theImg = document.createElement('div');
+ theImg.id = 'img_' + i;
+ theImg.className = 'imageBox_theImage';
+ imgBox.appendChild(theImg);
+
+ imageListWrapper.appendChild(imgBox);
+ if (i === uploadMaxNumber - 1) {
+ lastSpacer = spacer(spacerNo);
+ lastSpacer.style.height = "7px";
+ imageListWrapper.appendChild(lastSpacer);
+ }
+ }
+
+ imageListWrapper.style.padding = '5px 7px 0px 5px';
+ document.getElementById('imageInfoBox').style.height = '298px';
+ document.getElementById('imageInfoBox').style.width = '130px';
+}
+
+function setImageCount() {
+ imageCompleted++;
+ document.getElementById('imageCount').innerHTML = imageCompleted.toString();
+}
+
+function getImageCount() {
+ return imageCompleted;
+}
+
+function allowedMaxImage() {
+ return uploadMaxNumber - getImageCount();
+}
+
+function getUploadedCount() {
+ return imageListWrapper.getElementsByTagName('img').length;
+}
+
+function uploadedImageCount() {
+ imageCompleted = getUploadedCount();
+ document.getElementById('imageCount').innerHTML = imageCompleted.toString();
+}
+
+function getTopPos(inputObj) {
+ // ----------------------------------------------------------------------------------
+ var returnValue = inputObj.offsetTop;
+
+ inputObj = inputObj.offsetParent;
+ while (inputObj) {
+ if (inputObj.tagName.toLowerCase() !== 'html') {
+ returnValue += inputObj.offsetTop - inputObj.scrollTop;
+ if (browser.msie) {
+ returnValue += inputObj.clientTop;
+ }
+ }
+ inputObj = inputObj.offsetParent;
+ }
+ return returnValue;
+}
+
+function getLeftPos(inputObj) {
+ // ----------------------------------------------------------------------------------
+ var returnValue = inputObj.offsetLeft;
+
+ inputObj = inputObj.offsetParent;
+ while (inputObj) {
+ if (inputObj.id !== 'imageListWrapper') {
+ returnValue += inputObj.offsetLeft;
+ }
+ inputObj = inputObj.offsetParent;
+ }
+ return returnValue;
+}
+
+function getDivCoordinates() {
+ // ----------------------------------------------------------------------------------
+ var imgBox = imageListWrapper.getElementsByTagName('DIV'),
+ i = 0;
+
+ for (; i < imgBox.length; i++) {
+ if ((imgBox[i].className === 'imageBox' || imgBox[i].className === 'imageBoxHighlighted') && imgBox[i].id) {
+ divXPositions[imgBox[i].id] = getLeftPos(imgBox[i]);
+ divYPositions[imgBox[i].id] = getTopPos(imgBox[i]);
+ divWidth[imgBox[i].id] = imgBox[i].offsetWidth;
+ divHeight[imgBox[i].id] = imgBox[i].offsetHeight;
+ }
+ }
+}
+
+function reOrder() {
+ // ----------------------------------------------------------------------------------
+ var imgBox = imageListWrapper.getElementsByTagName('div'),
+ imgNum = 0, i, spacer, breakline = [];
+
+ for (i = 0; i < imgBox.length; i++) {
+ if (imgBox[i].id.indexOf('imgBox') === -1) {
+ continue;
+ }
+
+ imgBox[i].className = 'imageBox';
+ imgBox[i].firstChild.className = 'imageBox_theImage';
+
+ if (imgNum > 0 && imgNum % 4 === 0) {
+ breakline.push(imgBox[i].id);
+ }
+
+ imgNum++;
+ }
+
+ for (i = 0; i < breakline.length; i++) {
+ spacer = document.getElementById('spacer' + (i + 1));
+ if (i + 1 === breakline.length) {
+ imageListWrapper.appendChild(spacer);
+ } else {
+ imageListWrapper.insertBefore(spacer, document.getElementById(breakline[i]));
+ }
+ }
+}
+
+function showDelete() {
+ var self = this, btn;
+
+ if (readyToMove) {
+ return;
+ }
+
+ getDivCoordinates();
+ self.className = 'imageBox_theImage_over';
+ btn = document.getElementById('removeImageButton');
+ btn.style.left = showThumbnailSize.width - parseInt(btn.style.width, 10) - 1 + 'px';
+ btn.style.top = '-1px';
+
+ self.appendChild(btn);
+ btn.style.display = 'block';
+
+ btn.onmouseover = function (ev) {
+ oEditor.stopEvent(ev);
+ this.style.display = 'block';
+ this.className = 'removeButton_over';
+ self.className = 'imageBox_theImage_over';
+ };
+ btn.onmouseout = function () {
+ this.className = 'removeButton';
+ };
+ btn.onmousedown = function (ev) {
+ var images = self.getElementsByTagName('img'), i, moveobj, target;
+
+ for (i = 0; i < images.length; i++) {
+ self.removeChild(images[i]);
+ }
+
+ self.removeChild(self.firstChild);
+ self.className = 'imageBox_theImage';
+
+ if (self.parentNode.nextSibling && self.parentNode.nextSibling.id) {
+ moveobj = self.parentNode.nextSibling;
+ target = self.parentNode;
+
+ while (moveobj !== null) {
+ if (moveobj.firstChild && !moveobj.firstChild.firstChild) {
+ break;
+ }
+ if (/^spacer/.test(moveobj.id)) {
+ moveobj = moveobj.nextSibling;
+ continue;
+ }
+ imageListWrapper.insertBefore(moveobj, target);
+ moveobj = target.nextSibling;
+ }
+ }
+
+ reOrder();
+ uploadedImageCount();
+ this.style.display = 'none';
+ document.body.appendChild(ev.target);
+ oEditor.removeEvent(self, 'mouseover', showDelete);
+ self.removeAttribute('title');
+ };
+}
+
+function hideDelete() {
+ // ----------------------------------------------------------------------------------
+ document.getElementById('removeImageButton').style.display = 'none';
+}
+
+function startUpload(list) {
+ // ----------------------------------------------------------------------------------
+ var el = imageListWrapper.getElementsByTagName('div'), i, imgBox,
+ count = 0, len = list.length;
+
+ for (i = 0; i < el.length; i++) {
+ imgBox = el[i];
+ if (imgBox.className !== 'imageBox_theImage') {
+ continue;
+ }
+ if (count === len) {
+ break;
+ }
+ if (!imgBox.firstChild || imgBox.firstChild.tagName.toLowerCase() !== 'img') {
+ imgBox.style.backgroundImage = "url('" + uploadImagePath + "/loader.gif')";
+ list[count++].boxElem = imgBox;
+ }
+ }
+}
+
+function fileFilterError(file) {
+ alert("선택하신 '" + file + "' 파일은 전송할 수 없습니다.\n" +
+ "gif, png, jpg 사진 파일만 전송할 수 있습니다.");
+}
+
+function imgComplete(img, imgSize, boxId) {
+ var resizeW, resizeH, M, elem;
+ img.setAttribute("border", '0');
+
+ if (imgSize.width > showThumbnailSize.width || imgSize.height > showThumbnailSize.height) {
+ if (imgSize.width > imgSize.height) {
+ resizeW = imgSize.width > showThumbnailSize.width ? showThumbnailSize.width : imgSize.width;
+ resizeH = Math.round(imgSize.height * resizeW / imgSize.width);
+ } else {
+ resizeH = imgSize.height > showThumbnailSize.height ? showThumbnailSize.height : imgSize.height;
+ resizeW = Math.round(imgSize.width * resizeH / imgSize.height);
+ }
+
+ if (resizeH > showThumbnailSize.height) {
+ resizeH = imgSize.height > showThumbnailSize.height ? showThumbnailSize.height : imgSize.height;
+ resizeW = Math.round(imgSize.width * resizeH / imgSize.height);
+ }
+
+ } else {
+ resizeW = imgSize.width;
+ resizeH = imgSize.height;
+ }
+
+ img.style.width = resizeW - 2 + 'px';
+ img.style.height = resizeH - 2 + 'px';
+ img.style.margin = "1px";
+
+ if (resizeW < showThumbnailSize.width) {
+ M = showThumbnailSize.width - resizeW;
+ img.style.marginLeft = Math.round(M / 2) + 'px';
+ }
+
+ if (resizeH < showThumbnailSize.height) {
+ M = showThumbnailSize.height - resizeH;
+ img.style.marginTop = Math.round(M / 2) + 'px';
+ }
+
+ elem = document.getElementById(boxId);
+ boxId = boxId.replace(/img_/, '');
+
+ if (boxId % 12 === 0) {
+ imageListWrapper.scrollTop = elem.offsetTop - 6;
+ }
+
+ elem.style.backgroundImage = "url('" + uploadImagePath + "/dot.gif')";
+ setElemTitle(elem, imgSize.width, imgSize.height);
+ oEditor.addEvent(elem, 'mouseover', showDelete);
+ elem.onmouseout = function () {
+ this.className = 'imageBox_theImage';
+ hideDelete();
+ };
+
+ setImageCount();
+}
+
+function setElemTitle(elem, width, height) {
+ elem.setAttribute('title', 'Width: ' + width + 'px, Height: ' + height + 'px');
+}
+
+function showUploadWindow() {
+ // ----------------------------------------------------------------------------------
+ var uploadWindow = document.getElementById("uploadWindow"),
+ uploadWindowWidth = 700,
+ winWidth, el, i, j, imgBox, img;
+
+ if (!oEditor.undefined(window.innerWidth)) {
+ winWidth = window.innerWidth;
+ } else if (document.documentElement &&
+ !oEditor.undefined(document.documentElement.clientWidth) &&
+ document.documentElement.clientWidth !== 0) {
+ winWidth = document.documentElement.clientWidth;
+ } else if (document.body && !oEditor.undefined(document.body.clientWidth)) {
+ winWidth = document.body.clientWidth;
+ } else {
+ alert('현재 브라우저를 지원하지 않습니다.');
+ return;
+ }
+
+ uploadWindow.style.left = winWidth / 2 - uploadWindowWidth / 2 + 'px';
+ uploadWindow.style.display = "block";
+ uploadWindow.style.width = uploadWindowWidth + 'px';
+
+ if (modifyImages.length > 0) {
+ el = imageListWrapper.getElementsByTagName('div');
+ for (i = 0; i < modifyImages.length; i++) {
+ if (i > 7) {
+ break;
+ }
+
+ for (j = 0; j < el.length; j++) {
+ imgBox = el[j];
+ if (imgBox.className !== 'imageBox_theImage') {
+ continue;
+ }
+ if (imgBox.firstChild && imgBox.firstChild.src === modifyImages[i]) {
+ break;
+ }
+ if (imgBox.firstChild === null) {
+ img = new Image();
+ img.src = modifyImages[i];
+ img.border = 0;
+ img.alt = '';
+ img.style.width = '120px';
+ img.style.height = '90px';
+ imgBox.appendChild(img);
+ break;
+ }
+ }
+ }
+ }
+}
+
+function removeImages() {
+ var images = [], i, j, theImage, img, remove;
+ document.body.appendChild(document.getElementById('removeImageButton'));
+
+ for (i = 0; i < uploadMaxNumber; i++) {
+ theImage = document.getElementById('img_' + i);
+ if (theImage.hasChildNodes() && theImage.firstChild.tagName.toLowerCase() === 'img') {
+ images.push(theImage);
+ }
+ }
+
+ for (i = 0; i < images.length; i++) {
+ img = images[i];
+ if (img.firstChild !== null) {
+ oEditor.removeEvent(img, 'mouseover', showDelete);
+ remove = img.getElementsByTagName('img');
+
+ for (j = 0; j < remove.length; j++) {
+ img.removeChild(remove[j]);
+ }
+
+ img.parentNode.className = 'imageBox';
+ img.removeAttribute('title');
+ oEditor.removeEvent(img, 'mouseover', showDelete);
+ }
+ }
+ uploadedImageCount();
+ imageCompletedList = [];
+}
+
+function removeImage() {
+ // ----------------------------------------------------------------------------------
+ var i, theImage, found = false;
+
+ for (i = 0; i < uploadMaxNumber; i++) {
+ theImage = document.getElementById('img_' + i);
+ if (theImage.hasChildNodes() && theImage.firstChild.tagName.toLowerCase() === 'img') {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ if (!confirm('추가하신 사진이 있습니다. 사진 넣기를 취소하시겠습니까?')) {
+ return false;
+ }
+ removeImages();
+ }
+
+ return true;
+}
+
+function closeWindow() {
+ // ----------------------------------------------------------------------------------
+ if (removeImage()) {
+ popupClose();
+ }
+}
+
+function cancelEvent() {
+ // ----------------------------------------------------------------------------------
+ return false;
+}
+
+function startMoveTimer() {
+ // ----------------------------------------------------------------------------------
+ var subElements, newDiv;
+
+ if (moveTimer >= 0 && moveTimer < 10) {
+ moveTimer++;
+ setTimeout(startMoveTimer(), 8);
+ }
+
+ if (moveTimer === 5) {
+ getDivCoordinates();
+ subElements = dragDropDiv.getElementsByTagName('div');
+ if (subElements.length > 0) {
+ dragDropDiv.removeChild(subElements[0]);
+ }
+
+ dragDropDiv.style.display = 'block';
+ newDiv = activeImage.cloneNode(true);
+ newDiv.className = 'imageBox';
+ newDiv.style.opacity = 0.5;
+
+ newDiv.id = '';
+ newDiv.style.padding = '2px';
+ dragDropDiv.appendChild(newDiv);
+
+ dragDropDiv.style.top = tmpTop + 'px';
+ dragDropDiv.style.left = tmpLeft + 'px';
+ }
+
+ return false;
+}
+
+function getMouseButtn(e) {
+ var code;
+ e = e || window.event;
+ code = e.button;
+
+ if (code) {
+ if (browser.msie && browser.version < 9) {
+ code = code === 1 ? 0 : code === 4 ? 1 : code;
+ }
+ }
+
+ return code;
+}
+
+function selectImage(e) {
+ // ----------------------------------------------------------------------------------
+ var el = this.parentNode.firstChild.firstChild, obj;
+
+ if (!el) {
+ return;
+ }
+
+ e = e || window.event;
+ if (getMouseButtn(e) === 2) {
+ return;
+ }
+
+ obj = this.parentNode;
+ hideDelete();
+
+ obj.className = 'imageBoxHighlighted';
+ activeImage = obj;
+ readyToMove = true;
+ moveTimer = 0;
+
+ tmpLeft = e.clientX + Math.max(document.body.scrollLeft, document.documentElement.scrollLeft);
+ tmpTop = e.clientY + Math.max(document.body.scrollTop, document.documentElement.scrollTop);
+
+ startMoveTimer();
+ return false;
+}
+
+function dragDropEnd() {
+ // ----------------------------------------------------------------------------------
+ var parentObj, chkObj, turn = false;
+
+ readyToMove = false;
+ moveTimer = -1;
+ dragDropDiv.style.display = 'none';
+ insertionMarker.style.display = 'none';
+
+ if (!activeImage) {
+ return;
+ }
+
+ if (destinationObject && destinationObject !== activeImage) {
+ parentObj = destinationObject.parentNode;
+ chkObj = destinationObject.previousSibling;
+ turn = false;
+
+ if (chkObj === null) {
+ chkObj = imageListWrapper.firstChild;
+ turn = true;
+ }
+
+ if (chkObj.id.indexOf('spacer') !== -1) {
+ chkObj = chkObj.previousSibling;
+ }
+
+ if (chkObj.firstChild.firstChild === null) {
+ reOrder();
+ return;
+ }
+
+ if (chkObj && chkObj.id !== null) {
+ while (chkObj) {
+ if (chkObj.firstChild.firstChild !== null) {
+ break;
+ }
+ chkObj = chkObj.previousSibling;
+ }
+ destinationObject = turn ? chkObj : chkObj.nextSibling;
+ }
+
+ parentObj.insertBefore(activeImage, destinationObject);
+ reOrder();
+
+ activeImage = null;
+ destinationObject = null;
+ getDivCoordinates();
+
+ return false;
+ }
+
+ activeImage.className = "imageBox";
+ return true;
+}
+
+function dragDropMove(e) {
+ // ----------------------------------------------------------------------------------
+ var elementFound = false, prop, offsetX, offsetY, leftPos, topPos;
+
+ if (moveTimer === -1 || !readyToMove) {
+ return;
+ }
+
+ e = e || window.event;
+
+ leftPos = e.clientX + document.documentElement.scrollLeft - eventDiff_x;
+ topPos = e.clientY + document.documentElement.scrollTop - eventDiff_y;
+
+ dragDropDiv.style.top = topPos + 'px';
+ dragDropDiv.style.left = leftPos + 'px';
+
+ leftPos = leftPos + eventDiff_x;
+ topPos = topPos + eventDiff_y;
+
+ if (getMouseButtn(e) !== 0) {
+ dragDropEnd();
+ }
+
+ for (prop in divXPositions) {
+ if (!divXPositions.hasOwnProperty(prop) || divXPositions[prop].className === 'clear') {
+ continue;
+ }
+
+ if (divXPositions[prop] < leftPos &&
+ divXPositions[prop] + divWidth[prop] * 0.7 > leftPos &&
+ divYPositions[prop] < topPos &&
+ divYPositions[prop] + divWidth[prop] > topPos) {
+ if (browser.msie) {
+ offsetX = offsetX_marker;
+ offsetY = offsetY_marker;
+ } else {
+ offsetX = geckoOffsetX_marker;
+ offsetY = geckoOffsetY_marker;
+ }
+
+ insertionMarker.style.top = divYPositions[prop] + offsetY + 'px';
+ insertionMarker.style.left = divXPositions[prop] + offsetX + 'px';
+ insertionMarker.style.display = 'block';
+ destinationObject = document.getElementById(prop);
+ elementFound = true;
+ break;
+ }
+ }
+
+ if (!elementFound) {
+ insertionMarker.style.display = 'none';
+ destinationObject = false;
+ }
+
+ return false;
+}
+
+function initGallery() {
+ // ----------------------------------------------------------------------------------
+ var imgBox = imageListWrapper.getElementsByTagName('div'),
+ i;
+
+ for (i = 0; i < imgBox.length; i++) {
+ if (imgBox[i].className === 'imageBox_theImage') {
+ imgBox[i].onmousedown = selectImage;
+ }
+ }
+
+ document.body.onselectstart = cancelEvent;
+ document.body.ondragstart = cancelEvent;
+ document.body.onmouseup = dragDropEnd;
+ document.body.onmousemove = dragDropMove;
+
+ dragDropDiv = document.getElementById('dragDropContent');
+ insertionMarker = document.getElementById('insertionMarker');
+ getDivCoordinates();
+}
+
+function doSubmit() {
+ // ----------------------------------------------------------------------------------
+ var el = imageListWrapper.getElementsByTagName('div'),
+ imageArray = [],
+ num = 0,
+ elem = document.getElementById('id_alignment').elements,
+ imgParagraph = false,
+ useSpacer = false,
+ imgAlign = 'top', i, imgBox, input;
+
+ for (i = 0; i < elem.length; i++) {
+ input = elem[i];
+ switch (input.name) {
+ case "alignment" :
+ if (input.checked) {
+ imgAlign = input.value;
+ }
+ break;
+ case "para" :
+ imgParagraph = input.checked;
+ break;
+ case "use_spacer" :
+ useSpacer = input.checked;
+ break;
+ }
+ }
+
+ for (i = 0; i < el.length; i++) {
+ imgBox = el[i];
+ if (imgBox.className !== "imageBox_theImage") {
+ continue;
+ }
+
+ if (imgBox.firstChild !== null) {
+ imageArray[num] = imageCompletedList[imgBox.id];
+
+ if (imgAlign === "break") {
+ imageArray[num].alt = "break";
+ } else {
+ imageArray[num].alt = '';
+ imageArray[num].align = imgAlign;
+ }
+
+ num++;
+ }
+ }
+
+ if (imageArray.length > 0) {
+ oEditor.doInsertImage(imageArray, imgParagraph, useSpacer);
+ }
+ oEditor.popupWinClose();
+}
+
+function selectedFiles(evt) {
+ var upload = new DoUpload(),
+ files = evt.target.files || [];
+
+ oEditor.stopEvent(evt);
+ if (files) {
+ upload.select(files);
+ }
+}
+
+function DoUpload() {
+ this.list = [];
+ this.reader = new FileReader();
+ this.URL = window.URL || window.webkitURL;
+
+ this.reader.onprogress = null;
+ this.reader.onloadstart = null;
+ this.reader.onabort = null;
+ this.reader.onerror = null;
+
+ this.MyBlob = (function () {
+ var key, blob, self = this;
+ function MYBLOB(blob) {
+ var url = null;
+ this.blob = blob;
+ blob = null;
+
+ this.getURL = function () {
+ if (url) {
+ return url;
+ }
+ url = self.URL.createObjectURL(this.blob);
+ return url;
+ };
+ this.dispose = function () {
+ if (url) {
+ url = self.URL.revokeObjectURL(url);
+ }
+ if (typeof this.blob.msClose !== 'undefined') {
+ this.blob.msClose();
+ }
+ this.blob = null;
+ if (debug) {
+ console.log("Blob Data Clear");
+ }
+ };
+ }
+
+ blob = new Blob();
+ for (key in blob) {
+ if (blob.hasOwnProperty(key)) {
+ (function (key) {
+ Object.defineProperty(MYBLOB.prototype,
+ key,
+ {
+ enumerable: true,
+ configurable: true,
+ get: function () {
+ return this.blob[key];
+ }
+ }
+ );
+ }(key));
+ }
+ }
+
+ key = undefined;
+ return MYBLOB;
+ }());
+
+ return this;
+}
+
+DoUpload.prototype = {
+ select: function (files) {
+ var self = this,
+ num = files.length,
+ i = 0,
+ file = null;
+
+ if (num > allowedMaxImage()) {
+ num = allowedMaxImage();
+ }
+
+ for (; i < num; i++) {
+ file = files[i];
+
+ if (!file.type.match(fileTypeRe)) {
+ fileFilterError(file.name);
+ continue;
+ }
+ this.list.push(file);
+ }
+
+ if (this.list.length < 1) {
+ return;
+ }
+
+ this.reader.addEventListener("error", function (evt) {
+ self.onReadDataErrorHandler(evt);
+ }, false);
+
+ this.reader.onloadend = function (evt) {
+ self.dataLoadHandler(evt);
+ };
+
+ setResizeWidth();
+ startUpload(this.list);
+
+ this.load();
+ },
+
+ getDateTime : function () {
+ var date = new Date(),
+ year = date.getFullYear(),
+ month = date.getMonth() + 1,
+ day = date.getDate(),
+ hours = date.getHours(),
+ minutes = date.getMinutes(),
+ seconds = date.getSeconds();
+
+ return String(10000 * year + 100 * month + day +
+ ('0' + hours).slice(-2) + ('0' + minutes).slice(-2) + ('0' + seconds).slice(-2));
+ },
+
+ makeFilename : function (type) {
+ var chars = "abcdefghiklmnopqrstuvwxyz",
+ len = 8, clen = chars.length, rData = '', i, rnum;
+
+ for (i = 0; i < len; i++) {
+ rnum = Math.floor(Math.random() * clen);
+ rData += chars.substring(rnum, rnum + 1);
+ }
+
+ if (type !== '') {
+ rData += type.toLowerCase();
+ }
+
+ return this.getDateTime() + '_' + rData;
+ },
+
+ getOrientation : function (data) {
+ var view = new DataView(data),
+ length = view.byteLength,
+ offset = 2,
+ marker, little, tags, i;
+
+ if (view.getUint16(0, false) !== 0xffd8) {
+ return -2;
+ }
+
+ while (offset < length) {
+ marker = view.getUint16(offset, false);
+ offset += 2;
+
+ if (marker === 0xffe1) {
+ if (view.getUint32(offset += 2, false) !== 0x45786966) {
+ return -1;
+ }
+
+ little = view.getUint16(offset += 6, false) === 0x4949;
+ offset += view.getUint32(offset + 4, little);
+ tags = view.getUint16(offset, little);
+ offset += 2;
+
+ for (i = 0; i < tags; i++) {
+ if (view.getUint16(offset + i * 12, little) === 0x0112) {
+ return view.getUint16(offset + i * 12 + 8, little);
+ }
+ }
+ } else if ((marker & 0xff00) !== 0xff00) {
+ break;
+ } else {
+ offset += view.getUint16(offset, false);
+ }
+ }
+
+ return -1;
+ },
+
+ NewBlob : function (data, datatype) {
+ var blob = null, blobb;
+ try {
+ blob = new Blob([data], {type: datatype});
+ } catch (e) {
+ window.BlobBuilder = window.BlobBuilder
+ || window.WebKitBlobBuilder
+ || window.MozBlobBuilder
+ || window.MSBlobBuilder;
+
+ if (e.name === 'TypeError' && window.BlobBuilder) {
+ blobb = new BlobBuilder();
+ blobb.append(data);
+ blob = blobb.getBlob(datatype);
+ console.log("TypeError");
+ } else if (e.name === "InvalidStateError") {
+ console.log("InvalidStateError");
+ } else {
+ console.log("Error");
+ }
+ }
+ return blob;
+ },
+
+ imageResize : function (image, filetype, resizeWidth, orientation, addWaterMark) {
+ var canvas, source_w = image.width, source_h = image.height,
+ resize_h, resize_w, ratio_w, ratio_h, ratio_w_half, ratio_h_half,
+ source_img, resize_img, source_data, resize_data, j, i,
+ x2, weight, weights, weights_alpha, gx_a, gx_b, gx_g, gx_r, center_x, center_y, x_start, x_stop,
+ y_start, y_stop, y, dy, part_w, x, dx, w, pos_x,
+ ctx, gl, imageData = null;
+
+ // 카메라 로테이션 보정
+ if (orientation > 0) {
+ canvas = document.createElement("canvas");
+ canvas.width = source_w;
+ canvas.height = source_h;
+ ctx = canvas.getContext("2d");
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.save();
+
+ switch (orientation) {
+ case 2 :
+ ctx.translate(-1, 0, 0, 1, canvas.width, 0); break;
+ case 3 :
+ ctx.translate(-1, 0, 0, -1, canvas.width, canvas.height); break;
+ case 4 :
+ ctx.translate(1, 0, 0, -1, 0, canvas.height); break;
+ case 5 :
+ ctx.translate(0, 1, 1, 0, 0, 0); break;
+ case 6 :
+ ctx.translate(0, 1, -1, 0, canvas.height, 0); break;
+ case 7 :
+ ctx.translate(0, -1, -1, 0, canvas.height, canvas.width); break;
+ case 8 :
+ ctx.translate(0, -1, 1, 0, 0, canvas.width); break;
+ default: break;
+ }
+
+ ctx.drawImage(image, 0, 0);
+ imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ ctx.restore();
+ source_w = canvas.width;
+ source_h = canvas.height;
+ }
+
+ if (source_w > resizeWidth) {
+ resize_w = resizeWidth;
+ resize_h = Math.ceil(resize_w / source_w * source_h);
+
+ try {
+ gl = GLScale({
+ width: resize_w, height: resize_h
+ });
+ gl(imageData || image, function (gl_canvas) {
+ canvas = gl_canvas;
+ });
+ } catch (ignore) {
+ canvas = document.createElement("canvas");
+ ctx = canvas.getContext("2d");
+ canvas.width = source_w;
+ canvas.height = source_h;
+
+ if (imageData) {
+ ctx.putImageData(imageData, 0, 0);
+ } else {
+ ctx.drawImage(image, 0, 0);
+ }
+
+ ratio_w = source_w / resize_w;
+ ratio_h = source_h / resize_h;
+ ratio_w_half = Math.ceil(ratio_w / 2);
+ ratio_h_half = Math.ceil(ratio_h / 2);
+ source_img = ctx.getImageData(0, 0, source_w, source_h);
+ resize_img = ctx.createImageData(resize_w, resize_h);
+ source_data = source_img.data;
+ resize_data = resize_img.data;
+
+ for (j = 0; j < resize_h; j++) {
+ for (i = 0; i < resize_w; i++) {
+ x2 = (i + j * resize_w) * 4;
+ weight = weights = weights_alpha = 0;
+ gx_r = gx_g = gx_b = gx_a = 0;
+ center_y = (j + 0.5) * ratio_h;
+
+ x_start = Math.floor(i * ratio_w);
+ x_stop = Math.ceil((i + 1) * ratio_w);
+ y_start = Math.floor(j * ratio_h);
+ y_stop = Math.ceil((j + 1) * ratio_h);
+
+ x_stop = Math.min(x_stop, source_w);
+ y_stop = Math.min(y_stop, source_h);
+
+ for (y = y_start; y < y_stop; y++) {
+ dy = Math.abs(center_y - (y + 0.5)) / ratio_h_half;
+ center_x = (i + 0.5) * ratio_w;
+ part_w = dy * dy;
+
+ for (x = x_start; x < x_stop; x++) {
+ dx = Math.abs(center_x - (x + 0.5)) / ratio_w_half;
+ w = Math.sqrt(part_w + dx * dx);
+ if (w >= 1) {
+ continue;
+ }
+ // Hermite 필터
+ weight = 2 * w * w * w - 3 * w * w + 1;
+ pos_x = 4 * (x + y * source_w);
+ // 알파 채널
+ gx_a += weight * source_data[pos_x + 3];
+ weights_alpha += weight;
+
+ if (source_data[pos_x + 3] < 255) {
+ weight = weight * source_data[pos_x + 3] / 250;
+ }
+
+ gx_r += weight * source_data[pos_x];
+ gx_g += weight * source_data[pos_x + 1];
+ gx_b += weight * source_data[pos_x + 2];
+ weights += weight;
+ }
+ }
+ resize_data[x2] = gx_r / weights;
+ resize_data[x2 + 1] = gx_g / weights;
+ resize_data[x2 + 2] = gx_b / weights;
+ resize_data[x2 + 3] = gx_a / weights_alpha;
+ }
+ }
+ canvas.width = resize_w;
+ canvas.height = resize_h;
+ ctx.putImageData(resize_img, 0, 0);
+ }
+
+ } else {
+ canvas = document.createElement("canvas"),
+ canvas.width = source_w; canvas.height = source_h;
+ ctx = canvas.getContext("2d");
+ ctx.drawImage(image, 0, 0);
+ resize_h = source_h;
+ resize_w = source_w;
+ }
+
+ if (this.reader.watermark && addWaterMark) {
+ ctx.globalAlpha = oEditor.config.imgWaterMarkAlpha;
+ ctx.drawImage(this.reader.watermark,
+ canvas.width - this.reader.watermark.width, canvas.height - this.reader.watermark.height);
+ }
+
+ return canvas.toDataURL(filetype, oEditor.config.imgJpegQuality);
+ },
+
+ canvasToBlob : function (bitmapData, mimetype) {
+ var i = 0,
+ intArray = [],
+ len = bitmapData.length,
+ raw = atob(bitmapData.split(',')[1]);
+
+ for (; i < len; i++) {
+ intArray.push(raw.charCodeAt(i));
+ }
+ return new Blob([new Uint8Array(intArray)], {type: mimetype});
+ },
+
+ makeThumbnail : function (image, type, name, orientation) {
+ var width,
+ xhr = new XMLHttpRequest(),
+ data = new FormData(),
+ bitmapData, file;
+
+ xhr.open('POST', uploadScript, true);
+ width = oEditor.config.thumbnailWidth;
+
+ bitmapData = this.imageResize(image, type, width, orientation);
+ file = this.canvasToBlob(bitmapData, type);
+ data.append(inputFileName, file, 'thumb_' + name); // RFC Level 2
+
+ xhr.addEventListener("loadend", function () {
+ // loadend
+ }, false);
+
+ xhr.addEventListener("error", function () {
+ alert("Thumbnail 파일 전송 중 오류:");
+ }, false);
+
+ xhr.send(data);
+ },
+
+ dataLoadHandler: function (evt) {
+ var self = this,
+ filename = evt.target.file.name,
+ filetype = evt.target.file.type,
+ file = evt.target.file,
+ blob, image, orientation = 1, slice = 64 * 1024;
+
+ if (slice > file.size - 1) {
+ slice = file.size;
+ }
+
+ if (evt.target.readyState === FileReader.DONE) {
+ blob = new self.MyBlob(self.NewBlob(evt.target.result, filetype));
+ orientation = self.getOrientation(evt.target.result.slice(0, slice));
+
+ image = new Image();
+ image.onload = function () {
+ var bitmapData = null,
+ data = new FormData(),
+ fileFormat,
+ imgBox = file.boxElem,
+ imgInfo = {},
+ randomName,
+ xhr = new XMLHttpRequest();
+
+ xhr.open('POST', uploadScript, true);
+
+ if (imageResizeWidth > 0) {
+ bitmapData = self.imageResize(this, filetype, imageResizeWidth, orientation, true);
+ file = self.canvasToBlob(bitmapData, filetype);
+ }
+
+ fileFormat = filename.substring(filename.lastIndexOf('.'));
+ randomName = self.makeFilename(fileFormat);
+
+ data.append('origname', filename);
+ data.append(inputFileName, file, randomName); // RFC Level 2
+
+ if (debug) {
+ console.log('Successed: ' + filename);
+ }
+
+ xhr.addEventListener("error", function (evt) {
+ alert("파일 전송 중 오류: " + evt.toString());
+ }, false);
+
+ xhr.addEventListener("loadend", function onLoadendImageHandler(xhrevt) {
+ if (xhrevt.target.readyState === xhrevt.target.DONE) {
+ if (oEditor.config.makeThumbnail) {
+ self.makeThumbnail(image, filetype, randomName, orientation, false);
+ }
+ }
+ image.src = '';
+ image = null;
+ }, false);
+
+ xhr.addEventListener("load", function (xhrevt) {
+ var jsonText, jsonData, img, onLoadHandler;
+ data = null;
+
+ if (xhrevt.target.status === 200) {
+ jsonText = decodeURI(oEditor.trimSpace(this.responseText));
+ jsonText = jsonText.replace(/\+/g, ' ').replace(/\\/g, '\\\\');
+ jsonData = JSON.parse(jsonText);
+
+ onLoadHandler = function () {
+ imgInfo = {
+ fileName: jsonData.fileName,
+ filePath: jsonData.filePath,
+ fileSize: jsonData.fileSize,
+ fileUrl: jsonData.fileUrl,
+ origName: filename,
+ origSize: file.size,
+ height: img.height,
+ width: img.width
+ };
+ imageCompletedList[imgBox.id] = imgInfo;
+ imgComplete(this, imgInfo, imgBox.id);
+ imgBox.appendChild(img);
+
+ if (debug) {
+ console.log('Image URL: ' + img.src + ', size:' + file.size);
+ }
+
+ setTimeout(function () {
+ self.load();
+ }, 100);
+
+ if (debug) {
+ console.log('Uploaded');
+ }
+ };
+ img = new Image();
+ img.onload = onLoadHandler;
+ img.src = decodeURIComponent(jsonData.fileUrl);
+ } else {
+ alert("HTTP 오류: " + xhr.status);
+ }
+ }, false);
+
+ blob.dispose();
+ blob = null;
+ xhr.send(data);
+ };
+
+ image.src = blob.getURL();
+ }
+ },
+
+ onReadDataErrorHandler: function (evt) {
+ var status = '';
+ switch (evt.target.error.code) {
+ case evt.target.error.NOT_FOUND_ERR:
+ status = "파일을 찾을 수 없습니다.";
+ break;
+ case evt.target.error.NOT_READABLE_ERR:
+ status = "파일을 읽을 수 없습니다.";
+ break;
+ case evt.target.error.ABORT_ERR:
+ status = "파일 읽기가 중지되었습니다.";
+ break;
+ case evt.target.error.SECURITY_ERR:
+ status = "파일이 잠겨 있습니다.";
+ break;
+ case evt.target.error.ENCODING_ERR:
+ status = "data:// URL의 파일 인코딩 길이가 너무 깁니다.";
+ break;
+ default:
+ status = "파일 읽기 오류: " + evt.target.error.code;
+ }
+ this.removeEventListener('error', this.onReadDataErrorHandler);
+ alert("'" + evt.target.filename + "' " + status);
+ },
+
+ load: function () {
+ var file = this.list.shift(), self = this, watermark = null;
+
+ if (file) {
+ if (debug) {
+ console.log('File ' + this.index + ', Name: ' + file.name + ', Size: ' + file.size);
+ }
+ this.reader.file = file;
+ this.reader.watermark = null;
+
+ if (oEditor.config.imgWaterMarkUrl !== '' && oEditor.config.imgWaterMarkUrl !== null) {
+ watermark = new Image();
+ watermark.onerror = function () {
+ alert('워터마크 이미지를 읽을 수 없습니다. (' + oEditor.config.imgWaterMarkUrl + ')');
+ self.reader.readAsArrayBuffer(file);
+ };
+ watermark.onload = function () {
+ self.reader.watermark = this;
+ self.reader.readAsArrayBuffer(file);
+ };
+ watermark.src = oEditor.config.imgWaterMarkUrl;
+ } else {
+ this.reader.readAsArrayBuffer(file);
+ }
+ } else {
+ this.clear();
+ }
+ },
+
+ clear: function () {
+ var inputFile = document.getElementById('inputImageUpload'),
+ theForm = document.createElement('form'),
+ fileSelectButton = document.getElementById('fileSelectButton');
+
+ this.list = [];
+
+ theForm.appendChild(inputFile);
+ theForm.reset();
+ fileSelectButton.parentNode.insertBefore(inputFile, fileSelectButton);
+ fileSelectButton.style.marginLeft = '-1px';
+ }
+};
+
+function fileSelectDrop(evt) {
+ var files,
+ upload = new DoUpload();
+
+ oEditor.stopEvent(evt);
+ this.className = "imageListWrapperHtml5";
+
+ files = evt.dataTransfer.files;
+ upload.select(files);
+}
+
+function dragOver(ev) {
+ oEditor.stopEvent(ev);
+ this.className = "dragOver";
+}
+
+function dragOut(ev) {
+ oEditor.stopEvent(ev);
+ this.className = "imageListWrapperHtml5";
+}
+
+function setResizeWidth() {
+ var value = oEditor.trimSpace(imageResizeInput.value);
+ if (value) {
+ value = Math.ceil(parseInt(value, 10));
+ if (!isNaN(value) && value < oEditor.config.imgMaxWidth) {
+ imageResizeWidth = value;
+ } else {
+ imageResizeInput.value = '';
+ imageResizeWidth = oEditor.config.imgMaxWidth;
+ imageResizeInput.setAttribute('placeholder', oEditor.config.imgMaxWidth.toString());
+ }
+ }
+}
+
+function init(dialog) {
+ var dlg, i, elem, input, select, value, name, xhr_f, xhr_v, tmpcanvas, glicon;
+
+ oEditor = this;
+ oEditor.dialog = dialog;
+ dlg = new Dialog(oEditor);
+ browser = oEditor.getBrowser();
+
+ uploadImagePath = oEditor.config.iconPath + 'imageUpload';
+ uploadMaxNumber = oEditor.config.imgUploadNumber;
+ uploadScript = oEditor.config.editorPath + 'imageUpload/upload.php';
+ imageListWrapper = document.getElementById("imageListWrapper");
+ imageResizeInput = document.getElementById('idResizeWidth');
+ select = document.getElementById('idResizeSelectBox');
+
+ if (oEditor.config.imgMaxWidth > 0) {
+ imageResizeWidth = oEditor.config.imgMaxWidth;
+ for (i = 0; i < oEditor.config.imgResizeValue.length; i++) {
+ name = value = oEditor.config.imgResizeValue[i];
+ if (value > oEditor.config.imgMaxWidth) {
+ continue;
+ }
+ if (value === -1) {
+ name = '<입력>';
+ }
+ select.options[select.options.length] = new Option(name, value, false, value === oEditor.config.imgResizeSelected);
+ }
+ select.onchange = function () {
+ if (this.value < 0) {
+ document.getElementById('idUserInputWrapper').style.display = '';
+ imageResizeInput.value = '';
+ imageResizeWidth = oEditor.config.imgMaxWidth;
+ imageResizeInput.focus();
+ } else {
+ document.getElementById('idUserInputWrapper').style.display = 'none';
+ imageResizeWidth = this.value;
+ }
+ };
+ imageResizeInput.setAttribute('placeholder', imageResizeWidth.toString());
+ imageResizeWidth = select.value;
+ } else {
+ select.options[0] = new Option('원본', 0);
+ select.setAttribute('disabled', 'disabled');
+ imageResizeWidth = 0;
+ }
+
+ document.getElementById("maxImageNum").appendChild(document.createTextNode(uploadMaxNumber.toString()));
+
+ button = [
+ { alt: "", img: 'submit.gif', cmd: doSubmit, hspace: 2 },
+ { alt: "", img: 'cancel.gif', cmd: closeWindow, hspace: 2 }
+ ];
+
+ dlg.setDialogHeight(340);
+ dlg.showButton(button);
+ showContents();
+ initGallery();
+ showUploadWindow();
+ createInsertionMaker();
+
+ oEditor.addEvent(imageListWrapper, 'dragover', dragOver);
+ oEditor.addEvent(imageListWrapper, 'dragleave', dragOut);
+ oEditor.addEvent(imageListWrapper, 'drop', fileSelectDrop);
+
+ elem = document.getElementById('id_alignment').elements;
+
+ for (i = 0; i < elem.length; i++) {
+ if (elem[i].name === "alignment" && elem[i].value === oEditor.config.imgDefaultAlign) {
+ elem[i].checked = "checked";
+ break;
+ }
+ }
+
+ if (browser.mobile) {
+ input = document.getElementById('inputImageUpload');
+ input.setAttribute('capture', 'filesystem');
+ }
+
+ tmpcanvas = document.createElement('canvas');
+ if (tmpcanvas.getContext('webgl', {preserveDrawingBuffer: true}) ||
+ tmpcanvas.getContext('experimental-webgl', {preserveDrawingBuffer: true}))
+ {
+ useWebGL = true;
+ GLScale.Hermite = { vertex: '', fragment: '' };
+ xhr_v = new XMLHttpRequest();
+ xhr_f = new XMLHttpRequest();
+ xhr_f.open('POST', 'js/fragment-shader.glsl', true);
+ xhr_f.addEventListener("load", function (evt) {
+ if (evt.target.status === 200) {
+ GLScale.Hermite.fragment = this.responseText;
+ } else {
+ useWebGL = false;
+ }
+ });
+ xhr_v.open('POST', 'js/vertex-shader.glsl', true);
+ xhr_v.addEventListener("load", function (evt) {
+ if (evt.target.status === 200) {
+ GLScale.Hermite.vertex = this.responseText;
+ } else {
+ useWebGL = false;
+ }
+ });
+ xhr_f.send();
+ xhr_v.send();
+ }
+ glicon = new Image();
+ glicon.className = 'webgl_logo';
+ glicon.src = uploadImagePath + (useWebGL ? "/webgl.png" : "/webgl-off.png");
+ document.getElementById('webgl_logo_wrapper').appendChild(glicon);
+}
diff --git a/plugin/editor/cheditor5/popup/js/vertex-shader.glsl b/plugin/editor/cheditor5/popup/js/vertex-shader.glsl
new file mode 100644
index 000000000..56de4be9a
--- /dev/null
+++ b/plugin/editor/cheditor5/popup/js/vertex-shader.glsl
@@ -0,0 +1,10 @@
+// -------------------------------------------------------
+// CHEditor WebGL Vertex Shader
+// -------------------------------------------------------
+attribute vec2 a_position;
+uniform vec2 u_resolution;
+
+void main() {
+ vec2 clipSpace = (a_position / u_resolution * 2.0) - 1.0;
+ gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
+}
diff --git a/plugin/editor/cheditor5/template-mobile.xml b/plugin/editor/cheditor5/template-mobile.xml
new file mode 100644
index 000000000..f0d8a87e2
--- /dev/null
+++ b/plugin/editor/cheditor5/template-mobile.xml
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <html>
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugin/editor/cheditor5/template.xml b/plugin/editor/cheditor5/template.xml
index 8aef7b6f0..dd8ba52a0 100644
--- a/plugin/editor/cheditor5/template.xml
+++ b/plugin/editor/cheditor5/template.xml
@@ -10,7 +10,7 @@
-
+
@@ -73,6 +73,18 @@
+
+