/* Copyright 2010, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) { var doTextTransform = function(expression, onError, repeat, repeatCount) { Refine.postCoreProcess( "text-transform", { columnName: column.name, onError: onError, repeat: repeat, repeatCount: repeatCount }, { expression: expression }, { cellsChanged: true } ); }; var doTextTransformPrompt = function() { var frame = $( DOM.loadHTML("core", "scripts/views/data-table/text-transform-dialog.html") .replace("$EXPRESSION_PREVIEW_WIDGET$", ExpressionPreviewDialog.generateWidgetHtml())); var elmts = DOM.bind(frame); elmts.dialogHeader.text($.i18n._('core-views')["custom-text-trans"]+" " + column.name); elmts.or_views_errorOn.text($.i18n._('core-views')["on-error"]); elmts.or_views_keepOr.text($.i18n._('core-views')["keep-or"]); elmts.or_views_setBlank.text($.i18n._('core-views')["set-blank"]); elmts.or_views_storeErr.text($.i18n._('core-views')["store-err"]); elmts.or_views_reTrans.text($.i18n._('core-views')["re-trans"]); elmts.or_views_timesChang.text($.i18n._('core-views')["times-chang"]); elmts.okButton.html($.i18n._('core-buttons')["ok"]); elmts.cancelButton.text($.i18n._('core-buttons')["cancel"]); var level = DialogSystem.showDialog(frame); var dismiss = function() { DialogSystem.dismissUntil(level - 1); }; elmts.cancelButton.click(dismiss); elmts.okButton.click(function() { doTextTransform( previewWidget.getExpression(true), $('input[name="text-transform-dialog-onerror-choice"]:checked')[0].value, elmts.repeatCheckbox[0].checked, elmts.repeatCountInput[0].value ); dismiss(); }); var o = DataTableView.sampleVisibleRows(column); var previewWidget = new ExpressionPreviewDialog.Widget( elmts, column.cellIndex, o.rowIndices, o.values, null ); previewWidget._prepareUpdate = function(params) { params.repeat = elmts.repeatCheckbox[0].checked; params.repeatCount = elmts.repeatCountInput[0].value; }; elmts.repeatCheckbox.click(function() { previewWidget.update(); }); }; var doFillDown = function() { Refine.postCoreProcess( "fill-down", { columnName: column.name }, null, { modelsChanged: true } ); }; var doBlankDown = function() { Refine.postCoreProcess( "blank-down", { columnName: column.name }, null, { modelsChanged: true } ); }; var doJoinMultiValueCells = function() { var separator = window.prompt($.i18n._('core-views')["enter-separator"], ", "); if (separator !== null) { Refine.postCoreProcess( "join-multi-value-cells", { columnName: column.name, keyColumnName: theProject.columnModel.keyColumnName, separator }, null, { rowsChanged: true } ); } }; var doReplace = function() { function isValidPattern(p) { // check if a string can be used as a regexp pattern // parameters : // p : a string without beginning and trailing "/" // we need a manual check for unescaped / // the GREL replace function cannot contain a pattern with unescaped / // but javascript Regexp accepts it and auto escape it var pos = p.replace(/\\\//g,'').indexOf("/"); if (pos != -1) { alert($.i18n._('core-views')["warning-regex"] + " : " + p); return 0;} try { var pattern = new RegExp(p); return 1; } catch (e) { alert($.i18n._('core-views')["warning-regex"] + " : " + p); return 0;} } function escapeInputString(s) { // if the textarea input is used as a plain string // user input | result after escaping // 4 characters : A\tA | 5 characters : A\\tA // 4 characters : A\nA | 5 characters : A\\nA // 1 characters : \ | 2 characters : \\ // 1 character : ' | 2 characters : \' // 1 character : " | 2 characters : \" // new line | 2 characters : \n // tab | 2 characters : \t // parameters : // s : a string from a textarea if (typeof s != 'string') return "" // convert new lines and tabs manually typed in the textarea into \n and \t and suppress other printable characters, escape \ ' and " return s.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/[\x00-\x1F\x80-\x9F]/g, '').replace(/'/g, "\\'").replace(/"/g, '\\"') function hex(c) { // non used var v = '0' + c.charCodeAt(0).toString(16); return '\\x' + v.substr(v.length - 2); } } function escapeInputRegex(s) { // if the textarea input is used as a regex pattern // suppress new lines and tabs manually typed in the textarea, and other non printable characters // no need to escape \ or / // parameters : // s : a string from a textarea return (typeof s == 'string') ? s.replace(/[\x00-\x1F\x80-\x9F]/g, '') : "" } function stringToRegex(s) { // converts a plain string to regex, in order to use the i flag // escaping is needed to force the regex processor to interpret every character litteraly // parameters : // s : a string from a textarea, preprocessed with escapeInputString if (typeof s != 'string') return "" // no need to escape \ : already escaped by escapeInputString var EscapeCharsRegex = /[-|{}()[\]^$+*?.]/g; // FIXME escaping of / directly by adding / or \/ or // in EscapeCharsRegex don't work... return s.replace(EscapeCharsRegex, '\\$&').replace(/\//g, '\\/'); } function escapeReplacementString(dont_escape,s) { // in replacement string, the GREL replace function handle in a specific way the Java special escape sequences // cf https://docs.oracle.com/javase/tutorial/java/data/characters.html // Escape Sequence | Java documentation | GREL replace function // \t | tab | tabs // \n | new line | new line // \r | carriage return | // \b | backspace | b // \f | formfeed | f // \' | ' | '' // \" | " | "" // \\ | \ | \ // GREL replace function returns an error if a \ is not followed by an other character // it could be unexpected for the user, so the replace menu escape the replacement string, but gives the possibility to choose the default behavior // if dont_escape = 0, a complete escaping is done // if dont_escape = 1, no escaping is done, but a slight cleaning // parameters : // replace_dont_escape : 0 or 1 // s : a string from a textarea if (typeof s != 'string') {return "";} var temp = s; if (dont_escape == 0) {temp = temp.replace(/\\/g, '\\\\\\\\');} // convert newlines and tabs manually typed in the textarea into \n and \t and suppress other non printable characters return temp.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/[\x00-\x1F\x80-\x9F]/g,''); } var frame = $(DOM.loadHTML("core", "scripts/views/data-table/replace-dialog.html")); var elmts = DOM.bind(frame); elmts.dialogHeader.text($.i18n._('core-views')["replace"]); elmts.or_views_text_to_find.text($.i18n._('core-views')["text-to-find"]); elmts.or_views_replacement.text($.i18n._('core-views')["replacement-text"]); elmts.or_views_finding_info1.text($.i18n._('core-views')["finding-info1"]); elmts.or_views_finding_info2.text($.i18n._('core-views')["finding-info2"]); elmts.or_views_replacement_info.text($.i18n._('core-views')["replacement-info"]); elmts.or_views_find_regExp.text($.i18n._('core-views')["reg-exp"]); elmts.or_views_find_case_insensitive.text($.i18n._('core-views')["case-insensitive"]); elmts.or_views_replace_dont_escape.text($.i18n._('core-views')["replace-dont-escape"]); elmts.okButton.html($.i18n._('core-buttons')["ok"]); elmts.cancelButton.text($.i18n._('core-buttons')["cancel"]); var level = DialogSystem.showDialog(frame); var dismiss = function() { DialogSystem.dismissUntil(level - 1); }; elmts.cancelButton.click(dismiss); elmts.okButton.click(function() { var text_to_find = elmts.text_to_findTextarea[0].value; var replacement_text = elmts.replacementTextarea[0].value; var replace_dont_escape = elmts.replace_dont_escapeInput[0].checked; var find_regex = elmts.find_regexInput[0].checked; var find_case_insensitive = elmts.find_case_insensitiveInput[0].checked; replacement_text = escapeReplacementString(replace_dont_escape, replacement_text) if (find_regex) { text_to_find = escapeInputRegex(text_to_find); if (!isValidPattern (text_to_find)) {return} text_to_find = "/"+text_to_find+"/"; if (find_case_insensitive) {text_to_find = text_to_find + "i"} } else { text_to_find = escapeInputString(text_to_find); if (find_case_insensitive) { text_to_find = stringToRegex(text_to_find); if (!isValidPattern (text_to_find)) {return} text_to_find = "/"+text_to_find+"/i"; } else { text_to_find = '"'+text_to_find+'"'; } } expression = 'value.replace('+text_to_find+',"'+replacement_text+'")'; doTextTransform(expression, "keep-original", false, ""); dismiss(); }); }; var doSplitMultiValueCells = function() { var frame = $(DOM.loadHTML("core", "scripts/views/data-table/split-multi-valued-cells-dialog.html")); var elmts = DOM.bind(frame); elmts.dialogHeader.text($.i18n._('core-views')["split-cells"]); elmts.or_views_howSplit.text($.i18n._('core-views')["how-split-cells"]); elmts.or_views_bySep.text($.i18n._('core-views')["by-sep"]); elmts.or_views_separator.text($.i18n._('core-views')["separator"]); elmts.or_views_regExp.text($.i18n._('core-views')["reg-exp"]); elmts.or_views_fieldLen.text($.i18n._('core-views')["field-len"]); elmts.or_views_listInt.text($.i18n._('core-views')["list-int"]); elmts.okButton.html($.i18n._('core-buttons')["ok"]); elmts.cancelButton.text($.i18n._('core-buttons')["cancel"]); var level = DialogSystem.showDialog(frame); var dismiss = function() { DialogSystem.dismissUntil(level - 1); }; elmts.cancelButton.click(dismiss); elmts.okButton.click(function() { var mode = $("input[name='split-by-mode']:checked")[0].value; var config = { columnName: column.name, keyColumnName: theProject.columnModel.keyColumnName, mode }; if (mode === "separator") { config.separator = elmts.separatorInput[0].value; if (!(config.separator)) { alert($.i18n._('core-views')["specify-sep"]); return; } config.regex = elmts.regexInput[0].checked; } else { var s = "[" + elmts.lengthsTextarea[0].value + "]"; try { var a = JSON.parse(s); var lengths = []; $.each(a, function(i,n) { if (typeof n == "number") { lengths.push(n); } }); if (lengths.length === 0) { alert($.i18n._('core-views')["warning-no-length"]); return; } config.fieldLengths = JSON.stringify(lengths); } catch (e) { alert($.i18n._('core-views')["warning-format"]); return; } } Refine.postCoreProcess( "split-multi-value-cells", config, null, { rowsChanged: true } ); dismiss(); }); }; MenuSystem.appendTo(menu, [ "core/edit-cells" ], [ { id: "core/text-transform", label: $.i18n._('core-views')["transform"]+"...", click: function() { doTextTransformPrompt(); } }, { id: "core/common-transforms", label: $.i18n._('core-views')["common-transform"], submenu: [ { id: "core/trim-whitespace", label: $.i18n._('core-views')["trim-all"], click: function() { doTextTransform("value.trim()", "keep-original", false, ""); } }, { id: "core/collapse-whitespace", label: $.i18n._('core-views')["collapse-white"], click: function() { doTextTransform("value.replace(/\\s+/,' ')", "keep-original", false, ""); } }, {}, { id: "core/unescape-html-entities", label: $.i18n._('core-views')["unescape-html"], click: function() { doTextTransform("value.unescape('html')", "keep-original", true, 10); } }, {}, { id: "core/to-titlecase", label: $.i18n._('core-views')["titlecase"], click: function() { doTextTransform("value.toTitlecase()", "keep-original", false, ""); } }, { id: "core/to-uppercase", label: $.i18n._('core-views')["uppercase"], click: function() { doTextTransform("value.toUppercase()", "keep-original", false, ""); } }, { id: "core/to-lowercase", label: $.i18n._('core-views')["lowercase"], click: function() { doTextTransform("value.toLowercase()", "keep-original", false, ""); } }, {}, { id: "core/to-number", label: $.i18n._('core-views')["to-number"], click: function() { doTextTransform("value.toNumber()", "keep-original", false, ""); } }, { id: "core/to-date", label: $.i18n._('core-views')["to-date"], click: function() { doTextTransform("value.toDate()", "keep-original", false, ""); } }, { id: "core/to-text", label: $.i18n._('core-views')["to-text"], click: function() { doTextTransform("value.toString()", "keep-original", false, ""); } }, {}, { id: "core/to-blank", label: $.i18n._('core-views')["blank-out"], click: function() { doTextTransform("null", "keep-original", false, ""); } }, { id: "core/to-empty", label: $.i18n._('core-views')["blank-out-empty"], click: function() { doTextTransform("\"\"", "keep-original", false, ""); } } ] }, {}, { id: "core/fill-down", label: $.i18n._('core-views')["fill-down"], click: doFillDown }, { id: "core/blank-down", label: $.i18n._('core-views')["blank-down"], click: doBlankDown }, {}, { id: "core/split-multi-valued-cells", label: $.i18n._('core-views')["split-cells"]+"...", click: doSplitMultiValueCells }, { id: "core/join-multi-valued-cells", label: $.i18n._('core-views')["join-cells"]+"...", click: doJoinMultiValueCells }, {}, { id: "core/cluster", label: $.i18n._('core-views')["cluster-edit"]+"...", click: function() { new ClusteringDialog(column.name, "value"); } }, { id: "core/replace", label: $.i18n._('core-views')["replace"], click: doReplace } ]); var doTransposeColumnsIntoRows = function() { var dialog = $(DOM.loadHTML("core", "scripts/views/data-table/transpose-columns-into-rows.html")); var elmts = DOM.bind(dialog); var level = DialogSystem.showDialog(dialog); elmts.dialogHeader.html($.i18n._('core-views')["transp-cell"]); elmts.or_views_fromCol.html($.i18n._('core-views')["from-col"]); elmts.or_views_toCol.html($.i18n._('core-views')["to-col"]); elmts.or_views_transpose.html($.i18n._('core-views')["transp-into"]); elmts.or_views_twoCol.html($.i18n._('core-views')["two-new-col"]); elmts.or_views_keyCol.html($.i18n._('core-views')["key-col"]); elmts.or_views_containNames.html($.i18n._('core-views')["contain-names"]); elmts.or_views_valCol.html($.i18n._('core-views')["val-col"]); elmts.or_views_containOrig.html($.i18n._('core-views')["contain-val"]); elmts.or_views_oneCol.html($.i18n._('core-views')["one-col"]); elmts.or_views_prependName.html($.i18n._('core-views')["prepend-name"]); elmts.or_views_followBy.html($.i18n._('core-views')["follow-by"]); elmts.or_views_beforeVal.html($.i18n._('core-views')["before-val"]); elmts.or_views_ignoreBlank.html($.i18n._('core-views')["ignore-blank"]); elmts.or_views_fillOther.html($.i18n._('core-views')["fill-other"]); elmts.okButton.html($.i18n._('core-buttons')["transpose"]); elmts.cancelButton.html($.i18n._('core-buttons')["cancel"]); var dismiss = function() { DialogSystem.dismissUntil(level - 1); }; var columns = theProject.columnModel.columns; elmts.cancelButton.click(function() { dismiss(); }); elmts.okButton.click(function() { var config = { startColumnName: elmts.fromColumnSelect[0].value, columnCount: elmts.toColumnSelect[0].value, ignoreBlankCells: elmts.ignoreBlankCellsCheckbox[0].checked, fillDown: elmts.fillDownCheckbox[0].checked }; var mode = dialog.find('input[name="transpose-dialog-column-choices"]:checked')[0].value; if (mode == "2") { config.keyColumnName = $.trim(elmts.keyColumnNameInput[0].value); config.valueColumnName = $.trim(elmts.valueColumnNameInput[0].value); if (config.keyColumnName == "") { alert($.i18n._('core-views')["spec-new-name"]); return; } else if (config.valueColumnName == "") { alert($.i18n._('core-views')["spec-new-val"]); return; } } else { config.combinedColumnName = $.trim(elmts.combinedColumnNameInput[0].value); config.prependColumnName = elmts.prependColumnNameCheckbox[0].checked; config.separator = elmts.separatorInput[0].value; if (config.combinedColumnName == "") { alert($.i18n._('core-views')["spec-col-name"]); return; } else if (config.prependColumnName && config.separator == "") { alert($.i18n._('core-views')["spec-separator"]); return; } } Refine.postCoreProcess( "transpose-columns-into-rows", config, null, { modelsChanged: true }, { onDone: dismiss } ); }); for (var i = 0; i < columns.length; i++) { var column2 = columns[i]; var option = $('