From d770dd26e0f00a745eddca504e4ebb80e8cd02ae Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Thu, 14 Nov 2019 12:52:19 +0200 Subject: [PATCH] barcode field --- application/Espo/Core/Htmlizer/Htmlizer.php | 130 +++++++++++------- application/Espo/Core/Pdf/Tcpdf.php | 46 ++++++- .../Espo/Resources/i18n/en_US/Admin.json | 3 + .../Resources/i18n/en_US/FieldManager.json | 10 ++ .../Espo/Resources/metadata/app/jsLibs.json | 5 + .../Resources/metadata/fields/barcode.json | 50 +++++++ client/lib/JsBarcode.all.min.js | 2 + .../res/templates/fields/barcode/detail.tpl | 6 + client/src/views/fields/barcode.js | 102 ++++++++++++++ composer.json | 2 +- composer.lock | 29 ++-- 11 files changed, 319 insertions(+), 66 deletions(-) create mode 100644 application/Espo/Resources/metadata/fields/barcode.json create mode 100644 client/lib/JsBarcode.all.min.js create mode 100644 client/res/templates/fields/barcode/detail.tpl create mode 100644 client/src/views/fields/barcode.js diff --git a/application/Espo/Core/Htmlizer/Htmlizer.php b/application/Espo/Core/Htmlizer/Htmlizer.php index 386c2987a9..101d1cebb9 100644 --- a/application/Espo/Core/Htmlizer/Htmlizer.php +++ b/application/Espo/Core/Htmlizer/Htmlizer.php @@ -40,7 +40,7 @@ use Espo\Core\Utils\Language; use Espo\Core\Utils\Metadata; use Espo\ORM\EntityManager; -require('vendor/zordius/lightncandy/src/lightncandy.php'); +use LightnCandy\LightnCandy as LightnCandy; class Htmlizer { @@ -272,46 +272,38 @@ class Htmlizer public function render(Entity $entity, $template, $id = null, $additionalData = [], $skipLinks = false) { - $code = \LightnCandy::compile($template, [ - 'flags' => \LightnCandy::FLAG_HANDLEBARSJS, + $template = str_replace(' LightnCandy::FLAG_HANDLEBARSJS | LightnCandy::FLAG_ERROR_EXCEPTION, 'helpers' => [ - 'file' => function ($context, $options) { - if (count($context) && $context[0]) { - $id = $context[0]; - return "?entryPoint=attachment&id=" . $id; - } + 'file' => function () { + $args = func_get_args(); + $id = $args[0] ?? null; + if (!$id) return ''; + return "?entryPoint=attachment&id=" . $id; }, - 'numberFormat' => function ($context, $options) { - if ($context && isset($context[0])) { - $number = $context[0]; + 'var' => function () { + $args = func_get_args(); + $c = $args[1] ?? []; + $key = $args[0] ?? null; + if (is_null($key)) return null; + return $c[$key] ?? null; + }, + 'numberFormat' => function () { + $args = func_get_args(); + if (count($args) !== 2) return null; + $context = $args[count($args) - 1]; + $number = $args[0] ?? null; - $decimals = 0; - $decimalPoint = '.'; - $thousandsSeparator = ','; + if (is_null($number)) return ''; - if (isset($options['decimals'])) { - $decimals = $options['decimals']; - } - if (isset($options['decimalPoint'])) { - $decimalPoint = $options['decimalPoint']; - } - if (isset($options['thousandsSeparator'])) { - $thousandsSeparator = $options['thousandsSeparator']; - } - return number_format($number, $decimals, $decimalPoint, $thousandsSeparator); - } - return ''; + $decimals = $context['hash']['decimals'] ?? 0; + $decimalPoint = $context['hash']['decimalPoint'] ?? '.'; + $thousandsSeparator = $context['hash']['thousandsSeparator'] ?? ','; + + return number_format($number, $decimals, $decimalPoint, $thousandsSeparator); }, - 'var' => function ($context, $options) { - if ($context && isset($context[0]) && isset($context[1])) { - if (isset($context[1][$context[0]])) { - return $context[1][$context[0]]; - } - } - return; - }, - ], - 'hbhelpers' => [ 'dateFormat' => function () { $args = func_get_args(); if (count($args) !== 2) return null; @@ -326,6 +318,54 @@ class Htmlizer return $dateTime->convertSystemDate($dateValue, $format, $language); }, + 'barcodeImage' => function () { + $args = func_get_args(); + if (count($args) !== 2) return null; + $context = $args[count($args) - 1]; + $value = $args[0]; + + $codeType = $context['hash']['type'] ?? 'CODE128'; + + $typeMap = [ + "CODE128" => 'C128', + "CODE128A" => 'C128A', + "CODE128B" => 'C128B', + "CODE128C" => 'C128C', + "EAN13" => 'EAN13', + "EAN8" => 'EAN8', + "EAN5" => 'EAN5', + "EAN2" => 'EAN2', + "UPC" => 'UPCA', + "UPCE" => 'UPCE', + "ITF14" => 'I25', + "pharmacode" => 'PHARMA', + ]; + + $params = [ + $value, + $typeMap[$codeType] ?? null, + '', '', + $context['hash']['width'] ?? 60, + $context['hash']['height'] ?? 30, + 0.4, + [ + 'position' => 'S', + 'border' => false, + 'padding' => $context['hash']['padding'] ?? 0, + 'fgcolor' => $context['hash']['color'] ?? [0,0,0], + 'bgcolor' => $context['hash']['bgcolor'] ?? [255,255,255], + 'text' => $context['hash']['text'] ?? true, + 'font' => 'helvetica', + 'fontsize' => $context['hash']['fontsize'] ?? 14, + 'stretchtext' => 4, + ], + 'N', + ]; + + $paramsString = urlencode(json_encode($params)); + + return new LightnCandy\SafeString(""); + }, 'ifEqual' => function () { $args = func_get_args(); $context = $args[count($args) - 1]; @@ -356,23 +396,10 @@ class Htmlizer return $context['inverse'] ? $context['inverse']() : ''; } }, - ] + ], ]); - $toRemove = false; - if ($id === null) { - $id = uniqid('', true); - $toRemove = true; - } - - $fileName = 'data/cache/templates/' . $id . '.php'; - - $this->fileManager->putContents($fileName, $code); - $renderer = $this->fileManager->getPhpContents($fileName); - - if ($toRemove) { - $this->fileManager->removeFile($fileName); - } + $renderer = LightnCandy::prepare($code); $data = $this->getDataFromEntity($entity, $skipLinks, 0, $template); @@ -391,6 +418,7 @@ class Htmlizer } $data['__dateTime'] = $this->dateTime; + $data['__metadata'] = $this->metadata; $html = $renderer($data); diff --git a/application/Espo/Core/Pdf/Tcpdf.php b/application/Espo/Core/Pdf/Tcpdf.php index da754636c9..43da3918eb 100644 --- a/application/Espo/Core/Pdf/Tcpdf.php +++ b/application/Espo/Core/Pdf/Tcpdf.php @@ -29,6 +29,36 @@ namespace Espo\Core\Pdf; +define('K_TCPDF_EXTERNAL_CONFIG', true); + +define('K_TCPDF_CALLS_IN_HTML', true); + +define('K_BLANK_IMAGE', '_blank.png'); +define('PDF_PAGE_FORMAT', 'A4'); +define('PDF_PAGE_ORIENTATION', 'P'); +define('PDF_CREATOR', 'TCPDF'); +define('PDF_AUTHOR', 'TCPDF'); +define('PDF_UNIT', 'mm'); +define('PDF_MARGIN_HEADER', 5); +define('PDF_MARGIN_FOOTER', 10); +define('PDF_MARGIN_TOP', 27); +define('PDF_MARGIN_BOTTOM', 25); +define('PDF_MARGIN_LEFT', 15); +define('PDF_MARGIN_RIGHT', 15); +define('PDF_FONT_NAME_MAIN', 'helvetica'); +define('PDF_FONT_SIZE_MAIN', 10); +define('PDF_FONT_NAME_DATA', 'helvetica'); +define('PDF_FONT_SIZE_DATA', 8); +define('PDF_FONT_MONOSPACED', 'courier'); +define('PDF_IMAGE_SCALE_RATIO', 1.25); +define('HEAD_MAGNIFICATION', 1.1); +define('K_CELL_HEIGHT_RATIO', 1.25); +define('K_TITLE_MAGNIFICATION', 1.3); +define('K_SMALL_RATIO', 2/3); +define('K_THAI_TOPCHARS', true); +define('K_TCPDF_THROW_EXCEPTION_ERROR', false); +define('K_TIMEZONE', 'UTC'); + require "vendor/tecnickcom/tcpdf/tcpdf.php"; use \TCPDF_STATIC; @@ -42,6 +72,16 @@ class Tcpdf extends \TCPDF protected $useGroupNumbers = false; + public function serializeTCPDFtagParameters($data) + { + return urlencode(json_encode($data)); + } + + protected function unserializeTCPDFtagParameters($data) + { + return json_decode(urldecode($data), true); + } + public function setUseGroupNumbers($value) { $this->useGroupNumbers = $value; @@ -57,7 +97,8 @@ class Tcpdf extends \TCPDF $this->footerPosition = $position; } - public function Footer() { + public function Footer() + { $breakMargin = $this->getBreakMargin(); $autoPageBreak = $this->AutoPageBreak; @@ -80,7 +121,8 @@ class Tcpdf extends \TCPDF $this->SetAutoPageBreak($autoPageBreak, $breakMargin); } - protected function _putpages() { + protected function _putpages() + { $filter = ($this->compress) ? '/Filter /FlateDecode ' : ''; // get internal aliases for page numbers $pnalias = $this->getAllInternalPageNumberAliases(); diff --git a/application/Espo/Resources/i18n/en_US/Admin.json b/application/Espo/Resources/i18n/en_US/Admin.json index 9e6dfb35db..b12bf39207 100644 --- a/application/Espo/Resources/i18n/en_US/Admin.json +++ b/application/Espo/Resources/i18n/en_US/Admin.json @@ -135,6 +135,7 @@ "number": "Number (auto-increment)", "colorpicker": "Color Picker", "checklist": "Checklist", + "barcode": "Barcode", "jsonArray": "Json Array", "jsonObject": "Json Object" }, @@ -194,6 +195,8 @@ "maxCount": "Max Item Count", "accept": "Accept", "viewMap": "View Map Button", + "codeType": "Code Type", + "lastChar": "Last Character", "displayRawText": "Display raw text (no markdown)" }, "messages": { diff --git a/application/Espo/Resources/i18n/en_US/FieldManager.json b/application/Espo/Resources/i18n/en_US/FieldManager.json index e0a245292d..93aa69ad74 100644 --- a/application/Espo/Resources/i18n/en_US/FieldManager.json +++ b/application/Espo/Resources/i18n/en_US/FieldManager.json @@ -60,6 +60,15 @@ "javascript: return this.dateTime.getDateShiftedFromToday(10, 'months');": "+10 months", "javascript: return this.dateTime.getDateShiftedFromToday(11, 'months');": "+11 months", "javascript: return this.dateTime.getDateShiftedFromToday(1, 'year');": "+1 year" + }, + "barcodeType": { + "EAN13": "EAN-13", + "EAN8": "EAN-8", + "EAN5": "EAN-5", + "EAN2": "EAN-2", + "UPC": "UPC (A)", + "UPCE": "UPC (E)", + "pharmacode": "Pharmacode" } }, "tooltips": { @@ -75,6 +84,7 @@ "after": "The date value should be after the date value of the specified field.", "readOnly": "Field value can't be specified by user. But can be calculated by formula.", "fileAccept": "Which file types to accept. It's possible to add custom items.", + "barcodeLastChar": "For EAN-13 type.", "maxFileSize": "If empty or 0 then no limit." }, "fieldParts": { diff --git a/application/Espo/Resources/metadata/app/jsLibs.json b/application/Espo/Resources/metadata/app/jsLibs.json index b6ce2de146..734230addd 100644 --- a/application/Espo/Resources/metadata/app/jsLibs.json +++ b/application/Espo/Resources/metadata/app/jsLibs.json @@ -43,5 +43,10 @@ "path": "client/lib/exif-js.js", "exportsTo": "window", "exportsAs": "EXIF" + }, + "JsBarcode": { + "path": "client/lib/JsBarcode.all.min.js", + "exportsTo": "window", + "exportsAs": "JsBarcode" } } diff --git a/application/Espo/Resources/metadata/fields/barcode.json b/application/Espo/Resources/metadata/fields/barcode.json new file mode 100644 index 0000000000..e8de6183a2 --- /dev/null +++ b/application/Espo/Resources/metadata/fields/barcode.json @@ -0,0 +1,50 @@ +{ + "params": [ + { + "name": "required", + "type": "bool", + "default": false + }, + { + "name": "codeType", + "type": "enum", + "options": [ + "CODE128", + "CODE128A", + "CODE128B", + "CODE128C", + "EAN13", + "EAN8", + "EAN5", + "EAN2", + "UPC", + "UPCE", + "ITF14", + "pharmacode" + ], + "translation": "FieldManager.options.barcodeType" + }, + { + "name": "lastChar", + "type": "varchar", + "maxLength": 1, + "default": "", + "tooltip": "barcodeLastChar" + }, + { + "name":"readOnly", + "type":"bool" + } + ], + "validationList": [ + "required" + ], + "filter": true, + "textFilter": true, + "textFilterForeign": true, + "fieldDefs":{ + "type":"varchar", + "len": 255 + }, + "validatorClassName": "Espo\\Core\\FieldValidators\\VarcharType" +} diff --git a/client/lib/JsBarcode.all.min.js b/client/lib/JsBarcode.all.min.js new file mode 100644 index 0000000000..289aa08d9f --- /dev/null +++ b/client/lib/JsBarcode.all.min.js @@ -0,0 +1,2 @@ +/*! JsBarcode v3.11.0 | (c) Johan Lindell | MIT license */ +!function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}var n={};e.m=t,e.c=n,e.i=function(t){return t},e.d=function(t,n,r){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:r})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=20)}([function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var o=function t(e,n){r(this,t),this.data=e,this.text=n.text||e,this.options=n};e.default=o},function(t,e,n){"use strict";function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}Object.defineProperty(e,"__esModule",{value:!0});var o,i=e.SET_A=0,u=e.SET_B=1,a=e.SET_C=2,f=(e.SHIFT=98,e.START_A=103),c=e.START_B=104,s=e.START_C=105;e.MODULO=103,e.STOP=106,e.FNC1=207,e.SET_BY_CODE=(o={},r(o,f,i),r(o,c,u),r(o,s,a),o),e.SWAP={101:i,100:u,99:a},e.A_START_CHAR=String.fromCharCode(208),e.B_START_CHAR=String.fromCharCode(209),e.C_START_CHAR=String.fromCharCode(210),e.A_CHARS="[\0-_È-Ï]",e.B_CHARS="[ -È-Ï]",e.C_CHARS="(Ï*[0-9]{2}Ï*)",e.BARS=[11011001100,11001101100,11001100110,10010011e3,10010001100,10001001100,10011001e3,10011000100,10001100100,11001001e3,11001000100,11000100100,10110011100,10011011100,10011001110,10111001100,10011101100,10011100110,11001110010,11001011100,11001001110,11011100100,11001110100,11101101110,11101001100,11100101100,11100100110,11101100100,11100110100,11100110010,11011011e3,11011000110,11000110110,10100011e3,10001011e3,10001000110,10110001e3,10001101e3,10001100010,11010001e3,11000101e3,11000100010,10110111e3,10110001110,10001101110,10111011e3,10111000110,10001110110,11101110110,11010001110,11000101110,11011101e3,11011100010,11011101110,11101011e3,11101000110,11100010110,11101101e3,11101100010,11100011010,11101111010,11001000010,11110001010,1010011e4,10100001100,1001011e4,10010000110,10000101100,10000100110,1011001e4,10110000100,1001101e4,10011000010,10000110100,10000110010,11000010010,1100101e4,11110111010,11000010100,10001111010,10100111100,10010111100,10010011110,10111100100,10011110100,10011110010,11110100100,11110010100,11110010010,11011011110,11011110110,11110110110,10101111e3,10100011110,10001011110,10111101e3,10111100010,11110101e3,11110100010,10111011110,10111101110,11101011110,11110101110,11010000100,1101001e4,11010011100,1100011101011]},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});e.SIDE_BIN="101",e.MIDDLE_BIN="01010",e.BINARIES={L:["0001101","0011001","0010011","0111101","0100011","0110001","0101111","0111011","0110111","0001011"],G:["0100111","0110011","0011011","0100001","0011101","0111001","0000101","0010001","0001001","0010111"],R:["1110010","1100110","1101100","1000010","1011100","1001110","1010000","1000100","1001000","1110100"],O:["0001101","0011001","0010011","0111101","0100011","0110001","0101111","0111011","0110111","0001011"],E:["0100111","0110011","0011011","0100001","0011101","0111001","0000101","0010001","0001001","0010111"]},e.EAN2_STRUCTURE=["LL","LG","GL","GG"],e.EAN5_STRUCTURE=["GGLLL","GLGLL","GLLGL","GLLLG","LGGLL","LLGGL","LLLGG","LGLGL","LGLLG","LLGLG"],e.EAN13_STRUCTURE=["LLLLLL","LLGLGG","LLGGLG","LLGGGL","LGLLGG","LGGLLG","LGGGLL","LGLGLG","LGLGGL","LGGLGL"]},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(2),o=function(t,e,n){var o=t.split("").map(function(t,n){return r.BINARIES[e[n]]}).map(function(e,n){return e?e[t[n]]:""});if(n){var i=t.length-1;o=o.map(function(t,e){return e=200){i=t.shift()-105;var u=c.SWAP[i];void 0!==u?o=e.next(t,n+1,u):(r!==c.SET_A&&r!==c.SET_B||i!==c.SHIFT||(t[0]=r===c.SET_A?t[0]>95?t[0]-96:t[0]:t[0]<32?t[0]+96:t[0]),o=e.next(t,n+1,r))}else i=e.correctIndex(t,r),o=e.next(t,n+1,r);var a=e.getBar(i),f=i*n;return{result:a+o.result,checksum:f+o.checksum}}}]),e}(f.default);e.default=s},function(t,e,n){"use strict";function r(t){for(var e=0,n=0;n10*n.width?10*n.width:n.fontSize,r.guardHeight=n.height+r.fontSize/2+n.textMargin,r}return u(e,t),a(e,[{key:"encode",value:function(){return this.options.flat?this.encodeFlat():this.encodeGuarded()}},{key:"leftText",value:function(t,e){return this.text.substr(t,e)}},{key:"leftEncode",value:function(t,e){return(0,s.default)(t,e)}},{key:"rightText",value:function(t,e){return this.text.substr(t,e)}},{key:"rightEncode",value:function(t,e){return(0,s.default)(t,e)}},{key:"encodeGuarded",value:function(){var t={fontSize:this.fontSize},e={height:this.guardHeight};return[{data:f.SIDE_BIN,options:e},{data:this.leftEncode(),text:this.leftText(),options:t},{data:f.MIDDLE_BIN,options:e},{data:this.rightEncode(),text:this.rightText(),options:t},{data:f.SIDE_BIN,options:e}]}},{key:"encodeFlat",value:function(){return{data:[f.SIDE_BIN,this.leftEncode(),f.MIDDLE_BIN,this.rightEncode(),f.SIDE_BIN].join(""),text:this.text}}}]),e}(p.default);e.default=d},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function a(t){var e,n=0;for(e=1;e<11;e+=2)n+=parseInt(t[e]);for(e=0;e<11;e+=2)n+=3*parseInt(t[e]);return(10-n%10)%10}Object.defineProperty(e,"__esModule",{value:!0});var f=function(){function t(t,e){for(var n=0;n10*n.width?r.fontSize=10*n.width:r.fontSize=n.fontSize,r.guardHeight=n.height+r.fontSize/2+n.textMargin,r}return u(e,t),f(e,[{key:"valid",value:function(){return-1!==this.data.search(/^[0-9]{12}$/)&&this.data[11]==a(this.data)}},{key:"encode",value:function(){return this.options.flat?this.flatEncoding():this.guardedEncoding()}},{key:"flatEncoding",value:function(){var t="";return t+="101",t+=(0,s.default)(this.data.substr(0,6),"LLLLLL"),t+="01010",t+=(0,s.default)(this.data.substr(6,6),"RRRRRR"),t+="101",{data:t,text:this.text}}},{key:"guardedEncoding",value:function(){var t=[];return this.displayValue&&t.push({data:"00000000",text:this.text.substr(0,1),options:{textAlign:"left",fontSize:this.fontSize}}),t.push({data:"101"+(0,s.default)(this.data[0],"L"),options:{height:this.guardHeight}}),t.push({data:(0,s.default)(this.data.substr(1,5),"LLLLL"),text:this.text.substr(1,5),options:{fontSize:this.fontSize}}),t.push({data:"01010",options:{height:this.guardHeight}}),t.push({data:(0,s.default)(this.data.substr(6,5),"RRRRR"),text:this.text.substr(6,5),options:{fontSize:this.fontSize}}),t.push({data:(0,s.default)(this.data[11],"R")+"101",options:{height:this.guardHeight}}),this.displayValue&&t.push({data:"00000000",text:this.text.substr(11,1),options:{textAlign:"right",fontSize:this.fontSize}}),t}}]),e}(p.default);e.default=d},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var u=function(){function t(t,e){for(var n=0;n0?e.fontSize+e.textMargin:0)+e.marginTop+e.marginBottom}function o(t,e,n){if(n.displayValue&&ee&&(e=t[n].height);return e}function f(t,e,n){var r;if(n)r=n;else{if("undefined"==typeof document)return 0;r=document.createElement("canvas").getContext("2d")}return r.font=e.fontOptions+" "+e.fontSize+"px "+e.font,r.measureText(t).width}Object.defineProperty(e,"__esModule",{value:!0}),e.getTotalWidthOfEncodings=e.calculateEncodingAttributes=e.getBarcodePadding=e.getEncodingHeight=e.getMaximumHeightOfEncodings=void 0;var c=n(5),s=function(t){return t&&t.__esModule?t:{default:t}}(c);e.getMaximumHeightOfEncodings=a,e.getEncodingHeight=r,e.getBarcodePadding=o,e.calculateEncodingAttributes=i,e.getTotalWidthOfEncodings=u},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=n(27),o=n(26),i=n(33),u=n(37),a=n(42),f=n(44),c=n(43),s=n(34);e.default={CODE39:r.CODE39,CODE128:o.CODE128,CODE128A:o.CODE128A,CODE128B:o.CODE128B,CODE128C:o.CODE128C,EAN13:i.EAN13,EAN8:i.EAN8,EAN5:i.EAN5,EAN2:i.EAN2,UPC:i.UPC,UPCE:i.UPCE,ITF14:u.ITF14,ITF:u.ITF,MSI:a.MSI,MSI10:a.MSI10,MSI11:a.MSI11,MSI1010:a.MSI1010,MSI1110:a.MSI1110,pharmacode:f.pharmacode,codabar:c.codabar,GenericBarcode:s.GenericBarcode}},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var o=function(){function t(t,e){for(var n=0;n=a(t);return e+String.fromCharCode(o?206:205)+r(t,o)}Object.defineProperty(e,"__esModule",{value:!0});var i=n(1),u=function(t){return t.match(new RegExp("^"+i.A_CHARS+"*"))[0].length},a=function(t){return t.match(new RegExp("^"+i.B_CHARS+"*"))[0].length},f=function(t){return t.match(new RegExp("^"+i.C_CHARS+"*"))[0]};e.default=function(t){var e=void 0;if(f(t).length>=2)e=i.C_START_CHAR+o(t);else{var n=u(t)>a(t);e=(n?i.A_START_CHAR:i.B_START_CHAR)+r(t,n)}return e.replace(/[\xCD\xCE]([^])[\xCD\xCE]/,function(t,e){return String.fromCharCode(203)+e})}},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.CODE128C=e.CODE128B=e.CODE128A=e.CODE128=void 0;var o=n(24),i=r(o),u=n(21),a=r(u),f=n(22),c=r(f),s=n(23),l=r(s);e.CODE128=i.default,e.CODE128A=a.default,e.CODE128B=c.default,e.CODE128C=l.default},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function u(t){return a(c(t))}function a(t){return b[t].toString(2)}function f(t){return y[t]}function c(t){return y.indexOf(t)}function s(t){for(var e=0,n=0;n10*n.width?r.fontSize=10*n.width:r.fontSize=n.fontSize,r.guardHeight=n.height+r.fontSize/2+n.textMargin,r}return u(e,t),f(e,[{key:"valid",value:function(){return this.isValid}},{key:"encode",value:function(){return this.options.flat?this.flatEncoding():this.guardedEncoding()}},{key:"flatEncoding",value:function(){var t="";return t+="101",t+=this.encodeMiddleDigits(),t+="010101",{data:t,text:this.text}}},{key:"guardedEncoding",value:function(){var t=[];return this.displayValue&&t.push({data:"00000000",text:this.text[0],options:{textAlign:"left",fontSize:this.fontSize}}),t.push({data:"101",options:{height:this.guardHeight}}),t.push({data:this.encodeMiddleDigits(),text:this.text.substring(1,7),options:{fontSize:this.fontSize}}),t.push({data:"010101",options:{height:this.guardHeight}}),this.displayValue&&t.push({data:"00000000",text:this.text[7],options:{textAlign:"right",fontSize:this.fontSize}}),t}},{key:"encodeMiddleDigits",value:function(){var t=this.upcA[0],e=this.upcA[this.upcA.length-1],n=y[parseInt(e)][parseInt(t)];return(0,s.default)(this.middleDigits,n)}}]),e}(p.default);e.default=b},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0}),e.UPCE=e.UPC=e.EAN2=e.EAN5=e.EAN8=e.EAN13=void 0;var o=n(28),i=r(o),u=n(31),a=r(u),f=n(30),c=r(f),s=n(29),l=r(s),p=n(12),d=r(p),h=n(32),y=r(h);e.EAN13=i.default,e.EAN8=a.default,e.EAN5=c.default,e.EAN2=l.default,e.UPC=d.default,e.UPCE=y.default},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0}),e.GenericBarcode=void 0;var u=function(){function t(t,e){for(var n=0;n=3&&this.number<=131070}}]),e}(f.default);e.pharmacode=c},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(t){var e={};for(var n in f.default)f.default.hasOwnProperty(n)&&(t.hasAttribute("jsbarcode-"+n.toLowerCase())&&(e[n]=t.getAttribute("jsbarcode-"+n.toLowerCase())),t.hasAttribute("data-"+n.toLowerCase())&&(e[n]=t.getAttribute("data-"+n.toLowerCase())));return e.value=t.getAttribute("jsbarcode-value")||t.getAttribute("data-value"),e=(0,u.default)(e)}Object.defineProperty(e,"__esModule",{value:!0});var i=n(9),u=r(i),a=n(10),f=r(a);e.default=o},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var o=function(){function t(t,e){for(var n=0;n0?(o=0,n.textAlign="left"):"right"==t.textAlign?(o=e.width-1,n.textAlign="right"):(o=e.width/2,n.textAlign="center"),n.fillText(e.text,o,i)}}},{key:"moveCanvasDrawing",value:function(t){this.canvas.getContext("2d").translate(t.width,0)}},{key:"restoreCanvas",value:function(){this.canvas.getContext("2d").restore()}}]),t}();e.default=f},function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(e,"__esModule",{value:!0});var o=n(46),i=r(o),u=n(49),a=r(u),f=n(48),c=r(f);e.default={CanvasRenderer:i.default,SVGRenderer:a.default,ObjectRenderer:c.default}},function(t,e,n){"use strict";function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var o=function(){function t(t,e){for(var n=0;n0&&(this.drawRect(u-e.width*i,r,e.width*i,e.height,t),i=0);i>0&&this.drawRect(u-e.width*(i-1),r,e.width*i,e.height,t)}},{key:"drawSVGText",value:function(t,e,n){var r=this.document.createElementNS(f,"text");if(e.displayValue){var o,i;r.setAttribute("style","font:"+e.fontOptions+" "+e.fontSize+"px "+e.font),i="top"==e.textPosition?e.fontSize-e.textMargin:e.height+e.textMargin+e.fontSize,"left"==e.textAlign||n.barcodePadding>0?(o=0,r.setAttribute("text-anchor","start")):"right"==e.textAlign?(o=n.width-1,r.setAttribute("text-anchor","end")):(o=n.width/2,r.setAttribute("text-anchor","middle")),r.setAttribute("x",o),r.setAttribute("y",i),r.appendChild(this.document.createTextNode(n.text)),t.appendChild(r)}}},{key:"setSvgAttributes",value:function(t,e){var n=this.svg;n.setAttribute("width",t+"px"),n.setAttribute("height",e+"px"),n.setAttribute("x","0px"),n.setAttribute("y","0px"),n.setAttribute("viewBox","0 0 "+t+" "+e),n.setAttribute("xmlns",f),n.setAttribute("version","1.1"),n.setAttribute("style","transform: translate(0,0)")}},{key:"createGroup",value:function(t,e,n){var r=this.document.createElementNS(f,"g");return r.setAttribute("transform","translate("+t+", "+e+")"),n.appendChild(r),r}},{key:"setGroupOptions",value:function(t,e){t.setAttribute("style","fill:"+e.lineColor+";")}},{key:"drawRect",value:function(t,e,n,r,o){var i=this.document.createElementNS(f,"rect");return i.setAttribute("x",t),i.setAttribute("y",e),i.setAttribute("width",n),i.setAttribute("height",r),o.appendChild(i),i}}]),t}();e.default=c}]); \ No newline at end of file diff --git a/client/res/templates/fields/barcode/detail.tpl b/client/res/templates/fields/barcode/detail.tpl new file mode 100644 index 0000000000..0fc315a49f --- /dev/null +++ b/client/res/templates/fields/barcode/detail.tpl @@ -0,0 +1,6 @@ +{{#if isNotEmpty}} + + +{{else}} +{{#if valueIsSet}}{{{translate 'None'}}}{{else}}...{{/if}} +{{/if}} \ No newline at end of file diff --git a/client/src/views/fields/barcode.js b/client/src/views/fields/barcode.js new file mode 100644 index 0000000000..fce14d0119 --- /dev/null +++ b/client/src/views/fields/barcode.js @@ -0,0 +1,102 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2019 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: https://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +define('views/fields/barcode', ['views/fields/varchar', 'lib!JsBarcode'], function (Dep, JsBarcode) { + + return Dep.extend({ + + type: 'barcode', + + listTemplate: 'fields/barcode/detail', + + detailTemplate: 'fields/barcode/detail', + + setup: function () { + this.params.trim = true; + + var maxLength = 255; + + switch (this.params.codeType) { + case 'EAN2': + maxLength = 2; break; + case 'EAN5': + maxLength = 5; break; + case 'EAN8': + maxLength = 8; break; + case 'EAN13': + maxLength = 13; break; + case 'UPC': + maxLength = 12; break; + case 'UPCE': + maxLength = 11; break; + case 'ITF14': + maxLength = 14; break; + case 'pharmacode': + maxLength = 6; break; + + } + + this.params.maxLength = maxLength; + + Dep.prototype.setup.call(this); + + $(window).on('resize.' + this.cid, function () { + if (!this.isRendered()) return; + this.controlWidth(); + }.bind(this)); + }, + + onRemove: function () { + $(window).off('resize.' + this.cid); + }, + + + afterRender: function () { + Dep.prototype.afterRender.call(this); + + if (this.mode === 'list' || this.mode === 'detail') { + var value = this.model.get(this.name); + if (value) { + JsBarcode(this.getSelector() + ' .barcode', value, { + format: this.params.codeType, + height: 50, + fontSize: 14, + margin: 0, + lastChar: this.params.lastChar, + }); + } + this.controlWidth(); + } + }, + + controlWidth: function () { + this.$el.find('.barcode').css('max-width', this.$el.width() + 'px'); + }, + + }); +}); diff --git a/composer.json b/composer.json index 99169e61cd..cf330635b0 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "zendframework/zend-servicemanager": "3.3.2", "monolog/monolog": "1.*", "yzalis/identicon": "*", - "zordius/lightncandy": "0.*", + "zordius/lightncandy": "1.*", "composer/semver": "^1.4", "tecnickcom/tcpdf": "^6.2", "zbateson/mail-mime-parser": "1.1.*", diff --git a/composer.lock b/composer.lock index 6b246f926b..82f72c41e4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "58cf37fd7fae2d3b1889cdcc745eca1d", + "content-hash": "29e70cca19d64159b8ffefaf04116a84", "packages": [ { "name": "cboden/ratchet", @@ -3215,29 +3215,34 @@ }, { "name": "zordius/lightncandy", - "version": "v0.21", + "version": "v1.2.4", "source": { "type": "git", "url": "https://github.com/zordius/lightncandy.git", - "reference": "015fed62d0ae6fe7601d3910b8e4b6a6964f86a0" + "reference": "dfdb910ae7b59e274f1ff97d29b724871f01b4cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zordius/lightncandy/zipball/015fed62d0ae6fe7601d3910b8e4b6a6964f86a0", - "reference": "015fed62d0ae6fe7601d3910b8e4b6a6964f86a0", + "url": "https://api.github.com/repos/zordius/lightncandy/zipball/dfdb910ae7b59e274f1ff97d29b724871f01b4cc", + "reference": "dfdb910ae7b59e274f1ff97d29b724871f01b4cc", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "4.0.17" + "phpunit/phpunit": "^7" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.5-dev" + } + }, "autoload": { - "classmap": [ - "src/lightncandy.php" - ] + "psr-4": { + "LightnCandy\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3246,7 +3251,7 @@ "authors": [ { "name": "Zordius Chen", - "email": "zordius@yahoo-inc.com" + "email": "zordius@gmail.com" } ], "description": "An extremely fast PHP implementation of handlebars ( http://handlebarsjs.com/ ) and mustache ( http://mustache.github.io/ ).", @@ -3258,7 +3263,7 @@ "php", "template" ], - "time": "2015-05-08T01:56:46+00:00" + "time": "2019-06-09T04:10:55+00:00" } ], "packages-dev": [],