среда, 13 января 2010 г.

Изображение – ссылка на пост

Изображение – ссылка

Как сделать чтобы ссылка загруженного изображения Blogger вела на страницу сообщения? Отвечаю на вопросы читателей.


По-умолчанию, ссылка ведет на полноразмерное изображение, и обычными средствами Blogger это реализовать нельзя. Поэтому, я написал Javascript-функцию для ссылок изображений Blogger.


Читать дальше »

четверг, 3 сентября 2009 г.

Javascript и CSS в сообщениях Blogger

Довольно часто в конференциях проскакивают вопросы типа: «я написал функцию javascript. На отдельной странице работает, а в сообщении Blogger – нет». Это такие древние грабли, о которых я бы давно и забыл, поскольку «перешагиваю» уже на автомате. Но подобные вопросы всплывают снова и снова, поэтому проще один раз написать и избавить себя от головной боли в будущем.


Итак, как лечить. Дело в том, что у большинства пользователей Blogger активирована опция «Преобразовывать разрывы строк» (Настройки – Форматирование). Даже у меня, хотя если задуматься, она мне нафиг не нужна.


Все символы перевода строки в редактируемом сообщении \n преобразуются движком Blogger в теги <br />. И чтобы javascript не потерял работоспособность, код вида:

<script type="text/javascript">
function myBloggerFunction(){
/*...код функции...*/
}
</script>

в сообщении нужно утаптывать в одну строку:
<script type="text/javascript">function myBloggerFunction(){/*...код функции..*/}</script>


То же справедливо и для стилей CSS:

<style type="text/css">
.post-body blockquote {
font-style:italic;
color: #1A3457;
}
.post-body blockquote.myStyle {
border:1px dotted #1A3457;
}
</style>

