diff --git a/app/app.xhtml b/app/app.xhtml index 407d2873..be2288a9 100644 --- a/app/app.xhtml +++ b/app/app.xhtml @@ -146,11 +146,11 @@ - + @@ -225,7 +225,6 @@ - diff --git a/app/package.json b/app/package.json index a0555afb..5bda0a7e 100644 --- a/app/package.json +++ b/app/package.json @@ -2,7 +2,7 @@ "name": "Pencil", "productName": "Pencil", "description": "An open-source GUI prototyping tool that is available for ALL platforms.", - "version": "3.1.1", + "version": "3.1.2", "author": { "name": "Evolus", "url": "http://evolus.vn", diff --git a/app/pencil-core/behavior/commonFunctions.js b/app/pencil-core/behavior/commonFunctions.js index ff563297..f8a3a76f 100644 --- a/app/pencil-core/behavior/commonFunctions.js +++ b/app/pencil-core/behavior/commonFunctions.js @@ -84,8 +84,9 @@ F.newDOMElement = function (spec) { if (name.match(/^_/)) continue; e.setAttribute(name, spec[name]); } - - if (spec._text) { + if (spec._html) { + e.innerHTML = spec._html; + } else if (spec._text) { e.appendChild(e.ownerDocument.createTextNode(spec._text)); } if (spec._children && spec._children.length > 0) { diff --git a/app/pencil-core/canvasHelper/GestureHelper.js b/app/pencil-core/canvasHelper/GestureHelper.js index 8768593f..fdf06b3f 100644 --- a/app/pencil-core/canvasHelper/GestureHelper.js +++ b/app/pencil-core/canvasHelper/GestureHelper.js @@ -67,7 +67,7 @@ GestureHelper.prototype.updateKeyCodes = function () { if (this.activeGestureDef) break; } - GestureHelper._output.innerHTML = this.heldKeyCodes.join(", ") + ":" + this.heldKeyCodes.map(c => {return String.fromCharCode(c)}).join(", "); + //GestureHelper._output.innerHTML = this.heldKeyCodes.join(", ") + ":" + this.heldKeyCodes.map(c => {return String.fromCharCode(c)}).join(", "); }; GestureHelper.fromCanvas = function (canvas) { diff --git a/app/pencil-core/common/Canvas.js b/app/pencil-core/common/Canvas.js index 8d700345..eed1d28e 100644 --- a/app/pencil-core/common/Canvas.js +++ b/app/pencil-core/common/Canvas.js @@ -1945,6 +1945,24 @@ Canvas.prototype.doCopy = function () { var transferableData = this.currentController.createTransferableData(); + var target = null; + + if (transferableData.dataNode.getAttributeNS(PencilNamespaces.p, "type")) { + target = this.createControllerFor(transferableData.dataNode); + } else { + var targets = []; + for (var i = 0; i < transferableData.dataNode.childNodes.length; i ++) { + var node = transferableData.dataNode.childNodes[i]; + var subTarget = this.createControllerFor(node); + + targets.push(subTarget); + } + target = new TargetSet(this, targets); + } + + if (target.processExportingTransferableProperties) target.processExportingTransferableProperties(); + + transferableData.dataNode.removeAttribute("p:parentRef"); var metaNode = Dom.getSingle(".//p:metadata", transferableData.dataNode); var childTargetsNode = Dom.getSingle("./p:childTargets", metaNode); diff --git a/app/pencil-core/common/controller.js b/app/pencil-core/common/controller.js index 1c96ecc5..9641b157 100644 --- a/app/pencil-core/common/controller.js +++ b/app/pencil-core/common/controller.js @@ -1425,7 +1425,7 @@ Controller.prototype.invalidateBitmapFilePath = function (page, invalidatedIds) for (var key in page.bitmapCache) { var filePath = page.bitmapCache[key]; try { - fs.unlinkSync(page.bitmapFilePath); + fs.unlinkSync(filePath); } catch (e) { } } diff --git a/app/pencil-core/common/svgRasterizer.js b/app/pencil-core/common/svgRasterizer.js index bbeda177..24648b44 100644 --- a/app/pencil-core/common/svgRasterizer.js +++ b/app/pencil-core/common/svgRasterizer.js @@ -359,6 +359,8 @@ Rasterizer.getExportScale = function (inputScale) { } Rasterizer.prototype.rasterizeSelectionToFile = function (target, filePath, callback, scale, options) { var geo = target.getGeometry(); + var rect = target.svg.getBoundingClientRect(); + if (!geo) { //Util.showStatusBarWarning(Util.getMessage("the.selected.objects.cannot.be.exported"), true); alert(Util.getMessage("the.selected.objects.cannot.be.exported")); @@ -373,8 +375,8 @@ Rasterizer.prototype.rasterizeSelectionToFile = function (target, filePath, call padding += strokeStyle.w; } - var w = geo.dim.w + padding; - var h = geo.dim.h + padding; + var w = rect.width + padding; + var h = rect.height + padding; debug("w: " + w); @@ -382,18 +384,15 @@ Rasterizer.prototype.rasterizeSelectionToFile = function (target, filePath, call svg.setAttribute("width", "" + w + "px"); svg.setAttribute("height", "" + h + "px"); + var wrapper = document.createElementNS(PencilNamespaces.svg, "g"); + var prect = target.svg.ownerSVGElement.getBoundingClientRect(); + wrapper.setAttribute("transform", "translate(" + (prect.x - rect.x) + ", " + (prect.y - rect.y) + ")"); + var content = target.svg.cloneNode(true); - content.removeAttribute("transform"); content.removeAttribute("id"); - try { - var dx = Math.round((w - geo.dim.w) / 2); - var dy = Math.round((h - geo.dim.h) / 2); - content.setAttribute("transform", "translate(" + dx + ", " + dy + ")"); - } catch (e) { - Console.dumpError(e); - } - svg.appendChild(content); + svg.appendChild(wrapper); + wrapper.appendChild(content); var thiz = this; var s = Rasterizer.getExportScale(scale); @@ -411,7 +410,6 @@ Rasterizer.prototype.rasterizeSelectionToFile = function (target, filePath, call }); }, false, options); }; - Rasterizer.prototype._prepareWindowForRasterization = function(backgroundColor) { var h = 0; var w = 0; diff --git a/app/pencil-core/common/util.js b/app/pencil-core/common/util.js index 1d7ede19..6a0f5abf 100644 --- a/app/pencil-core/common/util.js +++ b/app/pencil-core/common/util.js @@ -469,9 +469,9 @@ Object.defineProperty(Event.prototype, "originalTarget", { var domParser = new DOMParser(); -/* public static XmlDocument */ Dom.loadSystemXml = function (relPath) { +/* public static XmlDocument */ Dom.loadSystemXml = function (relPath, preProcessFileContent) { var absPath = getStaticFilePath(relPath); - return Dom.parseFile(absPath); + return Dom.parseFile(absPath, preProcessFileContent); }; Dom.isElementExistedInDocument = function(element) { @@ -917,8 +917,9 @@ Dom.swapNode = function (node1, node2) { parentNode.removeChild(node1); parentNode.insertBefore(node1, ref); }; -Dom.parseFile = function (file) { +Dom.parseFile = function (file, preProcessFileContent) { var fileContents = fs.readFileSync(file, "utf8"); + if (preProcessFileContent) fileContents = preProcessFileContent(fileContents); var dom = Dom.parser.parseFromString(fileContents, "text/xml"); return dom; }; diff --git a/app/pencil-core/editor/handleEditor.config.xml b/app/pencil-core/editor/handleEditor.config.xml index fd9525da..b6802dad 100644 --- a/app/pencil-core/editor/handleEditor.config.xml +++ b/app/pencil-core/editor/handleEditor.config.xml @@ -12,8 +12,8 @@ @namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul); g.HandleEditor rect[p|name='Handle'] { - fill: #ff0; - stroke: #0a0; + fill: $handle_fill_color; + stroke: $handle_stroke_color; stroke-width: 3; stroke-opacity: 0; fill-opacity: .7; @@ -21,7 +21,7 @@ g.HandleEditor rect[p|name='Handle'][p|focused='true'] { stroke-width: 2; stroke-opacity: 1; - stroke: #f00; + stroke: $handle_focused_stroke_color; } g.HandleEditor rect[p|name='Handle']:hover { stroke-width: 6 !important; @@ -30,7 +30,7 @@ } g.HandleEditor rect[p|name='Handle'][p|connected='true'] { stroke-width: 15 !important; - stroke: #f00 !important; + stroke: $handle_connected_stroke_color !important; stroke-opacity: .5 !important; } ]]> diff --git a/app/pencil-core/editor/handleEditor.js b/app/pencil-core/editor/handleEditor.js index 3ce29e3c..55ce2e75 100644 --- a/app/pencil-core/editor/handleEditor.js +++ b/app/pencil-core/editor/handleEditor.js @@ -3,7 +3,15 @@ function HandleEditor() { this.canvas = null; } HandleEditor.ANCHOR_SIZE = 6; -HandleEditor.configDoc = Dom.loadSystemXml("pencil-core/editor/handleEditor.config.xml"); +HandleEditor.configDoc = Dom.loadSystemXml("pencil-core/editor/handleEditor.config.xml", function (fileContent) { + if (!fileContent) return ""; + var newContent = fileContent + .replace("$handle_fill_color", Config.get("handle.fill_color", "#ff0")) + .replace("$handle_stroke_color",Config.get("handle.stroke_color", "#0a0")) + .replace("$handle_focused_stroke_color", Config.get("handle.focused_stroke_color", "#f00")) + .replace("$handle_connected_stroke_color", Config.get("handle.connected_stroke_color", "#f00")); + return newContent; +}); HandleEditor.prototype.install = function (canvas) { this.canvas = canvas; this.canvas.onScreenEditors.push(this); diff --git a/app/pencil-core/propertyType/handle.js b/app/pencil-core/propertyType/handle.js index 2f9e29f8..a2c13079 100644 --- a/app/pencil-core/propertyType/handle.js +++ b/app/pencil-core/propertyType/handle.js @@ -6,8 +6,8 @@ Handle.REG_EX = /^([\-0-9\.]+)\,([\-0-9\.]+)$/; Handle.fromString = function(literal) { var handle = new Handle(); if (literal.match(Handle.REG_EX)) { - handle.x = parseFloat(RegExp.$1); - handle.y = parseFloat(RegExp.$2); + handle.x = Math.round(RegExp.$1); + handle.y = Math.round(RegExp.$2); } return handle; diff --git a/app/pencil-core/propertyType/imageData.js b/app/pencil-core/propertyType/imageData.js index d325783b..5b6dbc13 100644 --- a/app/pencil-core/propertyType/imageData.js +++ b/app/pencil-core/propertyType/imageData.js @@ -87,10 +87,40 @@ ImageData.invalidateValue = function (oldData, callback) { callback(null, error); } }); + } else if (oldData.data.match(/^(ref:\/\/([^@]+))@(.+)$/)) { + var ref = RegExp.$1; + var fp = RegExp.$3; + var id = ImageData.refStringToId(ref); + var refFilePath = Pencil.controller.refIdToFilePath(id); + + const fs = require("fs"); + // assume that the ref is local to this document, generate the local file path and check it + if (fsExistSync(refFilePath)) { + callback(new ImageData(oldData.w, oldData.h, ref, null)); + } else { + Pencil.controller.copyAsRef(fp, function (id, error) { + if (id) { + callback(new ImageData(oldData.w, oldData.h, ImageData.idToRefString(id)), null); + } else { + callback(null, error); + } + }); + } } else { callback(null); } }; +ImageData.prepareForTransferable = function (imageData, propDef) { + if (imageData.data.match(/^ref:\/\//)) { + var data = imageData.data; + if (imageData.data.match(/^(ref:\/\/[^@]+)(@.+)$/)) data = RegExp.$1; + var id = ImageData.refStringToId(data); + if (!id) return; + var filePath = Pencil.controller.refIdToFilePath(id); + data = data + "@" + filePath; + imageData.data = data; + } +}; ImageData.prepareForEmbedding = function (oldData, callback) { if (oldData.data.match(/^ref:\/\//)) { var id = ImageData.refStringToId(oldData.data); diff --git a/app/pencil-core/propertyType/richText.js b/app/pencil-core/propertyType/richText.js index 7b4abdd6..9f7bd994 100644 --- a/app/pencil-core/propertyType/richText.js +++ b/app/pencil-core/propertyType/richText.js @@ -1,6 +1,9 @@ function RichText(html) { this.html = html; this.value = html; + if (this.html instanceof PlainText && this.html.value) { + this.html.value = Dom.htmlEncode(this.html.value); + } } RichText.fromString = function (html) { return new RichText(html); diff --git a/app/pencil-core/target/group.js b/app/pencil-core/target/group.js index 1f411f69..3acb2295 100644 --- a/app/pencil-core/target/group.js +++ b/app/pencil-core/target/group.js @@ -440,6 +440,16 @@ Group.prototype.createTransferableData = function () { dataNode: this.svg.cloneNode(true) }; }; +Group.prototype.processExportingTransferableProperties = function () { + for (t in this.targets) { + this.targets[t].processExportingTransferableProperties(); + } +}; +Group.prototype.processImportedTransferableProperties = function () { + for (t in this.targets) { + this.targets[t].processImportedTransferableProperties(); + } +}; Group.prototype.lock = function () { this.svg.setAttributeNS(PencilNamespaces.p, "p:locked", "true"); }; diff --git a/app/pencil-core/target/shape.js b/app/pencil-core/target/shape.js index fa7a2b25..67319b77 100644 --- a/app/pencil-core/target/shape.js +++ b/app/pencil-core/target/shape.js @@ -878,16 +878,7 @@ Shape.prototype.getTextEditingInfo = function (editingEvent) { } } var targetObject = Dom.getSingle(".//*[@p:name='" + target + "']", this.svg); - //checking if the target is ok for use to base the location calculation - var ok = true; - try { - var clientRect = targetObject.getBoundingClientRect(); - if (clientRect.width == 0 || clientRect.height == 0) { - ok = false; - } - } catch (e) {} - - if (ok) { + if (targetObject) { info = {prop: prop, value: this.getProperty(name), targetName: target, @@ -1061,12 +1052,56 @@ Shape.prototype.getTextEditingInfo = function (editingEvent) { }; Shape.prototype.createTransferableData = function () { + var dataNode = this.svg.cloneNode(true); + return { type: ShapeXferHelper.MIME_TYPE, isSVG: true, - dataNode: this.svg.cloneNode(true) + dataNode: dataNode }; }; +Shape.prototype.processExportingTransferableProperties = function () { + for (var name in this.def.propertyMap) { + var prop = this.def.propertyMap[name]; + var value = this.getProperty(name); + + if (prop.type.prepareForTransferable) { + prop.type.prepareForTransferable(value, prop); + this.storeProperty(name, value); + } + } +}; + +Shape.prototype.processImportedTransferableProperties = function () { + var names = []; + for (var name in this.def.propertyMap) { + names.push(name); + } + var index = -1; + var thiz = this; + (function next() { + index ++; + if (index >= names.length) return; + var name = names[index]; + + var prop = thiz.def.propertyMap[name]; + var value = thiz.getProperty(name); + + if (prop.type.invalidateValue) { + prop.type.invalidateValue(value, function (newValue) { + if (newValue) { + thiz.storeProperty(name, newValue); + thiz.applyBehaviorForProperty(name); + } + next(); + }); + } else { + next(); + } + })(); +} + + Shape.prototype.lock = function () { this.svg.setAttributeNS(PencilNamespaces.p, "p:locked", "true"); }; diff --git a/app/pencil-core/target/targetSet.js b/app/pencil-core/target/targetSet.js index 48cdaa32..d606faaa 100644 --- a/app/pencil-core/target/targetSet.js +++ b/app/pencil-core/target/targetSet.js @@ -2,7 +2,7 @@ function TargetSet(canvas, targets) { this.canvas = canvas; this.targets = targets; this.targetIds = []; - + this.id = "sys_currentTargetSet"; for (var target of this.targets) this.targetIds.push(target.id); @@ -121,7 +121,7 @@ TargetSet.prototype.getBoundingRect = function () { }; rect2.width = Math.max(0, Math.max(rect.x + rect.width, r.x + r.width) - rect2.x); rect2.height = Math.max(0, Math.max(rect.y + rect.height, r.y + r.height) - rect2.y); - + rect = rect2; } return rect; @@ -536,6 +536,7 @@ TargetSet.prototype.sendToBack = function () { }; TargetSet.prototype.createTransferableData = function () { var node = this.canvas.ownerDocument.createElementNS(PencilNamespaces.svg, "g"); + for (i in this.targets) node.appendChild(this.targets[i].createTransferableData().dataNode); return {type: TargetSetXferHelper.MIME_TYPE, @@ -543,6 +544,16 @@ TargetSet.prototype.createTransferableData = function () { dataNode: node }; }; +TargetSet.prototype.processExportingTransferableProperties = function () { + for (t in this.targets) { + this.targets[t].processExportingTransferableProperties(); + } +}; +TargetSet.prototype.processImportedTransferableProperties = function () { + for (t in this.targets) { + this.targets[t].processImportedTransferableProperties(); + } +}; TargetSet.prototype.lock = function () { for (i in this.targets) if (this.targets[i].lock) this.targets[i].lock(); }; @@ -614,12 +625,12 @@ TargetSet.prototype.invalidateOutboundConnections = function () { TargetSet.prototype.getSnappingGuide = function () { var vertical = []; var horizontal = []; - + for (target of this.targets) { if (!target.getSnappingGuide) continue; var guide = target.getSnappingGuide(); if (!guide) continue; - + if (guide.horizontal && guide.horizontal.length > 0) horizontal = horizontal.concat(guide.horizontal); if (guide.vertical && guide.vertical.length > 0) vertical = vertical.concat(guide.vertical); } @@ -628,4 +639,3 @@ TargetSet.prototype.getSnappingGuide = function () { vertical: vertical, horizontal: horizontal }; }; - diff --git a/app/pencil-core/templates/HTML/prototype.HTML/Resources/script.js b/app/pencil-core/templates/HTML/prototype.HTML/Resources/script.js index 5040fa04..0f0af3ea 100644 --- a/app/pencil-core/templates/HTML/prototype.HTML/Resources/script.js +++ b/app/pencil-core/templates/HTML/prototype.HTML/Resources/script.js @@ -142,26 +142,6 @@ function handleMouseMove() { var THUMB_WIDTH = 250; var THUMB_HEIGHT = 160; -var THUMB_DISPLAY_SIZE = 160; - -function buildThumbnail(url, callback) { - var image = new Image(); - image.onload = function () { - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - - var r = Math.max(image.width / THUMB_WIDTH, image.height / THUMB_HEIGHT); - var w = image.width / r, h = image.height / r; - canvas.width = w; - canvas.height = h; - - ctx.drawImage(image, 0, 0, w, h); - - callback(canvas.toDataURL('image/png'), w, h); - }; - - image.src = url; -} function generateTOC() { var toc = document.createElement("div"); @@ -173,7 +153,7 @@ function generateTOC() { var item = document.createElement("div"); var imageWrapper = document.createElement("a"); - var itemImage = document.createElement("img"); + item.classList.add("Page_" + page.id); item.setAttribute("tabindex", 0); @@ -182,22 +162,19 @@ function generateTOC() { imageWrapper.setAttribute("href", "#" + page.id); item.appendChild(imageWrapper); - var name = document.createElement("strong"); - name.innerHTML = title.innerHTML; toc.appendChild(item); - buildThumbnail(img.src, function (dataUrl, w, h) { - var r = Math.max(w / THUMB_DISPLAY_SIZE, h / THUMB_DISPLAY_SIZE); - var w = w / r, h = h / r; - - imageWrapper.appendChild(itemImage); - itemImage.style.width = w + "px"; - itemImage.style.height = h + "px"; - itemImage.src = dataUrl; - - imageWrapper.appendChild(name); - }); + var itemImage = document.createElement("img"); + itemImage.style.maxWidth = THUMB_WIDTH + "px"; + itemImage.style.maxHeight = THUMB_HEIGHT + "px"; + itemImage.src = img.src; + imageWrapper.appendChild(itemImage); + + var name = document.createElement("strong"); + name.innerHTML = title.innerHTML; + imageWrapper.appendChild(name); + }); document.body.appendChild(toc); diff --git a/app/pencil-core/xferHelper/shapeXferHelper.js b/app/pencil-core/xferHelper/shapeXferHelper.js index 25edf6cf..bd82999e 100644 --- a/app/pencil-core/xferHelper/shapeXferHelper.js +++ b/app/pencil-core/xferHelper/shapeXferHelper.js @@ -48,21 +48,33 @@ ShapeXferHelper.prototype.handleData = function (dom) { } } + if (this.canvas.currentController.processImportedTransferableProperties) { + try { + var processed = this.canvas.currentController.processImportedTransferableProperties(); + if (processed) { + this.canvas.selectNone(); + this.canvas.selectShape(shape); + } + } catch (e) { + console.error(e); + } + } + var rect = this.canvas.currentController.getBoundingRect(); var mx = dx; var my = dy; - + var padding = this.canvas.element.getBoundingClientRect().left - this.canvas._wrapper.getBoundingClientRect().left; var x0 = this.canvas._scrollPane.scrollLeft - padding; var y0 = this.canvas._scrollPane.scrollTop - padding; - + console.log(this.canvas.getSize(), this.canvas._scrollPane.scrollWidth, this.canvas._scrollPane.scrollHeight); - + var x1 = x0 + Math.min(this.canvas.getSize().width, this.canvas._scrollPane.clientWidth - padding); var y1 = y0 + Math.min(this.canvas.getSize().height, this.canvas._scrollPane.clientHeight - padding); - + console.log(x0, y0, x1, y1, padding); - + if (rect.x + rect.width > x1 || rect.x < x0) { mx = Math.round((x1 + x0) / 2 - (rect.x + rect.width / 2)); } diff --git a/app/pencil-core/xferHelper/targetSetXferHelper.js b/app/pencil-core/xferHelper/targetSetXferHelper.js index 6e6446a5..27bf9d3c 100644 --- a/app/pencil-core/xferHelper/targetSetXferHelper.js +++ b/app/pencil-core/xferHelper/targetSetXferHelper.js @@ -33,23 +33,48 @@ TargetSetXferHelper.prototype.handleData = function (dom) { this.canvas.drawingLayer.appendChild(shape); importedShapes.push(shape); } - this.canvas.selectMultiple(importedShapes) - + + this.canvas.selectMultiple(importedShapes); + + if (this.canvas.currentController.renewTargetProperties) { + try { + var renewed = this.canvas.currentController.renewTargetProperties(); + if (renewed) { + this.canvas.selectNone(); + this.canvas.selectMultiple(importedShapes); + } + } catch (e) { + console.error(e); + } + } + + if (this.canvas.currentController.processImportedTransferableProperties) { + try { + var processed = this.canvas.currentController.processImportedTransferableProperties(); + if (processed) { + this.canvas.selectNone(); + this.canvas.selectMultiple(importedShapes); + } + } catch (e) { + console.error(e); + } + } + var rect = this.canvas.currentController.getBoundingRect(); var mx = dx; var my = dy; - + var padding = this.canvas.element.getBoundingClientRect().left - this.canvas._wrapper.getBoundingClientRect().left; var x0 = this.canvas._scrollPane.scrollLeft - padding; var y0 = this.canvas._scrollPane.scrollTop - padding; - + console.log(this.canvas.getSize(), this.canvas._scrollPane.scrollWidth, this.canvas._scrollPane.scrollHeight); - + var x1 = x0 + Math.min(this.canvas.getSize().width, this.canvas._scrollPane.clientWidth - padding); var y1 = y0 + Math.min(this.canvas.getSize().height, this.canvas._scrollPane.clientHeight - padding); - + console.log(x0, y0, x1, y1, padding); - + if (rect.x + rect.width > x1 || rect.x < x0) { mx = Math.round((x1 + x0) / 2 - (rect.x + rect.width / 2)); } diff --git a/app/stencils/BasicWebElements/Layout.xhtml b/app/stencils/BasicWebElements/Layout.xhtml new file mode 100644 index 00000000..60af3d25 --- /dev/null +++ b/app/stencils/BasicWebElements/Layout.xhtml @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/app/stencils/BasicWebElements/layout_image.png b/app/stencils/BasicWebElements/layout_image.png new file mode 100644 index 00000000..4f1dc061 Binary files /dev/null and b/app/stencils/BasicWebElements/layout_image.png differ diff --git a/app/stencils/Common/Definition.xml b/app/stencils/Common/Definition.xml index 4f618fe6..c342bef0 100644 --- a/app/stencils/Common/Definition.xml +++ b/app/stencils/Common/Definition.xml @@ -1661,6 +1661,7 @@