/*global tinymce */ /** * Report template editor. */ Ext.define('UB.ux.UBReportEditor', { extend: 'UB.ux.UBTinyMCETextArea', alias: 'widget.ubreporteditor', statics: { portrait: {width: 793}, landscape: {width: 1121}, paste_postprocess: function(plugin, args) { //console.log(args.node); //args.node.setAttribute('id', '42'); UB.ux.UBReportEditor.filter_node(args.node); }, possibleElement: { node: ['table', 'thead', 'tbody','tr','td','img','div','p','hr','strong','em','big','span','font', 'li','ul','ol', 'blockquote', 'h1','h2','h3','h4','h5','h6','#comment','#text'], inlineInnerNode: ['#comment','#text'], attributes : ['style', 'data-mce-style', 'src', 'rowspan', 'colspan'], style: ['font-family','font-weight','font-style','font-size','text-align','vertical-align','text-indent', 'list-style-type', 'list-style-position', 'background-color', 'width','height', 'border-style','border-top-style','border-bottom-style','border-right-style','border-left-style','border', 'border-width','border-top-width','border-bottom-width','border-right-width','border-left-width', 'padding','padding-top','padding-bottom','padding-right','padding-left', 'margin','margin-top','margin-bottom','margin-right','margin-left', 'disable-split','disableSplit','disablesplit', 'indissoluble-first-rows','indissoluble-end-rows','draw-border-onsplit','top-through-line'] }, filter_node: function(node){ var me = this, i, y, attr, style, styleElm, stylePair, resStyle = [], detail, subDetail, isInline, newNode; if (node.nodeName.toLowerCase() === 'table'){ me.filter_table(node); } if (node.attributes){ for(i = node.attributes.length - 1; i >= 0; i--){ attr = node.attributes[i]; if (me.possibleElement.attributes.indexOf(attr.name.toLowerCase()) < 0){ node.removeAttribute(attr.name); } } style = node.attributes.getNamedItem('style'); if (style && style.value){ style = style.value.split(';'); for (i = 0; i < style.length; i++){ styleElm = style[i]; if (styleElm){ stylePair = styleElm.split(':'); } if (stylePair.length === 2 && (typeof(stylePair[0]) === 'string') && (me.possibleElement.style.indexOf(stylePair[0].toLowerCase()) >= 0)){ resStyle.push(styleElm); } } style.value = resStyle.join(';'); } } if (node.childNodes){ for (i = 0; i < node.childNodes.length; i++){ detail = node.childNodes[i]; if( me.possibleElement.node.indexOf(detail.nodeName.toLowerCase()) < 0){ isInline = true; if (detail.childNodes){ for(y = 0; y < detail.childNodes.length; y++){ subDetail = detail.childNodes[y].nodeName.toLowerCase(); if (me.possibleElement.inlineInnerNode.indexOf(subDetail) < 0){ isInline = false; break; } } } newNode = document.createElement(isInline ? 'SPAN' : 'DIV'); me.copyNodeParams(detail, newNode); node.replaceChild(newNode, detail); detail = newNode; } me.filter_node(detail); } } }, copyNodeParams: function(oldNode, newNode){ var style, styleAttr; if (oldNode.attributes){ styleAttr = oldNode.attributes.getNamedItem('style'); style = styleAttr ? styleAttr.value : null; } if(style){ newNode.setAttribute('style', style); } newNode.innerHTML = oldNode.innerHTML; }, filter_table: function(table){ var tbody, val, attrWidth, styles = [], styleWith; val = table.attributes.getNamedItem('width'); if (val){ attrWidth = val.value; } val = table.attributes.getNamedItem('style'); if (val){ styles = val.value ? val.value.split(';') : []; _.forEach(styles, function(elm){ var pair; if (elm){ pair = elm.split(':'); if (pair.length === 2 && pair[0].toLowerCase() === 'width'){ styleWith = pair[1]; return false; } } }); } else { val = document.createAttribute('style'); table.attributes.setNamedItem(val); } if (!styleWith){ styles.push('width:' + (attrWidth || '100%')); val.value = styles.join(';'); } _.forEach(table.childNodes, function(child){ if (child.nodeName.toLowerCase() === 'tbody'){ tbody = child; return false; } }); if(!tbody){ tbody = document.createElement('TBODY'); table.appendChild(tbody); } // this function used only for correct rowSpan and colSpan. It was copy from csHtmlToPdf.js this.createSpanTableMap(tbody, [], []); }, /** * * @param {Object} tbody * @param {Array} rowSpan * @param {Array} colSpan * @returns {Object} */ createSpanTableMap: function(tbody, rowSpan, colSpan){ var row, q, qi, qq, i, ii, y, cCnt, len, cell, cellLast, rowCount, rowCountR, colCount = 0, cCntR, cSpan, rSpan, cSpanUp, calc = false, fRow; function getAttribute(node, name, defaultValue){ var val; if (!node.attributes){ return defaultValue; } val = node.attributes.getNamedItem(name); if (val){ return val.value || defaultValue; } return defaultValue; } function getAttributeInt(node, name){ return parseInt(getAttribute(node, name, 0), 10); } function updateAttributeInt(node, name, value){ if (!node.attributes){ return; } var val = node.attributes.getNamedItem(name); if (val){ val.value = value; } else { val = document.createAttribute(name); val.value = value; node.attributes.setNamedItem(val); } } for( var p = 0; p < tbody.childNodes.length; p++){ rowSpan[p] = []; colSpan[p] = []; } rowCountR = 0; // create span maps rowCount = tbody.childNodes.length; for( p = 0; p < rowCount; p++){ row = tbody.childNodes[p]; if (row.nodeName.toLowerCase() !== 'tr'){ continue; } rowCountR++; // calc cell count if (!calc){ for( q = 0; q < row.childNodes.length; q++){ cell = row.childNodes[q]; if (cell.nodeName.toLowerCase() !== 'td'){ continue; } cSpan = getAttributeInt(cell, 'colspan'); if( cSpan > 1){ colCount += cSpan - 1; } colCount++; } calc = true; } cCntR = 0; for( q = 0, qi = 0; (q < colCount); q++){ if (colSpan[p][q] || rowSpan[p][q] ){ cCntR++; continue; } if (qi >= row.childNodes.length ){ continue; } cell = row.childNodes[qi]; while (cell.nodeName.toLowerCase() !== 'td'){ qi++; cell = row.childNodes[qi]; } cellLast = cell; cCntR++; cSpan = getAttributeInt(cell, 'colspan', 0); rSpan = getAttributeInt(cell, 'rowspan', 0); // check valid rowSpan if (rSpan > 1){ if (rSpan - 1 + p >= rowCount){ rSpan = (rowCount - p) || 1; updateAttributeInt(cell, 'rowspan', rSpan); } for(ii = p + 1, i = p + 1; (i < p + rSpan) && ii < tbody.childNodes.length ; ii++ ){ fRow = tbody.childNodes[ii]; if (fRow.nodeName.toLowerCase() !== 'tr'){ continue; } len = fRow.childNodes.length; cCnt = 0; for(y = 0; y < len; y++ ){ if (fRow.childNodes[y].nodeName.toLowerCase() === 'td'){ cCnt++; cCnt += (getAttributeInt(fRow.childNodes[y], 'colspan') || 1) - 1; } } len = rowSpan[i].length; for ( y = 0; y < len; y++){ if (rowSpan[i][y]){ cCnt++; } } if (cCnt + ((cSpan || 1) - 1) >= colCount){ rSpan = i - p; updateAttributeInt(cell, 'rowspan', rSpan); break; } i++; } } // check valid colSpan if (cSpan > 1 ){ cCnt = 0; for(i = q; i < colCount; i++ ){ if (rowSpan[p][i] ){ continue; } cCnt++; } if (cSpan > cCnt){ cSpan = cCnt || 1; updateAttributeInt(cell, 'colspan', cSpan); } } if( rSpan > 1){ for( var r = p + 1; r < p + rSpan; r++ ){ rowSpan[r][q] = 1; if( cSpan > 1){ for( qq = q + 1; qq < q + cSpan; qq++ ){ if (!colSpan[r]){ colSpan[r] = []; } colSpan[r][qq] = 1; } } } } if(cSpan > 1){ //cCntR += cSpan - 1; for( qq = q + 1; qq < q + cSpan; qq++ ){ colSpan[p][qq] = 1; } } qi++; } if (cCntR < colCount){ updateAttributeInt(cellLast, 'colspan', colCount - cCntR + 1); } } return { colCount: colCount, rowCount: rowCountR}; } }, pageWidth: 793, /** * Set page orientation * @param {String} value possible values: portrait, landscape. * @returns {boolean} */ setOrientation: function(value){ var me = this; if ((value !== 'landscape') && (value !== 'portrait') ){ return false; } me.setWidth( value === 'landscape' ? UB.ux.UBReportEditor.landscape.width: UB.ux.UBReportEditor.portrait.width ); me.orientation = value; return true; }, initComponent: function () { var me = this, size = Ext.getBody().getSize(); me.width = UB.ux.UBReportEditor.portrait.width; me.orientation = 'portrait'; //me.elementStyle = me.elementStyle || '' + 'width: ' + me.pageWidth + 'px;'; me.tinyMCEConfig = Ext.apply({ language_url : $App.connection.baseURL + 'jslibs/tinymce/langs/' + $App.connection.userLang() + '.js', skin_url: $App.connection.baseURL + 'jslibs/tinymce/skins/lightgray/', content_css : $App.connection.baseURL + "css/tini-mce-content.css", table_default_attributes: { cellpadding: '3px', cellspacing: '0', border: '1px', width: me.width && me.width > 20 ? me.width - 20: 20, style: { wordBreak: "break-all"} }, browser_spellcheck : true, convert_urls: false, object_resizing: "img,table,p[class=isTopColontitle],p[class=isBottomColontitle]", // not exists plugins in new version 'style,advhr,advimage,advlink,iespell,xhtmlxtras,inlinepopups' plugins: [ //"autosave layer noneditable", //disabled - " media" "advlist autolink lists charmap print preview hr anchor pagebreak", //link image "searchreplace wordcount visualblocks visualchars code ", //fullscreen "insertdatetime nonbreaking table contextmenu directionality", //save "emoticons template textcolor colorpicker templateEditor image paste" //paste ], toolbar1: "undo redo | bold italic underline | alignleft aligncenter alignright alignjustify | formatselect fontsizeselect | pageOrientation | Colontitle | borderL borderR borderT borderB borderE borderA | forecolor | bullist numlist outdent indent |", contextmenu: 'link image inserttable | cell row column deletetable | rowTemplate', // fontselect styleselect //toolbar1: "newdocument fullpage | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | styleselect formatselect fontselect fontsizeselect", //toolbar2: "cut copy paste | searchreplace | bullist numlist | outdent indent blockquote | undo redo | link unlink anchor image media code | inserttime preview | forecolor backcolor", //toolbar3: "table | hr removeformat | subscript superscript | charmap emoticons | print fullscreen | ltr rtl | spellchecker | visualchars visualblocks nonbreaking template pagebreak restoredraft", //enable past data image paste_data_images: true, paste_postprocess: UB.ux.UBReportEditor.paste_postprocess, /* remove_linebreaks: false, remove_trailing_nbsp: false, paste_auto_cleanup_on_paste: false, paste_retain_style_properties : "all", paste_strip_class_attributes : "none", extended_valid_elements:"a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],table[style|class|border=2|width|cellspacing|cellpadding|bgcolor],colgroup,col[style|width],tbody,tr[style|class],td[style|class|colspan|rowspan|width|height],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]", */ //content_css : "contents.css", statusbar : false, menubar: "edit insert view format table tools", //menubar: true, /* menu : { //file : {title : 'File' , items : 'newdocument'}, edit : {title : 'Edit' , items : 'undo redo | cut copy paste pastetext | selectall'}, insert : {title : 'Insert', items : 'link media | template hr'}, view : {title : 'View' , items : 'visualaid'}, format : {title : 'Format', items : 'bold italic underline strikethrough superscript subscript | formats | removeformat'}, table : {title : 'Table' , items : 'inserttable tableprops deletetable | cell row column'}, tools : {title : 'Tools' , items : 'spellchecker code'} },*/ toolbar_items_size: 'small' //height: '100%' //resize: true }, me.tinyMCEEditorConfig || {} ); me.tinyMCEConfig.reportEditor = me; me.lastFrameHeight = '100%'; me.callParent(arguments); }, onStartSetup: function(ed){ var me = this; ed.on('change', function(e){ me.updateSize(); }, me); /* ed.on('paste', function(evnt) { var cbHtml, pos = 0, portion, cbText = evnt.clipboardData.getData('text/plain'); cbHtml = evnt.clipboardData.getData('text/HTML'); if (cbHtml){ cbText = cbHtml; } if ( !me.canPastLargeData && !evnt.userDecided && cbText.length > 10000){ //$App.dialogInfo('PastTooLargeText'); //UB.view.ErrorWindow.showError({errMsg: 'PastTooLargeText'}); //window.requestAnimationFrame(function(){return true;}); evnt.preventDefault(); $App.dialogYesNo('', 'PastTooLargeText').then(function(choice){ if (choice){ //var pasteEvent = new ClipboardEvent('paste', { dataType: 'text/plain', data: 'My string' } ); //pasteEvent.userDecided = true; //document.dispatchEvent(pasteEvent); //if (!cbHtml){ do { if (cbText[pos + 2000 - 1] === '\n'){ portion = cbText.substr(pos, 2000 - 1); pos += 2000 - 1; } else { portion = cbText.substr(pos, 2000); pos += 2000; } portion = portion.replace(/\r\n/g,'<br/>').replace(/\n/g,'<br/>'); ed.selection.setContent(portion); } while (pos < cbText.length); portion = cbText.replace(/\r\n/g,'<br/>').replace(/\n/g,'<br/>'); ed.selection.setContent(portion); } else { ed.selection.setContent(cbText); } me.canPastLargeData = true; } }); return false; } }); */ me.callParent(arguments); }, syncEditorHeight: function(){ var me = this; me.callParent(arguments); me.updateSize(); }, updateSize: function(){ var me = this, ed, mehuHeight = 50; var edIframe = Ext.get(me.getInputId() + "_ifr"); if (!me.inResizing && edIframe && edIframe.dom && edIframe.dom.contentDocument ){ ed = me.getEditor(); if (ed.editorContainer && ed.contentAreaContainer){ mehuHeight = ed.editorContainer.offsetHeight - ed.contentAreaContainer.offsetHeight + 50; } me.inResizing = true; me.setHeight(edIframe.dom.contentDocument.body.offsetHeight + mehuHeight); //edIframe.setHeight( edIframe.dom.contentDocument.body.offsetHeight); me.inResizing = false; } }, setValue: function(value){ var me = this, matches, re = /(<!--@\w+?\s*".+?"-->)/gi, reOptions = /(<!--%\w+?:(.+?)-->)/gi; me.valuesSpecialComments = null; if (value && typeof(value) === 'string'){ matches = value.match(re); if (matches && matches.length > 0){ me.valuesSpecialComments = matches.join('\r\n'); value = value.replace(re, ''); } // parse options matches = value.match(reOptions); if (matches && matches.length > 0){ _.forEach(matches, function(item){ var itemVal = item.match(/<!--%(\w+?\:.+?)-->/)[1]; itemVal = itemVal.split(':'); if (itemVal[0] === 'pageOrientation'){ me.setOrientation(itemVal[1]); } }); value = value.replace(reOptions, ''); } } me.callParent([value]); }, getValue: function(sender){ var me = this, value; value = me.callParent(); value = '<!--%pageOrientation:' + me.orientation + '-->' + value ; if (sender === 'UBDocument' && me.valuesSpecialComments){ value = me.valuesSpecialComments + value; } return value; }, /* todo make right function isDirty isDirty : function() { var me = this; return !me.disabled && !me.isEqual(me.getValue(), me.originalValue); }, */ // for get focus in BasePanel isFocusableField: true, isFocusable: function(){ return !this.readOnly; } });