Одной строкой:
<style type="text/css">.post-body blockquote {font-style:italic;color: #1A3457;}.post-body blockquote.myStyle {border:1px dotted #1A3457;}</style>


И еще один момент. Было замечено, что движок Блоггера ломает операции сравнения в javascript. Например, преобразует < в &lt; и > в &gt;. К сожалению (или к счастью), «на кошках» мне этот баг повторить не удалось. Возможно, что ошибка уже исправлена.


---
Увы, хворают не только скрипты; иногда болеют и домашние питомцы. Во втором случае – помощь окажут в ветеринарной клинике.


Читать дальше »

воскресенье, 19 июля 2009 г.

Rails Plugin подсветки синтаксиса

Rails Plugin для «клиентской» подсветки синтаксиса.


Установка


script/plugin install git://github.com/antono/sh2.git
rake -T sh2
rake sh2:install

Helpers


Подключение скриптов и стилей для плагина.

include_syntax_highlighter_assets(:themes => :midnight, :brushes => :all)

Поместить в layout, в тег head


Следующий хелпер запускает подсветку синтаксиса для полностью загруженной страницы.

sh2_highlight_code

Должен размещаться в конце страницы.


Пример использования


<pre class="brush:ruby">
1000.times { puts 'Руби Руби Руби Руби' }
</pre>

Ссылка: Client-side Syntax Highlighter для Rails
Читать дальше »

понедельник, 13 июля 2009 г.

Cкрытый текст в сообщениях блога

Или «как в блоге прятать текст под спойлеры». Недавно написал небольшой javascript-компонент Widget SpoilerManager для использования скрытого текста в блоге. Собственно, это та «культурная программа», которой я посвятил прошлую субботу. Да, я псих.


UPD: Последний раз я доверил свои файлы богом проклятому сервису HotLinkFiles! Пусть горит в аду! Позже выложу в текстовом виде.


Пример:


Спойлер (от англ. spoil — портить) — в кино, компьютерных играх, литературе — преждевременно раскрытая важная информация, которая портит впечатление от игры/книги/фильма и разрушает их интригу, а также лишает читателя некоторой части удовольствия от сюжета.
цитата из Википедии: Спойлер (кино)


Как использовать


  1. Создай стили CSS для компонента:
    /* Стили для спойлера */
    .bar {
    background:#B2BDCB url('https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj91MO6k3OKdYj59ONnuGLGObIMEJLBtDbz7lDf4L4_QOHq3x_bp5P8ra-DgCtL2XRJh1KtVd96j3CcxIvDto-b9nI8On3Zjv9Z-x1BftnGyEr9LrR2eHtJnZ7kIOai5Www6hgtWPjvoBFw/') no-repeat;
    padding-left: 30px;
    color: #1A3457;
    height:26px;
    font-weight:bold;
    cursor:pointer;
    }
    /* Скрытый спойлер */
    .spoiler-hidden .bar {
    background-position: 0 0;
    }
    .spoiler, .spoiler-hidden .text {
    display: none;
    }
    /* Открытый спойлер */
    .spoiler-visible .bar {
    background-position: 0 -26px;
    }
    .spoiler-visible .copy {
    text-align:right; font-size:0.6em;
    }
    .spoiler-visible .text {
    display:visible;
    padding: 0 1em;
    border: 1px dashed #B2BDCB;
    border-top-width:0;
    }

  2. Включи код спойлера сразу перед закрывающим тегом </body> (см. апдейт)
    <script src='http://www.hotlinkfiles.com/files/2667809_ezrak/widget_spoiler.js' type='text/javascript'></script>
    <script type='text/javascript'>
    /* Для предотвращения проблем с кириллицей, задай надпись по умолчанию */
    WidgetSpoilerManager.setOption ("defaultTitleText", "Скрытый текст");
    /* Запусти виджет Спойлер-Менеджера */
    WidgetSpoilerManager.init();
    </script>

    UPD 19.07.2009
    Скрипт залит на файлохранилище №1.
    Подключать файл (первая строка предыдущего листинга) можно так:
    <script src='http://sites.google.com/site/railsdepot/files/widget_spoiler.js' type='text/javascript'></script>

    UPD 27.08.2009
    Полный код для второго пункта:
    <script src='http://sites.google.com/site/railsdepot/files/widget_spoiler.js' type='text/javascript'></script>
    <script type='text/javascript'>
    WidgetSpoilerManager.setOption ("defaultTitleText", "Скрытый текст");
    WidgetSpoilerManager.init();
    </script>

  3. Сохрани шаблон.

  4. В сообщениях используй следующий код:
    <div class="spoiler" title="здесь задай краткое описание">
    А здесь текст, который хочешь сделать скрытым
    </div>

Виджет сам найдет и скроет все блоки текста, отмеченные как спойлер.


© dotrb.blogspot.com


Читать дальше »

среда, 8 июля 2009 г.

DHTML Tab Connection Panel

Результат выполнения еще одного «тестового задания». ..И в который раз затрудняюсь с выбором кавычек. Выкладываю коды здесь, вдруг да когда пригодится. Использовался фреймворк Prototype. Сам текст задания, возможно, выложу позже.


Скриншот



Известные проблемы и ограничения в рамках тестового задания


  • при добавления большого количества вкладок отсутствуют боковые границы рядов;
  • на странице main.html не отслеживается обновление (через F5) страницы child.html
  • в IE 6 было замечено вертикальное смещение правой границы динамически созданных вкладок;
  • на странице child.html не отслеживается наличие открывающего документа document.opener (main.html);
  • скрипт бесполезно проверять инструментами вроде IETester. Как правило, эти инструменты не отслеживают document.opener;
  • отключена возможность удаления активной вкладки с помощью CSS, отсутствует контроль этого процесса средствами javascript.

Изображения




Изображения получены из открытых источников


main.html


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html dir='ltr' xmlns='http://www.w3.org/1999/xhtml'>
<head>
<title>Main Window</title>
<link type='text/css' rel='stylesheet' href='public/stylesheets/general.css' />
<script type="text/javascript" src="public/javascripts/prototype.js"></script>
<script type="text/javascript" src="public/javascripts/main.js"></script>
</head>
<body>
<p><input id="btnOpen" type="button" value="Изменить..." onclick="return btnOpen_onclick();" /></p>
<div id="connections"></div>
</body>
</html>


child.html


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>DHTML Tab Connection Panel</title>
<script type="text/javascript" src="public/javascripts/prototype.js"></script>
<link type='text/css' rel='stylesheet' href='public/stylesheets/general.css' />
<script type="text/javascript" src="public/javascripts/child.js"></script>
</head>
<body>
<p id="navBar">
<input id="btnAdd" type="button" tabindex="1" value="Добавить" onclick="tabView.addControl(); return false;" />
<a id="aTabPrev" href="#" tabindex="2" onclick="tabView.tabPrev(); return false;">←</a>
<kbd>Ctrl</kbd>
<a id="aTabNext" href="#" tabindex="3" onclick="tabView.tabNext(); return false;">→</a>
</p>

<div id="tabView1" class="tabView">
<div id="tabPanel" class="tabPane">
<div id="tabViewTab_0" class="tabActive" style="left: 0px;" onclick="tabView.tabSelect(0); return false;">
<div class="icon"></div>
<span tabindex="4"><span id="tabText_0" class="tabText">Guest</span>
<a href="#" onclick="tabView.destroy(0); return false;"><img class="close" width="8" height="8" src="public/images/icon_delete.gif" /></a>
</span>
<img class="tab_right" src="public/images/tab_right.gif" />
</div>
</div>
<div class="clear"></div>

<div id="aFormCont" class="aTab">
<form id="aForm" action="">
<input id="index" type="hidden" />
<div>Логин</div>
<div><input id="login" type="text" onchange="tabView.onChange();" /></div>
<div>Пароль</div>
<div><input id="password" type="password" onchange="tabView.onChange();" /></div>
<div><input id="remember_login" type="checkbox" onchange="tabView.onChange();" /><label for="remember_login">Запомнить логин</label></div>
<div><input id="remember_password" type="checkbox" onchange="tabView.onChange();" /><label for="remember_password">Запомнить пароль</label></div>
<div><input id="auto_login" type="checkbox" onchange="tabView.onChange();" /><label for="auto_login">Входить автоматически</label></div>
<p style="text-align:right;">
<input id="button_submit" type="button" value="Подключить" onclick="tabView.onChangeStatus();" />
</p>
</form>
</div>
</div>
</body>
</html>

general.css


/* General */
body{
margin:10px;
font-size:0.9em;
}

/* Main */
#connections p {
border:1px solid #919B9C;
padding: 0 0.2em;
width: 500px;
font-family: Trebuchet MS, Lucida Sans Unicode, Arial, sans-serif;
}

