added virtual keyboard
This commit is contained in:
parent
f8526df99d
commit
7d02a50eaa
22 changed files with 6551 additions and 3 deletions
|
@ -110,6 +110,12 @@ h2 {
|
|||
padding: 20px;
|
||||
}
|
||||
|
||||
|
||||
#vkb {
|
||||
margin: 0 auto 0 15%;
|
||||
}
|
||||
|
||||
|
||||
/* Style for the footer */
|
||||
#footer {
|
||||
padding: 2px;
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,335 @@
|
|||
html.VirtualKeyboardPopup, body.VirtualKeyboardPopup {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#virtualKeyboard {
|
||||
border: 1px solid #686888;
|
||||
background: #fefefe;
|
||||
height: 160px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 396px;
|
||||
}
|
||||
/*
|
||||
* global overrides
|
||||
*/
|
||||
#virtualKeyboard * {
|
||||
border: 0;
|
||||
color: black;
|
||||
cursor: default;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 4px 2px 0 2px;
|
||||
/*IE5.5 will ignore the rule below */
|
||||
margin/**/:/**/ 4px 2px 0 4px;
|
||||
padding/**/:/**/ 0;
|
||||
/*--*/
|
||||
position: relative;
|
||||
font-size: 1px;
|
||||
overflow: hidden;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div.kbButton {
|
||||
float: left;
|
||||
height: 26px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 26px;
|
||||
z-index: 2;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton a {
|
||||
background: url(button_set.gif) 0 0 no-repeat;
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
}
|
||||
#virtualKeyboard #kbDesk.capsLock div.kbButton span.normal {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div.kbButtonHover a {
|
||||
background-position: 0 -27px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButtonDown a {
|
||||
background-position: 0 -54px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span {
|
||||
display: block;
|
||||
font-family: Verdana;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
overflow: visible;
|
||||
text-align: center;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.shifted,
|
||||
#virtualKeyboard #kbDesk div.kbButton span.alted {
|
||||
color: green;
|
||||
font-size: 6pt;
|
||||
height: 100%;
|
||||
line-height: 1.1;
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
top: 0;
|
||||
text-transform: none;
|
||||
vertical-align: bottom;
|
||||
width: 100%;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.alted {
|
||||
color: blue;
|
||||
right: 7px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.normal {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: 5px;
|
||||
text-indent: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk span.deadKey {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div#kb_benter {
|
||||
background-position: -194px 0px;
|
||||
margin-top: -26px;
|
||||
position: relative;
|
||||
float: right;
|
||||
height: 52px;
|
||||
width: 56px;
|
||||
z-index: -1;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter[id] {
|
||||
z-index: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter a {
|
||||
background-position: -194px 0px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter.kbButtonHover a {
|
||||
background-position: -194px -53px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter.kbButtonDown a {
|
||||
background-position: -194px -106px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace a {
|
||||
background-position: -27px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonHover a {
|
||||
background-position: -27px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonDown a {
|
||||
background-position: -27px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab {
|
||||
width: 41px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab a {
|
||||
background-position: -155px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab.kbButtonHover a {
|
||||
background-position: -155px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab.kbButtonDown a {
|
||||
background-position: -155px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps {
|
||||
width: 48px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps a {
|
||||
background-position: -107px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonHover a {
|
||||
background-position: -107px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonDown a {
|
||||
background-position: -107px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right {
|
||||
width: 52px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right a {
|
||||
background-position: -54px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonHover a {
|
||||
background-position: -54px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonDown a {
|
||||
background-position: -54px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right {
|
||||
padding: 0 0 0 2px;
|
||||
width: 32px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left {
|
||||
margin-left: 33px;
|
||||
padding-left: 0;
|
||||
/*IE5.5 will ignore the rule below */
|
||||
padding-left/**/:/**/ 41px;
|
||||
margin-left/**/:/**/ 0;
|
||||
/*--*/
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right a {
|
||||
background-position: -251px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonHover a {
|
||||
background-position: -251px -27px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonDown a {
|
||||
background-position: -251px -54px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right {
|
||||
float: left;
|
||||
width: 32px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right {
|
||||
float: right;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right a {
|
||||
background-position: -251px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonHover a {
|
||||
background-position: -251px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonDown a {
|
||||
background-position: -251px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel a {
|
||||
background-position: 0 -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonHover a {
|
||||
background-position: 0 -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonDown a {
|
||||
background-position: 0 -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace {
|
||||
width: 166px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace a {
|
||||
background-position: -27px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonHover a {
|
||||
background-position: -27px -27px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonDown a {
|
||||
background-position: -27px -54px;
|
||||
}
|
||||
|
||||
#virtualKeyboard select#kb_langselector,
|
||||
#virtualKeyboard select#kb_mappingselector {
|
||||
border: 1px solid black;
|
||||
bottom: 2px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
width: 125px;
|
||||
}
|
||||
#virtualKeyboard select#kb_mappingselector {
|
||||
right: 140px;
|
||||
}
|
||||
#virtualKeyboard select,
|
||||
#virtualKeyboard select option {
|
||||
background: #fff;
|
||||
font-family: Arial, Tahoma, Verdana sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
#virtualKeyboard select optgroup option {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#virtualKeyboard #copyrights {
|
||||
bottom: 4px;
|
||||
color: blue;
|
||||
font-size: 9px;
|
||||
left: 2px;
|
||||
line-height: normal;
|
||||
position: absolute;
|
||||
}
|
||||
#virtualKeyboard #copyrights a {
|
||||
font-size: 9px;
|
||||
color: blue;
|
||||
cursor: default;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Styles for the IME field
|
||||
*
|
||||
*/
|
||||
#VirtualKeyboardIME {
|
||||
background: #fff;
|
||||
border:1px solid #333;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
#VirtualKeyboardIME div.IMEContent {
|
||||
border: 1px solid #333;
|
||||
border-top: 0;
|
||||
border-bottom: 0;
|
||||
height: 21px;
|
||||
line-height: 21px;
|
||||
margin: 0 12px;
|
||||
overflow: auto;
|
||||
padding: 0 3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#VirtualKeyboardIME div.left {
|
||||
border-bottom: 10px solid #fff;
|
||||
border-left: 0px solid black;
|
||||
border-right: 10px solid #000;
|
||||
border-top: 10px solid #fff;
|
||||
position: absolute;
|
||||
left: 1px;
|
||||
font-size: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
#VirtualKeyboardIME div.right {
|
||||
border-bottom: 10px solid #fff;
|
||||
border-left: 10px solid #000;
|
||||
border-right: 0px solid black;
|
||||
border-top: 10px solid #fff;
|
||||
float: right;
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Place for the locale-dependent styles
|
||||
* overload fonts here
|
||||
*
|
||||
* Language-dependent class name is equal to uppercased language domain code (ZH in zh-CN)
|
||||
*/
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span {
|
||||
font-family: MingLiU, SimSun, "Arial Unicode MS";
|
||||
font-size: 13px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span.alted,
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span.shifted {
|
||||
font-size: 9px;
|
||||
}
|
||||
#VirtualKeyboardIME.ZH div.IMEContent {
|
||||
font-family: SimSun, "Arial Unicode MS";
|
||||
font-size: 16px;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
|
@ -0,0 +1,307 @@
|
|||
html.VirtualKeyboardPopup, body.VirtualKeyboardPopup {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#virtualKeyboard {
|
||||
border: 1px solid #686888;
|
||||
background: #f0ecff;
|
||||
height: 120px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 276px;
|
||||
}
|
||||
/*
|
||||
* global overrides
|
||||
*/
|
||||
#virtualKeyboard * {
|
||||
border: 0;
|
||||
color: black;
|
||||
cursor: default;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 4px 2px 0 2px;
|
||||
/*IE5.5 will ignore the rule below */
|
||||
margin/**/:/**/ 4px 2px 0 4px;
|
||||
padding/**/:/**/ 0;
|
||||
/*--*/
|
||||
position: relative;
|
||||
font-size: 1px;
|
||||
overflow: hidden;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div.kbButton {
|
||||
float: left;
|
||||
height: 18px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 18px;
|
||||
z-index: 2;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton a {
|
||||
background: url(button_set.gif) 0 0 no-repeat;
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
}
|
||||
#virtualKeyboard #kbDesk.capsLock div.kbButton span.normal {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div.kbButtonHover a {
|
||||
background-position: 0 -21px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButtonDown a {
|
||||
background-position: 0 -42px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span {
|
||||
display: block;
|
||||
font-family: Verdana;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
top: 2px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.shifted,
|
||||
#virtualKeyboard #kbDesk div.kbButton span.alted {
|
||||
display: none;
|
||||
}
|
||||
#virtualKeyboard #kbDesk span.deadKey {
|
||||
color: red;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter {
|
||||
margin-top: -18px;
|
||||
position: relative;
|
||||
float: right;
|
||||
height: 36px;
|
||||
width: 38px;
|
||||
z-index: -1;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter[id] {
|
||||
z-index: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter a {
|
||||
background-position: -150px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter.kbButtonHover a {
|
||||
background-position: -150px -42px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter.kbButtonDown a {
|
||||
background-position: -150px -84px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace a {
|
||||
background-position: -21px -63px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonHover a {
|
||||
background-position: -21px -84px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonDown a {
|
||||
background-position: -21px -105px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab {
|
||||
width: 29px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab a {
|
||||
background-position: -117px -63px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab.kbButtonHover a {
|
||||
background-position: -117px -84px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab.kbButtonDown a {
|
||||
background-position: -117px -105px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps {
|
||||
width: 33px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps a {
|
||||
background-position: -81px -63px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonHover a {
|
||||
background-position: -81px -84px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonDown a {
|
||||
background-position: -81px -105px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right {
|
||||
width: 36px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right a {
|
||||
background-position: -42px -63px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonHover a {
|
||||
background-position: -42px -84px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonDown a {
|
||||
background-position: -42px -105px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right {
|
||||
width: 21px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left {
|
||||
margin-left: -23px;
|
||||
padding-left: 0;
|
||||
/*IE5.5 will ignore the rule below */
|
||||
padding-left/**/:/**/ 32px;
|
||||
margin-left/**/:/**/ 0;
|
||||
/*--*/
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right a {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonHover a {
|
||||
background-position: -192px -21px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonDown a {
|
||||
background-position: -192px -42px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right {
|
||||
float: left;
|
||||
width: 29px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right {
|
||||
float: right;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right a {
|
||||
background-position: -191px -63px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonHover a {
|
||||
background-position: -191px -84px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonDown a {
|
||||
background-position: -191px -105px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel a {
|
||||
background-position: 0 -63px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonHover a {
|
||||
background-position: 0 -84px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonDown a {
|
||||
background-position: 0 -105px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace {
|
||||
width: 100px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace a {
|
||||
background-position: -21px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonHover a {
|
||||
background-position: -21px -21px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonDown a {
|
||||
background-position: -21px -42px;
|
||||
}
|
||||
|
||||
#virtualKeyboard select#kb_langselector,
|
||||
#virtualKeyboard select#kb_mappingselector {
|
||||
border: 1px solid black;
|
||||
bottom: 2px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
width: 75px;
|
||||
}
|
||||
#virtualKeyboard select#kb_mappingselector {
|
||||
right: 80px;
|
||||
}
|
||||
#virtualKeyboard select,
|
||||
#virtualKeyboard select option {
|
||||
background: #fff;
|
||||
font-family: Arial, Tahoma, Verdana sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
#virtualKeyboard select optgroup option {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#virtualKeyboard #copyrights {
|
||||
bottom: 2px;
|
||||
color: #77a;
|
||||
font-size: 9px;
|
||||
left: 4px;
|
||||
line-height: normal;
|
||||
position: absolute;
|
||||
}
|
||||
#virtualKeyboard #copyrights a {
|
||||
font-size: 9px;
|
||||
color: #77a;
|
||||
cursor: default;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Styles for the IME field
|
||||
*
|
||||
*/
|
||||
#VirtualKeyboardIME {
|
||||
background: #fff;
|
||||
border:1px solid #333;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
#VirtualKeyboardIME div.IMEContent {
|
||||
border: 1px solid #333;
|
||||
border-top: 0;
|
||||
border-bottom: 0;
|
||||
height: 21px;
|
||||
line-height: 21px;
|
||||
margin: 0 12px;
|
||||
overflow: auto;
|
||||
padding: 0 3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#VirtualKeyboardIME div.left {
|
||||
border-bottom: 10px solid #fff;
|
||||
border-left: 0px solid black;
|
||||
border-right: 10px solid #000;
|
||||
border-top: 10px solid #fff;
|
||||
position: absolute;
|
||||
left: 1px;
|
||||
font-size: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
#VirtualKeyboardIME div.right {
|
||||
border-bottom: 10px solid #fff;
|
||||
border-left: 10px solid #000;
|
||||
border-right: 0px solid black;
|
||||
border-top: 10px solid #fff;
|
||||
float: right;
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Place for the locale-dependent styles
|
||||
* overload fonts here
|
||||
*
|
||||
* Language-dependent class name is equal to uppercased language domain code (ZH in zh-CN)
|
||||
*/
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span {
|
||||
font-family: MingLiU, SimSun, "Arial Unicode MS";
|
||||
font-size: 11px;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 6 KiB |
|
@ -0,0 +1,342 @@
|
|||
/* Skin made by Bastiaan Fronik (info [ at ] bastiaanfronik dot com)
|
||||
based on stylesheet of WingedFox */
|
||||
html.VirtualKeyboardPopup, body.VirtualKeyboardPopup {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#virtualKeyboard {
|
||||
border: 1px solid #686888;
|
||||
background: #dedfe0;
|
||||
height: 242px;
|
||||
margin: 0;
|
||||
padding-right: 2px;
|
||||
position: relative;
|
||||
width: 606px;
|
||||
}
|
||||
/*
|
||||
* global overrides
|
||||
*/
|
||||
#virtualKeyboard * {
|
||||
border: 0;
|
||||
color: black;
|
||||
cursor: default;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 4px 2px 0 2px;
|
||||
/*IE5.5 will ignore the rule below */
|
||||
margin/**/:/**/ 4px 2px 0 4px;
|
||||
padding/**/:/**/ 0;
|
||||
/*--*/
|
||||
position: relative;
|
||||
font-size: 1px;
|
||||
overflow: hidden;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div.kbButton {
|
||||
float: left;
|
||||
height: 38px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 1px;
|
||||
position: relative;
|
||||
width: 38px;
|
||||
z-index: 2;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton a {
|
||||
background: url(button_set.gif) 0 0 no-repeat;
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
}
|
||||
#virtualKeyboard #kbDesk.capsLock div.kbButton span.normal {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div.kbButtonHover a {
|
||||
background-position: 0 -41px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButtonDown a {
|
||||
background-position: 0 -82px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span {
|
||||
display: block;
|
||||
font-family: Verdana;
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
overflow: visible;
|
||||
text-align: center;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.shifted,
|
||||
#virtualKeyboard #kbDesk div.kbButton span.alted {
|
||||
color: green;
|
||||
font-size: 9pt;
|
||||
height: 100%;
|
||||
line-height: 1.1;
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
top: 0;
|
||||
text-transform: none;
|
||||
vertical-align: bottom;
|
||||
width: 100%;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.alted {
|
||||
color: blue;
|
||||
right: 7px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.normal {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: 5px;
|
||||
text-indent: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk span.deadKey {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div#kb_benter
|
||||
{
|
||||
background-position: -303px 0px;
|
||||
margin-top: -39px;
|
||||
margin-bottom: 1px;
|
||||
position: relative;
|
||||
float: right;
|
||||
height: 78px;
|
||||
width: 85px;
|
||||
z-index: -1;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter[id] {
|
||||
z-index: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter a {
|
||||
background-position: -303px 0px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter.kbButtonHover a {
|
||||
background-position: -303px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter.kbButtonDown a {
|
||||
background-position: -303px -162px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace a {
|
||||
background-position: -41px -123px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonHover a {
|
||||
background-position: -41px -164px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonDown a {
|
||||
background-position: -41px -205px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab {
|
||||
width: 60px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab a {
|
||||
background-position: -238px -123px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab.kbButtonHover a {
|
||||
background-position: -238px -164px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab.kbButtonDown a {
|
||||
background-position: -238px -205px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps {
|
||||
width: 71px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps a {
|
||||
background-position: -164px -123px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonHover a {
|
||||
background-position: -164px -164px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonDown a {
|
||||
background-position: -164px -205px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right {
|
||||
width: 78px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right a {
|
||||
background-position: -82px -123px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonHover a {
|
||||
background-position: -82px -164px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonDown a {
|
||||
background-position: -82px -205px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right {
|
||||
padding: 0 0 0 2px;
|
||||
width: 47px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left {
|
||||
margin-left: 33px;
|
||||
padding-left: 0;
|
||||
/*IE5.5 will ignore the rule below */
|
||||
padding-left/**/:/**/ 41px;
|
||||
margin-left/**/:/**/ 0;
|
||||
/*--*/
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right a {
|
||||
background-position: -391px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonHover a {
|
||||
background-position: -391px -41px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonDown a {
|
||||
background-position: -391px -82px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right {
|
||||
float: left;
|
||||
width: 48px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right {
|
||||
float: right;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right a {
|
||||
background-position: -391px -123px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonHover a {
|
||||
background-position: -391px -164px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonDown a {
|
||||
background-position: -391px -205px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel a {
|
||||
background-position: 0 -123px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonHover a {
|
||||
background-position: 0 -164px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonDown a {
|
||||
background-position: 0 -205px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace {
|
||||
width: 259px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace a {
|
||||
background-position: -41px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonHover a {
|
||||
background-position: -41px -41px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonDown a {
|
||||
background-position: -41px -82px;
|
||||
}
|
||||
|
||||
#virtualKeyboard select#kb_langselector,
|
||||
#virtualKeyboard select#kb_mappingselector {
|
||||
border: 1px solid black;
|
||||
bottom: 2px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
width: 125px;
|
||||
}
|
||||
#virtualKeyboard select#kb_mappingselector {
|
||||
right: 140px;
|
||||
}
|
||||
#virtualKeyboard select,
|
||||
#virtualKeyboard select option {
|
||||
background: #fff;
|
||||
font-family: Arial, Tahoma, Verdana sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
#virtualKeyboard select optgroup option {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#virtualKeyboard #copyrights
|
||||
{
|
||||
bottom: 4px;
|
||||
color: #6f737a;
|
||||
font-size: 9px;
|
||||
left: 4px;
|
||||
line-height: normal;
|
||||
position: absolute;
|
||||
}
|
||||
#virtualKeyboard #copyrights a {
|
||||
font-size: 9px;
|
||||
color: #6f737a;
|
||||
cursor: default;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Styles for the IME field
|
||||
*
|
||||
*/
|
||||
#VirtualKeyboardIME {
|
||||
background: #fff;
|
||||
border:1px solid #333;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
#VirtualKeyboardIME div.IMEContent {
|
||||
border: 1px solid #333;
|
||||
border-top: 0;
|
||||
border-bottom: 0;
|
||||
height: 21px;
|
||||
line-height: 21px;
|
||||
margin: 0 12px;
|
||||
overflow: auto;
|
||||
padding: 0 3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#VirtualKeyboardIME div.left {
|
||||
border-bottom: 10px solid #fff;
|
||||
border-left: 0px solid black;
|
||||
border-right: 10px solid #000;
|
||||
border-top: 10px solid #fff;
|
||||
position: absolute;
|
||||
left: 1px;
|
||||
font-size: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
#VirtualKeyboardIME div.right {
|
||||
border-bottom: 10px solid #fff;
|
||||
border-left: 10px solid #000;
|
||||
border-right: 0px solid black;
|
||||
border-top: 10px solid #fff;
|
||||
float: right;
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
/************************************
|
||||
* Place for the locale-dependent styles
|
||||
* overload fonts here
|
||||
*
|
||||
* Language-dependend class name is equal to uppercased language domain code (ZH in zh-CN)
|
||||
*/
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span {
|
||||
font-family: MingLiU, SimSun, "Arial Unicode MS";
|
||||
font-size: 13px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span.alted,
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span.shifted {
|
||||
font-size: 9px;
|
||||
}
|
||||
#VirtualKeyboardIME.ZH div.IMEContent {
|
||||
font-family: SimSun, "Arial Unicode MS";
|
||||
font-size: 16px;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,338 @@
|
|||
html.VirtualKeyboardPopup, body.VirtualKeyboardPopup {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#virtualKeyboard {
|
||||
border: 1px solid #686888;
|
||||
background: #ECE9D8;
|
||||
height: 160px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 396px;
|
||||
}
|
||||
/*
|
||||
* global overrides
|
||||
*/
|
||||
#virtualKeyboard * {
|
||||
border: 0;
|
||||
color: black;
|
||||
cursor: default;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 4px 2px 0 2px;
|
||||
/*IE5.5 will ignore the rule below */
|
||||
margin/**/:/**/ 4px 2px 0 4px;
|
||||
padding/**/:/**/ 0;
|
||||
/*--*/
|
||||
position: relative;
|
||||
font-size: 1px;
|
||||
overflow: hidden;
|
||||
-moz-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div.kbButton {
|
||||
float: left;
|
||||
height: 26px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 26px;
|
||||
z-index: 2;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton a {
|
||||
background: url(button_set.gif) 0 0 no-repeat;
|
||||
display: block;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
}
|
||||
#virtualKeyboard #kbDesk.capsLock div.kbButton span.normal {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div.kbButtonHover a {
|
||||
background-position: 0 -27px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButtonDown a {
|
||||
background-position: 0 -54px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span {
|
||||
display: block;
|
||||
font-family: Verdana;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
overflow: visible;
|
||||
text-align: center;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.shifted,
|
||||
#virtualKeyboard #kbDesk div.kbButton span.alted {
|
||||
color: green;
|
||||
font-size: 6pt;
|
||||
height: 100%;
|
||||
line-height: 1.1;
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
top: 0;
|
||||
text-transform: none;
|
||||
vertical-align: bottom;
|
||||
width: 100%;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.alted {
|
||||
color: blue;
|
||||
right: 7px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div.kbButton span.normal {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
left: 5px;
|
||||
text-indent: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk span.deadKey {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#virtualKeyboard #kbDesk div#kb_benter {
|
||||
background-position: -194px 0px;
|
||||
margin-top: -26px;
|
||||
position: relative;
|
||||
float: right;
|
||||
height: 52px;
|
||||
width: 56px;
|
||||
z-index: -1;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter[id] {
|
||||
z-index: 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter a {
|
||||
background-position: -194px 0px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter.kbButtonHover a {
|
||||
background-position: -194px -53px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_benter.kbButtonDown a {
|
||||
background-position: -194px -106px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace a {
|
||||
background-position: -27px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonHover a {
|
||||
background-position: -27px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bbackspace.kbButtonDown a {
|
||||
background-position: -27px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab {
|
||||
width: 41px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab a {
|
||||
background-position: -155px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab.kbButtonHover a {
|
||||
background-position: -155px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_btab.kbButtonDown a {
|
||||
background-position: -155px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps {
|
||||
width: 48px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps a {
|
||||
background-position: -107px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonHover a {
|
||||
background-position: -107px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bcaps.kbButtonDown a {
|
||||
background-position: -107px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right {
|
||||
width: 52px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right a {
|
||||
background-position: -54px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonHover a {
|
||||
background-position: -54px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_bshift_right.kbButtonDown a {
|
||||
background-position: -54px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right {
|
||||
padding: 0 0 0 2px;
|
||||
width: 32px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left {
|
||||
margin-left: 33px;
|
||||
padding-left: 0;
|
||||
/*IE5.5 will ignore the rule below */
|
||||
padding-left/**/:/**/ 41px;
|
||||
margin-left/**/:/**/ 0;
|
||||
/*--*/
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right a {
|
||||
background-position: -251px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonHover a {
|
||||
background-position: -251px -27px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_balt_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_balt_right.kbButtonDown a {
|
||||
background-position: -251px -54px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right {
|
||||
float: left;
|
||||
width: 32px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right {
|
||||
float: right;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right a {
|
||||
background-position: -251px -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonHover a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonHover a {
|
||||
background-position: -251px -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_left.kbButtonDown a,
|
||||
#virtualKeyboard #kbDesk div#kb_bctrl_right.kbButtonDown a {
|
||||
background-position: -251px -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel a {
|
||||
background-position: 0 -81px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonHover a {
|
||||
background-position: 0 -108px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bdel.kbButtonDown a {
|
||||
background-position: 0 -135px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace {
|
||||
width: 166px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace a {
|
||||
background-position: -27px 0;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonHover a {
|
||||
background-position: -27px -27px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk div#kb_bspace.kbButtonDown a {
|
||||
background-position: -27px -54px;
|
||||
}
|
||||
|
||||
#virtualKeyboard select#kb_langselector,
|
||||
#virtualKeyboard select#kb_mappingselector {
|
||||
border: 1px solid black;
|
||||
bottom: 2px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
width: 125px;
|
||||
}
|
||||
#virtualKeyboard select#kb_mappingselector {
|
||||
right: 140px;
|
||||
}
|
||||
#virtualKeyboard select,
|
||||
#virtualKeyboard select option {
|
||||
background: #fff;
|
||||
font-family: Arial, Tahoma, Verdana sans-serif;
|
||||
font-size: 11px;
|
||||
}
|
||||
#virtualKeyboard select optgroup option {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#virtualKeyboard #copyrights {
|
||||
bottom: 4px;
|
||||
color: blue;
|
||||
font-size: 9px;
|
||||
left: 2px;
|
||||
line-height: normal;
|
||||
position: absolute;
|
||||
}
|
||||
#virtualKeyboard #copyrights a {
|
||||
font-size: 9px;
|
||||
color: blue;
|
||||
cursor: default;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Styles for the IME field
|
||||
*
|
||||
*/
|
||||
#VirtualKeyboardIME {
|
||||
background: #fff;
|
||||
border:1px solid #333;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
}
|
||||
#VirtualKeyboardIME div.IMEContent {
|
||||
border: 1px solid #333;
|
||||
border-top: 0;
|
||||
border-bottom: 0;
|
||||
height: 21px;
|
||||
line-height: 21px;
|
||||
margin: 0 12px;
|
||||
overflow: auto;
|
||||
padding: 0 3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#VirtualKeyboardIME div.left {
|
||||
border-bottom: 10px solid #fff;
|
||||
border-left: 0px solid black;
|
||||
border-right: 10px solid #000;
|
||||
border-top: 10px solid #fff;
|
||||
position: absolute;
|
||||
left: 1px;
|
||||
font-size: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
#VirtualKeyboardIME div.right {
|
||||
border-bottom: 10px solid #fff;
|
||||
border-left: 10px solid #000;
|
||||
border-right: 0px solid black;
|
||||
border-top: 10px solid #fff;
|
||||
float: right;
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
/************************************
|
||||
* Place for the locale-dependent styles
|
||||
* overload fonts here
|
||||
*
|
||||
* Language-dependend class name is equal to uppercased language domain code (ZH in zh-CN)
|
||||
*/
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span {
|
||||
font-family: MingLiU, SimSun, "Arial Unicode MS";
|
||||
font-size: 13px;
|
||||
}
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span.alted,
|
||||
#virtualKeyboard #kbDesk.ZH div.kbButton span.shifted {
|
||||
font-size: 9px;
|
||||
}
|
||||
#VirtualKeyboardIME.ZH div.IMEContent {
|
||||
font-family: SimSun, "Arial Unicode MS";
|
||||
font-size: 16px;
|
||||
}
|
|
@ -0,0 +1,695 @@
|
|||
/*
|
||||
* $Id: documentselection.js 413 2008-05-16 21:30:59Z wingedfox $
|
||||
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/documentselection.js $
|
||||
*
|
||||
* Class implements cross-browser work with text selection
|
||||
*
|
||||
* @author Ilya Lebedev
|
||||
* @author $Author: wingedfox $
|
||||
* @modified $Date: 2008-05-17 01:30:59 +0400 (Сбт, 17 Май 2008) $
|
||||
* @version $Rev: 413 $
|
||||
* @license LGPL
|
||||
*/
|
||||
/*
|
||||
* @class DocumentSelection
|
||||
*/
|
||||
DocumentSelection = new function () {
|
||||
var self = this;
|
||||
/*
|
||||
* Stores hash of keys, applied to elements
|
||||
*
|
||||
* @type Object
|
||||
* @scope private
|
||||
*/
|
||||
var keys = {
|
||||
'prevCalcNode' : '__prevCalcNode'
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// PRIVATES
|
||||
//---------------------------------------------------------------------------
|
||||
/**
|
||||
* Calls specified method with the supplied params
|
||||
* This is done to process only correct requests
|
||||
*
|
||||
* @param {Function} method to call
|
||||
* @param {Array} arguments of [target, param1, paramN]
|
||||
* @return {Object} method call result or false, if any error happened
|
||||
* @scope private
|
||||
*/
|
||||
var callMethod = function (m, arg) {
|
||||
var el = arg[0]
|
||||
,id
|
||||
,module = ""
|
||||
if (!el || !el.tagName) return false;
|
||||
switch (arg[0].tagName.toLowerCase()) {
|
||||
case 'input':
|
||||
if (el.type && el.type != 'text' && el.type != 'password') return false;
|
||||
case 'textarea':
|
||||
module = "input";
|
||||
break;
|
||||
case 'iframe':
|
||||
module = "frame";
|
||||
arg[0] = el.contentWindow;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
* instantiate the module
|
||||
*/
|
||||
if ('function' == typeof self.module[module])
|
||||
self.module[module] = new self.module[module](keys);
|
||||
/*
|
||||
* throw the exception, is method is not implemented
|
||||
*/
|
||||
if (!self.module[module] || !self.module[module][m])
|
||||
throw new Error ('Method \''+m+'\' is not implemented for DocumentSelection \''+module+'\' module.');
|
||||
|
||||
return self.module[module][m].apply(self,arg);
|
||||
}
|
||||
/**
|
||||
* Keeps scrolling on the place for browsers, those don't support this natively
|
||||
*
|
||||
* @param {HTMLElement} el target element
|
||||
* @param {Number} ot old scrollTop property
|
||||
* @param {Number} ol old scrollLeft property
|
||||
* @scope private
|
||||
*/
|
||||
var keepScroll = function (el,ot,ol) {
|
||||
if (window.getSelection && 'iframe'!=el.tagName.toLowerCase()) {
|
||||
var q = self.getSelectionOffset(el)
|
||||
if (el.contentWindow) el = el.contentWindow.document.body;
|
||||
|
||||
if (ot>q.y) el.scrollTop = q.y;
|
||||
else if (ot+el.clientHeight>q.y) el.scrollTop = ot;
|
||||
else el.scrollTop = q.y-el.clientHeight/2;
|
||||
|
||||
if (ol>q.x) el.scrollLeft = q.x;
|
||||
else if (ol+el.clientWidth>q.x) el.scrollLeft = ol;
|
||||
else el.scrollLeft = q.x-el.clientWidth/2;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// SETTERS
|
||||
//---------------------------------------------------------------------------
|
||||
/**
|
||||
* getSelectionRange wrapper/emulator
|
||||
*
|
||||
* @param {HTMLElement}
|
||||
* @param {Number} start position
|
||||
* @param {Number} end position
|
||||
* @param {Boolean} related indicates calculation of range relatively to current start point
|
||||
* @return void
|
||||
* @scope public
|
||||
*/
|
||||
self.setRange = function(el, start, end, related) {
|
||||
var ot = el.scrollTop
|
||||
,ol = el.scrollLeft
|
||||
/*
|
||||
* set range on relative coordinates
|
||||
*/
|
||||
if (related) {
|
||||
var st = self.getStart(el);
|
||||
end = st+end;
|
||||
start = st+start;
|
||||
}
|
||||
if (start < 0) start = 0;
|
||||
if (end < start) end = start;
|
||||
|
||||
callMethod ('setRange',[el,start,end]);
|
||||
|
||||
keepScroll(el,ot,ol);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// GETTERS
|
||||
//---------------------------------------------------------------------------
|
||||
/**
|
||||
* Return contents of the current selection
|
||||
*
|
||||
* @param {HTMLElement} el element to look position on
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
self.getSelection = function(el) {
|
||||
return callMethod('getSelection',[el]);
|
||||
}
|
||||
/**
|
||||
* getSelectionStart wrapper/emulator
|
||||
* adapted version
|
||||
*
|
||||
* @param {HTMLElement} el element to calculate end position for
|
||||
* @return {Number} start position
|
||||
* @scope public
|
||||
*/
|
||||
self.getStart = function (el) {
|
||||
return callMethod('getPos',[el,true]);
|
||||
}
|
||||
/*
|
||||
* getSelectionEnd wrapper/emulator
|
||||
* adapted version
|
||||
*
|
||||
* @param {HTMLElement} el element to calculate end position for
|
||||
* @return {Number} start position
|
||||
* @scope public
|
||||
*/
|
||||
self.getEnd = function (el) {
|
||||
return callMethod('getPos',[el,false]);
|
||||
}
|
||||
/*
|
||||
* Return cursor position for supplied field
|
||||
*
|
||||
* @param {HTMLElement} element to get cursor position from
|
||||
* @return {Number} position
|
||||
* @scope public
|
||||
*/
|
||||
self.getCursorPosition = function (el) {
|
||||
return self.getStart(el);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
// MISC FUNCTIONS
|
||||
//---------------------------------------------------------------------------
|
||||
/*
|
||||
* Insert text at cursor position
|
||||
*
|
||||
* @param {HTMLElement} text field to insert text
|
||||
* @param {String} text to insert
|
||||
* @scope public
|
||||
*/
|
||||
self.insertAtCursor = function (el, val, keep) {
|
||||
var ot = el.scrollTop
|
||||
,ol = el.scrollLeft
|
||||
if (!keep) {
|
||||
callMethod('del',[el]);
|
||||
}
|
||||
var pos = callMethod('ins',[el,val]);
|
||||
keepScroll(el,ot,ol);
|
||||
return pos;
|
||||
}
|
||||
/*
|
||||
* Wraps selection with start and end text
|
||||
*
|
||||
* @param {HTMLElement} text field to insert text
|
||||
* @param {String} start text at the beginnging of the selection
|
||||
* @param {String} end text at the end of the selection
|
||||
* @scope public
|
||||
*/
|
||||
self.wrapSelection = function (el, start, end) {
|
||||
var s = self.getCursorPosition(el)
|
||||
,e = self.getEnd(el)
|
||||
if (s==e) {
|
||||
self.insertAtCursor(el,start+end);
|
||||
} else {
|
||||
self.insertAtCursor(el,start,true);
|
||||
self.setRange(el,e+start.length,e+start.length);
|
||||
self.insertAtCursor(el,end,true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletes char at cursor position
|
||||
*
|
||||
* @param {HTMLElement} text field to delete text
|
||||
* @param {Boolean} delete text before (backspace) or after (del) cursor
|
||||
* @scope public
|
||||
*/
|
||||
self.deleteAtCursor = function (el, after) {
|
||||
if (!self.getSelection(el)) {
|
||||
if (after)
|
||||
self.setRange(el,0,1,true);
|
||||
else
|
||||
self.setRange(el,-1,0,true);
|
||||
}
|
||||
return self.deleteSelection(el);
|
||||
}
|
||||
/**
|
||||
* Removes the selection, if available
|
||||
*
|
||||
* @param {HTMLElement} el field to delete text from
|
||||
* @scope public
|
||||
*/
|
||||
self.deleteSelection = function (el) {
|
||||
var ol = el.scrollLeft
|
||||
,ot = el.scrollTop
|
||||
,ret = callMethod('del',[el]);
|
||||
keepScroll(el,ot,ol);
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Method is used to caclulate pixel offsets for the selection in TextArea (other inputs are not tested yet)
|
||||
*
|
||||
* @param {HTMLTextareaElement} el target to calculate offsets
|
||||
* @return {Object} {x: horizontal offset, y: vertical offset, h: height offset}
|
||||
* @scope public
|
||||
*/
|
||||
self.getSelectionOffset = function (el) {
|
||||
return callMethod('getSelectionOffset',[el],true);
|
||||
}
|
||||
|
||||
}
|
||||
DocumentSelection.module = {
|
||||
/**
|
||||
* Module processing selection in the 'input' and 'textarea' fields
|
||||
*
|
||||
* @param {Object} keys properties, registered for use in DS
|
||||
* @scope protected
|
||||
*/
|
||||
'input' : function (keys) {
|
||||
var self=this;
|
||||
/**
|
||||
* Special document node, used to calculate range offsets in Mozilla
|
||||
*
|
||||
* @type HtmlDivElement
|
||||
* @scope private
|
||||
*/
|
||||
var offsetCalculator = null;
|
||||
/**
|
||||
* Returns selection start or end position in absolute chars from the field start
|
||||
*
|
||||
* @param {HTMLInputElement, HTMLTextareaElement} el input or textarea to get position from
|
||||
* @param {Boolean} start get start or end selection position
|
||||
* @return {Number} offset from the beginning
|
||||
* @scope private
|
||||
*/
|
||||
self.getPos = function (el, start) {
|
||||
var off;
|
||||
try {
|
||||
el.setActive();
|
||||
if (start)
|
||||
off = Math.abs(el.document.selection.createRange().moveStart("character", -100000000));
|
||||
else
|
||||
off = Math.abs(el.document.selection.createRange().moveEnd("character", -100000000));
|
||||
/*
|
||||
* test for the TEXTAREA's dumb behavior
|
||||
*/
|
||||
if (el.tagName.toLowerCase() != 'input') {
|
||||
/*
|
||||
* calculate node offset
|
||||
*/
|
||||
var r = el.document.body.createTextRange();
|
||||
r.moveToElementText(el);
|
||||
var sTest = Math.abs(r.moveStart("character", -100000000));
|
||||
off -= sTest;
|
||||
}
|
||||
} catch (e) {
|
||||
try {
|
||||
off = (start?el.selectionStart:el.selectionEnd);
|
||||
} catch (e) {
|
||||
off = 0;
|
||||
}
|
||||
}
|
||||
return off;
|
||||
}
|
||||
/**
|
||||
* Removes the selection, if available
|
||||
*
|
||||
* @param {HTMLElement} el field to delete text from
|
||||
* @return {String} deleted substring
|
||||
* @scope public
|
||||
*/
|
||||
self.del = function (el) {
|
||||
var ret = ""
|
||||
,s = self.getPos(el,true)
|
||||
,e = self.getPos(el,false)
|
||||
if (s!=e) {
|
||||
/*
|
||||
* check for IE, because Opera does use \r\n sequence, but calculate positions correctly
|
||||
*/
|
||||
var tmp = document.selection&&!window.opera?el.value.replace(/\r/g,""):el.value;
|
||||
ret = tmp.substring(s,e);
|
||||
el.value = tmp.substring(0, s)+tmp.substring(e,tmp.length);
|
||||
self.setRange(el,s,s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/**
|
||||
* Inserts text to the textarea
|
||||
*
|
||||
* @param {HTMLElement} text field to insert text
|
||||
* @param {String} text to insert
|
||||
* @return {Number} new cursor position
|
||||
* @scope public
|
||||
*/
|
||||
self.ins = function (el,val) {
|
||||
var ret = ""
|
||||
,s = self.getPos(el,true)
|
||||
/*
|
||||
* check for IE, because Opera does use \r\n sequence, but calculate positions correctly
|
||||
*/
|
||||
var tmp = document.selection&&!window.opera?el.value.replace(/\r/g,""):el.value;
|
||||
el.value = tmp.substring(0,s)+val+tmp.substring(s,tmp.length);
|
||||
s += val.length;
|
||||
self.setRange(el,s,s);
|
||||
return s;
|
||||
}
|
||||
/**
|
||||
* Return contents of the current selection
|
||||
*
|
||||
* @param {HTMLElement} el element to look position on
|
||||
* @param {Number} s start position
|
||||
* @param {Number} e end position
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
self.getSelection = function (el) {
|
||||
var s = self.getPos(el,true),
|
||||
e = self.getPos(el,false)
|
||||
/*
|
||||
* w/o this check content might be duplicated on delete
|
||||
*/
|
||||
if (e<s) e = s;
|
||||
/*
|
||||
* check for IE, because Opera does use \r\n sequence, but calculate positions correctly
|
||||
*/
|
||||
var tmp = document.selection&&!window.opera?el.value.replace(/\r/g,""):el.value;
|
||||
return tmp.substring(s,e);
|
||||
}
|
||||
/**
|
||||
* Sets the selection range
|
||||
*
|
||||
* @param {HTMLElement}
|
||||
* @param {Number} start position
|
||||
* @param {Number} end position
|
||||
* @return void
|
||||
* @scope public
|
||||
*/
|
||||
self.setRange = function (el,start,end) {
|
||||
if ('function' == typeof el.setSelectionRange) {
|
||||
/*
|
||||
* for Mozilla
|
||||
*/
|
||||
try {el.setSelectionRange(start, end)} catch (e) {}
|
||||
} else {
|
||||
/*
|
||||
* for IE
|
||||
*/
|
||||
var range;
|
||||
/*
|
||||
* just try to create a range....
|
||||
*/
|
||||
try {
|
||||
range = el.createTextRange();
|
||||
} catch(e) {
|
||||
try {
|
||||
range = el.document.body.createTextRange();
|
||||
range.moveToElementText(el);
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
el.focus();
|
||||
range.collapse(true);
|
||||
range.moveStart("character", start);
|
||||
range.moveEnd("character", end - start);
|
||||
range.select();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Method is used to caclulate pixel offsets for the selection in TextArea (other inputs are not tested yet)
|
||||
*
|
||||
* @param {HTMLTextareaElement} el target to calculate offsets
|
||||
* @return {Object} {x: horizontal offset, y: vertical offset, h: height offset}
|
||||
* @scope public
|
||||
*/
|
||||
self.getSelectionOffset = function (el) {
|
||||
var range;
|
||||
if ('function' == typeof el.setSelectionRange) {
|
||||
/*
|
||||
* For Mozilla
|
||||
*/
|
||||
if (!offsetCalculator) {
|
||||
/*
|
||||
* create hidden div, which will 'emulate' the textarea
|
||||
* it's put 'below the ground', because toggling block/none is too expensive
|
||||
*/
|
||||
offsetCalculator = document.createElement('td');
|
||||
|
||||
document.body.appendChild(offsetCalculator);
|
||||
}
|
||||
/*
|
||||
* store the reference to last-checked object, to prevent recalculation of styles
|
||||
*/
|
||||
if (offsetCalculator[keys.prevCalcNode] != el) {
|
||||
offsetCalculator[keys.prevCalcNode] = el;
|
||||
var cs = document.defaultView.getComputedStyle(el, null);
|
||||
for (var i in cs) {
|
||||
try {if (cs[i]) offsetCalculator.style[i] = cs[i];}catch(e){}
|
||||
}
|
||||
offsetCalculator.style.overflow = 'auto';
|
||||
offsetCalculator.style.position = 'absolute';
|
||||
offsetCalculator.style.visibility = 'hidden';
|
||||
offsetCalculator.style.zIndex = '-10';
|
||||
offsetCalculator.style.left="-10000px";
|
||||
offsetCalculator.style.top="-10000px";
|
||||
offsetCalculator.style.backgroundColor = 'yellow';
|
||||
}
|
||||
/*
|
||||
* caclulate offsets to target and move div right below it
|
||||
*/
|
||||
var range = document.createRange()
|
||||
,val = el.value || " ";
|
||||
|
||||
if ('input'==el.tagName.toLowerCase()) {
|
||||
offsetCalculator.style.width = 'auto'
|
||||
offsetCalculator.style.whiteSpace = 'nowrap';
|
||||
} else {
|
||||
offsetCalculator.style.whiteSpace = 'off'==el.getAttribute('wrap')?"pre":"";
|
||||
}
|
||||
|
||||
val = val.replace(/\x20\x20/g,"\x20\xa0").replace(/</g,"<").replace(/>/g,">");
|
||||
offsetCalculator.innerHTML = ( val.substring(0,el.selectionStart-1)+"<span>"+val.substring(el.selectionStart-1,el.selectionStart)+"</span>"
|
||||
+val.substring(el.selectionStart)).replace(/\n/g,"<br />")
|
||||
.replace(/\t/g,"<em style=\"white-space:pre\">\t</em>")
|
||||
/*
|
||||
* span is used to find the offsets
|
||||
*/
|
||||
var span = offsetCalculator.getElementsByTagName('span')[0];
|
||||
span.style.border = '1px solid red';
|
||||
range.offsetLeft = span.offsetLeft// - el.scrollLeft + span.clientWidth;
|
||||
range.offsetTop = span.offsetTop// - el.scrollTop;
|
||||
range.offsetHeight = span.offsetHeight;
|
||||
if ("\n"==val.charAt(el.selectionStart-1)) range.offsetTop += range.offsetHeight*2;
|
||||
span = null;
|
||||
} else if (document.selection && document.selection.createRange) {
|
||||
/*
|
||||
* For IE
|
||||
*/
|
||||
range = document.selection.createRange();
|
||||
/*
|
||||
* IE does not allow to calculate lineHeight, but this check is easy
|
||||
*/
|
||||
range.offsetHeight = Math.round(range.boundingHeight/(range.text.replace(/[^\n]/g,"").length+1));
|
||||
if (el.tagName && 'textarea'==el.tagName.toLowerCase()) {
|
||||
var xy = DOM.getOffset(el)
|
||||
range = {
|
||||
'offsetTop' : range.offsetTop-xy.y+DOM.getBodyScrollTop()
|
||||
,'offsetLeft' : range.offsetLeft-xy.x+DOM.getBodyScrollLeft()
|
||||
,'offsetHeight' : range.offsetHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
if (range) {
|
||||
return {'x': range.offsetLeft, 'y': range.offsetTop, 'h': range.offsetHeight};
|
||||
}
|
||||
return {'x': 0, 'y': 0, 'h': 0};
|
||||
}
|
||||
}
|
||||
,'frame' : function () {
|
||||
var self=this;
|
||||
/**
|
||||
* Returns selection start or end position in absolute chars from the field start
|
||||
*
|
||||
* @param {HTMLInputElement, HTMLTextareaElement} el input or textarea to get position from
|
||||
* @param {Boolean} start get start or end selection position
|
||||
* @return {Number} offset from the beginning
|
||||
* @scope private
|
||||
*/
|
||||
self.getPos = function (el, start) {
|
||||
var pos = 0
|
||||
if ('function' == typeof el.getSelection) {
|
||||
/*
|
||||
* we need to calculate both start and end points, because range could be reversed
|
||||
* but we can't move selection end point before start one
|
||||
*/
|
||||
var sel = el.getSelection()
|
||||
,sn = sel.anchorNode
|
||||
,so = sel.anchorOffset
|
||||
,en = sel.focusNode
|
||||
,eo = sel.focusOffset
|
||||
,ss = false
|
||||
,es = false
|
||||
,sc = 0
|
||||
,ec = 0
|
||||
,cn
|
||||
,tw=document.createTreeWalker(el.document.body,NodeFilter.SHOW_TEXT,null,false)
|
||||
while (sn && sn.nodeType != 3) {
|
||||
sn = sn.childNodes[so]
|
||||
so = 0;
|
||||
}
|
||||
while (en && en.nodeType != 3) {
|
||||
en = en.childNodes[eo]
|
||||
eo = 0;
|
||||
}
|
||||
while (cn=tw.nextNode()) {
|
||||
if (cn == en) {
|
||||
ec += eo
|
||||
es = true
|
||||
}
|
||||
if (cn == sn) {
|
||||
sc += so
|
||||
ss = true
|
||||
}
|
||||
if (!es) ec += cn.nodeValue.length
|
||||
if (!ss) sc += cn.nodeValue.length
|
||||
if (es && ss) break;
|
||||
}
|
||||
pos = start?Math.min(ec,sc):Math.max(ec,sc)
|
||||
} else {
|
||||
el.document.body.setActive();
|
||||
pos = Math.abs(el.document.selection.createRange()[start?"moveStart":"moveEnd"]("character", -100000000));
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
/**
|
||||
* Removes the selection, if available
|
||||
*
|
||||
* @param {HTMLElement} el field to delete text from
|
||||
* @return {String} deleted substring
|
||||
* @scope public
|
||||
*/
|
||||
self.del = function (el) {
|
||||
if ('function' == typeof el.getSelection) {
|
||||
var s = el.getSelection()
|
||||
,i = s.rangeCount
|
||||
while (--i>-1) s.getRangeAt(i).deleteContents();
|
||||
} else if (el.document && el.document.selection) {
|
||||
el.document.selection.createRange().text = "";
|
||||
el.document.selection.createRange().select();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Inserts text to the textarea
|
||||
*
|
||||
* @param {HTMLElement} text field to insert text
|
||||
* @param {String} text to insert
|
||||
* @scope public
|
||||
*/
|
||||
self.ins = function (el,val) {
|
||||
var p = self.getPos(el,true)+val.length;
|
||||
if ('function' == typeof el.getSelection) {
|
||||
var n = el.document.createTextNode(val)
|
||||
,s = el.getSelection()
|
||||
s.getRangeAt(0).insertNode(n);
|
||||
n.parentNode.normalize();
|
||||
} else if (el.document && el.document.selection) {
|
||||
el.document.body.setActive();
|
||||
el.document.selection.createRange().text = val;
|
||||
}
|
||||
self.setRange(el,p,p)
|
||||
return p;
|
||||
}
|
||||
/**
|
||||
* Return contents of the current selection
|
||||
*
|
||||
* @param {HTMLElement} el element to look position on
|
||||
* @param {Number} s start position
|
||||
* @param {Number} e end position
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
self.getSelection = function (el,s,e) {
|
||||
if ('function' == typeof el.getSelection) {
|
||||
var s = el.getSelection();
|
||||
return s?s.toString():"";
|
||||
} else if (el.document && el.document.selection) {
|
||||
return el.document.selection.createRange().text;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets the selection range
|
||||
*
|
||||
* @param {HTMLElement}
|
||||
* @param {Number} start position
|
||||
* @param {Number} end position
|
||||
* @return void
|
||||
* @scope public
|
||||
*/
|
||||
self.setRange = function (el,start,end) {
|
||||
if ('function' == typeof el.getSelection) {
|
||||
var sel = el.getSelection();
|
||||
sel.removeAllRanges();
|
||||
var r = el.document.createRange()
|
||||
,cnt = 0
|
||||
,cl = 0
|
||||
,cn
|
||||
,pn
|
||||
,tw=document.createTreeWalker(el.document.body,NodeFilter.SHOW_TEXT,null,false);
|
||||
|
||||
while ((cn=tw.nextNode())&&(!cn.nodeValue.length||(cnt+cn.nodeValue.length < start))) {
|
||||
pn = cn;
|
||||
cnt += cn.nodeValue.length;
|
||||
}
|
||||
/*
|
||||
* explicitly set range borders
|
||||
*/
|
||||
if (cn||(cn=pn)) {
|
||||
r.setStart(cn,start-cnt);
|
||||
r.setEnd(cn,start-cnt);
|
||||
}
|
||||
if (cn) {
|
||||
do {
|
||||
if (cn.nodeType != 3) continue;
|
||||
if (cnt+cn.nodeValue.length < end) {
|
||||
cnt += cn.nodeValue.length;
|
||||
} else {
|
||||
r.setEnd(cn,end-cnt);
|
||||
break;
|
||||
}
|
||||
} while (cn=tw.nextNode())
|
||||
}
|
||||
sel.addRange(r);
|
||||
} else if (el.document && el.document.selection) {
|
||||
el.document.body.setActive();
|
||||
var r = el.document.selection.createRange()
|
||||
r.moveToElementText(el.document.body);
|
||||
r.move("character",start);
|
||||
r.moveEnd("character",end-start);
|
||||
r.select();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Method is used to calculate pixel offsets for the selection in TextArea (other inputs are not tested yet)
|
||||
*
|
||||
* @param {HTMLTextareaElement} el target to calculate offsets
|
||||
* @return {Object} {x: horizontal offset, y: vertical offset, h: height offset}
|
||||
* @scope public
|
||||
*/
|
||||
self.getSelectionOffset = function (el) {
|
||||
var off = {'x':0, 'y':0, 'h':0};
|
||||
if ('function' == typeof el.getSelection) {
|
||||
var r = el.getSelection().getRangeAt(0)
|
||||
,e = r.endOffset
|
||||
,s = el.document.createElement('span')
|
||||
,n = s;
|
||||
s.style.borderLeft='1px solid red';
|
||||
r.insertNode(s);
|
||||
off.h = n.offsetHeight;
|
||||
while (n.offsetParent) {
|
||||
off.x += n.offsetLeft;
|
||||
off.y += n.offsetTop;
|
||||
n = n.offsetParent
|
||||
}
|
||||
s.parentNode.removeChild(s);
|
||||
if (e-r.endOffset) {
|
||||
r.setEnd(r.endContainer.nextSibling,e-r.endOffset);
|
||||
el.getSelection().addRange(r)
|
||||
}
|
||||
} else if (el.document && el.document.selection) {
|
||||
var r = el.document.selection.createRange()
|
||||
off.h = r.boundingHeight
|
||||
off.x = r.offsetLeft;
|
||||
off.y = r.offsetTop;
|
||||
}
|
||||
return off;
|
||||
}
|
||||
}
|
||||
}
|
338
fotokiste/fotokiste/static/virtual_keyboard/extensions/dom.js
Normal file
338
fotokiste/fotokiste/static/virtual_keyboard/extensions/dom.js
Normal file
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* $Id: dom.js 378 2007-12-13 10:07:23Z wingedfox $
|
||||
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/dom.js $
|
||||
*
|
||||
* DOM-related stuff and CSS manipulation class
|
||||
*
|
||||
* @author Ilya Lebedev
|
||||
* @author $Author: wingedfox $
|
||||
* @modified $Date: 2007-12-13 13:07:23 +0300 (Чтв, 13 Дек 2007) $
|
||||
* @version $Rev: 378 $
|
||||
* @license LGPL
|
||||
* @depends helpers.js
|
||||
* @depends arrayextensions.js
|
||||
*/
|
||||
|
||||
if (isUndefined(DOM)) var DOM = {};
|
||||
/**
|
||||
* Performs parent lookup by
|
||||
* - node object: actually it's "is child of" check
|
||||
* - tagname: getParent(el, 'li') == getParent(el, 'tagName', 'LI')
|
||||
* - any node attribute
|
||||
*
|
||||
* @param {HTMLElement} el source element
|
||||
* @param {HTMLElement, String} cp DOMNode or string tagname or string attribute name
|
||||
* @param {String} vl optional attribute value
|
||||
* @return {HTMLElement, Null}
|
||||
* @scope public
|
||||
*/
|
||||
DOM.getParent = function (el /* : HTMLElement */, cp /* :String, HTMLElement */, vl /* :String */) /* :HTMLElement */ {
|
||||
if (el == null) return null;
|
||||
else if (el.nodeType == 1 &&
|
||||
((!isUndefined(vl) && el[cp] == vl) ||
|
||||
('string' == typeof cp && DOM.hasTagName(el, cp)) ||
|
||||
el == cp)) return el;
|
||||
else return arguments.callee(el.parentNode, cp, vl);
|
||||
};
|
||||
/**
|
||||
* Calculates the offset for the DOM node from top left corner
|
||||
*
|
||||
* @author Matt Kruse
|
||||
* @see http://javascripttoolbox.com/lib/objectposition/index.php
|
||||
* @param {HTMLElement} el
|
||||
* @return {Object} x: horizontal offset, y: vertical offset
|
||||
* @scope public
|
||||
*/
|
||||
DOM.getOffset = function (el /* :HTMLElement */) /* :Object */ {
|
||||
var fixBrowserQuirks = true
|
||||
,o = el
|
||||
,left = 0
|
||||
,top = 0
|
||||
,width = 0
|
||||
,height = 0
|
||||
,parentNode = null
|
||||
,offsetParent = null;
|
||||
|
||||
if (o==null) return null;
|
||||
|
||||
offsetParent = o.offsetParent;
|
||||
var originalObject = o
|
||||
,el = o; // "el" will be nodes as we walk up, "o" will be saved for offsetParent references
|
||||
while (el.parentNode!=null) {
|
||||
el = el.parentNode;
|
||||
if (el.offsetParent!==null) {
|
||||
var considerScroll = true;
|
||||
/*
|
||||
In Opera, if parentNode of the first object is scrollable, then offsetLeft/offsetTop already
|
||||
take its scroll position into account. If elements further up the chain are scrollable, their
|
||||
scroll offsets still need to be added in. And for some reason, TR nodes have a scrolltop value
|
||||
which must be ignored.
|
||||
*/
|
||||
if (fixBrowserQuirks && window.opera) {
|
||||
if (el==originalObject.parentNode || el.nodeName=="TR") {
|
||||
considerScroll = false;
|
||||
}
|
||||
}
|
||||
if (considerScroll) {
|
||||
if (el.scrollTop && el.scrollTop>0) {
|
||||
top -= el.scrollTop;
|
||||
}
|
||||
if (el.scrollLeft && el.scrollLeft>0) {
|
||||
left -= el.scrollLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If this node is also the offsetParent, add on the offsets and reset to the new offsetParent
|
||||
if (el == offsetParent) {
|
||||
left += o.offsetLeft;
|
||||
if (el.clientLeft && el.nodeName!="TABLE") {
|
||||
left += el.clientLeft;
|
||||
}
|
||||
top += o.offsetTop;
|
||||
if (el.clientTop && el.nodeName!="TABLE") {
|
||||
top += el.clientTop;
|
||||
}
|
||||
o = el;
|
||||
if (o.offsetParent==null) {
|
||||
if (o.offsetLeft) {
|
||||
left += o.offsetLeft;
|
||||
}
|
||||
if (o.offsetTop) {
|
||||
top += o.offsetTop;
|
||||
}
|
||||
}
|
||||
offsetParent = o.offsetParent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (originalObject.offsetWidth) {
|
||||
width = originalObject.offsetWidth;
|
||||
}
|
||||
if (originalObject.offsetHeight) {
|
||||
height = originalObject.offsetHeight;
|
||||
}
|
||||
|
||||
return {'x':left, 'y':top, 'width':width, 'height':height};
|
||||
};
|
||||
|
||||
//DOM.getOffset = function (el /* :HTMLElement */) /* :Object */ {
|
||||
/*
|
||||
var xy = {'x' : el.offsetLeft , 'y' : el.offsetTop};
|
||||
if (el.offsetParent) {
|
||||
var xy1 = arguments.callee(el.offsetParent);
|
||||
xy.x += xy1.x;
|
||||
xy.y += xy1.y;
|
||||
}
|
||||
return xy;
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Returns the width of the window canvas
|
||||
*
|
||||
* @return {Number}
|
||||
* @scope public
|
||||
*/
|
||||
DOM.getClientWidth = function () /* :Number */{
|
||||
var w=0;
|
||||
if (self.innerHeight) w = self.innerWidth;
|
||||
else if (document.documentElement && document.documentElement.clientWidth) w = document.documentElement.clientWidth;
|
||||
else if (document.body) w = document.body.clientWidth;
|
||||
return w;
|
||||
};
|
||||
/**
|
||||
* Returns the height of the window canvas
|
||||
*
|
||||
* @return {Number}
|
||||
* @scope public
|
||||
*/
|
||||
DOM.getClientHeight = function () /* :Number */{
|
||||
var h=0;
|
||||
if (self.innerHeight) h = self.innerHeight;
|
||||
else if (document.documentElement && document.documentElement.clientHeight) h = document.documentElement.clientHeight;
|
||||
else if (document.body) h = document.body.clientHeight;
|
||||
return h;
|
||||
};
|
||||
/**
|
||||
* Returns the height of the scrolled area for the body
|
||||
*
|
||||
* @return {Number}
|
||||
* @scope public
|
||||
*/
|
||||
DOM.getBodyScrollTop = function () /* :Number */{
|
||||
return self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || (document.body && document.body.scrollTop);
|
||||
};
|
||||
/**
|
||||
* Returns the height of the scrolled area for the body
|
||||
*
|
||||
* @return {Number}
|
||||
* @scope public
|
||||
*/
|
||||
DOM.getBodyScrollLeft = function () /* :Number */{
|
||||
return self.pageXOffset || (document.documentElement && document.documentElement.scrollLeft) || (document.body && document.body.scrollLeft);
|
||||
};
|
||||
/**
|
||||
* Calculates cursor position properly
|
||||
*
|
||||
* @param {Event} e event object to get cursor positions from
|
||||
* @return {Object} object with x and y cursor positions
|
||||
* @scope protected
|
||||
* @see http://hartshorne.ca/2006/01/23/javascript_cursor_position/
|
||||
* @author Beau Hartshorne
|
||||
*/
|
||||
DOM.getCursorPosition = function (e) {
|
||||
if (e.pageX || e.pageY) return {'x': e.pageX, 'y': e.pageY};
|
||||
|
||||
var de = document.documentElement || document.body;
|
||||
return {'x': e.clientX + de.scrollLeft - (de.clientLeft || 0)
|
||||
,'y': e.clientY + de.scrollTop - (de.clientTop || 0)};
|
||||
};
|
||||
/**
|
||||
* Checks, if property matches a tagname(s)
|
||||
*
|
||||
* @param {HTMLElement} prop
|
||||
* @param {String, Array} tags
|
||||
* @return {Boolean}
|
||||
* @scope public
|
||||
*/
|
||||
DOM.hasTagName = function (prop /* :HTMLElement */, tags /* :String, Array */) {
|
||||
if (isString(tags)) tags = [tags];
|
||||
if (!isArray(tags) || isEmpty(tags) || isUndefined(prop) || isEmpty(prop.tagName)) return false;
|
||||
var t = prop.tagName.toLowerCase();
|
||||
for (var i=0, tL=tags.length; i<tL; i++) {
|
||||
if (tags[i].toLowerCase() == t) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* Return the actual rgb color value from the following formats
|
||||
* #rrggbb
|
||||
* #rgb
|
||||
* rgb (0..255, 0..255,0..255)
|
||||
* rgb (0..100%, 0..100%,0..100%)
|
||||
* <color_name>
|
||||
*
|
||||
* @param {String} from attr name
|
||||
* @return {Array} r,g,b values
|
||||
* @scope public
|
||||
*/
|
||||
DOM.color2rgb = function (prop) {
|
||||
var e;
|
||||
/*
|
||||
* note, properties like borderColor might have the series of colors
|
||||
*/
|
||||
if (/^([a-z]+)($|\s[a-z]+)/i.test(prop)) {
|
||||
var d = document.body, ov = d.vLink;
|
||||
d.vLink = prop.split(" ")[0];
|
||||
prop = d.vLink;
|
||||
d.vLink = ov;
|
||||
}
|
||||
try {
|
||||
if (e = prop.match(/^#([\da-f]{6})$/i))
|
||||
return e=parseInt(e[1],16),[(e&0xff0000)>>16,(e&0xff00)>>8,(e&0xff)]
|
||||
else if (e = prop.match(/^#([\da-f]{3})$/i)) {
|
||||
return e=parseInt(e[1],16),[((e&0xf00)>>8)*0x11,((e&0xf0)>>4)*0x11,(e&0xf)*0x11];
|
||||
} else
|
||||
return (prop.match(/([\d%]+)/g).splice(0,3).map(function(a){ return /%/.test(a)?(parseInt(a)*2.55).toFixed(0):parseInt(a)}))
|
||||
} catch(err){
|
||||
}
|
||||
}
|
||||
/**
|
||||
* DOM.CSS is the CSS processing class, allowing to easy mangle class names
|
||||
*
|
||||
* @param {HTMLElement} el element to provide interface for
|
||||
* @scope public
|
||||
* @constructor
|
||||
* @class DOM.CSS
|
||||
* @exception on invalid parameter
|
||||
* @depends arrayextensions.js
|
||||
* @depends helpers.js
|
||||
*/
|
||||
DOM.CSS = function (el) {
|
||||
var self = this
|
||||
/**
|
||||
* Adds the class name, unlimited number of arguments is supported
|
||||
*
|
||||
* @param {String} class classname to apply to the element
|
||||
* @return {Object} singleton object to chain operations
|
||||
* @scope public
|
||||
*/
|
||||
self.addClass = function() {
|
||||
var arg = isArray(arguments[0])?arguments[0]:Array.prototype.slice.call(arguments);
|
||||
self.removeClass(arg);
|
||||
el.className = el.className+" "+Array.prototype.join.call(arg," ");
|
||||
return self;
|
||||
};
|
||||
/**
|
||||
* Removes the class name, unlimited number of arguments is supported
|
||||
*
|
||||
* @param {String} class classname to apply to the element
|
||||
* @return {Object} singleton object to chain operations
|
||||
* @scope public
|
||||
*/
|
||||
self.removeClass = function() {
|
||||
var arg = Array.prototype.join.call((isArray(arguments[0])?arguments[0]:arguments),"|");
|
||||
if (!arguments.callee.cache) arguments.callee.cache = {}
|
||||
var c = arguments.callee.cache
|
||||
if (!c.hasOwnProperty(arg)) c[arg] = new RegExp("(^|\\s+)("+arg+")(\\s+|$)","g");
|
||||
el.className = el.className.replace(c[arg]," ");
|
||||
return self;
|
||||
};
|
||||
/**
|
||||
* Checks classname for the certain class
|
||||
*
|
||||
* @param {String} c class name to check for
|
||||
* @return {Boolean} class name existence
|
||||
* @scope public
|
||||
*/
|
||||
self.hasClass = function(c) {
|
||||
re=new RegExp("(^|\\s+)"+c+"(\\s+|$)");
|
||||
return el.className.match(re," "+c+" ");
|
||||
};
|
||||
/**
|
||||
* Returns the actual CSS class for the element
|
||||
*
|
||||
* @return {String} css class
|
||||
* @scope public
|
||||
*/
|
||||
self.getClass = function() {
|
||||
return el.className;
|
||||
}
|
||||
/**
|
||||
* Retrieves class value from class name by pattern
|
||||
* class-var = "name:value"
|
||||
* name = [a-z][-a-z0-9]
|
||||
* value = value | val1:val2:...:valN
|
||||
*
|
||||
* @param {String} c class name to check for
|
||||
* @return {String, Array} value(s)
|
||||
* @scope public
|
||||
*/
|
||||
self.getClassValue = function(c) {
|
||||
var vals = el.className.match(new RegExp("(^|\\s)"+c+":([^\\s]+)"));
|
||||
|
||||
return vals?((vals[2].indexOf(":")+1)?vals[2].split(":")
|
||||
:vals[2])
|
||||
:null;
|
||||
};
|
||||
/**
|
||||
* Returns actual style for the element, computed from CSS and inline styles
|
||||
*
|
||||
* @param {String} prop optional style property to fetch
|
||||
* @return {Object} computed style or property value
|
||||
* @scope public
|
||||
*/
|
||||
self.getComputedStyle = function(prop) {
|
||||
var y;
|
||||
if (el.currentStyle)
|
||||
y = prop?el.currentStyle[prop]:el.currentStyle;
|
||||
else if (window.getComputedStyle) {
|
||||
y = document.defaultView.getComputedStyle(el,null);
|
||||
if (prop) y=y[prop];
|
||||
} else {
|
||||
y = null;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
return this;
|
||||
};
|
|
@ -0,0 +1,524 @@
|
|||
/**
|
||||
* $Id: eventmanager.js 397 2008-04-22 20:17:57Z wingedfox $
|
||||
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/eventmanager.js $
|
||||
*
|
||||
* EventManager (EM shorthand) is the class, written to manage event attach/detach/register and so on
|
||||
*
|
||||
* @modified $Date: 2008-04-23 00:17:57 +0400 (Срд, 23 Апр 2008) $
|
||||
* @version $Rev: 397 $
|
||||
* @license LGPL 2.1 or later
|
||||
* @author Ilya Lebedev <ilya@lebedev.net>
|
||||
* @depends helpers.js
|
||||
*
|
||||
* @class
|
||||
* @constructor EventManager
|
||||
*/
|
||||
var EM = new function () {
|
||||
var self = this;
|
||||
/**
|
||||
* Events pool
|
||||
* Element format:
|
||||
* { 'node' : {HTMLElement},
|
||||
* ['rootEHCaller' : {Function}]
|
||||
* 'handler' : {
|
||||
* <event_name> : [Function[, Function[, ...]]]
|
||||
* [,<event_name> : [Function[, Function[, ...]]]]
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @type Array
|
||||
* @scope private
|
||||
*/
|
||||
var pool = [];
|
||||
/**
|
||||
* Unique ID counter, used to attach IDs to the objects
|
||||
*
|
||||
* @type Number
|
||||
* @scope private
|
||||
*/
|
||||
var UID = 0;
|
||||
/**
|
||||
* List of used keys, applied to different kinds of objects
|
||||
*
|
||||
* @type Object
|
||||
* @scope private
|
||||
*/
|
||||
var keys = {
|
||||
'UEID' : '__eventManagerUniqueElementId'
|
||||
// ,'UHID' : '__eventManagerUniqueHandlerId'
|
||||
};
|
||||
/**************************************************************************
|
||||
* PROTECTED METHODS
|
||||
***************************************************************************/
|
||||
/**
|
||||
* Method is being binded to any new event handler, then, when called,
|
||||
* does some unification between browser platforms and calls all binded
|
||||
* event handlers
|
||||
*
|
||||
* @param {Event} e event object
|
||||
* @scope protected
|
||||
*/
|
||||
var rootEventHandler = function (e) {
|
||||
unifyEvent(e);
|
||||
var id = null
|
||||
,hid = null
|
||||
,el = e.target
|
||||
,fe = true
|
||||
,res = true;
|
||||
|
||||
if (!e.currentTarget || !(id = e.currentTarget[keys.UEID]) || !(hid = pool[id].handler[e.type])) return;
|
||||
|
||||
try {
|
||||
for (var i=0, hL=hid.length; i<hL; i++) if (isFunction(hid[i])) res=res&&!(false===hid[i].call(e.currentTarget, e));
|
||||
} catch (err) { setTimeout(function(){throw new Error("Event handler for ["+e.type+"] has failed with exception: \""+err.message+"\"");},10) }
|
||||
|
||||
return res;
|
||||
};
|
||||
/**
|
||||
* Performs events cleanup on page unload
|
||||
* It aims to remove leaking closures
|
||||
*
|
||||
* @param {Event} e window.unload event
|
||||
* @scope protected
|
||||
*/
|
||||
var unloadEventHandler = function (e) {
|
||||
for (var i=pool.length-1,pid=null,el=null; i>=0; i--) {
|
||||
if (pool[i] && (el=(pid = pool[i]).node)) {
|
||||
for (var z in pid.handler) {
|
||||
if (!pid.handler.hasOwnProperty(z)) continue;
|
||||
try {
|
||||
if (el.removeEventListener) {
|
||||
el.removeEventListener(z, pid.rootEHCaller?pid.rootEHCaller:rootEventHandler, false);
|
||||
} else if (el.detachEvent) {
|
||||
el.detachEvent('on'+z, pid.rootEHCaller?pid.rootEHCaller:rootEventHandler);
|
||||
}
|
||||
} catch (e) {}
|
||||
pid.handler[z].length = 0;
|
||||
}
|
||||
}
|
||||
el = pid.node = null;
|
||||
}
|
||||
if (window.removeEventListener) {
|
||||
window.removeEventListener(z, arguments.callee, false);
|
||||
} else {
|
||||
window.detachEvent('on'+z, arguments.callee);
|
||||
}
|
||||
};
|
||||
/**************************************************************************
|
||||
* PRIVATE METHODS
|
||||
***************************************************************************/
|
||||
/**
|
||||
* Makes an event clone, it does not dereference objects in the event properties
|
||||
*
|
||||
* @param {Event} e event handler
|
||||
* @return {Object} cloned event
|
||||
* @scope private
|
||||
*/
|
||||
var unifyEvent = function (e) {
|
||||
var i=self.EU.length
|
||||
,cur,cur1,k,init
|
||||
while (i--) {
|
||||
cur = self.EU[i];
|
||||
if (cur[0].test(e.type)) {
|
||||
k=cur[1].length;
|
||||
init = null;
|
||||
while (k--) {
|
||||
cur1 = cur[1][k];
|
||||
if ('init' == cur1[0]) init = cur1[1]
|
||||
else if (!e[cur1[0]]) e[cur1[0]] = cur1[1];
|
||||
}
|
||||
if (init) init.call(e);
|
||||
}
|
||||
}
|
||||
if (!e.target && e.type != 'unload') e.target = e.srcElement;
|
||||
return e;
|
||||
};
|
||||
/**
|
||||
* Returns UEID property for the specified element, creates it, if asked
|
||||
*
|
||||
* @param {Object} el element to find UEID on
|
||||
* @param {Boolean} f optional flag to force UEID creation, if not exists
|
||||
* @retutn {Number} UEID, if > 0
|
||||
* @scope private
|
||||
*/
|
||||
var getUEID = function (el, f) {
|
||||
return el[keys.UEID] || (f && (el[keys.UEID] = ++UID));
|
||||
};
|
||||
/**************************************************************************
|
||||
* PUBLIC METHODS
|
||||
***************************************************************************/
|
||||
/**
|
||||
* Adds the event listener to the queue
|
||||
*
|
||||
* @param {Object} el element to attach event handler to
|
||||
* @param {String} et event name to attach event handler to (without 'on' prefix)
|
||||
* @param {Function} h event handler
|
||||
* @return {Boolean} success state
|
||||
* @scope public
|
||||
*/
|
||||
self.addEventListener = function (el, et, h) {
|
||||
if (!el || !isFunction(h)) return false;
|
||||
// if (!el.addEventListener && !el.attachEvent) return false;
|
||||
/*
|
||||
* unique identifier is used to keep an eye on the element
|
||||
*/
|
||||
var id = getUEID(el, true)
|
||||
,pid = null
|
||||
,hid = null;
|
||||
|
||||
/*
|
||||
* prepare pool object, if needed
|
||||
*/
|
||||
if (!pool[id]) {
|
||||
pool[id] = {
|
||||
'node' : el
|
||||
,'handler' : {}
|
||||
}
|
||||
};
|
||||
pid = pool[id];
|
||||
/*
|
||||
* prepare handlers storage in the pool object, if needed
|
||||
*/
|
||||
if (!pid.handler.hasOwnProperty(et)) {
|
||||
pid.handler[et] = [];
|
||||
/*
|
||||
* if we a here, this means that we have not connected to a node yet
|
||||
* note, we've already made a check for the required methods existense
|
||||
*/
|
||||
if (el.addEventListener) {
|
||||
el.addEventListener(et, rootEventHandler, false);
|
||||
} else if (el.attachEvent) {
|
||||
/*
|
||||
* this workaround is used to avoid IE's lack of currentTarget property
|
||||
*/
|
||||
pid.rootEHCaller = function(e) {
|
||||
e.currentTarget = pid.node;//pool[id].node;
|
||||
var res = rootEventHandler(e);
|
||||
e.currentTarget = null;
|
||||
return res;
|
||||
};
|
||||
el.attachEvent('on'+et, pid.rootEHCaller);
|
||||
}
|
||||
};
|
||||
hid = pid.handler[et];
|
||||
/*
|
||||
* finally, attach handler, if it was not attached before
|
||||
*/
|
||||
if (hid.indexOf(h)==-1) {
|
||||
hid[hid.length] = h;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* Removes the event listener from the queue
|
||||
*
|
||||
* @param {Object} el element to attach event handler to
|
||||
* @param {String} et event name to attach event handler to (without 'on' prefix)
|
||||
* @param {Function} h event handler
|
||||
* @return {Boolean} success state
|
||||
* @scope public
|
||||
*/
|
||||
self.removeEventListener = function (el,et,h) {
|
||||
if (!el || !isFunction(h)) return false;
|
||||
var id = getUEID(el)
|
||||
,pid = pool[id]
|
||||
,eid = null;
|
||||
if (pid && (eid = pid.handler[et])) {
|
||||
/*
|
||||
* we've found an event handler
|
||||
*/
|
||||
eid.splice(eid.indexOf(h),1);
|
||||
if (0 == eid.length) {
|
||||
delete pid.handler[et];
|
||||
/*
|
||||
* remove the actual listener
|
||||
*/
|
||||
if (el.removeEventListener) {
|
||||
el.removeEventListener(et, pid.rootEHCaller?pid.rootEHCaller:rootEventHandler, false);
|
||||
} else if (el.detachEvent) {
|
||||
el.detachEvent('on'+et, pid.rootEHCaller?pid.rootEHCaller:rootEventHandler);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* Dispatch custom events on the specified element
|
||||
*
|
||||
* @param {Object} e event object itself
|
||||
* @return {Boolean} cancelled status
|
||||
* @scope public
|
||||
*/
|
||||
self.dispatchEvent = function (e) {
|
||||
var res = rootEventHandler(e);
|
||||
return res;
|
||||
};
|
||||
/**
|
||||
* Registers new event handler for any object
|
||||
* It's a good idea to register events on the object instances, really
|
||||
*
|
||||
* @param {Object} o object to register new event on
|
||||
* @param {String} n bindable event name
|
||||
* @param {Boolean} b optional bubbling allowed flag
|
||||
* @param {Function} d optional default action function
|
||||
* @return {EMEvent} object, allowing to invoke events
|
||||
* @scope public
|
||||
* @see EM.EventTarget
|
||||
*/
|
||||
self.registerEvent = function (o, n, b, d) {
|
||||
var id = getUEID(o,true);
|
||||
if (!pool[id]) {
|
||||
pool[id] = {'node' : o,
|
||||
'handler' : []};
|
||||
} else {
|
||||
pool[id].node = o;
|
||||
}
|
||||
return new EM.EventTarget(o, n, b, d);
|
||||
};
|
||||
/**
|
||||
* Performs object initialization
|
||||
*
|
||||
*/
|
||||
var __construct = function() {
|
||||
/*
|
||||
* for IE, to dereference event handlers and remove memory leaks
|
||||
*/
|
||||
if (window.attachEvent && !window.addEventListener) {
|
||||
window.attachEvent('onunload',unloadEventHandler);
|
||||
}
|
||||
};
|
||||
__construct();
|
||||
};
|
||||
/******************************************************************************
|
||||
* STATIC METHODS
|
||||
******************************************************************************/
|
||||
EM.preventDefaultAction = function(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
EM.stopPropagationAction = function(e) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* SUPPLEMENTARY CLASSES
|
||||
******************************************************************************/
|
||||
/**
|
||||
* EventTarget base class
|
||||
* Used to create self-containing event object
|
||||
*
|
||||
* @class EM.EventTarget
|
||||
* @constructor
|
||||
* @param {String} name event name
|
||||
* @param {Null, Object} obj event execution context (this), window if null passed
|
||||
* @param {Boolean} bubble flag allowing event to bubble across element.parentNode
|
||||
* @param {Function} def default action for the event
|
||||
*/
|
||||
EM.EventTarget = function (obj, name, bubble, def) {
|
||||
var self = this;
|
||||
|
||||
/**
|
||||
* Indicates possible bubbling, by default bubbling is not allowed
|
||||
*
|
||||
* @type Boolean
|
||||
* @default false
|
||||
* @scope private
|
||||
*/
|
||||
var canBubble = !!bubble;
|
||||
/**
|
||||
* Stores function, performing default action for the event
|
||||
*
|
||||
* @type Function
|
||||
* @scope private
|
||||
*/
|
||||
var defaultAction = isFunction(def)?def:null;
|
||||
/**************************************************************************
|
||||
* PRIVATE METHODS
|
||||
***************************************************************************/
|
||||
/**************************************************************************
|
||||
* PROTECTED METHODS
|
||||
***************************************************************************/
|
||||
/**
|
||||
* Used to trigger created event on the supplied object or on the 'obj' constructor param
|
||||
*
|
||||
*
|
||||
* @param {Object} el optional element to trigger event on (.target property in the event object)
|
||||
* @param {Object} event data
|
||||
*/
|
||||
self.trigger = function (el, data) {
|
||||
if (!(arguments.length-1) && el!=obj) {
|
||||
data = el;
|
||||
el = null;
|
||||
}
|
||||
if (!el) el = obj;
|
||||
var e = {}
|
||||
,res = true
|
||||
,undef = true
|
||||
,tmp = null
|
||||
for (var i in data) {
|
||||
if (data.hasOwnProperty(i)) e[i] = data[i];
|
||||
}
|
||||
|
||||
/*
|
||||
* set defaults
|
||||
*/
|
||||
canBubble = !!bubble;
|
||||
defaultAction = def;
|
||||
|
||||
/*
|
||||
* start the go
|
||||
*/
|
||||
do {
|
||||
e.preventDefault = preventDefault;
|
||||
e.stopPropagation = stopPropagation;
|
||||
e.target = el;
|
||||
e.currentTarget = el;
|
||||
e.type = name;
|
||||
tmp = EM.dispatchEvent(e);
|
||||
undef &= (isUndefined(tmp))
|
||||
res &= !(false===tmp);
|
||||
} while ((el = el.parentNode) && canBubble);
|
||||
/*
|
||||
* try to execute the default action
|
||||
*/
|
||||
if (isFunction(defaultAction) && res && !undef) {
|
||||
defaultAction(e);
|
||||
}
|
||||
return (defaultAction && res && !undef);
|
||||
};
|
||||
/**
|
||||
* Prevents default event action
|
||||
*
|
||||
* @scope protected
|
||||
*/
|
||||
var preventDefault = function () {
|
||||
defaultAction = null;
|
||||
};
|
||||
/**
|
||||
* Stops bubbling
|
||||
*
|
||||
* @scope protected
|
||||
*/
|
||||
var stopPropagation = function () {
|
||||
canBubble = false;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Namespace for event unification routines
|
||||
*
|
||||
* @type Array
|
||||
* @scope protected
|
||||
*/
|
||||
EM.EU = [
|
||||
[/./ , [
|
||||
/**
|
||||
* Prevents event from calling default event handler
|
||||
*
|
||||
* @scope protected
|
||||
*/
|
||||
['preventDefault', function() {
|
||||
this.returnValue = false;
|
||||
}
|
||||
]
|
||||
/**
|
||||
* Prevents event from futher bubbling
|
||||
*
|
||||
* @scope protected
|
||||
*/
|
||||
,['stopPropagation', function() {
|
||||
this.cancelBubble = true;
|
||||
}
|
||||
]
|
||||
]]
|
||||
,[/^mouse(over|out|down|up)/ , [
|
||||
/**
|
||||
* Used to detect left or right button pressed.
|
||||
* Due to some browser inconsistense, middle button is ignored
|
||||
*
|
||||
* @return {Number} 1 - left button, 2 - right button
|
||||
* @scope protected
|
||||
*/
|
||||
['getButton', function () {
|
||||
return this.button==2?2:1
|
||||
}
|
||||
]
|
||||
,['EM_MB_LEFT', '1']
|
||||
,['EM_MB_RIGHT', '2']
|
||||
]]
|
||||
,[/^key(down|up|press)/ , [
|
||||
/**
|
||||
* Used to return browser-independend keycode
|
||||
*
|
||||
* @return {Number} fixed key code
|
||||
* @scope protected
|
||||
*/
|
||||
['getKeyCode', function () {
|
||||
switch (this.keyCode) {
|
||||
case 189: return 109;
|
||||
case 187: return 61;
|
||||
case 186: return 59;
|
||||
default: return this.keyCode;
|
||||
}
|
||||
}
|
||||
]
|
||||
/**
|
||||
* Calculates 'repeat' property for the key events
|
||||
*
|
||||
* @return {Number} 0 means no repeating keystroke detected
|
||||
* @scope protected
|
||||
*/
|
||||
,['getRepeat', function () {
|
||||
return arguments.callee.repeat
|
||||
}
|
||||
]
|
||||
,['init', function () {
|
||||
var ac = this.getRepeat
|
||||
if ('keyup' == this.type) {
|
||||
ac.repeat = 0;
|
||||
ac.keyCode = 0;
|
||||
} else if ('keydown' == this.type) {
|
||||
ac.repeat = ac.keyCode==this.keyCode;
|
||||
ac.keyCode=this.keyCode;
|
||||
}
|
||||
}
|
||||
]
|
||||
]]
|
||||
|
||||
];
|
||||
|
||||
/*
|
||||
* register core event handler, domload
|
||||
* it's called right on the document initialization, before images complete load
|
||||
*/
|
||||
(function (){
|
||||
|
||||
var evt = EM.registerEvent(window,'domload')
|
||||
,executed = false
|
||||
,clearEvents = function() {
|
||||
//For IE
|
||||
EM.removeEventListener(document, 'propertychange', handlers.ie);
|
||||
//For Mozilla
|
||||
EM.removeEventListener(document, 'DOMContentLoaded', handlers.mz);
|
||||
//For someone else
|
||||
EM.removeEventListener(window, 'load', handlers.mz);
|
||||
}
|
||||
,handlers = { 'ie' : function(e) {
|
||||
if (window.event.propertyName == 'activeElement' && !executed) {
|
||||
evt.trigger(window);
|
||||
clearEvents();
|
||||
executed = true;
|
||||
}
|
||||
}
|
||||
,'mz' : function (e) {if(!executed)evt.trigger(window); executed=true;}
|
||||
};
|
||||
|
||||
//For IE
|
||||
EM.addEventListener(document, 'propertychange', handlers.ie);
|
||||
//For Mozilla
|
||||
EM.addEventListener(document,'DOMContentLoaded', handlers.mz);
|
||||
//For Safari and Opera
|
||||
if(/WebKit|Khtml/i.test(navigator.userAgent)||(window.opera&&parseInt(window.opera.version())<9))(function(){/loaded|complete/.test(document.readyState)?(evt.trigger(window),executed=true):setTimeout(arguments.callee,100)})();
|
||||
//For someone else
|
||||
EM.addEventListener(window, 'load', handlers.mz);
|
||||
})();
|
|
@ -0,0 +1,325 @@
|
|||
// Array Extensions v1.0.7
|
||||
// documentation: http://www.dithered.com/javascript/array/index.html
|
||||
// license: http://creativecommons.org/licenses/by/1.0/
|
||||
// code by Chris Nott (chris[at]dithered[dot]com)
|
||||
// code by Ilya Lebedev (ilya[at]lebedev[dot]net)
|
||||
|
||||
|
||||
// Array.concat() - Join two arrays
|
||||
if (isUndefined(Array.prototype.concat)) {
|
||||
Array.prototype.concat = function (secondArray) {
|
||||
var firstArray = this.copy();
|
||||
for (var i = 0, saL = secondArray.length; i < saL; i++) {
|
||||
firstArray[firstArray.length] = secondArray[i];
|
||||
}
|
||||
return firstArray;
|
||||
};
|
||||
}
|
||||
|
||||
// Array.copy() - Copy an array
|
||||
if (isUndefined(Array.prototype.copy)) {
|
||||
Array.prototype.copy = function() {
|
||||
var copy = new Array();
|
||||
for (var i = 0, tL = this.length; i < tL; i++) {
|
||||
copy[i] = this[i];
|
||||
}
|
||||
return copy;
|
||||
};
|
||||
}
|
||||
|
||||
// Array.pop() - Remove the last element of an array and return it
|
||||
if (isUndefined(Array.prototype.pop)) {
|
||||
Array.prototype.pop = function() {
|
||||
var lastItem = undefined;
|
||||
if ( this.length > 0 ) {
|
||||
lastItem = this[this.length - 1];
|
||||
this.length--;
|
||||
}
|
||||
return lastItem;
|
||||
};
|
||||
}
|
||||
|
||||
// Array.push() - Add an element to the end of an array
|
||||
if (isUndefined(Array.prototype.push)) {
|
||||
Array.prototype.push = function() {
|
||||
var currentLength = this.length;
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
this[currentLength + i] = arguments[i];
|
||||
}
|
||||
return this.length;
|
||||
};
|
||||
}
|
||||
|
||||
// Array.shift() - Remove the first element of an array and return it
|
||||
if (isUndefined(Array.prototype.shift)) {
|
||||
Array.prototype.shift = function() {
|
||||
var firstItem = this[0];
|
||||
for (var i = 0, tL = this.length - 1; i < tL; i++) {
|
||||
this[i] = this[i + 1];
|
||||
}
|
||||
this.length--;
|
||||
return firstItem;
|
||||
};
|
||||
}
|
||||
|
||||
// Array.slice() - Copy several elements of an array and return them
|
||||
if (isUndefined(Array.prototype.slice)) {
|
||||
Array.prototype.slice = function(start, end) {
|
||||
var temp;
|
||||
|
||||
if (end == null || end == '') end = this.length;
|
||||
|
||||
// negative arguments measure from the end of the array
|
||||
else if (end < 0) end = this.length + end;
|
||||
if (start < 0) start = this.length + start;
|
||||
|
||||
// swap limits if they are backwards
|
||||
if (end < start) {
|
||||
temp = end;
|
||||
end = start;
|
||||
start = temp;
|
||||
}
|
||||
|
||||
// copy elements from array to a new array and return the new array
|
||||
var newArray = new Array();
|
||||
for (var i = 0; i < end - start; i++) {
|
||||
newArray[i] = this[start + i];
|
||||
}
|
||||
return newArray;
|
||||
};
|
||||
}
|
||||
|
||||
// Array.splice() - Splice out and / or replace several elements of an array and return any deleted elements
|
||||
if (isUndefined(Array.prototype.splice)) {
|
||||
Array.prototype.splice = function(start, deleteCount) {
|
||||
if (deleteCount == null || deleteCount == '') deleteCount = this.length - start;
|
||||
|
||||
// create a temporary copy of the array
|
||||
var tempArray = this.copy();
|
||||
|
||||
// Copy new elements into array (over-writing old entries)
|
||||
for (var i = start, aL = start + arguments.length - 2; i < aL; i++) {
|
||||
this[i] = arguments[i - start + 2];
|
||||
}
|
||||
|
||||
// Copy old entries after the end of the splice back into array and return
|
||||
var dC = deleteCount - arguments.length + 2;
|
||||
for (var i = start + arguments.length - 2, tL = this.length - deleteCount + arguments.length - 2; i < tL; i++) {
|
||||
this[i] = tempArray[i + dC];
|
||||
}
|
||||
this.length = this.length - dC;
|
||||
return tempArray.slice(start, start + deleteCount);
|
||||
};
|
||||
}
|
||||
|
||||
// Array.unshift - Add an element to the beginning of an array
|
||||
if (isUndefined(Array.prototype.unshift)) {
|
||||
Array.prototype.unshift = function(the_item) {
|
||||
for (var loop = this.length-1 ; loop >= 0; loop--) {
|
||||
this[loop+1] = this[loop];
|
||||
}
|
||||
this[0] = the_item;
|
||||
return this.length;
|
||||
};
|
||||
}
|
||||
|
||||
// Array.indexOf - return index of found element or -1 (similar to String.indexOf)
|
||||
// Don't do the check on 'undefined' because Mozilla does calculate index weirdly
|
||||
Array.prototype.indexOf = function(needle,begin) {
|
||||
for (var i=(null==begin||isNaN(begin)||begin<0)?0:Math.round(begin),len = this.length, idx = -1; idx==-1 & i<len; i++) {
|
||||
idx = (this[i]==needle)?i:idx;
|
||||
}
|
||||
return idx;
|
||||
};
|
||||
// Array.lastIndexOf - return index of found element or -1 (similar to String.lastIndexOf)
|
||||
// Don't do the check on 'undefined' because Mozilla does calculate index weirdly
|
||||
Array.prototype.lastIndexOf = function(needle,end) {
|
||||
for (var i=(null==end||isNaN(end)||end>this.length)?this.length-1:Math.round(end), idx = -1; idx==-1 & i>-1; i--) {
|
||||
idx = (this[i]==needle)?i:idx;
|
||||
}
|
||||
return idx;
|
||||
};
|
||||
// Array.map - maps a function on the array elements
|
||||
if (isUndefined(Array.prototype.map)) {
|
||||
Array.prototype.map = function(func) {
|
||||
if ('function' != typeof func) return this;
|
||||
var tmp = [];
|
||||
for (var loop = this.length-1 ; loop >= 0; loop--) {
|
||||
tmp[loop] = func(this[loop]);
|
||||
}
|
||||
return tmp;
|
||||
};
|
||||
}
|
||||
|
||||
if (isUndefined(Array.prototype.unique)) {
|
||||
/**
|
||||
* Method removes dumplicate entries
|
||||
*
|
||||
* @return {Array}
|
||||
* @scope public
|
||||
*/
|
||||
Array.prototype.unique = function() /* :Array */{
|
||||
var tmp = [];
|
||||
for(var i=0, tL=this.length; i<tL; i++ ) {
|
||||
if( tmp.indexOf(this[i]) < 0 ) tmp[tmp.length] = this[i];
|
||||
}
|
||||
return tmp;
|
||||
};
|
||||
}
|
||||
|
||||
if (isUndefined(Array.prototype.flatten)) {
|
||||
/**
|
||||
* Method flattens 2-dimensional array, when no cols supplied only the cols number from 0th row will be counted
|
||||
*
|
||||
* @param {Number, Array} cols columns to insert to resulting array
|
||||
* @return {Array}
|
||||
* @scope public
|
||||
*/
|
||||
Array.prototype.flatten = function(cols /* :Array */, cd) /* :Array */{
|
||||
if (this.length<1) return [];
|
||||
if (isNumeric(cols)) cols = [cols];
|
||||
var idx = false;
|
||||
if (isArray(cols)) {
|
||||
idx = {};
|
||||
for (var i=0,cL=cols.length;i<cL;i++) idx[cols[i]]=true;
|
||||
}
|
||||
var tmp = [];
|
||||
for (var i=0, tL=this.length; i<tL; i++ ) {
|
||||
if (isUndefined(this[i])) continue;
|
||||
if (!isArray(this[i])) {
|
||||
if (false===idx) tmp[tmp.length] = this[i];
|
||||
} else {
|
||||
for (var k=0, cL=this[i].length; k<cL; k++) {
|
||||
if (false===idx || idx.hasOwnProperty(k)) tmp[tmp.length] = this[i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
};
|
||||
}
|
||||
if (isUndefined(Array.prototype.filter)) {
|
||||
/**
|
||||
* Method returns array with non-empty (not evaluating to false) entries
|
||||
*
|
||||
* @param {Function} cbk optional callback function to perform a filter
|
||||
* @return {Array}
|
||||
* @scope public
|
||||
*/
|
||||
Array.prototype.filter = function(cbk /* :Function */) /* :Array */ {
|
||||
if (!isFunction(cbk)) cbk = null;
|
||||
for (var i=0, tL = this.length, tmp = [], ti=null; i<tL;i++) {
|
||||
ti = cbk?cbk(this[i]):this[i];
|
||||
if (!isEmpty(ti)) tmp[tmp.length] = ti;
|
||||
}
|
||||
return tmp;
|
||||
};
|
||||
}
|
||||
if (isUndefined(Array.prototype.binSearch)) {
|
||||
/**
|
||||
* Provides binary search for the sorted array, causes unexpected results on unsorted one
|
||||
*
|
||||
* @param {Variant} el element to search for
|
||||
* @return {Number} array index
|
||||
* @scope public
|
||||
*/
|
||||
Array.prototype.binSearch = function (el,key) {
|
||||
var l = 0
|
||||
,r = this.length
|
||||
,len = Math.max(r-1,0)
|
||||
,c = Math.ceil(r/2)
|
||||
,cnt = 0
|
||||
if (null != key)
|
||||
while ((!this[c] || el!=this[c][key]) && r>=l) {
|
||||
if (this[c] && el>this[c][key])
|
||||
l=c+1
|
||||
else
|
||||
r=c-1
|
||||
c=Math.max(0,Math.ceil((r+l)/2))
|
||||
}
|
||||
else
|
||||
while (el!=this[c] && r>=l) {
|
||||
if (el>this[c])
|
||||
l=c+1
|
||||
else
|
||||
r=c-1
|
||||
c=Math.max(0,Math.ceil((r+l)/2));
|
||||
}
|
||||
return c
|
||||
}
|
||||
}
|
||||
/**
|
||||
* heap sort ( N log N )
|
||||
*
|
||||
* @scope public
|
||||
*/
|
||||
Array.prototype.heapSort = function () {
|
||||
|
||||
// prepare the array with special sorting method
|
||||
if (!this.sift) {
|
||||
/**
|
||||
* Innersorting method for the heap sort
|
||||
*
|
||||
* @param {Number} low
|
||||
* @param {Number} up
|
||||
*/
|
||||
this.sift = function (low, up) {
|
||||
var c, tmp = this[low];
|
||||
|
||||
while(true){
|
||||
c = (low << 1) + 1;
|
||||
if( c > up ) break;
|
||||
if( c < up && this[c+1][0] > this[c][0] ) c++;
|
||||
if( tmp[0] >= this[c][0] ) break;
|
||||
this[low] = this[c]; // 1/2 (mini) swap ))
|
||||
low = c;
|
||||
}
|
||||
this[low] = tmp;
|
||||
}
|
||||
}
|
||||
var tmp,
|
||||
maximal = this.length - 1,
|
||||
i = maximal << 1;
|
||||
|
||||
while( i >= 0 ){ this.sift(i--, maximal) };
|
||||
i = maximal;
|
||||
while( i > 0 ){
|
||||
// full swap
|
||||
tmp = this[0];
|
||||
this[0] = this[i];
|
||||
this[i] = tmp;
|
||||
this.sift(0,--i);
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// STATIC METHODS
|
||||
//-----------------------------------------------------------------------------
|
||||
if (isUndefined(Array.range)) {
|
||||
/**
|
||||
* Method creates the array with values in the specified range
|
||||
* 1 argument: create array from min(0, end) to max(0, end) with increment 1
|
||||
* 2 arguments: create array from min(start, end) to max(start, end) with increment 1
|
||||
* 3 arguments: create array from min(start, end) to max(start, end) with increment inc
|
||||
*
|
||||
* @param {Number} end end position
|
||||
* @param {Number} start start position
|
||||
* @param {Number} inc increment
|
||||
* @return {Array}
|
||||
* @scope public
|
||||
*/
|
||||
Array.range = function(end /* :Number */, start /* :Number */, inc /* :Number */) /* :Array */{
|
||||
if (!isNumber(end)) return null;
|
||||
if (!isNumber(inc)) inc = 1;
|
||||
if (!isNumber(start)) start = 0;
|
||||
var tmp = []
|
||||
,mn = Math.min(start, end)
|
||||
,mx = Math.max(start, end)
|
||||
,i = Math.abs(inc)
|
||||
,cnt = -1;
|
||||
do {
|
||||
cnt++;
|
||||
tmp[cnt] = mn;
|
||||
mn += i;
|
||||
} while (mn<=mx);
|
||||
return inc>0?tmp:tmp.reverse();
|
||||
};
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* Checks if property is derived from prototype, applies method if it is not exists
|
||||
*
|
||||
* @param string property name
|
||||
* @return bool true if prototyped
|
||||
* @access public
|
||||
*/
|
||||
if ('undefined' == typeof Object.hasOwnProperty) {
|
||||
Object.prototype.hasOwnProperty = function (prop) {
|
||||
return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**************************************************
|
||||
*
|
||||
* Extensions for the RegExp object
|
||||
*
|
||||
* @author Ilya Lebedev <ilya@lebedev.net>
|
||||
* @modified $Date: 2007-10-26 19:25:39 +0400 (Птн, 26 Окт 2007) $
|
||||
* @version $Rev: 339 $
|
||||
* @license LGPL 2.1 or later
|
||||
**************************************************/
|
||||
/**
|
||||
* Does escape of special regexp characters
|
||||
*
|
||||
* Modified version from Simon Willison
|
||||
*
|
||||
* @see http://simon.incutio.com/archive/2006/01/20/escape
|
||||
* @param {String, Array} text to escape
|
||||
* @return {String} escaped result
|
||||
* @scope public
|
||||
*/
|
||||
RegExp.escape = function(text /* :String, Array */) /* :String */ {
|
||||
if (!arguments.callee.sRE) {
|
||||
var specials = [
|
||||
'/', '.', '*', '+', '?', '|',
|
||||
'(', ')', '[', ']', '{', '}', '$', '^', '\\'
|
||||
];
|
||||
arguments.callee.sRE = new RegExp(
|
||||
'(\\' + specials.join('|\\') + ')', 'g'
|
||||
);
|
||||
}
|
||||
return isString(text)?text.replace(arguments.callee.sRE, '\\$1')
|
||||
:(isArray(text)?text.map(RegExp.escape).join("|")
|
||||
:"");
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
/**
|
||||
* $Id: string.js 370 2007-11-25 01:39:30Z wingedfox $
|
||||
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/ext/string.js $
|
||||
*
|
||||
* @author Ildar Shaimordanov
|
||||
* @author Ilya Lebedev
|
||||
* @license LGPL
|
||||
* @version $Rev: 370 $
|
||||
*/
|
||||
|
||||
/**
|
||||
* Decodes html entities
|
||||
*
|
||||
* @return {String} string with decoded entities
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.entityDecode = function() {
|
||||
if (!arguments.callee.span) arguments.callee.span = document.createElement('span');
|
||||
var s = arguments.callee.span;
|
||||
s.innerHTML = this;
|
||||
return s.firstChild?s.firstChild.nodeValue:"";
|
||||
}
|
||||
|
||||
/**
|
||||
* Method is used to trim specified chars from the left of the string
|
||||
*
|
||||
* @param {String, Array} c char or char list to be trimmed, default is \s
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.ltrim = function(c) {
|
||||
if (isString(c)) c=c.split("");
|
||||
if (isArray(c) || isUndefined(c)) {
|
||||
c = isEmpty(c)?"\\s":RegExp.escape(c);
|
||||
c = new RegExp("^(?:"+c+")+", "g");
|
||||
return this.replace(c, "");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Method is used to trim specified list from the right of the string
|
||||
*
|
||||
* @param {String, Array} c char or char sequence to be trimmed, default is \s
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.rtrim = function(c) {
|
||||
if (isString(c)) c=c.split("");
|
||||
if (isArray(c) || isUndefined(c)) {
|
||||
c = isEmpty(c)?"\\s":RegExp.escape(c);
|
||||
c = new RegExp("(?:"+c+")+$", "g");
|
||||
return this.replace(c, "");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Method is used to trim specified chars from the left and the right of the string
|
||||
*
|
||||
* @param {String, Array} c char or char list to be trimmed, default is \s
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.trim = function(c) {
|
||||
if (isString(c)) c=c.split("");
|
||||
if (isArray(c) || isUndefined(c)) {
|
||||
c = isEmpty(c)?"\\s":RegExp.escape(c);
|
||||
c = new RegExp("^(?:"+c+")+|(?:"+c+")+$", "g");
|
||||
return this.replace(c, "");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates the string
|
||||
*
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.dup = function() {
|
||||
var val = this.valueOf();
|
||||
return [val,val].join("");
|
||||
}
|
||||
/**
|
||||
* Repeats string specified number of times
|
||||
*
|
||||
* @param {Number} n number of times to repeat the string
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.repeat = function(n /* :Number */) /* :String */ {
|
||||
if (isNaN(n=parseInt(n)) || n<0) return "";
|
||||
return Array(n+1).join(this.valueOf());
|
||||
}
|
||||
/**
|
||||
* Pads the string to the specified length
|
||||
*
|
||||
* @param {Number} n number of times to repeat c
|
||||
* positive - on the right side
|
||||
* negative - on the left side
|
||||
* @param {String} c fill char, space is default
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.padding = function(n, c) {
|
||||
var val = this.valueOf();
|
||||
n = parseInt(n);
|
||||
if (!n) return val;
|
||||
if (isUndefined(c)) c = " ";
|
||||
var pad = String(c).charAt(0).repeat(Math.abs(n) - this.length);
|
||||
return (n < 0) ? pad + val : val + pad;
|
||||
}
|
||||
/**
|
||||
* Pads the string on the right side
|
||||
*
|
||||
* @param {Number} n number of times to repeat c
|
||||
* @param {String} c fill char
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.padLeft = function(n, c) {
|
||||
return this.padding(-Math.abs(n), c);
|
||||
}
|
||||
/**
|
||||
* Pads the string on the left side
|
||||
*
|
||||
* @param {Number} n number of times to repeat c
|
||||
* @param {String} c fill char
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.padRight = function(n, c) {
|
||||
return this.padding(Math.abs(n), c);
|
||||
}
|
||||
|
||||
/**
|
||||
* sprintf(format, argument_list)
|
||||
*
|
||||
* The string format function like the one in C/C++, PHP, Perl
|
||||
* Each conversion specification is defined as below:
|
||||
*
|
||||
* %[index][alignment][padding][width][precision]type
|
||||
*
|
||||
* index An optional index specifier that changes the order of the
|
||||
* arguments in the list to be displayed.
|
||||
* alignment An optional alignment specifier that says if the result should be
|
||||
* left-justified or right-justified. The default is
|
||||
* right-justified; a "-" character here will make it left-justified.
|
||||
* padding An optional padding specifier that says what character will be
|
||||
* used for padding the results to the right string size. This may
|
||||
* be a space character or a "0" (zero character). The default is to
|
||||
* pad with spaces. An alternate padding character can be specified
|
||||
* by prefixing it with a single quote ('). See the examples below.
|
||||
* width An optional number, a width specifier that says how many
|
||||
* characters (minimum) this conversion should result in.
|
||||
* precision An optional precision specifier that says how many decimal digits
|
||||
* should be displayed for floating-point numbers. This option has
|
||||
* no effect for other types than float.
|
||||
* type A type specifier that says what type the argument data should be
|
||||
* treated as. Possible types:
|
||||
*
|
||||
* % - a literal percent character. No argument is required.
|
||||
* b - the argument is treated as an integer, and presented as a binary number.
|
||||
* c - the argument is treated as an integer, and presented as the character
|
||||
* with that ASCII value.
|
||||
* d - the argument is treated as an integer, and presented as a decimal number.
|
||||
* u - the same as "d".
|
||||
* f - the argument is treated as a float, and presented as a floating-point.
|
||||
* o - the argument is treated as an integer, and presented as an octal number.
|
||||
* s - the argument is treated as and presented as a string.
|
||||
* x - the argument is treated as an integer and presented as a hexadecimal
|
||||
* number (with lowercase letters).
|
||||
* X - the argument is treated as an integer and presented as a hexadecimal
|
||||
* number (with uppercase letters).
|
||||
*
|
||||
* @return {String}
|
||||
* @scope public
|
||||
*/
|
||||
String.prototype.sprintf = function() {
|
||||
var args = isArray(arguments[0])?arguments[0]:arguments
|
||||
,index = 0
|
||||
,frmt = this.replace(/%%/g, "\0\0")
|
||||
,re = /%((?:\d+\$)?)((?:[-0+# ])?)((?:\d+|\*(?:\d+\$)?)?)((?:.(?:\d+|\*(?:\d+\$)?))?)([bcdeEfosuxX])/g;
|
||||
/*
|
||||
* The re.exec() method returns the array with the following properties
|
||||
* wich are used in this function
|
||||
* x.index contains the substring position found at the origin string
|
||||
* x[0] contains the found substring
|
||||
* x[1] contains the explicit parameter number
|
||||
* x[2] contains the flags
|
||||
* x[3] contains the minwidth
|
||||
* x[4] contains the precision
|
||||
* x[5] contains the type specifier (as [bcdfosuxX])
|
||||
*/
|
||||
frmt = frmt.replace(re, function() {
|
||||
var x = arguments
|
||||
,sign = false
|
||||
,ins;
|
||||
|
||||
/*
|
||||
* calculate min width
|
||||
*/
|
||||
if (!isUndefined(x[3]) && x[3].indexOf("*")==0) {
|
||||
x[3] = parseInt(x[3].replace(/\D/g,""))
|
||||
if (isNaN(x[3])) {
|
||||
x[3] = args[index];
|
||||
/*
|
||||
* increment
|
||||
*/
|
||||
index++;
|
||||
} else {
|
||||
x[3] = args[x[3]]
|
||||
}
|
||||
}
|
||||
/*
|
||||
* calculate precision
|
||||
*/
|
||||
if ("" != x[4]) {
|
||||
if (x[4].indexOf("*")==1) {
|
||||
x[4] = parseInt(x[4].replace(/\D/g,""))
|
||||
if (isNaN(x[4])) {
|
||||
x[4] = args[index];
|
||||
/*
|
||||
* increment
|
||||
*/
|
||||
index++;
|
||||
} else {
|
||||
x[4] = args[x[4]]
|
||||
}
|
||||
} else {
|
||||
x[4] = x[4].replace(/\D/,"")
|
||||
}
|
||||
x[4] = Math.abs(x[4]);
|
||||
}
|
||||
/*
|
||||
* calculate insertion value
|
||||
*/
|
||||
x[1] = parseInt(x[1]);
|
||||
var ins;
|
||||
if (isNumeric(x[1])) {
|
||||
ins = args[x[1]];
|
||||
} else {
|
||||
ins = args[index];
|
||||
/*
|
||||
* index should be incremented only when no explicit parameter number is specified
|
||||
*/
|
||||
index++;
|
||||
}
|
||||
switch (x[5]) {
|
||||
case "b":
|
||||
if (ins<0) ins = 0x10000000000000000+parseInt(ins);
|
||||
ins = Number(ins).bin(x[4]);
|
||||
if (x[4]) ins = ins.substr(0,x[4]);
|
||||
if (x[2]=='#') ins = '0b'+ins;
|
||||
break;
|
||||
case "c":
|
||||
ins = String.fromCharCode(ins);
|
||||
break;
|
||||
case "u":
|
||||
ins = Math.abs(ins);
|
||||
case "d":
|
||||
ins = Math.round(ins);
|
||||
if (ins<0) {
|
||||
ins = "-"+Math.abs(ins).dec(x[4]);
|
||||
} else {
|
||||
ins = Number(ins).dec(x[4]);
|
||||
sign = (x[2] == ' ' || x[2] == '+');
|
||||
}
|
||||
break;
|
||||
case "e":
|
||||
case "E":
|
||||
if (ins>0) {
|
||||
sign = (x[2] == ' ' || x[2] == '+');
|
||||
}
|
||||
ins = Number(ins).toExponential(x[4]?x[4]:6);
|
||||
if (x[5]=='E') ins=ins.toUpperCase();
|
||||
break;
|
||||
case "f":
|
||||
if (ins>0) {
|
||||
sign = (x[2] == ' ' || x[2] == '+');
|
||||
}
|
||||
ins = Number(ins).toFixed(isNumeric(x[4])?x[4]:6);
|
||||
break;
|
||||
case "o":
|
||||
if (ins<0) ins = 0x10000000000000000+parseInt(ins);
|
||||
ins = Number(ins).toString(8);
|
||||
if (x[4]) ins = ins.substr(0,x[4]);
|
||||
if (x[2]=='#' && ins != 0) ins = '0'+ins;
|
||||
break;
|
||||
case "s":
|
||||
ins = String(ins);
|
||||
if (x[4]) ins = ins.substr(0,x[4]);
|
||||
break;
|
||||
case "x":
|
||||
case "X":
|
||||
if (ins<0) ins = 0x10000000000000000+parseInt(ins);
|
||||
ins = Number(ins).hex(-x[4]);
|
||||
if (x[4]) ins = ins.substr(0,x[4]);
|
||||
if (x[2]=='#') ins = '0x'+ins;
|
||||
if (x[5]=='X') ins = ins.toUpperCase();
|
||||
break;
|
||||
}
|
||||
if (sign) ins = x[2]+ins;
|
||||
if (x[3]) ins = (x[2]=='-' || x[3]<0)?ins.padRight(x[3]):ins.padLeft(x[3],x[2]=='0'?0:" ");
|
||||
return ins;
|
||||
})
|
||||
return frmt.replace(/\0\0/g, "%");
|
||||
}
|
|
@ -0,0 +1,388 @@
|
|||
/**
|
||||
* $Id: helpers.js 366 2007-11-24 02:27:32Z wingedfox $
|
||||
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/helpers.js $
|
||||
*
|
||||
* File contains differrent helper functions
|
||||
*
|
||||
* @author Ilya Lebedev <ilya@lebedev.net>
|
||||
* @license LGPL
|
||||
* @version $Rev: 366 $
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
// Variable/property checks
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* Checks if property is undefined
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isUndefined (prop /* :Object */) /* :Boolean */ {
|
||||
return (typeof prop == 'undefined');
|
||||
}
|
||||
/**
|
||||
* Checks if property is function
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isFunction (prop /* :Object */) /* :Boolean */ {
|
||||
return (typeof prop == 'function');
|
||||
}
|
||||
/**
|
||||
* Checks if property is string
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isString (prop /* :Object */) /* :Boolean */ {
|
||||
return (typeof prop == 'string');
|
||||
}
|
||||
/**
|
||||
* Checks if property is number
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isNumber (prop /* :Object */) /* :Boolean */ {
|
||||
return (typeof prop == 'number');
|
||||
}
|
||||
/**
|
||||
* Checks if property is the calculable number
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isNumeric (prop /* :Object */) /* :Boolean */ {
|
||||
return (isNumber(prop)||isString(prop))&&!isNaN(parseInt(prop))&&isFinite(parseInt(prop));
|
||||
}
|
||||
/**
|
||||
* Checks if property is array
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isArray (prop /* :Object */) /* :Boolean */ {
|
||||
return (prop instanceof Array);
|
||||
}
|
||||
/**
|
||||
* Checks if property is regexp
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isRegExp (prop /* :Object */) /* :Boolean */ {
|
||||
return (prop instanceof RegExp);
|
||||
}
|
||||
/**
|
||||
* Checks if property is a boolean value
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isBoolean (prop /* :Object */) /* :Boolean */ {
|
||||
return ('boolean' == typeof prop);
|
||||
}
|
||||
/**
|
||||
* Checks if property is a scalar value (value that could be used as the hash key)
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isScalar (prop /* :Object */) /* :Boolean */ {
|
||||
return isNumeric(prop)||isString(prop)||isBoolean(prop);
|
||||
}
|
||||
/**
|
||||
* Checks if property is empty
|
||||
*
|
||||
* @param {Object} prop value to check
|
||||
* @return {Boolean} true if matched
|
||||
* @scope public
|
||||
*/
|
||||
function isEmpty (prop /* :Object */) /* :Boolean */ {
|
||||
if (isBoolean(prop)) return false;
|
||||
if (isRegExp(prop) && new RegExp("").toString() == prop.toString()) return true;
|
||||
if (isString(prop) || isNumber(prop)) return !prop;
|
||||
if (Boolean(prop)&&false != prop) {
|
||||
for (var i in prop) if(prop.hasOwnProperty(i)) return false
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// File paths functions
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* used to glue path's
|
||||
*
|
||||
* @param {String} number of strings
|
||||
* @return {String} glued path
|
||||
* @scope public
|
||||
*/
|
||||
function gluePath () /* :String */ {
|
||||
var aL=arguments.length, i=aL-2, s = arguments[aL-1];
|
||||
for(;i>=0;i--)
|
||||
s = ((!isString(arguments[i])&&!isNumber(arguments[i]))||isEmpty(arguments[i])
|
||||
?s
|
||||
:arguments[i]+'\x00'+s);
|
||||
return s?s.replace(/\/*\x00+\/*/g,"/"):"";
|
||||
}
|
||||
|
||||
/**
|
||||
* return full path to the script
|
||||
*
|
||||
* @param {String} sname script name
|
||||
* @return {String, Null} mixed string full path or null
|
||||
* @scope public
|
||||
*/
|
||||
function findPath (sname /* :String */) /* :String */{
|
||||
var h =document.getElementsByTagName('html')[0].innerHTML
|
||||
,sr=new RegExp('<scr'+'ipt[^>]+?src\s*=\s*["\']?([^>]+?/)'+sname+'[^>]*>.?</scr'+'ipt>','i')
|
||||
,m =h.match(sr);
|
||||
if (m) {
|
||||
/*
|
||||
* we've matched the full path
|
||||
*/
|
||||
if (m[1].match(/^((https?|file)\:\/{2,}|\w:[\\])/)) return m[1];
|
||||
/*
|
||||
* we've matched absolute path from the site root
|
||||
*/
|
||||
if (m[1].indexOf("/")==0) return m[1];
|
||||
b = document.getElementsByTagName('base');
|
||||
if (b[0] && b[0].href) return b[0].href+m[1];
|
||||
/*
|
||||
* return matching part of the document location and path to js file
|
||||
*/
|
||||
return (document.location.href.match(/(.*[\/\\])/)[0]+m[1]).replace(/^\/+/,"");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* return parsed query string for the specified script name
|
||||
*
|
||||
* @param {String} sname script name
|
||||
* @return {String, Null} mixed string full path or null
|
||||
* @scope public
|
||||
*/
|
||||
function getScriptQuery (sname) {
|
||||
var h =document.getElementsByTagName('html')[0].innerHTML
|
||||
,sr=new RegExp('<scr'+'ipt[^>]+?src\s*[^>]+?/'+sname+'([^#"\']*).+?</scr'+'ipt>','i')
|
||||
,m = h.match(sr);
|
||||
if (m) return parseQuery(m[1].replace(/^[^?]*\?([^#]+)/,"$1"));
|
||||
return {};
|
||||
}
|
||||
/**
|
||||
* Function parses supplied query string and returns the hash with the values
|
||||
* Multiple values are stored in the array
|
||||
*
|
||||
* @param {String} q query string
|
||||
* @return {Object}
|
||||
* @scope public
|
||||
*/
|
||||
function parseQuery (q) {
|
||||
if ('string'!=typeof q || q.length<2) return {};
|
||||
q = q.split(/&|&/g);
|
||||
for (var z=0,qL=q.length,rs={},kv,rkv;z<qL;z++) {
|
||||
kv=q[z].split("=");
|
||||
/*
|
||||
* convert PHP and Perl-styled hashes to JS has keys
|
||||
*/
|
||||
kv[0]=kv[0].replace(/[{}\[\]]*$/,"");
|
||||
rkv = rs[kv[0]];
|
||||
/*
|
||||
* replace all + with spaces, unescape skips this part
|
||||
*/
|
||||
kv[1]=unescape(kv[1]?kv[1].replace("+"," "):"");
|
||||
if (rkv)
|
||||
if ('array'==typeof(rkv))rs[kv[0]][rs[kv[0]].length]=kv[1];
|
||||
else rs[kv[0]]=[rs[kv[0]],kv[1]];
|
||||
else rs[kv[0]]=kv[1];
|
||||
}
|
||||
return rs
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Misc helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* Method is used to convert table into the array
|
||||
*
|
||||
* @param {String, HTMLTableElement, HTMLTBodyElement, HTMLTHeadElement, HTMLTFootElement} id
|
||||
* @param {Number} ci column indexes to put in the array
|
||||
* @param {String} section optional section type
|
||||
* @param {Object} subsection optional subsection index
|
||||
* @return {NULL, Array}
|
||||
* @scope public
|
||||
*/
|
||||
function table2array (id, ci, section, subsection) {
|
||||
if (isString(id)) id = document.getElementById(id);
|
||||
if (!id || !DOM.hasTagName(id, ['table','tbody,','thead','tfoot'])) return null;
|
||||
if (!isEmpty(section) && (!isString(section) || !(id = id.getElementsByTagName(section)))) return null;
|
||||
if (!isEmpty(subsection) && (!isNumber(subsection) || subsection<0 || !(id = id[subsection]))) return null;
|
||||
|
||||
if (isUndefined(id.rows)) return null;
|
||||
var res = []
|
||||
,span = document.createElement('span')
|
||||
,ts = null
|
||||
,ce = null
|
||||
for (var i=0, rL=id.rows.length; i<rL; i++) {
|
||||
var tr = [];
|
||||
if (isArray(ci)) {
|
||||
for (var z=0, cL=ci.length; z<cL; z++) {
|
||||
ce = id.rows[i].cells[ci[z]];
|
||||
if (ce) {
|
||||
span.innerHTML = ce.innerText?ce.innerText:ce.innerHTML.replace(/<script\s+(.|\r?\n)*?<\/script>|<[^>]*>/g,"");
|
||||
span.normalize();
|
||||
tr[tr.length] = span.firstChild?span.firstChild.nodeValue.trim(" \xA0"):"";
|
||||
} else {
|
||||
tr[tr.length] = "";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var z=0, tL=id.rows[i].cells.length; z<tL; z++) {
|
||||
cd = id.rows[i].cells[z];
|
||||
span.innerHTML = ce.innerText?ce.innerText:ce.innerHTML.replace(/<script\s+(.|\r?\n)*?<\/script>|<[^>]*>/g,"");
|
||||
span.normalize();
|
||||
tr[tr.length] = span.firstChild?span.firstChild.nodeValue.trim(" \xA0"):"";
|
||||
}
|
||||
}
|
||||
if (!isEmpty(tr)) res[res.length] = tr;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates element all-at-once
|
||||
*
|
||||
* @param {String} tag name
|
||||
* @param {Object} p element properties { 'class' : 'className',
|
||||
* 'style' : { 'property' : value, ... },
|
||||
* 'event' : { 'eventType' : handler, ... },
|
||||
* 'child' : [ child1, child2, ...],
|
||||
* 'param' : { 'property' : value, ... },
|
||||
* @return {HTMLElement} created element or null
|
||||
* @scope public
|
||||
*/
|
||||
document.createElementExt = function (tag /* :String */, p /* :Object */ ) /* :HTMLElement */{
|
||||
var L, i, k, el = document.createElement(tag);
|
||||
if (!el) return null;
|
||||
for (i in p) {
|
||||
if (!p.hasOwnProperty(i)) continue;
|
||||
switch (i) {
|
||||
case "class" : el.setAttribute('className',p[i]); el.setAttribute('class',p[i]); break;
|
||||
case "style" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; el.style[k] = p[i][k]; } break;
|
||||
case "event" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; el.attachEvent(k,p[i][k]); } break;
|
||||
case "child" : L = p[i].length; for (k = 0; k<L; k++) el.appendChild(p[i][k]); break;
|
||||
case "param" : for (k in p[i]) { if (!p[i].hasOwnProperty(k)) continue; try { el[k] = p[i][k] } catch(e) {} } break;
|
||||
}
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
/**
|
||||
* simple setInterval/setTimout wrappers
|
||||
*
|
||||
* @param {Function} f function to be launched
|
||||
* @param {Number} i interval
|
||||
* @param {Array} o optional function parameters to be applied
|
||||
* @return {Number} interval id
|
||||
* @scope public
|
||||
*/
|
||||
function playInterval (f /* :Function */, i /* :Number */, o /* :Array */) /* :Number */ { return setInterval(function(){(o instanceof Array)?f.apply(this,o):f.call(this,o)},i) }
|
||||
function playTimeout (f /* :Function */, i /* :Number */, o /* :Array */) /* :Number */ { return setTimeout(function(){(o instanceof Array)?f.apply(this,o):f.call(this,o)},i) }
|
||||
|
||||
/**
|
||||
* Clone object
|
||||
*
|
||||
* @param optional object to clone
|
||||
* @return cloned object
|
||||
* @access public
|
||||
*/
|
||||
function cloneObject (obj) {
|
||||
if (isScalar(obj) || isFunction(obj) || null == obj) return obj;
|
||||
try { var newObject = new obj.constructor(); } catch(e) {return null;}
|
||||
if (isArray(newObject)) {
|
||||
for (var i=0,oL=obj.length;i<oL;i++) {
|
||||
newObject[i] = cloneObject(obj[i]);
|
||||
}
|
||||
} else {
|
||||
for (var i in obj) {
|
||||
if (!obj.hasOwnProperty(i)) continue;
|
||||
newObject[i] = cloneObject(obj[i]);
|
||||
}
|
||||
}
|
||||
return newObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple objects to one
|
||||
*
|
||||
* @param {Object} obj1 original object
|
||||
* @param {Object} obj2 update object
|
||||
* @param {Object} objN update object
|
||||
* @return {Object}
|
||||
* @access public
|
||||
*/
|
||||
function mergeObject () {
|
||||
var res = {}
|
||||
,oi
|
||||
,obj
|
||||
for (var z=0,aL=arguments.length;z<aL;z++) {
|
||||
obj = arguments[z];
|
||||
for (var i in obj) {
|
||||
if (!obj.hasOwnProperty(i)) continue;
|
||||
oi = obj[i];
|
||||
if (null == oi) {
|
||||
if (!res.hasOwnProperty(i)) res[i] = oi;
|
||||
} else if (isArray(oi)) {
|
||||
if (isArray(res[i]))
|
||||
res[i] = res[i].concat(oi).unique();
|
||||
else
|
||||
res[i] = oi.slice(0);
|
||||
} else if (isScalar(oi) || isFunction(oi)) {
|
||||
res[i] = oi;
|
||||
} else {
|
||||
if (res.hasOwnProperty(i))
|
||||
res[i] = mergeObject(res[i],oi)
|
||||
else
|
||||
res[i] = cloneObject(oi);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Loaders
|
||||
//-----------------------------------------------------------------------------
|
||||
/**
|
||||
* Method to load stylesheets
|
||||
*
|
||||
* @param {String} sn path to stylesheet
|
||||
* @return {HTMLLinkElement} reference to the corresponding link
|
||||
*/
|
||||
function loadStyleSheet (sn) {
|
||||
var head = document.getElementsByTagName('head')[0]
|
||||
,links = head.getElementsByTagName('link')
|
||||
,ll = links.length
|
||||
,cl;
|
||||
while (--ll>-1) {
|
||||
cl = links[ll];
|
||||
if (!cl.rel || cl.rel.toLowerCase() != 'stylesheet' || cl.src != sn) continue;
|
||||
return cl;
|
||||
}
|
||||
var link = document.createElementExt('link',{'param': { 'rel': 'stylesheet', 'type': 'text/css', 'href': sn}})
|
||||
head.appendChild(link);
|
||||
return link;
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/**
|
||||
* $Id: scriptqueue.js 351 2007-11-13 12:56:18Z wingedfox $
|
||||
* $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/tags/BrowserExtensions.018/scriptqueue.js $
|
||||
*
|
||||
* Dynamically load scripts and script queues (when load order is important)
|
||||
*
|
||||
**********NOTE********
|
||||
* If you need to load any scripts before ScriptQueue exists, use the following snippet
|
||||
* <code>
|
||||
* if (!(window.ScriptQueueIncludes instanceof Array)) window.ScriptQueueIncludes = []
|
||||
* window.ScriptQueueIncludes = window.ScriptQueueIncludes.concat(scriptsarray);
|
||||
* </code>
|
||||
* ScriptQueue loads all the scripts, queued before its' load in the ScriptQueueIncludes
|
||||
**********
|
||||
*
|
||||
* @author Ilya Lebedev <ilya@lebedev.net>
|
||||
* @modified $Date: 2007-11-13 15:56:18 +0300 (Втр, 13 Ноя 2007) $
|
||||
* @version $Rev: 351 $
|
||||
* @license LGPL 2.1 or later
|
||||
*
|
||||
* @class ScriptQueue
|
||||
* @param {Function} optional callback function, called on each successful script load
|
||||
* @scope public
|
||||
*/
|
||||
ScriptQueue = function (cbk) {
|
||||
var self = this
|
||||
,static = arguments.callee;
|
||||
/*
|
||||
* empty function is better than number of checks in the code...
|
||||
*/
|
||||
if ('function' != typeof cbk) cbk = function(){}
|
||||
/**
|
||||
* Queue for the current loader instance
|
||||
*
|
||||
* @type {Array}
|
||||
* @scope private
|
||||
*/
|
||||
var queue = [];
|
||||
//-------------------------------------------------------------------------
|
||||
// PUBLIC
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Loads the single script, independent from any other
|
||||
*
|
||||
* @param {String} path path to the target script
|
||||
* @return {Boolean} true when script is getting loaded, false otherwise
|
||||
* @scope public
|
||||
*/
|
||||
self.load = function (path) {
|
||||
load(path,cbk);
|
||||
}
|
||||
/**
|
||||
* Builds a queue of scripts, when they should be loaded in the proper order
|
||||
*
|
||||
* @param {String} path script name to add to the queue
|
||||
* @scope public
|
||||
*/
|
||||
self.queue = function (path) {
|
||||
var f = queue.length;
|
||||
queue[f] = path;
|
||||
if (!f) load(path,queuemonitor);
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
// PRIVATE
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Performs scripts existense check and loads it, if needed
|
||||
*
|
||||
* @param {String} path path to the script
|
||||
* @param {Function} cbk callback
|
||||
* @scope private
|
||||
*/
|
||||
var load = function (path, cbk) {
|
||||
var sid
|
||||
,scr = static.scripts;
|
||||
if (sid = scr.hash[path]) { // in queue
|
||||
scr = static.scripts[sid]
|
||||
if (scr[2]) { // loaded
|
||||
cbk(path,scr[2]);
|
||||
} else {
|
||||
scr[1].push(cbk);
|
||||
}
|
||||
} else {
|
||||
sid = scr.length;
|
||||
scr[sid] = [path,[cbk],false];
|
||||
scr.hash[path] = sid;
|
||||
ls(path);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Attaches script to the document
|
||||
*
|
||||
* @param {String} src path to script
|
||||
* @scope private
|
||||
*/
|
||||
var ls = function (src) {
|
||||
if (document.body) { // document is loaded, don't use document.write
|
||||
var s = document.createElement('script')
|
||||
,h = document.getElementsByTagName("head")[0];
|
||||
s.type= "text/javascript";
|
||||
s.charset="UTF-8";
|
||||
s.src=src;
|
||||
/*
|
||||
* some browsers does change the src, store original one here
|
||||
*/
|
||||
s.rSrc=src;
|
||||
s.onload = s.onreadystatechange = loadmonitor;
|
||||
h.appendChild(s);
|
||||
} else {
|
||||
document.write("<scr"+"ipt onload=\"\" src=\""+src+"\" charset=\"UTF-8\"></scr"+"ipt>");
|
||||
/*
|
||||
* note, real onload handler is commented out, because IE calls it too late,
|
||||
* which is not acceptable, because it breaks onload there
|
||||
* assume, that scripts are loaded successfully
|
||||
*/
|
||||
// s.onload = s.onreadystatechange = loadmonitor;
|
||||
loadmonitor.call({'rSrc':src},{'type':'load'});
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
// PROTECTED
|
||||
//-------------------------------------------------------------------------
|
||||
/**
|
||||
* Monitors queue load and runs next iteration, untill empties the queue
|
||||
*
|
||||
* @param {String} path loaded script
|
||||
* @param {Boolean} s load completed status
|
||||
* @scope protected
|
||||
*/
|
||||
var queuemonitor = function (path,s) {
|
||||
/*
|
||||
* execute the user callback
|
||||
*/
|
||||
cbk(path,s);
|
||||
queue.splice(0,1);
|
||||
/*
|
||||
* next run
|
||||
*/
|
||||
if (queue.length && s)
|
||||
load(queue[0],arguments.callee);
|
||||
else
|
||||
cbk(null,s)
|
||||
}
|
||||
/**
|
||||
* Handles onload and onreadystatechange events
|
||||
*
|
||||
* @param {Event} e handled event object
|
||||
* @scope protected
|
||||
*/
|
||||
var loadmonitor = function (e) {
|
||||
var scr = static.scripts
|
||||
,sid = scr.hash[this.rSrc]
|
||||
,e = e||window.event
|
||||
scr = scr[sid];
|
||||
if (('load' == e.type || 'complete'==this.readyState)) {
|
||||
if (!scr[2])
|
||||
scr[2] = true;
|
||||
else
|
||||
return; // prevent duplicate calls from event handler
|
||||
}
|
||||
for (var i=0,cbk=scr[1],cL=cbk.length;i<cL;i++) {
|
||||
cbk[i](scr[0],scr[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Stores information about the loaded scripts
|
||||
* Element structure:
|
||||
* [0 : string script path
|
||||
* 1 : [ array of callback functions ]
|
||||
* 2 : boolean 'loaded' flag
|
||||
* ]
|
||||
* Array fields:
|
||||
* .hash { maps script paths' to array ids }
|
||||
*
|
||||
* @type {Array}
|
||||
* @scope protected
|
||||
*/
|
||||
ScriptQueue.scripts = [false];
|
||||
ScriptQueue.scripts.hash = {};
|
||||
/**
|
||||
* Static method to load bunch of scripts at once
|
||||
* note, there's no callback support
|
||||
*
|
||||
* @param {Array} arr list of scripts to execute
|
||||
* @scope public
|
||||
*/
|
||||
ScriptQueue.queue = function(arr) {
|
||||
if (!arr.length) return;
|
||||
var q = new ScriptQueue;
|
||||
for (var i=0,aL=arr.length;i<aL;i++) {
|
||||
q.queue(arr[i]);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If any load requests does exists, serve them
|
||||
*/
|
||||
if (window.ScriptQueueIncludes instanceof Array) {
|
||||
ScriptQueue.queue(window.ScriptQueueIncludes);
|
||||
}
|
750
fotokiste/fotokiste/static/virtual_keyboard/layouts/layouts.js
Normal file
750
fotokiste/fotokiste/static/virtual_keyboard/layouts/layouts.js
Normal file
File diff suppressed because one or more lines are too long
1544
fotokiste/fotokiste/static/virtual_keyboard/virtualkeyboard.js
Normal file
1544
fotokiste/fotokiste/static/virtual_keyboard/virtualkeyboard.js
Normal file
File diff suppressed because it is too large
Load diff
92
fotokiste/fotokiste/static/virtual_keyboard/vk_loader.js
Normal file
92
fotokiste/fotokiste/static/virtual_keyboard/vk_loader.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
VirtualKeyboard = new function () {
|
||||
var self = this, to = null;
|
||||
self.show = self.hide = self.toggle = self.attachInput = function () {
|
||||
window.status = 'VirtualKeyboard is not loaded yet.';
|
||||
if (!to) setTimeout(function(){window.status = ''},1000);
|
||||
}
|
||||
self.isOpen = function () {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
(function () {
|
||||
var pq = function (q) {if ('string'!=typeof q || q.length<2) return {};q = q.split(/&|&/g);for (var z=0,qL=q.length,rs={},kv,rkv;z<qL;z++){kv=q[z].split("=");kv[0]=kv[0].replace(/[{}\[\]]*$/,"");rkv = rs[kv[0]];kv[1]=unescape(kv[1]?kv[1].replace("+"," "):"");if (rkv)if ('array'==typeof(rkv))rs[kv[0]][rs[kv[0]].length]=kv[1];else rs[kv[0]]=[rs[kv[0]],kv[1]];else rs[kv[0]]=kv[1];}return rs}
|
||||
|
||||
/*
|
||||
* track, how we've opened
|
||||
*/
|
||||
var targetWindow = window.dialogArguments||window.opener||window.top
|
||||
,addHead = null
|
||||
,targetScript = 'vk_loader.js';
|
||||
try {
|
||||
if (targetWindow != window) {
|
||||
var addHead = targetWindow.document.getElementsByTagName('head')[0];
|
||||
var targetScript = window.location.href.match(/.*\/(.+)\..+$/)[1]+'.js';
|
||||
}
|
||||
} catch (e) {
|
||||
targetWindow = window;
|
||||
}
|
||||
|
||||
q = (function (sname,td){var h=(td||document).getElementsByTagName('html')[0].innerHTML,sr=new RegExp('<scr'+'ipt[^>]+?src[^"\']+.*?'+sname+'([^#"\']*)','i'),m = h.match(sr);if (m) return pq(m[1].replace(/^[^?]*\?([^#]+)/,"$1"));return {};})(targetScript,targetWindow.document)
|
||||
var p = (function (sname){var sc=document.getElementsByTagName('script'),sr=new RegExp('^(.*/|)('+sname+')([#?]|$)');for (var i=0,scL=sc.length; i<scL; i++) {var m = String(sc[i].src).match(sr);if (m) {if (m[1].match(/^((https?|file)\:\/{2,}|\w:[\\])/)) return m[1];if (m[1].indexOf("/")==0) return m[1];b = document.getElementsByTagName('base');if (b[0] && b[0].href) return b[0].href+m[1];return (document.location.href.match(/(.*[\/\\])/)[0]+m[1]).replace(/^\/+/,"");}}return null;})
|
||||
('vk_loader.js');
|
||||
|
||||
var qs = pq(targetWindow.location.search.slice(1));
|
||||
var dpd = [ 'extensions/helpers.js'
|
||||
,'extensions/dom.js'
|
||||
,'extensions/ext/object.js'
|
||||
,'extensions/ext/string.js'
|
||||
,'extensions/ext/regexp.js'
|
||||
,'extensions/ext/array.js'
|
||||
,'extensions/eventmanager.js'
|
||||
,'extensions/documentselection.js'
|
||||
/*
|
||||
* not used by default
|
||||
*
|
||||
* ,'layouts/unconverted.js'
|
||||
*/
|
||||
];
|
||||
q.skin = qs.vk_skin || q.vk_skin || 'winxp';
|
||||
q.layout = qs.vk_layout || q.vk_layout || null;
|
||||
|
||||
var head = document.getElementsByTagName('head')[0]
|
||||
,s;
|
||||
/*
|
||||
* load styles at the proper places
|
||||
*/
|
||||
s = document.createElement('link');
|
||||
s.rel = 'stylesheet';
|
||||
s.type= 'text/css';
|
||||
s.href= p+'css/'+q.skin+'/keyboard.css';
|
||||
head.appendChild(s);
|
||||
if (addHead) {
|
||||
var lnk = targetWindow.document.createElement('link');
|
||||
lnk.rel = 'stylesheet';
|
||||
lnk.type= 'text/css';
|
||||
lnk.href= p+'css/'+q.skin+'/keyboard.css';
|
||||
addHead.appendChild(lnk);
|
||||
lnk = null;
|
||||
}
|
||||
|
||||
for (var i=0,dL=dpd.length;i<dL;i++)
|
||||
dpd[i] = p+dpd[i];
|
||||
dpd[i++] = p+'virtualkeyboard.js?layout='+q.layout;
|
||||
dpd[i] = p+'layouts/layouts.js';
|
||||
if (window.ScriptQueue) {
|
||||
ScriptQueue.queue(dpd);
|
||||
} else {
|
||||
if (!(window.ScriptQueueIncludes instanceof Array)) window.ScriptQueueIncludes = []
|
||||
window.ScriptQueueIncludes = window.ScriptQueueIncludes.concat(dpd);
|
||||
|
||||
/*
|
||||
* attach script loader
|
||||
*/
|
||||
if (document.body) {
|
||||
s = document.createElement('script');
|
||||
s.type="text/javascript";
|
||||
s.src = p+'extensions/scriptqueue.js';
|
||||
head.appendChild(s);
|
||||
} else {
|
||||
document.write("<scr"+"ipt type=\"text/javascript\" src=\""+p+'extensions/scriptqueue.js'+"\"></scr"+"ipt>");
|
||||
}
|
||||
}
|
||||
})();
|
|
@ -3,6 +3,9 @@
|
|||
py:extends="'master.kid'">
|
||||
<head>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" py:replace="''"/>
|
||||
<script type="text/javascript"
|
||||
src="../static/virtual_keyboard/vk_loader.js?vk_layout=DE German"
|
||||
py:attrs="src=tg.url('/static/virtual_keyboard/vk_loader.js?vk_layout=DE%20German&vk_skin=soberTouch')" />
|
||||
<title>Bild versenden</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -20,17 +23,26 @@
|
|||
<form action="${tg.url('/senden')}" method="post">
|
||||
<label for="mailaddress">An:</label>
|
||||
<input type="textfield" id="mailaddress"
|
||||
name="mailaddress" value="${mailaddress}" size="30" />
|
||||
name="mailaddress" value="${mailaddress}" size="30"
|
||||
onfocus="VirtualKeyboard.attachInput(this)" />
|
||||
<br/>
|
||||
<label for="mailtext">Text:</label>
|
||||
<textarea name="mailtext" id="mailtext"
|
||||
rows="10" cols="40" wrap="physical">${mailtext}</textarea>
|
||||
rows="10" cols="40" wrap="physical"
|
||||
onfocus="VirtualKeyboard.attachInput(this)"
|
||||
>${mailtext}</textarea>
|
||||
<br/>
|
||||
<input type="submit" name="senden" value="senden" />
|
||||
</form>
|
||||
</div>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
<div id="vkb"></div>
|
||||
<script type="text/javascript">
|
||||
EM.addEventListener(window,'domload',function(){
|
||||
VirtualKeyboard.toggle('mailaddress','vkb');
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Add table
Reference in a new issue