diff --git a/notebook/nbconvert/handlers.py b/notebook/nbconvert/handlers.py
index 4dd5352cc6..648c9827f8 100644
--- a/notebook/nbconvert/handlers.py
+++ b/notebook/nbconvert/handlers.py
@@ -58,12 +58,12 @@ def get_exporter(format, **kwargs):
"""get an exporter, raising appropriate errors"""
# if this fails, will raise 500
try:
- from nbconvert.exporters.export import exporter_map
+ from nbconvert.exporters.base import get_exporter
except ImportError as e:
raise web.HTTPError(500, "Could not import nbconvert: %s" % e)
try:
- Exporter = exporter_map[format]
+ Exporter = get_exporter(format)
except KeyError:
# should this be 400?
raise web.HTTPError(404, u"No exporter for format: %s" % format)
diff --git a/notebook/notebookapp.py b/notebook/notebookapp.py
index 132aa4ddf2..97599f276f 100755
--- a/notebook/notebookapp.py
+++ b/notebook/notebookapp.py
@@ -389,21 +389,31 @@ class NbserverListApp(JupyterApp):
description=_("List currently running notebook servers.")
flags = dict(
+ jsonlist=({'NbserverListApp': {'jsonlist': True}},
+ _("Produce machine-readable JSON list output.")),
json=({'NbserverListApp': {'json': True}},
- _("Produce machine-readable JSON output.")),
+ _("Produce machine-readable JSON object on each line of output.")),
)
+ jsonlist = Bool(False, config=True,
+ help=_("If True, the output will be a JSON list of objects, one per "
+ "active notebook server, each with the details from the "
+ "relevant server info file."))
json = Bool(False, config=True,
help=_("If True, each line of output will be a JSON object with the "
- "details from the server info file."))
+ "details from the server info file. For a JSON list output, "
+ "see the NbserverListApp.jsonlist configuration value"))
def start(self):
- if not self.json:
- print(_("Currently running servers:"))
- for serverinfo in list_running_servers(self.runtime_dir):
- if self.json:
+ serverinfo_list = list(list_running_servers(self.runtime_dir))
+ if self.jsonlist:
+ print(json.dumps(serverinfo_list, indent=2))
+ elif self.json:
+ for serverinfo in serverinfo_list:
print(json.dumps(serverinfo))
- else:
+ else:
+ print("Currently running servers:")
+ for serverinfo in serverinfo_list:
url = serverinfo['url']
if serverinfo.get('token'):
url = url + '?token=%s' % serverinfo['token']
diff --git a/notebook/static/auth/js/main.js b/notebook/static/auth/js/main.js
index 7be82388ed..68d7871c58 100644
--- a/notebook/static/auth/js/main.js
+++ b/notebook/static/auth/js/main.js
@@ -1,7 +1,10 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
-define(['./loginmain', './logoutmain'], function (login_main, logout_main) {
+define(['./loginmain', './logoutmain', 'bidi/bidi'], function (login_main, logout_main, bidi) {
+ if(bidi.isMirroringEnabled()){
+ $("body").attr("dir","rtl");
+ }
return {
login_main: login_main,
logout_main: logout_main
diff --git a/notebook/static/auth/less/login.less b/notebook/static/auth/less/login.less
index d21a3a1c74..8a4ce3ffcb 100644
--- a/notebook/static/auth/less/login.less
+++ b/notebook/static/auth/less/login.less
@@ -3,4 +3,21 @@
display: inline-block;
// pull the lower margin back
margin-bottom: -4px;
-}
\ No newline at end of file
+}
+
+[dir="rtl"] .center-nav {
+ form.pull-left {
+ .pull-right();
+ }
+ .navbar-text {
+ float: right;
+ }
+}
+
+[dir="rtl"] .navbar-inner {
+ text-align: right;
+}
+
+[dir="rtl"] div.text-left {
+ .text-right();
+}
diff --git a/notebook/static/base/less/page.less b/notebook/static/base/less/page.less
index c300591d2e..85e7f825a9 100644
--- a/notebook/static/base/less/page.less
+++ b/notebook/static/base/less/page.less
@@ -63,6 +63,15 @@ body > #header {
padding-bottom: (@navbar-height - @logo_height) / 2;
}
+[dir="rtl"] #ipython_notebook {
+ margin-right: 10px;
+ margin-left: 0;
+}
+
+[dir="rtl"] #ipython_notebook.pull-left {
+ .pull-right();
+}
+
.flex-spacer {
flex: 1;
}
@@ -107,7 +116,11 @@ span#kernel_logo_widget {
}
span#login_widget {
-
+ float: right;
+}
+
+[dir="rtl"] span#login_widget {
+ float: left;
}
span#login_widget > .button,
diff --git a/notebook/static/bidi/bidi.js b/notebook/static/bidi/bidi.js
new file mode 100644
index 0000000000..bd7118d147
--- /dev/null
+++ b/notebook/static/bidi/bidi.js
@@ -0,0 +1,56 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+define([
+ 'bidi/numericshaping',
+], function (numericshaping){
+ "use strict";
+
+ var shaperType="";
+ var textDir="";
+
+ var _uiLang= function (){
+ return navigator.language.toLowerCase();
+ };
+
+ var _loadLocale = function () {
+ if(_isMirroringEnabled()){
+ $("body").attr("dir","rtl");
+ }
+ requirejs(['components/moment/locale/'+_uiLang()], function (err){
+ console.warn("Error loading the required locale");
+ console.warn(err);
+ });
+ shaperType= _uiLang()=='ar'? "national" : "defaultNumeral";
+ };
+
+ var _isMirroringEnabled= function() {
+ return (new RegExp("^(ar|he)").test(_uiLang()));
+ };
+
+ /**
+ * NS : for digit Shaping.
+ * BTD : for future work in case of Base Text Direction Addition.
+ */
+ /*var _flags= {
+ NS: 1,
+ BTD : 2
+ };*/
+
+ /**
+ * @param value : the string to apply the bidi-support on it.
+ * @param flag :indicates the type of bidi-support (Numeric-shaping ,Base-text-dir ).
+ */
+ var _applyBidi = function (value /*, flag*/) {
+ value = numericshaping.shapeNumerals(value, shaperType);
+ return value;
+ };
+
+ var bidi = {
+ applyBidi : _applyBidi,
+ isMirroringEnabled : _isMirroringEnabled,
+ loadLocale : _loadLocale,
+ };
+
+ return bidi;
+});
diff --git a/notebook/static/bidi/numericshaping.js b/notebook/static/bidi/numericshaping.js
new file mode 100644
index 0000000000..d78ec0d0df
--- /dev/null
+++ b/notebook/static/bidi/numericshaping.js
@@ -0,0 +1,42 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+define([],
+ function(bidi) {
+ "use strict";
+
+ 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;
+
+ var shape = function(text, shaperType) {
+ text = text.toString();
+ if (!text) {
+ return text;
+ }
+ switch (shaperType) {
+ case "defaultNumeral":
+ return _shapeEuropean(text);
+ case "national":
+ return _shapeArabic(text);
+ default:
+ return text;
+ }
+ };
+
+ var _shapeEuropean = function(text) {
+ return text.replace(/[\u0660-\u0669]/g, function(c) {
+ return c.charCodeAt(0) - 1632;
+ });
+ };
+
+ var _shapeArabic = function(text) {
+ return text.replace(/[0-9]/g, function(c) {
+ return String.fromCharCode(parseInt(c) + 1632);
+ });
+ };
+
+ var numericshaping = {
+ shapeNumerals : shape
+ };
+
+ return numericshaping;
+});
diff --git a/notebook/static/custom/custom.css b/notebook/static/custom/custom.css
index 9f4abdaa49..b8367c9135 100644
--- a/notebook/static/custom/custom.css
+++ b/notebook/static/custom/custom.css
@@ -4,4 +4,18 @@ Placeholder for custom user CSS
mainly to be overridden in profile/static/custom/custom.css
This will always be an empty file in IPython
-*/
\ No newline at end of file
+*/
+
+/*for the error , connecting & renaming window*/
+
+[dir="rtl"] .modal-footer {
+ text-align : left !important;
+}
+
+[dir="rtl"] .close {
+ float : left;
+}
+
+[dir="rtl"] .fa-step-forward::before {
+ content: "\f048";
+}
diff --git a/notebook/static/edit/js/main.js b/notebook/static/edit/js/main.js
index 006d20cb6e..9b2a2cb682 100644
--- a/notebook/static/edit/js/main.js
+++ b/notebook/static/edit/js/main.js
@@ -13,6 +13,7 @@ require([
'edit/js/menubar',
'edit/js/savewidget',
'edit/js/notificationarea',
+ 'bidi/bidi',
], function(
$,
contents_service,
@@ -24,12 +25,14 @@ require([
editmod,
menubar,
savewidget,
- notificationarea
+ notificationarea,
+ bidi
){
"use strict";
try {
requirejs(['custom/custom'], function() {});
+ bidi.loadLocale();
} catch(err) {
console.log("Error loading custom.js from edition service. Continuing and logging");
console.warn(err);
diff --git a/notebook/static/edit/js/savewidget.js b/notebook/static/edit/js/savewidget.js
index 7df4ed4d64..6154100998 100644
--- a/notebook/static/edit/js/savewidget.js
+++ b/notebook/static/edit/js/savewidget.js
@@ -7,9 +7,10 @@ define([
'base/js/dialog',
'base/js/keyboard',
'moment',
-], function($, utils, dialog, keyboard, moment) {
+ 'bidi/bidi',
+], function($, utils, dialog, keyboard, moment, bidi) {
"use strict";
-
+
var SaveWidget = function (selector, options) {
this.editor = undefined;
this.selector = selector;
@@ -113,6 +114,7 @@ define([
SaveWidget.prototype.update_filename = function (filename) {
+ filename = bidi.applyBidi(filename);
this.element.find('span.filename').text(filename);
};
@@ -151,7 +153,7 @@ define([
if (!this._last_modified) {
el.text('').attr('title', 'never saved');
return;
- }
+ }
var chkd = moment(this._last_modified);
var long_date = chkd.format('llll');
var human_date;
diff --git a/notebook/static/notebook/js/main.js b/notebook/static/notebook/js/main.js
index fec68fd708..2e64d3cdc8 100644
--- a/notebook/static/notebook/js/main.js
+++ b/notebook/static/notebook/js/main.js
@@ -42,7 +42,8 @@ require([
'codemirror/lib/codemirror',
'notebook/js/about',
'notebook/js/searchandreplace',
- 'notebook/js/clipboard'
+ 'notebook/js/clipboard',
+ 'bidi/bidi'
], function(
$,
contents_service,
@@ -65,7 +66,8 @@ require([
CodeMirror,
about,
searchandreplace,
- clipboard
+ clipboard,
+ bidi
) {
"use strict";
@@ -74,6 +76,7 @@ require([
try{
requirejs(['custom/custom'], function() {});
+ bidi.loadLocale();
} catch(err) {
console.log("Error processing custom.js. Logging and continuing");
console.warn(err);
diff --git a/notebook/static/notebook/js/outputarea.js b/notebook/static/notebook/js/outputarea.js
index ef83fea5b6..872c1987f4 100644
--- a/notebook/static/notebook/js/outputarea.js
+++ b/notebook/static/notebook/js/outputarea.js
@@ -77,7 +77,6 @@ define([
OutputArea.prototype.style = function () {
this.collapse_button.hide();
- this.prompt_overlay.hide();
this.wrapper.addClass('output_wrapper');
this.element.addClass('output');
@@ -263,6 +262,7 @@ define([
var MIME_SVG = 'image/svg+xml';
var MIME_PNG = 'image/png';
var MIME_JPEG = 'image/jpeg';
+ var MIME_GIF = 'image/gif';
var MIME_PDF = 'application/pdf';
var MIME_TEXT = 'text/plain';
@@ -275,6 +275,7 @@ define([
MIME_SVG,
MIME_PNG,
MIME_JPEG,
+ MIME_GIF,
MIME_PDF,
MIME_TEXT,
];
@@ -660,6 +661,7 @@ define([
OutputArea.safe_outputs[MIME_LATEX] = true;
OutputArea.safe_outputs[MIME_PNG] = true;
OutputArea.safe_outputs[MIME_JPEG] = true;
+ OutputArea.safe_outputs[MIME_GIF] = true;
OutputArea.prototype.append_mime_type = function (json, element, handle_inserted) {
for (var i=0; i < OutputArea.display_order.length; i++) {
@@ -683,7 +685,7 @@ define([
// callback, if the mime type is something other we must call the
// inserted callback only when the element is actually inserted
// into the DOM. Use a timeout of 0 to do this.
- if ([MIME_PNG, MIME_JPEG].indexOf(type) < 0 && handle_inserted !== undefined) {
+ if ([MIME_PNG, MIME_JPEG, MIME_GIF].indexOf(type) < 0 && handle_inserted !== undefined) {
setTimeout(handle_inserted, 0);
}
this.events.trigger('output_appended.OutputArea', [type, value, md, toinsert]);
@@ -822,7 +824,7 @@ define([
});
}
img[0].src = 'data:image/png;base64,'+ png;
- set_width_height(img, md, MIME_PNG);
+ set_width_height(img, md, type);
dblclick_to_reset_size(img);
toinsert.append(img);
element.append(toinsert);
@@ -840,7 +842,24 @@ define([
});
}
img[0].src = 'data:image/jpeg;base64,'+ jpeg;
- set_width_height(img, md, MIME_JPEG);
+ set_width_height(img, md, type);
+ dblclick_to_reset_size(img);
+ toinsert.append(img);
+ element.append(toinsert);
+ return toinsert;
+ };
+
+ var append_gif = function (gif, md, element, handle_inserted) {
+ var type = MIME_GIF;
+ var toinsert = this.create_output_subarea(md, "output_gif", type);
+ var img = $("");
+ if (handle_inserted !== undefined) {
+ img.on('load', function(){
+ handle_inserted(img);
+ });
+ }
+ img[0].src = 'data:image/gif;base64,'+ gif;
+ set_width_height(img, md, type);
dblclick_to_reset_size(img);
toinsert.append(img);
element.append(toinsert);
@@ -1073,6 +1092,7 @@ define([
MIME_SVG,
MIME_PNG,
MIME_JPEG,
+ MIME_GIF,
MIME_PDF,
MIME_TEXT
];
@@ -1084,6 +1104,7 @@ define([
OutputArea.append_map[MIME_SVG] = append_svg;
OutputArea.append_map[MIME_PNG] = append_png;
OutputArea.append_map[MIME_JPEG] = append_jpeg;
+ OutputArea.append_map[MIME_GIF] = append_gif;
OutputArea.append_map[MIME_LATEX] = append_latex;
OutputArea.append_map[MIME_JAVASCRIPT] = append_javascript;
OutputArea.append_map[MIME_PDF] = append_pdf;
diff --git a/notebook/static/notebook/js/savewidget.js b/notebook/static/notebook/js/savewidget.js
index 141d624fd7..39c64a188a 100644
--- a/notebook/static/notebook/js/savewidget.js
+++ b/notebook/static/notebook/js/savewidget.js
@@ -8,7 +8,8 @@ define([
'base/js/dialog',
'base/js/keyboard',
'moment',
-], function($, utils, i18n, dialog, keyboard, moment) {
+ 'bidi/bidi',
+], function($, utils, i18n, dialog, keyboard, moment, bidi) {
"use strict";
var SaveWidget = function (selector, options) {
@@ -133,6 +134,7 @@ define([
SaveWidget.prototype.update_notebook_name = function () {
var nbname = this.notebook.get_notebook_name();
+ nbname = bidi.applyBidi(nbname);
this.element.find('span.filename').text(nbname);
};
@@ -186,10 +188,11 @@ define([
// less than 24 hours old, use relative date
human_date = chkd.fromNow();
} else {
- // otherwise show calendar
+ // otherwise show calendar
// at hh,mm,ss
human_date = chkd.calendar();
}
+
el.text(i18n.msg.sprintf(i18n.msg._('Last Checkpoint: %s'),human_date)).attr('title', long_date);
};
diff --git a/notebook/static/notebook/less/commandpalette.less b/notebook/static/notebook/less/commandpalette.less
index 28e738660f..7c4069ed11 100644
--- a/notebook/static/notebook/less/commandpalette.less
+++ b/notebook/static/notebook/less/commandpalette.less
@@ -3,6 +3,11 @@ ul.typeahead-list i{
width: 18px;
}
+[dir="rtl"] ul.typeahead-list i {
+ margin-left: 0;
+ margin-right: -10px;
+}
+
ul.typeahead-list {
max-height: 80vh;
overflow:auto;
@@ -14,6 +19,14 @@ ul.typeahead-list {
}
}
+ul.typeahead-list & > li > a.pull-right {
+ .pull-left();
+}
+
+[dir="rtl"] .typeahead-list {
+ text-align : right;
+}
+
.cmd-palette {
& .modal-body{
padding: 7px;
@@ -33,6 +46,14 @@ ul.typeahead-list {
color: transparent;
}
+[dir="rtl"] .no-shortcut.pull-right{
+ .pull-left();
+}
+
+[dir="rtl"] .command-shortcut.pull-right{
+ .pull-left();
+}
+
.command-shortcut:before{
content:"(command mode)";
padding-right:3px;
@@ -44,3 +65,7 @@ ul.typeahead-list {
padding-right:3px;
color:@gray-light;
}
+
+[dir="rtl"] .edit-shortcut.pull-right {
+ .pull-left();
+}
diff --git a/notebook/static/notebook/less/kernelselector.less b/notebook/static/notebook/less/kernelselector.less
index fab2cf7458..9dc98d2d4f 100644
--- a/notebook/static/notebook/less/kernelselector.less
+++ b/notebook/static/notebook/less/kernelselector.less
@@ -6,3 +6,7 @@
height: 32px;
}
}
+
+[dir="rtl"] #kernel_logo_widget {
+ .pull-left();
+}
diff --git a/notebook/static/notebook/less/menubar.less b/notebook/static/notebook/less/menubar.less
index 7f776c0355..414557aee4 100644
--- a/notebook/static/notebook/less/menubar.less
+++ b/notebook/static/notebook/less/menubar.less
@@ -20,6 +20,39 @@
}
+[dir="rtl"] #menubar {
+ .navbar-toggle {
+ float: right;
+ }
+}
+
+[dir="rtl"] #menubar {
+ .navbar-collapse {
+ clear: right;
+ }
+ .navbar-nav {
+ float : right;
+ }
+ .nav {
+ padding-right : 0px;
+ }
+ .navbar-nav > li {
+ float: right;
+ }
+ .navbar-right {
+ float : left !important;
+ }
+}
+
+[dir="rtl"] ul.dropdown-menu {
+ text-align: right;
+ left : auto;
+}
+
+[dir="rtl"] ul#new-menu.dropdown-menu {
+ right : auto;
+ left: 0;
+}
.nav-wrapper {
border-bottom: 1px solid @navbar-default-border;
}
@@ -29,6 +62,10 @@ i.menu-icon {
padding-top: 4px;
}
+[dir="rtl"] i.menu-icon.pull-right {
+ .pull-left();
+}
+
ul#help_menu li a{
overflow: hidden;
padding-right: 2.2em;
@@ -37,6 +74,18 @@ ul#help_menu li a{
}
}
+[dir="rtl"] ul#help_menu li a{
+ padding-left : 2.2em;
+ i {
+ margin-right: 0;
+ margin-left : -1.2em;
+ }
+
+ i.pull-right {
+ .pull-left();
+ }
+}
+
// Make sub menus work in BS3.
// Credit: http://www.bootply.com/86684
.dropdown-submenu {
@@ -50,6 +99,11 @@ ul#help_menu li a{
margin-left: -1px;
}
+[dir="rtl"] .dropdown-submenu>.dropdown-menu {
+ right:100%;
+ margin-right: -1px;
+}
+
// arrow that indicate presence of submenu
.dropdown-submenu:hover>.dropdown-menu {
display: block;
@@ -65,6 +119,13 @@ ul#help_menu li a{
margin-right: -10px;
}
+[dir="rtl"] .dropdown-submenu>a:after {
+ float: left;
+ content: @fa-var-caret-left;
+ margin-right : 0;
+ margin-left : -10px;
+}
+
.dropdown-submenu:hover>a:after {
color: @dropdown-link-hover-color;
}
diff --git a/notebook/static/notebook/less/notificationarea.less b/notebook/static/notebook/less/notificationarea.less
index bfbf5b73f6..8f8b7566c9 100644
--- a/notebook/static/notebook/less/notificationarea.less
+++ b/notebook/static/notebook/less/notificationarea.less
@@ -3,6 +3,10 @@
z-index: 10;
}
+[dir="rtl"] #notification_area {
+ .pull-left();
+}
+
.indicator_area {
.pull-right();
color: @navbar-default-link-color;
@@ -14,6 +18,10 @@
width: auto;
}
+[dir="rtl"] .indicator_area {
+ .pull-left();
+}
+
#kernel_indicator {
.indicator_area();
@@ -25,11 +33,21 @@
}
}
+[dir="rtl"] #kernel_indicator {
+ .pull-left();
+ border-left: 0;
+ border-right : 1px solid;
+}
+
#modal_indicator {
.pull-right();
.indicator_area();
}
+[dir="rtl"] #modal_indicator {
+ .pull-left();
+}
+
#readonly-indicator {
.pull-right();
.indicator_area();
diff --git a/notebook/static/notebook/less/renderedhtml.less b/notebook/static/notebook/less/renderedhtml.less
index 73ecd2defb..34b085dcb5 100644
--- a/notebook/static/notebook/less/renderedhtml.less
+++ b/notebook/static/notebook/less/renderedhtml.less
@@ -130,3 +130,10 @@
.alert {margin-bottom: initial;}
* + .alert {margin-top: 1em;}
}
+
+[dir="rtl"] .rendered_html {
+ p {
+ text-align : right;
+ }
+}
+
diff --git a/notebook/static/notebook/less/savewidget.less b/notebook/static/notebook/less/savewidget.less
index 13f76b4d4a..74b9d04bb0 100644
--- a/notebook/static/notebook/less/savewidget.less
+++ b/notebook/static/notebook/less/savewidget.less
@@ -25,6 +25,17 @@ span.save_widget {
}
}
+[dir="rtl"] span.save_widget.pull-left {
+ .pull-right();
+}
+
+[dir="rtl"] span.save_widget {
+ span.filename {
+ margin-left : 0;
+ margin-right : @padding-large-horizontal;
+ }
+}
+
span.checkpoint_status, span.autosave_status {
font-size: small;
white-space: nowrap;
diff --git a/notebook/static/notebook/less/toolbar.less b/notebook/static/notebook/less/toolbar.less
index af074b445c..d5e7d5b529 100644
--- a/notebook/static/notebook/less/toolbar.less
+++ b/notebook/static/notebook/less/toolbar.less
@@ -55,6 +55,9 @@
height: @btn_small_height;
}
+[dir="rtl"] .btn-group > .btn, .btn-group-vertical > .btn {
+ float: right;
+}
// highlight the new menu where celltoolbar is
.pulse, .dropdown-menu > li > a.pulse, li.pulse > a.dropdown-toggle, li.pulse.open > a.dropdown-toggle {
diff --git a/notebook/static/tree/js/main.js b/notebook/static/tree/js/main.js
index 40580c2f32..44cb7e2008 100644
--- a/notebook/static/tree/js/main.js
+++ b/notebook/static/tree/js/main.js
@@ -35,6 +35,7 @@ require([
'tree/js/terminallist',
'tree/js/newnotebook',
'auth/js/loginwidget',
+ 'bidi/bidi',
], function(
$,
contents_service,
@@ -49,10 +50,13 @@ require([
kernellist,
terminallist,
newnotebook,
- loginwidget){
+ loginwidget,
+ bidi){
"use strict";
+
try{
requirejs(['custom/custom'], function() {});
+ bidi.loadLocale();
} catch(err) {
console.log("Error loading custom.js from tree service. Continuing and logging");
console.warn(err);
diff --git a/notebook/static/tree/js/notebooklist.js b/notebook/static/tree/js/notebooklist.js
index 562ef1fe81..49e73b7206 100644
--- a/notebook/static/tree/js/notebooklist.js
+++ b/notebook/static/tree/js/notebooklist.js
@@ -9,8 +9,9 @@ define([
'base/js/dialog',
'base/js/events',
'base/js/keyboard',
- 'moment'
-], function($, IPython, utils, i18n, dialog, events, keyboard, moment) {
+ 'moment',
+ 'bidi/bidi'
+], function($, IPython, utils, i18n, dialog, events, keyboard, moment, bidi) {
"use strict";
var extension = function(path){
@@ -702,6 +703,7 @@ define([
select_all.data('indeterminate', true);
}
// Update total counter
+ checked = bidi.applyBidi(checked);
$('#counter-select-all').html(checked===0 ? ' ' : checked);
// If at aleast on item is selected, hide the selection instructions.
@@ -714,12 +716,11 @@ define([
NotebookList.prototype.add_link = function (model, item) {
var running = (model.type === 'notebook' && this.sessions[model.path] !== undefined);
-
- item.data('name', model.name);
+ item.data('name',model.name);
item.data('path', model.path);
item.data('modified', model.last_modified);
item.data('type', model.type);
- item.find(".item_name").text(model.name);
+ item.find(".item_name").text(bidi.applyBidi(model.name));
var icon = NotebookList.icons[model.type];
if (running) {
icon = 'running_' + icon;
diff --git a/notebook/static/tree/js/sessionlist.js b/notebook/static/tree/js/sessionlist.js
index b850ef64b0..031fa7ab08 100644
--- a/notebook/static/tree/js/sessionlist.js
+++ b/notebook/static/tree/js/sessionlist.js
@@ -4,9 +4,11 @@
define([
'jquery',
'base/js/utils',
-], function($, utils) {
+ 'bidi/bidi',
+], function($, utils, bidi) {
"use strict";
+ var isRTL = bidi.isMirroringEnabled();
var SesssionList = function (options) {
/**
* Constructor
@@ -36,7 +38,7 @@ define([
// to do the animation (borderSpacing).
$icon.animate({ borderSpacing: 90 }, {
step: function(now,fx) {
- $icon.css('transform','rotate(-' + now + 'deg)');
+ isRTL ? $icon.css('transform','rotate(' + now + 'deg)') : $icon.css('transform','rotate(-' + now + 'deg)');
}
}, 250);
} else {
@@ -44,7 +46,7 @@ define([
// See comment above.
$icon.animate({ borderSpacing: 0 }, {
step: function(now,fx) {
- $icon.css('transform','rotate(-' + now + 'deg)');
+ isRTL ? $icon.css('transform','rotate(' + now + 'deg)') : $icon.css('transform','rotate(-' + now + 'deg)');
}
}, 250);
}
diff --git a/notebook/static/tree/less/tree.less b/notebook/static/tree/less/tree.less
index faebeaf623..518dc72a67 100644
--- a/notebook/static/tree/less/tree.less
+++ b/notebook/static/tree/less/tree.less
@@ -25,6 +25,14 @@ ul#tabs a {
padding-bottom: @dashboard_tb_pad;
}
+[dir="rtl"] ul#tabs.nav-tabs > li {
+ float : right;
+}
+
+[dir="rtl"] ul#tabs.nav.nav-tabs {
+ padding-right: 0;
+}
+
ul.breadcrumb {
a:focus, a:hover {
text-decoration: none;
@@ -48,6 +56,15 @@ ul.breadcrumb {
}
}
+[dir="rtl"] .list_toolbar {
+ .tree-buttons .pull-right {
+ .pull-left();
+ }
+ .col-sm-4 , .col-sm-8 {
+ float : right;
+ }
+}
+
.dynamic-buttons {
padding-top: @dashboard_tb_pad - 1px;
display: inline-block;
@@ -121,6 +138,13 @@ ul.breadcrumb {
}
}
+[dir="rtl"] .list_item>div {
+
+ input {
+ margin-right : 0;
+ }
+}
+
.new-file input[type=checkbox] {
visibility: hidden;
}
@@ -144,6 +168,10 @@ ul.breadcrumb {
margin-left: @dashboard_lr_pad;
}
+[dir="rtl"] .item_modified.pull-right{
+ .pull-left();
+}
+
.item_buttons {
line-height: 1em;
.btn-toolbar();
@@ -162,6 +190,17 @@ ul.breadcrumb {
}
}
+[dir="rtl"] .item_buttons.pull-right {
+ .pull-left();
+}
+
+[dir="rtl"] .item_buttons {
+ .kernel-name {
+ margin-left : @dashboard_lr_pad;
+ float : right;
+ }
+}
+
.toolbar_info {
height: @btn_small_height;
line-height: @btn_small_height;
@@ -198,6 +237,10 @@ ul.breadcrumb {
padding-left: @dashboard_lr_pad;
}
+[dir="rtl"] .sort_button.pull-right {
+ .pull-left();
+}
+
#tree-selector {
padding-right: 0px;
}
@@ -206,11 +249,19 @@ ul.breadcrumb {
min-width: 50px;
}
+[dir="rtl"] #button-select-all.btn {
+ float : right ;
+}
+
#select-all {
margin-left: @dashboard_lr_pad;
margin-right: 2px;
}
+[dir="rtl"] #select-all.pull-left {
+ .pull-right();
+}
+
.menu_icon {
margin-right: 2px;
}