/* Child */
a{
color:#F00;
}
.tabView {
width:500px;
height:400px;
}
.tabPane{
height:21px; /* Height of tabs */
border-bottom:1px solid #919b9c;
}
.aTab{
border-left:1px solid #919b9c;
border-right:1px solid #919b9c;
border-bottom:1px solid #919b9c;
font-family: Trebuchet MS, Lucida Sans Unicode, Arial, sans-serif;
padding:5px;

}
.tabPane div{
float:left;
height:100%; /* Height of tabs */
padding-left:3px;
vertical-align:middle;
background-repeat:no-repeat;
background-position:bottom left;
cursor:pointer;
position:relative;
bottom:-1px;
margin-left:0px;
margin-right:0px;
}
.tabPane .tabActive{
background-image:url('../images/tab_left_active.gif');
margin-left:0px;
margin-right:0px;
z-index:10;
}
.tabPane .tabInactive{
background-image:url('../images/tab_left_inactive.gif');
margin-left:0px;
margin-right:0px;
z-index:10;
}
.tabPane .inactiveTabOver{
background-image:url('../images/tab_left_over.gif');
margin-left:0px;
margin-right:0px;
}
.tabPane span{
font-family:arial;
vertical-align:top;
font-size:11px;
padding-left:3px;
padding-right:3px;
line-height:21px;
float:left;
}
.tabPane .tabActive span{
padding-bottom:1px;
line-height:20px;
position: relative;
padding-left: 4px;
padding-right: 12px;
}
.tabPane .tabInactive span{
padding-bottom:1px;
line-height:20px;
position: relative;
padding-left: 3px;
padding-right:10px;
}
.tabPane img{
float:left;
}
.tabPane .tabActive img.tab_right {
background-image:url(../images/tab_right_active.gif);
}
.tabPane .tabInactive img.tab_right {
background-image:url(../images/tab_right_inactive.gif);
}
.tabActive a {
display:none;
}
.icon {
background-image:url(../images/globe_icon.gif);
background-repeat:no-repeat;
background-position:bottom left;
width:15px;
}
img.close {
position: absolute;
top: 6px;
right: 0;
border:0;
}
a img.close {
opacity:.01;
filter: alpha(opacity=1); /* IE */
-moz-opacity: 0.01; /* Firefox */
}
a:hover img.close {
opacity:1;
filter: alpha(opacity=100); /* IE */
-moz-opacity: 1; /* Firefox */
}
.tabText{
min-width:30px;
display:inline-block;
}
.clear {
clear: both;
}

/* Navigation Bar */
#navBar {
width:500px;
text-align:right;
}
#navBar input {
float:left;
}
#navBar a {
text-decoration:none;
}
#navBar kbd {
font-size:larger;
}

