четверг, 19 сентября 2013 г.
Всплывающий календарь с указанием даты и времени
Файл index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="style/default/index.css" rel="stylesheet" type="text/css">
<script data-main="js/index.js" src="js/lib/require/require.js"></script>
<title>Календарь</title>
</head>
<body>
<div id="grid">
<div id="sessions-start-time" class="calendar">
<input class="calendar-input" type="text" size="19" name="session-time" value="12/02/2012 23:12:30" data-date="12.02.2012.23.12.30"><span class="calendar-button"><i class="calendar-icon"></i></span>
<div class="calendar-datepicker hidden">
<div class="calendar-datepicker-border-arrow"></div>
<table class="period-selector">
<tr>
<td class="prev-month"><div class="arrow left"></div></td>
<td class="select-month"><select>
<option value="1" selected="selected">Январь</option>
<option value="2">Февраль</option>
<option value="3">Март</option>
<option value="4">Апрель</option>
<option value="5">Май</option>
<option value="6">Июнь</option>
<option value="7">Июль</option>
<option value="8">Август</option>
<option value="9">Сентябрь</option>
<option value="10">Октябрь</option>
<option value="11">Ноябрь</option>
<option value="12">Декабрь</option>
</select></th>
<td class="next-month"><div class="arrow right"></div></td>
<td class="prev-year"><div class="arrow left"></div></td>
<td class="select-year"><select>
<option value="2014">2014</option>
<option value="2013">2013</option>
<option value="2012" selected="selected">2012</option>
<option value="2011">2011</option>
<option value="2010">2010</option>
<option value="1970">1970</option>
</select></th>
<td class="next-year"><div class="arrow right"></div></td>
</tr>
</table>
<table class="day-selector">
<thead>
<tr>
<th class="dow">Пн</th>
<th class="dow">Вт</th>
<th class="dow">Ср</th>
<th class="dow">Чт</th>
<th class="dow">Пт</th>
<th class="dow">Сб</th>
<th class="dow">Вс</th>
</tr>
</thead>
<tbody>
<tr>
<td class="day old">29</td>
<td class="day old">30</td>
<td class="day old">31</td>
<td class="day">1</td>
<td class="day">2</td>
<td class="day">3</td>
<td class="day">4</td>
</tr>
<tr>
<td class="day">5</td>
<td class="day">6</td>
<td class="day">7</td>
<td class="day">8</td>
<td class="day">9</td>
<td class="day">10</td>
<td class="day">11</td>
</tr>
<tr>
<td class="day active">12</td>
<td class="day">13</td>
<td class="day">14</td>
<td class="day">15</td>
<td class="day">16</td>
<td class="day">17</td>
<td class="day">18</td>
</tr>
<tr>
<td class="day">19</td>
<td class="day">20</td>
<td class="day">21</td>
<td class="day">22</td>
<td class="day">23</td>
<td class="day">24</td>
<td class="day">25</td>
</tr>
<tr>
<td class="day">26</td>
<td class="day">27</td>
<td class="day">28</td>
<td class="day">29</td>
<td class="day new">1</td>
<td class="day new">2</td>
<td class="day new">3</td>
</tr>
<tr>
<td class="day new">4</td>
<td class="day new">5</td>
<td class="day new">6</td>
<td class="day new">7</td>
<td class="day new">8</td>
<td class="day new">9</td>
<td class="day new">10</td>
</tr>
</tbody>
</table>
<table class="time-selector">
<tr>
<td> </td>
<td class="next-hour"><div class="arrow up"></div></td>
<td> </td>
<td class="next-minute"><div class="arrow up"></div></td>
<td> </td>
<td class="next-second"><div class="arrow up"></div></td>
<td> </td>
</tr>
<tr>
<td><div class="clock"></div></td>
<td class="select-hour"><select>
<option value="0" selected="selected">00</option>
<option value="1">01</option>
<option value="2">02</option>
<option value="3">03</option>
<option value="4">04</option>
<option value="5">05</option>
<option value="6">06</option>
<option value="7">07</option>
<option value="8">08</option>
<option value="9">09</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
</select></td>
<td>ч</td>
<td class="select-minute"><select>
<option value="0" selected="selected">00</option>
<option value="1">01</option>
<option value="2">02</option>
<option value="3">03</option>
<option value="4">04</option>
<option value="5">05</option>
<option value="6">06</option>
<option value="7">07</option>
<option value="8">08</option>
<option value="9">09</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="28">28</option>
<option value="29">29</option>
<option value="30">30</option>
<option value="31">31</option>
<option value="32">32</option>
<option value="33">33</option>
<option value="34">34</option>
<option value="35">35</option>
<option value="36">36</option>
<option value="37">37</option>
<option value="38">38</option>
<option value="39">39</option>
<option value="40">40</option>
<option value="41">41</option>
<option value="42">42</option>
<option value="43">43</option>
<option value="44">44</option>
<option value="45">45</option>
<option value="46">46</option>
<option value="47">47</option>
<option value="48">48</option>
<option value="49">49</option>
<option value="50">50</option>
<option value="51">51</option>
<option value="52">52</option>
<option value="53">53</option>
<option value="54">54</option>
<option value="55">55</option>
<option value="56">56</option>
<option value="57">57</option>
<option value="58">58</option>
<option value="59">59</option>
</select></td>
<td>м</td>
<td class="select-second"><select>
<option value="0" selected="selected">00</option>
<option value="1">01</option>
<option value="2">02</option>
<option value="3">03</option>
<option value="4">04</option>
<option value="5">05</option>
<option value="6">06</option>
<option value="7">07</option>
<option value="8">08</option>
<option value="9">09</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="28">28</option>
<option value="29">29</option>
<option value="30">30</option>
<option value="31">31</option>
<option value="32">32</option>
<option value="33">33</option>
<option value="34">34</option>
<option value="35">35</option>
<option value="36">36</option>
<option value="37">37</option>
<option value="38">38</option>
<option value="39">39</option>
<option value="40">40</option>
<option value="41">41</option>
<option value="42">42</option>
<option value="43">43</option>
<option value="44">44</option>
<option value="45">45</option>
<option value="46">46</option>
<option value="47">47</option>
<option value="48">48</option>
<option value="49">49</option>
<option value="50">50</option>
<option value="51">51</option>
<option value="52">52</option>
<option value="53">53</option>
<option value="54">54</option>
<option value="55">55</option>
<option value="56">56</option>
<option value="57">57</option>
<option value="58">58</option>
<option value="59">59</option>
</select></td>
<td>с</td>
</tr>
<tr>
<td> </td>
<td class="prev-hour"><div class="arrow down"></div></td>
<td> </td>
<td class="prev-minute"><div class="arrow down"></div></td>
<td> </td>
<td class="prev-second"><div class="arrow down"></div></td>
<td> </td>
</tr>
<tr>
<td class="now" colspan="7">Сейчас</td>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>
Файл index.css
/******************************************************************\
Reset CSS
\******************************************************************/
html {
font-size: 100.01%; /* Bug fix for Opera */
}
body {
width: 1000px;
position: relative; /* Bug fix for IE 6 */
margin: 0;
padding: 0;
margin-left: auto;
margin-right: auto;
text-align: center;
font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif;
font-size: 62.5%;
background-color: #ffffff;
color: #333333;
}
div,h1,h2,h3,h4,h5,h6,p,img,ol,ul,li,table,th,td,form,select,fieldset {
margin: 0;
padding: 0;
text-align: left;
}
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block;
}
ol,ul {
list-style: none;
}
table {
border: 0px; /* border="0" */
border-collapse: collapse; /* cellspacing="0" */
}
table tr th {
padding: 0px; /* cellpadding="0" */
}
table tr td {
padding: 0px; /* cellpadding="0" */
}
input,textarea,select {
font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif;
font-size: 1.0em;
color: #333333;
}
textarea {
resize: none;
}
a img {
border: none;
}
a {
color: #333333;
text-decoration: underline;
}
a:link {
color: #333333;
text-decoration: underline;
}
a:visited {
color: #333333;
text-decoration: underline;
}
a:hover {
color: #333333;
text-decoration: none;
}
a:active {
color: #333333;
text-decoration: none;
}
a:active,a:focus,img {
outline: 0; /* Firefox anchor border remove */
}
/*****************************************************************\
Common classes
\*****************************************************************/
.hidden {
display: none !important;
}
/******************************************************************\
Grid
\******************************************************************/
div#grid {
font-size: 1.2em;
}
/******************************************************************\
Selectbox
\******************************************************************/
div.selectbox {
position: relative;
zoom: 1;
display: inline-block;
*display: inline;
_display: inline;
width: 100%;
height: 20px;
line-height: 20px;
background-color: #ffffff;
border: 1px solid #bbbbbb;
vertical-align: top;
cursor: default;
}
div.selectbox div.selectbox-label {
overflow: hidden;
height: 20px;
margin-right: 20px;
text-indent: 5px;
}
div.selectbox div.selectbox-button {
position: absolute;
width: 20px;
height: 20px;
top: 0;
right: 0;
background: url(img/icons/selectbox.png) no-repeat 0 0;
}
div.selectbox ul.selectbox-dropbox {
display: none;
overflow: hidden;
overflow-y: auto;
position: absolute;
z-index: 100;
width: 100%;
max-height: 150px;
_height: expression(this.scrollHeight > 150 ? '150px' : 'auto');
line-height: 1.5em;
margin-left: -1px;
background-color: #ffffff;
border: 1px solid #bbbbbb;
}
div.selectbox ul.selectbox-dropbox li.selectbox-option {
position: relative;
display: block;
padding: 1px 5px;
}
div.selectbox ul.selectbox-dropbox li.hover {
background: #40c0c0;
color: #ffffff;
}
/******************************************************************\
Calendar
\******************************************************************/
div.calendar {
position: relative;
display: inline-block;
*display: inline;
_display: inline;
}
div.calendar input.calendar-input {
display: inline-block;
*display: inline;
_display: inline;
width: 150px;
height: 20px;
line-height: 20px;
padding: 4px 6px;
border: 1px solid #cccccc;
font-size: 1.2em;
vertical-align: top;
}
div.calendar span.calendar-button {
display: inline-block;
*display: inline;
_display: inline;
height: 20px;
line-height: 20px;
width: 16px;
margin-left: -1px;
padding: 4px 5px;
background-color: #eeeeee;
border: 1px solid #cccccc;
vertical-align: top;
font-size: 1.2em;
text-align: center;
cursor: pointer;
}
div.calendar span.calendar-button i.calendar-icon {
display: block;
width: 11px;
height: 12px;
margin-top: 3px;
margin-left: auto;
margin-right: auto;
background: url(img/icons/calendar.gif) no-repeat 0 0;
}
div.calendar div.calendar-datepicker {
position: absolute;
margin-top: 6px;
padding: 4px;
background-color: #ffffff;
border: 1px solid #cccccc;
z-index: 1000;
}
div.calendar div.calendar-datepicker-border-arrow {
width: 14px;
height: 7px;
margin-top: -11px;
margin-left: auto;
margin-right: auto;
background: url(img/icons/border-arrow.gif) no-repeat 0 0;
}
div.calendar div.calendar-datepicker table {
margin-top: 4px;
}
div.calendar div.calendar-datepicker table tr td select {
height: 20px;
line-height: 20px;
border: 1px solid #cccccc;
}
div.calendar div.selectbox {
height: 18px;
line-height: 18px;
}
div.calendar div.selectbox div.selectbox-label {
height: 18px;
margin-right: 5px;
text-indent: 5px;
}
div.calendar div.selectbox div.selectbox-button {
width: 17px;
height: 18px;
background: url(img/icons/selectbox-small.png) no-repeat 0 0;
}
div.calendar div.selectbox ul.selectbox-dropbox li.selectbox-option {
padding: 1px 5px;
}
div.calendar div.calendar-datepicker table tr td.select-month select {
width: 80px;
}
div.calendar div.calendar-datepicker table tr td.select-month div.selectbox {
width: 80px;
}
div.calendar div.calendar-datepicker table tr td.select-month div.selectbox ul.selectbox-dropbox {
width: 80px;
}
div.calendar div.calendar-datepicker table tr td.select-year select {
width: 55px;
}
div.calendar div.calendar-datepicker table tr td.select-year div.selectbox {
width: 55px;
}
div.calendar div.calendar-datepicker table tr td.select-year div.selectbox ul.selectbox-dropbox {
width: 55px;
}
div.calendar div.calendar-datepicker table tr td.select-hour select,
div.calendar div.calendar-datepicker table tr td.select-minute select,
div.calendar div.calendar-datepicker table tr td.select-second select {
width: 40px;
}
div.calendar div.calendar-datepicker table tr td.select-hour div.selectbox,
div.calendar div.calendar-datepicker table tr td.select-minute div.selectbox,
div.calendar div.calendar-datepicker table tr td.select-second div.selectbox {
width: 40px;
}
div.calendar div.calendar-datepicker table tr td.select-hour div.selectbox ul.selectbox-dropbox,
div.calendar div.calendar-datepicker table tr td.select-minute div.selectbox ul.selectbox-dropbox,
div.calendar div.calendar-datepicker table tr td.select-second div.selectbox ul.selectbox-dropbox {
width: 40px;
}
div.calendar div.calendar-datepicker table tr td div.arrow {
width: 10px;
height: 10px;
background: url(img/icons/arrows.gif) no-repeat;
}
div.calendar div.calendar-datepicker table tr td div.left {
background-position: 0px 0px;
}
div.calendar div.calendar-datepicker table tr td div.right {
background-position: -10px 0px;
}
div.calendar div.calendar-datepicker table tr td div.up {
background-position: -20px 0px;
}
div.calendar div.calendar-datepicker table tr td div.down {
background-position: -30px 0px;
}
div.calendar div.calendar-datepicker table tr td div.clock {
width: 12px;
height: 12px;
background: url(img/icons/clock.gif) no-repeat 0px 0px;
}
div.calendar div.calendar-datepicker table.period-selector tr td {
width: 20px;
height: 20px;
padding: 4px 5px;
text-align: center;
}
div.calendar div.calendar-datepicker table.period-selector tr td.prev-month,
div.calendar div.calendar-datepicker table.period-selector tr td.next-month,
div.calendar div.calendar-datepicker table.period-selector tr td.prev-year,
div.calendar div.calendar-datepicker table.period-selector tr td.next-year {
cursor: pointer;
}
div.calendar div.calendar-datepicker table.period-selector tr td.prev-month:hover,
div.calendar div.calendar-datepicker table.period-selector tr td.next-month:hover,
div.calendar div.calendar-datepicker table.period-selector tr td.prev-year:hover,
div.calendar div.calendar-datepicker table.period-selector tr td.next-year:hover {
background-color: #eeeeee;
}
div.calendar div.calendar-datepicker table.day-selector {
margin-left: auto;
margin-right: auto;
}
div.calendar div.calendar-datepicker table.day-selector tr th,
div.calendar div.calendar-datepicker table.day-selector tr td {
width: 24px;
height: 24px;
padding: 4px 5px;
text-align: center;
}
div.calendar div.calendar-datepicker table.day-selector tr td.day {
cursor: pointer;
}
div.calendar div.calendar-datepicker table.day-selector tr td.day:hover {
background-color: #eeeeee;
}
div.calendar div.calendar-datepicker table.day-selector tr td.old,
div.calendar div.calendar-datepicker table.day-selector tr td.new {
color: #999999;
}
div.calendar div.calendar-datepicker table.day-selector tr td.active,
div.calendar div.calendar-datepicker table.day-selector tr td.active:hover {
background-color: #40c0c0;
color: #ffffff;
}
div.calendar div.calendar-datepicker table.time-selector tr td {
width: 24px;
height: 24px;
padding: 4px 5px;
text-align: center;
font-weight: bold;
}
div.calendar div.calendar-datepicker table tr td.select-hour,
div.calendar div.calendar-datepicker table tr td.select-minute,
div.calendar div.calendar-datepicker table tr td.select-second {
font-weight: normal;
}
div.calendar div.calendar-datepicker table.time-selector tr td.next-hour,
div.calendar div.calendar-datepicker table.time-selector tr td.prev-hour,
div.calendar div.calendar-datepicker table.time-selector tr td.next-minute,
div.calendar div.calendar-datepicker table.time-selector tr td.prev-minute,
div.calendar div.calendar-datepicker table.time-selector tr td.next-second,
div.calendar div.calendar-datepicker table.time-selector tr td.prev-second,
div.calendar div.calendar-datepicker table.time-selector tr td.now {
cursor: pointer;
}
div.calendar div.calendar-datepicker table.time-selector tr td.next-hour:hover,
div.calendar div.calendar-datepicker table.time-selector tr td.prev-hour:hover,
div.calendar div.calendar-datepicker table.time-selector tr td.next-minute:hover,
div.calendar div.calendar-datepicker table.time-selector tr td.prev-minute:hover,
div.calendar div.calendar-datepicker table.time-selector tr td.next-second:hover,
div.calendar div.calendar-datepicker table.time-selector tr td.prev-second:hover,
div.calendar div.calendar-datepicker table.time-selector tr td.now:hover {
background-color: #eeeeee;
}
div.calendar div.calendar-datepicker table.time-selector tr td div {
margin-left: auto;
margin-right: auto;
}
Файл index.js
require.config({
paths: {
jquery: 'lib/jquery/jquery'
}
});
require(
[
'jquery'
]
, function(
$
) {
// Всплывающий календарь
function createCalendar (calendarId) {
// Вспомогательные функции
function isLeapYear (year) {
return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
}
function getDaysInMonth (year, month) {
return [31, (isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1];
}
function addLeadingZero (value) {
return value < 10 ? '0' + value : value;
}
function removeLeadingZero (value) {
return parseInt(value, 10);
}
function normalizeYear (year) {
return year < 1000 ? year += 1900 : year;
}
function normalizeMonth (month) {
return month + 1;
}
function getCurrentDate () {
return new Date();
}
function getCurrentYear () {
return normalizeYear(getCurrentDate().getYear());
}
function getCurrentMonth () {
return normalizeMonth(getCurrentDate().getMonth());
}
function getCurrentDay () {
return getCurrentDate().getDate();
}
function getCurrentHour () {
return getCurrentDate().getHours();
}
function getCurrentMinute () {
return getCurrentDate().getMinutes();
}
function getCurrentSecond () {
return getCurrentDate().getSeconds();
}
function getNumberOfDayOfTheWeek (year, month, day) {
var dayNumber = new Date(year, month - 1, day).getDay();
return dayNumber === 0 ? dayNumber = 7 : dayNumber;
}
function createYearSelect (name, startYear, endYear) {
var select = '<select name="' + name + '">'
, i;
for (i = endYear; i >= startYear; i--) {
select += '<option value="' + i + '">' + i + '</option>';
}
select += '</select>'
return select;
}
function createMonthSelect (name) {
var select = '<select name="' + name + '">'
, months = [
'Январь', 'Февраль', 'Март'
, 'Апрель', 'Май', 'Июнь'
, 'Июль', 'Август', 'Сентябрь'
, 'Октябрь', 'Ноябрь', 'Декабрь'
]
, len = months.length
, i;
for (i = 0; i < len; i++) {
select += '<option value="' + (i+1) + '">' + months[i] + '</option>';
}
select += '</select>'
return select;
}
function createTimeSelect (name, startTime, endTime) {
var len = endTime - startTime
, select = '<select name="' + name + '">'
, i;
for (i = 0; i <= len; i++) {
select += '<option value="' + i + '">' + addLeadingZero (i) + '</option>';
}
select += '</select>'
return select;
}
// Изменение дизайна элемента <select>
function replaceStandartSelect (select) {
var selectOptions = select.find('option')
, selectOptionsLength = selectOptions.length
, selectedOptionText = ''
, selectbox = ''
, selectboxOptions = ''
, i;
selectOptions.eq(0).prop('selected', true);
for (i = 0; i < selectOptionsLength; i++) {
if (selectOptions.eq(i).is(':selected')) {
selectedOptionText = selectOptions.eq(i).text();
}
selectboxOptions += '<li class="selectbox-option">' + selectOptions.eq(i).text() + '</li>';
}
selectbox = '<div class="selectbox">'
+ '<div class="selectbox-label">' + selectedOptionText + '</div>'
+ '<div class="selectbox-button"></div>'
+ '<ul class="selectbox-dropbox">'
+ selectboxOptions
+ '</ul>'
+ '</div>';
select.hide();
selectbox = $(selectbox);
selectbox.insertAfter(select);
selectbox.find('.selectbox-label, .selectbox-button').click(function(event){
event.stopPropagation();
if (selectbox.find('.selectbox-dropbox').is(':visible')) {
selectbox.find('.selectbox-dropbox').hide();
} else {
selectbox.find('.selectbox-dropbox').show();
}
});
selectbox.find('.selectbox-option').hover(function(){
selectbox.find('.selectbox-option').removeClass('hover');
$(this).addClass('hover');
});
selectbox.find('.selectbox-dropbox .selectbox-option').click(function(event){
event.stopPropagation();
selectOptions.removeAttr('selected');
selectOptions.eq($(this).index()).attr('selected', true);
selectbox.find('.selectbox-label').text($(this).text());
selectbox.find('.selectbox-dropbox').hide();
// Установить дату и время
if (selectbox.parent().hasClass('select-month')) {
selectedMonth = $(this).index() + 1;
$('#' + calendarId + ' .day-selector tr td').removeClass('active');
selectedDay = 1;
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(0).addClass('active');
updateInputValue();
} else if (selectbox.parent().hasClass('select-year')) {
selectedYear = parseInt($(this).text(), 10);
$('#' + calendarId + ' .day-selector tr td').removeClass('active');
selectedDay = 1;
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(0).addClass('active');
updateInputValue();
} else if (selectbox.parent().hasClass('select-hour')) {
selectedHour = parseInt($(this).text(), 10);
updateInputValue();
} else if (selectbox.parent().hasClass('select-minute')) {
selectedMinute = parseInt($(this).text(), 10);
updateInputValue();
} else if (selectbox.parent().hasClass('select-second')) {
selectedSecond = parseInt($(this).text(), 10);
updateInputValue();
}
});
}
// Переменные, хранящие текущую выбранную дату и время
var selectedYear = getCurrentYear()
, selectedMonth = getCurrentMonth()
, selectedDay = getCurrentDay()
, selectedHour = getCurrentHour()
, selectedMinute = getCurrentMinute()
, selectedSecond = getCurrentSecond();
// Одноразовая запись первоначальных значений текущей даты и времени после загрузки страницы
updateInputValue();
// Функция обновления данных в input и data-date
function updateInputValue () {
var value = addLeadingZero(selectedDay) + '/'
+ addLeadingZero(selectedMonth) + '/'
+ selectedYear + ' '
+ addLeadingZero(selectedHour) + ':'
+ addLeadingZero(selectedMinute) + ':'
+ addLeadingZero(selectedSecond)
, date = addLeadingZero(selectedDay) + '.'
+ addLeadingZero(selectedMonth) + '.'
+ selectedYear + '.'
+ addLeadingZero(selectedHour) + '.'
+ addLeadingZero(selectedMinute) + '.'
+ addLeadingZero(selectedSecond);
$('#' + calendarId + ' .calendar-input').val(value).data('date', date);
}
// Функция отрисовки всего календаря
function renderCalendar () {
var date = $('#' + calendarId + ' .calendar-input').data('date').split('.');
selectedYear = removeLeadingZero(date[2]);
selectedMonth = removeLeadingZero(date[1]);
selectedDay = removeLeadingZero(date[0]);
selectedHour = removeLeadingZero(date[3]);
selectedMinute = removeLeadingZero(date[4]);
selectedSecond = removeLeadingZero(date[5]);
var calendar = '<div class="calendar-datepicker">'
+ '<div class="calendar-datepicker-border-arrow"></div>'
+ '<table class="period-selector">'
+ '<tr>'
+ '<td class="prev-month"><div class="arrow left"></div></td>'
+ '<td class="select-month">' + createMonthSelect ('months') + '</th>'
+ '<td class="next-month"><div class="arrow right"></div></td>'
+ '<td class="prev-year"><div class="arrow left"></div></td>'
+ '<td class="select-year">' + createYearSelect ('years', 1970, getCurrentYear() + 1) + '</th>'
+ '<td class="next-year"><div class="arrow right"></div></td>'
+ '</tr>'
+ '</table>'
+ '<table class="day-selector">'
+ '<thead>'
+ '<tr>'
+ '<th class="dow">Пн</th>'
+ '<th class="dow">Вт</th>'
+ '<th class="dow">Ср</th>'
+ '<th class="dow">Чт</th>'
+ '<th class="dow">Пт</th>'
+ '<th class="dow">Сб</th>'
+ '<th class="dow">Вс</th>'
+ '</tr>'
+ '</thead>'
+ '<tbody>'
+ '</tbody>'
+ '</table>'
+ '<table class="time-selector">'
+ '<tr>'
+ '<td> </td>'
+ '<td class="next-hour"><div class="arrow up"></div></td>'
+ '<td> </td>'
+ '<td class="next-minute"><div class="arrow up"></div></td>'
+ '<td> </td>'
+ '<td class="next-second"><div class="arrow up"></div></td>'
+ '<td> </td>'
+ '</tr>'
+ '<tr>'
+ '<td><div class="clock"></div></td>'
+ '<td class="select-hour">' + createTimeSelect ('hours', 0, 23) + '</td>'
+ '<td>ч</td>'
+ '<td class="select-minute">' + createTimeSelect ('minutes', 0, 59) + '</td>'
+ '<td>м</td>'
+ '<td class="select-second">' + createTimeSelect ('seconds', 0, 59) + '</td>'
+ '<td>с</td>'
+ '</tr>'
+ '<tr>'
+ '<td> </td>'
+ '<td class="prev-hour"><div class="arrow down"></div></td>'
+ '<td> </td>'
+ '<td class="prev-minute"><div class="arrow down"></div></td>'
+ '<td> </td>'
+ '<td class="prev-second"><div class="arrow down"></div></td>'
+ '<td> </td>'
+ '</tr>'
+ '<tr>'
+ '<td class="now" colspan="7">Сейчас</td>'
+ '</tr>'
+ '</table>'
+ '</div>';
$('#' + calendarId + ' .calendar-datepicker').replaceWith(calendar);
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(selectedDay - 1).addClass('active');
$('#' + calendarId + ' .select-month select option').eq(selectedMonth - 1).prop('selected', true);
$('#' + calendarId + ' .select-year select option[value="' + selectedYear + '"]').prop('selected', true);
$('#' + calendarId + ' .select-hour select option').eq(selectedHour).prop('selected', true);
$('#' + calendarId + ' .select-minute select option').eq(selectedMinute).prop('selected', true);
$('#' + calendarId + ' .select-second select option').eq(selectedSecond).prop('selected', true);
replaceStandartSelect($('#' + calendarId + ' .select-month select'));
replaceStandartSelect($('#' + calendarId + ' .select-year select'));
replaceStandartSelect($('#' + calendarId + ' .select-hour select'));
replaceStandartSelect($('#' + calendarId + ' .select-minute select'));
replaceStandartSelect($('#' + calendarId + ' .select-second select'));
$('#' + calendarId + ' .select-month .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-year .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-hour .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-minute .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-second .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).addClass('hover');
$('#' + calendarId + ' .select-year .selectbox-option:contains(' + selectedYear + ')').addClass('hover');
$('#' + calendarId + ' .select-hour .selectbox-option').eq(selectedHour).addClass('hover');
$('#' + calendarId + ' .select-minute .selectbox-option').eq(selectedMinute).addClass('hover');
$('#' + calendarId + ' .select-second .selectbox-option').eq(selectedSecond).addClass('hover');
$('#' + calendarId + ' .select-month .selectbox-label').text($('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).text());
$('#' + calendarId + ' .select-year .selectbox-label').text(selectedYear);
$('#' + calendarId + ' .select-hour .selectbox-label').text(addLeadingZero(selectedHour));
$('#' + calendarId + ' .select-minute .selectbox-label').text(addLeadingZero(selectedMinute));
$('#' + calendarId + ' .select-second .selectbox-label').text(addLeadingZero(selectedSecond));
// Скрытие селектов при клике по календарю и блокирование закрытия календаря при клике по нему
$('#' + calendarId + ' .calendar-datepicker').click(function(e){
$('#' + calendarId + ' .selectbox-dropbox').hide();
e.stopPropagation();
});
// Функции кликов по стрелкам календаря
$('#' + calendarId + ' .prev-month').click(function(){
if (selectedMonth === 1) {
selectedMonth = 12;
selectedYear -= 1;
} else {
selectedMonth -= 1;
}
selectedDay = 1;
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(0).addClass('active');
$('#' + calendarId + ' .select-month select option').eq(selectedMonth - 1).prop('selected', true);
$('#' + calendarId + ' .select-month .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).addClass('hover');
$('#' + calendarId + ' .select-month .selectbox-label').text($('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).text());
updateInputValue();
});
$('#' + calendarId + ' .next-month').click(function(){
$('#' + calendarId + ' .day-selector tr td').removeClass('active');
if (selectedMonth === 12) {
selectedMonth = 1;
selectedYear += 1;
} else {
selectedMonth += 1;
}
selectedDay = 1;
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(0).addClass('active');
$('#' + calendarId + ' .select-month select option').eq(selectedMonth - 1).prop('selected', true);
$('#' + calendarId + ' .select-month .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).addClass('hover');
$('#' + calendarId + ' .select-month .selectbox-label').text($('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).text());
updateInputValue();
});
$('#' + calendarId + ' .prev-year').click(function(){
if (selectedYear === 1970) {
selectedYear = 1970;
} else {
selectedYear -= 1;
}
selectedDay = 1;
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(0).addClass('active');
$('#' + calendarId + ' .select-year select option[value="' + selectedYear + '"]').prop('selected', true);
$('#' + calendarId + ' .select-year .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-year .selectbox-option:contains(' + selectedYear + ')').addClass('hover');
$('#' + calendarId + ' .select-year .selectbox-label').text(selectedYear);
updateInputValue();
});
$('#' + calendarId + ' .next-year').click(function(){
if (selectedYear === getCurrentYear() + 1) {
selectedYear === getCurrentYear() + 1;
} else {
selectedYear += 1;
}
selectedDay = 1;
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(0).addClass('active');
$('#' + calendarId + ' .select-year select option[value="' + selectedYear + '"]').prop('selected', true);
$('#' + calendarId + ' .select-year .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-year .selectbox-option:contains(' + selectedYear + ')').addClass('hover');
$('#' + calendarId + ' .select-year .selectbox-label').text(selectedYear);
updateInputValue();
});
$('#' + calendarId + ' .prev-hour').click(function(){
if (selectedHour === 0) {
selectedHour = 23;
} else {
selectedHour -= 1;
}
$('#' + calendarId + ' .select-hour select option').eq(selectedHour).prop('selected', true);
$('#' + calendarId + ' .select-hour .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-hour .selectbox-option').eq(selectedHour).addClass('hover');
$('#' + calendarId + ' .select-hour .selectbox-label').text(addLeadingZero(selectedHour));
updateInputValue();
});
$('#' + calendarId + ' .next-hour').click(function(){
if (selectedHour === 23) {
selectedHour = 0;
} else {
selectedHour += 1;
}
$('#' + calendarId + ' .select-hour select option').eq(selectedHour).prop('selected', true);
$('#' + calendarId + ' .select-hour .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-hour .selectbox-option').eq(selectedHour).addClass('hover');
$('#' + calendarId + ' .select-hour .selectbox-label').text(addLeadingZero(selectedHour));
updateInputValue();
});
$('#' + calendarId + ' .prev-minute').click(function(){
if (selectedMinute === 0) {
selectedMinute = 59;
} else {
selectedMinute -= 1;
}
$('#' + calendarId + ' .select-minute select option').eq(selectedMinute).prop('selected', true);
$('#' + calendarId + ' .select-minute .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-minute .selectbox-option').eq(selectedMinute).addClass('hover');
$('#' + calendarId + ' .select-minute .selectbox-label').text(addLeadingZero(selectedMinute));
updateInputValue();
});
$('#' + calendarId + ' .next-minute').click(function(){
if (selectedMinute === 59) {
selectedMinute = 0;
} else {
selectedMinute += 1;
}
$('#' + calendarId + ' .select-minute select option').eq(selectedMinute).prop('selected', true);
$('#' + calendarId + ' .select-minute .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-minute .selectbox-option').eq(selectedMinute).addClass('hover');
$('#' + calendarId + ' .select-minute .selectbox-label').text(addLeadingZero(selectedMinute));
updateInputValue();
});
$('#' + calendarId + ' .prev-second').click(function(){
if (selectedSecond === 0) {
selectedSecond = 59;
} else {
selectedSecond -= 1;
}
$('#' + calendarId + ' .select-second select option').eq(selectedSecond).prop('selected', true);
$('#' + calendarId + ' .select-second .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-second .selectbox-option').eq(selectedSecond).addClass('hover');
$('#' + calendarId + ' .select-second .selectbox-label').text(addLeadingZero(selectedSecond));
updateInputValue();
});
$('#' + calendarId + ' .next-second').click(function(){
if (selectedSecond === 59) {
selectedSecond = 0;
} else {
selectedSecond += 1;
}
$('#' + calendarId + ' .select-second select option').eq(selectedSecond).prop('selected', true);
$('#' + calendarId + ' .select-second .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-second .selectbox-option').eq(selectedSecond).addClass('hover');
$('#' + calendarId + ' .select-second .selectbox-label').text(addLeadingZero(selectedSecond));
updateInputValue();
});
$('#' + calendarId + ' .now').click(function(){
selectedYear = getCurrentYear();
selectedMonth = getCurrentMonth();
selectedDay = getCurrentDay();
selectedHour = getCurrentHour();
selectedMinute = getCurrentMinute();
selectedSecond = getCurrentSecond();
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(selectedDay - 1).addClass('active');
$('#' + calendarId + ' .select-month select option').eq(selectedMonth - 1).prop('selected', true);
$('#' + calendarId + ' .select-year select option[value="' + selectedYear + '"]').prop('selected', true);
$('#' + calendarId + ' .select-hour select option').eq(selectedHour).prop('selected', true);
$('#' + calendarId + ' .select-minute select option').eq(selectedMinute).prop('selected', true);
$('#' + calendarId + ' .select-second select option').eq(selectedSecond).prop('selected', true);
$('#' + calendarId + ' .select-month .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-year .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-hour .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-minute .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-second .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).addClass('hover');
$('#' + calendarId + ' .select-year .selectbox-option:contains(' + selectedYear + ')').addClass('hover');
$('#' + calendarId + ' .select-hour .selectbox-option').eq(selectedHour).addClass('hover');
$('#' + calendarId + ' .select-minute .selectbox-option').eq(selectedMinute).addClass('hover');
$('#' + calendarId + ' .select-second .selectbox-option').eq(selectedSecond).addClass('hover');
$('#' + calendarId + ' .select-month .selectbox-label').text($('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).text());
$('#' + calendarId + ' .select-year .selectbox-label').text(selectedYear);
$('#' + calendarId + ' .select-hour .selectbox-label').text(addLeadingZero(selectedHour));
$('#' + calendarId + ' .select-minute .selectbox-label').text(addLeadingZero(selectedMinute));
$('#' + calendarId + ' .select-second .selectbox-label').text(addLeadingZero(selectedSecond));
updateInputValue();
});
// Функции изменения значений селектов календаря
$('#' + calendarId + ' .select-month select').change(function(){
selectedMonth = parseInt($(this).find('option:selected').val(), 10);
$('#' + calendarId + ' .day-selector tr td').removeClass('active');
selectedDay = 1;
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(0).addClass('active');
updateInputValue();
});
$('#' + calendarId + ' .select-year select').change(function(){
selectedYear = parseInt($(this).find('option:selected').val(), 10);
$('#' + calendarId + ' .day-selector tr td').removeClass('active');
selectedDay = 1;
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(0).addClass('active');
updateInputValue();
});
$('#' + calendarId + ' .select-hour select').change(function(){
selectedHour = parseInt($(this).find('option:selected').val(), 10);
updateInputValue();
});
$('#' + calendarId + ' .select-minute select').change(function(){
selectedMinute = parseInt($(this).find('option:selected').val(), 10);
updateInputValue();
});
$('#' + calendarId + ' .select-second select').change(function(){
selectedSecond = parseInt($(this).find('option:selected').val(), 10);
updateInputValue();
});
}
// Одноразовая отрисовка и скрытие календаря после загрузки страницы
renderCalendar();
$('#' + calendarId + ' .calendar-datepicker').addClass('hidden');
// Функция отрисовки дней календаря
function renderDays () {
// Получение значений предыдущего, следующего месяца и года относительно текущей выбранной даты
var previousMonth = selectedMonth
, nextMonth = selectedMonth
, previousMonthYear = selectedYear
, nextMonthYear = selectedYear;
if (selectedMonth === 12) {
previousMonth -= 1;
nextMonth = 1;
nextMonthYear += 1;
} else if (selectedMonth === 1) {
previousMonth = 12;
nextMonth += 1;
previousMonthYear -= 1;
} else {
previousMonth -= 1;
nextMonth += 1;
}
// Получение числа дней в предыдущем и текущем месяце
var daysInPreviousMonth = getDaysInMonth(previousMonthYear, previousMonth)
, daysInSelectedMonth = getDaysInMonth(selectedYear, selectedMonth);
// Общее число ячеек в таблице дней календаря и общее число дней в неделе
var totalDayCells = 42
, daysInTheWeek = 7;
// Определение числа дней в календаре, стоящих перед днями текущего месяца, по порядковому номеру последнего дня в последней неделе
var daysNumberForPreviousMonth = getNumberOfDayOfTheWeek(previousMonthYear, previousMonth, daysInPreviousMonth);
// Определение числа дней в календаре, стоящих после дней текущего месяца
var daysNumberForNextMonth = totalDayCells - daysInSelectedMonth - daysNumberForPreviousMonth;
// Создание таблицы дней для календаря
var i
, daysArray = [];
for (i = daysNumberForPreviousMonth; i > 0; i--, daysInPreviousMonth--) {
daysArray.push('<td class="day old">' + daysInPreviousMonth + '</td>');
}
daysArray.reverse();
for (i = 1; i <= daysInSelectedMonth; i++) {
daysArray.push('<td class="day">' + i + '</td>');
}
for (i = 1; i <= daysNumberForNextMonth; i++) {
daysArray.push('<td class="day new">' + i + '</td>');
}
var days = '<tbody>'
var tableRowsNumber = Math.round(totalDayCells / daysInTheWeek);
var j
, cellCounterStart = 0
, cellCounterStop = daysInTheWeek
, row = '';
for (i = 0; i < tableRowsNumber; i++) {
for (j = cellCounterStart; j < cellCounterStop; j++) {
row += daysArray[j];
}
days += '<tr>' + row + '</tr>';
row = '';
cellCounterStart = j;
cellCounterStop = j + daysInTheWeek;
}
days += '</tbody>';
// Вставка дней в календарь
$('#' + calendarId + ' .day-selector tbody').replaceWith(days);
// Навешивание функции кликов по дням календаря. Функция определена ниже
$('#' + calendarId + ' .day').click(dayClick);
}
// Функция кликов по дням календаря. Вызывается выше во время отрисовки дней календаря
// Выделено в отдельную функцию, чтобы срабатывали клики на днях при использовании кода $(document).on('click', function(){...});
// написанного ниже
function dayClick () {
var day = $(this);
selectedDay = parseInt(day.text(), 10);
if (day.hasClass('old')) {
if (selectedMonth === 1) {
selectedMonth = 12;
if (selectedYear === 1970) {
selectedYear = 1970;
} else {
selectedYear -= 1;
}
} else {
selectedMonth -= 1;
}
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(selectedDay - 1).addClass('active');
} else if (day.hasClass('new')) {
if (selectedMonth === 12) {
selectedMonth = 1;
if (selectedYear === getCurrentYear() + 1) {
selectedYear === getCurrentYear() + 1;
} else {
selectedYear += 1;
}
} else {
selectedMonth += 1;
}
renderDays();
$('#' + calendarId + ' .day-selector tr td.day').not('.old').not('.new').eq(selectedDay - 1).addClass('active');
} else {
$('#' + calendarId + ' .day-selector tr td').removeClass('active');
day.addClass('active');
}
$('#' + calendarId + ' .select-month select option').eq(selectedMonth - 1).prop('selected', true);
$('#' + calendarId + ' .select-year select option[value="' + selectedYear + '"]').prop('selected', true);
$('#' + calendarId + ' .select-month .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).addClass('hover');
$('#' + calendarId + ' .select-month .selectbox-label').text($('#' + calendarId + ' .select-month .selectbox-option').eq(selectedMonth - 1).text());
$('#' + calendarId + ' .select-year .selectbox-option').removeClass('hover');
$('#' + calendarId + ' .select-year .selectbox-option:contains(' + selectedYear + ')').addClass('hover');
$('#' + calendarId + ' .select-year .selectbox-label').text(selectedYear);
updateInputValue();
}
// Функции показа и скрытия календаря
$('#' + calendarId + ' .calendar-button').click(function(e){
var calendar = $(this).next();
if (calendar.hasClass('hidden')) {
calendar.removeClass('hidden');
renderCalendar();
} else {
calendar.addClass('hidden');
}
$('#' + calendarId + ' .selectbox-dropbox').hide();
e.stopPropagation();
});
$(document).on('click', function(){
var calendar = $('#' + calendarId + ' .calendar-datepicker');
if (!calendar.hasClass('hidden')) {
calendar.addClass('hidden');
}
$('#' + calendarId + ' .selectbox-dropbox').hide();
});
// Функции удаления символов, недопустимых при вводе даты в поле input календаря
// Удаление всех символов из времени начала сессии кроме цифр, пробела, символов "/", ":"
// и замена значения даты, если данные введены правильно
$('#' + calendarId + ' .calendar-input').keyup(function(){
deleteNotDateSymbols(this);
replaceDataDate(this);
}).change(function(){
deleteNotDateSymbols(this);
replaceDataDate(this);
});
// Удаление всех символов, кроме цифр, пробела, символов / и :
function deleteNotDateSymbols (input) {
var value = $(input).val();
value = value.replace(/[^0-9\s\/:]/gi, '');
value = $.trim(value);
$(input).val(value);
}
// Замена значения даты, если данные введены в правильном формате
function replaceDataDate (input) {
var value = $(input).val()
, date
, day
, month
, year
, hour
, minute
, second;
if ( value.length === 19 && (/(\d{2}\/\d{2}\/\d{4}\s\d{2}:\d{2}:\d{2}){1}/gi).test(value) ) {
value = value.replace(/[\s\/:]/gi, '.');
date = value.split('.');
day = removeLeadingZero(date[0]);
month = removeLeadingZero(date[1]);
year = removeLeadingZero(date[2]);
hour = removeLeadingZero(date[3]);
minute = removeLeadingZero(date[4]);
second = removeLeadingZero(date[5]);
if (
(day > 0 && day < getDaysInMonth(year, month) + 1)
&& (month > 0 && month < 13)
&& (year > 1969 && year < getCurrentYear() + 2)
&& (hour > -1 && hour < 24)
&& (minute > -1 && minute < 60)
&& (second > -1 && second < 60)
) {
$(input).data('date', value);
}
}
}
}
// Создание календаря для времени начала сессии
createCalendar('sessions-start-time');
}
);
понедельник, 16 сентября 2013 г.
Обфускация JavaScript
В статье собраны всем известные методы и предельно извращенные.
Первый способ
Он всем известен — обфускация минимизаторами такими как JS Packer, JSmin, YUI Compressor, Closure compiler или можно просто пугуглить «JavaScript Obfuscator» и найдется ещё сто штук разных обфускаторов.
Они превращают существующий код
function MyClass(){
this.foo = function(argument1, argument2){
var addedArgs = parseInt(argument1)+parseInt(argument2);
return addedArgs;
}
var anonymousInnerFunction = function(){
// do stuff here!
}
}
В какой-то такой вид:
function MyClass(){this.foo=function(c,b){var d=parseInt(c)+parseInt(b);return d};var a=function(){}};
Или такой:
var _0xd799=["\x66\x6F\x6F"];function MyClass(){this[_0xd799[0]]=function (_0xefcax2,_0xefcax3){var _0xefcax4=parseInt(_0xefcax2)+parseInt(_0xefcax3);return _0xefcax4;} ;var _0xefcax5=function (){} ;} ;
Или вот такой:
eval(function(p,a,c,k,e,d){e=function(c){return c};if(!''.replace(/^/,String)){while(c--){d[c]=k[c]||c}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('4 0="3 5!";9 2(1){6(1+"\\7"+0)}2("8");',10,10,'a|msg|MsgBox|Hello|var|World|alert|n|OK|function'.split('|'),0,{}))
Но ничего не стоит его восстановить с помощью jsbeautifier.org либо просто убрать eval и получить исходный код, многое потеряем, но смысл кода восстановим. Ну и с первого взгляда мы видим, что перед нами JavaScript.
Все это были цветочки под катом жесткие методы обфускации.
Способ второй
Изменение кода до неузнаваемости, который превратит наш мизерный скрипт:
alert(0)В такой Braifuck-подобный вид:
([][(![]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]][([][(![]+[])[+[]]+(![]+[]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]()[(![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]])(+[])Или вот в такой:
゚ω゚ノ= /`m´)ノ ~┻━┻ //*´∇`*/ ['_']; o=(゚ー゚) =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\'; (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [゚o゚]='\"';(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+(゚Д゚)[゚o゚]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+((o^_^o) +(o^_^o))+ (c^_^o)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');Тут с первого раза и не скажешь, что перед нами работающий JavaScript.
Тулза делающая код вида один, код вида два и jjencode
Объяснение некоторых моментов способа два
Пример:
($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+
($$=($_=!''+$)[_/_]+$_[+$])])()[__[_/_]+__
[_+~$]+$_[_]+$$](_/_)
Имеем какое-то месево символов, но на самом деле в нем скрывается
alert(1), но ведь там нет ни одной строки и ни одного символа, откуда это?!Будем разбираться:
$=[] это пустой массив$=[$=[]] это массив с ссылкой на массивВ переменной $ будет 0.
Теперь у нас есть 0 и мы можем ссылаться. Делаем
__ = "false" через (__ = !$ + $ )Далее
_ = -~-~-~$Оператор ~ в JavaScript означает -(N+1) поэтому
-~ = +1Если
$ = 0 тогда -~-~-~$ = 3Получаем:
_ = 3Таким образом
_/_ = 3/3 = 1(__ = !$ + $ )[ _ = -~-~-~$]
("false")[_]
("false")[3]
"false"[3] = s({} + $)[_/_]
(" object")[_/_]
(" object")[1]
" object"[1] = o$$ = ( $_ = !'' + $)[_/_]
$$ = ( "true")[1]
"true"[1] = r$_[+$] = "true"[0] = t$_ = "true"null
$$ = rt ($$ = ( $_ = !'' + $)[_/_] + $_[+$] ))!'' = "true"
$_ = (true)
$_[1] = r
$_[0] = t
$$ = rtТаким образом первая строка станет
($ = [] ["s" + "o"+ "r"+ "t" ] )()($=[]["sort"])()Идем дельше
[__[_/_]+__[_+~$]+$_[_]+$$](_/_)$ = 0
_ = 3
__ = "false"
$_ = "true"
$$ = "rt"Строка превращается…
[__[_/_]+__[_+~$]+$_[_]+$$](_/_)Превращается…
[__[1] + __[3 + -1] + $_[3] + $$)(1);Превращается…
["false"[1] + "false"[3 + -1 ] + "true"[3] + "rt"] (1)Превращается в
[ "a" + "l" + "e" + "r" + "t" ](1)В конце мы получаем
($=[]["sort"])()["alert"](1)Разобьём по частям
a = [] // Создает массив
b = a["sort"] // Получает ссылку на метод sort
c = b() // Выполяет метод вне контекста массива для получения ссылки на window
d = c["alert"] // Получает ссылку на window.alert
d(1) // Выполняет window.alert с аргументом 1Итог:
window["alert"](1)Это, конечно, искусственный пример и никакой из обфускаторов так не сможет.
Способ третий
Первый способ делал код похожим на JavaScript, второй совершенно не похожим, а третий сделает код вообще невидимым.
Готовых решений не видел, концепт, подсмотренный с одного из видео JS конференций.
Код будет состоять из двух частей: видимая часть — можно использовать что-нибудь описанное выше для её обфускации и невидимая часть.
Если с видимой все ясно, то секрет невидимой вот в чем: Имеющийся «плохой код» (иначе зачем его прятать) мы пропускаем через наш обфускатор-изчезатор, который превращает видимый скрипт в невидимый, то есть в строку состоящую из знаков табуляции (бит 1) и пробелов (бит 0).
В итоге мы получим в 8 раз больше кода чем имели. Видимая часть будет декодировать невидимую часть и её выполнять: декодирует биты в число, а число переделает в символ
String.fromCharCode() ну а дальше evalВ конце получается что-то такое (невидимую часть не обязательно скрывать в элементе)
decodeAndEval(document.getElementById("evilCode").innerHTML);
<div id="evilCode">
</div>обфускатор-изчезатор
По мотивам:
Очень оригинальный скрипт на JavaScript
゚ω゚ノ= /`m´)ノ ~┻━┻ //*´∇`*/ ['_']; o=(゚ー゚) =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); (゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] ,゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] ,゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + ((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; (゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\'; (゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];(゚Д゚) [゚o゚]='\"';(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+(゚Д゚)[゚o゚]+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((゚ー゚) + (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚ー゚)+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (o^_^o)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ ((゚ー゚) + (゚Θ゚))+ (゚Д゚)[゚ε゚]+(゚ー゚)+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (c^_^o)+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (゚Θ゚)+ ((o^_^o) +(o^_^o))+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+(゚ー゚)+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ ((o^_^o) - (゚Θ゚))+ (o^_^o)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (c^_^o)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+(゚Θ゚)+ (o^_^o)+ (゚Θ゚)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (o^_^o))+ ((゚ー゚) + (o^_^o))+ (゚Д゚)[゚ε゚]+(゚ー゚)+ ((o^_^o) - (゚Θ゚))+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (゚Θ゚)+ (゚Д゚)[゚o゚]) (゚Θ゚)) ('_');
вторник, 10 сентября 2013 г.
Random Number - Формирование случайного числа из диапазона
function randomNumber (m,n) {
m = parseInt(m);
n = parseInt(n);
return Math.floor( Math.random() * (n - m + 1) ) + m;
}
var random_number = randomNumber (1,999);
m = parseInt(m);
n = parseInt(n);
return Math.floor( Math.random() * (n - m + 1) ) + m;
}
var random_number = randomNumber (1,999);
Raphael Pie Chart Library
Файл index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
#canvas {
width: 640px;
height: 480px;
margin: 0 auto;
text-align: left;
border: 1px solid #000000;
}
</style>
<script data-main="js/index.js" src="js/lib/require/require.js"></script>
<title>Chart Lib</title>
</head>
<body>
<div id="canvas"></div>
</body>
</html>
Файл index.js
require.config({
paths: {
jquery: 'lib/jquery/jquery'
, raphael: 'lib/raphael/raphael'
, raphaelPieChart: 'lib/raphael/raphael.piechart'
}
, shim: {
raphaelPieChart: {
deps: ['raphael']
}
}
});
require(
[
'jquery'
, 'raphael'
, 'raphaelPieChart'
]
, function(
$
, Raphael
) {
// Тестируем работу библиотеки Pie Chart.
var paper = Raphael("canvas", 640, 480);
paper.piechart(
320, 240, 100
, [25, 25, 25, 25]
, {
colors: ['#cc0000', '#00ff00', '#000000', '#aa00aa']
, labels: ['one', 'two', 'three', 'four']
, labelsTextColor: '#ff0000'
}
);
}
);
Файл raphael.piechart.js
// Библиотека Pie Chart.
// Параметры функции piechart(cx, cy, r, values, options):
// cx (number) - координата x центра круговой диаграммы.
// cy (number) - координата y вцентра круговой диаграммы.
// r (number) - радиус круговой диаграммы.
// values (array) - массив значений, по которым строится круговая диаграмма. Пример: [55, 20, 13, 32, 5, 1, 2].
// options (object) - список опций, использующихся для модификации круговой диаграммы.
// Возможные параметры options:
// options = {
// stroke (string) - цвет линни окружности круговой диаграммы в формате "#ffffff".
// strokeWidth (number) (по умолчанию равно 1) - толщина линии окружности круговой диаграммы.
// colors (array) - массив цветов в формате "#ffffff", каждый из которых будет использоваться для закрашивания секторов круговой диаграмме.
// labels (array) - массив, содержащий строки, которые будут использованы в качестве подписей к секторам круговой диаграммы.
// Ниже следующие опции будут работать, если опция labels была определена.
// labelsTextColor (string) (по умолчанию равно "#000000") - цвет текста подписи в формате "#ffffff".
// labelsMark (string) (по умолчанию равно "circle") - символ, используемый в качестве маркера слева от текста подписи. Данный символ имеет тот же цвет, что и соответствующий сектор на круговой диаграмме.
// labelsPosition (string) (по умолчанию равно "east") - место положения подписей рядом с круговой диаграммой. Для данной опции возможны следующие значения: "north", "south", "east", "west".
// }
// Пример использования библиотеки:
// paper.piechart(
// 320, 240, 100
// , [25, 25, 25, 25]
// , {
// colors: ['#cc0000', '#00ff00', '#000000', '#aa00aa']
// , labels: ['one', 'two', 'three', 'four']
// , labelsTextColor: '#ff0000'
// }
// );
;(function(){
// Главная функция библиотеки.
function PieChart (paper, cx, cy, r, values, options) {
// Опции библиотеки.
options = options || {};
// Опции задающие цвета секторов и толщину разделительных линний на круговой диаграмме.
var stroke = options.stroke || "#ffffff"
, strokeWidth = options.strokeWidth || 1
, colors = options.colors || (function () {
var hues = [0.6, 0.2, 0.05, 0.1333, 0.75, 0]
, colors = []
, i;
// Допустимо только 10 цветов. Для большего числа цветов необходимо изменить 10 и массив hues.
for (i = 0; i < 10; i++) {
if (i < hues.length) {
colors.push('hsb(' + hues[i] + ', 0.75, 0.75)');
} else {
colors.push('hsb(' + hues[i - hues.length] + ', 1, 0.5)');
}
}
return colors;
})();
// Опции для отрисовки секторов круговой диаграммы
var len = values.length
, total = 0
, mangle
, angle = 0
, sectorPath
, i;
for (i = 0; i < len; i++) {
total += values[i];
}
// Функция вычисления пути для отрисовки каждого сектора на круговой диаграмме.
function sector(cx, cy, r, startAngle, endAngle) {
var rad = Math.PI / 180
, x1 = cx + r * Math.cos(-startAngle * rad)
, x2 = cx + r * Math.cos(-endAngle * rad)
, y1 = cy + r * Math.sin(-startAngle * rad)
, y2 = cy + r * Math.sin(-endAngle * rad)
, path = [
'M', cx, cy // MoveTo: cx, cy
, 'L', x1, y1 // LineTo: x1, y1
, 'A', r, r, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2 // Elliptical Arc: rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y
, 'z' // Close path
];
return path.join();
}
// Цикл отрисовки секторов на круговой диаграмме.
for (i = 0; i < len; i++) {
mangle = angle - 360 * values[i] / total / 2;
if (!i) {
angle = 90 - mangle;
mangle = angle - 360 * values[i] / total / 2;
}
sectorPath = sector(cx, cy, r, angle, angle -= 360 * values[i] / total);
paper.path(sectorPath).attr({
'fill': colors[i]
, 'stroke': stroke
, 'stroke-width': strokeWidth
, 'stroke-linejoin': 'round'
});
}
// Опции задающие цвета, метки и положение подписей рядом с кгруговой диаграммой.
var labels = options.labels || values
, labelsTextColor = options.labelsTextColor || '#000000'
, labelsMark = options.labelsMark || 'circle'
, labelsPosition = options.labelsPosition || 'east'
, labelsSet = paper.set();
labelsMark = labelsMark.toLowerCase();
labelsPosition = labelsPosition.toLowerCase();
// Цикл отрисовки подписей рядом с круговой диаграммой.
var x = cx + r + r / 5
, y = cy
, h = y + 10
, labelMark
, labelText;
for (i = 0; i < len; i++) {
labelMark = paper[labelsMark](x + 5, h, 5).attr({fill: colors[i], stroke: 'none'});
labelText = paper.text(x + 20, h, labels[i]).attr({fill: labelsTextColor, 'text-anchor': 'start'});
h += labelText.getBBox().height * 1.2;
labelsSet.push(paper.set());
labelsSet[i].push(labelMark).push(labelText);
}
var labelsBoundingBox = labelsSet.getBBox()
, translateToPosition = {
east: [0, -labelsBoundingBox.height / 2]
, west: [-labelsBoundingBox.width - 2 * r - 20, -labelsBoundingBox.height / 2]
, north: [-r - labelsBoundingBox.width / 2, -r - labelsBoundingBox.height - 10]
, south: [-r - labelsBoundingBox.width / 2, r + 10]
}[labelsPosition];
labelsSet.translate.apply(labelsSet, translateToPosition);
}
// Добавляем библиотеку Pie Chart в состав библиотеки Raphael JS.
Raphael.fn.piechart = function (cx, cy, r, values, options) {
return new PieChart(this, cx, cy, r, values, options);
};
})();
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
#canvas {
width: 640px;
height: 480px;
margin: 0 auto;
text-align: left;
border: 1px solid #000000;
}
</style>
<script data-main="js/index.js" src="js/lib/require/require.js"></script>
<title>Chart Lib</title>
</head>
<body>
<div id="canvas"></div>
</body>
</html>
Файл index.js
require.config({
paths: {
jquery: 'lib/jquery/jquery'
, raphael: 'lib/raphael/raphael'
, raphaelPieChart: 'lib/raphael/raphael.piechart'
}
, shim: {
raphaelPieChart: {
deps: ['raphael']
}
}
});
require(
[
'jquery'
, 'raphael'
, 'raphaelPieChart'
]
, function(
$
, Raphael
) {
// Тестируем работу библиотеки Pie Chart.
var paper = Raphael("canvas", 640, 480);
paper.piechart(
320, 240, 100
, [25, 25, 25, 25]
, {
colors: ['#cc0000', '#00ff00', '#000000', '#aa00aa']
, labels: ['one', 'two', 'three', 'four']
, labelsTextColor: '#ff0000'
}
);
}
);
Файл raphael.piechart.js
// Библиотека Pie Chart.
// Параметры функции piechart(cx, cy, r, values, options):
// cx (number) - координата x центра круговой диаграммы.
// cy (number) - координата y вцентра круговой диаграммы.
// r (number) - радиус круговой диаграммы.
// values (array) - массив значений, по которым строится круговая диаграмма. Пример: [55, 20, 13, 32, 5, 1, 2].
// options (object) - список опций, использующихся для модификации круговой диаграммы.
// Возможные параметры options:
// options = {
// stroke (string) - цвет линни окружности круговой диаграммы в формате "#ffffff".
// strokeWidth (number) (по умолчанию равно 1) - толщина линии окружности круговой диаграммы.
// colors (array) - массив цветов в формате "#ffffff", каждый из которых будет использоваться для закрашивания секторов круговой диаграмме.
// labels (array) - массив, содержащий строки, которые будут использованы в качестве подписей к секторам круговой диаграммы.
// Ниже следующие опции будут работать, если опция labels была определена.
// labelsTextColor (string) (по умолчанию равно "#000000") - цвет текста подписи в формате "#ffffff".
// labelsMark (string) (по умолчанию равно "circle") - символ, используемый в качестве маркера слева от текста подписи. Данный символ имеет тот же цвет, что и соответствующий сектор на круговой диаграмме.
// labelsPosition (string) (по умолчанию равно "east") - место положения подписей рядом с круговой диаграммой. Для данной опции возможны следующие значения: "north", "south", "east", "west".
// }
// Пример использования библиотеки:
// paper.piechart(
// 320, 240, 100
// , [25, 25, 25, 25]
// , {
// colors: ['#cc0000', '#00ff00', '#000000', '#aa00aa']
// , labels: ['one', 'two', 'three', 'four']
// , labelsTextColor: '#ff0000'
// }
// );
;(function(){
// Главная функция библиотеки.
function PieChart (paper, cx, cy, r, values, options) {
// Опции библиотеки.
options = options || {};
// Опции задающие цвета секторов и толщину разделительных линний на круговой диаграмме.
var stroke = options.stroke || "#ffffff"
, strokeWidth = options.strokeWidth || 1
, colors = options.colors || (function () {
var hues = [0.6, 0.2, 0.05, 0.1333, 0.75, 0]
, colors = []
, i;
// Допустимо только 10 цветов. Для большего числа цветов необходимо изменить 10 и массив hues.
for (i = 0; i < 10; i++) {
if (i < hues.length) {
colors.push('hsb(' + hues[i] + ', 0.75, 0.75)');
} else {
colors.push('hsb(' + hues[i - hues.length] + ', 1, 0.5)');
}
}
return colors;
})();
// Опции для отрисовки секторов круговой диаграммы
var len = values.length
, total = 0
, mangle
, angle = 0
, sectorPath
, i;
for (i = 0; i < len; i++) {
total += values[i];
}
// Функция вычисления пути для отрисовки каждого сектора на круговой диаграмме.
function sector(cx, cy, r, startAngle, endAngle) {
var rad = Math.PI / 180
, x1 = cx + r * Math.cos(-startAngle * rad)
, x2 = cx + r * Math.cos(-endAngle * rad)
, y1 = cy + r * Math.sin(-startAngle * rad)
, y2 = cy + r * Math.sin(-endAngle * rad)
, path = [
'M', cx, cy // MoveTo: cx, cy
, 'L', x1, y1 // LineTo: x1, y1
, 'A', r, r, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2 // Elliptical Arc: rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y
, 'z' // Close path
];
return path.join();
}
// Цикл отрисовки секторов на круговой диаграмме.
for (i = 0; i < len; i++) {
mangle = angle - 360 * values[i] / total / 2;
if (!i) {
angle = 90 - mangle;
mangle = angle - 360 * values[i] / total / 2;
}
sectorPath = sector(cx, cy, r, angle, angle -= 360 * values[i] / total);
paper.path(sectorPath).attr({
'fill': colors[i]
, 'stroke': stroke
, 'stroke-width': strokeWidth
, 'stroke-linejoin': 'round'
});
}
// Опции задающие цвета, метки и положение подписей рядом с кгруговой диаграммой.
var labels = options.labels || values
, labelsTextColor = options.labelsTextColor || '#000000'
, labelsMark = options.labelsMark || 'circle'
, labelsPosition = options.labelsPosition || 'east'
, labelsSet = paper.set();
labelsMark = labelsMark.toLowerCase();
labelsPosition = labelsPosition.toLowerCase();
// Цикл отрисовки подписей рядом с круговой диаграммой.
var x = cx + r + r / 5
, y = cy
, h = y + 10
, labelMark
, labelText;
for (i = 0; i < len; i++) {
labelMark = paper[labelsMark](x + 5, h, 5).attr({fill: colors[i], stroke: 'none'});
labelText = paper.text(x + 20, h, labels[i]).attr({fill: labelsTextColor, 'text-anchor': 'start'});
h += labelText.getBBox().height * 1.2;
labelsSet.push(paper.set());
labelsSet[i].push(labelMark).push(labelText);
}
var labelsBoundingBox = labelsSet.getBBox()
, translateToPosition = {
east: [0, -labelsBoundingBox.height / 2]
, west: [-labelsBoundingBox.width - 2 * r - 20, -labelsBoundingBox.height / 2]
, north: [-r - labelsBoundingBox.width / 2, -r - labelsBoundingBox.height - 10]
, south: [-r - labelsBoundingBox.width / 2, r + 10]
}[labelsPosition];
labelsSet.translate.apply(labelsSet, translateToPosition);
}
// Добавляем библиотеку Pie Chart в состав библиотеки Raphael JS.
Raphael.fn.piechart = function (cx, cy, r, values, options) {
return new PieChart(this, cx, cy, r, values, options);
};
})();
понедельник, 2 сентября 2013 г.
jQuery Firefox offsetX offestY undefined
В Firefox значения offestX и offsetY равны undefined.
Для устранения этого недостатка нужно написать следующий код.
$('div').click(function(event){
var offestX = event.pageX - $(event.target).offset().left;
var offsetY = event.pageY - $(event.target).offset().top;
console.log(offsetX);
console.log(offsetY);
});
Для устранения этого недостатка нужно написать следующий код.
$('div').click(function(event){
var offestX = event.pageX - $(event.target).offset().left;
var offsetY = event.pageY - $(event.target).offset().top;
console.log(offsetX);
console.log(offsetY);
});
Подписаться на:
Сообщения (Atom)
