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) ==&gt;<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 редактор за сайт
JS_WisWyg_Editor_by_Ned
Дълго съм се чудил кой е най-подходящия 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("/;/", "&#59;", $clearpost);
$clearpost = preg_replace("/\*/", "&#42;", $clearpost);
$clearpost = preg_replace("/\r\n/", "<br />", $clearpost);
$clearpost = preg_replace("/\r/", "<br />", $clearpost);
$clearpost = preg_replace("/\n/", "<br />", $clearpost);
$clearpost = preg_replace("/</", "&lt;", $clearpost);
$clearpost = preg_replace("/=/", "&#61;", $clearpost);
$clearpost = preg_replace("/>/", "&gt;", $clearpost);
$clearpost = preg_replace("/\'/", "&#39;", $clearpost);
$clearpost = preg_replace("/\`/", "&#96;", $clearpost);
$clearpost = preg_replace("/\"/", "&quot;", $clearpost);
 
if (!get_magic_quotes_gpc()) $clearpost = preg_replace('@\\\@', "&#92;", $clearpost);
else {
	$clearpost = stripslashes($clearpost);
	$clearpost = preg_replace('@\\\@', "&#92;", $clearpost);
}
 
 
$clearpost = preg_replace("/&#39;/", "\&#39;", $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 кода.

Калкулатор за пресмятане на течност за електронни цигари

Написах скромен HTML-JavaScript калкулатор за пресмятане на прости рецепти за сокчета (e-juice) за електронни цигари.
Демо на калкулатора.
Изтегляне.

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
IMDB ProUser - banner

Това е смешно… и естествено е редно да го разкараме:

// ==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';

След като приложихме скрипта, получаваме една нормална страница:
IMDB ProUser Banner removed - Greasemonkey

======================================

И още един скрипт за оналайн магазина 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

Резултат:
JavaScript GUI - Fahrenheit to Celsius Converter
С WinRar можем да направим програмката изпълнимо exe, като включим всички необходими файлове: F_to_C_Converter.exe

ТОТО 6 от 49 генератор – Javascript generate random unique numbers

Скоро в форума на DBG коментирахме скрипт за генериране на случайни числа за тото 6 от 49. Аз си написах собствен JavaScript генератор, който използва специфични и важни javascript трикове:
1. Генериране на обхват от числа
2. Проверка дали дадено число е част от масив
3. Възходящо сортиране на масив от числа
Ето и кода за тото-генератора:

// Деклариране на минимално и максимално число
var min = 1;
var max = 49;
// Брой на случайно-генерираните числа
var randnums = 6;
/* =================================== */
var nums = [];
var c = 0;
var seqarr =[];
 
function compare(a,b){return a - b}
 
for (var num = min; num <= max; num++){nums.push(num)}
 
do{
	var el = nums[Math.floor(Math.random() * nums.length)];
	if(seqarr.indexOf(el) != -1){continue}
	else {
		seqarr.push(el);
		c++;
	}
}while(c<randnums);
 
document.write(seqarr.sort(compare));

Пример може да се види тук:
JavaScript Random Numbers – ТОТО 6 от 49