/* Form elements */
input[type="text"], input[type="password"] {border:1px solid #919b9c;}
/* for IE */
input { border:expression((this.type=='text')||(this.type=='password') ? '1px solid #919b9c' : ''); }

main.js


// <!CDATA[
var pPrefix = "connection_";
var prefixLogin = "login_";

document.addConnection = addConnection;
document.updateConnection = updateConnection;
document.destroyConnection = destroyConnection;
document.updateConnectionStatus = updateConnectionStatus;

/* Open Child document */
function btnOpen_onclick(){
open("child.html", "Child");
}

/* Helpers */
bool2human = function(value){
return (value == true) ? "да" : "нет";
}

humanStatus = function(value){
return (value == true) ? "Подключен" : "Отключен";
}

/* Dynamic template for #connections P.innerHTML */
getTemplate = function(attr){
return 'Логин: <span class="login">'+ attr.login +'</span><br />'+
'Пароль: <span class="password">'+ attr.password +'</span><br />'+
'Запомнить: логин (<span class="remember_login">'+ bool2human(attr.remember_login) +'</span>),'+
' пароль (<span class="remember_password">'+ bool2human(attr.remember_password) +'</span>)<br />'+
'Входить автоматически (<span class="auto_login">'+ bool2human(attr.auto_login) +'</span>)<br />'+
'<span class="status">'+ humanStatus(attr.status) +'</span>';
}

/* functions called by Child document */
function addConnection(attr){
try {
var p1 = document.createElement("p");
p1.id = pPrefix + attr.index;
var template = getTemplate(attr);
p1.innerHTML = template;
$("connections").appendChild(p1);
}
catch (e) {
alert(e.description);
}
}

function updateConnection(attr){
try {
var p1 = $(pPrefix + attr.index);
var template = getTemplate(attr);
p1.innerHTML = template;
}
catch (e) {
alert(e.description);
}
}

function destroyConnection(index){
var p1 = $(pPrefix + index);
Element.remove(p1);
}

function updateConnectionStatus(index, status){
var cssExpr = $$("#"+ pPrefix + index +" .status");
cssExpr[0].innerHTML = humanStatus(status);
}
// ]]>

child.js


document.onkeydown = navigateTabs;

function navigateTabs (event){
if (window.event) event = window.event;
if (event.ctrlKey){
switch (event.keyCode ? event.keyCode : event.which ? event.which : null){
case 0x25:
tabView.tabPrev();
break;
case 0x27:
tabView.tabNext();
break;
}
}
}

/* Class: Tab View */
TabView = function(){
this.tabPrefix = "tabViewTab_";
this.tabTextPrefix = "tabText_";
this.tabPanelId = "tabPanel";
this.items = new Array();
this.cnActive = "tabActive";
this.cnInactive = "tabInactive";
this.patternTabActive = "#tabView1 ." + this.cnActive;
this.tabIndexShift = 4; //сдвиг tabindex

this.init = function(){
this.add("Guest", "guest", true, true, false, false);
}

this.destroy = function(index){
if ( $(this.tabPrefix + index) != undefined ){
this.items[index] = null;
this.destroyConnection(index);
Element.remove(this.tabPrefix + index);
}
}

this.add = function(login, password, remember_login, remember_password, auto_login, status){
var index = this.items.length;
var Item = new Object();
Item.index = index;
Item.login = login;
Item.password = password;
Item.remember_login = remember_login;
Item.remember_password = remember_password;
Item.auto_login = auto_login;
Item.status = status;
this.items.push(Item);
this.addConnection(Item);
}

/* Functions for Document.Opener */
this.addConnection = function(obj){
opener.document.addConnection(obj);
}
this.updateConnection = function(obj){
opener.document.updateConnection(obj);
}
this.destroyConnection = function(index){
opener.document.destroyConnection(index);
}
this.updateConnectionStatus = function(index, status){
opener.document.updateConnectionStatus(index, status);
}

/* Helpers */
this.humanStatus = function(value){
return (value == true) ? "Отключить" : "Подключить";
}

this.checkbox2bool = function(value){
return (value == null) ? false : true;
}

/* DOM Functions */
this.addControl = function(){
this.add("", "", false, false, false, false);

var index = this.items.length-1;
var p1 = document.createElement("p");
var div1 = document.createElement("div");
div1.id = this.tabPrefix + index;
div1.className = this.cnInactive;//;
div1.onclick = function(){ tabView.tabSelect(index); return false; };

var div2 = document.createElement("div");
div2.className = "icon";
div1.appendChild(div2);

var span1 = document.createElement("span");
span1.setAttribute("tabindex", index*1 + this.tabIndexShift);

var span2 = document.createElement("span");
span2.id = this.tabTextPrefix + index;
span2.className = "tabText";
span1.appendChild(span2);

var a1 = document.createElement("a");
a1.href = "#";
a1.onclick = function(){ tabView.destroy(index); return false; };

var img1 = document.createElement("img");
img1.className = "close";
img1.setAttribute("width", 8);
img1.setAttribute("height", 8);
img1.setAttribute("src", "public/images/icon_delete.gif");
a1.appendChild(img1);
span1.appendChild(a1);

var img2 = document.createElement("img");
img2.className = "tab_right";
img2.setAttribute("src", "public/images/tab_right.gif");

div1.appendChild(span1);
div1.appendChild(img2);
$(this.tabPanelId).appendChild(div1);
}

this.fillForm = function(obj){
$("index").value = obj.index;
$("login").value = obj.login;
$("password").value = obj.password;
$("remember_login").checked = obj.remember_login;
$("remember_password").checked = obj.remember_password;
$("auto_login").checked = obj.auto_login;
$("button_submit").value = this.humanStatus(obj.status);
}

this.tabSelect = function(index){
//scope for each() function
cnActive = this.cnActive;
cnInactive = this.cnInactive;
if ( $(this.tabPrefix + index) != undefined ){
//off
$$(this.patternTabActive).each( function(elem){
Element.removeClassName(elem, cnActive);
Element.addClassName(elem, cnInactive);
});
//on
Element.removeClassName(this.tabPrefix + index, this.cnInactive);
Element.addClassName(this.tabPrefix + index, this.cnActive);
this.fillForm(this.items[index]);
return true;
}
return false;
}

/* onModyfy functions */
this.onChange = function(){
var index = $F("index");

var Item = this.items[index];
Item.index = index;
Item.login = $F("login");
Item.password = $F("password");
Item.remember_login = this.checkbox2bool( $F("remember_login") );
Item.remember_password = this.checkbox2bool( $F("remember_password") );
Item.auto_login = this.checkbox2bool( $F("auto_login") );

$(this.tabTextPrefix + index).innerHTML = Item.login;

this.updateConnection(Item);
}

this.onChangeStatus = function(){
var index = $F("index");
var Item = this.items[index];
Item.status = (Item.status == true) ? false : true;
this.updateConnectionStatus(Item.index, Item.status);
$("button_submit").value = this.humanStatus(Item.status);
}

/* Navigation through Tabs */
this.tabPrev = function(){
var index = $F("index");
for (var i = index*1-1; i >= this.items.first().index; i--){
if (this.tabSelect(i)){
break;
}
}
}

this.tabNext = function(){
var index = $F("index");
for (var i = index*1+1; i <= this.items.last().index; i++){
if (this.tabSelect(i)){
break;
}
}
}

this.init();
}
// End: Class TabView

// Init tabView
tabView = new TabView();
Event.observe(window, "load", function() {
tabView.fillForm(tabView.items[0]);
});

Вот как-то так :).


Creative Commons License
DHTML Tab Connection Panel by JCDen (aka Croaker) is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
Читать дальше »

вторник, 9 июня 2009 г.

Определить IE6 с помощью JavaScript 2

Фактически это не второй скрипт, а фикс предыдущего.


Напоминаю задачу: определить, что браузер посетителя IE6 или более древний.


В Internet Explorer в navigator.appVersion первой идет версия движка, а потом уж все остальное. Примерно так:

4.0 (compatible; MSIE 6.0; Windows NT 5.2; Win64; x64; SV1; .NET CLR 2.0.50727)


Исправленная функция:

function detectIE6(){
var browser = navigator.appName;
if (browser == "Microsoft Internet Explorer"){
var b_version = navigator.appVersion;
var re = /\MSIE\s+(\d\.\d\b)/;
var res = b_version.match(re);
if (res[1] <= 6){
return true;
}
}
return false;
}


Для выборки части строки использовались регулярные выражения.


Читать дальше »

среда, 29 апреля 2009 г.

Определить IE6 с помощью JavaScript

Не так давно мне понадобилась функция для определения браузера и его версии. А точнее, что браузер пользователя – именно Internet Explorer 6-й или более древний.


А вот и сама функция javascript:


function detectIE6(){
var browser = navigator.appName;
var b_version = navigator.appVersion;
var version = parseFloat(b_version);
if ((browser == "Microsoft Internet Explorer") && (version <= 6)){
return true;
}else{
return false;
}
}

И пример использования:


if ( detectIE6() ){
// Выполняем действия только для IE6 или более ранней версии
}


UPD: Исправленная версия скрипта для определения ИЕ6.
Читать дальше »

суббота, 28 февраля 2009 г.

Коварный rel external

Что значит атрибут ссылки rel="external".


Довольно часто просматривая чужие блоги натыкаюсь на ссылки вида:

