Refactor slide methods in utils and use them for toolbar menus

This commit is contained in:
JC Brand 2017-07-15 11:03:22 +02:00
parent ce2548c838
commit b2a118ca9e
12 changed files with 624 additions and 608 deletions

View File

@ -148,7 +148,7 @@ css/mobile.min.css:: stamp-npm sass/*
.PHONY: watch
watch: stamp-bundler
$(SASS) --watch -I ./node_modules/bourbon/app/assets/stylesheets/ sass/converse/converse.scss:css/converse.css sass/_muc_embedded.scss:css/converse-muc-embedded.css
$(SASS) --watch -I ./node_modules/bourbon/app/assets/stylesheets/ sass/converse/converse.scss:css/converse.css sass/_muc_embedded.scss:css/converse-muc-embedded.css sass/inverse/inverse.scss:css/inverse.css
.PHONY: watchjs
watchjs: stamp-npm

View File

@ -1201,9 +1201,6 @@
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
#converse-embedded-chat .emoticon,
#conversejs .emoticon {
font-size: 14px; }
@keyframes fadein {
0% {
opacity: 0; }
@ -1234,6 +1231,10 @@
#conversejs .hidden {
opacity: 0;
display: none; }
#converse-embedded-chat .collapsed,
#conversejs .collapsed {
height: 0;
overflow: hidden; }
#converse-embedded-chat .locked,
#conversejs .locked {
padding-right: 22px; }
@ -1697,12 +1698,6 @@
color: #818479;
text-decoration: none;
text-shadow: none; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .emoji-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .emoji-picker {
margin-bottom: 30px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toolbar-picker-panel a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toolbar-picker-panel a {
color: #578EA9; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .chat-toolbar-text,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .chat-toolbar-text {
font-size: 12px;
@ -1712,10 +1707,10 @@
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted {
color: #818479; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a .toolbar-picker-panel a,
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted .toolbar-picker-panel a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a .toolbar-picker-panel a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted .toolbar-picker-panel a {
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a .toolbar-menu a,
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted .toolbar-menu a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a .toolbar-menu a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted .toolbar-menu a {
color: #578EA9; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unverified a,
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unverified,
@ -1736,79 +1731,75 @@
float: right; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li {
cursor: pointer;
display: inline-block;
list-style: none;
padding: 0 3px 0 3px;
cursor: pointer;
margin-top: 1px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li:hover {
cursor: pointer; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar ul,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul {
background: #fff;
bottom: 100%;
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
font-size: 12px;
margin: 0;
position: absolute;
right: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul li {
cursor: pointer;
list-style: none;
position: relative; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar ul li a:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul li a:hover {
color: #8f2831; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li {
margin-left: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley {
color: #818479;
padding-left: 5px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul {
left: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-category-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-category-picker {
margin-top: 1px;
padding: 0 3px 0 3px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li:hover {
cursor: pointer; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu {
background-color: #fff;
bottom: 100%;
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
font-size: 12px;
margin: 0;
position: absolute;
right: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu a {
color: #578EA9; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-category-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-category-picker {
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
z-index: 100; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-category-picker .picked,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-category-picker .picked {
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-category-picker .picked,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-category-picker .picked {
background-color: #DCF9F6; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-picker {
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-picker {
height: 250px;
overflow: scroll; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li {
font-size: 14px;
padding: 5px;
z-index: 98; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li.emoji a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li.emoji a {
font-size: 20px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li:hover {
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul li {
margin-left: 0;
cursor: pointer;
list-style: none;
position: relative; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul li a:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul li a:hover {
color: #8f2831; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-toolbar-menu,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-toolbar-menu {
color: #818479; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-toolbar-menu ul li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-toolbar-menu ul li:hover {
background-color: #DCF9F6; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li {
padding: 7px;
background-color: white;
display: block;
z-index: 99; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li a {
-moz-transition: background-color 0.2s ease-in-out;
-webkit-transition: background-color 0.2s ease-in-out;
transition: background-color 0.2s ease-in-out;
display: block;
padding: 1px;
text-decoration: none; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li:hover {
background-color: #DCF9F6; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley {
padding-left: 5px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul {
left: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul li {
padding: 5px;
z-index: 98; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul li.emoji a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul li.emoji a {
font-size: 20px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul {
z-index: 99; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul li {
display: block;
padding: 7px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul li a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul li a {
display: block; }
#converse-embedded-chat .chatbox .dragresize,
#conversejs .chatbox .dragresize {
background: transparent;

View File

@ -1201,9 +1201,6 @@
-moz-user-select: none;
-ms-user-select: none;
user-select: none; }
#converse-embedded-chat .emoticon,
#conversejs .emoticon {
font-size: 16px; }
@keyframes fadein {
0% {
opacity: 0; }
@ -1234,6 +1231,10 @@
#conversejs .hidden {
opacity: 0;
display: none; }
#converse-embedded-chat .collapsed,
#conversejs .collapsed {
height: 0;
overflow: hidden; }
#converse-embedded-chat .locked,
#conversejs .locked {
padding-right: 22px; }
@ -1743,12 +1744,6 @@ body {
color: #818479;
text-decoration: none;
text-shadow: none; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .emoji-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .emoji-picker {
margin-bottom: 34px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toolbar-picker-panel a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toolbar-picker-panel a {
color: #578EA9; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .chat-toolbar-text,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .chat-toolbar-text {
font-size: 12px;
@ -1758,10 +1753,10 @@ body {
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted {
color: #818479; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a .toolbar-picker-panel a,
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted .toolbar-picker-panel a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a .toolbar-picker-panel a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted .toolbar-picker-panel a {
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a .toolbar-menu a,
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted .toolbar-menu a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted a .toolbar-menu a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .unencrypted .toolbar-menu a {
color: #578EA9; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unverified a,
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .unverified,
@ -1782,79 +1777,75 @@ body {
float: right; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li {
cursor: pointer;
display: inline-block;
list-style: none;
padding: 0 3px 0 3px;
cursor: pointer;
margin-top: 1px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li:hover {
cursor: pointer; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar ul,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul {
background: #fff;
bottom: 100%;
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
font-size: 12px;
margin: 0;
position: absolute;
right: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul li {
cursor: pointer;
list-style: none;
position: relative; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar ul li a:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar ul li a:hover {
color: #8f2831; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li {
margin-left: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley {
color: #818479;
padding-left: 5px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul {
left: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-category-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-category-picker {
margin-top: 1px;
padding: 0 3px 0 3px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li:hover {
cursor: pointer; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu {
background-color: #fff;
bottom: 100%;
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
font-size: 12px;
margin: 0;
position: absolute;
right: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu a {
color: #578EA9; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-category-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-category-picker {
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
z-index: 100; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-category-picker .picked,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-category-picker .picked {
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-category-picker .picked,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-category-picker .picked {
background-color: #DCF9F6; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul.emoji-picker {
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-picker,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul.emoji-picker {
height: 250px;
overflow: scroll; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li {
font-size: 16px;
padding: 5px;
z-index: 98; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li.emoji a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li.emoji a {
font-size: 26px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-smiley ul li:hover {
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul li {
margin-left: 0;
cursor: pointer;
list-style: none;
position: relative; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul li a:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li .toolbar-menu ul li a:hover {
color: #8f2831; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-toolbar-menu,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-toolbar-menu {
color: #818479; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-toolbar-menu ul li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-toolbar-menu ul li:hover {
background-color: #DCF9F6; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li {
padding: 7px;
background-color: white;
display: block;
z-index: 99; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li a {
-moz-transition: background-color 0.2s ease-in-out;
-webkit-transition: background-color 0.2s ease-in-out;
transition: background-color 0.2s ease-in-out;
display: block;
padding: 1px;
text-decoration: none; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li:hover,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar .toggle-otr ul li:hover {
background-color: #DCF9F6; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley {
padding-left: 5px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul {
left: 0; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul li {
padding: 5px;
z-index: 98; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul li.emoji a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-smiley ul li.emoji a {
font-size: 26px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul {
z-index: 99; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul li,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul li {
display: block;
padding: 7px; }
#converse-embedded-chat .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul li a,
#conversejs .chatbox form.sendXMPPMessage .chat-toolbar li.toggle-otr ul li a {
display: block; }
#converse-embedded-chat .chatbox .dragresize,
#conversejs .chatbox .dragresize {
background: transparent;

View File

@ -272,14 +272,6 @@
text-decoration: none;
text-shadow: none;
}
.emoji-picker {
margin-bottom: $toolbar-height + 5px;
}
.toolbar-picker-panel {
a {
color: $link-color;
}
}
.chat-toolbar-text {
font-size: 12px;
padding-right: 3px;
@ -287,7 +279,7 @@
.unencrypted a,
.unencrypted {
color: $text-color;
.toolbar-picker-panel {
.toolbar-menu {
a {
color: $link-color;
}
@ -307,83 +299,83 @@
float: right;
}
li {
cursor: pointer;
display: inline-block;
list-style: none;
padding: 0 3px 0 3px;
cursor: pointer;
margin-top: 1px;
}
li:hover {
cursor: pointer;
}
ul {
background: #fff;
bottom: 100%;
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
font-size: 12px;
margin: 0;
position: absolute;
right: 0;
li {
padding: 0 3px 0 3px;
&:hover {
cursor: pointer;
list-style: none;
position: relative;
a:hover {
color: #8f2831;
}
}
}
li {
margin-left: 0;
}
.toggle-smiley {
color: $text-color;
padding-left: 5px;
ul {
&.emoji-category-picker {
z-index: 100;
.picked {
background-color: $highlight-color;
.toolbar-menu {
background-color: #fff;
bottom: 100%;
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
font-size: 12px;
margin: 0;
position: absolute;
right: 0;
a {
color: $link-color;
}
ul {
&.emoji-category-picker {
box-shadow: -1px -1px 2px 0 rgba(0, 0, 0, 0.4);
z-index: 100;
.picked {
background-color: $highlight-color;
}
}
}
&.emoji-picker {
height: 250px;
overflow: scroll;
}
left: 0;
li {
font-size: $font-size;
padding: 5px;
z-index: 98;
&.emoji {
a {
font-size: $font-size-huge;
&.emoji-picker {
height: 250px;
overflow: scroll;
}
li {
margin-left: 0;
cursor: pointer;
list-style: none;
position: relative;
a:hover {
color: #8f2831;
}
}
}
li:hover {
background-color: $highlight-color;
}
}
}
.toggle-otr {
ul {
li {
padding: 7px;
background-color: white;
display: block;
z-index: 99;
a {
-moz-transition: background-color 0.2s ease-in-out;
-webkit-transition: background-color 0.2s ease-in-out;
transition: background-color 0.2s ease-in-out;
display: block;
padding: 1px;
text-decoration: none;
&.toggle-toolbar-menu {
color: $text-color;
ul {
li {
&:hover {
background-color: $highlight-color;
}
}
}
li:hover {
background-color: $highlight-color;
}
&.toggle-smiley {
padding-left: 5px;
ul {
left: 0;
li {
padding: 5px;
z-index: 98;
&.emoji {
a {
font-size: $font-size-huge;
}
}
}
}
}
&.toggle-otr {
ul {
z-index: 99;
li {
display: block;
padding: 7px;
a {
display: block;
}
}
}
}
}

View File

@ -74,6 +74,10 @@
opacity: 0;
display: none;
}
.collapsed {
height: 0;
overflow: hidden;
}
.locked {
padding-right: 22px;

View File

@ -54,14 +54,13 @@
//
registerGlobalEventHandlers: function () {
this.__super__.registerGlobalEventHandlers();
document.addEventListener('click', function () {
if ($('.toggle-smiley ul').is(':visible')) {
_.each(
document.querySelectorAll('.toggle-smiley .emoji-picker-container'),
utils.hideElement
);
document.addEventListener(
'click', function () {
utils.slideInAllElements(
document.querySelectorAll('.toolbar-menu')
)
}
});
);
},
ChatBoxViews: {
@ -114,7 +113,7 @@
});
_converse.EmojiPickerView = Backbone.View.extend({
className: 'emoji-picker-container hidden',
className: 'emoji-picker-container toolbar-menu collapsed',
events: {
'click .emoji-category-picker li a': 'chooseCategory',
},
@ -710,7 +709,16 @@
return;
}
}
utils.toggleElement(this.emoji_picker_view.el);
const elements = _.difference(
document.querySelectorAll('.toolbar-menu'),
[this.emoji_picker_view.el]
);
utils.slideInAllElements(elements).then(
_.partial(
utils.slideToggleElement,
this.emoji_picker_view.el
)
);
},
toggleCall (ev) {

View File

@ -42,6 +42,7 @@
OTR_CLASS_MAPPING[VERIFIED] = 'verified';
OTR_CLASS_MAPPING[FINISHED] = 'finished';
converse.plugins.add('converse-otr', {
overrides: {
@ -51,15 +52,6 @@
//
// New functions which don't exist yet can also be added.
registerGlobalEventHandlers () {
this.__super__.registerGlobalEventHandlers();
document.addEventListener('click', function () {
if ($('.toggle-otr ul').is(':visible')) {
_.each($('.toggle-otr ul', this), utils.hideElement);
}
});
},
ChatBox: {
initialize () {
this.__super__.initialize.apply(this, arguments);
@ -347,7 +339,6 @@
},
startOTRFromToolbar (ev) {
$(ev.target).parent().parent().slideUp();
ev.stopPropagation();
this.model.initiateOTR();
},
@ -392,7 +383,17 @@
toggleOTRMenu (ev) {
ev.stopPropagation();
utils.toggleElement(this.el.querySelector('.toggle-otr ul'));
const menu = this.el.querySelector('.toggle-otr ul');
const elements = _.difference(
document.querySelectorAll('.toolbar-menu'),
[menu]
);
utils.slideInAllElements(elements).then(
_.partial(
utils.slideToggleElement,
menu
)
);
},
getOTRTooltip () {

View File

@ -70,7 +70,7 @@
});
this.hide();
if (this.list_model.get('toggle-state') !== _converse.OPENED) {
this.el.querySelector('.open-rooms-list').classList.add('hidden');
this.el.querySelector('.open-rooms-list').classList.add('collapsed');
}
this.model.each(this.renderRoomsListElement.bind(this));
const controlboxview = _converse.chatboxviews.get('controlbox');
@ -142,13 +142,13 @@
if (ev && ev.preventDefault) { ev.preventDefault(); }
const el = ev.target;
if (el.classList.contains("icon-opened")) {
utils.slideUp(this.el.querySelector('.open-rooms-list')).then(() => {
utils.slideIn(this.el.querySelector('.open-rooms-list')).then(() => {
this.list_model.save({'toggle-state': _converse.CLOSED});
el.classList.remove("icon-opened");
el.classList.add("icon-closed");
});
} else {
utils.slideDown(this.el.querySelector('.open-rooms-list')).then(() => {
utils.slideOut(this.el.querySelector('.open-rooms-list')).then(() => {
this.list_model.save({'toggle-state': _converse.OPENED});
el.classList.remove("icon-closed");
el.classList.add("icon-opened");

View File

@ -1,10 +1,3 @@
<ul class="emoji-category-picker">
{[ _.forEach(emojis_by_category, function (obj, category) { ]}
<li data-category="{{{category}}}" class="emoji-category {[ if (current_category === category) { ]} picked {[ } ]}">
<a href="#" data-category="{{{category}}}"> {{ emojione.shortnameToUnicode(emojis_by_category[category][0]._shortname) }} </a>
</li>
{[ }); ]}
</ul>
{[ _.forEach(emojis_by_category, function (obj, category) { ]}
<ul class="emoji-picker emoji-picker-{{{category}}} {[ if (current_category !== category) { ]} hidden {[ } ]}">
{[ _.forEach(emojis_by_category[category], function (emoji) { ]}
@ -14,3 +7,10 @@
{[ }); ]}
</ul>
{[ }); ]}
<ul class="emoji-category-picker">
{[ _.forEach(emojis_by_category, function (obj, category) { ]}
<li data-category="{{{category}}}" class="emoji-category {[ if (current_category === category) { ]} picked {[ } ]}">
<a href="#" data-category="{{{category}}}"> {{ emojione.shortnameToUnicode(emojis_by_category[category][0]._shortname) }} </a>
</li>
{[ }); ]}
</ul>

View File

@ -1,5 +1,5 @@
{[ if (use_emoji) { ]}
<li class="toggle-smiley icon-happy" title="{{{label_insert_smiley}}}">
<li class="toggle-toolbar-menu toggle-smiley icon-happy" title="{{{label_insert_smiley}}}">
<ul class="emoji-picker"></ul>
</li>
{[ } ]}

View File

@ -1,5 +1,5 @@
{[ if (allow_otr) { ]}
<li class="toggle-otr {{{otr_status_class}}}" title="{{{otr_tooltip}}}">
<li class="toggle-toolbar-menu toggle-otr {{{otr_status_class}}}" title="{{{otr_tooltip}}}">
<span class="chat-toolbar-text">{{{otr_translated_status}}}</span>
{[ if (otr_status == UNENCRYPTED) { ]}
<span class="icon-unlocked"></span>
@ -13,7 +13,7 @@
{[ if (otr_status == FINISHED) { ]}
<span class="icon-unlocked"></span>
{[ } ]}
<ul class="toolbar-picker-panel">
<ul class="toolbar-menu collapsed">
{[ if (otr_status == UNENCRYPTED) { ]}
<li><a class="start-otr" href="#">{{{label_start_encrypted_conversation}}}</a></li>
{[ } ]}

View File

@ -129,356 +129,385 @@
return this;
};
var utils = {
// Translation machinery
// ---------------------
__: function (str) {
if (!utils.isConverseLocale(this.locale) || this.locale === 'en') {
return Jed.sprintf.apply(Jed, arguments);
}
if (typeof this.jed === "undefined") {
this.jed = new Jed(window.JSON.parse(locales[this.locale]));
}
var t = this.jed.translate(str);
if (arguments.length>1) {
return t.fetch.apply(t, [].slice.call(arguments,1));
} else {
return t.fetch();
}
},
function calculateSlideStep (height) {
if (height > 100) {
return 10;
} else if (height > 50) {
return 5;
} else {
return 1;
}
}
___: function (str) {
/* XXX: This is part of a hack to get gettext to scan strings to be
* translated. Strings we cannot send to the function above because
* they require variable interpolation and we don't yet have the
* variables at scan time.
*
* See actionInfoMessages in src/converse-muc.js
*/
return str;
},
var utils = {};
isLocaleAvailable: function (locale, available) {
/* Check whether the locale or sub locale (e.g. en-US, en) is supported.
*
* Parameters:
* (Function) available - returns a boolean indicating whether the locale is supported
*/
if (available(locale)) {
return locale;
} else {
var sublocale = locale.split("-")[0];
if (sublocale !== locale && available(sublocale)) {
return sublocale;
}
}
},
// Translation machinery
// ---------------------
utils.__ = function (str) {
if (!utils.isConverseLocale(this.locale) || this.locale === 'en') {
return Jed.sprintf.apply(Jed, arguments);
}
if (typeof this.jed === "undefined") {
this.jed = new Jed(window.JSON.parse(locales[this.locale]));
}
var t = this.jed.translate(str);
if (arguments.length>1) {
return t.fetch.apply(t, [].slice.call(arguments,1));
} else {
return t.fetch();
}
};
hideElement: function (el) {
el.classList.add('hidden');
},
utils.___ = function (str) {
/* XXX: This is part of a hack to get gettext to scan strings to be
* translated. Strings we cannot send to the function above because
* they require variable interpolation and we don't yet have the
* variables at scan time.
*
* See actionInfoMessages in src/converse-muc.js
*/
return str;
};
toggleElement: function (el) {
if (_.includes(el.classList, 'hidden')) {
// XXX: use fadeIn?
el.classList.remove('hidden');
} else {
this.hideElement (el);
}
},
slideDown: function (el, interval=0.6) {
return new Promise((resolve, reject) => {
if (_.isNil(el)) {
const err = "Undefined or null element passed into slideDown"
console.warn(err);
reject(new Error(err));
}
let intval = el.getAttribute('data-slider-intval');
if (intval) {
window.clearInterval(intval);
}
let h = 0;
const end_height = el.getAttribute('data-slider-height');
intval = window.setInterval(function () {
h++;
el.style.height = h + 'px';
if (h >= end_height) {
window.clearInterval(intval);
el.style.height = '';
el.style.overflow = '';
el.removeAttribute('data-slider-intval');
el.removeAttribute('data-slider-height');
resolve();
}
}, interval);
el.setAttribute('data-slider-intval', intval);
});
},
slideUp: function (el, interval=0.6) {
return new Promise((resolve, reject) => {
if (_.isNil(el)) {
const err = "Undefined or null element passed into slideUp";
console.warn(err);
reject(new Error(err));
}
let intval = el.getAttribute('data-slider-intval');
if (intval) {
window.clearInterval(intval);
}
let h = el.offsetHeight;
el.setAttribute('data-slider-height', h);
el.style.overflow = 'hidden';
intval = window.setInterval(function () {
el.style.height = h + 'px';
h--;
if (h < 0) {
window.clearInterval(intval);
el.removeAttribute('data-slider-intval');
resolve();
}
}, interval);
el.setAttribute('data-slider-intval', intval);
});
},
fadeIn: function (el, callback) {
if (_.isNil(el)) {
console.warn("Undefined or null element passed into fadeIn");
}
if ($.fx.off) {
el.classList.remove('hidden');
if (_.isFunction(callback)) {
callback();
}
return;
}
if (_.includes(el.classList, 'hidden')) {
/* XXX: This doesn't appear to be working...
el.addEventListener("webkitAnimationEnd", _.partial(afterAnimationEnd, el, callback), false);
el.addEventListener("animationend", _.partial(afterAnimationEnd, el, callback), false);
*/
setTimeout(_.partial(afterAnimationEnd, el, callback), 351);
el.classList.add('visible');
el.classList.remove('hidden');
} else {
afterAnimationEnd(el, callback);
}
},
isSameBareJID: function (jid1, jid2) {
return Strophe.getBareJidFromJid(jid1).toLowerCase() ===
Strophe.getBareJidFromJid(jid2).toLowerCase();
},
isNewMessage: function (message) {
/* Given a stanza, determine whether it's a new
* message, i.e. not a MAM archived one.
*/
if (message instanceof Element) {
return !(sizzle('result[xmlns="'+Strophe.NS.MAM+'"]', message).length);
} else {
return !message.get('archive_id');
}
},
isOTRMessage: function (message) {
var body = message.querySelector('body'),
text = (!_.isNull(body) ? body.textContent: undefined);
return text && !!text.match(/^\?OTR/);
},
isHeadlineMessage: function (message) {
var from_jid = message.getAttribute('from');
if (message.getAttribute('type') === 'headline') {
return true;
}
if (message.getAttribute('type') !== 'error' &&
!_.isNil(from_jid) &&
!_.includes(from_jid, '@')) {
// Some servers (I'm looking at you Prosody) don't set the message
// type to "headline" when sending server messages. For now we
// check if an @ signal is included, and if not, we assume it's
// a headline message.
return true;
}
return false;
},
merge: function merge (first, second) {
/* Merge the second object into the first one.
*/
for (var k in second) {
if (_.isObject(first[k])) {
merge(first[k], second[k]);
} else {
first[k] = second[k];
}
}
},
applyUserSettings: function applyUserSettings (context, settings, user_settings) {
/* Configuration settings might be nested objects. We only want to
* add settings which are whitelisted.
*/
for (var k in settings) {
if (_.isUndefined(user_settings[k])) {
continue;
}
if (_.isObject(settings[k]) && !_.isArray(settings[k])) {
applyUserSettings(context[k], settings[k], user_settings[k]);
} else {
context[k] = user_settings[k];
}
}
},
refreshWebkit: function () {
/* This works around a webkit bug. Refreshes the browser's viewport,
* otherwise chatboxes are not moved along when one is closed.
*/
if ($.browser.webkit && window.requestAnimationFrame) {
window.requestAnimationFrame(function () {
var conversejs = document.getElementById('conversejs');
conversejs.style.display = 'none';
var tmp = conversejs.offsetHeight; // jshint ignore:line
conversejs.style.display = 'block';
});
}
},
webForm2xForm: function (field) {
/* Takes an HTML DOM and turns it into an XForm field.
*
* Parameters:
* (DOMElement) field - the field to convert
*/
var $input = $(field), value;
if ($input.is('[type=checkbox]')) {
value = $input.is(':checked') && 1 || 0;
} else if ($input.is('textarea')) {
value = [];
var lines = $input.val().split('\n');
for( var vk=0; vk<lines.length; vk++) {
var val = $.trim(lines[vk]);
if (val === '')
continue;
value.push(val);
}
} else {
value = $input.val();
}
return $(tpl_field({
name: $input.attr('name'),
value: value
}))[0];
},
contains: function (attr, query) {
return function (item) {
if (typeof attr === 'object') {
var value = false;
_.forEach(attr, function (a) {
value = value || _.includes(item.get(a).toLowerCase(), query.toLowerCase());
});
return value;
} else if (typeof attr === 'string') {
return _.includes(item.get(attr).toLowerCase(), query.toLowerCase());
} else {
throw new TypeError('contains: wrong attribute type. Must be string or array.');
}
};
},
xForm2webForm: function ($field, $stanza) {
/* Takes a field in XMPP XForm (XEP-004: Data Forms) format
* and turns it into a HTML DOM field.
*
* Parameters:
* (XMLElement) field - the field to convert
*/
// FIXME: take <required> into consideration
var options = [], j, $options, $values, value, values;
if ($field.attr('type') === 'list-single' || $field.attr('type') === 'list-multi') {
values = [];
$values = $field.children('value');
for (j=0; j<$values.length; j++) {
values.push($($values[j]).text());
}
$options = $field.children('option');
for (j=0; j<$options.length; j++) {
value = $($options[j]).find('value').text();
options.push(tpl_select_option({
value: value,
label: $($options[j]).attr('label'),
selected: _.startsWith(values, value),
required: $field.find('required').length
}));
}
return tpl_form_select({
name: $field.attr('var'),
label: $field.attr('label'),
options: options.join(''),
multiple: ($field.attr('type') === 'list-multi'),
required: $field.find('required').length
});
} else if ($field.attr('type') === 'fixed') {
return $('<p class="form-help">').text($field.find('value').text());
} else if ($field.attr('type') === 'jid-multi') {
return tpl_form_textarea({
name: $field.attr('var'),
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else if ($field.attr('type') === 'boolean') {
return tpl_form_checkbox({
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
checked: $field.find('value').text() === "1" && 'checked="1"' || '',
required: $field.find('required').length
});
} else if ($field.attr('type') && $field.attr('var') === 'username') {
return tpl_form_username({
domain: ' @'+this.domain,
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else if ($field.attr('type')) {
return tpl_form_input({
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else {
if ($field.attr('var') === 'ocr') { // Captcha
return _.reduce(_.map($field.find('uri'),
$.proxy(function (uri) {
return tpl_form_captcha({
label: this.$field.attr('label'),
name: this.$field.attr('var'),
data: this.$stanza.find('data[cid="'+uri.textContent.replace(/^cid:/, '')+'"]').text(),
type: uri.getAttribute('type'),
required: this.$field.find('required').length
});
}, {'$stanza': $stanza, '$field': $field})
),
function (memo, num) { return memo + num; }, ''
);
}
utils.isLocaleAvailable = function (locale, available) {
/* Check whether the locale or sub locale (e.g. en-US, en) is supported.
*
* Parameters:
* (Function) available - returns a boolean indicating whether the locale is supported
*/
if (available(locale)) {
return locale;
} else {
var sublocale = locale.split("-")[0];
if (sublocale !== locale && available(sublocale)) {
return sublocale;
}
}
};
utils.slideInAllElements = function (elements) {
return Promise.all(
_.map(
elements,
_.partial(utils.slideIn, _, 600)
));
};
utils.slideToggleElement = function (el) {
if (!el.offsetHeight) {
return utils.slideOut(el);
} else {
return utils.slideIn(el);
}
};
utils.slideOut = function (el, duration=600) {
/* Shows/expands an element by sliding it out of itself. */
return new Promise((resolve, reject) => {
if (_.isNil(el)) {
const err = "Undefined or null element passed into slideOut"
console.warn(err);
reject(new Error(err));
}
let interval_marker = el.getAttribute('data-slider-marker');
if (interval_marker) {
window.clearInterval(interval_marker);
}
const end_height = _.reduce(el.children, function (result, child) {
return result + child.offsetHeight;
}, 0);
const step = calculateSlideStep(end_height),
interval = end_height/duration*step;
let h = 0;
interval_marker = window.setInterval(function () {
h += step;
if (h < end_height) {
el.style.height = h + 'px';
} else {
el.style.height = end_height + 'px';
window.clearInterval(interval_marker);
el.style.overflow = '';
el.removeAttribute('data-slider-marker');
resolve();
}
}, interval);
el.setAttribute('data-slider-marker', interval_marker);
});
};
utils.slideIn = function (el, duration=600) {
/* Hides/collapses an element by sliding it into itself. */
return new Promise((resolve, reject) => {
if (_.isNil(el)) {
const err = "Undefined or null element passed into slideIn";
console.warn(err);
reject(new Error(err));
}
if (!el.offsetHeight) {
resolve();
return;
}
let interval_marker = el.getAttribute('data-slider-marker');
if (interval_marker) {
window.clearInterval(interval_marker);
}
let h = el.offsetHeight;
const step = calculateSlideStep(h),
interval = h/duration*step;
el.style.overflow = 'hidden';
interval_marker = window.setInterval(function () {
h -= step;
if (h > 0) {
el.style.height = h + 'px';
} else {
el.style.height = 0 + 'px';
window.clearInterval(interval_marker);
el.removeAttribute('data-slider-marker');
resolve();
}
}, interval);
el.setAttribute('data-slider-marker', interval_marker);
});
};
utils.fadeIn = function (el, callback) {
if (_.isNil(el)) {
console.warn("Undefined or null element passed into fadeIn");
}
if ($.fx.off) {
el.classList.remove('hidden');
if (_.isFunction(callback)) {
callback();
}
return;
}
if (_.includes(el.classList, 'hidden')) {
/* XXX: This doesn't appear to be working...
el.addEventListener("webkitAnimationEnd", _.partial(afterAnimationEnd, el, callback), false);
el.addEventListener("animationend", _.partial(afterAnimationEnd, el, callback), false);
*/
setTimeout(_.partial(afterAnimationEnd, el, callback), 351);
el.classList.add('visible');
el.classList.remove('hidden');
} else {
afterAnimationEnd(el, callback);
}
};
utils.isSameBareJID = function (jid1, jid2) {
return Strophe.getBareJidFromJid(jid1).toLowerCase() ===
Strophe.getBareJidFromJid(jid2).toLowerCase();
};
utils.isNewMessage = function (message) {
/* Given a stanza, determine whether it's a new
* message, i.e. not a MAM archived one.
*/
if (message instanceof Element) {
return !(sizzle('result[xmlns="'+Strophe.NS.MAM+'"]', message).length);
} else {
return !message.get('archive_id');
}
};
utils.isOTRMessage = function (message) {
var body = message.querySelector('body'),
text = (!_.isNull(body) ? body.textContent: undefined);
return text && !!text.match(/^\?OTR/);
};
utils.isHeadlineMessage = function (message) {
var from_jid = message.getAttribute('from');
if (message.getAttribute('type') === 'headline') {
return true;
}
if (message.getAttribute('type') !== 'error' &&
!_.isNil(from_jid) &&
!_.includes(from_jid, '@')) {
// Some servers (I'm looking at you Prosody) don't set the message
// type to "headline" when sending server messages. For now we
// check if an @ signal is included, and if not, we assume it's
// a headline message.
return true;
}
return false;
};
utils.merge = function merge (first, second) {
/* Merge the second object into the first one.
*/
for (var k in second) {
if (_.isObject(first[k])) {
merge(first[k], second[k]);
} else {
first[k] = second[k];
}
}
};
utils.applyUserSettings = function applyUserSettings (context, settings, user_settings) {
/* Configuration settings might be nested objects. We only want to
* add settings which are whitelisted.
*/
for (var k in settings) {
if (_.isUndefined(user_settings[k])) {
continue;
}
if (_.isObject(settings[k]) && !_.isArray(settings[k])) {
applyUserSettings(context[k], settings[k], user_settings[k]);
} else {
context[k] = user_settings[k];
}
}
};
utils.refreshWebkit = function () {
/* This works around a webkit bug. Refreshes the browser's viewport,
* otherwise chatboxes are not moved along when one is closed.
*/
if ($.browser.webkit && window.requestAnimationFrame) {
window.requestAnimationFrame(function () {
var conversejs = document.getElementById('conversejs');
conversejs.style.display = 'none';
var tmp = conversejs.offsetHeight; // jshint ignore:line
conversejs.style.display = 'block';
});
}
};
utils.webForm2xForm = function (field) {
/* Takes an HTML DOM and turns it into an XForm field.
*
* Parameters:
* (DOMElement) field - the field to convert
*/
var $input = $(field), value;
if ($input.is('[type=checkbox]')) {
value = $input.is(':checked') && 1 || 0;
} else if ($input.is('textarea')) {
value = [];
var lines = $input.val().split('\n');
for( var vk=0; vk<lines.length; vk++) {
var val = $.trim(lines[vk]);
if (val === '')
continue;
value.push(val);
}
} else {
value = $input.val();
}
return $(tpl_field({
name: $input.attr('name'),
value: value
}))[0];
};
utils.contains = function (attr, query) {
return function (item) {
if (typeof attr === 'object') {
var value = false;
_.forEach(attr, function (a) {
value = value || _.includes(item.get(a).toLowerCase(), query.toLowerCase());
});
return value;
} else if (typeof attr === 'string') {
return _.includes(item.get(attr).toLowerCase(), query.toLowerCase());
} else {
throw new TypeError('contains: wrong attribute type. Must be string or array.');
}
};
};
utils.xForm2webForm = function ($field, $stanza) {
/* Takes a field in XMPP XForm (XEP-004: Data Forms) format
* and turns it into a HTML DOM field.
*
* Parameters:
* (XMLElement) field - the field to convert
*/
// FIXME: take <required> into consideration
var options = [], j, $options, $values, value, values;
if ($field.attr('type') === 'list-single' || $field.attr('type') === 'list-multi') {
values = [];
$values = $field.children('value');
for (j=0; j<$values.length; j++) {
values.push($($values[j]).text());
}
$options = $field.children('option');
for (j=0; j<$options.length; j++) {
value = $($options[j]).find('value').text();
options.push(tpl_select_option({
value: value,
label: $($options[j]).attr('label'),
selected: _.startsWith(values, value),
required: $field.find('required').length
}));
}
return tpl_form_select({
name: $field.attr('var'),
label: $field.attr('label'),
options: options.join(''),
multiple: ($field.attr('type') === 'list-multi'),
required: $field.find('required').length
});
} else if ($field.attr('type') === 'fixed') {
return $('<p class="form-help">').text($field.find('value').text());
} else if ($field.attr('type') === 'jid-multi') {
return tpl_form_textarea({
name: $field.attr('var'),
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else if ($field.attr('type') === 'boolean') {
return tpl_form_checkbox({
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
checked: $field.find('value').text() === "1" && 'checked="1"' || '',
required: $field.find('required').length
});
} else if ($field.attr('type') && $field.attr('var') === 'username') {
return tpl_form_username({
domain: ' @'+this.domain,
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else if ($field.attr('type')) {
return tpl_form_input({
name: $field.attr('var'),
type: XFORM_TYPE_MAP[$field.attr('type')],
label: $field.attr('label') || '',
value: $field.find('value').text(),
required: $field.find('required').length
});
} else {
if ($field.attr('var') === 'ocr') { // Captcha
return _.reduce(_.map($field.find('uri'),
$.proxy(function (uri) {
return tpl_form_captcha({
label: this.$field.attr('label'),
name: this.$field.attr('var'),
data: this.$stanza.find('data[cid="'+uri.textContent.replace(/^cid:/, '')+'"]').text(),
type: uri.getAttribute('type'),
required: this.$field.find('required').length
});
}, {'$stanza': $stanza, '$field': $field})
),
function (memo, num) { return memo + num; }, ''
);
}
}
}
utils.detectLocale = function (library_check) {
/* Determine which locale is supported by the user's system as well
* as by the relevant library (e.g. converse.js or moment.js).