parts = {
"one": [ 2, 3, 4 ],
"two": [ 5, 6, 7 ],
"tree": [ 8, 9, 10 ]
}
Object.keys(parts).map((part) =>
parts[part].map((el, index) =>
parts[part][index] = el+1
)
);
console.log(parts);
// Result:
// { one: [ 3, 4, 5 ], two: [ 6, 7, 8 ], tree: [ 9, 10, 11 ] }
Category Archives: JavaScript
SVG text as HTML background
И що чак сега се сетих, че мога да ползвам SVG text като background?! И не само текст. Че даже мога да си го променям динамично през javascript! Така някои дизайни можеше да станат по-фън-шуй. По-добре късно от колкото без SVG.
Едно примерче:
<!DOCTYPE html>
<html>
<body>
<button onclick="myFunction()">Try it</button>
<p style="min-height: 400px">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<script>
function myFunction() {
let txt = "SVG Txt";
let s = window.btoa(`
<svg height="400" width="800" xmlns="http://www.w3.org/2000/svg">
<text x="0" y="120" font-weight="bold" font-size="160" fill="#fef" stroke="#ddd">${txt}</text>
</svg>`
);
document.querySelector("p").style.background = `url('data:image/svg+xml;base64,${s}') no-repeat top left`;
}
</script>
</body>
</html>
Demo: text_as_background.html
Simple Tile Calculator – прост калкулатор за редене на плочки
Престои ми ремонт и имам нужда от нещо, което да ми смята бързо броя плочки или ламиниран паркет, като добавя фугите. За това си написах калкулатор на jacascript. Представлява обикновена web-страница. Във версия 002 на калкулатора са направени някои промени:
- Кода е изцяло пренаписан, като вече е обектен, което ще ме улесни да прилагам нови методи на редене
- Добавен е диагонален модел за редене на плочките
- Добавен е генериран код за CAD-софтуера QCad
Програмата работи с всички модерни браузери и мобилни устройства. Калкулатора може да се зареди онлайн от тук:
Tile Calculator
Изтегляне на калкулатора + source: Simple_Tile_Calculator-v.002.zip
След разархивиране на архива може да се ползва само html-файла в основната директория. В папката source е развойната версия на калкулатора с scss-кода.
Кратко видео, което показва моя начин на ползване на това тулче:
Chrome Extension – how to. Кратък урок за създаване на Chrome добавка.
Ще се опитам да опиша простичко, как се разработва прост extension add-on за Chrome. Понякога е много полезно да се работи с подобни скриптове, особено при скрапване на web-съдържание, когато конвенционалните методи не работят или изискват прекалено много усилия.
За да се създаде подобен скрипт с потребителски интерфейс ще са ни необходими няколко файла:
manifest.json – всяка добавка (extension) за Chrome (а и за другите браузери) съдържа подобен скрипт, който предоставя важна информация на браузера. Повече тук: Manifest File Format
popup.html – стандартно наименование на файла с потребителския интерфейс, който се появява при клик с мишката върху добавката. Разбира се, можем да създадем добавка, която няма нужда от потребителски интерфейс, но в случая аз искам да имам. Името на този файл се посочва в manifest.json.
popup.js – файл, който се зарежда чрез popup.html. Можем и да нямаме подобен файл и да поместим javascript кода направо в popup.html. Но тенденциите в модерното програмиране съветват да се диференцира всичко – стилове, скриптове, html. В моя случай popup.js е двигателя на Chrome добавката. Той посочва какво, кога и къде да се активира.
getPagesSource.js – файл за инжектиране в web-страницата и извлича информацията от нея. Този файл се зарежда от popup.js.
icon.png – някаква иконка, която да се показва в листата с добавките на Chrome.
Нека създадем скрипт, който извлиза съдържанието на определени тагове, като използваме javascript функцията querySelectorAll(). Много приятна функция, която заменя в известна степен нуждата от XPath при web-скрапинга.
Да започваме! Първо създаваме manifest.json, като описваме какво прави тая добавка:
1 2 3 4 5 6 7 8 9 10 11 | { "name": "Simple web scraper", "version": "1.0", "manifest_version": 2, "description": "Get content from tags through querySelector", "browser_action": { "default_icon": "icon.png", "default_popup": "popup.html" }, "permissions": ["tabs", "<all_urls>"] } |
След това си правим потребителския интерфейс popup.html – бутончета, поленца, форми, стилове, каквото ни е кеф. В случая ще се огранича на минимума за моите нужди – текстово поле, бутон, слой за резултата:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <!DOCTYPE html> <html style=''> <head> </head> <body style="width:400px;"> <input type="text" id="selector" style="width:300px;" /> <button id="getselector">Get Selector</button><br /><hr /> <div id='message'>Injecting Script....</div> <script src='popup.js'></script> </body> </html> |
В по-горния скрипт се вижда, че зареждам popup.js. Неговото съдържание е следното:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | chrome.runtime.onMessage.addListener(function(request, sender) { if (request.action == "getSlectedContent") { message.innerHTML = request.source; } }); document.querySelector('#getselector').addEventListener('click', winLoad); function winLoad() { var message = document.querySelector('#message'); var inputSel = document.querySelector('#selector').value; var queryInfo = { active: true, currentWindow: true }; chrome.tabs.query(queryInfo, function(tabs) { chrome.tabs.sendMessage( tabs[0].id, { customSelector: inputSel }, function(response) { }); }); chrome.tabs.executeScript(null, { file: "getPageContent.js" }, function() { if (chrome.runtime.lastError) { message.innerText = 'There was an error injecting script : \n' + chrome.runtime.lastError.message; } }); } |
Чрез popup.js зарежда javascripta, който се инжектира в страницата – getPageContent.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | chrome.runtime.onMessage.addListener(function(request, sender) { selElements(document, request.customSelector); }); function selElements(document_root, s){ // Tova go dobaviam zaradi kefa da polzvam foreach() v JavaScript var forEach = function (array, callback, scope) { for (var i = 0; i < array.length; i++) { callback.call(scope, i, array[i]); } }; var myNodeList = document.querySelectorAll(s); var concatenateall = ''; forEach(myNodeList, function (index, value) { concatenateall = concatenateall + value.innerHTML + "<hr />"; }); // return concatenateall; chrome.runtime.sendMessage({ action: "getSlectedContent", source: concatenateall }); } |
Това е.
Сега остава да заредим добавката в Chrome. Това става като отворим More Tools -> Extensions. След това кликаме на бутона Load unpacked и избираме директорията с файловете на нашата добавка.
На базата на тази добавка могат да се направят много други, тъй като съдържа базата за писане на добавки за Chrome.
Сорс кода може да се изтегли от тук: Chrome_Extension-Simple.zip
Кратко видео, което показва как може да се ползва добавката:
Bootstrap and tinyMCE examples
JavaScript обекно ориентирано програмиране – наследяване (пример)
Един много прост пример за наследяване на клас в JavaScript.
В случая имам клас Shape (форма), който ще разширя с клас за правоъгълник (Rectangle), който на свой ред ще разширя с клас за квадрат (Square).
<html> <head> <script type="text/javascript"> var Shape = function() {name: 'Shape'}; Shape.prototype.toString = function() {return this.name;}; var Rectangle = function(width, height) {this.width = width; this.height = height; this.shape = 'Rectangle';}; Rectangle.prototype = new Shape; Rectangle.prototype.constructor = Rectangle; Rectangle.prototype.area = function() {return this.width * this.height;}; var Square = function(width) {this.width = width; this.shape = 'Square';}; Square.prototype = new Rectangle(); Square.prototype.constructor = Square; Square.prototype.area = function() {return this.width * this.width;}; myShape = new Square(6); </script> </head> <body> myShape = new Square(6) ==><br/> <script type="text/javascript">document.write(myShape.width);</script> </body> </html> |
==========================================================
По-горния код е интересен, но тъй като съм го копирал и преработвал, без много да му вниквам, не е мисля, че е добър.
Ето така го оптимизирах, след като попрочетох малко за ООП-то на JavaScript:
var Shape = function () {}; var Triangle = function(w, h) { this.width = w; this.heigh = h; } Triangle.prototype = new Shape(); Triangle.prototype.getArea = function () {return this.width * this.heigh; }; // ====== Kvadrat var Square = function (l) { this.width = l; this.heigh = l; }; Square.prototype = new Triangle(); // ======== Examples var square = new Square(4), triangle = new Triangle(2, 5); print(square.getArea()); print(triangle.getArea()); |
За да стартирам кода използвам SublimeText2 с инсталирана приставка за стартиране на команди от шела Turtlestein, а за JavaScript интерпретатор използвам SpiderMonkey 1.8.5 for Windows.
Simple JavaScript rich text format editor
Прост, базов RTF редактор за сайт
Дълго съм се чудил кой е най-подходящия JavaScript Wysiwyg редактор с най-много възможности за напасване към сайт. Ползвал съм NicEdit, TinyMCE и други, които сам съм писал, неподдържащи rich text format (RTF). Обаче напасването на тези редактори към различни дизайни е развибащо от към бачкане и тестване в различните браузери. Реших да почопля няколко такива редактора и да разбера кое е толкова загадъчно и сложно, за да се напише подобен редактор. Истината е тривиална и се казва – iFrame. Този таг се ползва в почти всички подобни редактори, точно заради поддръжката му на RTF. При събмитване на формата, цялото съдържание на iform се подава на textarea, който си седи удобно скрит.
Това е моят редактор, без CSS-форматиране, като в примера добавям и опция за обработка на текста от базата данни, където присъства без тагове, с ексейпнати малко по-рискови символи.
<?php $field = '<a href="aloooha">Test\'ed. kavicha</a> dyra, byra.<br />Още текст и още "кирилица".'; $clearpost = $field; if(isset($_POST['button'])){ echo $_POST['myTextArea']; $clearpost = $_POST['myTextArea']; } //$clearpost = preg_replace('@delete|select|insert|update|where@i',"", $clearpost); // Почистване на //$clearpost = preg_replace('/[\x7f-\xff]/', "", $clearpost); // Clear Dirty Data $clearpost = preg_replace("/;/", ";", $clearpost); $clearpost = preg_replace("/\*/", "*", $clearpost); $clearpost = preg_replace("/\r\n/", "<br />", $clearpost); $clearpost = preg_replace("/\r/", "<br />", $clearpost); $clearpost = preg_replace("/\n/", "<br />", $clearpost); $clearpost = preg_replace("/</", "<", $clearpost); $clearpost = preg_replace("/=/", "=", $clearpost); $clearpost = preg_replace("/>/", ">", $clearpost); $clearpost = preg_replace("/\'/", "'", $clearpost); $clearpost = preg_replace("/\`/", "`", $clearpost); $clearpost = preg_replace("/\"/", """, $clearpost); if (!get_magic_quotes_gpc()) $clearpost = preg_replace('@\\\@', "\", $clearpost); else { $clearpost = stripslashes($clearpost); $clearpost = preg_replace('@\\\@', "\", $clearpost); } $clearpost = preg_replace("/'/", "\'", $clearpost); // Ескейпване на единичната кавичка, за да може да се показва в iframe!!! ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1251" /> <script src="wiswyg_ned/nedEditor.js"></script> <script type="text/javascript"> window.onload=function(){ iFrameOn(); if(isIE){ var myFrame = document.getElementById('richTextField'); var frameDoc = myFrame.contentDocument || myFrame.contentWindow; if (frameDoc.document){ frameDoc = frameDoc.document; } frameDoc.write ('<?php echo html_entity_decode($clearpost, ENT_QUOTES); ?>') ; } else { window.frames['richTextField'].document.body.innerHTML = '<?php echo html_entity_decode($clearpost, ENT_QUOTES); ?>' ; } } </script> </head> <!-- <body onLoad="iFrameOn();" > --> <body> <form action="" enctype="multipart/form-data" name="myForm" id="myform" method="post"> <div id="wysiwyg_cp" style="padding:8px; width:700px;"> <input type="button" onClick="iBold()" value="B"> <input type="button" onClick="iUnderline()" value="U"> <input type="button" onClick="iItalic()" value="I"> <input type="button" onClick="iFontSize()" value="Text Size"> <input type="button" onClick="iForeColor()" value="Text Color"> <input type="button" onClick="iHorizontalRule()" value="HR"> <input type="button" onClick="iUnorderedList()" value="UL"><br /> <input type="button" onClick="iOrderedList()" value="OL"> <input type="button" onClick="iLink()" value="Link"> <input type="button" onClick="iUnLink()" value="UnLink"> <input type="button" onClick="iImage()" value="Image"> <input type="button" onClick="iRemoveFormat()" value="Remove Format"> </div> <!-- Hide(but keep)your normal textarea and place in the iFrame replacement for it --> <textarea style="display:none;" name="myTextArea" id="myTextArea" cols="100" rows="14"></textarea> <iframe name="richTextField" id="richTextField" ></iframe> <br /> <input type="submit" name="button" id="button" value="Make Changes" onClick="javascript:submit_form();"/> </form> </body> </html> |
Съдръжанието на JavaScript файла:
// Check Browser var isOpera = !!(window.opera && window.opera.version); // Opera 8.0+ var isFirefox = testCSS('MozBoxSizing'); // FF 0.8+ var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; // At least Safari 3+: "[object HTMLElementConstructor]" var isChrome = !isSafari && testCSS('WebkitTransform'); // Chrome 1+ var isIE = /*@cc_on!@*/false || testCSS('msTransform'); // At least IE6 function testCSS(prop) { return prop in document.documentElement.style; } //==================== function iFrameOn(){ richTextField.document.designMode = 'On'; //window.frames['richTextField'].document.body.innerHTML = '<a href="aloooha">Aloha</a> dyra, byra.<br />Още текст има тук.'; } function iRemoveFormat(){ richTextField.document.execCommand('removeformat',false,null); } function iBold(){ richTextField.document.execCommand('bold',false,null); } function iUnderline(){ richTextField.document.execCommand('underline',false,null); } function iItalic(){ richTextField.document.execCommand('italic',false,null); } function iFontSize(){ var size = prompt('Enter a size 1 - 7', ''); richTextField.document.execCommand('FontSize',false,size); } function iForeColor(){ var color = prompt('Define a basic color or apply a hexadecimal color code for advanced colors:', ''); richTextField.document.execCommand('ForeColor',false,color); } function iHorizontalRule(){ richTextField.document.execCommand('inserthorizontalrule',false,null); } function iUnorderedList(){ richTextField.document.execCommand("InsertOrderedList", false,"newOL"); } function iOrderedList(){ richTextField.document.execCommand("InsertUnorderedList", false,"newUL"); } function iLink(){ var linkURL = prompt("Enter the URL for this link:", "http://"); richTextField.document.execCommand("CreateLink", false, linkURL); } function iUnLink(){ richTextField.document.execCommand("Unlink", false, null); } function iImage(){ var imgSrc = prompt('Enter image location', ''); if(imgSrc != null){ richTextField.document.execCommand('insertimage', false, imgSrc); } } function submit_form(){ var theForm = document.getElementById("myform"); theForm.elements["myTextArea"].value = window.frames['richTextField'].document.body.innerHTML; theForm.submit(); } |
Сорс кода: wiswyg_by_ned.rar
Demo нa кода.
Калкулатор за пресмятане на течност за електронни цигари
Greasemonkey scripts
Ползвали ли сте Greasemonkey? Това е една изключително готина добавка за Firefox (вече и за други браузери, в Chrome 4 си я има по подразбиране), която доста улеснява живота. Greasemonkey ви позволява да промените начина по който изглежда или се държи дадена Web-страница, благодарение на малки парченца javaScript код.
Greasemonkey може да се използва за персонализиране на редакторите във форумите. Как примерно да добавим бутончета към редактора за постове в Dbg:
– да прави цвета на селектирания текст в синьо, а текста удебелен
– да слага тагове за цитиран текст
Ей го скрипта:
// ==UserScript== // @name Add DBG Buttons // @namespace http://www.download.bg/* // @description Add DBG Buttons // @include // ==/UserScript== var BlueBtn = document.createElement('a'); BlueBtn.appendChild(document.createTextNode('Blue')); BlueBtn.setAttribute("onclick", "s('[color=blue][b]', '[/b][/color]', document.posting_form.message)"); BlueBtn.setAttribute("style", "color: blue; font-weight: bold; cursor:pointer; margin: 0 2px; background: #eeeedd; border: 1px solid #bbbbaa;"); var content=document.evaluate("//a[@class='rtbutton']", document, null, 9, null).singleNodeValue; content.parentNode.insertBefore(BlueBtn, content); var QuotBtn = document.createElement('a'); QuotBtn.appendChild(document.createTextNode('"quot"')); QuotBtn.setAttribute("onclick", "s('[q]', '[/q]', document.posting_form.message)"); QuotBtn.setAttribute("style", "color: black; font-weight: normal; cursor:pointer; margin: 0 2px; background: #eeeedd; border: 1px solid #bbbbaa;"); var content=document.evaluate("//a[@class='rtbutton']", document, null, 9, null).singleNodeValue; content.parentNode.insertBefore(QuotBtn, content); |
Много готино е, че Frefox поддържа XPath! За разлика от лайното Internet Explorer (трябва да се забрани със закон и всеки потребител да подписва договор, че никога, за нищо на света няма да използва IE, ам наистина НИКОГА!). А XPath яко улеснява писането на JavaScript и неимоверно съкращава кода.
Резултата може да се види на картинките по-долу.
Оригинална лента:
С добавените бутони:
Скрипта може да се изтегли от тук:
Добавяне на бутони към коментарите в DBG
======================================
Между другото Greasemonkey може да автоматизира и въвеждането на информация в специални сайтове, като например онлайн игрите. Има една онлайн игра Dimiva.com, където трябва да въртиш някакво зомбирано колело и междувременно ти излизат някакви зомбирани реклами, които трябва да познаваш за какво са и да кликаш на radio-бутони под тях. Изобщо зомбирана ситуация. Използвам я само за примерен скрипт, който да маркира автоматично radio-бутоните.
// ==UserScript== // @name Dimiva // @namespace https://www.dimiva.com/* // @description Dimiva advent script // @include // ==/UserScript== var items = { "24ins" : "Застрахователен", "0_7_wonders" : "Сладкарница", "0_svobodni_kvartiri" : "жилища под наем", "folio4cars" : "Затъмняване", "cube_fitness_club" : "Фитнес", "0_4by4" : "Off-Road", "0_qbi_group" : "Застрахователен", "0_maniq_varna" : "Дрехи втора упореба", "e4995150fc0a" : "Алмохадон" }; var images = document.getElementsByTagName('img'); for (var i=0; i<images.length; i++){ for(var index in items) { if (images[i].src.indexOf(index) != -1) { document.evaluate("//div[contains(@class,'banner-container')]/a/img[contains(@src,'" + index +"')]/../../div/label[contains(text(),'" + items[index] + "')]/input", document, null, 9, null).singleNodeValue.setAttribute('checked', 'checked'); } } } |
Спред картинката, която се зарежда, маркирам и съответния бутон. Картинките са с постоянни имена, което улеснява зомбираната ситуация.
И скрипта: dimiva.com – radio clicker
======================================
Ще покажа и още един пример, който обработва всички зададени тагове от дадена страница. Примерно искаме да сменим цвета на “син” на всички линкове в някой сайт. За да си спестя безмислено писане на код, отново ще използвам XPath.
// ==UserScript== // @name Blue Links // @namespace http://statcounter.com/ // @include http://statcounter.com/* // ==/UserScript== textNodes = document.evaluate("//a", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i=0;i<textNodes.snapshotLength;i++) { var node = textNodes.snapshotItem(i); node.style.color = "blue"; } |
======================================
На сайта на филмовата база данни IMDB има много интересни класации и рейтинги на филми. Но при отварянето на някои излиза досаден банер, който те призовава да станеш ProUser. Примерна страница:
http://pro.imdb.com/moviemeter/?d=tt_moviemeter_why
Това е смешно… и естествено е редно да го разкараме:
// ==UserScript== // @name imdb hide pro banner // @namespace none // @include http://pro.imdb.com/moviemeter/* // ==/UserScript== var snode = document.evaluate("//div[@id='pro_upsell_wrapper']", document, null, 9, null).singleNodeValue; snode.style.display = 'none'; |
След като приложихме скрипта, получаваме една нормална страница:
======================================
И още един скрипт за оналайн магазина SportsDirect, който скрива резултати с цена по-висока от избраната от нас. Примерно искаме да скрием всички стоки, които са с цена по-висока от 29 паунда.
// ==UserScript== // @name SportsDirect // @namespace http://www.sportsdirect.com/ // @include http://www.sportsdirect.com/* // ==/UserScript== var price_custom = 29; // Nad kakva cena da skriva rezultata textNodes = document.evaluate("//span[@class=\"sellingprice s-largered productPrice productHasRef\"]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); for (var i=0;i<textNodes.snapshotLength;i++) { var nodeText = textNodes.snapshotItem(i).textContent.replace("£",""); var node = textNodes.snapshotItem(i) if(nodeText>=price_custom){ node.parentNode.parentNode.parentNode.parentNode.parentNode.style.visibility = 'hidden'; } } |
Файл за инсталиране: SportsDirect price filter
======================================
Малко полезни линкове:
http://userscripts.org/ – база данни с потребителски скриптове. Добро място за разучаване на кодирането с Greasemonkey.
http://wiki.greasespot.net/ – мястото от където е добре да започнем
document.evaluate – обяснение за опциите на document.evaluate
JavaScript GUI – бързо, вкусно, лесно с GLUEScript
Днес докато се ровех за интересни нови неща около JavaScript интепретатора на mozilla – SpiderMonkey попаднах на много интересна среда за програмиране GLUEScript, базирана на този интерпретатор. За графичния потребителски интерфейс (GUI) се използват wxWidgets.
Възможността да се пишат GUI програми с JavaScript особено много ме гизкефи. JavaScript е доволно популярен и приложим език за програмиране. Информация в мрежата бол.
Ето едно много просто приложение, което показва лекотата за писане с GLUEScript – температурен конвертор между Фаренхайд и Целзий:
var wx = require("wx"); wx.theApp.onInit = function() { var frame = new wx.Frame(null, wx.Id.ANY, "Fahrenheit to Celsius Converter", { x:-1, y: -1}, new wx.Size(307, 73)); var panel = new wx.Panel(frame, wx.Id.ANY); var button = new wx.Button(panel, wx.Id.EXIT, "Convert", { x : 112, y : 8 }); var textbox1 = new wx.TextCtrl(panel, wx.Id.EXIT, "", { x : 6, y : 8 }); var textbox2 = new wx.TextCtrl(panel, wx.Id.EXIT, "", { x : 192, y : 8 }); button.onClicked = function(event){ textbox2.value = (textbox1.value - 32)*5/9; } frame.center(); frame.show(); return true; } |
Запазваме програмата като converter_c_to_t.js и я изпълняваме през промпта или конзолата:
glue converter_f_to_c.js |
Резултат:
С WinRar можем да направим програмката изпълнимо exe, като включим всички необходими файлове: F_to_C_Converter.exe