<a rel="external nofollow" href="http://dotrb.blogspot.com">Солодоварни Рубина</a>


Что значит атрибут nofollow я знаю, но вот что такое external? Дело в том, что в спецификации XHTML атрибут ссылки target не поддерживается. Следовательно, конструкция вида: target="_blank" не является валидной. Открывание нового окна браузера – это задача скрипта, а не гипертекстовой разметки. Открывать ссылки в новом окне теперь предлагается с помощью, например языка javascript. Для этого отдельными разработчиками и был искусственно введен атрибут external.


Читать дальше »

четверг, 12 февраля 2009 г.

Удалить Blogger navbar при помощи javascript

Как удалить navbar из шаблона Blogger используя JavaScript.

Добавьте в конец шаблона перед тегом </body> следующий скрипт (или добавьте гаджет HTML/Javascript):
<script type="text/javascript">
function removeBloggerNavbar(){
var parent = document.getElementById("Navbar1");
var child = document.getElementById("navbar-iframe");
parent.removeChild(child);
}
removeBloggerNavbar();
</script>

Cкрипт полностью удалит navbar со страницы. Работает в FF и IE.
upd: Работает в Opera, Safari, Google Chrome. Читать дальше »

среда, 11 февраля 2009 г.

Pastie подсветка синтаксиса

Самый первый пост, опубликованный мной с тегом JavaScript освещал такую интересную для любого «кодоблоггера» тему, как Динамическая подсветка синтаксиса с помощью javascript.

Если же по каким-то причинам вам лень добавлять javascript к вашему шаблону, вы можете воспользоваться сервисом Pastie.

Pastie код
Pastie «умеет» подсвечивать код ActionScript, C/C++, CSS, Diff, HTML (ERB / Rails), HTML / XML, Java, Javascript, Objective C/C++, Pascal, Perl, PHP, Plain text, Python, Ruby, Ruby (on Rails), Shell Script (Bash), SQL, YAML. Вставьте полученный код javascript в ваш блог и подсветка кода готова.

Код Pastie в блоге
Второй, неявный способ применения Pastie -- обмен фрагментами кода. Удобно при удаленной разработке в команде.

P.S. Pastie написан на Ruby on Rails.


Читать дальше »

вторник, 10 февраля 2009 г.

Заставить IE создать элемент style

Сегодня с помощью JavaScript динамически создавал HTML элемент <style> внутри <iframe>. Да, мы, бля, не ищем легких путей ;). В Firefox срабатывает на «отлично», но как всегда не обошлось без сюрпризов от IE. И никакие «умные» (даже затрудняюсь в выборе кавычек) способы не помогали.

Зато вот какой шикарный трюк нагуглил:
var CSS = 'body { margin: 0px; }';
var htmDiv = document.createElement('div');
htmDiv.innerHTML = '<p>x</p><style>'+CSS+'</style>';
document.body.appendChild(htmDiv.childNodes[1]);

Работает в IE6 and IE7 и в нормальных браузерах.

Читать дальше »

четверг, 5 февраля 2009 г.

Javascript. Пляски с ифреймом

Как получить содержимое iframe с помощью Javascript:

function getContentFromIframe(iFrameName){
var iFrame = document.getElementById(iFrameName);
var content = iFrame.contentWindow.document.body.innerHTML;
//Любые операции с содержимым iframe
}

И наоборот.
Из iframe выполнить функцию в «родительском» окне.

parentReloadImages = function(){
parent.xajax_reloadImages();
}

parent -- как раз и есть ссылка на родительское окно.
Читать дальше »

среда, 28 января 2009 г.

Radio group value с помощью Javascript

Недавно начал разрабатывать инструментарий для управления стилями шаблона пользователя, основанными на использовании переменных CSS. Задумал нечто похожее на реализацию в Blogger инструмента «Шрифты и Цвета».

В процессе написания javascript класса столкнулся с проблемой: как получить значение группы радио переключателей (radio group)?

Дело в том, что каждый переключатель имеет собственный id и собственное значение value. В группу же они объединяются по атрибуту name (name у них одинаковый).

<input type="radio" name="font-face" id="font-face-georgia" value="Georgia, Times, serif" />
<label for="font-face-georgia" style="font-family: Georgia;" class="font-label">Georgia</label>

<input type="radio" name="font-face" id="font-face-arial" value="Arial, sans-serif" />
<label class="font-label" style="font-family: Arial;" for="font-face-arial">Arial</label>

<input type="radio" name="font-face" id="font-face-courier" value="Courier, monospace" />
<label for="font-face-courier" style="font-family: Courier;" class="font-label">Courier</label>

При обработке/отправке формы (form) отправляется value переключателя, у которого установлен атрибут checked или checked="checked".

Radio group value на «чистом» javascript


var radioGrp = document['forms']['form_name_or_id']['radio_grp_name'];
for(i=0; i < radioGrp.length; i++){
if (radioGrp[i].checked == true){
var radioValue = radioGrp[i].value;
}
}

В данном случае вы должны знать name или id формы и name группы переключателей.

Radio group value с использованием Prototype javascript


Внимание: в данном примере используется javascript-фреймворк Prototype.
function $RF(el, radioGroup) {
if($(el).type && $(el).type.toLowerCase() == 'radio') {
var radioGroup = $(el).name;
var el = $(el).form;
} else if ($(el).tagName.toLowerCase() != 'form') {
return false;
}

var checked = $(el).getInputs('radio', radioGroup).find(
function(re) {return re.checked;}
);
return (checked) ? $F(checked) : null;
}

В этом случае вы получаете доступ к элементу или через form (id или object) и radio group name, или посредством radio button (id или object).
var value = $RF('radio_btn_id'); 
var value = $RF('form_id', 'radio_grp_name');

