From e5511ea86d9927b9ebdf0de949db3bf63ad51be8 Mon Sep 17 00:00:00 2001 From: samarsultan Date: Tue, 18 Oct 2016 11:26:51 +0200 Subject: [PATCH] Rework bidi file structure Closes #1026,#983,#982,#978 PR #1026 contains the full history of the changes made herein. Due to the volume of commits with no meaningful comment, they have been squashed down to this one. Adding bidi Files Tuning code style Adding rest of bidi files and its dependencies Tuning code style editing numeric shaping value Tuning Code style adding bidi support Adding Bidi Support for the rest of files Adding Bidi support Editing Bidi menu adding mirroring enablement handeling code style Addinng Bidi Support Adding Bidi Support Adding locale settings to national calendar support Adding Numeric Shaping Support scss files after adding rtl direction part 1 adding rtl direction at scss files part2 adding right directionality at comman typeInput correcting some comments editing spaces applying code style editing code style editing code style editing code style editing code style adding right directionality adding right directionality adding style in case of right directionality adding style in case of right directionality adding style in case of right directionality create a global variable for ui direction to call it once need Update main.js Update typedInput.js Update 10-switch.html manage palette mirroring adding RTL directionality to Tabs and Manage palette Style Editing Adding mirroring to subflow workspace handle mirroring defects at manage palette Handle Mirroring defects at sidebar seperator Numeric Shaping Updates Editing code style Handling mirroring defects Handling mirroring defects Fixing mirroring defects editing code style fixing mirroring defects at deploy dialog editing code style Updating Bidi Support handling some reviewing comments handling chicks Update base-text-dir.js Update bidi-util.js Update bidi-util.js Handling reviewing comment Fixing Popover mirroring defect Handling namespace structure for bidi features reflecting new namespace structure for bidi features at editorfiles Handling comments that related to css moving bidi.js under js/bidi folder --- Gruntfile.js | 6 +- editor/js/bidi/base-text-dir.js | 67 +++++++++ editor/js/bidi/bidi.js | 189 ++++++++++++++++++++++++ editor/js/{text => bidi}/format.js | 3 +- editor/js/bidi/numeric-shaping.js | 86 +++++++++++ editor/js/main.js | 23 ++- editor/js/text/bidi.js | 130 ---------------- editor/js/ui/common/menu.js | 2 +- editor/js/ui/common/popover.js | 4 +- editor/js/ui/common/searchBox.js | 1 + editor/js/ui/common/tabs.js | 7 +- editor/js/ui/common/typedInput.js | 19 ++- editor/js/ui/deploy.js | 4 +- editor/js/ui/editor.js | 10 +- editor/js/ui/keyboard.js | 4 +- editor/js/ui/notifications.js | 1 + editor/js/ui/palette-editor.js | 3 +- editor/js/ui/palette.js | 10 +- editor/js/ui/sidebar.js | 24 +-- editor/js/ui/subflow.js | 21 ++- editor/js/ui/tab-info.js | 16 +- editor/js/ui/view.js | 6 +- editor/js/ui/workspaces.js | 2 +- editor/sass/dropdownMenu.scss | 37 +++++ editor/sass/editor.scss | 44 ++++++ editor/sass/flow.scss | 8 + editor/sass/header.scss | 28 ++++ editor/sass/jquery.scss | 21 +++ editor/sass/keyboard.scss | 12 ++ editor/sass/palette-editor.scss | 77 ++++++++++ editor/sass/palette.scss | 42 +++++- editor/sass/popover.scss | 6 + editor/sass/sidebar.scss | 31 ++++ editor/sass/tab-config.scss | 18 +++ editor/sass/tab-info.scss | 7 + editor/sass/tabs.scss | 50 +++++++ editor/sass/ui/common/editableList.scss | 13 ++ editor/sass/ui/common/searchBox.scss | 15 ++ editor/sass/ui/common/typedInput.scss | 21 +++ editor/sass/workspace.scss | 49 ++++++ editor/sass/workspaceToolbar.scss | 32 ++++ editor/templates/index.mst | 33 ++++- nodes/core/core/25-catch.html | 17 ++- nodes/core/core/25-status.html | 13 +- nodes/core/core/58-debug.html | 5 +- nodes/core/core/60-link.html | 23 ++- nodes/core/core/80-template.html | 17 ++- nodes/core/core/89-delay.html | 11 +- nodes/core/core/89-trigger.html | 12 +- nodes/core/io/10-mqtt.html | 26 +++- nodes/core/logic/10-switch.html | 3 +- red/api/locales/en-US/editor.json | 10 +- 52 files changed, 1107 insertions(+), 212 deletions(-) create mode 100644 editor/js/bidi/base-text-dir.js create mode 100644 editor/js/bidi/bidi.js rename editor/js/{text => bidi}/format.js (99%) create mode 100644 editor/js/bidi/numeric-shaping.js delete mode 100644 editor/js/text/bidi.js diff --git a/Gruntfile.js b/Gruntfile.js index 2c5da4ab1..258ea4519 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -104,8 +104,10 @@ module.exports = function(grunt) { "editor/js/settings.js", "editor/js/user.js", "editor/js/comms.js", - "editor/js/text/bidi.js", - "editor/js/text/format.js", + "editor/js/bidi/bidi.js", + "editor/js/bidi/base-text-dir.js", + "editor/js/bidi/format.js", + "editor/js/bidi/numeric-shaping.js", "editor/js/ui/state.js", "editor/js/nodes.js", "editor/js/history.js", diff --git a/editor/js/bidi/base-text-dir.js b/editor/js/bidi/base-text-dir.js new file mode 100644 index 000000000..9e699f867 --- /dev/null +++ b/editor/js/bidi/base-text-dir.js @@ -0,0 +1,67 @@ +/** + * Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ +RED.bidi.baseTextDir = (function() { + var LRE = "\u202A", + RLE = "\u202B", + PDF = "\u202C"; + + function _isRTLValue(stringValue) { + var length = stringValue.length; + for (var i = 0 ; i < length; i++) { + if (_isBidiChar(stringValue.charCodeAt(i))) { + return true; + } else if (_isLatinChar(stringValue.charCodeAt(i))) { + return false; + } + } + return RED.bidi.isMirroringEnabled(); + } + + function _isBidiChar(c) { + return (c >= 0x05d0 && c <= 0x05ff)|| + (c >= 0x0600 && c <= 0x065f)|| + (c >= 0x066a && c <= 0x06ef)|| + (c >= 0x06fa && c <= 0x07ff)|| + (c >= 0xfb1d && c <= 0xfdff)|| + (c >= 0xfe70 && c <= 0xfefc); + } + + function _isLatinChar(c) { + return (c > 64 && c < 91) || (c > 96 && c < 123); + } + + /** + * Enforces the text direction of a given string by adding + * UCC (Unicode Control Characters) + * @param value - the string + */ + function _enforceTextDirectionWithUCC(value) { + if (value) { + var dir = RED.bidi.resolveBaseTextDir(value); + if (dir == "ltr") { + return LRE + value + PDF; + } else if (dir == "rtl") { + return RLE + value + PDF; + } + } + return value; + } + + return { + enforceTextDirectionWithUCC: _enforceTextDirectionWithUCC, + isRTLValue : _isRTLValue + } +})(); diff --git a/editor/js/bidi/bidi.js b/editor/js/bidi/bidi.js new file mode 100644 index 000000000..89a68a9e6 --- /dev/null +++ b/editor/js/bidi/bidi.js @@ -0,0 +1,189 @@ +/** + * Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ +RED.bidi = (function() { + var textDir = ""; + var shaperType = ""; + var calendarType = ""; + + /** + * Indicates the type of bidi-support + * BTD : Base text direction + * NS : Numeric Shaping + * CALENDAR : National Calendar + * STT_ATTACH : Structure Text Support, it is using to call attach function located at format.js + * STT_GETHTML : STT_ATTACH : Structure Text Support, it is using to call getHtml function located at format.js + */ + var _flags = { + BTD: 1, + NS: 2, + CALENDAR: 4, + STT_ATTACH: 8, + STT_GETHTML: 16 + }; + + /** + * Reverse component position when mirroring is enabled + */ + var _componentPos = {}; + + /** + * Check if browser language is RTL language + */ + function _isMirroringEnabled() { + var isRTLLang = new RegExp("^(ar|he)").test(navigator.language); + if (isRTLLang) { + _componentPos.left = "right"; + _componentPos.right = "left"; + return true; + } else { + _componentPos.left = "left"; + _componentPos.right = "right"; + return false; + } + } + + /** + * @param val - the numeric shaping type: None , National or contextual + */ + function _setNumericShapingType(val) { + shaperType = val; + _refreshView(); + } + + /** + * Sets the national calendar preference + * @param val - the calendar type hijri, hebrew or gregorian + */ + function _setCalendarType(val) { + calendarType = val; + } + + /** + * Formats the date according to the current selected calendar + * @param date - the date object to be formatted + */ + function _getGlobalizedDate(date) { + var options = {}; + var lang = navigator.language; + if (calendarType === "hijri") { + options = lang + "-u-ca-islamic"; + } else if (calendarType === "hebrew") { + options = lang + "-u-ca-hebrew"; + } + return date.toLocaleString(options); + } + + /** + * Sets the text direction preference + * @param dir - the text direction preference + */ + function _setTextDirection(dir) { + textDir = dir; + _refreshView(); + _enforceTextDirectionOnPage(); + } + + /** + * Enforces the text direction for all the spans with style bidiAware under + * workspace or sidebar div + */ + function _enforceTextDirectionOnPage() { + $("#workspace").find('span.bidiAware').each(function() { + $(this).attr("dir", _resolveBaseTextDir($(this).html())); + }); + $("#sidebar").find('span.bidiAware').each(function() { + $(this).attr("dir", _resolveBaseTextDir($(this).text())); + }); + } + + /** + * Determines the text direction of a given string. + * @param value - the string + */ + function _resolveBaseTextDir(value) { + if (textDir == "auto") { + if (RED.bidi.baseTextDir.isRTLValue(value)) { + return "rtl"; + } else { + return "ltr"; + } + } else { + return textDir; + } + } + + /** + * Adds event listeners to the Input to ensure its text-direction attribute + * is properly set based on its content. + * @param input - the input field + */ + function _prepareInput(input) { + input.on("keyup",_onInputChange).on("paste",_onInputChange).on("cut",_onInputChange); + // Set the initial text direction + _onInputChange.call(input); + } + + function _onInputChange() { + $(this).attr("dir", _resolveBaseTextDir($(this).val())); + } + + /** + * Refreshes the view whenever changing the user preferences + */ + function _refreshView() { + RED.nodes.eachNode(function(n) { n.dirty = true;}); + RED.view.redraw(); + RED.palette.refresh(); + } + + /** + * Applying bidi support for these features: base-text-dir ,Numeric-shaping or both, STT ,Calendar which is controlled by the flag value. + * @param value- the string to apply the bidi-support on it. + * @param flag - indicates the type of bidi-support (Base-text-dir ,Numeric-shaping or both, STT , Calendar) + * @param type - could be one of filepath, url, email + * @param args - pass additional arguments to the handler. generally null. + */ + function _applyBidiSupport(value, flag, type, args) { + switch (flag) { + case 0: + value = RED.bidi.baseTextDir.enforceTextDirectionWithUCC(value); + return RED.bidi.numericShaping.shape(value, shaperType, textDir); + case 1: + return RED.bidi.baseTextDir.enforceTextDirectionWithUCC(value); + case 2: + return RED.bidi.numericShaping.shape(value, shaperType, textDir); + case 4: + return _getGlobalizedDate(value); + case 8: + return RED.bidi.format.attach(value, type, args, _isMirroringEnabled(), navigator.language); + case 16: + return RED.bidi.format.getHtml(value, type, args, _isMirroringEnabled(), navigator.language); + default: + return value; + } + } + return { + isMirroringEnabled: _isMirroringEnabled, + setNumericShapingType : _setNumericShapingType, + setCalendarType: _setCalendarType, + setTextDirection : _setTextDirection, + applyBidiSupport : _applyBidiSupport, + resolveBaseTextDir : _resolveBaseTextDir, + prepareInput: _prepareInput, + flags: _flags, + componentPos: _componentPos + } + })(); diff --git a/editor/js/text/format.js b/editor/js/bidi/format.js similarity index 99% rename from editor/js/text/format.js rename to editor/js/bidi/format.js index ddb568b86..95020100b 100644 --- a/editor/js/text/format.js +++ b/editor/js/bidi/format.js @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -RED.text.format = (function() { + +RED.bidi.format = (function() { var TextSegment = (function() { var TextSegment = function (obj) { diff --git a/editor/js/bidi/numeric-shaping.js b/editor/js/bidi/numeric-shaping.js new file mode 100644 index 000000000..bd3795443 --- /dev/null +++ b/editor/js/bidi/numeric-shaping.js @@ -0,0 +1,86 @@ +/** + * Copyright 2016 IBM Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ +RED.bidi.numericShaping = (function(){ + var regex = /([0-9])|([\u0660-\u0669])|([\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F\u0671-\u06D5\u06E5-\u06E6\u06EE-\u06EF\u06FA-\u06FF\u0750-\u077F\u08A0-\u08E3\u200F\u202B\u202E\u2067\uFB50-\uFD3D\uFD40-\uFDCF\uFDF0-\uFDFC\uFDFE-\uFDFF\uFE70-\uFEFE]+)|([^0-9\u0660-\u0669\u0608\u060B\u060D\u061B-\u064A\u066D-\u066F\u0671-\u06D5\u06E5-\u06E6\u06EE-\u06EF\u06FA-\u06FF\u0750-\u077F\u08A0-\u08E3\u200F\u202B\u202E\u2067\uFB50-\uFD3D\uFD40-\uFDCF\uFDF0-\uFDFC\uFDFE-\uFDFF\uFE70-\uFEFE\u0600-\u0607\u0609-\u060A\u060C\u060E-\u061A\u064B-\u066C\u0670\u06D6-\u06E4\u06E7-\u06ED\u06F0-\u06F9\u08E4-\u08FF\uFD3E-\uFD3F\uFDD0-\uFDEF\uFDFD\uFEFF\u0000-\u0040\u005B-\u0060\u007B-\u007F\u0080-\u00A9\u00AB-\u00B4\u00B6-\u00B9\u00BB-\u00BF\u00D7\u00F7\u02B9-\u02BA\u02C2-\u02CF\u02D2-\u02DF\u02E5-\u02ED\u02EF-\u02FF\u2070\u2074-\u207E\u2080-\u208E\u2100-\u2101\u2103-\u2106\u2108-\u2109\u2114\u2116-\u2118\u211E-\u2123\u2125\u2127\u2129\u212E\u213A-\u213B\u2140-\u2144\u214A-\u214D\u2150-\u215F\u2189\uA720-\uA721\uA788\uFF01-\uFF20\uFF3B-\uFF40\uFF5B-\uFF65\uFFE0-\uFFE6\uFFE8-\uFFEE]+)/g; + + /** + * Converts the digits in the text to European or Arabic digits According to + * the shaperType & the textDir. + */ + function _shape(text, shaperType, textDir) { + text = text.toString(); + if(textDir === "auto"){ + textDir = RED.bidi.resolveBaseTextDir(text); + } + if (!text) { + return text; + } + switch (shaperType) { + case "defaultNumeral": + return _shapeEuropean(text); + case "national": + return _shapeArabic(text); + case "contextual": + return _shapeContextual(text, textDir === "rtl" ? 2 : 1); + default: + return text; + } + } + + /** + * Converts the digits in the text to European digits. + */ + function _shapeEuropean(text) { + return text.replace(/[\u0660-\u0669]/g, function(c) { + return c.charCodeAt(0) - 1632; + }); + } + + /** + * Converts the digits in the text to Arabic digits. + */ + function _shapeArabic(text) { + return text.replace(/[0-9]/g, function(c) { + return String.fromCharCode(parseInt(c) + 1632); + }); + } + + /** + * Converts the digits in the text to European or Arabic digits + * According to the type of the preceding strong character. + * @param context:The current effective context. + * Allowed values: + * '1': European context + * '2': Arabic context + */ + function _shapeContextual(text, context) { + return text.replace(regex, function(match, latinDigit, arabicDigit, strongArabic, strongLatin){ + if (latinDigit) { + return (context === 2) ? String.fromCharCode(parseInt(latinDigit) + 1632) : latinDigit; + } else if (arabicDigit) { + return (context === 1) ? arabicDigit.charCodeAt(0) - 1632 : arabicDigit; + } else if (strongArabic) { + context = 2; + } else if (strongLatin) { + context = 1; + } + return match; + }); + } + return { + shape: _shape + } +})(); diff --git a/editor/js/main.js b/editor/js/main.js index 79fff2996..009f6b172 100644 --- a/editor/js/main.js +++ b/editor/js/main.js @@ -180,10 +180,20 @@ var RED = (function() { {id:"menu-item-status",label:RED._("menu.label.displayStatus"),toggle:true,onselect:toggleStatus, selected: true}, null, {id:"menu-item-bidi",label:RED._("menu.label.view.textDir"),options:[ - {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if(s){RED.text.bidi.setTextDirection("")}}}, - {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("ltr")}}}, - {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("rtl")}}}, - {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if(s){RED.text.bidi.setTextDirection("auto")}}} + {id:"menu-item-bidi-default",toggle:"text-direction",label:RED._("menu.label.view.defaultDir"),selected: true, onselect:function(s) { if (s) {RED.bidi.setTextDirection("")}}}, + {id:"menu-item-bidi-ltr",toggle:"text-direction",label:RED._("menu.label.view.ltr"), onselect:function(s) { if (s) {RED.bidi.setTextDirection("ltr")}}}, + {id:"menu-item-bidi-rtl",toggle:"text-direction",label:RED._("menu.label.view.rtl"), onselect:function(s) { if (s) {RED.bidi.setTextDirection("rtl")}}}, + {id:"menu-item-bidi-auto",toggle:"text-direction",label:RED._("menu.label.view.auto"), onselect:function(s) { if (s) {RED.bidi.setTextDirection("auto")}}} + ]}, + {id:"menu-item-numerals",label:RED._("menu.label.view.numericShaping"),options:[ + {id:"menu-item-numerals-default",toggle:"numeral-type",label:RED._("menu.label.view.defaultNumeral"),selected: true, onselect:function(s) { if(s){RED.bidi.setNumericShapingType("defaultNumeral")}}}, + {id:"menu-item-numerals-national",toggle:"numeral-type",label:RED._("menu.label.view.national"), onselect:function(s) { if (s) {RED.bidi.setNumericShapingType("national")}}}, + {id:"menu-item-numerals-contextual",toggle:"numeral-type",label:RED._("menu.label.view.contextual"), onselect:function(s) { if (s){RED.bidi.setNumericShapingType("contextual")}}} + ]}, + {id:"menu-item-calendars",label:RED._("menu.label.view.calendar"),options:[ + {id:"menu-item-calendars-default",toggle:"calendar-type",label:RED._("menu.label.view.defaultCalendar"),selected: true, onselect:function(s) { if(s) {RED.bidi.setCalendarType("gregorian")}}}, + {id:"menu-item-calendars-hijri",toggle:"calendar-type",label:RED._("menu.label.view.hijri"), onselect:function(s) { if (s) {RED.bidi.setCalendarType("hijri")}}}, + {id:"menu-item-calendars-hebrew",toggle:"calendar-type",label:RED._("menu.label.view.hebrew"), onselect:function(s) { if (s) {RED.bidi.setCalendarType("hebrew")}}} ]}, null, {id:"menu-item-sidebar",label:RED._("menu.label.sidebar.show"),toggle:true,onselect:RED.sidebar.toggleSidebar, selected: true} @@ -226,6 +236,11 @@ var RED = (function() { RED.menu.init({id:"btn-sidemenu",options: menuOptions}); + //apply rtl direction on body tag in case of GUI mirroring is enabled + if (RED.bidi.isMirroringEnabled()) { + $("body").attr("dir","rtl"); + } + RED.user.init(); RED.library.init(); diff --git a/editor/js/text/bidi.js b/editor/js/text/bidi.js deleted file mode 100644 index 00000567d..000000000 --- a/editor/js/text/bidi.js +++ /dev/null @@ -1,130 +0,0 @@ -/** - * Copyright 2016 IBM Corp. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -RED.text = {}; -RED.text.bidi = (function() { - var textDir = ""; - var LRE = "\u202A", - RLE = "\u202B", - PDF = "\u202C"; - - function isRTLValue(stringValue) { - var length = stringValue.length; - for (var i=0;i= 0x05d0 && c <= 0x05ff)|| - (c >= 0x0600 && c <= 0x065f)|| - (c >= 0x066a && c <= 0x06ef)|| - (c >= 0x06fa && c <= 0x07ff)|| - (c >= 0xfb1d && c <= 0xfdff)|| - (c >= 0xfe70 && c <= 0xfefc); - } - - function isLatinChar(c){ - return (c > 64 && c < 91)||(c > 96 && c < 123) - } - - /** - * Determines the text direction of a given string. - * @param value - the string - */ - function resolveBaseTextDir(value) { - if (textDir == "auto") { - if (isRTLValue(value)) { - return "rtl"; - } else { - return "ltr"; - } - } - else { - return textDir; - } - } - - function onInputChange() { - $(this).attr("dir", resolveBaseTextDir($(this).val())); - } - - /** - * Adds event listeners to the Input to ensure its text-direction attribute - * is properly set based on its content. - * @param input - the input field - */ - function prepareInput(input) { - input.on("keyup",onInputChange).on("paste",onInputChange).on("cut",onInputChange); - // Set the initial text direction - onInputChange.call(input); - } - - /** - * Enforces the text direction of a given string by adding - * UCC (Unicode Control Characters) - * @param value - the string - */ - function enforceTextDirectionWithUCC(value) { - if (value) { - var dir = resolveBaseTextDir(value); - if (dir == "ltr") { - return LRE + value + PDF; - } - else if (dir == "rtl") { - return RLE + value + PDF; - } - } - return value; - } - - /** - * Enforces the text direction for all the spans with style bidiAware under - * workspace or sidebar div - */ - function enforceTextDirectionOnPage() { - $("#workspace").find('span.bidiAware').each(function() { - $(this).attr("dir", resolveBaseTextDir($(this).html())); - }); - $("#sidebar").find('span.bidiAware').each(function() { - $(this).attr("dir", resolveBaseTextDir($(this).text())); - }); - } - - /** - * Sets the text direction preference - * @param dir - the text direction preference - */ - function setTextDirection(dir) { - textDir = dir; - RED.nodes.eachNode(function(n) { n.dirty = true;}); - RED.view.redraw(); - RED.palette.refresh(); - enforceTextDirectionOnPage(); - } - - return { - setTextDirection: setTextDirection, - enforceTextDirectionWithUCC: enforceTextDirectionWithUCC, - resolveBaseTextDir: resolveBaseTextDir, - prepareInput: prepareInput - } -})(); diff --git a/editor/js/ui/common/menu.js b/editor/js/ui/common/menu.js index b2a7ee6c6..8f6322f71 100644 --- a/editor/js/ui/common/menu.js +++ b/editor/js/ui/common/menu.js @@ -75,7 +75,7 @@ RED.menu = (function() { linkContent += ''+opt.label+''+ ''+opt.sublabel+'' } else { - linkContent += ''+opt.label+'' + linkContent += ''+RED.bidi.applyBidiSupport(opt.label, RED.bidi.flags.NS)+'' } linkContent += ''; diff --git a/editor/js/ui/common/popover.js b/editor/js/ui/common/popover.js index 05e758072..2aa1e9051 100644 --- a/editor/js/ui/common/popover.js +++ b/editor/js/ui/common/popover.js @@ -34,8 +34,8 @@ RED.popover = (function() { var targetHeight = target.height(); var divHeight = div.height(); - div.css({top: targetPos.top+targetHeight/2-divHeight/2-10,left:targetPos.left+targetWidth+17}); - + var popoverPos = ((RED.bidi.isMirroringEnabled()) ? targetPos.left-targetWidth-210 : targetPos.left+targetWidth+17); + div.css({top: targetPos.top+targetHeight/2-divHeight/2-10,left:popoverPos}); div.fadeIn("fast"); } } diff --git a/editor/js/ui/common/searchBox.js b/editor/js/ui/common/searchBox.js index 792759dfd..3afdf5517 100644 --- a/editor/js/ui/common/searchBox.js +++ b/editor/js/ui/common/searchBox.js @@ -89,6 +89,7 @@ if (val === undefined || val === null || val === "") { this.resultCount.text("").hide(); } else { + val = RED.bidi.applyBidiSupport(val,RED.bidi.flags.NS); this.resultCount.text(val).show(); } } diff --git a/editor/js/ui/common/tabs.js b/editor/js/ui/common/tabs.js index 783db3d41..74fe1ad27 100644 --- a/editor/js/ui/common/tabs.js +++ b/editor/js/ui/common/tabs.js @@ -202,9 +202,8 @@ RED.tabs = (function() { if (tab.icon) { $('').appendTo(link); } - var span = $('',{class:"bidiAware"}).text(tab.label).appendTo(link); - span.attr('dir', RED.text.bidi.resolveBaseTextDir(tab.label)); - + var span = $('',{class:"bidiAware"}); + span.attr('dir', RED.bidi.resolveBaseTextDir(tab.label)).text(RED.bidi.applyBidiSupport(tab.label,RED.bidi.flags.NS)).appendTo(link); link.on("click",onTabClick); link.on("dblclick",onTabDblClick); if (tab.closeable) { @@ -314,7 +313,7 @@ RED.tabs = (function() { tabs[id].label = label; var tab = ul.find("a[href='#"+id+"']"); tab.attr("title",label); - tab.find("span").text(label).attr('dir', RED.text.bidi.resolveBaseTextDir(label)); + tab.find("span").attr('dir', RED.bidi.resolveBaseTextDir(label)).text(RED.bidi.applyBidiSupport(label,RED.bidi.flags.NS)); updateTabWidths(); }, order: function(order) { diff --git a/editor/js/ui/common/typedInput.js b/editor/js/ui/common/typedInput.js index 90749d509..afc0fd8a2 100644 --- a/editor/js/ui/common/typedInput.js +++ b/editor/js/ui/common/typedInput.js @@ -198,12 +198,12 @@ if (opt.label) { op.text(opt.label); } + // reverse property direction in case of right directionality if (opt.icon) { - $('',{src:opt.icon,style:"margin-right: 4px; height: 18px;"}).prependTo(op); + $('',{src:opt.icon,style:"margin-"+RED.bidi.componentPos.right+": 4px; height: 18px;"}).prependTo(op); } else { - op.css({paddingLeft: "18px"}); + op.css("padding-"+RED.bidi.componentPos.left, "18px"); } - op.click(function(event) { event.preventDefault(); callback(opt.value); @@ -225,15 +225,19 @@ var that = this; var pos = relativeTo.offset(); var height = relativeTo.height(); + var width = relativeTo.outerWidth(); var menuHeight = menu.height(); var top = (height+pos.top-3); if (top+menuHeight > $(window).height()) { top -= (top+menuHeight)-$(window).height()+5; } + + var menuPos = ((RED.bidi.isMirroringEnabled()) ? ((pos.left + width) - (menu.offset().left + menu.outerWidth())) : (2+pos.left)); menu.css({ top: top+"px", - left: (2+pos.left)+"px", + left: menuPos+"px", }); + menu.slideDown(100); this._delay(function() { that.uiSelect.addClass('red-ui-typedInput-focus'); @@ -271,9 +275,10 @@ } else { this.selectTrigger.width('auto'); var labelWidth = this._getLabelWidth(this.selectTrigger); - this.elementDiv.css('left',labelWidth+"px"); + // reverse property direction in case of right directionality + this.elementDiv.css(RED.bidi.componentPos.left,labelWidth+"px"); if (this.optionSelectTrigger) { - this.optionSelectTrigger.css('left',(labelWidth+5)+"px"); + this.optionSelectTrigger.css(RED.bidi.componentPos.left,(labelWidth+5)+"px"); } } }, @@ -336,7 +341,7 @@ image = new Image(); image.name = opt.icon; image.src = opt.icon; - $('',{src:opt.icon,style:"margin-right: 4px;height: 18px;"}).prependTo(this.selectLabel); + $('',{src:opt.icon,style:"margin-"+RED.bidi.componentPos.right+": 4px;height: 18px;"}).prependTo(this.selectLabel); } else { this.selectLabel.text(opt.label); } diff --git a/editor/js/ui/deploy.js b/editor/js/ui/deploy.js index 9ac340fcd..ae0260225 100644 --- a/editor/js/ui/deploy.js +++ b/editor/js/ui/deploy.js @@ -114,7 +114,7 @@ RED.deploy = (function() { ], create: function() { $("#node-dialog-confirm-deploy").parent().find("div.ui-dialog-buttonpane") - .prepend('
'+ + .prepend('
'+ ''+ ''+ ''+ @@ -570,7 +570,7 @@ RED.deploy = (function() { $( "#node-dialog-confirm-deploy-config" ).show(); invalidNodes.sort(sortNodeInfo); $( "#node-dialog-confirm-deploy-invalid-list" ) - .html("
  • "+invalidNodes.map(function(A) { return (A.tab?"["+A.tab+"] ":"")+A.label+" ("+A.type+")"}).join("
  • ")+"
  • "); + .html("
  • "+invalidNodes.map(function(A) { return (A.tab?"["+RED.bidi.applyBidiSupport(A.tab, RED.bidi.flags.NS)+"] ":"")+RED.bidi.applyBidiSupport(A.label, RED.bidi.flags.NS)+" ("+A.type+")"}).join("
  • ")+"
  • "); } else if (hasUnusedConfig && !ignoreDeployWarnings.unusedConfig) { // showWarning = true; diff --git a/editor/js/ui/editor.js b/editor/js/ui/editor.js index ea2e97dd4..5103b72b0 100644 --- a/editor/js/ui/editor.js +++ b/editor/js/ui/editor.js @@ -315,12 +315,12 @@ RED.editor = (function() { val = ""; } if (definition !== undefined && definition[property].hasOwnProperty("format") && definition[property].format !== "" && input[0].nodeName === "DIV") { - input.html(RED.text.format.getHtml(val, definition[property].format, {}, false, "en")); - RED.text.format.attach(input[0], definition[property].format, {}, false, "en"); + input.html(RED.bidi.applyBidiSupport(val, RED.bidi.flags.STT_GETHTML, definition[property].format, {})); + RED.bidi.applyBidiSupport(input[0],RED.bidi.flags.STT_ATTACH, definition[property].format, {}); } else { input.val(val); if (input[0].nodeName === 'INPUT' || input[0].nodeName === 'TEXTAREA') { - RED.text.bidi.prepareInput(input); + RED.bidi.prepareInput(input); } } } @@ -1186,7 +1186,7 @@ RED.editor = (function() { } configNodes.forEach(function(cn) { - select.append(''); + select.append(''); delete cn.__label__; }); @@ -1320,7 +1320,7 @@ RED.editor = (function() { }); $("#subflow-input-name").val(subflow.name); - RED.text.bidi.prepareInput($("#subflow-input-name")); + RED.bidi.prepareInput($("#subflow-input-name")); subflowEditor.getSession().setValue(subflow.info||"",-1); var userCount = 0; var subflowType = "subflow:"+editing_node.id; diff --git a/editor/js/ui/keyboard.js b/editor/js/ui/keyboard.js index 07ff5790e..5b6471b42 100644 --- a/editor/js/ui/keyboard.js +++ b/editor/js/ui/keyboard.js @@ -105,7 +105,7 @@ RED.keyboard = (function() { } if (!dialog) { dialog = $('
    '+ - '
    '+ + '
    '+ ''+ ''+ ''+ @@ -121,7 +121,7 @@ RED.keyboard = (function() { ''+ '
    Ctrl/⌘ + a'+RED._("keyboard.selectAll")+'
    Shift + Click'+RED._("keyboard.selectAllConnected")+'
    Shift +
    '+ '
    '+ - '
    '+ + '
    '+ ''+ ''+ ''+ diff --git a/editor/js/ui/notifications.js b/editor/js/ui/notifications.js index f64bf6f89..e1d106eae 100644 --- a/editor/js/ui/notifications.js +++ b/editor/js/ui/notifications.js @@ -17,6 +17,7 @@ RED.notify = (function() { var currentNotifications = []; var c = 0; return function(msg,type,fixed,timeout) { + msg = RED.bidi.applyBidiSupport(msg ,RED.bidi.flags.NS); if (currentNotifications.length > 4) { var ll = currentNotifications.length; for (var i = 0;ll > 4 && i 0) { @@ -454,7 +455,7 @@ RED.palette.editor = (function() { var titleRow = $('
    ').appendTo(headerRow); $('').html(entry.name).appendTo(titleRow); var metaRow = $('
    ').appendTo(headerRow); - $('').html(entry.version).appendTo(metaRow); + $('').html(RED.bidi.applyBidiSupport(entry.version,RED.bidi.flags.NS)).appendTo(metaRow); var buttonRow = $('
    ',{class:"palette-module-meta"}).appendTo(headerRow); var setButton = $(' ').appendTo(buttonRow); var setCount = $('').appendTo(setButton); diff --git a/editor/js/ui/palette.js b/editor/js/ui/palette.js index 4435bfb30..abb9c3586 100644 --- a/editor/js/ui/palette.js +++ b/editor/js/ui/palette.js @@ -86,20 +86,22 @@ RED.palette = (function() { } displayLines.push(currentLine); - var lines = displayLines.join("
    "); + var tempLines = displayLines.join("^&%"); + tempLines =RED.bidi.applyBidiSupport(tempLines, RED.bidi.flags.NS); + var lines = tempLines.replace("^&%", "
    "); var multiLineNodeHeight = 8+(lineHeight*displayLines.length); el.css({height:multiLineNodeHeight+"px"}); var labelElement = el.find(".palette_label"); - labelElement.html(lines).attr('dir', RED.text.bidi.resolveBaseTextDir(lines)); + labelElement.html(lines).attr('dir', RED.bidi.resolveBaseTextDir(lines)); el.find(".palette_port").css({top:(multiLineNodeHeight/2-5)+"px"}); var popOverContent; try { - var l = "

    "+RED.text.bidi.enforceTextDirectionWithUCC(label)+"

    "; + var l = "

    "+RED.bidi.applyBidiSupport(label,RED.bidi.flags.BTD & RED.bidi.flags.NS)+"

    "; if (label != type) { - l = "

    "+RED.text.bidi.enforceTextDirectionWithUCC(label)+"
    "+type+"

    "; + l = "

    "+RED.bidi.applyBidiSupport(label,RED.bidi.flags.BTD & RED.bidi.flags.NS)+"
    "+type+"

    "; } popOverContent = $(l+(info?info:$("script[data-help-name$='"+type+"']").html()||"

    "+RED._("palette.noInfo")+"

    ").trim()) .filter(function(n) { diff --git a/editor/js/ui/sidebar.js b/editor/js/ui/sidebar.js index 9a3e75dae..90188a274 100644 --- a/editor/js/ui/sidebar.js +++ b/editor/js/ui/sidebar.js @@ -113,7 +113,7 @@ RED.sidebar = (function() { sidebarSeparator.opening = true; var newChartRight = 7; $("#sidebar").addClass("closing"); - $("#workspace").css("right",newChartRight); + $("#workspace").css(RED.bidi.componentPos.right,newChartRight); $("#editor-stack").css("right",newChartRight+1); $("#sidebar").width(0); RED.menu.setSelected("menu-item-sidebar",true); @@ -123,16 +123,21 @@ RED.sidebar = (function() { }, drag: function(event,ui) { var d = ui.position.left-sidebarSeparator.start; - var newSidebarWidth = sidebarSeparator.width-d; + // using to handle sidebar width at both RTL and LTR UIs + var newSidebarWidth = (RED.bidi.isMirroringEnabled() ? sidebarSeparator.width + d : sidebarSeparator.width - d); if (sidebarSeparator.opening) { newSidebarWidth -= 3; } if (newSidebarWidth > 150) { - if (sidebarSeparator.chartWidth+d < 200) { + // to handle sidebar width at both RTL and LTR UIs + var tempValue = (RED.bidi.isMirroringEnabled() ? sidebarSeparator.chartWidth - d : sidebarSeparator.chartWidth + d); + if (tempValue < 200) { + ui.position.left = 200+sidebarSeparator.start-sidebarSeparator.chartWidth; d = ui.position.left-sidebarSeparator.start; - newSidebarWidth = sidebarSeparator.width-d; + // to handle sidebar width at both RTL and LTR UIs + newSidebarWidth = (RED.bidi.isMirroringEnabled() ? sidebarSeparator.width + d : sidebarSeparator.width - d); } } @@ -151,8 +156,9 @@ RED.sidebar = (function() { $("#sidebar").removeClass("closing"); } - var newChartRight = sidebarSeparator.chartRight-d; - $("#workspace").css("right",newChartRight); + //to handle workspace css right property at both RTL and LTR UIs + var newChartRight = (RED.bidi.isMirroringEnabled() ? $("#editor-stack").css("right") : sidebarSeparator.chartRight-d); + $("#workspace").css(RED.bidi.componentPos.right,(RED.bidi.isMirroringEnabled() ? newSidebarWidth+2 : newChartRight)); $("#editor-stack").css("right",newChartRight+1); $("#sidebar").width(newSidebarWidth); @@ -165,12 +171,12 @@ RED.sidebar = (function() { RED.menu.setSelected("menu-item-sidebar",false); if ($("#sidebar").width() < 180) { $("#sidebar").width(180); - $("#workspace").css("right",187); + $("#workspace").css(RED.bidi.componentPos.right,187); $("#editor-stack").css("right",188); } } - $("#sidebar-separator").css("left","auto"); - $("#sidebar-separator").css("right",($("#sidebar").width()+2)+"px"); + $("#sidebar-separator").css(RED.bidi.componentPos.left,"auto"); + $("#sidebar-separator").css(RED.bidi.componentPos.right,($("#sidebar").width()+2)+"px"); RED.events.emit("sidebar:resize"); } }); diff --git a/editor/js/ui/subflow.js b/editor/js/ui/subflow.js index 8b7d2b03a..2d78f75b6 100644 --- a/editor/js/ui/subflow.js +++ b/editor/js/ui/subflow.js @@ -139,7 +139,7 @@ RED.subflow = (function() { RED.view.select(); RED.nodes.dirty(true); RED.view.redraw(); - $("#workspace-subflow-output .spinner-value").html(subflow.out.length); + $("#workspace-subflow-output .spinner-value").html(RED.bidi.applyBidiSupport(subflow.out.length,RED.bidi.flags.NS)); } function removeSubflowOutput(removedSubflowOutputs) { @@ -216,7 +216,7 @@ RED.subflow = (function() { $("#workspace-subflow-input-add").toggleClass("active", activeSubflow.in.length !== 0); $("#workspace-subflow-input-remove").toggleClass("active",activeSubflow.in.length === 0); - $("#workspace-subflow-output .spinner-value").html(activeSubflow.out.length); + $("#workspace-subflow-output .spinner-value").html(RED.bidi.applyBidiSupport(activeSubflow.out.length,RED.bidi.flags.NS)); } } @@ -224,15 +224,15 @@ RED.subflow = (function() { var toolbar = $("#workspace-toolbar"); toolbar.empty(); - $(' ').appendTo(toolbar); - $(' '+ - '
    '+ - '0'+ + $(' ').appendTo(toolbar); + $(' '+ + '
    '+ + '0'+ '1'+ '
    ').appendTo(toolbar); - $('
    '+ - ''+ + $('
    '+ + ''+ '
    3
    '+ ''+ '
    ').appendTo(toolbar); @@ -243,6 +243,11 @@ RED.subflow = (function() { toolbar.i18n(); + var subflow_add = RED.bidi.applyBidiSupport($("#workspace-subflow-input-add").text(),RED.bidi.flags.NS); + var subflow_remove = RED.bidi.applyBidiSupport($("#workspace-subflow-input-remove").text(),RED.bidi.flags.NS); + $("#workspace-subflow-input-add").html(subflow_add); + $("#workspace-subflow-input-remove").html(subflow_remove); + $("#workspace-subflow-output-remove").click(function(event) { event.preventDefault(); var wasDirty = RED.nodes.dirty(); diff --git a/editor/js/ui/tab-info.js b/editor/js/ui/tab-info.js index f8b0de8b4..6d6963c3e 100644 --- a/editor/js/ui/tab-info.js +++ b/editor/js/ui/tab-info.js @@ -70,10 +70,10 @@ RED.sidebar.info = (function() { var table = '
    Ctrl/⌘ + Space'+RED._("keyboard.toggleSidebar")+'
    Ctrl/⌘ + .'+RED._("keyboard.searchBox")+'
    '; table += ''; if (node.type != "subflow" && node.name) { - table += ''; + table += ''; } table += ""; - table += ""; + table += ""; var m = /^subflow(:(.+))?$/.exec(node.type); var subflowNode; @@ -93,8 +93,8 @@ RED.sidebar.info = (function() { userCount++; } }); - table += ''; - table += ""; + table += ''; + table += ""; } if (!m && node.type != "subflow" && node.type != "comment") { @@ -132,7 +132,7 @@ RED.sidebar.info = (function() { val = val.replace(/&/g,"&").replace(//g,">"); } - table += '"; + table += '"; } } } @@ -140,14 +140,14 @@ RED.sidebar.info = (function() { table += "
    '+RED._("sidebar.info.node")+'
    '+RED._("common.label.name")+' '+node.name+'
    '+RED._("common.label.name")+' '+RED.bidi.applyBidiSupport(node.name,RED.bidi.flags.NS)+'
    "+RED._("sidebar.info.type")+" "+node.type+"
    "+RED._("sidebar.info.id")+" "+node.id+"
    "+RED._("sidebar.info.id")+" "+RED.bidi.applyBidiSupport(node.id,RED.bidi.flags.NS)+"
    '+RED._("common.label.name")+''+subflowNode.name+'
    "+RED._("sidebar.info.instances")+""+userCount+"
    '+RED._("common.label.name")+''+RED.bidi.applyBidiSupport(subflowNode.name,RED.bidi.flags.NS)+'
    "+RED._("sidebar.info.instances")+""+RED.bidi.applyBidiSupport(userCount,RED.bidi.flags.NS)+"
    '+n+""+val+"
    '+n+""+RED.bidi.applyBidiSupport(val,RED.bidi.flags.NS)+"

    "; if (!subflowNode && node.type != "comment") { var helpText = $("script[data-help-name$='"+node.type+"']").html()||""; - table += '
    '+helpText+'
    '; + table += '
    '+RED.bidi.applyBidiSupport(helpText,RED.bidi.flags.NS)+'
    '; } if (subflowNode) { - table += '
    '+marked(subflowNode.info||"")+'
    '; + table += '
    '+marked(subflowNode.info||"")+'
    '; } else if (node._def && node._def.info) { var info = node._def.info; var textInfo = (typeof info === "function" ? info.call(node) : info); - table += '
    '+marked(textInfo)+'
    '; + table += '
    '+marked(textInfo)+'
    '; //table += '
    '+(typeof info === "function" ? info.call(node) : info)+'
    '; } diff --git a/editor/js/ui/view.js b/editor/js/ui/view.js index 04922d658..5f5447d25 100644 --- a/editor/js/ui/view.js +++ b/editor/js/ui/view.js @@ -1454,7 +1454,7 @@ RED.view = (function() { .on("mouseout",function(d,i) { var port = d3.select(this); port.classed("port_hovered",false);}); outGroup.append("svg:text").attr("class","port_label").attr("x",20).attr("y",8).style("font-size","10px").text("output"); - outGroup.append("svg:text").attr("class","port_label port_index").attr("x",20).attr("y",24).text(function(d,i){ return i+1}); + outGroup.append("svg:text").attr("class","port_label port_index").attr("x",20).attr("y",24).text(function(d,i){ return RED.bidi.applyBidiSupport(i+1,RED.bidi.flags.NS)}); var subflowInputs = vis.selectAll(".subflowinput").data(activeSubflow.in,function(d,i){ return d.id;}); subflowInputs.exit().remove(); @@ -1503,7 +1503,7 @@ RED.view = (function() { if (d.dirty) { var output = d3.select(this); output.selectAll(".subflowport").classed("node_selected",function(d) { return d.selected; }) - output.selectAll(".port_index").text(function(d){ return d.i+1}); + output.selectAll(".port_index").text(function(d){ return RED.bidi.applyBidiSupport(d.i+1, RED.bidi.flags.NS)}); output.attr("transform", function(d) { return "translate(" + (d.x-d.w/2) + "," + (d.y-d.h/2) + ")"; }); dirtyNodes[d.id] = d; d.dirty = false; @@ -1809,7 +1809,7 @@ RED.view = (function() { l = d._def.label; try { l = (typeof l === "function" ? l.call(d) : l)||""; - l = RED.text.bidi.enforceTextDirectionWithUCC(l); + l = RED.bidi.applyBidiSupport(l,RED.bidi.flags.BTD & RED.bidi.flags.NS); } catch(err) { console.log("Definition error: "+d.type+".label",err); l = d.type; diff --git a/editor/js/ui/workspaces.js b/editor/js/ui/workspaces.js index f19e49543..bc8d6a855 100644 --- a/editor/js/ui/workspaces.js +++ b/editor/js/ui/workspaces.js @@ -113,7 +113,7 @@ RED.workspaces = (function() { $('').prependTo(dialogForm); dialogForm.submit(function(e) { e.preventDefault();}); $("#node-input-name").val(workspace.label); - RED.text.bidi.prepareInput($("#node-input-name")) + RED.bidi.prepareInput($("#node-input-name")) dialogForm.i18n(); }, close: function() { diff --git a/editor/sass/dropdownMenu.scss b/editor/sass/dropdownMenu.scss index 8ada3a2d9..8260022ae 100644 --- a/editor/sass/dropdownMenu.scss +++ b/editor/sass/dropdownMenu.scss @@ -25,19 +25,41 @@ margin-left: -25px; margin-top: 3px; } + +[dir="rtl"] .dropdown-menu * .fa-check-square { + float: right; + margin-left: initial; + margin-right: -8px; +} + .dropdown-menu * a.active > .fa-check-square { display: inline-block; } + +[dir="rtl"] .dropdown-menu * a.active > .fa-check-square { + float: right; +} + .dropdown-menu * .fa-square { display: inline-block; color: #e0e0e0; margin-left: -25px; margin-top: 3px; } + +[dir="rtl"] .dropdown-menu * .fa-square { + float: right; + margin-left: initial; + margin-right: -8px; +} + .dropdown-menu * a.active > .fa-square { display: none; } +[dir="rtl"] .dropdown-menu * a.active > .fa-square { + float: right; +} .dropdown-menu>li.disabled>a:hover>[class^="icon-"] { background-image: url("vendor/bootstrap/img/glyphicons-halflings.png") !important; @@ -48,6 +70,12 @@ width: 200px !important; margin-left: 0px !important; } + +[dir="rtl"] .dropdown-menu{ + right: auto; + left: 0; +} + .dropdown-menu > li > a > i { width: 10px; text-align: center; @@ -76,9 +104,18 @@ content: " "; } +[dir="rtl"] .dropdown-submenu>a:before { + float : right; + transform: rotate(180deg); +} + .dropdown-submenu.disabled > a:before { border-right-color: #444; } .dropdown-submenu.pull-left>.dropdown-menu { border-radius: 0; } + +[dir="rtl"] .dropdown-submenu.pull-left>.dropdown-menu { + right: -250px; +} diff --git a/editor/sass/editor.scss b/editor/sass/editor.scss index fe0b18dac..92ead727b 100644 --- a/editor/sass/editor.scss +++ b/editor/sass/editor.scss @@ -24,6 +24,11 @@ width: 0; z-index: 5; } + +[dir="rtl"] #editor-stack { + right: 180px; +} + .editor-tray { position:absolute; margin: 0; @@ -48,6 +53,7 @@ .editor-tray-body { margin: 20px; } + .editor-tray-header { @include disable-selection; position: relative; @@ -118,6 +124,16 @@ } } +[dir="rtl"] .editor-tray-toolbar { + text-align: left; + + button { + &.leftButton { + float: left; + } + } +} + .editor-tray-titlebar { border-bottom: 1px solid $secondary-border-color; padding: 8px; @@ -266,6 +282,9 @@ font-size: 12px !important; line-height: 35px; } +[dir="rtl"] #node-config-dialog-scope-container { + float: left; +} #node-config-dialog-scope-warning { display: inline-block; margin-right: 5px; @@ -287,3 +306,28 @@ font-size: 12px; line-height: 35px; } +[dir="rtl"] #node-config-dialog-user-count { + float: right; + margin-right: 0; + margin-left: 20px; +} + +/* +* some icons have to be rotated in case of rtl dir +*/ +[dir="rtl"] .fa-tag, +[dir="rtl"] .fa-tags, +[dir="rtl"] .fa-repeat { + transform: rotate(90deg); +} + +/* +* some icons have to be rotated in case of rtl dir +*/ +[dir="rtl"] .fa-random, +[dir="rtl"] .fa-tasks, +[dir="rtl"] .fa-list, +[dir="rtl"] .fa-sign-out, +[dir="rtl"] .fa-sign-in { + transform: rotate(180deg); +} diff --git a/editor/sass/flow.scss b/editor/sass/flow.scss index 88dad4622..df3830e3e 100644 --- a/editor/sass/flow.scss +++ b/editor/sass/flow.scss @@ -68,6 +68,10 @@ @include disable-selection; } +[dir="rtl"] .node_label { + direction: ltr; +} + .port_label { stroke-width: 0; fill: #888; @@ -179,6 +183,10 @@ text-anchor:start; } +[dir="rtl"] .node_status_label { + direction: ltr; +} + .port_hovered { stroke: $port-selected-color; fill: $port-selected-color; diff --git a/editor/sass/header.scss b/editor/sass/header.scss index 780c211c4..bafe7e5dd 100644 --- a/editor/sass/header.scss +++ b/editor/sass/header.scss @@ -65,6 +65,12 @@ span.logo { } +[dir="rtl"] span.logo { + float: right; + direction: ltr; + padding-right: 18px; +} + .header-toolbar { padding: 0; margin: 0; @@ -80,6 +86,10 @@ span.logo { } } +[dir="rtl"] .header-toolbar { + float: left; +} + .button { @include disable-selection; } @@ -119,6 +129,10 @@ span.logo { margin: 0; } +[dir="rtl"] #header .button-group > a { + float: right; +} + .deploy-button { background: $deployButton; color: #eee !important; @@ -217,6 +231,11 @@ span.logo { display: inline-block; text-indent: 0px; } + +[dir="rtl"] #header ul.dropdown-menu li a span.menu-label { + text-indent: 20px; +} + #header ul.dropdown-menu li a span.menu-sublabel { color: #aeaeae; font-size: 13px; @@ -224,6 +243,10 @@ span.logo { text-indent: 0px; } +[dir="rtl"] #header ul.dropdown-menu li a span.menu-sublabel { + text-indent: 15px; +} + #header ul.dropdown-menu > li:hover > a, #header ul.dropdown-menu > li:focus > a { background: $headerMenuItemHover !important; @@ -251,6 +274,11 @@ span.logo { display: inline-block; text-indent: 0px; } + +[dir="rtl"] #header ul#btn-deploy-options-submenu li a span.menu-label { + text-indent: 20px; +} + #header ul#btn-deploy-options-submenu li a { padding: 10px 30px; color: #fff; diff --git a/editor/sass/jquery.scss b/editor/sass/jquery.scss index 02356bf4b..cf6cca30a 100644 --- a/editor/sass/jquery.scss +++ b/editor/sass/jquery.scss @@ -49,6 +49,12 @@ .ui-dialog .ui-dialog-title { width: auto; } + +[dir="rtl"] .ui-dialog .ui-dialog-title { + float: right; + text-align: right; +} + .ui-dialog .ui-dialog-titlebar { padding: 10px; background: #f3f3f3; @@ -66,10 +72,19 @@ display: none; } +[dir="rtl"] .ui-dialog-titlebar-close{ + left: 15px; + right: auto; +} + .ui-dialog-buttonset { text-align: right; } +[dir="rtl"] .ui-dialog-buttonset { + text-align: left; +} + .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: none; } @@ -119,6 +134,12 @@ } } +[dir="rtl"] .ui-dialog-buttonset button { + &.leftButton { + float: right; + } +} + .ui-dialog .ui-dialog-buttonpane { padding: .3em 1em .5em 1em; } diff --git a/editor/sass/keyboard.scss b/editor/sass/keyboard.scss index 6c05e5046..786283d29 100644 --- a/editor/sass/keyboard.scss +++ b/editor/sass/keyboard.scss @@ -38,3 +38,15 @@ box-shadow: #999 1px 1px 1px; } +#keyboard-help-dialog-div1, +#keyboard-help-dialog-div2 { + vertical-align: top; + display: inline-block; + box-sizing: border-box; + width:50%; + padding: 10px; +} + +[dir="rtl"] #keyboard-help-dialog-div2 { + padding: 50px; +} diff --git a/editor/sass/palette-editor.scss b/editor/sass/palette-editor.scss index 8565d91b3..ebfafcaa1 100644 --- a/editor/sass/palette-editor.scss +++ b/editor/sass/palette-editor.scss @@ -230,3 +230,80 @@ } } + +[dir="rtl"] #palette-editor { + right: 0px; + text-align: right; + + .palette-editor-toolbar { + text-align: left; + + .button-group { + margin-right: 0px; + margin-left: 10px; + } + } + + .palette-module-button-group { + right: initial; + left:0; + + a { + margin-left: 0px; + margin-right: 5px; + float : left; + } + } + + .palette-module-shade { + left:0; + right:0; + } + + .palette-module-meta { + + .fa { + margin-left: 5px; + margin-right: 0px; + } + } + + .palette-module-updated { + margin-right: 10px; + margin-left: 0px; + } + + .palette-module-link { + margin-right: 5px; + margin-left: 0px; + } + + .palette-module-description { + margin-right: 20px; + margin-left: 0px; + } + + .palette-module-type { + padding-right: 5px; + padding-left: 0px; + } + + .palette-module-type-swatch { + margin-left: 5px; + margin-right: 0px; + } + + .palette-module-set-button-group { + left: 4px; + right: initial; + } + + i.fa.palette-module-node-chevron { + transform: rotate(180deg); + } + .expanded { + i.fa.palette-module-node-chevron { + transform: rotate(90deg); + } + } +} diff --git a/editor/sass/palette.scss b/editor/sass/palette.scss index 988717013..daafff31f 100644 --- a/editor/sass/palette.scss +++ b/editor/sass/palette.scss @@ -28,6 +28,11 @@ transition: width 0.2s ease-in-out; } +[dir="rtl"] #palette { + left: initial; + right: 0px; +} + .palette-expanded { & #palette { width: 380px; @@ -42,6 +47,18 @@ & #palette-editor { display: block !important } } +[dir="rtl"] .palette-expanded { + + & #palette { + width: 380px; + box-shadow: 0 1px 6px rgba(0,0,0,0.1); + } + + & #workspace { + left: 315px !important; + right: 380px !important; + } +} .palette-scroll { position: absolute; @@ -74,7 +91,9 @@ @include component-footer-button; } - +[dir="rtl"] .palette-button { + float: left; +} .palette-category { border-bottom: 1px solid #ccc; } @@ -95,6 +114,11 @@ text-overflow: ellipsis; } + +[dir="rtl"] .palette-header { + text-align: right; +} + .palette-header i { margin: 3px 10px 3px 3px; -webkit-transition: all 0.2s ease-in-out; @@ -104,6 +128,12 @@ -moz-transform: rotate(-90deg); -o-transform: rotate(-90deg); } + +[dir="rtl"] .palette-header i { + margin: 3px 3px 3px 10px; + transform: rotate(90deg); +} + .palette-header i.expanded { -webkit-transform: rotate(0deg); -moz-transform: rotate(0deg); @@ -123,6 +153,10 @@ margin: 4px 28px 4px 0; } +[dir="rtl"] .palette_label_right { + margin: 4px 0 4px 28px; +} + .palette_node { cursor:move; background: #ddd; @@ -177,6 +211,12 @@ border-right: none; border-left: 1px solid rgba(0,0,0,0.1); } +[dir="rtl"] .palette_icon_container_right { + left: 0; + right: auto; + border-left: none; + border-right: 1px solid rgba(0,0,0,0.1); +} .palette_icon { display: inline-block; width: 20px; diff --git a/editor/sass/popover.scss b/editor/sass/popover.scss index 7a9e6bf78..2bbae6523 100644 --- a/editor/sass/popover.scss +++ b/editor/sass/popover.scss @@ -28,6 +28,12 @@ line-height: 1.4em; @include component-shadow; } + [dir="rtl"] .red-ui-popover { + transform: rotateY(180deg); + p { + transform: rotateY(180deg); + } + } .red-ui-popover:after, .red-ui-popover:before { right: 100%; top: 50%; diff --git a/editor/sass/sidebar.scss b/editor/sass/sidebar.scss index 0f782e773..301f32aef 100644 --- a/editor/sass/sidebar.scss +++ b/editor/sass/sidebar.scss @@ -26,6 +26,11 @@ @include component-border; } +[dir="rtl"] #sidebar { + right: auto; + left: 0px; +} + #sidebar.closing { background: #eee; border-color: #900; @@ -52,9 +57,26 @@ cursor: col-resize; } +[dir="rtl"] #sidebar-separator { + left: 315px; + right: auto; +} + .sidebar-closed > #sidebar { display: none; } .sidebar-closed > #sidebar-separator { right: 0px !important; } + +[dir="rtl"] .sidebar-closed > #sidebar-separator { + left: 0px !important; + right: auto !important; +} + .sidebar-closed > #workspace { right: 7px !important; } + +[dir="rtl"] .sidebar-closed > #workspace { + left: 7px !important; + right: 179px !important; +} + .sidebar-closed > #editor-stack { right: 8px !important; } #sidebar .button { @@ -73,6 +95,10 @@ border-bottom: 1px solid $secondary-border-color; } +[dir="rtl"] .sidebar-header { + text-align: left; +} + #sidebar-footer { @include component-footer; } @@ -96,6 +122,11 @@ border-left: none; } +[dir="rtl"] .button-group .sidebar-header-button:not(:first-child) { + border-left: solid 1px; + border-right: none; +} + .sidebar-shade { position: absolute; top:0; diff --git a/editor/sass/tab-config.scss b/editor/sass/tab-config.scss index a38390f86..406eda090 100644 --- a/editor/sass/tab-config.scss +++ b/editor/sass/tab-config.scss @@ -49,6 +49,14 @@ border-bottom-right-radius: 4px; } } +[dir="rtl"] .config_node { + .palette_label { + margin-left: 0px; + margin-right: 8px; + text-align: right; + + } +} .config_node_type { color: #999; text-align: right; @@ -57,11 +65,21 @@ margin-top: 20px; } } +[dir="rtl"] .config_node_type { + text-align: left; + padding-right: 0px; + padding-left: 3px; +} .config_node_none { color: #ddd; text-align:right; padding-right: 3px; } +[dir="rtl"] .config_node_none { + text-align: left; + padding-right: 0px; + padding-left: 3px; +} .config_node_unused { border-color: #aaa; background: #f9f9f9; diff --git a/editor/sass/tab-info.scss b/editor/sass/tab-info.scss index b74b791c4..b21473eff 100644 --- a/editor/sass/tab-info.scss +++ b/editor/sass/tab-info.scss @@ -51,6 +51,13 @@ div.node-info { .node-info-property-header { color: #666; } + +[dir="rtl"] .node-info-property-header { + i{ + transform: rotate(180deg); + } +} + .node-info-property-header:hover, .node-info-property-header:focus { color: #666; diff --git a/editor/sass/tabs.scss b/editor/sass/tabs.scss index 5c2697788..96d63f347 100644 --- a/editor/sass/tabs.scss +++ b/editor/sass/tabs.scss @@ -114,6 +114,22 @@ padding-right: 59px; } } + +[dir="rtl"] .red-ui-tabs { + & ul { + li { + a.red-ui-tab-label { + padding-left: 0px; + padding-right: 12px; + } + } + } + &.red-ui-tabs-add.red-ui-tabs-scrollable { + padding-left: 59px; + padding-right: 21px; + } +} + .red-ui-tab-button { position: absolute; box-sizing: border-box; @@ -137,6 +153,11 @@ } } +[dir="rtl"] .red-ui-tab-button { + right: initial; + left: 0; +} + .red-ui-tab-scroll { width: 21px; top: 0; @@ -160,6 +181,19 @@ // box-shadow: 8px 0px 5px -2px rgba(0,0,0,0.1); } } +[dir="rtl"] ul.red-ui-tabs li a.red-ui-tab-label { + padding-left: 0px; + padding-right: 12px; +} +ul.red-ui-tabs li { + position: relative; +} + +[dir="rtl"] .red-ui-tab-scroll-left { + right: 0; + left: initial; +} + .red-ui-tab-scroll-right { right: 0px; a { @@ -172,6 +206,11 @@ right: 38px; } +[dir="rtl"] .red-ui-tabs.red-ui-tabs-add .red-ui-tab-scroll-right { + right: initial; + left: 38px; +} + .red-ui-tab-icon { margin-left: -8px; margin-right: 3px; @@ -182,6 +221,11 @@ vertical-align: middle; } +[dir="rtl"] .red-ui-tab-icon{ + margin-left: 0; + margin-right: 0; +} + .red-ui-tabs-badges { position: absolute; top:2px; @@ -223,3 +267,9 @@ opacity: 1; } } + +[dir="rtl"] .red-ui-tab-close { + right: initial; + left: 0px; +} + diff --git a/editor/sass/ui/common/editableList.scss b/editor/sass/ui/common/editableList.scss index 9905bee82..0aa310cf6 100644 --- a/editor/sass/ui/common/editableList.scss +++ b/editor/sass/ui/common/editableList.scss @@ -69,3 +69,16 @@ } } + +[dir="rtl"] .red-ui-editableList-container { + li { + .red-ui-editableList-item-handle { + left: auto; + right: 2px; + } + .red-ui-editableList-item-remove { + right: auto; + left: 0px; + } + } +} diff --git a/editor/sass/ui/common/searchBox.scss b/editor/sass/ui/common/searchBox.scss index 28bf0d0da..d89252c16 100644 --- a/editor/sass/ui/common/searchBox.scss +++ b/editor/sass/ui/common/searchBox.scss @@ -68,3 +68,18 @@ border-radius: 4px; } } + +[dir="rtl"] .red-ui-searchBox-container { + input { + text-indent: 6px; + } + i.fa-search { + left: initial; + right: 8px + } + .red-ui-searchBox-resultCount { + left: 18px; + right: initial; + } +} + diff --git a/editor/sass/ui/common/typedInput.scss b/editor/sass/ui/common/typedInput.scss index b2cbcdfde..517398e36 100644 --- a/editor/sass/ui/common/typedInput.scss +++ b/editor/sass/ui/common/typedInput.scss @@ -122,6 +122,27 @@ } } } + +[dir="rtl"] .red-ui-typedInput-container { + a { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + + span { + padding: 0 5px 0 1px; + } + } + a.red-ui-typedInput-option-trigger { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + padding: 0 0 0 5px; + } +} + .red-ui-typedInput-options { @include component-shadow; position: absolute; diff --git a/editor/sass/workspace.scss b/editor/sass/workspace.scss index 0d27a97f1..008e072fe 100644 --- a/editor/sass/workspace.scss +++ b/editor/sass/workspace.scss @@ -27,6 +27,11 @@ transition: right 0.2s ease; } +[dir="rtl"] #chart { + direction: rtl; + text-align: right; +} + #chart:focus { outline: none; } @@ -44,10 +49,54 @@ } +[dir="rtl"] #workspace { + left: 322px; + right: 179px; +} + .workspace-footer-button { @include component-footer-button; } +#workspace-tabs { + margin-right: 35px; +} + +[dir="rtl"] #workspace-tabs { + margin-left: 35px; + margin-right: initial; +} + +#workspace-add-tab { + position: absolute; + box-sizing: border-box; + top: 0; + right: 0; + height: 35px; + width: 35px; + background: #fff; + border-bottom: 1px solid $primary-border-color; +} + +[dir="rtl"] #workspace-add-tab { + left: 0px; + right: initial; +} + +#btn-workspace-add-tab { + @include workspace-button; + line-height: 32px; + height: 32px; + width: 32px; + margin-top: 3px; + margin-right:3px; + border: 1px solid $primary-border-color; +} + #workspace-footer { @include component-footer; } + +[dir="rtl"] #workspace-footer { + text-align: left; +} diff --git a/editor/sass/workspaceToolbar.scss b/editor/sass/workspaceToolbar.scss index 1bee0d510..fdd1f940f 100644 --- a/editor/sass/workspaceToolbar.scss +++ b/editor/sass/workspaceToolbar.scss @@ -74,3 +74,35 @@ } } + +[dir="rtl"] #workspace-toolbar { + .button { + margin-right: 0px; + } + .button-group { + &:not(.spinner-group) { + .button:not(:first-child) { + border-right: none; + border-left: solid 0.25px; + } + } + } +} + +.workspace-subflow-label { + margin-left: 5px; + } + + [dir="rtl"] .workspace-subflow-label { + margin-right: 15px; + margin-top: 3px; + float: right; + } + +[dir="rtl"] .subflow-toolbar { + float: right; +} + +[dir="rtl"] #workspace-subflow-delete { + margin-right: 15px !important; +} diff --git a/editor/templates/index.mst b/editor/templates/index.mst index 6fa473c93..4aa202c22 100644 --- a/editor/templates/index.mst +++ b/editor/templates/index.mst @@ -87,13 +87,13 @@
    -
    -
      +
      +
        -
          +
            -
            +
            @@ -164,5 +164,30 @@ + diff --git a/nodes/core/core/25-catch.html b/nodes/core/core/25-catch.html index 87c87c9cc..3196c84e0 100644 --- a/nodes/core/core/25-catch.html +++ b/nodes/core/core/25-catch.html @@ -27,7 +27,7 @@
            - +
              @@ -85,6 +85,17 @@ #node-input-catch-target-container li:hover .node-input-target-node-sublabel { background: #f0f0f0; } +#node-input-catch-target-sort-type { + position: absolute; + right: 10px; + width: 50px; + display: inline-block; + text-align: right; +} +[dir="rtl"] #node-input-catch-target-sort-type { + right: auto; + left: 0px; +} .node-input-target-node-sublabel { position:absolute; right: 0px; @@ -93,6 +104,10 @@ font-size: 0.8em; background: #fbfbfb; } +[dir="rtl"] .node-input-target-node-sublabel { + right: auto; + left: 0; +} + + diff --git a/nodes/core/core/89-delay.html b/nodes/core/core/89-delay.html index e46f03452..3a66a192f 100644 --- a/nodes/core/core/89-delay.html +++ b/nodes/core/core/89-delay.html @@ -50,7 +50,7 @@
              -
              +
              @@ -241,3 +241,12 @@ } }); + diff --git a/nodes/core/core/89-trigger.html b/nodes/core/core/89-trigger.html index e70fe49bf..f3b226084 100644 --- a/nodes/core/core/89-trigger.html +++ b/nodes/core/core/89-trigger.html @@ -48,7 +48,7 @@
              -
              +
              • @@ -171,3 +171,13 @@ } }); + diff --git a/nodes/core/io/10-mqtt.html b/nodes/core/io/10-mqtt.html index b3d4baae4..309fb2089 100644 --- a/nodes/core/io/10-mqtt.html +++ b/nodes/core/io/10-mqtt.html @@ -148,7 +148,7 @@
                - +
                @@ -165,7 +165,7 @@
                - +
                @@ -357,3 +357,25 @@ } }); + + diff --git a/nodes/core/logic/10-switch.html b/nodes/core/logic/10-switch.html index 0d666f514..a0e5edf0a 100644 --- a/nodes/core/logic/10-switch.html +++ b/nodes/core/logic/10-switch.html @@ -130,7 +130,8 @@ var btwnValueField = $('',{class:"node-input-rule-btwn-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'num',types:['msg','flow','global','str','num',previousValueType]}); var btwnAndLabel = $('',{class:"node-input-rule-btwn-label"}).text(" "+andLabel+" ").appendTo(row3); var btwnValue2Field = $('',{class:"node-input-rule-btwn-value2",type:"text",style:"margin-left:2px;"}).appendTo(row3).typedInput({default:'num',types:['msg','flow','global','str','num',previousValueType]}); - var finalspan = $('',{style:"float: right;margin-top: 6px;"}).appendTo(row); + // reverse float property in case of right directionality + var finalspan = $('',{style:"float: "+RED.bidi.componentPos.right+";margin-top: 6px;"}).appendTo(row); finalspan.append(' → '+(i+1)+' '); var caseSensitive = $('',{id:"node-input-rule-case-"+i,class:"node-input-rule-case",type:"checkbox",style:"width:auto;vertical-align:top"}).appendTo(row2); $('