Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bidi support #2357

Merged
merged 20 commits into from Sep 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions notebook/nbconvert/handlers.py
Expand Up @@ -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)
Expand Down
24 changes: 17 additions & 7 deletions notebook/notebookapp.py
Expand Up @@ -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']
Expand Down
5 changes: 4 additions & 1 deletion 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
Expand Down
19 changes: 18 additions & 1 deletion notebook/static/auth/less/login.less
Expand Up @@ -3,4 +3,21 @@
display: inline-block;
// pull the lower margin back
margin-bottom: -4px;
}
}

[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();
}
15 changes: 14 additions & 1 deletion notebook/static/base/less/page.less
Expand Up @@ -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;
}
Expand Down Expand Up @@ -107,7 +116,11 @@ span#kernel_logo_widget {
}

span#login_widget {

float: right;
}

[dir="rtl"] span#login_widget {
float: left;
}

span#login_widget > .button,
Expand Down
56 changes: 56 additions & 0 deletions 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){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to special case en and en-us since the files are not there and are the builtins from moment: moment/moment#2081

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you already took care of it! 👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah I should have noted that again here. Good to go now.

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;
});
42 changes: 42 additions & 0 deletions 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;
});
16 changes: 15 additions & 1 deletion notebook/static/custom/custom.css
Expand Up @@ -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
*/
*/

/*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";
}
5 changes: 4 additions & 1 deletion notebook/static/edit/js/main.js
Expand Up @@ -13,6 +13,7 @@ require([
'edit/js/menubar',
'edit/js/savewidget',
'edit/js/notificationarea',
'bidi/bidi',
], function(
$,
contents_service,
Expand All @@ -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);
Expand Down
8 changes: 5 additions & 3 deletions notebook/static/edit/js/savewidget.js
Expand Up @@ -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;
Expand Down Expand Up @@ -113,6 +114,7 @@ define([


SaveWidget.prototype.update_filename = function (filename) {
filename = bidi.applyBidi(filename);
this.element.find('span.filename').text(filename);
};

Expand Down Expand Up @@ -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;
Expand Down
7 changes: 5 additions & 2 deletions notebook/static/notebook/js/main.js
Expand Up @@ -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,
Expand All @@ -65,7 +66,8 @@ require([
CodeMirror,
about,
searchandreplace,
clipboard
clipboard,
bidi
) {
"use strict";

Expand All @@ -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);
Expand Down