Лично мне этот способ помог. Надеюсь, еще кому-нибудь пригодится.

Копирайты

Читать дальше »

понедельник, 26 января 2009 г.

Flash облако тегов

“Blobumus” -- это основанное на Flash облако тегов, использующее сконвертированные скрипты, с Roy Tanck's WP Cumulus plugin для Wordpress. Этот виджет использует комбинацию JavaScript и Flash-анимации для разбора и отображения ярлыков вашего блога.



Установка “Blobumus”


Установка этого виджета довольно проста:
  1. На панели управления вашего блога: Макет - Изменить HTML;
  2. Щелкните крыжик «Расширить шаблоны виджета» и найдите следующую строчку (или похожую):

  3. <b:section class='sidebar' id='sidebar' preferred='yes'>

  4. Сразу после этой строки вставьте следующий код:

  5. <b:widget id='Label99' locked='false' title='Labels' type='Label'>
    <b:includable id='main'>
    <b:if cond='data:title'>
    <h2><data:title/></h2>
    </b:if>
    <div class='widget-content'>

    <script src='http://halotemplates.s3.amazonaws.com/wp-cumulus-example/swfobject.js' type='text/javascript'/>
    <div id='flashcontent'>Blogumulus by <a href='http://www.roytanck.com/'>Roy Tanck</a> and <a href='http://www.bloggerbuster.com'>Amanda Fazani</a></div>
    <script type='text/javascript'>

    var so = new SWFObject(&quot;http://halotemplates.s3.amazonaws.com/wp-cumulus-example/tagcloud.swf&quot;, &quot;tagcloud&quot;, &quot;240&quot;, &quot;300&quot;, &quot;7&quot;, &quot;#ffffff&quot;);
    // uncomment next line to enable transparency

    //so.addParam(&quot;wmode&quot;, &quot;transparent&quot;);
    so.addVariable(&quot;tcolor&quot;, &quot;0x333333&quot;);
    so.addVariable(&quot;mode&quot;, &quot;tags&quot;);

    so.addVariable(&quot;distr&quot;, &quot;true&quot;);
    so.addVariable(&quot;tspeed&quot;, &quot;100&quot;);
    so.addVariable(&quot;tagcloud&quot;, &quot;<tags><b:loop values='data:labels' var='label'><a expr:href='data:label.url' style='12'><data:label.name/></a></b:loop></tags>&quot;);

    so.addParam(&quot;allowScriptAccess&quot;, &quot;always&quot;);
    so.write(&quot;flashcontent&quot;);
    </script>

    <b:include name='quickedit'/>

    </div>
    </b:includable>
    </b:widget>

  6. Щелкните «просмотр»

  7. Если установленно корректно, вы должны увидеть ваше флеш-облако тегов в боковой панели Blogger;
  8. Сохраните шаблон.

Настройка “Blobumus”


По умолчанию, flash-облако тегов “Blobumus” использует следующие установки:
  • Ширина: 240px;
  • Высота: 300px;
  • Цвет фона: белый (#FFFFFF);
  • Цвет текста: темно-серый (#333333);
  • Размер шрифта: 12.

Настройка размеров
Размеры заданы в следующей строке кода:
var so = new SWFObject("http://halotemplates.s3.amazonaws.com/wp-cumulus-example/tagcloud.swf", "tagcloud", "240", "300", "7", "#ffffff");

Где 240 и 300 -- соответственно, ширина и высота.

Настройка фона
В предыдущем фрагменте кода цвет фона задан как "#ffffff" (белый). Для примера вы можете изменить его на "#C61B1B". Чтобы сделать фон прозрачным, раcкомментируйте (уберите "//" в начале строки) следующую строчку кода:
//so.addParam(&quot;wmode&quot;, &quot;transparent&quot;);


Изменить цвет текста
Цвет текста задается в строке:
so.addVariable(&quot;tcolor&quot;, &quot;0x333333&quot;);

Замените 0x333333 например на 0xE3635C.

Изменить размер шрифта
Найдите следующую строку:
so.addVariable(&quot;tagcloud&quot;, &quot;<tags><b:loop values='data:labels' var='label'><a expr:href='data:label.url' style='12'><data:label.name/></a></b:loop></tags>&quot;);

Замените 12 на 14 или как захотите.


UPD: Добавлено обновленное

облако тегов с поддержкой русского языка

.

Читать дальше »

воскресенье, 18 января 2009 г.

Облако тегов для Blogger

tag cloudОдна из недоработок виджетов Blogger -- отсутствие виджета для Облака Тегов (Tag Cloud). В отличие от прочих решений для Облака Тегов, данное решение работает.

1. Сделайте резервную копию шаблона Blogger.

2. У вас уже должно быть несколько сообщений с тегами (ярлыками). Добавьте элемент Ярлыки на странице Макет - Элементы страницы.

3. Добавьте стили CSS для отображения тегов. На странице Макет - Изменить HTML сразу перед закрывающим тегом ]]></b:skin>.
/* Label Cloud Styles */
#labelCloud {text-align:center;font-family:arial,sans-serif;}
#labelCloud .label-cloud li{display:inline;background-image:none !important;padding:0 5px;margin:0;vertical-align:baseline !important;border:0 !important;}
#labelCloud ul{list-style-type:none;margin:0 auto;padding:0;}
#labelCloud a img{border:0;display:inline;margin:0 0 0 3px;padding:0}
#labelCloud a{text-decoration:none}
#labelCloud a:hover{text-decoration:underline}
#labelCloud li a{}
#labelCloud .label-cloud {}
#labelCloud .label-count {padding-left:0.2em;font-size:9px;color:#000}
#labelCloud .label-cloud li:before{content:"" !important}


4. Вставьте следующий код сразу после ]]></b:skin>, но перед тегом </head>.
<script type='text/javascript'>
// Label Cloud User Variables
var cloudMin = 1;
var maxFontSize = 20;
var maxColor = [122,109,85];
var minFontSize = 10;
var minColor = [0,0,0];
var lcShowCount = false;
</script>


