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); $('