JSFiddle - React, Tailwind, and code Playground
by Pavel Kityan
HTML
<body>
<p>
In the battle to dominate Europe’s cloud computing market, American tech giants are spending big to build up their local credibility.
</p>
<p>
Amazon Web Services, the largest player, announced last week that it would soon open multiple data centers in France and Britain. Google, which already has sites in countries like Finland and Belgium, is expected to finish a new multimillion-dollar data complex in the Netherlands by the end of the year.
</p>
<p>
And Microsoft, by some measures the second-largest cloud computing provider in Europe, said on Monday that it had spent $1 billion in the last 12 months to expand its offerings, taking its total investment in European-based cloud services to $3 billion since 2005.
</p>
<p>
“We’re building our global cloud infrastructure in Europe so it can be trusted by the multiple constituents,” Satya Nadella, Microsoft’s chief executive, said in an interview. “We can meet the data residency needs of our European customers.”
</p>
<p>
With many in Europe questioning why America’s largest tech companies control how many of the region’s 500 million citizens use everyday digital services, it is not surprising that the likes of Microsoft and Amazon are eager to play up their local roots.
</p>
<p>
As the European Union continues to clamp down on the perceived misuse of people’s digital information, analysts also say that many Silicon Valley giants are responding to these privacy concerns by increasingly offering individuals and companies the ability to keep information close to home, whereas in the past, data might have been stored solely in the United States.
</p>
“Countries like Germany are well aware of data privacy, and it has made them more wary of where data is kept,” said Gregor Petri, a cloud computing analyst at the technology research firm Gartner in Veghel, the Netherlands. “Local data sovereignty has become important, and American companies are now aware of...
CSS
.translation-card.translation-card-container {
position: absolute;
width: 200px;
min-height: 275px;
box-sizing: border-box;
border-radius: 5px;
-webkit-box-shadow: 0px 0px 15px 2px rgba(0,0,0,0.35);
-moz-box-shadow: 0px 0px 15px 2px rgba(0,0,0,0.35);
box-shadow: 0px 0px 15px 2px rgba(0,0,0,0.35);
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
color: #000;
display: none;
background-color: #FFF;
}
.translation-card.translation-card-picture {
width: 200px;
height: 150px;
background-size: cover;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.translation-card.translation-card-word {
padding: 8px;
padding-bottom: 0px;
font-size: 80%;
color: #999;
}
.translation-card.translation-card-meaning {
padding: 8px;
padding-top: 3px;
padding-bottom: 3px;
font-size: 90%;
color: #000;
cursor: default;
}
.translation-card.translation-card-meanings {
max-height: 200px;
overflow-y: auto;
margin-bottom: 8px;
margin-top: 3px;
}
.translation-card.translation-card-meaning.translation-card-meaning-selected {
font-weight: bold;
}
.translation-card.translation-card-meaning.selected {
font-weight: bold;
}
JavaScript
;
(function (global) {
/**
* @namespace App
*/
var
apiURL = 'https://dictionary.skyeng.ru/api/v2/search-word-translation?text='
, selectionCardVerticalPadding = 5 // px
, requestManager // RequestManager instance
, card // Card instance
, currentSelection = {} // current selection
;
// global.onload = init;
setTimeout(init, 0);
/**
* Init app
* @memberOf App
*/
function init() {
requestManager = new RequestManager(apiURL);
card = new Card(global.document, { selectionCardVerticalPadding: selectionCardVerticalPadding });
global.onresize = function () { card.hide(); };
['touchend', 'mouseup', 'keyup'].forEach(
function (eventName) {
global.addEventListener(eventName, onPossibleSelectionEnd)
}
);
}
/**
* Response handler for requestManager
* @memberOf App
* @param {Object} err - error or null
* @param {string} text - requested text
* @param {Object=} data - API response
* @param {boolean=} fromCache - from cache?
*/
function onResponse(err, text, data, fromCache) {
// console.info(err, data, fromCache);
if (!err && data && data.length && currentSelection.text == text) {
card.show(data, currentSelection.rect);
}
}
/**
* Event handler for user events which can end with selected text
* @memberOf App
* @param {Object} event
*/
function onPossibleSelectionEnd(event) {
event.preventDefault();
var selection = window.getSelection();
var selectedText = selection.toString().trim().split(' ')[0];
// anything selected?
if (selectedText) {
currentSelection = {
text: selectedText,
dt: Date.now(),
rect: selection.getRangeAt(0).getBoundingClientRect(),
response: null
}
requestManager.get(currentSelection.text, onResponse)
}
}
// Card module ----------------------->
/**
* @namespace Card
*/
/**
* Card constructor
* @memberOf Card
* @param {object} document Ref to window.document
* @param {object=} options
* @param {number=}...