5. Сохраните шаблон.

6. Включите опцию расширить шаблоны виджета и найдите примерно такую строчку: <b:widget id='Label1' locked='false' title='Labels' type='Label'/>

7. Удалите все строки между <b:widget id='Label1' locked='false' title='Labels' type='Label'/> и следующим тегом </b:widget>

8. Вставьте следующий код вместо удаленного.
<b:widget id='Label1' locked='false' title='Модное облако тегов' type='Label'>
<b:includable id='main'>
<b:if cond='data:title'>
<h2><data:title/></h2>
</b:if>

<div class='widget-content'>
<div id='labelCloud'/>
<script type='text/javascript'>

// Don't change anything past this point -----------------
// Cloud function s() ripped from del.icio.us
function s(a,b,i,x){
if(a &gt; b){
var m=(a-b)/Math.log(x),v=a-Math.floor(Math.log(i)*m)
}
else{
var m=(b-a)/Math.log(x),v=Math.floor(Math.log(i)*m+a)
}
return v
}


var c=[];
var labelCount = new Array();
var ts = new Object;
<b:loop values='data:labels' var='label'>
var theName = "<data:label.name/>";
ts[theName] = <data:label.count/>;
</b:loop>

for (t in ts){
if (!labelCount[ts[t]]){
labelCount[ts[t]] = new Array(ts[t])
}
}
var ta=cloudMin-1;
tz = labelCount.length - cloudMin;
lc2 = document.getElementById('labelCloud');
ul = document.createElement('ul');
ul.className = 'label-cloud';
for(var t in ts){
if(ts[t] &lt; cloudMin){
continue;
}
for (var i=0;3 &gt; i;i++) {
c[i]=s(minColor[i],maxColor[i],ts[t]-ta,tz)
}
var fs = s(minFontSize,maxFontSize,ts[t]-ta,tz);
li = document.createElement('li');
li.style.fontSize = fs+'px';
li.style.lineHeight = '1';
a = document.createElement('a');
a.title = ts[t]+' Posts in '+t;
a.style.color = 'rgb('+c[0]+','+c[1]+','+c[2]+')';
a.href = '/search/label/'+encodeURIComponent(t);
if (lcShowCount){
span = document.createElement('span');
span.innerHTML = '('+ts[t]+') ';
span.className = 'label-count';
a.appendChild(document.createTextNode(t));
li.appendChild(a);
li.appendChild(span);
}
else {
a.appendChild(document.createTextNode(t));
li.appendChild(a);
}
ul.appendChild(li);
abnk = document.createTextNode(' ');
ul.appendChild(abnk);
}
lc2.appendChild(ul);
</script>

<noscript>
<ul>
<b:loop values='data:labels' var='label'>
<li>
<b:if cond='data:blog.url == data:label.url'>
<data:label.name/>
<b:else/>
<a expr:href='data:label.url'><data:label.name/></a>
</b:if>
(<data:label.count/>)
</li>
</b:loop>
</ul>
</noscript>
<b:include name='quickedit'/>
</div>

</b:includable>
</b:widget>


6. Сохраните шаблон

Если все сделали правильно, то ваш виджет «Ярлыки» будет заменен «Облаком тегов».

Настройки виджета:
var cloudMin = 1; // количество отображаемых тегов. Если 1, то все.
var maxFontSize = 20; // максимальный размер шрифта
var maxColor = [122,109,85]; // максимальный цвет
var minFontSize = 10; // минимальный размер шрифта
var minColor = [0,0,0]; // минимальный цвет
var lcShowCount = false; // показывать/не показывать количество записей с тегом. false - не показывать.



Обновлено: Решение для ошибки с сохранением XML нашел блоггер 256, за что ему и спасибо.

Проблема заключалась в знаках «больше», «меньше». Коды в этой статье уже исправлены.


Облако тегов от Blogger


Читать дальше »

пятница, 9 января 2009 г.

Yahoo Samsung Internet@TV


Компания Samsung совместно с крупнейшим порталом Yahoo объявили о сотрудничестве по разработке нового интернет-сервиса “Internet@TV - Content Service”, который будет запущен весной 2009. Для этого отдельные модели телевизоров Samsung HDTV будут оснащены встроенным програмным комплектом Yahoo! Widget Engine, который позволит зрителям осуществлять интерактивный просмотр программ при помощи набора “TV Widgets”.

TV Widgets дадут возможность управлять пользователям интернет-контентом и расширить возможности просмотра телевизионных каналов за счет программ и каналов в сети Интернет. Сервис, разработанный с использованием Javascript и XML позволит осуществлять поиск по видеороликам, просматривать видеоконтент и участвовать в работе социальных сетей и приложений. Таким образом обыкновенный телевизор превратится в интерактивное устройство для глобальной сети.

Набор TV Widgets позволит работать также с такими порталами как с Flickr, Yahoo! News, Yahoo! Weather и Yahoo! Finance и просматривать видео на ряде других сервисолв, к примеру USA TODAY, YouTube, eBay и Showtime Networks.
Читать дальше »

ColorPicker - инструмент для выбора цвета

ColorPickerЭтот JavaScript-компонент предоставляет простой и удобный инструмент для выбора HSV цвета.

