Merge pull request #126 from todoubaba/translate-js
Refactoring translate.js
This commit is contained in:
commit
82824be2d4
|
@ -1,8 +1,42 @@
|
|||
.original-english {
|
||||
border-top: 1px dashed $regal;
|
||||
&.hidden {
|
||||
display: none !important;
|
||||
.docs-content {
|
||||
display: none;
|
||||
.original-english {
|
||||
border-top: 1px dashed $regal;
|
||||
|
||||
&.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
h1.original-english {
|
||||
margin-top: -($unit * 2);
|
||||
}
|
||||
|
||||
h2.original-english {
|
||||
margin-top: -($unit * 1);
|
||||
}
|
||||
|
||||
h3.original-english {
|
||||
margin-top: -($unit * 0);
|
||||
}
|
||||
|
||||
h3.original-english {
|
||||
margin-top: -($unit * 0);
|
||||
}
|
||||
|
||||
p.original-english {
|
||||
margin-top: -($unit * 3);
|
||||
}
|
||||
|
||||
li {
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
td, th {
|
||||
|
|
|
@ -1,150 +1,119 @@
|
|||
// TODO: refactor me!
|
||||
var sourceVisible = localStorage.getItem('source-visible') === 'true';
|
||||
|
||||
(function ($) {
|
||||
addOriginalToggler();
|
||||
addSpacingBetweenCnAndEn();
|
||||
var content = document.querySelector('article.docs-content');
|
||||
var footer = document.querySelector('.main-footer');
|
||||
|
||||
function addOriginalToggler() {
|
||||
var nodes = document.querySelectorAll('p, li, h1, h2, h3, h4, h5, h6, header, a, button, small');
|
||||
_.each(nodes, function (node) {
|
||||
var $node = $(node);
|
||||
processContainer(content);
|
||||
|
||||
if (isLink(node) || isButton(node)) {
|
||||
$node.on('click', function (event) {
|
||||
event.stopPropagation();
|
||||
if (!sourceVisible) {
|
||||
var nodes = document.querySelectorAll('.original-english');
|
||||
_.each(nodes, function (node) {
|
||||
$(node).addClass('hidden');
|
||||
});
|
||||
|
||||
if (/^http?s:\/\//.test($node.attr('href')) && !$node.attr('target')) {
|
||||
$node.attr('target', '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
var prevNode = node.previousElementSibling;
|
||||
var $prevNode = $(prevNode);
|
||||
|
||||
if (!prevNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTranslationResult(node, prevNode)) {
|
||||
if ($prevNode.hasClass('nav-list-item')) {
|
||||
return;
|
||||
}
|
||||
if (isPureEnglish($node.text()) && $node.text() !== $prevNode.text()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPureEnglish($prevNode.text())) {
|
||||
$node.attr('id', prevNode.id);
|
||||
$node.addClass('translated');
|
||||
$node.addClass('translated-cn');
|
||||
$prevNode.removeAttr('id');
|
||||
$prevNode.addClass('original-english');
|
||||
if (!sourceVisible) {
|
||||
$prevNode.addClass('hidden');
|
||||
}
|
||||
if (!isLink(node) && !isButton(node)) {
|
||||
var isDragging = false;
|
||||
$node.on('mousedown', function(){
|
||||
$(window).on('mousemove', function(){
|
||||
isDragging = true;
|
||||
$(window).unbind('mousemove');
|
||||
});
|
||||
});
|
||||
$prevNode.on('mousedown', function(){
|
||||
$(window).on('mousemove', function(){
|
||||
isDragging = true;
|
||||
$(window).unbind('mousemove');
|
||||
});
|
||||
});
|
||||
$node.on('mouseup', function () {
|
||||
var wasDragging = isDragging;
|
||||
isDragging = false;
|
||||
$(window).unbind('mousemove');
|
||||
if(!wasDragging){
|
||||
$prevNode.toggleClass('hidden');
|
||||
}
|
||||
});
|
||||
$prevNode.on('mouseup', function () {
|
||||
var wasDragging = isDragging;
|
||||
isDragging = false;
|
||||
$(window).unbind('mousemove');
|
||||
if(!wasDragging){
|
||||
$prevNode.addClass('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
$node.after($prevNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addSpacingBetweenCnAndEn($node) {
|
||||
var nodes = document.querySelectorAll('.translated-cn');
|
||||
_.each(nodes, function (node) {
|
||||
var text = node.innerHTML;
|
||||
text = text.replace(/([\x20-\xff]+)/g, function (word) {
|
||||
if (!word.replace(/\s/, '')) {
|
||||
return '';
|
||||
} else if (/<[^>]*>/.test(word)) {
|
||||
return ' ' + word + ' ';
|
||||
} else {
|
||||
return ' ' + word + ' ';
|
||||
}
|
||||
});
|
||||
node.innerHTML = text;
|
||||
});
|
||||
}
|
||||
|
||||
function isLink(node) {
|
||||
return node.tagName.toUpperCase() === 'A';
|
||||
}
|
||||
|
||||
function isButton(node) {
|
||||
return node.tagName.toUpperCase() === 'BUTTON';
|
||||
}
|
||||
|
||||
function isPureEnglish(text) {
|
||||
// accept — , quotes, ® and façade too.
|
||||
text = text.replace('在线例子', '');
|
||||
return /^[\1-\255—’“”ç®…à\u200B]*$/.test(text);
|
||||
}
|
||||
|
||||
function attributesToString(node) {
|
||||
return _.chain(node.attributes)
|
||||
.map(function (value) {
|
||||
if (value.name === 'id') {
|
||||
return '';
|
||||
} else {
|
||||
return value.name + '=' + value.value;
|
||||
}
|
||||
})
|
||||
.sortBy()
|
||||
.value()
|
||||
.join(';');
|
||||
}
|
||||
|
||||
function isClonedNode(node1, node2) {
|
||||
return node1.tagName === node2.tagName &&
|
||||
attributesToString(node1) === attributesToString(node2);
|
||||
}
|
||||
|
||||
function indexOfSameType(node) {
|
||||
var i = 0;
|
||||
var aNode = node.parentNode.firstChild;
|
||||
while (aNode !== node) {
|
||||
++i;
|
||||
if (aNode.tagName !== node.tagName) {
|
||||
i = 0;
|
||||
}
|
||||
aNode = aNode.nextElementSibling;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
function isTranslationResult(node, prevNode) {
|
||||
return indexOfSameType(node) % 2 === 1 && isClonedNode(node, prevNode) && isPureEnglish(prevNode.innerText);
|
||||
}
|
||||
// restore
|
||||
content.style.display = 'block';
|
||||
footer.style.display = 'block';
|
||||
|
||||
/**
|
||||
* Process container recursively.
|
||||
* @param container
|
||||
*/
|
||||
function processContainer(container) {
|
||||
for (var i = 0; i < container.children.length; i++) {
|
||||
var node = container.children[i];
|
||||
|
||||
// ignore example code.
|
||||
if (node.classList.contains('code-example') ||
|
||||
node.tagName === 'CODE-EXAMPLE') {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (node.tagName) {
|
||||
case 'P':
|
||||
case 'H1':
|
||||
case 'H2':
|
||||
case 'H3':
|
||||
case 'H4':
|
||||
case 'H5':
|
||||
case 'H6':
|
||||
case 'HEADER':
|
||||
if (processBlock(node)) {
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
case 'TD':
|
||||
case 'TH':
|
||||
processContainer(node);
|
||||
return; // stop
|
||||
default:
|
||||
if (node.children.length > 0) {
|
||||
processContainer(node);
|
||||
// For <li><p>...</p></li>, processes it as block.
|
||||
if (node.children.length === 1) {
|
||||
if (processBlock(node)) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process block elements. The first element is original english, the
|
||||
* second element is translated one.
|
||||
* @param current the first element.
|
||||
* @returns {boolean} Is success?
|
||||
*/
|
||||
function processBlock(current) {
|
||||
var sibling = current.nextElementSibling;
|
||||
var $current = $(current);
|
||||
var $sibling = $(sibling);
|
||||
|
||||
if (sibling) {
|
||||
if (isClonedNode(current, sibling)) {
|
||||
if (isPureEnglish(current.textContent)) {
|
||||
$current.addClass('original-english');
|
||||
$sibling.addClass('translated');
|
||||
$sibling.addClass('translated-cn');
|
||||
$sibling.after($current);
|
||||
$sibling.on('click', function() {
|
||||
$current.toggleClass('hidden');
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
console.error('Error: ' + current.innerText);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isPureEnglish(text) {
|
||||
return !/\p{Han}/.test(text);
|
||||
}
|
||||
|
||||
function attributesToString(node) {
|
||||
return _.chain(node.attributes)
|
||||
.map(function (value) {
|
||||
if (value.name === 'id' || value.name === 'class') {
|
||||
return '';
|
||||
} else {
|
||||
return value.name + '=' + value.value;
|
||||
}
|
||||
})
|
||||
.sortBy()
|
||||
.value()
|
||||
.join(';');
|
||||
}
|
||||
|
||||
function isClonedNode(node1, node2) {
|
||||
return node1.tagName === node2.tagName &&
|
||||
attributesToString(node1) === attributesToString(node2);
|
||||
}
|
||||
})(angular.element);
|
||||
|
|
Loading…
Reference in New Issue