@@ -65,7 +65,7 @@ | |||
"public/js/frappe/ui/messages.js", | |||
"public/js/frappe/request.js", | |||
"public/js/frappe/socket.js", | |||
"public/js/frappe/socketio_client.js", | |||
"public/js/frappe/router.js", | |||
"public/js/frappe/defaults.js", | |||
"public/js/lib/microtemplate.js", | |||
@@ -149,8 +149,10 @@ | |||
"public/js/frappe/form/print_layout.html", | |||
"public/js/frappe/form/print.js", | |||
"public/js/frappe/form/sidebar.js", | |||
"public/js/frappe/form/users_in_sidebar.html", | |||
"public/js/frappe/form/share.js", | |||
"public/js/frappe/form/set_sharing.html", | |||
"public/js/frappe/form/form_viewers.js", | |||
"public/js/frappe/form/form_sidebar.html", | |||
"public/js/frappe/form/footer/form_footer.html", | |||
@@ -6,7 +6,7 @@ | |||
margin-left: -1px; | |||
} | |||
th.fc-widget-header { | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
color: #8C99A5; | |||
} | |||
.fc-unthemed th, | |||
@@ -18,10 +18,10 @@ p { | |||
margin: 10px 0px; | |||
} | |||
.text-color { | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
} | |||
.text-muted { | |||
color: #8d99a6 !important; | |||
color: #8D99A6 !important; | |||
} | |||
.text-extra-muted { | |||
color: #d1d8dd !important; | |||
@@ -82,7 +82,7 @@ a.text-extra-muted { | |||
} | |||
kbd { | |||
color: inherit; | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
.btn [class^="icon-"], | |||
.nav [class^="icon-"], | |||
@@ -186,7 +186,7 @@ a.badge-hover:active .badge { | |||
transform: translate(-50%, -50%); | |||
-webkit-transform: translate(-50%, -50%); | |||
text-align: center; | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
} | |||
#freeze.dark { | |||
background-color: #334143; | |||
@@ -18,10 +18,10 @@ p { | |||
margin: 10px 0px; | |||
} | |||
.text-color { | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
} | |||
.text-muted { | |||
color: #8d99a6 !important; | |||
color: #8D99A6 !important; | |||
} | |||
.text-extra-muted { | |||
color: #d1d8dd !important; | |||
@@ -82,7 +82,7 @@ a.text-extra-muted { | |||
} | |||
kbd { | |||
color: inherit; | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
.btn [class^="icon-"], | |||
.nav [class^="icon-"], | |||
@@ -186,7 +186,7 @@ a.badge-hover:active .badge { | |||
transform: translate(-50%, -50%); | |||
-webkit-transform: translate(-50%, -50%); | |||
text-align: center; | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
} | |||
#freeze.dark { | |||
background-color: #334143; | |||
@@ -237,11 +237,11 @@ a.form-link { | |||
display: none; | |||
} | |||
.link-primary { | |||
color: #5e64ff; | |||
color: #5E64FF; | |||
} | |||
.link-primary:hover, | |||
.link-primary:focus { | |||
color: #5e64ff; | |||
color: #5E64FF; | |||
} | |||
.ui-autocomplete .link-option { | |||
font-weight: normal; | |||
@@ -358,13 +358,13 @@ ul.linked-with-list li { | |||
.ui-autocomplete .ui-state-focus, | |||
.ui-datepicker .ui-state-hover, | |||
.ui-autocomplete .ui-state-hover { | |||
background-color: #f0f4f7 !important; | |||
color: #36414c !important; | |||
background-color: #F0F4F7 !important; | |||
color: #36414C !important; | |||
text-shadow: none !important; | |||
} | |||
.ui-datepicker .ui-state-active, | |||
.ui-autocomplete .ui-state-active { | |||
background-color: #5e64ff !important; | |||
background-color: #5E64FF !important; | |||
color: #fff !important; | |||
text-shadow: none !important; | |||
} | |||
@@ -390,7 +390,7 @@ ul.linked-with-list li { | |||
} | |||
} | |||
.panel-bg { | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
} | |||
.light-bg { | |||
background-color: #fafbfc; | |||
@@ -452,7 +452,7 @@ ul.linked-with-list li { | |||
.msg-box { | |||
padding: 30px 15px; | |||
text-align: center; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
} | |||
.no-border { | |||
border: none !important; | |||
@@ -483,7 +483,7 @@ ul.linked-with-list li { | |||
border-top: 1px solid #d1d8dd; | |||
} | |||
.file-upload .input-group-addon { | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
font-size: 12px; | |||
} | |||
.file-upload .file-upload-or { | |||
@@ -75,11 +75,11 @@ body[data-route="desktop"] .navbar-default { | |||
letter-spacing: normal; | |||
} | |||
.app-icon:hover path { | |||
fill: #ffffff; | |||
fill: #fff; | |||
} | |||
.app-icon:hover i, | |||
.app-icon:hover { | |||
color: #ffffff; | |||
color: #fff; | |||
} | |||
.app-icon-small { | |||
padding: 12px; | |||
@@ -168,7 +168,7 @@ body[data-route="desktop"] .navbar-default { | |||
} | |||
.desktop-list-item:hover, | |||
.desktop-list-item:focus { | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
} | |||
.desktop-list-item h4 { | |||
display: inline-block; | |||
@@ -38,7 +38,7 @@ body { | |||
.offcanvas .sidebar .divider { | |||
height: 1px; | |||
overflow: hidden; | |||
background-color: #ebeff2; | |||
background-color: #EBEFF2; | |||
width: 100%; | |||
margin: 0px; | |||
} | |||
@@ -52,7 +52,7 @@ body { | |||
.offcanvas .sidebar .dropdown-menu > li > a:focus, | |||
.offcanvas .sidebar .sidebar-menu > li > a:active, | |||
.offcanvas .sidebar .dropdown-menu > li > a:active { | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
@media (max-width: 767px) { | |||
.page-content { | |||
@@ -124,7 +124,7 @@ body { | |||
} | |||
.offcanvas .sidebar-label { | |||
text-transform: uppercase; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
font-size: 85%; | |||
margin: 0px; | |||
font-weight: bold; | |||
@@ -175,7 +175,7 @@ body { | |||
background-color: rgba(255, 255, 255, 0.9); | |||
} | |||
.navbar .navbar-search-icon { | |||
color: #6c7680; | |||
color: #6C7680; | |||
font-size: inherit; | |||
position: relative; | |||
right: 24px; | |||
@@ -194,7 +194,7 @@ body { | |||
} | |||
.navbar-center { | |||
float: left; | |||
color: #6c7680; | |||
color: #6C7680; | |||
} | |||
#navbar-breadcrumbs > li > a:before { | |||
font-family: FontAwesome; | |||
@@ -211,12 +211,12 @@ body { | |||
top: 3px; | |||
content: "\f105"; | |||
margin-right: 10px; | |||
color: #c0c9d2; | |||
color: #C0C9D2; | |||
} | |||
#navbar-breadcrumbs > li > a:hover:before, | |||
#navbar-breadcrumbs > li > a:focus:before, | |||
#navbar-breadcrumbs > li > a:active:before { | |||
color: #36414c; | |||
color: #36414C; | |||
} | |||
#navbar-breadcrumbs > li > a { | |||
padding: 6px 15px 10px 0px; | |||
@@ -245,7 +245,7 @@ body { | |||
} | |||
.breadcrumb { | |||
line-height: 1.5em; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
background-color: transparent; | |||
margin-bottom: 10px; | |||
padding: 0px; | |||
@@ -261,7 +261,7 @@ a, | |||
a:hover, | |||
a:focus, | |||
a:visited { | |||
color: #5e64ff; | |||
color: #5E64FF; | |||
} | |||
a.btn-primary { | |||
color: #fff; | |||
@@ -296,7 +296,7 @@ h2 { | |||
border-top: 1px solid #d1d8dd; | |||
} | |||
.docs-footer a { | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
} | |||
.docs-footer li { | |||
display: inline-block; | |||
@@ -312,7 +312,7 @@ h2 { | |||
font-weight: 400; | |||
} | |||
.jumbotron p { | |||
font-color: #8d99a6 !important; | |||
font-color: #8D99A6 !important; | |||
} | |||
.browser-image { | |||
min-height: 300px; | |||
@@ -22,7 +22,7 @@ | |||
.form-clickable-section { | |||
border-top: 1px solid #d1d8dd; | |||
padding: 10px 15px; | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
} | |||
.form-page.second-page { | |||
border-top: 1px solid #d1d8dd; | |||
@@ -56,7 +56,7 @@ | |||
} | |||
.form-section:not(:last-child), | |||
.form-inner-toolbar { | |||
border-bottom: 1px solid #ebeff2; | |||
border-bottom: 1px solid #EBEFF2; | |||
} | |||
.empty-section { | |||
display: none !important; | |||
@@ -125,7 +125,7 @@ | |||
} | |||
.control-label, | |||
.grid-heading-row { | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
font-size: 12px; | |||
} | |||
.control-label { | |||
@@ -186,7 +186,7 @@ select.form-control { | |||
margin-top: -3px; | |||
margin-left: 1px; | |||
font-weight: 500; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
} | |||
@media (min-width: 768px) { | |||
.layout-main .form-column.col-sm-12 > form > .input-max-width { | |||
@@ -208,7 +208,7 @@ select.form-control { | |||
padding: 15px 15px 15px 0px; | |||
} | |||
.form-column { | |||
border-bottom: 1px solid #ebeff2; | |||
border-bottom: 1px solid #EBEFF2; | |||
} | |||
.form-column:last-child { | |||
border-bottom: 0px; | |||
@@ -229,7 +229,7 @@ select.form-control { | |||
} | |||
.form-page .frappe-control { | |||
padding: 7px 15px; | |||
border-bottom: 1px solid #ebeff2; | |||
border-bottom: 1px solid #EBEFF2; | |||
margin: 0px -15px; | |||
} | |||
.form-page .frappe-control .link-btn { | |||
@@ -4,7 +4,7 @@ | |||
} | |||
.grid-heading-row { | |||
border-bottom: 1px solid #d1d8dd; | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
font-weight: bold; | |||
} | |||
.grid-row { | |||
@@ -31,7 +31,7 @@ | |||
.fn-gantt .rightPanel .month, | |||
.fn-gantt .rightPanel .year, | |||
.fn-gantt .bottom { | |||
background-color: #f7fafc !important; | |||
background-color: #F7FAFC !important; | |||
} | |||
.fn-gantt .today { | |||
background-color: #D9F6FF !important; | |||
@@ -22,7 +22,7 @@ | |||
} | |||
.indicator.grey::before, | |||
.indicator-right.grey::after { | |||
background: #f0f4f7; | |||
background: #F0F4F7; | |||
} | |||
.indicator.blue::before, | |||
.indicator-right.blue::after { | |||
@@ -20,7 +20,7 @@ | |||
.set-filters .btn-group .btn-default { | |||
background-color: transparent; | |||
border: 1px solid #d1d8dd; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
} | |||
.filter-box { | |||
border-top: 1px solid #d1d8dd; | |||
@@ -61,18 +61,18 @@ | |||
margin-bottom: 0px; | |||
} | |||
.list-row-head { | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
border-bottom: 1px solid #d1d8dd !important; | |||
} | |||
.list-row:hover, | |||
.grid-row:hover { | |||
background: #f7fafc; | |||
background: #F7FAFC; | |||
} | |||
.list-row:last-child { | |||
border-bottom: 0px; | |||
} | |||
.list-row-head { | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
border-bottom: 1px solid #d1d8dd !important; | |||
} | |||
.list-row .h6 { | |||
@@ -38,7 +38,7 @@ body { | |||
.offcanvas .sidebar .divider { | |||
height: 1px; | |||
overflow: hidden; | |||
background-color: #ebeff2; | |||
background-color: #EBEFF2; | |||
width: 100%; | |||
margin: 0px; | |||
} | |||
@@ -52,7 +52,7 @@ body { | |||
.offcanvas .sidebar .dropdown-menu > li > a:focus, | |||
.offcanvas .sidebar .sidebar-menu > li > a:active, | |||
.offcanvas .sidebar .dropdown-menu > li > a:active { | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
@media (max-width: 991px) { | |||
input[type='checkbox'] { | |||
@@ -133,7 +133,7 @@ body { | |||
#navbar-breadcrumbs > li > a:before { | |||
content: "\f104"; | |||
margin-right: 10px; | |||
color: #6c7680; | |||
color: #6C7680; | |||
} | |||
#navbar-breadcrumbs li:not(:nth-last-child(-n+1)) { | |||
display: none; | |||
@@ -204,7 +204,7 @@ body { | |||
} | |||
.sidebar .navbar-search-icon { | |||
float: right; | |||
color: #6c7680; | |||
color: #6C7680; | |||
font-size: inherit; | |||
position: relative; | |||
right: 7px; | |||
@@ -232,7 +232,7 @@ body { | |||
} | |||
.sidebar .user-menu, | |||
.sidebar .user-menu .octicon { | |||
color: #6c7680; | |||
color: #6C7680; | |||
} | |||
.sidebar .user-menu img { | |||
margin-top: -1px; | |||
@@ -266,12 +266,12 @@ body { | |||
top: 3px; | |||
content: "\f104"; | |||
margin-right: 10px; | |||
color: #6c7680; | |||
color: #6C7680; | |||
} | |||
body.no-breadcrumbs .navbar .navbar-home:hover:before, | |||
body.no-breadcrumbs .navbar .navbar-home:focus:before, | |||
body.no-breadcrumbs .navbar .navbar-home:active:before { | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
} | |||
body[data-route=""] .navbar .navbar-home, | |||
body[data-route="desktop"] .navbar .navbar-home { | |||
@@ -18,7 +18,7 @@ | |||
} | |||
.module-item:hover, | |||
.module-item:focus { | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
} | |||
.module-item:last-child { | |||
border: none; | |||
@@ -42,7 +42,7 @@ | |||
background-color: rgba(255, 255, 255, 0.9); | |||
} | |||
.navbar .navbar-search-icon { | |||
color: #6c7680; | |||
color: #6C7680; | |||
font-size: inherit; | |||
position: relative; | |||
right: 24px; | |||
@@ -61,7 +61,7 @@ | |||
} | |||
.navbar-center { | |||
float: left; | |||
color: #6c7680; | |||
color: #6C7680; | |||
} | |||
#navbar-breadcrumbs > li > a:before { | |||
font-family: FontAwesome; | |||
@@ -78,12 +78,12 @@ | |||
top: 3px; | |||
content: "\f105"; | |||
margin-right: 10px; | |||
color: #c0c9d2; | |||
color: #C0C9D2; | |||
} | |||
#navbar-breadcrumbs > li > a:hover:before, | |||
#navbar-breadcrumbs > li > a:focus:before, | |||
#navbar-breadcrumbs > li > a:active:before { | |||
color: #36414c; | |||
color: #36414C; | |||
} | |||
#navbar-breadcrumbs > li > a { | |||
padding: 6px 15px 10px 0px; | |||
@@ -38,7 +38,7 @@ body { | |||
.offcanvas .sidebar .divider { | |||
height: 1px; | |||
overflow: hidden; | |||
background-color: #ebeff2; | |||
background-color: #EBEFF2; | |||
width: 100%; | |||
margin: 0px; | |||
} | |||
@@ -52,7 +52,7 @@ body { | |||
.offcanvas .sidebar .dropdown-menu > li > a:focus, | |||
.offcanvas .sidebar .sidebar-menu > li > a:active, | |||
.offcanvas .sidebar .dropdown-menu > li > a:active { | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
@media (max-width: 767px) { | |||
.page-content { | |||
@@ -124,7 +124,7 @@ body { | |||
} | |||
.offcanvas .sidebar-label { | |||
text-transform: uppercase; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
font-size: 85%; | |||
margin: 0px; | |||
font-weight: bold; | |||
@@ -38,7 +38,7 @@ body { | |||
.offcanvas .sidebar .divider { | |||
height: 1px; | |||
overflow: hidden; | |||
background-color: #ebeff2; | |||
background-color: #EBEFF2; | |||
width: 100%; | |||
margin: 0px; | |||
} | |||
@@ -52,5 +52,5 @@ body { | |||
.offcanvas .sidebar .dropdown-menu > li > a:focus, | |||
.offcanvas .sidebar .sidebar-menu > li > a:active, | |||
.offcanvas .sidebar .dropdown-menu > li > a:active { | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} |
@@ -38,7 +38,7 @@ body { | |||
.offcanvas .sidebar .divider { | |||
height: 1px; | |||
overflow: hidden; | |||
background-color: #ebeff2; | |||
background-color: #EBEFF2; | |||
width: 100%; | |||
margin: 0px; | |||
} | |||
@@ -52,7 +52,7 @@ body { | |||
.offcanvas .sidebar .dropdown-menu > li > a:focus, | |||
.offcanvas .sidebar .sidebar-menu > li > a:active, | |||
.offcanvas .sidebar .dropdown-menu > li > a:active { | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
.hide-form-sidebar .form-sidebar { | |||
display: none !important; | |||
@@ -108,7 +108,7 @@ body[data-route^="Module"] .main-menu .form-sidebar { | |||
.sidebar-menu h6, | |||
.sidebar-menu .h6 { | |||
text-transform: uppercase; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
font-size: 10px; | |||
margin-top: 0px; | |||
} | |||
@@ -122,7 +122,7 @@ body[data-route^="Module"] .main-menu .form-sidebar { | |||
} | |||
.form-sidebar .form-tags input { | |||
font-size: 12px !important; | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
font-style: italic; | |||
} | |||
.form-sidebar .form-tags .tagit-new { | |||
@@ -137,34 +137,39 @@ body[data-route^="Module"] .main-menu .form-sidebar { | |||
.form-sidebar .attachment-row a.close { | |||
margin-top: -5px; | |||
} | |||
.form-sidebar .form-shared .share-doc-btn { | |||
.form-sidebar .form-shared .share-doc-btn, | |||
.form-sidebar .form-viewers .share-doc-btn { | |||
cursor: pointer; | |||
} | |||
.form-sidebar .form-shared .octicon { | |||
.form-sidebar .form-shared .octicon, | |||
.form-sidebar .form-viewers .octicon { | |||
position: relative; | |||
top: 2px; | |||
left: 7px; | |||
} | |||
.form-sidebar .form-shared .avatar { | |||
.form-sidebar .form-shared .avatar, | |||
.form-sidebar .form-viewers .avatar { | |||
margin-top: 5px; | |||
} | |||
.form-sidebar .form-shared .shared-with-everyone { | |||
.form-sidebar .form-shared .shared-with-everyone, | |||
.form-sidebar .form-viewers .shared-with-everyone { | |||
border-style: solid; | |||
border-color: #f0f4f7; | |||
background-color: #f0f4f7; | |||
border-color: #F0F4F7; | |||
background-color: #F0F4F7; | |||
} | |||
.form-sidebar .form-shared .shared-with-everyone .octicon { | |||
color: #36414c !important; | |||
.form-sidebar .form-shared .shared-with-everyone .octicon, | |||
.form-sidebar .form-viewers .shared-with-everyone .octicon { | |||
color: #36414C !important; | |||
} | |||
.form-sidebar .form-shared .share-doc-btn:hover, | |||
.form-sidebar .form-shared .share-doc-btn:focus, | |||
.form-sidebar .form-shared .share-doc-btn:active { | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
.form-sidebar .form-shared .share-doc-btn:hover .octicon-plus, | |||
.form-sidebar .form-shared .share-doc-btn:focus .octicon-plus, | |||
.form-sidebar .form-shared .share-doc-btn:active .octicon-plus { | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
} | |||
.sidebar-left .form-sidebar .form-tags, | |||
.sidebar-left .form-sidebar .assignment-row, | |||
@@ -172,20 +177,24 @@ body[data-route^="Module"] .main-menu .form-sidebar { | |||
.sidebar-left .form-sidebar .modified-by, | |||
.sidebar-left .form-sidebar .created-by, | |||
.sidebar-left .form-sidebar .tags-label, | |||
.sidebar-left .form-sidebar .shared-with-label { | |||
.sidebar-left .form-sidebar .shared-with-label, | |||
.sidebar-left .form-sidebar .form-viewers, | |||
.sidebar-left .form-sidebar .viewers-label { | |||
padding: 12px 14px; | |||
} | |||
.sidebar-left .form-sidebar .assigned-to-label, | |||
.sidebar-left .form-sidebar .attachments-label, | |||
.sidebar-left .form-sidebar .tags-label, | |||
.sidebar-left .form-sidebar .shared-with-label { | |||
.sidebar-left .form-sidebar .shared-with-label, | |||
.sidebar-left .form-sidebar .viewers-label { | |||
padding: 12px 14px; | |||
margin-bottom: 0px; | |||
} | |||
.sidebar-left .form-sidebar .assigned-to-label, | |||
.sidebar-left .form-sidebar .tags-label, | |||
.sidebar-left .form-sidebar .attachments-label.has-attachments, | |||
.sidebar-left .form-sidebar .shared-with-label { | |||
.sidebar-left .form-sidebar .shared-with-label, | |||
.sidebar-left .form-sidebar .viewers-label { | |||
padding-bottom: 0px; | |||
} | |||
.sidebar-left .form-sidebar a.close { | |||
@@ -13,7 +13,7 @@ | |||
border-bottom: 1px solid #d1d8dd; | |||
} | |||
.slick-headerrow-column { | |||
background-color: #f7fafc !important; | |||
background-color: #F7FAFC !important; | |||
text-overflow: clip; | |||
} | |||
.slick-headerrow-column input { | |||
@@ -37,9 +37,9 @@ | |||
.slick-header-columns { | |||
font-size: 12px; | |||
font-weight: bold; | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
border-color: #d1d8dd !important; | |||
color: #8d99a6 !important; | |||
color: #8D99A6 !important; | |||
} | |||
.slick-header-column:hover, | |||
.slick-header-column-active { | |||
@@ -15,7 +15,7 @@ ul.tree-children { | |||
color: #5e64ff !important; | |||
} | |||
.tree-hover { | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
min-height: 20px; | |||
border: 1px solid #d1d8dd; | |||
} | |||
@@ -18,10 +18,10 @@ p { | |||
margin: 10px 0px; | |||
} | |||
.text-color { | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
} | |||
.text-muted { | |||
color: #8d99a6 !important; | |||
color: #8D99A6 !important; | |||
} | |||
.text-extra-muted { | |||
color: #d1d8dd !important; | |||
@@ -82,7 +82,7 @@ a.text-extra-muted { | |||
} | |||
kbd { | |||
color: inherit; | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
.btn [class^="icon-"], | |||
.nav [class^="icon-"], | |||
@@ -186,7 +186,7 @@ a.badge-hover:active .badge { | |||
transform: translate(-50%, -50%); | |||
-webkit-transform: translate(-50%, -50%); | |||
text-align: center; | |||
color: #36414c !important; | |||
color: #36414C !important; | |||
} | |||
#freeze.dark { | |||
background-color: #334143; | |||
@@ -288,7 +288,7 @@ a.no-decoration:active { | |||
} | |||
.indicator.grey::before, | |||
.indicator-right.grey::after { | |||
background: #f0f4f7; | |||
background: #F0F4F7; | |||
} | |||
.indicator.blue::before, | |||
.indicator-right.blue::after { | |||
@@ -339,7 +339,7 @@ a.no-decoration:active { | |||
background-color: #fafbfc; | |||
} | |||
.panel-bg { | |||
background-color: #f7fafc; | |||
background-color: #F7FAFC; | |||
} | |||
.navbar-bg { | |||
background-color: #f5f7fa; | |||
@@ -463,7 +463,7 @@ fieldset { | |||
margin: 0px; | |||
padding: 5px 0px; | |||
border: none; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
font-size: 12px; | |||
} | |||
.page-sidebar .sidebar-item:first-child { | |||
@@ -473,7 +473,7 @@ fieldset { | |||
padding-bottom: 10px; | |||
} | |||
.page-sidebar .sidebar-item a { | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
} | |||
.page-sidebar .sidebar-item a:hover { | |||
border-color: inherit; | |||
@@ -499,7 +499,7 @@ fieldset { | |||
} | |||
.web-list-item { | |||
padding: 15px 0px; | |||
border-bottom: 1px solid #ebeff2; | |||
border-bottom: 1px solid #EBEFF2; | |||
} | |||
.web-list-item h1, | |||
.web-list-item h2, | |||
@@ -609,7 +609,7 @@ a.active { | |||
color: inherit; | |||
} | |||
.breadcrumb > .active { | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
} | |||
.post:last-child { | |||
border-bottom: none; | |||
@@ -662,7 +662,7 @@ body { | |||
.offcanvas .sidebar .divider { | |||
height: 1px; | |||
overflow: hidden; | |||
background-color: #ebeff2; | |||
background-color: #EBEFF2; | |||
width: 100%; | |||
margin: 0px; | |||
} | |||
@@ -676,7 +676,7 @@ body { | |||
.offcanvas .sidebar .dropdown-menu > li > a:focus, | |||
.offcanvas .sidebar .sidebar-menu > li > a:active, | |||
.offcanvas .sidebar .dropdown-menu > li > a:active { | |||
background-color: #f0f4f7; | |||
background-color: #F0F4F7; | |||
} | |||
@media (max-width: 767px) { | |||
.page-content { | |||
@@ -748,7 +748,7 @@ body { | |||
} | |||
.offcanvas .sidebar-label { | |||
text-transform: uppercase; | |||
color: #8d99a6; | |||
color: #8D99A6; | |||
font-size: 85%; | |||
margin: 0px; | |||
font-weight: bold; | |||
@@ -39,6 +39,11 @@ | |||
<li class="h6 shared-with-label">{%= __("Shared With") %}</li> | |||
<li class="form-shared"></li> | |||
</ul> | |||
<ul class="list-unstyled sidebar-menu"> | |||
<li class="divider"></li> | |||
<li class="h6 viewers-label">{%= __("Currently Viewing") %}</li> | |||
<li class="form-viewers"></li> | |||
</ul> | |||
<ul class="list-unstyled sidebar-menu text-muted"> | |||
<li class="modified-by"></li> | |||
<li class="created-by"></li> | |||
@@ -0,0 +1,76 @@ | |||
frappe.provide("frappe.ui.form"); | |||
frappe.ui.form.Viewers = Class.extend({ | |||
init: function(opts) { | |||
$.extend(this, opts); | |||
}, | |||
refresh: function(data_updated) { | |||
var me = this; | |||
this.parent.empty(); | |||
var viewers = this.frm.get_docinfo().viewers || {}; | |||
var users = []; | |||
var new_users = []; | |||
for (var i=0, l=(viewers.current || []).length; i < l; i++) { | |||
var username = viewers.current[i]; | |||
if (username===user) { | |||
// current user | |||
continue; | |||
} | |||
var user_info = frappe.user_info(username); | |||
users.push({ | |||
image: user_info.image, | |||
fullname: user_info.fullname, | |||
title: __("{0} is currently viewing this document", [user_info.fullname]) | |||
}); | |||
if (viewers.new.indexOf(username)!==-1) { | |||
new_users.push(user_info.fullname); | |||
} | |||
} | |||
if (users.length) { | |||
this.parent.parent().removeClass("hidden"); | |||
this.parent.append(frappe.render_template("users_in_sidebar", {"users": users})); | |||
} else { | |||
this.parent.parent().addClass("hidden"); | |||
} | |||
if (data_updated && new_users.length) { | |||
// new user viewing this document, who wasn't viewing in the past | |||
if (new_users.length===1) { | |||
show_alert(__("{0} is currently viewing this document", [new_users[0]])); | |||
} else { | |||
show_alert(__("{0} are currently viewing this document", [frappe.utils.comma_and(new_users)])); | |||
} | |||
} | |||
} | |||
}); | |||
frappe.ui.form.set_viewers = function(data) { | |||
var doctype = data.doctype; | |||
var docname = data.docname; | |||
var past_viewers = (frappe.model.get_docinfo(doctype, docname).viewers || {}).past || []; | |||
var new_viewers = []; | |||
var viewers = data.viewers || []; | |||
for (i=0, l=viewers.length; i < l; i++) { | |||
var username = viewers[i]; | |||
if (past_viewers.indexOf(username)===-1) { | |||
new_viewers.push(username); | |||
} | |||
} | |||
frappe.model.set_docinfo(doctype, docname, "viewers", { | |||
past: past_viewers.concat(new_viewers), | |||
new: new_viewers, | |||
current: viewers | |||
}); | |||
if (cur_frm.doc && cur_frm.doc.doctype===doctype && cur_frm.doc.name==docname) { | |||
cur_frm.viewers.refresh(true); | |||
} | |||
} |
@@ -8,44 +8,45 @@ frappe.ui.form.Share = Class.extend({ | |||
$.extend(this, opts); | |||
}, | |||
refresh: function() { | |||
this.render_sidebar(); | |||
}, | |||
render_sidebar: function() { | |||
var me = this; | |||
this.parent.empty(); | |||
var everyone = null; | |||
var shared = $.map(this.shared || this.frm.get_docinfo().shared, function(s) { | |||
var shared = this.shared || this.frm.get_docinfo().shared; | |||
var users = []; | |||
for (var i=0, l=shared.length; i < l; i++) { | |||
var s = shared[i]; | |||
if (s.everyone) { | |||
everyone = s; | |||
users.push({ | |||
icon: "octicon octicon-megaphone text-muted", | |||
avatar_class: "avatar-empty share-doc-btn shared-with-everyone", | |||
title: __("Shared with everyone") | |||
}); | |||
} else { | |||
var user_info = frappe.user_info(s.user); | |||
users.push({ | |||
image: user_info.image, | |||
fullname: user_info.fullname, | |||
title: __("Shared with {0}", [user_info.fullname]) | |||
}); | |||
} | |||
return s ? s.user : null; | |||
}); | |||
if (everyone) { | |||
$(repl('<span><a class="avatar avatar-small avatar-empty share-doc-btn shared-with-everyone" title="%(title)s">\ | |||
<i class="octicon octicon-megaphone text-muted"></i></a></span>', {title: __("Shared with everyone")})) | |||
.appendTo(this.parent) | |||
.on("click", function() { me.frm.share_doc(); }); | |||
} | |||
for(var i=0; i<shared.length; i++) { | |||
var user_info = frappe.user_info(shared[i]); | |||
$(repl('<span class="avatar avatar-small" title="' | |||
+__("Shared with {0}", [user_info.fullname])+'">\ | |||
<img class="media-object" src="%(image)s" alt="%(fullname)s"></span>', | |||
{image: user_info.image, fullname: user_info.fullname})) | |||
.appendTo(this.parent) | |||
.on("click", function() { me.frm.share_doc(); }); | |||
} | |||
// share | |||
if(!me.frm.doc.__islocal) { | |||
$(repl('<span><a class="avatar avatar-small avatar-empty share-doc-btn" title="%(title)s">\ | |||
<i class="octicon octicon-plus text-muted"></i></a></span>', {title: __("Share")})) | |||
.appendTo(this.parent) | |||
.on("click", function() { me.frm.share_doc(); }); | |||
if (!me.frm.doc.__islocal) { | |||
users.push({ | |||
icon: "octicon octicon-plus text-muted", | |||
avatar_class: "avatar-empty share-doc-btn", | |||
title: __("Share") | |||
}); | |||
} | |||
this.parent.append(frappe.render_template("users_in_sidebar", {"users": users})); | |||
this.parent.find(".avatar").on("click", function() { | |||
me.frm.share_doc(); | |||
}); | |||
}, | |||
show: function() { | |||
var me = this; | |||
@@ -20,6 +20,7 @@ frappe.ui.form.Sidebar = Class.extend({ | |||
this.make_assignments(); | |||
this.make_attachments(); | |||
this.make_shared(); | |||
this.make_viewers(); | |||
this.make_tags(); | |||
this.bind_events(); | |||
@@ -46,6 +47,7 @@ frappe.ui.form.Sidebar = Class.extend({ | |||
this.frm.assign_to.refresh(); | |||
this.frm.attachments.refresh(); | |||
this.frm.shared.refresh(); | |||
this.frm.viewers.refresh(); | |||
this.frm.tags && this.frm.tags.refresh(this.frm.doc._user_tags); | |||
this.sidebar.find(".modified-by").html(__("{0} edited this {1}", | |||
["<strong>" + frappe.user.full_name(this.frm.doc.modified_by) + "</strong>", | |||
@@ -97,6 +99,12 @@ frappe.ui.form.Sidebar = Class.extend({ | |||
parent: this.sidebar.find(".form-shared") | |||
}); | |||
}, | |||
make_viewers: function() { | |||
this.frm.viewers = new frappe.ui.form.Viewers({ | |||
frm: this.frm, | |||
parent: this.sidebar.find(".form-viewers") | |||
}); | |||
}, | |||
add_user_action: function(label, click) { | |||
return $('<a>').html(label).appendTo($('<li class="user-action-row">') | |||
.appendTo(this.user_actions.removeClass("hide"))).on("click", click); | |||
@@ -0,0 +1,11 @@ | |||
{% for (var i=0, l=users.length; i < l; i++) { | |||
var u = users[i]; | |||
%} | |||
<span class="avatar avatar-small {{ u.avatar_class || "" }}" title="{{ u.title }}"> | |||
{% if (u.icon) { %} | |||
<i class="{{ u.icon }}"></i> | |||
{% } else { %} | |||
<img class="media-object" src="{{ u.image }}" alt="{{ u.fullname }}"> | |||
{% } %} | |||
</span> | |||
{% } %} |
@@ -153,6 +153,12 @@ $.extend(frappe.model, { | |||
return frappe.model.docinfo[doctype] && frappe.model.docinfo[doctype][name] || null; | |||
}, | |||
set_docinfo: function(doctype, name, key, value) { | |||
if (frappe.model.docinfo[doctype] && frappe.model.docinfo[doctype][name]) { | |||
frappe.model.docinfo[doctype][name][key] = value; | |||
} | |||
}, | |||
new_comment: function(comment) { | |||
var reference_doctype = comment.comment_doctype || comment.reference_doctype; | |||
var reference_name = comment.comment_docname || comment.reference_name; | |||
@@ -42,9 +42,21 @@ frappe.socket = { | |||
frappe.socket.doc_subscribe(frm.doctype, frm.docname); | |||
}); | |||
// $(document).on('form-unload', function(e, frm) { | |||
// frappe.socket.doc_unsubscribe(frm.doctype, frm.docname); | |||
// }); | |||
$(document).on("form_refresh", function(e, frm) { | |||
frappe.socket.doc_open(frm.doctype, frm.docname); | |||
}); | |||
$(document).on('form-unload', function(e, frm) { | |||
// frappe.socket.doc_unsubscribe(frm.doctype, frm.docname); | |||
frappe.socket.doc_close(frm.doctype, frm.docname); | |||
}); | |||
window.onbeforeunload = function() { | |||
// if tab/window is closed, notify other users | |||
if (cur_frm && cur_frm.doc) { | |||
frappe.socket.doc_close(cur_frm.doctype, cur_frm.docname); | |||
} | |||
} | |||
}, | |||
get_host: function() { | |||
var host = frappe.urllib.get_base_url(); | |||
@@ -77,6 +89,14 @@ frappe.socket = { | |||
} | |||
}) | |||
}, | |||
doc_open: function(doctype, docname) { | |||
// notify that the user has opened this doc | |||
frappe.socket.socket.emit('doc_open', doctype, docname); | |||
}, | |||
doc_close: function(doctype, docname) { | |||
// notify that the user has closed this doc | |||
frappe.socket.socket.emit('doc_close', doctype, docname); | |||
}, | |||
setup_listeners: function() { | |||
frappe.socket.socket.on('task_status_change', function(data) { | |||
frappe.socket.process_response(data, data.status.toLowerCase()); | |||
@@ -88,16 +108,25 @@ frappe.socket = { | |||
setup_reconnect: function() { | |||
// subscribe again to open_tasks | |||
frappe.socket.socket.on("connect", function() { | |||
$.each(frappe.socket.open_tasks, function(task_id, opts) { | |||
frappe.socket.subscribe(task_id, opts); | |||
}); | |||
// re-connect open docs | |||
$.each(frappe.socket.open_docs, function(d) { | |||
if(locals[d.doctype] && locals[d.doctype][d.name]) { | |||
frappe.socket.doc_subscribe(d.doctype, d.name); | |||
// wait for 5 seconds before subscribing again | |||
// because it takes more time to start python server than nodejs server | |||
// and we use validation requests to python server for subscribing | |||
setTimeout(function() { | |||
$.each(frappe.socket.open_tasks, function(task_id, opts) { | |||
frappe.socket.subscribe(task_id, opts); | |||
}); | |||
// re-connect open docs | |||
$.each(frappe.socket.open_docs, function(d) { | |||
if(locals[d.doctype] && locals[d.doctype][d.name]) { | |||
frappe.socket.doc_subscribe(d.doctype, d.name); | |||
} | |||
}); | |||
if (cur_frm && cur_frm.doc) { | |||
frappe.socket.doc_open(cur_frm.doc.doctype, cur_frm.doc.name); | |||
} | |||
}) | |||
}, 5000); | |||
}); | |||
}, | |||
@@ -136,3 +165,9 @@ frappe.realtime.on = function(event, callback) { | |||
frappe.socket.socket.on(event, callback); | |||
} | |||
} | |||
frappe.realtime.publish = function(event, message) { | |||
if(frappe.socket.socket) { | |||
frappe.socket.socket.emit(event, message); | |||
} | |||
} |
@@ -29,6 +29,9 @@ frappe.views.FormFactory = frappe.views.Factory.extend({ | |||
frappe.model.new_comment(data); | |||
}); | |||
frappe.realtime.on("doc_viewers", function(data) { | |||
frappe.ui.form.set_viewers(data); | |||
}); | |||
} | |||
@@ -445,7 +445,7 @@ _f.Frm.prototype.render_form = function(is_a_different_doc) { | |||
// trigger global trigger | |||
// to use this | |||
$(document).trigger('form_refresh'); | |||
$(document).trigger('form_refresh', [this]); | |||
// fields | |||
this.refresh_fields(); | |||
@@ -115,7 +115,7 @@ body[data-route^="Module"] .main-menu { | |||
margin-top: -5px; | |||
} | |||
.form-shared { | |||
.form-shared, .form-viewers { | |||
.share-doc-btn { | |||
cursor: pointer; | |||
} | |||
@@ -161,14 +161,17 @@ body[data-route^="Module"] .main-menu { | |||
.modified-by, | |||
.created-by, | |||
.tags-label, | |||
.shared-with-label { | |||
.shared-with-label, | |||
.form-viewers, | |||
.viewers-label { | |||
.sidebar-padding; | |||
} | |||
.assigned-to-label, | |||
.attachments-label, | |||
.tags-label, | |||
.shared-with-label { | |||
.shared-with-label, | |||
.viewers-label { | |||
.sidebar-padding; | |||
margin-bottom: 0px; | |||
} | |||
@@ -176,7 +179,8 @@ body[data-route^="Module"] .main-menu { | |||
.assigned-to-label, | |||
.tags-label, | |||
.attachments-label.has-attachments, | |||
.shared-with-label { | |||
.shared-with-label, | |||
.viewers-label { | |||
padding-bottom: 0px; | |||
} | |||
@@ -6,7 +6,6 @@ var fs = require('fs'); | |||
var redis = require("redis") | |||
var subscriber = redis.createClient(12311); | |||
var r = redis.createClient(12311); | |||
var request = require('superagent') | |||
var default_site; | |||
@@ -31,6 +30,9 @@ io.on('connection', function(socket){ | |||
if(!sid) { | |||
return; | |||
} | |||
socket.user = cookie.parse(socket.request.headers.cookie).user_id; | |||
// console.log("firing get_user_info"); | |||
request.get(get_url(socket, '/api/method/frappe.async.get_user_info')) | |||
.type('form') | |||
@@ -63,25 +65,17 @@ io.on('connection', function(socket){ | |||
socket.on('doc_subscribe', function(doctype, docname) { | |||
// console.log('trying to subscribe', doctype, docname) | |||
request.get(get_url(socket, '/api/method/frappe.async.can_subscribe_doc')) | |||
.type('form') | |||
.send({ | |||
sid: sid, | |||
doctype: doctype, | |||
docname: docname | |||
}) | |||
.end(function(err, res) { | |||
if(err) console.log(err); | |||
if(!res) { | |||
console.log("No response for doc_subscribe"); | |||
return; | |||
} | |||
if(res.status == 200) { | |||
var room = get_doc_room(socket, doctype, docname); | |||
// console.log('joining', room) | |||
socket.join(room); | |||
} | |||
}) | |||
can_subscribe_doc({ | |||
socket: socket, | |||
sid: sid, | |||
doctype: doctype, | |||
docname: docname, | |||
callback: function(err, res) { | |||
var room = get_doc_room(socket, doctype, docname); | |||
// console.log('joining', room) | |||
socket.join(room); | |||
} | |||
}); | |||
}); | |||
socket.on('doc_unsubscribe', function(doctype, docname) { | |||
@@ -89,13 +83,45 @@ io.on('connection', function(socket){ | |||
socket.leave(room); | |||
}); | |||
socket.on('doc_open', function(doctype, docname) { | |||
// show who is currently viewing the form | |||
can_subscribe_doc({ | |||
socket: socket, | |||
sid: sid, | |||
doctype: doctype, | |||
docname: docname, | |||
callback: function(err, res) { | |||
var room = get_open_doc_room(socket, doctype, docname); | |||
// console.log('joining', room) | |||
socket.join(room); | |||
send_viewers({ | |||
socket: socket, | |||
doctype: doctype, | |||
docname: docname, | |||
}); | |||
} | |||
}); | |||
}); | |||
socket.on('doc_close', function(doctype, docname) { | |||
// remove this user from the list of 'who is currently viewing the form' | |||
var room = get_open_doc_room(socket, doctype, docname); | |||
socket.leave(room); | |||
send_viewers({ | |||
socket: socket, | |||
doctype: doctype, | |||
docname: docname, | |||
}); | |||
}); | |||
// socket.on('disconnect', function (arguments) { | |||
// console.log("user disconnected", arguments); | |||
// }); | |||
}); | |||
function send_existing_lines(task_id, socket) { | |||
r.hgetall('task_log:' + task_id, function(err, lines) { | |||
subscriber.hgetall('task_log:' + task_id, function(err, lines) { | |||
socket.emit('task_progress', { | |||
"task_id": task_id, | |||
"message": { | |||
@@ -122,6 +148,10 @@ function get_doc_room(socket, doctype, docname) { | |||
return get_site_name(socket) + ':doc:'+ doctype + '/' + docname; | |||
} | |||
function get_open_doc_room(socket, doctype, docname) { | |||
return get_site_name(socket) + ':open_doc:'+ doctype + '/' + docname; | |||
} | |||
function get_user_room(socket, user) { | |||
return get_site_name(socket) + ':user:' + user; | |||
} | |||
@@ -159,3 +189,52 @@ function get_url(socket, path) { | |||
} | |||
return socket.request.headers.origin + path; | |||
} | |||
function can_subscribe_doc(args) { | |||
request.get(get_url(args.socket, '/api/method/frappe.async.can_subscribe_doc')) | |||
.type('form') | |||
.send({ | |||
sid: args.sid, | |||
doctype: args.doctype, | |||
docname: args.docname | |||
}) | |||
.end(function(err, res) { | |||
if(err) console.log(err); | |||
if(!res) { | |||
console.log("No response for doc_subscribe"); | |||
return; | |||
} | |||
if(res.status == 200) { | |||
args.callback(err, res); | |||
} | |||
}); | |||
} | |||
function send_viewers(args) { | |||
// send to doc room, 'users currently viewing this document' | |||
if (!(args && args.doctype && args.docname)) { | |||
return; | |||
} | |||
// open doc room | |||
var room = get_open_doc_room(args.socket, args.doctype, args.docname); | |||
// socket ids connected to this room | |||
var clients = Object.keys(io.sockets.adapter.rooms[room] || {}); | |||
var viewers = []; | |||
for (var i in io.sockets.sockets) { | |||
var s = io.sockets.sockets[i]; | |||
if (clients.indexOf(s.id)!==-1) { | |||
// this socket is connected to the room | |||
viewers.push(s.user); | |||
} | |||
} | |||
// notify | |||
io.to(room).emit("doc_viewers", { | |||
doctype: args.doctype, | |||
docname: args.docname, | |||
viewers: viewers | |||
}); | |||
} |