Как добавить ColorPicker


  1. включите файлы javascript в секции HEAD
  2. добавьте ссылку на файл стилей colorpicker.css в секции HEAD
  3. добавьте поле input для хранения/отправки 16-ричного значения цвета (без ведущего #)
  4. инициализируйте ColorPicker

<script type="text/javascript">
new Control.ColorPicker("colorFieldName");
</script>

Внимание: Не вызывайте "new Control.ColorPicker()" пока не закроете все окружающие форму (form) блочные элементы (напр. div). В противном случае это вызовет ошибку IE Operation Aborted в IE 6/7. Вместо этого используйте:
Event.observe(window, "load", function() { 
new Control.ColorPicker("colorfield4", { "swatch" : "colorbox4" })
});

Этот способ в «чистом» виде непригоден для AJAX-методов, поэтому рекомендую вынести его в отдельную функцию, которую вызывать каждый раз, когда аяксовый метод отработал.

яваскрипт (javascript)


<script type="text/javascript">
//<![CDATA[
function activateColorPicker(){
cp_Label = new Control.ColorPicker("label_color", { "swatch" : "inside_color1" });
}
// first time Run (for IE)
Event.observe(window, "load", function() {
activateColorPicker();
});
//]]>
</script>

ajax_delete_label.rjs : Пример вызова функции для Ruby on Rails.


page.replace_html 'labels_container', :partial => 'custom_labels'
page.call 'activateColorPicker'

Скачать ColorPicker можно с его страницы в Google Code: colorpickerjs.
Читать дальше »

среда, 26 ноября 2008 г.

Тестер RegExp - регулярных выражений

Нашел полезный инструмент для тестирования регулярных выражений (RegExp) JavaScript. Нужно ввести шаблон (регулярное выражение) и проверяемый объект. Тестер выполняет операции:
String.match(pattern)
Проверяет совпадение заданной строки (String) регулярному выражению (pattern). С флагом g возвращает массив совпадений, без флага g возвращает первое совпадение. Если совпадений не найдено, возвращает null.
String.replace(pattern, string)
Заменяет совпадения заданной строкой и возвращает полученную строку.

Тестер регулярных выражений (RegExp) на JavaScript


RegExp:

Subject string:

Replacement text:

Result:



Ссылка: Online Regular Expression Tester
Читать дальше »

пятница, 21 ноября 2008 г.

Ошибка Internet Explorer: Операция прервана

Время от времени, особенно когда web-разработка вам начинает казаться на редкость простым и приятным делом, вы натыкаетесь на это:

Ошибка Microsoft Internet Explorer: Не удалось открыть узел... Операция прервана.
Error: Internet Explorer cannot open the Internet site. Operation aborted
IE Не удалось открыть узел. Операция прервана
В интернете вы скорее всего найдёте только одну причину, вызывающую эту ошибку. Видимо мне исключительно "повезло" -- я знаю целых 3 (три!).

1. Первая -- самая известная. Вы без труда найдёте её описание и решение в любом поисковике (я даже ссылки дам). Это ошибка DOM и JavaScript.

Это вызовет ошибку в IE


<html>
<head>
<script type="text/javascript">
function appendElementToBody() {
var span = document.createElement('span');
document.body.appendChild(span);
}
</script>
</head>
<body>
<table>
<tr>
<td>
<script type="text/javascript">
appendElementToBody();
</script>
</td>
</tr>
</table>
</body>
</html>

a) Дело в том, что вы не можете добавлять в элемент BODY из скрипта (javascript), который не является прямым потомком BODY;
b)Более того: вы не можете изменять родительский элемент из скрипта, являющегося его потомком.

Решение проблемы (фрагмент):


<body>
<table>
<tr>
<td>
...
</td>
</tr>
</table>
<script type="text/javascript">
appendElementToBody();
</script>
</body>

Это был первый случай. Два других не столь распространенныё, но описать их проще.
2. Wrong HTML code при использовании SSL
Причиной служит корявый HTML-код. Чаще всего наблюдается при защищенном соединении (по протоколу https://).
Решение: Перепроверьте, нет ли у вас «пересекающихся» элементов, все ли теги закрыты и т.п.

Третий случай совсем не тривиальный и довольно редкий
3. «Tabs in ERb views»
ХЗ, это уже просто «родной» глюк Ruby on Rails. Только вот один момент: иногда табы в видах .rhtml прокатывают. Их и не замечаешь пока не начнешь тестить страницу в IE. Опять-таки, чаще всего по https:. «Мистика», а бывает :).
Решение: не используйте символы табуляции в .rhtml

А вот и ссылки (только по первому случаю):
BUG: Error message when you visit a Web page or interact with a Web application in Internet Explorer: "Operation aborted"
Error: Internet Explorer cannot open the Internet site Operation aborted
Dealing with IE "Operation Aborted". Or, how to Crash IE


Еще по теме
Определить IE6 с помощью JavaScript 2
IE8 узнайте факты!
IE и параметр white-space:pre

Читать дальше »

вторник, 11 ноября 2008 г.

XML термин CDATA

Элемент CDATA содержит в себе текстовые данные, которые не должны быть проанализированы XML-парсером.


Дополнение: по-умолчанию, парсер воспринимает их как PCDATA.


Такие символы как "<" и "&", содержащиеся в тексте, вызовут ошибку XML.


Символ "<" XML-парсер интерпретирует как начало нового элемента. А символ "&" – как начало сущности.


Некоторые текстовые данные, например JavaScript, могут содержать множество символов "<" или "&". Чтобы избежать ошибок, такие блоки должны быть определены как CDATA.


Всё внутри секции CDATA игнорируется XML-парсером.


Секция CDATA начинается с "<![CDATA[" и заканчивается "]]>".


Пример использования CDATA


Читать дальше »