Commit 8a145c24 authored by Vladimir Baranov's avatar Vladimir Baranov

1.2.0

parents 8b2dfb8c 35cdd5d4
.pyc .pyc
.pyo .pyo
.nvmrc
logs/* logs/*
!.gitkeep !.gitkeep
tmp tmp
...@@ -109,4 +110,4 @@ sync ...@@ -109,4 +110,4 @@ sync
*.rdb *.rdb
api-docs/ api-docs/
api-docs-source/ api-docs-source/
\ No newline at end of file
.pyc
.pyo
logs/*
!.gitkeep
tmp
node_modules/
.idea
bower_components/
!dist/bower_components/
# Thanks to Octocat https://gist.github.com/octocat/9257657
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Python Specific from github
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
# Distribution / packaging
.Python
env/
build/
develop-eggs/
#dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Sphinx documentation
docs/_build/
# PyBuilder
target/
coverage/
sync
*.rdb
api-docs/
api-docs-source/
\ No newline at end of file
...@@ -82,7 +82,7 @@ module.exports = function (grunt) { ...@@ -82,7 +82,7 @@ module.exports = function (grunt) {
{expand: true, cwd: 'app/styles/images/', src: '*', dest: 'dist/css/images/', flatten: true}, {expand: true, cwd: 'app/styles/images/', src: '*', dest: 'dist/css/images/', flatten: true},
{expand: true, cwd: 'app/bower_components/bootstrap/dist/fonts/', src: '*', dest: 'dist/fonts/', flatten: true, filter: 'isFile'}, {expand: true, cwd: 'app/bower_components/bootstrap/dist/fonts/', src: '*', dest: 'dist/fonts/', flatten: true, filter: 'isFile'},
{expand: true, cwd: 'app/bower_components/jquery/dist/', src: 'jquery.min.js', dest: 'dist/bower_components/', flatten: true, filter: 'isFile'}, {expand: true, cwd: 'app/bower_components/jquery/dist/', src: 'jquery.min.js', dest: 'dist/bower_components/', flatten: true, filter: 'isFile'},
{expand: true, cwd: 'app/bower_components/angular/', src: 'angular.min.js', dest: 'dist/bower_components/', flatten: true, filter: 'isFile'} {expand: true, cwd: 'app/bower_components/angular/', src: 'angular.js', dest: 'dist/bower_components/', flatten: true, filter: 'isFile'}
] ]
}, },
local_prod: { local_prod: {
...@@ -124,19 +124,28 @@ module.exports = function (grunt) { ...@@ -124,19 +124,28 @@ module.exports = function (grunt) {
"app/zetalib/interceptors.js", "app/zetalib/interceptors.js",
"app/zetalib/general.js", "app/zetalib/general.js",
"app/zetalib/form_service.js", "app/zetalib/form_service.js",
"app/zetalib/form_constraints.js",
"app/zetalib/error_service.js",
"app/zetalib/action_service.js",
"app/zetalib/socket.js",
"app/zetalib/utils_service.js",
"app/shared/directives.js", "app/shared/directives.js",
"app/components/auth/auth_controller.js", "app/components/auth/auth_controller.js",
"app/components/auth/auth_service.js", "app/components/auth/auth_service.js",
"app/components/dashboard/dashboard_controller.js", "app/components/dashboard/dashboard_controller.js",
"app/components/crud/crud_controller.js", "app/components/crud/crud_controller.js",
"app/components/crud/crud_widgets.js",
"app/components/debug/debug_controller.js", "app/components/debug/debug_controller.js",
"app/components/devSettings/devSettings_controller.js", "app/components/devSettings/devSettings_controller.js",
"app/components/error_pages/error_controller.js", "app/components/error_pages/error_controller.js",
"app/components/wf/wf_controller.js", "app/components/wf/wf_controller.js",
"app/components/version/version.js", "app/components/version/version.js",
"app/components/version/interpolate-filter.js", "app/components/version/interpolate-filter.js",
"app/components/version/version-directive.js" "app/components/version/version-directive.js",
"app/components/messaging/messaging_service.js",
"app/components/messaging/messaging.js"
], ],
nonull: true,
dest: 'dist/app.js' dest: 'dist/app.js'
}, },
components: { components: {
...@@ -148,6 +157,8 @@ module.exports = function (grunt) { ...@@ -148,6 +157,8 @@ module.exports = function (grunt) {
"app/bower_components/angular-resource/angular-resource.js", "app/bower_components/angular-resource/angular-resource.js",
"app/bower_components/angular-bootstrap/ui-bootstrap.js", "app/bower_components/angular-bootstrap/ui-bootstrap.js",
"app/bower_components/angular-bootstrap/ui-bootstrap-tpls.js", "app/bower_components/angular-bootstrap/ui-bootstrap-tpls.js",
"app/bower_components/showdown/dist/showdown.min.js",
"app/bower_components/angular-markdown-filter/markdown.js",
"app/bower_components/angular-sanitize/angular-sanitize.js", "app/bower_components/angular-sanitize/angular-sanitize.js",
"app/bower_components/tv4/tv4.js", "app/bower_components/tv4/tv4.js",
"app/bower_components/objectpath/lib/ObjectPath.js", "app/bower_components/objectpath/lib/ObjectPath.js",
...@@ -159,7 +170,8 @@ module.exports = function (grunt) { ...@@ -159,7 +170,8 @@ module.exports = function (grunt) {
"app/bower_components/metisMenu/dist/metisMenu.js", "app/bower_components/metisMenu/dist/metisMenu.js",
"app/bower_components/Chart.js/Chart.js", "app/bower_components/Chart.js/Chart.js",
"app/bower_components/intro.js/intro.js", "app/bower_components/intro.js/intro.js",
"app/bower_components/moment/min/moment.min.js" "app/bower_components/moment/min/moment.min.js",
"app/bower_components/toastr/toastr.min.js"
], ],
dest: 'dist/bower_components/components.js' dest: 'dist/bower_components/components.js'
}, },
...@@ -173,7 +185,8 @@ module.exports = function (grunt) { ...@@ -173,7 +185,8 @@ module.exports = function (grunt) {
"app/bower_components/angular-loading-bar/build/loading-bar.min.css", "app/bower_components/angular-loading-bar/build/loading-bar.min.css",
"app/bower_components/font-awesome/css/font-awesome.min.css", "app/bower_components/font-awesome/css/font-awesome.min.css",
"app/bower_components/intro.js/intro.css", "app/bower_components/intro.js/intro.css",
"app/bower_components/intro.js/themes/introjs-nassim.css" "app/bower_components/intro.js/themes/introjs-nassim.css",
"app/bower_components/toastr/toastr.min.css"
] ]
} }
}, },
...@@ -187,7 +200,9 @@ module.exports = function (grunt) { ...@@ -187,7 +200,9 @@ module.exports = function (grunt) {
'app/shared/scripts/theme.js', 'app/shared/scripts/theme.js',
'app/shared/directives.js', 'app/shared/directives.js',
'app/components/**/*controller.js', 'app/components/**/*controller.js',
'app/components/**/*service.js' 'app/components/**/*service.js',
"app/components/messaging/messaging_service.js",
"app/components/messaging/messaging.js"
], ],
dest: 'dist/<%= grunt.branchname %>/app.js' dest: 'dist/<%= grunt.branchname %>/app.js'
}, },
...@@ -311,7 +326,7 @@ module.exports = function (grunt) { ...@@ -311,7 +326,7 @@ module.exports = function (grunt) {
dev: { dev: {
files: { files: {
'app/index.html': 'app/main.html', 'app/index.html': 'app/main.html',
'app/app.js': 'app/main.js', 'app/app.js': 'app/main.js'
} }
}, },
prod: { prod: {
...@@ -417,4 +432,4 @@ module.exports = function (grunt) { ...@@ -417,4 +432,4 @@ module.exports = function (grunt) {
'uglify:branch' 'uglify:branch'
]); ]);
}); });
}; };
\ No newline at end of file
0.7.2 1.2.0
\ No newline at end of file
/* line 1, styles/app.less */
* {
box-sizing: border-box;
}
/* line 5, styles/app.less */
body,
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 12px;
height: 100%;
max-height: 100%;
padding: 0;
margin: 0;
}
/* line 18, styles/app.less */
a:link {
text-decoration: none;
}
/* line 22, styles/app.less */
.content {
position: relative;
width: 100%;
height: 100%;
}
/* line 27, styles/app.less */
.content > .message {
width: 100%;
height: 100%;
text-align: center;
display: table;
font-size: 16px;
color: #111;
}
/* line 36, styles/app.less */
.content > .message .note {
vertical-align: middle;
text-align: center;
display: table-cell;
}
/* line 43, styles/app.less */
.content > .message .error .details {
max-width: 500px;
font-size: 12px;
margin: 20px auto;
text-align: left;
}
/* line 50, styles/app.less */
.content > .message .error pre {
border: solid 1px #CCC;
background: #EEE;
padding: 10px;
}
/* line 57, styles/app.less */
.content:not(.with-error) .error,
.content.with-error .intro,
.content.with-diagram .intro {
display: none;
}
/* line 63, styles/app.less */
.content .canvas {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
/* line 71, styles/app.less */
.content .canvas,
.content.with-error .canvas {
visibility: hidden;
}
/* line 76, styles/app.less */
.content.with-diagram .canvas {
visibility: visible;
}
/* line 82, styles/app.less */
.buttons {
position: fixed;
bottom: 20px;
left: 20px;
padding: 0;
margin: 0;
list-style: none;
}
/* line 91, styles/app.less */
.buttons > li {
display: inline-block;
margin-right: 10px;
}
/* line 95, styles/app.less */
.buttons > li > a {
background: #DDD;
border: solid 1px #666;
display: inline-block;
padding: 5px;
}
/* line 103, styles/app.less */
.buttons a {
opacity: 0.3;
}
/* line 107, styles/app.less */
.buttons a.active {
opacity: 1.0;
}
/* line 112, styles/app.less */
#js-properties-panel {
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 260px;
z-index: 10;
border-left: 1px solid #ccc;
overflow: auto;
}
/* line 121, styles/app.less */
#js-properties-panel:empty {
display: none;
}
/* line 124, styles/app.less */
#js-properties-panel > .djs-properties-panel {
padding-bottom: 70px;
min-height: 100%;
}
@font-face {
font-family: 'bpmn-js-pp';
src: url("data:;base64,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");
src: url("data:;base64,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") format('embedded-opentype'), url("data:application/font-woff;base64,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") format('woff'), url("data:application/x-font-ttf;base64,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IDxZIyAuRrACJUZQWCA8WS6xKwEUKy2wPiywNSsjIC5GsAIlRlJYIDxZLrErARQrLbA/LLA2K4ogIDywBCNCijgjIC5GsAIlRlJYIDxZLrErARQrsARDLrArKy2wQCywABawBCWwBCYgLkcjRyNhsAlDKyMgPCAuIzixKwEUKy2wQSyxCAQlQrAAFrAEJbAEJSAuRyNHI2EgsAQjQrAJQysgsGBQWCCwQFFYswIgAyAbswImAxpZQkIjIEewBEOwAmIgsABQWLBAYFlmsAFjYCCwASsgiophILACQ2BkI7ADQ2FkUFiwAkNhG7ADQ2BZsAMlsAJiILAAUFiwQGBZZrABY2GwAiVGYTgjIDwjOBshICBGI0ewASsjYTghWbErARQrLbBCLLA1Ky6xKwEUKy2wQyywNishIyAgPLAEI0IjOLErARQrsARDLrArKy2wRCywABUgR7AAI0KyAAEBFRQTLrAxKi2wRSywABUgR7AAI0KyAAEBFRQTLrAxKi2wRiyxAAEUE7AyKi2wRyywNCotsEgssAAWRSMgLiBGiiNhOLErARQrLbBJLLAII0KwSCstsEossgAAQSstsEsssgABQSstsEwssgEAQSstsE0ssgEBQSstsE4ssgAAQistsE8ssgABQistsFAssgEAQistsFEssgEBQistsFIssgAAPistsFMssgABPistsFQssgEAPistsFUssgEBPistsFYssgAAQCstsFcssgABQCstsFgssgEAQCstsFkssgEBQCstsFossgAAQystsFsssgABQystsFwssgEAQystsF0ssgEBQystsF4ssgAAPystsF8ssgABPystsGAssgEAPystsGEssgEBPystsGIssDcrLrErARQrLbBjLLA3K7A7Ky2wZCywNyuwPCstsGUssAAWsDcrsD0rLbBmLLA4Ky6xKwEUKy2wZyywOCuwOystsGgssDgrsDwrLbBpLLA4K7A9Ky2waiywOSsusSsBFCstsGsssDkrsDsrLbBsLLA5K7A8Ky2wbSywOSuwPSstsG4ssDorLrErARQrLbBvLLA6K7A7Ky2wcCywOiuwPCstsHEssDorsD0rLbByLLMJBAIDRVghGyMhWUIrsAhlsAMkUHiwARUwLQBLuADIUlixAQGOWbABuQgACABjcLEABUKxAAAqsQAFQrEACCqxAAVCsQAIKrEABUK5AAAACSqxAAVCuQAAAAkqsQMARLEkAYhRWLBAiFixA2REsSYBiFFYugiAAAEEQIhjVFixAwBEWVlZWbEADCq4Af+FsASNsQIARAA=") format('truetype'), url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxtZXRhZGF0YT5Db3B5cmlnaHQgKEMpIDIwMTYgYnkgb3JpZ2luYWwgYXV0aG9ycyBAIGZvbnRlbGxvLmNvbTwvbWV0YWRhdGE+CjxkZWZzPgo8Zm9udCBpZD0iYnBtbi1pby1wcCIgaG9yaXotYWR2LXg9IjEwMDAiID4KPGZvbnQtZmFjZSBmb250LWZhbWlseT0iYnBtbi1pby1wcCIgZm9udC13ZWlnaHQ9IjQwMCIgZm9udC1zdHJldGNoPSJub3JtYWwiIHVuaXRzLXBlci1lbT0iMTAwMCIgYXNjZW50PSI4NTAiIGRlc2NlbnQ9Ii0xNTAiIC8+CjxtaXNzaW5nLWdseXBoIGhvcml6LWFkdi14PSIxMDAwIiAvPgo8Z2x5cGggZ2x5cGgtbmFtZT0iY2xlYXIiIHVuaWNvZGU9IiYjeGU4MDI7IiBkPSJNNDUyIDE5NHExOC0xOCAxOC00M3QtMTgtNDNxLTE4LTE2LTQzLTE2dC00MyAxNmwtMTMyIDE1Mi0xMzItMTUycS0xOC0xNi00My0xNnQtNDMgMTZxLTE2IDE4LTE2IDQzdDE2IDQzbDEzOCAxNTYtMTM4IDE1OHEtMTYgMTgtMTYgNDN0MTYgNDNxMTggMTYgNDMgMTZ0NDMtMTZsMTMyLTE1MiAxMzIgMTUycTE4IDE2IDQzIDE2dDQzLTE2cTE4LTE4IDE4LTQzdC0xOC00M2wtMTM4LTE1OHoiIGhvcml6LWFkdi14PSI0NzAiIC8+CjxnbHlwaCBnbHlwaC1uYW1lPSJhZGQiIHVuaWNvZGU9IiYjeGU4MDM7IiBkPSJNNTUwIDQwMHEzMCAwIDMwLTUwdC0zMC01MGwtMjEwIDAgMC0yMTBxMC0zMC01MC0zMHQtNTAgMzBsMCAyMTAtMjEwIDBxLTMwIDAtMzAgNTB0MzAgNTBsMjEwIDAgMCAyMTBxMCAzMCA1MCAzMHQ1MC0zMGwwLTIxMCAyMTAgMHoiIGhvcml6LWFkdi14PSI1ODAiIC8+CjxnbHlwaCBnbHlwaC1uYW1lPSJzZWFyY2giIHVuaWNvZGU9IiYjeGU4MDU7IiBkPSJNNzcyIDc4cTMwLTM0IDYtNjJsLTQ2LTQ2cS0zNi0zMi02OCAwbC0xOTAgMTkwcS03NC00Mi0xNTYtNDItMTI4IDAtMjIzIDk1dC05NSAyMjMgOTAgMjE5IDIxOCA5MSAyMjQtOTUgOTYtMjIzcTAtODgtNDYtMTYyeiBtLTY3OCAzNThxMC04OCA2OC0xNTZ0MTU2LTY4IDE1MSA2MyA2MyAxNTNxMCA4OC02OCAxNTV0LTE1NiA2Ny0xNTEtNjMtNjMtMTUxeiIgaG9yaXotYWR2LXg9Ijc4OSIgLz4KPGdseXBoIGdseXBoLW5hbWU9ImF0dGVudGlvbiIgdW5pY29kZT0iJiN4ZTgwNjsiIGQ9Ik05NTctMjRxMTAtMTYgMC0zNC0xMC0xNi0zMC0xNmwtODkyIDBxLTE4IDAtMjggMTYtMTMgMTgtMiAzNGw0NDYgNzgycTggMTggMzAgMTh0MzAtMTh6IG0tNDIwIDUwbDAgMTAwLTExMCAwIDAtMTAwIDExMCAweiBtMCAxNzRsMCAzMDAtMTEwIDAgMC0zMDAgMTEwIDB6IiBob3Jpei1hZHYteD0iOTYyIiAvPgo8Z2x5cGggZ2x5cGgtbmFtZT0iY2xlYXItY2lyY2xlZCIgdW5pY29kZT0iJiN4ZTkwMjsiIGQ9Ik00MjAgNzcwcTE3NCAwIDI5Ny0xMjN0MTIzLTI5Ny0xMjMtMjk3LTI5Ny0xMjMtMjk3IDEyMy0xMjMgMjk3IDEyMyAyOTcgMjk3IDEyM3ogbTg2LTQyMGwxNTQgMTU0LTg2IDg2LTE1NC0xNTItMTUyIDE1Mi04OC04NiAxNTQtMTU0LTE1NC0xNTIgODgtODYgMTUyIDE1MiAxNTQtMTUyIDg2IDg2eiIgaG9yaXotYWR2LXg9Ijg0MCIgLz4KPGdseXBoIGdseXBoLW5hbWU9ImFkZC1jaXJjbGVkIiB1bmljb2RlPSImI3hlOTAzOyIgZD0iTTQyMCA3NzBxMTc0IDAgMjk3LTEyM3QxMjMtMjk3LTEyMy0yOTctMjk3LTEyMy0yOTcgMTIzLTEyMyAyOTcgMTIzIDI5NyAyOTcgMTIzeiBtNTItNDcwbDIwMCAwIDAgMTAyLTIwMCAwIDAgMjAyLTEwMiAwIDAtMjAyLTIwMiAwIDAtMTAyIDIwMiAwIDAtMjAyIDEwMiAwIDAgMjAyeiIgaG9yaXotYWR2LXg9Ijg0MCIgLz4KPC9mb250Pgo8L2RlZnM+Cjwvc3ZnPg==") format('svg');
font-weight: normal;
font-style: normal;
}
/* line 16, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel {
background-color: #f8f8f8;
position: relative;
}
/* line 20, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel:empty {
display: none;
}
/* line 24, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel label,
.djs-properties-panel input {
vertical-align: middle;
}
/* line 30, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel input,
.djs-properties-panel button,
.djs-properties-panel textarea {
padding: 3px 6px;
border: 1px solid #ccc;
}
/* line 36, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel input:focus,
.djs-properties-panel button:focus,
.djs-properties-panel textarea:focus {
outline: none;
border-color: #52B415;
box-shadow: 0 0 1px 2px rgba(82, 180, 21, 0.2);
}
/* line 40, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel input.invalid,
.djs-properties-panel button.invalid,
.djs-properties-panel textarea.invalid {
border-color: #cc3333;
background: #f0c2c2;
}
/* line 42, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel input.invalid:focus,
.djs-properties-panel button.invalid:focus,
.djs-properties-panel textarea.invalid:focus {
box-shadow: 0 0 1px 2px rgba(204, 51, 51, 0.2);
}
/* line 49, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel [type=text],
.djs-properties-panel textarea,
.djs-properties-panel select {
width: 100%;
}
/* line 55, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel textarea {
resize: vertical;
}
/* line 59, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel label {
font-weight: bolder;
display: inline-block;
vertical-align: middle;
color: #666;
}
/* line 71, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel label[for] {
cursor: pointer;
}
/* line 74, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel label.pp-hidden {
display: none;
}
/* line 63, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel .entry-label {
font-weight: bolder;
display: inline-block;
vertical-align: middle;
color: #666;
font-size: 120%;
margin-top: 5px;
margin-bottom: 10px;
transition: margin 0.218s linear;
font-style: italic;
}
/* line 71, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel .entry-label[for] {
cursor: pointer;
}
/* line 74, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel .entry-label.pp-hidden {
display: none;
}
/* line 71, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel .entry-label.divider {
border-top: 1px dotted #ccc;
padding-top: 8px;
margin-top: 16px;
width: 100%;
}
/* line 79, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-panel button {
position: absolute;
top: 0;
height: 23px;
width: 24px;
overflow: hidden;
cursor: pointer;
background-color: #f8f8f8;
border: 1px solid #ccc;
}
/* line 44, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel button > span {
display: none;
}
/* line 48, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel button:before {
font-family: "bpmn-js-pp";
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
text-align: center;
font-variant: normal;
text-transform: none;
line-height: 1em;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
position: relative;
}
/* line 53, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel button.add:before {
content: '\E803';
}
/* line 57, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel button.clear:before {
content: '\E802';
}
/* line 61, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-panel button:hover {
color: #52B415;
}
/* line 84, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-error-message,
.pp-error-message.pp-entry-link {
color: #cc3333;
}
/* line 89, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-row {
margin-top: 10px;
margin-bottom: 10px;
}
/* line 92, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-row:first-of-type {
margin-top: 0;
}
/* line 95, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-row:last-of-type {
margin-bottom: 0;
}
/* line 100, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-textfield,
.pp-textarea {
margin-bottom: 3px;
}
/* line 105, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-radios-group {
list-style: none;
padding: 0;
margin: 0 0 9px 0;
}
/* line 110, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-radios-group .pp-radio-wrapper {
margin: 6px 0;
}
/* line 114, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-radios-group input,
.pp-radios-group label {
vertical-align: middle;
}
/* line 119, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-radios-group input {
margin-top: 0;
margin-left: 0;
}
/* line 127, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-radios-group input,
.pp-checkbox input {
margin-left: 0;
}
/* line 132, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-radios-group label:after,
.pp-checkbox label:after {
display: none;
}
/* line 139, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-textfield input {
padding-right: 28px;
}
/* line 143, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-textfield .clear {
background: transparent;
border: none;
top: 0;
right: 0;
}
/* line 151, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-combo-input {
margin-top: 7px;
}
/* line 156, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-select select {
height: 23px;
}
/* line 159, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-select button.add {
top: -22px;
right: 0;
}
/* line 169, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-select button.add,
.pp-element-list button.add,
.pp-select button.clear,
.pp-element-list button.clear {
top: -23px;
border-bottom: none;
}
/* line 176, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-select button.add,
.pp-element-list button.add {
right: 0px;
}
/* line 180, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-select button.clear,
.pp-element-list button.clear {
right: 23px;
}
/* line 185, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-entry {
margin-bottom: 9px;
}
/* line 187, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-entry .pp-field-wrapper {
position: relative;
}
/* line 192, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-hidden {
display: none;
}
/* line 196, node_modules/bpmn-js-properties-panel/styles/properties.less */
label.pp-hidden {
display: none;
}
/* line 201, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-add-row > button {
position: relative;
margin-left: 10px;
}
/* line 207, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table {
margin-top: 10px;
}
/* line 211, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row {
margin-bottom: 2px;
overflow: hidden;
}
/* line 215, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row > input,
.pp-table-row > button {
float: left;
}
/* line 220, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row > label {
padding-left: 5px;
}
/* line 227, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row > label.pp-table-row-columns-1,
.pp-table-row > input.pp-table-row-columns-1 {
width: 100%;
}
/* line 229, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row > label.pp-table-row-columns-1.pp-table-row-removable,
.pp-table-row > input.pp-table-row-columns-1.pp-table-row-removable {
width: calc(100% - 24px);
}
/* line 234, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row > label.pp-table-row-columns-2,
.pp-table-row > input.pp-table-row-columns-2 {
width: 50%;
}
/* line 236, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row > label.pp-table-row-columns-2.pp-table-row-removable,
.pp-table-row > input.pp-table-row-columns-2.pp-table-row-removable {
width: calc(50% - 12px);
}
/* line 239, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row > label.pp-table-row-columns-2:nth-child(2),
.pp-table-row > input.pp-table-row-columns-2:nth-child(2) {
border-left: none;
}
/* line 245, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-table-row > button {
border-left: none;
position: static;
}
/* line 251, node_modules/bpmn-js-properties-panel/styles/properties.less */
.djs-properties-static {
margin-bottom: 0;
margin-top: 0;
border: 1px solid #ccc;
background-color: white;
padding: 3px 6px;
font: 13.3333px Arial;
width: 100%;
}
/* line 261, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-entry-link {
cursor: pointer;
color: #52B415;
}
/* line 266, node_modules/bpmn-js-properties-panel/styles/properties.less */
.pp-icon-warning:before {
font-family: "bpmn-js-pp";
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
text-align: center;
font-variant: normal;
text-transform: none;
line-height: 1em;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
content: '\E806';
}
/* line 1, node_modules/bpmn-js-properties-panel/styles/header.less */
.djs-properties-header {
padding: 15px;
padding-bottom: 5px;
}
/* line 5, node_modules/bpmn-js-properties-panel/styles/header.less */
.djs-properties-header > .label {
font-size: 120%;
font-weight: bolder;
}
/* line 10, node_modules/bpmn-js-properties-panel/styles/header.less */
.djs-properties-header > .search {
display: none;
margin-top: 5px;
position: relative;
}
/* line 15, node_modules/bpmn-js-properties-panel/styles/header.less */
.djs-properties-header > .search input {
position: relative;
border-radius: 15px;
width: 100%;
z-index: 1;
}
/* line 22, node_modules/bpmn-js-properties-panel/styles/header.less */
.djs-properties-header > .search button {
position: absolute;
top: 0;
bottom: 0;
right: 0;
border: none;
background-color: transparent;
z-index: 2;
}
/* line 30, node_modules/bpmn-js-properties-panel/styles/header.less */
.djs-properties-header > .search button:before {
content: '\E805';
}
/* line 1, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group {
padding: 6px 15px 6px 15px;
position: relative;
max-height: 2000px;
overflow: hidden;
transition: max-height 0.218s ease-in-out, padding-top 0.218s ease-in-out, padding-bottom 0.218s ease-in-out;
}
/* line 10, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group:empty {
display: none;
}
/* line 14, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group > .group-toggle {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 4px;
cursor: pointer;
transition: background-color 0.218s linear;
}
/* line 22, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group > .group-toggle:hover {
background-color: #8fc071;
}
/* line 27, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group > .group-label {
font-weight: bolder;
display: inline-block;
vertical-align: middle;
color: #666;
font-size: 120%;
margin-top: 5px;
margin-bottom: 10px;
transition: margin 0.218s linear;
font-style: italic;
}
/* line 71, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-group > .group-label[for] {
cursor: pointer;
}
/* line 74, node_modules/bpmn-js-properties-panel/styles/_mixins.less */
.djs-properties-group > .group-label.pp-hidden {
display: none;
}
/* line 36, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group:hover > .group-toggle {
background-color: #ccc;
}
/* line 38, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group:hover > .group-toggle:hover {
background-color: #8fc071;
}
/* line 43, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group.group-closed {
max-height: 20px;
border-top: none;
cursor: pointer;
background-color: rgba(143, 192, 113, 0.2);
padding-top: 0;
padding-bottom: 0;
}
/* line 51, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group.group-closed > div {
visibility: hidden;
}
/* line 55, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group.group-closed > .group-label {
margin-top: 2px;
margin-bottom: 2px;
}
/* line 60, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group.group-closed:hover > .group-label {
color: #52B415;
}
/* line 65, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group + .djs-properties-group {
border-top: 1px dotted #ccc;
}
/* line 69, node_modules/bpmn-js-properties-panel/styles/groups.less */
.djs-properties-group:last-child {
padding-bottom: 9px;
}
/* line 2, node_modules/bpmn-js-properties-panel/styles/listeners.less */
.cam-add-listener > button {
position: relative;
margin-left: 10px;
}
/* line 8, node_modules/bpmn-js-properties-panel/styles/listeners.less */
[data-list-entry-container] > .djs-listener-area {
border: 1px solid #ccc;
margin: 10px 1px;
padding: 10px;
}
/* line 14, node_modules/bpmn-js-properties-panel/styles/listeners.less */
.djs-listener-area {
position: relative;
}
/* line 16, node_modules/bpmn-js-properties-panel/styles/listeners.less */
.djs-listener-area > button {
position: absolute;
right: 0;
top: 0;
border: none;
background: none;
}
/* line 25, node_modules/bpmn-js-properties-panel/styles/listeners.less */
.djs-listener-area + .djs-listener-area {
margin-top: 20px;
}
/* line 1, node_modules/bpmn-js-properties-panel/styles/tabs.less */
.djs-properties-tab-bar {
border-bottom: 1px solid #ccc;
padding: 0 15px;
}
/* line 5, node_modules/bpmn-js-properties-panel/styles/tabs.less */
.djs-properties-tab-bar .scroll-tabs-button {
cursor: pointer;
font-size: 16px;
padding: 3px 4px 3px 4px;
color: #666;
}
/* line 11, node_modules/bpmn-js-properties-panel/styles/tabs.less */
.djs-properties-tab-bar .scroll-tabs-button:hover {
font-weight: bold;
}
/* line 15, node_modules/bpmn-js-properties-panel/styles/tabs.less */
.djs-properties-tab-bar .scroll-tabs-button.scroll-tabs-left {
float: left;
margin-left: -15px;
}
/* line 20, node_modules/bpmn-js-properties-panel/styles/tabs.less */
.djs-properties-tab-bar .scroll-tabs-button.scroll-tabs-right {
float: right;
margin-right: -15px;
}
/* line 27, node_modules/bpmn-js-properties-panel/styles/tabs.less */
.djs-properties-tab-bar:not(.scroll-tabs-overflow) .scroll-tabs-button {
display: none;
}
/* line 33, node_modules/bpmn-js-properties-panel/styles/tabs.less */
ul.djs-properties-tabs-links {
margin: 5px 0 -1px 0;
padding: 0;
white-space: nowrap;
overflow: hidden;
}
/* line 39, node_modules/bpmn-js-properties-panel/styles/tabs.less */
ul.djs-properties-tabs-links > li {
display: inline-block;
margin: 0;
}
/* line 43, node_modules/bpmn-js-properties-panel/styles/tabs.less */
ul.djs-properties-tabs-links > li.pp-hidden {
display: none;
}
/* line 47, node_modules/bpmn-js-properties-panel/styles/tabs.less */
ul.djs-properties-tabs-links > li > a {
display: inline-block;
font-size: 12px;
padding: 4px 7px;
border: 1px solid #ccc;
border-radius: 3px 3px 0 0;
border-bottom: transparent;
background-color: #f8f8f8;
color: #666;
text-decoration: none;
}
/* line 62, node_modules/bpmn-js-properties-panel/styles/tabs.less */
ul.djs-properties-tabs-links > li > a:hover {
color: #4d4d4d;
}
/* line 68, node_modules/bpmn-js-properties-panel/styles/tabs.less */
ul.djs-properties-tabs-links > li + li {
margin-left: 4px;
}
/* line 74, node_modules/bpmn-js-properties-panel/styles/tabs.less */
ul.djs-properties-tabs-links > li.pp-active a {
padding-bottom: 5px;
border-top: 2px solid #52B415;
border-bottom: none;
}
/* line 83, node_modules/bpmn-js-properties-panel/styles/tabs.less */
.djs-properties-tab,
.djs-properties-tab.pp-hidden {
display: none;
}
/* line 88, node_modules/bpmn-js-properties-panel/styles/tabs.less */
.djs-properties-tab.pp-active {
display: block;
}
/**
* outline styles
*/
.djs-outline {
fill: none;
visibility: hidden;
}
.djs-element.hover .djs-outline,
.djs-element.selected .djs-outline {
visibility: visible;
shape-rendering: crispEdges;
stroke-dasharray: 3,3;
}
.djs-element.selected .djs-outline {
stroke: #8888FF;
stroke-width: 1px;
}
.djs-element.hover .djs-outline {
stroke: #FF8888;
stroke-width: 1px;
}
.djs-shape.connect-ok .djs-visual > :nth-child(1) {
fill: #DCFECC /* light-green */ !important;
}
.djs-shape.connect-not-ok .djs-visual > :nth-child(1),
.djs-shape.drop-not-ok .djs-visual > :nth-child(1) {
fill: #f9dee5 /* light-red */ !important;
}
.djs-shape.new-parent .djs-visual > :nth-child(1) {
fill: #F7F9FF !important;
}
svg.drop-not-ok {
background: #f9dee5 /* light-red */ !important;
}
svg.new-parent {
background: #F7F9FF /* light-blue */ !important;
}
.djs-connection.connect-ok .djs-visual > :nth-child(1),
.djs-connection.drop-ok .djs-visual > :nth-child(1) {
stroke: #90DD5F /* light-green */ !important;
}
.djs-connection.connect-not-ok .djs-visual > :nth-child(1),
.djs-connection.drop-not-ok .djs-visual > :nth-child(1) {
stroke: #E56283 /* light-red */ !important;
}
.drop-not-ok,
.connect-not-ok {
cursor: not-allowed;
}
.djs-element.attach-ok .djs-visual > :nth-child(1) {
stroke-width: 5px !important;
stroke: rgba(255, 116, 0, 0.7);
}
/**
* Selection box style
*
*/
.djs-lasso-overlay {
fill: rgb(255, 116, 0);
fill-opacity: 0.1;
stroke-dasharray: 5 1 3 1;
stroke: rgb(255, 116, 0);
shape-rendering: crispEdges;
pointer-events: none;
}
/**
* Resize styles
*/
.djs-resize-overlay {
fill: white;
fill-opacity: 0.8;
stroke-dasharray: 5 1 3 1;
stroke: rgb(255, 116, 0);
pointer-events: none;
}
.djs-resizer-hit {
fill: none;
pointer-events: all;
}
.djs-resizer-visual {
fill: white;
stroke-width: 1px;
stroke: black;
shape-rendering: crispEdges;
stroke-opacity: 0.2;
}
.djs-cursor-resize-nwse,
.djs-resizer-nw,
.djs-resizer-se {
cursor: nwse-resize;
}
.djs-cursor-resize-nesw,
.djs-resizer-ne,
.djs-resizer-sw {
cursor: nesw-resize;
}
.djs-shape.djs-resizing > .djs-outline {
visibility: hidden !important;
}
.djs-shape.djs-resizing > .djs-resizer {
visibility: hidden;
}
.djs-dragger > .djs-resizer {
visibility: hidden;
}
/**
* drag styles
*/
.djs-dragger {
fill: white;
fill-opacity: 0.6;
stroke: #333;
}
.djs-dragger .djs-visual > :first-child {
stroke: rgb(255, 116, 0) !important;
}
.djs-dragging {
opacity: 0.3;
}
.djs-dragging,
.djs-dragging > * {
pointer-events: none !important;
}
.djs-dragging .djs-context-pad,
.djs-dragging .djs-outline {
display: none !important;
}
/**
* no pointer events for visual
*/
.djs-visual,
.djs-outline {
pointer-events: none;
}
/**
* all pointer events for hit shape
*/
.djs-shape .djs-hit {
pointer-events: all;
}
.djs-connection .djs-hit {
pointer-events: stroke;
}
/**
* shape / connection basic styles
*/
.djs-connection .djs-visual {
stroke-width: 2px;
fill: none;
}
.djs-cursor-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
cursor: grab;
}
.djs-cursor-grabbing {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
cursor: grabbing;
}
.djs-cursor-crosshair {
cursor: crosshair;
}
.djs-cursor-move {
cursor: move;
}
.djs-cursor-resize-ns {
cursor: ns-resize;
}
.djs-cursor-resize-ew {
cursor: ew-resize;
}
/**
* snapping
*/
.djs-snap-line {
stroke: rgb(255, 195, 66);
stroke: rgba(255, 195, 66, 0.50);
stroke-linecap: round;
stroke-width: 2px;
pointer-events: none;
}
/**
* snapping
*/
.djs-crosshair {
stroke: #555;
stroke-linecap: round;
stroke-width: 1px;
pointer-events: none;
shape-rendering: crispEdges;
stroke-dasharray: 5, 5;
}
/**
* palette
*/
.djs-palette {
position: absolute;
left: 20px;
top: 20px;
}
.djs-palette:not(.open) {
overflow: hidden;
}
.djs-palette .entry,
.djs-palette .djs-palette-toggle {
width: 46px;
height: 46px;
line-height: 46px;
cursor: default;
}
.djs-palette .separator {
margin: 3px 5px 5px 5px;
border: none;
border-top: solid 1px #DDD;
}
.djs-palette .entry:before {
vertical-align: middle;
}
.djs-palette .djs-palette-toggle {
cursor: pointer;
}
.djs-palette .entry,
.djs-palette .djs-palette-toggle {
color: #333;
font-size: 30px;
text-align: center;
}
.djs-palette .entry img {
max-width: 100%;
}
.djs-palette.open .djs-palette-toggle {
height: 10px;
}
.djs-palette:not(.open) .djs-palette-entries {
display: none;
}
confirm
.djs-palette .djs-palette-toggle:hover {
background: #666;
}
.djs-palette .entry:hover {
color: rgb(255, 116, 0);
}
.highlighted-entry {
color: rgb(255, 116, 0) !important;
}
confirm
/**
* context-pad
*/
.djs-overlay-context-pad {
width: 72px;
}
.djs-context-pad {
position: absolute;
display: none;
pointer-events: none;
}
.djs-context-pad .entry {
width: 22px;
height: 22px;
text-align: center;
display: inline-block;
font-size: 22px;
margin: 0 2px 2px 0;
border-radius: 3px;
cursor: default;
background-color: #FEFEFE;
box-shadow: 0 0 2px 1px #FEFEFE;
pointer-events: all;
}
.djs-context-pad .entry:before {
vertical-align: top;
}
.djs-context-pad .entry:hover {
background: rgb(255, 252, 176);
}
.djs-context-pad.open {
display: block;
}
/**
* popup styles
*/
.djs-popup .entry {
line-height: 20px;
white-space: nowrap;
border: solid 1px transparent;
cursor: default;
}
/* larger font for prefixed icons */
.djs-popup .entry:before {
vertical-align: middle;
font-size: 20px;
}
.djs-popup .entry > span {
vertical-align: middle;
font-size: 14px;
}
.djs-popup .entry:hover,
.djs-popup .entry.active:hover {
background: rgb(255, 252, 176);
}
.djs-popup .entry.disabled {
background: inherit;
}
.djs-popup .entry.active {
color: rgb(255, 116, 0);
border: solid 1px rgb(255, 116, 0);
border-radius: 3px;
background-color: #F6F6F6;
}
.djs-popup-body .entry {
padding: 2px 10px 2px 5px;
}
.djs-popup-header .entry {
display: inline-block;
padding: 2px 3px 2px 3px;
}
.djs-popup-body .entry > span {
margin-left: 5px;
}
.djs-popup-body {
background-color: #FEFEFE;
}
.djs-popup-header {
border-bottom: 1px solid #DDD;
}
.djs-popup-header .entry {
margin: 1px;
margin-left: 3px;
}
.djs-popup-header .entry:last-child {
margin-right: 3px;
}
/**
* popup / palette styles
*/
.djs-popup, .djs-palette {
background: #FAFAFA;
border: solid 1px #CCC;
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
/**
* touch
*/
.djs-shape,
.djs-connection {
touch-action: none;
}
.djs-segment-dragger,
.djs-bendpoint {
display: none;
}
/**
* bendpoints
*/
.djs-segment-dragger .djs-visual {
fill: rgba(255, 255, 121, 0.2);
stroke-width: 1px;
stroke-opacity: 1;
stroke: rgba(255, 255, 121, 0.3);
}
.djs-bendpoint .djs-visual {
fill: rgba(255, 255, 121, 0.8);
stroke-width: 1px;
stroke-opacity: 0.5;
stroke: black;
}
.djs-segment-dragger:hover,
.djs-bendpoints.hover .djs-segment-dragger,
.djs-bendpoints.selected .djs-segment-dragger,
.djs-bendpoint:hover,
.djs-bendpoints.hover .djs-bendpoint,
.djs-bendpoints.selected .djs-bendpoint {
display: block;
}
.djs-drag-active .djs-bendpoints * {
display: none;
}
.djs-bendpoints:not(.hover) .floating {
display: none;
}
.djs-segment-dragger:hover .djs-visual,
.djs-segment-dragger.djs-dragging .djs-visual,
.djs-bendpoint:hover .djs-visual,
.djs-bendpoint.floating .djs-visual {
fill: yellow;
stroke-opacity: 0.5;
stroke: black;
}
.djs-bendpoint.floating .djs-hit {
pointer-events: none;
}
.djs-segment-dragger .djs-hit,
.djs-bendpoint .djs-hit {
pointer-events: all;
fill: none;
}
.djs-segment-dragger.horizontal .djs-hit {
cursor: ns-resize;
}
.djs-segment-dragger.vertical .djs-hit {
cursor: ew-resize;
}
.djs-segment-dragger.djs-dragging .djs-hit {
pointer-events: none;
}
.djs-updating,
.djs-updating > * {
pointer-events: none !important;
}
.djs-updating .djs-context-pad,
.djs-updating .djs-outline,
.djs-updating .djs-bendpoint,
.connect-ok .djs-bendpoint,
.connect-not-ok .djs-bendpoint,
.drop-ok .djs-bendpoint,
.drop-not-ok .djs-bendpoint {
display: none !important;
}
.djs-segment-dragger.djs-dragging,
.djs-bendpoint.djs-dragging {
display: block;
opacity: 1.0;
}
.djs-segment-dragger.djs-dragging .djs-visual,
.djs-bendpoint.djs-dragging .djs-visual {
fill: yellow;
stroke-opacity: 0.5;
}
/**
* tooltips
*/
.djs-tooltip-error {
font-size: 11px;
line-height: 18px;
text-align: left;
padding: 5px;
opacity: 0.7;
}
.djs-tooltip-error > * {
width: 160px;
background: rgb(252, 236, 240);
color: rgb(158, 76, 76);
padding: 3px 7px;
box-shadow: 0 1px 2px rgba(0,0,0, 0.2);
border-radius: 5px;
border-left: solid 5px rgb(174, 73, 73);
}
.djs-tooltip-error:hover {
opacity: 1;
}
{
"name": "Magic",
"prefix": "magic",
"uri": "http://magic",
"xml": {
"tagAlias": "lowerCase"
},
"associations": [],
"types": [
{
"name": "BewitchedStartEvent",
"extends": [
"bpmn:StartEvent"
],
"properties": [
{
"name": "spell",
"isAttr": true,
"type": "String"
},
]
},
]
}
\ No newline at end of file
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ulakbus İş Akışı Düzenleme Paneli</title>
<link rel="stylesheet" href="css/diagram-js.css"/>
<link rel="stylesheet" href="vendor/bpmn-font/css/bpmn-embedded.css"/>
<link rel="stylesheet" href="css/app.css"/>
<link rel="icon" type="image/png" href="../img/favicon.ico">
<link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../app.css">
<link href="../styles/roboto/roboto.css" rel="stylesheet">
<link rel="stylesheet" href="../bower_components/font-awesome/css/font-awesome.min.css" type="text/css">
</head>
<body>
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0; min-height: 45px;">
<div class="navbar-header">
<div class="brand">
<a href="/#/dashboard" class="logo"><img src="../img/brand-logo.png"/></a>
</div>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- /.navbar-header -->
<header-notification></header-notification>
</nav>
<div class="content" id="js-drop-zone">
<div class="message intro">
<div class="note">
Düzenlemek istediğiniz BPMN diagramını sürükleyip bırakın ya da <a id="js-create-diagram" href>yeni bir BPMN
diagramı oluşturun.</a>
</div>
</div>
<div class="message error">
<div class="note">
<p>BPMN 2.0 diagramı gösterilemiyor.</p>
<div class="details">
<span>Problemin sebebi;</span>
<pre></pre>
</div>
</div>
</div>
<div class="canvas" id="js-canvas"></div>
<div id="js-properties-panel"></div>
</div>
<ul class="buttons">
<li>
<a id="js-save-diagram" href title="download BPMN diagram">
Kaydet
</a>
</li>
<li>
indir
</li>
<li>
<a id="js-download-diagram" href title="download BPMN diagram">
BPMN diagram olarak
</a>
</li>
<li>
<a id="js-download-svg" href title="download as SVG image">
SVG resmi olarak
</a>
</li>
</ul>
<script src="index.js"></script>
</body>
</html>
This source diff could not be displayed because it is too large. You can view the blob instead.
@font-face {
font-family: 'bpmn';
src: url('../font/bpmn.eot?43681877');
src: url('../font/bpmn.eot?43681877#iefix') format('embedded-opentype'),
url('../font/bpmn.svg?43681877#bpmn') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'bpmn';
src: url('data:application/octet-stream;base64,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') format('woff'),
url('data:application/octet-stream;base64,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AQEBAQIIAgECAgQBFgEBBAMMBQkEBgUEAwoCCAECAQICAgcBAQEBAQQDBAj8pwUICAQCAQEBAgYCAgIBBAEGAgoDBAEDBgQFCQQEBAMEAgESAQIBAgECAgIHAgEBAQECBwMFAvAEBQQEAwQCAgcCAwUCBAECAwwKAwQCBAEBBAMEBAkIBQcDDwIBBgUIAQEBBgECAQIBAgICCQECAgMECP2tBAgEAwICAgUGDAYBDAEGBwMBAwMBBwcDAQcHAQMBAwQIBAQMBAQEBAkEBAQFAgEBBAQDFQMECgcZAwoCAwMDAwMDAwIGAwIDAgMCCAGcBQQEAQcKHAsHEgQLBAcEBAcECAQQCAQDAgIBBAQDBAUMBQ0EBQQFCAUmBAkEBAQEBAQBBAMBAwEDBAQIBAkEAgIBAgYDBAX+RAQFBAYCAgECAwMFBAEEDQkBDQEEBQUEAQQFBQoFGQEEARQGBQUFCwoJBQQEAwQBAgMDBAcTBQQFBQQFBQQlHggEBAkMAw0CEgUEBQMBFAQECQgWLAUFBAUFBQQFGwQGBAEBAgMDBAQECQMGBQsFBQUGFAEeBQoFBQQBBAEEBRwNBAEEBQMCAQICAwQIAfr+yAE4MVo+urp9AfIBAQEBBwICBAMEBAQJBAUGAwIJAgEBAQEBAQIFAQIDAwgEBQQJAwMDBwEBAQFTAQICBAcJCQoBCQcGBwMEAwQDBAcIBxQEDQQEIAMDAgICAgMDCAkFBgUFBAEEAQQFHA0EAQgEAQQEBAgBAwEDAQMECAMBAwQDAQYEBwgBBAQBAwQDAQMMAwEDAQMBCAQEBAEEBAQBBA0XBQUEAQQBCQUKBQwEBQQEAwQBAgUHDB4IBAkEFAcIBwQDBAMEAwcGBAMHBQQECQQEAwQBAgIFDAUJBAMGAgEBAQEBAgIHAgIDAgICAQIDAwgFCQgDBQIBAgECAQICAgkCAQEBJwIDBQIEAQIPAwIBAgkMCQEJBAMDAQMDAQMLBwcJCQQDBAQBAQQDDAMEBgMDAgMDAwMDAwIDAwIDAgMCAwIDBAMWAwMICQkHAwQ7AQIDAwQNBQsCAwMDAwMDAgMDCiMDBwMHBA4LAwcDCAMDAgEBAwIECAkEAgQJBAQEBAQFAwEDAQMEAQMQBAMBAwgDAQoBAwMBAwMBAwMBBgQJAQMCAwOpAQQEAwQIBAQJBQQJDQQbBQ0JBAQJ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CAQmBAgDBAQEBwQIAxoDCAcHAwkFBAQEAwQBBAMHAQMFBAQEBAQJBCYECQUEBAUNsQUDBgcBAwgDARUDAQMDAQkBDAEJCQMDAgECAwMIBAEEAgICAwMIBAUECQMIAwIEAwIDAgMCAwIDAwMCAwMDAwMDAwMGAyMCAwQEAgIFBAgFAYQEBAQDAwMBBgMDAgMCAwIDAgMHFgEEAQQBBgMCAgQEAwQFCQQEBAMEAQICAgECAQIBAgICAQEBCAEBAQICBAECBwMCAQIDAgECBgMJAwMDBAn9xwQIAwMCAgECAQEBAQEBAgEIAgEBAQMDBAQEBQkEAwMEAQIFAwIBAQEBAQECAQECAwMJBAKNBQQEAwQCAgcCAwUCBAECAwwKAwQCBAEBBAMEBAkIBQcDDwIBBgUIAQEBBgECAQIBAgICCQECAgMECAX9rgQEBAMCAgIFBgwGAQwBBgcDAQMDAQcHAwEHBwEDAQMECAQEDAQEBAQJBAQEBQIBAQQEAxUDBAoHGQMKAgMDAwMDAwMCBgMCAwIDAggOAaUEBAEHChwLBxIECwQHBAQHBAgEEAgEAwICAQQEAwQFEQ0EBQQFCAUmBAkEBAQEBAQBBAMBAwEDBAQIBAkEAgIBAgYDBAUEpwUGBgsFDAUFBiYGCggEAgMBAQIGBAkEKwUJBQUFBQoFHgUKBQUFBQoEGAkFBAMEBAEBBAMEByYFBgULBgsG7wQFAwQEAgIIAgwHCAcEAwQDBAMHBgcPAgkCAxEEAwQJCQQEAwQBAgMCAQIDAgECEgEJBAYBAwQDAQMIBAMBAwEDAQgEBAQBBAgBBAoI/fQECAUEAQQEBAwEBAQIAwEDBAMEAwQJAQ8CAQIDAwUCAQQDAwECAwMIBAkFBwUFEAYCBgIPBwYHAwQDBAMEBwgEBAcCAQICAwQIBAKvBAgGAgEBAQEBAggCAQICBAEWAQEEAwwFCQQGBQQDCgIIAQIBAgICBwEBAQEBBAMECAT8pgQECAQCAQEBAgYCAgIBBAEGAgoDBAEDBgQFCQQEBAMEAgESAQIBAgECAgIHAgEBAQECBwMFBJQFBAYCAgECAwMFBAEEDQkBDQEEBQUEAQQFBQoFGQEEARQGBQUFCwoJBQQEAwQBAgMDBAcTBQQFBQQFBQQlHggEBAkMAw0NAhoEBQMBFAQECQgWLAUFBAUFBQQFGwQGBAEBAgMDBAQECQMGBQsFBQUGFAEeBQoFBQQBBAEEBRwNBAEEBQMCAQICAwQIBAI0SXd8Wx4VFmqCbRwVJ0lybB4fDld7NCUrMTU2AxoHBQkZMzMG7wECAgUMBQkEAwYCAQEBAQECAgcCAgMCAgIBAgMDCAUJCAMFAgECAQIBAgICCQIBAQEnAQEDBQIEAQIPAwIBAgkMCQEJBAMDAQMDAQMLBwcJCQQDBAQBAQQDDAMEBgMDAgMDAwMDAwIDAwIDAgMCAwIDBAMWAwMICQkHAwQ8AQEDAwQNBQsCAwMDAwMDAgMDCiMDBwMHBA4LAwcDCAMDAgEBAwIECAkEAgQJBAQEBAQFAwEDAQMEAQMQBAMBAwgDAQoBAwMBAwMBAwMBBgQJAQMCAwMCqwEEBAMECAQECQUECQ0EGwUNCQQECQQBBCIEBQEEBAMDAgECAgMECAkFBBIECwQHBAQHBAgEHgQIBAcEBAcEBAkEBAQDBAF3AQIDAwgHBAcEGgMLCwcGBAMHFA8DBwEIBQQFCAMDAgICAgcBAxUBAwsBBxAEBAwEBAQEBAQJBCYFBQgEBAMEoQICAwMECQkJBgEMAQYMBgUDAwIBBAEEAQIFBAICAQEBBAEBAQYBAQECAQECAwcFBAUECAMDCQIBBgMQAwYDAgMCAwIDAgMGAgMDAwMDBwNNAQIBAwYMAwMFAwIBAQEEAwMECQUECAMDAgEBAQECCQICAgECAQIBAQECAgIBAQEEAQEBBQQDBQQFCAgDAgECzgEBAQEHAgIEAwQEBAkEBQYDAgkCAQEBAQEBAgUBAgMDCAQFBAkDAwMHAQEBAVMBAgIEBwkJCgEJBwYHAwQDBAMEBwgHFAQNBAQgAwMCAgICAwMICQUGBQUEAQQBBAUcDQQBCAQBBAQECAEDAQMBAwQIAwEDBAMBBgQHAgoBBAQBAwQDAQMMAwEDAQMBCAQEBAEEBAQBBA0XBQUEAQQBCQUKBQwEBQQEAwQBAgUHDB4IBAkEFAcIBwQDBAMEAwcGBAMHBQQECQQEAwT+xQEECAQEBAQeBQoFBQUFCQUnBQQFCQoEMgQFBAgEBgICBggKBRkBBAEUBgUFBQsGJgUGBQsGCwYWBgkIAwMEEAEBBggICQYRBQYFBgsFIQYLBQUKBg8BBAEZBQoBBAYCAQEDAgQICQgBKQQFBQQFBQkFIgUJBQUFBQoF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AQMGBAUJBAQEAwQCARIBAgECAQICAgcCAQEBAQIHAwUC8AQFBAQDBAICBwIDBQIEAQIDDAoDBAIEAQEEAwQECQgFBwMPAgEGBQgBAQEGAQIBAgECAgIJAQICAwQI/a0ECAQDAgICBQYMBgEMAQYHAwEDAwEHBwMBBwcBAwEDBAgEBAwEBAQECQQEBAUCAQEEBAMVAwQKBxkDCgIDAwMDAwMDAgYDAgMCAwIIAZwFBAQBBwocCwcSBAsEBwQEBwQIBBAIBAMCAgEEBAMEBQwFDQQFBAUIBSYECQQEBAQEBAEEAwEDAQMEBAgECQQCAgECBgMEBf5EBAUEBgICAQIDAwUEAQQNCQENAQQFBQQBBAUFCgUZAQQBFAYFBQULCgkFBAQDBAECAwMEBxMFBAUFBAUFBCUeCAQECQwDDQISBQQFAwEUBAQJCBYsBQUEBQUFBAUbBAYEAQECAwMEBAQJAwYFCwUFBQYUAR4FCgUFBAEEAQQFHA0EAQQFAwIBAgIDBAgCIX2MfX2MfRd9Xn1+XQGVAQEBAQcCAgQDBAQECQQFBgMCCQIBAQEBAQECBQECAwMIBAUECQMDAwcBAQEBUwECAgQHCQkKAQkHBgcDBAMEAwQHCAcUBA0EBCADAwICAgIDAwgJBQYFBQQBBAEEBRwNBAEIBAEEBAQIAQMBAwEDBAgDAQMEAwEGBAcIAQQEAQMEAwEDDAMBAwEDAQgEBAQBBAQEAQQNFwUFBAEEAQkFCgUMBAUEBAMEAQIFBwweCAQJBBQHCAcEAwQDBAMHBgQDBwUEBAkEBAMEAQICBQwFCQQDBgIBAQEBAQICBwICAwICAgECAwMIBQkIAwUCAQIBAgECAgIJAgEBAScCAwUCBAECDwMCAQIJDAkBCQQDAwEDAwEDCwcHCQkEAwQEAQEEAwwDBAYDAwIDAwMDAwMCAwMCAwIDAgMCAwQDFgMDCAkJBwMEOwECAwMEDQULAgMDAwMDAwIDAwojAwcDBwQOCwMHAwgDAwIBAQMCBAgJBAIECQQEBAQEBQMBAwEDBAEDEAQDAQMIAwEKAQMDAQMDAQMDAQYECQEDAgMDqQEEBAMECAQECQUECQ0EGwUNCQQECQQBBCIEBQEEBAMDAgECAgMECAkFBBIECwQHBAQHBAgEHgQIBAcEBAcEBAkEBAQDBC0BBAgEBAQEHgUKBQUFBQkF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CgUGAwkECQQEAwQCBAYBBAMCAwIDAgECCAEFAwQCBAICBQIHAgIBAgkBAgIDBwMCAwIBAgMCBgIKBf3zBQcBAgMCAwIDAgMCAwQBAgIDAgQBBAQBAgICAgICAQICAgQCAgQBAQECAwICCgECAgIBBAECAQIBAgECAgEEBAMOBAgEAwEBAgMBAgICAQIBAgECAQICAwIBAggCAQICAgEEAgQBBgIKAgYDCgMGAwUDAgEEBggFArIEBQMGAgEBAQEBAQEBAgEDBQMFAwQDAgYDAQIDBgQJCQQEAwIBAQMCAQIDAwIBBQEMAwECAQEBAQEBAQEEAwQECPymBAUDBAQBAQMCAQMCAQQBCgEEAwIDAgECAwECBAcJCQQEAwQCBAIDAgcEAQYBAgECCAEBAQEFCAgCsQQECQQFCgQPBQULDwYFCwUhBgsQCAQFAgIEAwQNCQYGFAUBEgYHBQEFAQUBBQEcAQsFAQUFAQULDwEEAQMDAgEEAwQECP3eBAQEAwICAQIDBA0CAQIDAgECAwMLAgEIAwMFAQIBAgECAQIDAwECAQIBAgQDBgMNAx0CAw0EAw0JBQgFAgEEAwQEAwQIAxQCEQMJBRECBgUDBQUFAgEPAgUCAgEEAwQRBAQFAhwM/pABfBj+tAEnGRlKGBhVGBhNGBgCLQECBgECBAIDBAgJBQQEAwQBAgICBAIBAQEBAQUBBgQDCQUICAIEBgEBAU8BAQMDBAQEBQkEBgECAQYDBAIIDgMIAwYDBAECAgMEAwQDBwcDCAMSCggCBAICAwMICgcHAQwIBAQEBAQEBAsBBwMGAgYCAwUDBwMCAwkDAgIHAgICAgEBAQICBAIFDAEEAgICAgIBAgICAgIBBAIBAgIDBAEEAQQBAgMCAwIBAgMCAQIGAgECBgMDAgUCAQIPAwIBAgECAwYDAwMDAwMDAwEECQUIAwMDAQQDAwQGBQMCBQECAwIDAgMCAwMCBQIDAgwCAwIDAgMEAwQDBgMKAwYCCgEGAgUEBAQJCQYEAf7GAQICCAQEBAQzAwkDBgIGAwMDAwMDBgIDAwkCDgMIAQ0FCwUGCgcEBQkEBgICAgIDAwMDBgYGBQEFBw8mAwoDAwcDAwQDAwQDAwQDBwMOAywFCQgEAgMCEwECAwMIBBsGBxMHDRMGBw0GHw0FAQUBBQEFAQUBBQEBBAQEAgICAwMJ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CAMBFQMBAwMBCQEMAQkJAwMCAQIDAwgEAQQCAgIDAwgEBQQJAwgDAgQDAgMCAwIDAgMDAwIDAwMDAwMDAwYDIwIDBAQCAgUECAGEBQgEAwMDAQYDAwIDAgMCAwIDBxYBBAEEAQYDAgIEBAMEBQkEBAQDBAECAgIBAgECAQICAgEBAQgBAQECAgQBAgcDAgECAwIBAgYDCQMDAwT9wwUECAMDAgIBAgEBAQEBAQIBCAIBAQEDAwQEBAUJBAMDBAECBQMCAQEBAQEBAgEBAgMDCQLuBQQIBgIBAQEBAQIIAgECAgQBFgEBBAMMBQkEBgUEAwoCCAECAQICAgcBAQEBAQQDBAj8pwUICAQCAQEBAgYCAgIBBAEGAgoDBAEDBgQFCQQEBAMEAgESAQIBAgECAgIHAgEBAQECBwMFAvAEBQQEAwQCAgcCAwUCBAECAwwKAwQCBAEBBAMEBAkIBQcDDwIBBgUIAQEBBgECAQIBAgICCQECAgMECP2tBAgEAwICAgUGDAYBDAEGBwMBAwMBBwcDAQcHAQMBAwQIBAQMBAQEBAkEBAQFAgEBBAQDFQMECgcZAwoCAwMDAwMDAwIGAwIDAgMCCAGcBQQEAQcKHAsHEgQLBAcEBAcECAQQCAQDAgIBBAQDBAUMBQ0EBQQFCAUmBAkEBAQEBAQBBAMBAwEDBAQIBAkEAgIBAgYDBAX+RAQFBAYCAgECAwMFBAEEDQkBDQEEBQUEAQQFBQoFGQEEARQGBQUFCwoJBQQEAwQBAgMDBAcTBQQFBQQFBQQlHggEBAkMAw0CEgUEBQMBFAQECQgWLAUFBAUFBQQFGwQGBAEBAgMDBAQECQMGBQsFBQUGFAEeBQoFBQQBBAEEBRwNBAEEBQMCAQICAwQIAhwM/pABfBj+tAEnGRlKGBhVGBhNGBgCLwEBAQEHAgIEAwQEBAkEBQYDAgkCAQEBAQEBAgUBAgMDCAQFBAkDAwMHAQEBAVMBAgIEBwkJCgEJBwYHAwQDBAMEBwgHFAQNBAQgAwMCAgICAwMICQUGBQUEAQQBBAUcDQQBCAQBBAQECAEDAQMBAwQIAwEDBAMBBgQHCAEEBAEDBAMBAwwDAQMBAwEIBAQEAQQEBAEEDRcFBQQBBAEJBQoFDAQFBAQDBAECBQcMHggECQQUBwgHBAMEAwQDBwYEAwcFBAQJBAQDBAECAgUM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bHRpcGxlJWludGVybWVkaWF0ZS1ldmVudC1jYXRjaC1jb21wZW5zYXRpb24LZ2F0ZXdheS14b3IKY29ubmVjdGlvbhBlbmQtZXZlbnQtY2FuY2VsImludGVybWVkaWF0ZS1ldmVudC1jYXRjaC1jb25kaXRpb247aW50ZXJtZWRpYXRlLWV2ZW50LWNhdGNoLW5vbi1pbnRlcnJ1cHRpbmctcGFyYWxsZWwtbXVsdGlwbGUVc3RhcnQtZXZlbnQtY29uZGl0aW9uInN0YXJ0LWV2ZW50LW5vbi1pbnRlcnJ1cHRpbmctdGltZXIUc2VxdWVudGlhbC1taS1tYXJrZXIJdXNlci10YXNrDWJ1c2luZXNzLXJ1bGUSc3ViLXByb2Nlc3MtbWFya2VyHXN0YXJ0LWV2ZW50LXBhcmFsbGVsLW11bHRpcGxlEXN0YXJ0LWV2ZW50LWVycm9yH2ludGVybWVkaWF0ZS1ldmVudC1jYXRjaC1zaWduYWweaW50ZXJtZWRpYXRlLWV2ZW50LWNhdGNoLWVycm9yFmVuZC1ldmVudC1jb21wZW5zYXRpb24Uc3VicHJvY2Vzcy1jb2xsYXBzZWQTc3VicHJvY2Vzcy1leHBhbmRlZAR0YXNrD2VuZC1ldmVudC1lcnJvciNpbnRlcm1lZGlhdGUtZXZlbnQtY2F0Y2gtZXNjYWxhdGlvbh5pbnRlcm1lZGlhdGUtZXZlbnQtY2F0Y2gtdGltZXIWc3RhcnQtZXZlbnQtZXNjYWxhdGlvbhJzdGFydC1ldmVudC1zaWduYWwSYnVzaW5lc3MtcnVsZS10YXNrBm1hbnVhbAdyZWNlaXZlDWNhbGwtYWN0aXZpdHkRc3RhcnQtZXZlbnQtdGltZXITc3RhcnQtZXZlbnQtbWVzc2FnZRdpbnRlcm1lZGlhdGUtZXZlbnQtbm9uZR1pbnRlcm1lZGlhdGUtZXZlbnQtY2F0Y2gtbGluaxRlbmQtZXZlbnQtZXNjYWxhdGlvbg90ZXh0LWFubm90YXRpb24HYnBtbi1pbw9nYXRld2F5LWNvbXBsZXgSZ2F0ZXdheS1ldmVudGJhc2VkDGdhdGV3YXktbm9uZQpnYXRld2F5LW9yE2VuZC1ldmVudC10ZXJtaW5hdGUQZW5kLWV2ZW50LXNpZ25hbA5lbmQtZXZlbnQtbm9uZRJlbmQtZXZlbnQtbXVsdGlwbGURZW5kLWV2ZW50LW1lc3NhZ2UOZW5kLWV2ZW50LWxpbmsgaW50ZXJtZWRpYXRlLWV2ZW50LWNhdGNoLW1lc3NhZ2UlaW50ZXJtZWRpYXRlLWV2ZW50LXRocm93LWNvbXBlbnNhdGlvbhRzdGFydC1ldmVudC1tdWx0aXBsZQZzY3JpcHQLbWFudWFsLXRhc2sEc2VuZAdzZXJ2aWNlDHJlY2VpdmUtdGFzawR1c2VyEHN0YXJ0LWV2ZW50LW5vbmUjaW50ZXJtZWRpYXRlLWV2ZW50LXRocm93LWVzY2FsYXRpb24haW50ZXJtZWRpYXRlLWV2ZW50LWNhdGNoLW11bHRpcGxlNGludGVybWVkaWF0ZS1ldmVudC1jYXRjaC1ub24taW50ZXJydXB0aW5nLWVzY2FsYXRpb24daW50ZXJtZWRpYXRlLWV2ZW50LXRocm93LWxpbmsmc3RhcnQtZXZlbnQtbm9uLWludGVycnVwdGluZy1jb25kaXRpb24LZGF0YS1vYmplY3QLc2NyaXB0LXRhc2sJc2VuZC10YXNrCmRhdGEtc3RvcmUnc3RhcnQtZXZlbnQtbm9uLWludGVycnVwdGluZy1lc2NhbGF0aW9uIGludGVybWVkaWF0ZS1ldmVudC10aHJvdy1tZXNzYWdlMmludGVybWVkaWF0ZS1ldmVudC1jYXRjaC1ub24taW50ZXJydXB0aW5nLW11bHRpcGxlMGludGVybWVkaWF0ZS1ldmVudC1jYXRjaC1ub24taW50ZXJydXB0aW5nLXNpZ25hbCFpbnRlcm1lZGlhdGUtZXZlbnQtdGhyb3ctbXVsdGlwbGUkc3RhcnQtZXZlbnQtbm9uLWludGVycnVwdGluZy1tZXNzYWdlDWFkLWhvYy1tYXJrZXIMc2VydmljZS10YXNrCXRhc2stbm9uZRNjb21wZW5zYXRpb24tbWFya2VyJXN0YXJ0LWV2ZW50LW5vbi1pbnRlcnJ1cHRpbmctbXVsdGlwbGUfaW50ZXJtZWRpYXRlLWV2ZW50LXRocm93LXNpZ25hbDNpbnRlcm1lZGlhdGUtZXZlbnQtY2F0Y2gtbm9uLWludGVycnVwdGluZy1jb25kaXRpb24LcGFydGljaXBhbnQZZXZlbnQtc3VicHJvY2Vzcy1leHBhbmRlZBFsYW5lLWluc2VydC1iZWxvdwpzcGFjZS10b29sEGNvbm5lY3Rpb24tbXVsdGkEbGFuZQpsYXNzby10b29sEWxhbmUtaW5zZXJ0LWFib3ZlEWxhbmUtZGl2aWRlLXRocmVlD2xhbmUtZGl2aWRlLXR3bwpkYXRhLWlucHV0C2RhdGEtb3V0cHV0CWhhbmQtdG9vbAt0cmFuc2FjdGlvbgAAAA==') format('truetype');
}
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
/*
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'bpmn';
src: url('../font/bpmn.svg?43681877#bpmn') format('svg');
}
}
*/
[class^="bpmn-icon-"]:before, [class*=" bpmn-icon-"]:before {
font-family: "bpmn";
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
text-align: center;
/* opacity: .8; */
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* fix buttons height, for twitter bootstrap */
line-height: 1em;
/* Animation center compensation - margins should be symmetric */
/* remove if not needed */
margin-left: .2em;
/* you can be more comfortable with increased icons size */
/* font-size: 120%; */
/* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}
.bpmn-icon-screw-wrench:before { content: '\e800'; } /* '' */
.bpmn-icon-trash:before { content: '\e801'; } /* '' */
.bpmn-icon-conditional-flow:before { content: '\e802'; } /* '' */
.bpmn-icon-default-flow:before { content: '\e803'; } /* '' */
.bpmn-icon-gateway-parallel:before { content: '\e804'; } /* '' */
.bpmn-icon-intermediate-event-catch-cancel:before { content: '\e805'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-message:before { content: '\e806'; } /* '' */
.bpmn-icon-start-event-compensation:before { content: '\e807'; } /* '' */
.bpmn-icon-start-event-non-interrupting-parallel-multiple:before { content: '\e808'; } /* '' */
.bpmn-icon-loop-marker:before { content: '\e809'; } /* '' */
.bpmn-icon-parallel-mi-marker:before { content: '\e80a'; } /* '' */
.bpmn-icon-start-event-non-interrupting-signal:before { content: '\e80b'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-timer:before { content: '\e80c'; } /* '' */
.bpmn-icon-intermediate-event-catch-parallel-multiple:before { content: '\e80d'; } /* '' */
.bpmn-icon-intermediate-event-catch-compensation:before { content: '\e80e'; } /* '' */
.bpmn-icon-gateway-xor:before { content: '\e80f'; } /* '' */
.bpmn-icon-connection:before { content: '\e810'; } /* '' */
.bpmn-icon-end-event-cancel:before { content: '\e811'; } /* '' */
.bpmn-icon-intermediate-event-catch-condition:before { content: '\e812'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-parallel-multiple:before { content: '\e813'; } /* '' */
.bpmn-icon-start-event-condition:before { content: '\e814'; } /* '' */
.bpmn-icon-start-event-non-interrupting-timer:before { content: '\e815'; } /* '' */
.bpmn-icon-sequential-mi-marker:before { content: '\e816'; } /* '' */
.bpmn-icon-user-task:before { content: '\e817'; } /* '' */
.bpmn-icon-business-rule:before { content: '\e818'; } /* '' */
.bpmn-icon-sub-process-marker:before { content: '\e819'; } /* '' */
.bpmn-icon-start-event-parallel-multiple:before { content: '\e81a'; } /* '' */
.bpmn-icon-start-event-error:before { content: '\e81b'; } /* '' */
.bpmn-icon-intermediate-event-catch-signal:before { content: '\e81c'; } /* '' */
.bpmn-icon-intermediate-event-catch-error:before { content: '\e81d'; } /* '' */
.bpmn-icon-end-event-compensation:before { content: '\e81e'; } /* '' */
.bpmn-icon-subprocess-collapsed:before { content: '\e81f'; } /* '' */
.bpmn-icon-subprocess-expanded:before { content: '\e820'; } /* '' */
.bpmn-icon-task:before { content: '\e821'; } /* '' */
.bpmn-icon-end-event-error:before { content: '\e822'; } /* '' */
.bpmn-icon-intermediate-event-catch-escalation:before { content: '\e823'; } /* '' */
.bpmn-icon-intermediate-event-catch-timer:before { content: '\e824'; } /* '' */
.bpmn-icon-start-event-escalation:before { content: '\e825'; } /* '' */
.bpmn-icon-start-event-signal:before { content: '\e826'; } /* '' */
.bpmn-icon-business-rule-task:before { content: '\e827'; } /* '' */
.bpmn-icon-manual:before { content: '\e828'; } /* '' */
.bpmn-icon-receive:before { content: '\e829'; } /* '' */
.bpmn-icon-call-activity:before { content: '\e82a'; } /* '' */
.bpmn-icon-start-event-timer:before { content: '\e82b'; } /* '' */
.bpmn-icon-start-event-message:before { content: '\e82c'; } /* '' */
.bpmn-icon-intermediate-event-none:before { content: '\e82d'; } /* '' */
.bpmn-icon-intermediate-event-catch-link:before { content: '\e82e'; } /* '' */
.bpmn-icon-end-event-escalation:before { content: '\e82f'; } /* '' */
.bpmn-icon-text-annotation:before { content: '\e830'; } /* '' */
.bpmn-icon-bpmn-io:before { content: '\e831'; } /* '' */
.bpmn-icon-gateway-complex:before { content: '\e832'; } /* '' */
.bpmn-icon-gateway-eventbased:before { content: '\e833'; } /* '' */
.bpmn-icon-gateway-none:before { content: '\e834'; } /* '' */
.bpmn-icon-gateway-or:before { content: '\e835'; } /* '' */
.bpmn-icon-end-event-terminate:before { content: '\e836'; } /* '' */
.bpmn-icon-end-event-signal:before { content: '\e837'; } /* '' */
.bpmn-icon-end-event-none:before { content: '\e838'; } /* '' */
.bpmn-icon-end-event-multiple:before { content: '\e839'; } /* '' */
.bpmn-icon-end-event-message:before { content: '\e83a'; } /* '' */
.bpmn-icon-end-event-link:before { content: '\e83b'; } /* '' */
.bpmn-icon-intermediate-event-catch-message:before { content: '\e83c'; } /* '' */
.bpmn-icon-intermediate-event-throw-compensation:before { content: '\e83d'; } /* '' */
.bpmn-icon-start-event-multiple:before { content: '\e83e'; } /* '' */
.bpmn-icon-script:before { content: '\e83f'; } /* '' */
.bpmn-icon-manual-task:before { content: '\e840'; } /* '' */
.bpmn-icon-send:before { content: '\e841'; } /* '' */
.bpmn-icon-service:before { content: '\e842'; } /* '' */
.bpmn-icon-receive-task:before { content: '\e843'; } /* '' */
.bpmn-icon-user:before { content: '\e844'; } /* '' */
.bpmn-icon-start-event-none:before { content: '\e845'; } /* '' */
.bpmn-icon-intermediate-event-throw-escalation:before { content: '\e846'; } /* '' */
.bpmn-icon-intermediate-event-catch-multiple:before { content: '\e847'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-escalation:before { content: '\e848'; } /* '' */
.bpmn-icon-intermediate-event-throw-link:before { content: '\e849'; } /* '' */
.bpmn-icon-start-event-non-interrupting-condition:before { content: '\e84a'; } /* '' */
.bpmn-icon-data-object:before { content: '\e84b'; } /* '' */
.bpmn-icon-script-task:before { content: '\e84c'; } /* '' */
.bpmn-icon-send-task:before { content: '\e84d'; } /* '' */
.bpmn-icon-data-store:before { content: '\e84e'; } /* '' */
.bpmn-icon-start-event-non-interrupting-escalation:before { content: '\e84f'; } /* '' */
.bpmn-icon-intermediate-event-throw-message:before { content: '\e850'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-multiple:before { content: '\e851'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-signal:before { content: '\e852'; } /* '' */
.bpmn-icon-intermediate-event-throw-multiple:before { content: '\e853'; } /* '' */
.bpmn-icon-start-event-non-interrupting-message:before { content: '\e854'; } /* '' */
.bpmn-icon-ad-hoc-marker:before { content: '\e855'; } /* '' */
.bpmn-icon-service-task:before { content: '\e856'; } /* '' */
.bpmn-icon-task-none:before { content: '\e857'; } /* '' */
.bpmn-icon-compensation-marker:before { content: '\e858'; } /* '' */
.bpmn-icon-start-event-non-interrupting-multiple:before { content: '\e859'; } /* '' */
.bpmn-icon-intermediate-event-throw-signal:before { content: '\e85a'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-condition:before { content: '\e85b'; } /* '' */
.bpmn-icon-participant:before { content: '\e85c'; } /* '' */
.bpmn-icon-event-subprocess-expanded:before { content: '\e85d'; } /* '' */
.bpmn-icon-lane-insert-below:before { content: '\e85e'; } /* '' */
.bpmn-icon-space-tool:before { content: '\e85f'; } /* '' */
.bpmn-icon-connection-multi:before { content: '\e860'; } /* '' */
.bpmn-icon-lane:before { content: '\e861'; } /* '' */
.bpmn-icon-lasso-tool:before { content: '\e862'; } /* '' */
.bpmn-icon-lane-insert-above:before { content: '\e863'; } /* '' */
.bpmn-icon-lane-divide-three:before { content: '\e864'; } /* '' */
.bpmn-icon-lane-divide-two:before { content: '\e865'; } /* '' */
.bpmn-icon-data-input:before { content: '\e866'; } /* '' */
.bpmn-icon-data-output:before { content: '\e867'; } /* '' */
.bpmn-icon-hand-tool:before { content: '\e868'; } /* '' */
.bpmn-icon-transaction:before { content: '\e8c4'; } /* '' */
\ No newline at end of file
@font-face {
font-family: 'bpmn';
src: url('../font/bpmn.eot?70672887');
src: url('../font/bpmn.eot?70672887#iefix') format('embedded-opentype'),
url('../font/bpmn.woff?70672887') format('woff'),
url('../font/bpmn.ttf?70672887') format('truetype'),
url('../font/bpmn.svg?70672887#bpmn') format('svg');
font-weight: normal;
font-style: normal;
}
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
/*
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'bpmn';
src: url('../font/bpmn.svg?70672887#bpmn') format('svg');
}
}
*/
[class^="bpmn-icon-"]:before, [class*=" bpmn-icon-"]:before {
font-family: "bpmn";
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
text-align: center;
/* opacity: .8; */
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* fix buttons height, for twitter bootstrap */
line-height: 1em;
/* Animation center compensation - margins should be symmetric */
/* remove if not needed */
margin-left: .2em;
/* you can be more comfortable with increased icons size */
/* font-size: 120%; */
/* Font smoothing. That was taken from TWBS */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}
.bpmn-icon-screw-wrench:before { content: '\e800'; } /* '' */
.bpmn-icon-trash:before { content: '\e801'; } /* '' */
.bpmn-icon-conditional-flow:before { content: '\e802'; } /* '' */
.bpmn-icon-default-flow:before { content: '\e803'; } /* '' */
.bpmn-icon-gateway-parallel:before { content: '\e804'; } /* '' */
.bpmn-icon-intermediate-event-catch-cancel:before { content: '\e805'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-message:before { content: '\e806'; } /* '' */
.bpmn-icon-start-event-compensation:before { content: '\e807'; } /* '' */
.bpmn-icon-start-event-non-interrupting-parallel-multiple:before { content: '\e808'; } /* '' */
.bpmn-icon-loop-marker:before { content: '\e809'; } /* '' */
.bpmn-icon-parallel-mi-marker:before { content: '\e80a'; } /* '' */
.bpmn-icon-start-event-non-interrupting-signal:before { content: '\e80b'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-timer:before { content: '\e80c'; } /* '' */
.bpmn-icon-intermediate-event-catch-parallel-multiple:before { content: '\e80d'; } /* '' */
.bpmn-icon-intermediate-event-catch-compensation:before { content: '\e80e'; } /* '' */
.bpmn-icon-gateway-xor:before { content: '\e80f'; } /* '' */
.bpmn-icon-connection:before { content: '\e810'; } /* '' */
.bpmn-icon-end-event-cancel:before { content: '\e811'; } /* '' */
.bpmn-icon-intermediate-event-catch-condition:before { content: '\e812'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-parallel-multiple:before { content: '\e813'; } /* '' */
.bpmn-icon-start-event-condition:before { content: '\e814'; } /* '' */
.bpmn-icon-start-event-non-interrupting-timer:before { content: '\e815'; } /* '' */
.bpmn-icon-sequential-mi-marker:before { content: '\e816'; } /* '' */
.bpmn-icon-user-task:before { content: '\e817'; } /* '' */
.bpmn-icon-business-rule:before { content: '\e818'; } /* '' */
.bpmn-icon-sub-process-marker:before { content: '\e819'; } /* '' */
.bpmn-icon-start-event-parallel-multiple:before { content: '\e81a'; } /* '' */
.bpmn-icon-start-event-error:before { content: '\e81b'; } /* '' */
.bpmn-icon-intermediate-event-catch-signal:before { content: '\e81c'; } /* '' */
.bpmn-icon-intermediate-event-catch-error:before { content: '\e81d'; } /* '' */
.bpmn-icon-end-event-compensation:before { content: '\e81e'; } /* '' */
.bpmn-icon-subprocess-collapsed:before { content: '\e81f'; } /* '' */
.bpmn-icon-subprocess-expanded:before { content: '\e820'; } /* '' */
.bpmn-icon-task:before { content: '\e821'; } /* '' */
.bpmn-icon-end-event-error:before { content: '\e822'; } /* '' */
.bpmn-icon-intermediate-event-catch-escalation:before { content: '\e823'; } /* '' */
.bpmn-icon-intermediate-event-catch-timer:before { content: '\e824'; } /* '' */
.bpmn-icon-start-event-escalation:before { content: '\e825'; } /* '' */
.bpmn-icon-start-event-signal:before { content: '\e826'; } /* '' */
.bpmn-icon-business-rule-task:before { content: '\e827'; } /* '' */
.bpmn-icon-manual:before { content: '\e828'; } /* '' */
.bpmn-icon-receive:before { content: '\e829'; } /* '' */
.bpmn-icon-call-activity:before { content: '\e82a'; } /* '' */
.bpmn-icon-start-event-timer:before { content: '\e82b'; } /* '' */
.bpmn-icon-start-event-message:before { content: '\e82c'; } /* '' */
.bpmn-icon-intermediate-event-none:before { content: '\e82d'; } /* '' */
.bpmn-icon-intermediate-event-catch-link:before { content: '\e82e'; } /* '' */
.bpmn-icon-end-event-escalation:before { content: '\e82f'; } /* '' */
.bpmn-icon-text-annotation:before { content: '\e830'; } /* '' */
.bpmn-icon-bpmn-io:before { content: '\e831'; } /* '' */
.bpmn-icon-gateway-complex:before { content: '\e832'; } /* '' */
.bpmn-icon-gateway-eventbased:before { content: '\e833'; } /* '' */
.bpmn-icon-gateway-none:before { content: '\e834'; } /* '' */
.bpmn-icon-gateway-or:before { content: '\e835'; } /* '' */
.bpmn-icon-end-event-terminate:before { content: '\e836'; } /* '' */
.bpmn-icon-end-event-signal:before { content: '\e837'; } /* '' */
.bpmn-icon-end-event-none:before { content: '\e838'; } /* '' */
.bpmn-icon-end-event-multiple:before { content: '\e839'; } /* '' */
.bpmn-icon-end-event-message:before { content: '\e83a'; } /* '' */
.bpmn-icon-end-event-link:before { content: '\e83b'; } /* '' */
.bpmn-icon-intermediate-event-catch-message:before { content: '\e83c'; } /* '' */
.bpmn-icon-intermediate-event-throw-compensation:before { content: '\e83d'; } /* '' */
.bpmn-icon-start-event-multiple:before { content: '\e83e'; } /* '' */
.bpmn-icon-script:before { content: '\e83f'; } /* '' */
.bpmn-icon-manual-task:before { content: '\e840'; } /* '' */
.bpmn-icon-send:before { content: '\e841'; } /* '' */
.bpmn-icon-service:before { content: '\e842'; } /* '' */
.bpmn-icon-receive-task:before { content: '\e843'; } /* '' */
.bpmn-icon-user:before { content: '\e844'; } /* '' */
.bpmn-icon-start-event-none:before { content: '\e845'; } /* '' */
.bpmn-icon-intermediate-event-throw-escalation:before { content: '\e846'; } /* '' */
.bpmn-icon-intermediate-event-catch-multiple:before { content: '\e847'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-escalation:before { content: '\e848'; } /* '' */
.bpmn-icon-intermediate-event-throw-link:before { content: '\e849'; } /* '' */
.bpmn-icon-start-event-non-interrupting-condition:before { content: '\e84a'; } /* '' */
.bpmn-icon-data-object:before { content: '\e84b'; } /* '' */
.bpmn-icon-script-task:before { content: '\e84c'; } /* '' */
.bpmn-icon-send-task:before { content: '\e84d'; } /* '' */
.bpmn-icon-data-store:before { content: '\e84e'; } /* '' */
.bpmn-icon-start-event-non-interrupting-escalation:before { content: '\e84f'; } /* '' */
.bpmn-icon-intermediate-event-throw-message:before { content: '\e850'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-multiple:before { content: '\e851'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-signal:before { content: '\e852'; } /* '' */
.bpmn-icon-intermediate-event-throw-multiple:before { content: '\e853'; } /* '' */
.bpmn-icon-start-event-non-interrupting-message:before { content: '\e854'; } /* '' */
.bpmn-icon-ad-hoc-marker:before { content: '\e855'; } /* '' */
.bpmn-icon-service-task:before { content: '\e856'; } /* '' */
.bpmn-icon-task-none:before { content: '\e857'; } /* '' */
.bpmn-icon-compensation-marker:before { content: '\e858'; } /* '' */
.bpmn-icon-start-event-non-interrupting-multiple:before { content: '\e859'; } /* '' */
.bpmn-icon-intermediate-event-throw-signal:before { content: '\e85a'; } /* '' */
.bpmn-icon-intermediate-event-catch-non-interrupting-condition:before { content: '\e85b'; } /* '' */
.bpmn-icon-participant:before { content: '\e85c'; } /* '' */
.bpmn-icon-event-subprocess-expanded:before { content: '\e85d'; } /* '' */
.bpmn-icon-lane-insert-below:before { content: '\e85e'; } /* '' */
.bpmn-icon-space-tool:before { content: '\e85f'; } /* '' */
.bpmn-icon-connection-multi:before { content: '\e860'; } /* '' */
.bpmn-icon-lane:before { content: '\e861'; } /* '' */
.bpmn-icon-lasso-tool:before { content: '\e862'; } /* '' */
.bpmn-icon-lane-insert-above:before { content: '\e863'; } /* '' */
.bpmn-icon-lane-divide-three:before { content: '\e864'; } /* '' */
.bpmn-icon-lane-divide-two:before { content: '\e865'; } /* '' */
.bpmn-icon-data-input:before { content: '\e866'; } /* '' */
.bpmn-icon-data-output:before { content: '\e867'; } /* '' */
.bpmn-icon-hand-tool:before { content: '\e868'; } /* '' */
.bpmn-icon-transaction:before { content: '\e8c4'; } /* '' */
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -18,6 +18,17 @@ body { ...@@ -18,6 +18,17 @@ body {
background-color:#999; background-color:#999;
} }
.tooltip {
font-family:'robotolight';
font-size:13px;
letter-spacing:0.3px;
padding:15px;
}
.dropdown-toggle {
cursor:pointer;
}
.badge { .badge {
border-radius: 100%; border-radius: 100%;
width: 22px; width: 22px;
...@@ -34,6 +45,19 @@ body { ...@@ -34,6 +45,19 @@ body {
font-weight: normal; font-weight: normal;
} }
.form-container {
width: 650px;
background-color: #fff;
padding: 25px;
border-radius: 3px;
margin-left: auto;
margin-right: auto;
-webkit-box-shadow: 0 0 25px rgba(0,0,0,0.04);
-moz-box-shadow: 0 0 25px rgba(0,0,0,0.04);
box-shadow: 0 0 25px rgba(0,0,0,0.04);
}
.form-control { .form-control {
box-shadow:none; box-shadow:none;
border-radius:0; border-radius:0;
...@@ -1071,6 +1095,7 @@ table.dataTable thead .sorting:after { ...@@ -1071,6 +1095,7 @@ table.dataTable thead .sorting:after {
.dashboard-main-search .panel-default { .dashboard-main-search .panel-default {
padding-bottom:25px; padding-bottom:25px;
border-radius:2px;
} }
.dashboard-main-search .dashboard-student-search h3, .dashboard-main-search .dashboard-student-search h3,
...@@ -1311,13 +1336,22 @@ table.dataTable thead .sorting:after { ...@@ -1311,13 +1336,22 @@ table.dataTable thead .sorting:after {
.dashboard .panel-default > .panel-heading { .dashboard .panel-default > .panel-heading {
background-color:#fff; background-color:#fff;
border-color:#F2F2F2; border-color:#F2F2F2;
font-family:'robotomedium'; font-family:'robotolight';
color: rgb(93, 93, 93); color: rgb(95, 95, 95);
text-align:center; padding:15px;
} }
.dashboard .panel-default > .panel-heading .panel-title { .dashboard .panel-default > .panel-heading .panel-title {
font-size:18px; font-size:18px;
display:inline-block;
}
.dashboard .panel-default > .panel-heading .panel-action {
font-size: 15px;
padding-top: 3px;
padding-right: 10px;
font-family:'robotomedium';
cursor:pointer;
} }
.dashboard .user-info .user-name { .dashboard .user-info .user-name {
...@@ -1547,219 +1581,1658 @@ table.dataTable thead .sorting:after { ...@@ -1547,219 +1581,1658 @@ table.dataTable thead .sorting:after {
/* END OF SIDEBAR COLLAPSE */ /* END OF SIDEBAR COLLAPSE */
/* Responsive: Portrait tablets and up */
@media screen and (min-width: 768px) {
/* Remove the padding we set earlier */
.header,
.marketing,
.footer {
padding-left: 0;
padding-right: 0;
}
/* Space out the masthead */
.header {
margin-bottom: 30px;
}
/* Remove the bottom border on the jumbotron for visual effect */
.jumbotron {
border-bottom: 0;
}
.sidebar {
z-index: 1;
position: absolute;
overflow-y: auto;
width: 250px;
height: 100%;
-webkit-box-shadow: 0 0 25px rgba(0,0,0,0.1);
-moz-box-shadow: 0 0 25px rgba(0,0,0,0.1);
box-shadow: 0 0 25px rgba(0,0,0,0.1);
}
.navbar-top-links .dropdown-messages,
.navbar-top-links .dropdown-tasks,
.navbar-top-links .dropdown-alerts {
margin-left: auto;
}
.container { /* STUDENT DASHBOARD */
max-width: 730px;
}
.manager-view { .student-dashboard a:hover {
height:100%; text-decoration:none;
} background-color:#f9f9f9;
}
.sidebar .sidebar-nav.navbar-collapse {
overflow-x: visible;
/*overflow-y: auto;*/
/*position: absolute;*/
width: 100%;
/*max-height: calc(50% - 139px);*/
}
.sidebar-container { .student-dashboard .panel-body ul,
max-height: calc(100% - 120px); overflow-y: auto; .student-dashboard .panel-body {
} padding:0;
margin:0;
footer {
position: absolute;
bottom: 35px;
padding: 15px;
width:100%;
text-align:center;
}
footer span {
font-family:'robotobold';
color:#777;
}
} }
@media (max-width: 767px) { .student-dashboard .panel-body ul li {
.manager-view { list-style: none;
width:100%; border-bottom: 1px solid #f5f5f5;
} font-size:16px;
ul.timeline:before { }
left: 40px;
}
ul.timeline > li > .timeline-panel { .student-dashboard .panel-body ul li a {
width: calc(100% - 90px); padding:25px;
width: -moz-calc(100% - 90px); display:block;
width: -webkit-calc(100% - 90px); color:#333;
} }
ul.timeline > li > .timeline-badge { .student-dashboard .panel-body ul li:last-child {
top: 16px; border:none;
left: 15px; }
margin-left: 0;
}
ul.timeline > li > .timeline-panel { .student-course-list .panel-body,
float: right; .student-assignment-list .panel-body {
} height:437px;
overflow-y:auto;
}
ul.timeline > li > .timeline-panel:before { .student-course-list .panel-body ul li span {
right: auto; margin-right:15px;
left: -15px; }
border-right-width: 15px;
border-left-width: 0;
}
ul.timeline > li > .timeline-panel:after {
right: auto;
left: -14px;
border-right-width: 14px;
border-left-width: 0;
}
.sidebar {
width:100% !important;
}
.brand, .student-assignment-list .assignment-status {
footer { width:35px;
display:none; float:left;
} }
.logo img { .student-assignment-list .assignment-status .assignment-circle {
width:200px; width:10px;
margin-left:0; height:10px;
} border-radius:100%;
margin-top: 7px;
margin-left: 3px;
}
.manager-view-content { .student-assignment-list .urgent-assignment .assignment-circle {
overflow:inherit; background-color:#D4244B;
} }
body { .student-assignment-list .urgent-assignment .assignment-due-date {
overflow:auto; color:#D4244B;
}
.sidebar-collapse-button {
display:none;
}
.right-sidebar {
display: none;
}
} }
.student-assignment-list .approaching-assignment .assignment-circle {
background-color:#F7941E;
}
@media (max-width: 1350px) { .student-assignment-list .approaching-assignment .assignment-due-date {
.personnel-info-container { color:#F7941E;
width:700px; }
}
.personnel-info-right { .student-assignment-list .non-urgent-assignment .assignment-circle {
width:450px; background-color:#01AEEE;
}
} }
.student-assignment-list .non-urgent-assignment .assignment-due-date {
color:#01AEEE;
}
.student-assignment-list .assignment-title {
width:calc(100% - 100px);
float:left;
}
.student-assignment-list .assignment-title {
font-family:'robotomedium';
}
.student-assignment-list .assignment-title div:nth-child(1) {
font-family:'robotomedium';
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-right: 15px;
}
.student-assignment-list .assignment-title div:nth-child(2) {
font-size:15px;
font-family:'robotolight';
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-right: 15px;
}
@media (max-width: 1000px) { .student-assignment-list .assignment-due-date {
.personnel-info-container { width:65px;
width:500px; float:left;
height:auto; font-family:'robotolight';
} position:relative;
}
.personnel-info-left { .student-assignment-list .assignment-due-date div:nth-child(1) {
width:100%; width:65px;
position:relative; font-size:22px;
height:auto; position:absolute;
border:none; text-align:center;
} }
.personnel-info-right { .student-assignment-list .assignment-due-date div:nth-child(2) {
width:100%; width:65px;
position:relative; font-size:13px;
height:auto; position:absolute;
} margin-top:25px;
text-align:center;
}
.generic-profile-picture, .student-assignment-list .last-assignment .assignment-status div {
.personnel-info-left ul li:nth-child(1), width:3px;
.personnel-info-left ul li:nth-child(2) { height:47px;
text-align:center; background-color: #00A650;
} margin-left: 6px;
}
.generic-profile-picture img { .student-assignment-list .last-assignment .panel-title {
border-radius:100%; background-color: #fff;
} border-color: #F2F2F2;
font-family: 'robotolight';
color: rgb(95, 95, 95);
padding: 12px 0 0;
font-size: 18px;
}
.student-assignment-list .last-assignment .assignment-due-date i {
color:#01A550;
margin-top: 16px;
} }
.student-announcement-list .announcement-date {
float:left;
font-family:'robotolight';
margin-right:25px;
width:30px;
}
.student-announcement-list .announcement-text {
float:left;
width:calc(100% - 55px);
margin-top:3px;
}
.student-announcement-list .announcement-date div:first-child {
font-size: 22px;
text-align: center;
}
@media (max-width: 560px) { .student-announcement-list .announcement-date div:last-child {
.personnel-info-container { font-size: 13px;
width: 350px; text-align: center;
}
} }
@media (max-width: 991px) { .student-message-list .profile-pic {
.dashboard .major-buttons a button { width: 65px;
margin-bottom:20px; display: block;
} margin-right: 20px;
float: left;
} }
.tablescroll{ .student-message-list .profile-pic img {
width: 100%; width: 100%;
overflow-x:auto; border-radius: 100%;
overflow-y:visible;
padding-bottom:1px;
} }
.tablescrollfixleft {
position:absolute; .student-message-list .message-content {
left:0; width: calc(100% - 200px);
top:auto; float: left;
} }
.tablescrollfixleft {
position:absolute; .student-message-list .message-content div:first-child {
right:0; margin-top:7px;
top:auto; font-family:'robotomedium';
font-size:18px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.student-message-list .message-content div:last-child {
margin-top: 5px;
color: #848484;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.student-message-list .message-time {
width: 100px;
float: right;
text-align:right;
padding-top: 21px;
color: #B3B3B3;
font-size: 14px;
}
/* END OF STUDENT DASHBOARD */
/* ACADEMICIAN DASHBOARD */
.academician-dashboard a:hover {
text-decoration:none;
background-color:#f9f9f9;
}
.academician-dashboard .panel-body ul,
.academician-dashboard .panel-body {
padding:0;
margin:0;
}
.academician-dashboard .panel-body ul li {
list-style: none;
border-bottom: 1px solid #f5f5f5;
font-size:16px;
}
.academician-dashboard .panel-body ul li a {
padding:20px 25px;
display:block;
color:#333;
}
.academician-dashboard .panel-body ul li:last-child {
border:none;
}
.academician-course-list .panel-body,
.academician-weekly-schedule .panel-body {
height:437px;
overflow-y:auto;
overflow-x:hidden;
}
.academician-course-list .panel-body ul li span {
margin-right:15px;
}
.academician-course-list .panel-body ul li div {
margin-left: 47px;
font-size: 15px;
color: #7E7E7E;
}
.academician-dashboard .academician-weekly-schedule table {
width: calc(100% + 2px);
-webkit-width: calc(100% + 2px);
border: none;
margin-top: -1px;
margin-left: -1px;
text-align:center;
}
.academician-dashboard .academician-weekly-schedule table a {
color:#333;
display:block;
height: 38px;
line-height: 38px;
}
.academician-dashboard .academician-weekly-schedule table a:hover {
font-family:'robotobold';
background-color:transparent;
font-size:16px;
}
.academician-dashboard .academician-weekly-schedule table tr.days td {
width: calc(100% / 6);
font-family: 'robotomedium';
background-color: #FDFDFD;
}
.academician-dashboard .academician-weekly-schedule table tr.days td:first-child {
background-color:transparent;
}
.academician-dashboard .academician-weekly-schedule table tr td:first-child {
height: 38px;
font-family: 'robotomedium';
background-color: #FDFDFD;
}
.academician-dashboard .academician-weekly-schedule p.schedule-notice {
margin-left: 36px;
margin-top: 18px;
}
.academician-dashboard .academician-weekly-schedule p.schedule-notice span {
font-family: 'robotomedium';
}
/* END OF ACADEMICIAN DASHBOARD */
/* ACADEMIC CALENDER DASHBOARD WIDGET */
.academic-calendar-widget .panel-body {
padding-top:30px;
padding-bottom:30px;
}
.academic-calendar-widget .calendar-inner {
width: 85%;
margin-left: auto;
margin-right: auto;
position: relative;
}
.academic-calendar-widget .date-circle {
width: calc(100%/7);
float:left;
}
.academic-calendar-widget .date-circle .year {
width: 75px;
text-align: center;
font-size: 11px;
color: #C6C6C6;
}
.academic-calendar-widget .date-circle-container .date-circle:nth-child(5) .year,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(6) .year,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(7) .year {
float:right;
}
.academic-calendar-widget .date-circle a {
width:75px;
height:75px;
color:#808285;
border: 3px solid #fff;
background-color:#fff;
border-radius: 100%;
text-align: center;
display:block;
margin-left: auto;
margin-right: auto;
margin-top:12px;
z-index:1;
position:relative;
cursor:pointer;
font-family:'robotolight';
}
.academic-calendar-widget .date-circle a:hover {
background-color:#EBEBEB;
}
.academic-calendar-widget .date-circle a:before {
border: 2px solid #939598;
content: " ";
position: absolute;
z-index: -1;
border-radius: 100%;
width: 100%;
height: 100%;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
.academic-calendar-widget .date-today .year {
width: 95px;
margin-left: auto;
margin-right: auto;
}
.academic-calendar-widget .date-today a {
width:95px;
height:95px;
border: 2px solid #fff;
border-radius: 100%;
text-align: center;
margin-top:0;
color:#000;
}
.academic-calendar-widget .date-today a:hover {
background-color:#C9635F;
color:#fff;
}
.academic-calendar-widget .date-today a:before {
border-color: #BE1E2D;
}
.academic-calendar-widget .date-today a .date-day {
margin-top: 18px;
font-size: 25px;
}
.academic-calendar-widget .date-today a .date-month {
font-size: 17px;
}
.academic-calendar-widget a .date-day {
margin-top: 12px;
font-size: 19px;
}
.academic-calendar-widget a .date-month {
line-height: 7px;
}
.calendar-line {
width: 100%;
height: 1px;
background-color: #E5E5E5;
position: absolute;
margin-top: 48px;
z-index: 0;
}
.academic-calendar-widget .date-circle-container .date-circle:nth-child(1) a,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(2) a,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(3) a {
margin-left:0;
}
.academic-calendar-widget .date-circle-container .date-circle:nth-child(5) a,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(6) a,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(7) a {
margin-right:0;
}
.calendar-widget-navigation {
position: relative;
font-size: 40px;
color: #ccc;
}
.calendar-widget-navigation .fa {
position:absolute;
top: 27px;
cursor:pointer;
-webkit-transition: all .2s;
-moz-transition: all .2s;
-ms-transition: all .2s;
-o-transition: all .2s;
transition: all .2s;
}
.calendar-widget-navigation .fa:hover {
color:#666;
}
.calendar-widget-navigation .fa-angle-left {
left:25px;
}
.calendar-widget-navigation .fa-angle-right {
right:25px;
}
.academic-calendar-widget-popover label {
color:#A61229;
}
.academic-calendar-widget-popover .content-wrapper {
border-bottom:1px solid #dedede;
margin-bottom:10px;
}
.academic-calendar-widget-popover .content-wrapper:last-child {
border:none;
}
.academic-calendar-widget .date-circle .popover {
width:450px !important;
padding-bottom:0 !important;
}
/* END OF ACADEMIC CALENDER DASHBOARD WIDGET */
/* CHAT APPLICATION */
.chat-app {
width: 800px;
height: 600px;
background-color: #fff;
position: fixed;
bottom: 15px;
right: 15px;
-moz-box-shadow: 0px 0px 45px rgba(0,0,0,0.4);
box-shadow: 0px 0px 45px rgba(0,0,0,0.4);
z-index: 2100;
border-radius: 3px;
}
.chat-app .chat-app-container {
padding-left:240px;
}
.chat-app .side-navigation {
background-color: #8C1028;
width: 240px;
height: 100%;
position: absolute;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
overflow: auto;
padding-bottom: 20px;
left:0;
}
.chat-app .side-navigation ul {
margin: 0;
padding-left: 0;
padding-top: 15px;
}
.chat-app .side-navigation ul.channels {
border-bottom: 1px solid #9B1334;
padding-bottom: 15px;
}
.chat-app .side-navigation ul.channels li.public-ro-channel {
font-style:italic;
}
.chat-app .side-navigation ul li {
list-style: none;
color: #fff;
font-size: 15px;
padding-left: 20px;
padding-bottom: 3px;
padding-top: 3px;
position:relative;
cursor:pointer;
}
.chat-app .side-navigation ul li:hover {
background-color:#B51533;
}
.chat-app .side-navigation ul li.title {
font-family:'robotobold';
cursor:default;
}
.chat-app .side-navigation ul li.title:hover {
background-color:transparent;
}
.chat-app .side-navigation ul li.title .badge {
position: relative;
top: -3px;
border-radius: 20px;
padding: 1px 7px;
width: auto;
height: auto;
background-color: #B51533;
border: none;
margin-left: 4px;
font-family: 'robotoblack';
}
.chat-app .side-navigation ul li.title .add-action {
display: inline-block;
position: absolute;
right: 21px;
top: 6px;
/*margin-left: 4px;*/
/*top: 2px;*/
/*position: relative;*/
/*display: inline-block;*/
}
.chat-app .side-navigation ul li.compose {
background-color: #6f0d20;
margin: 5px 10px;
border-radius: 3px;
padding-left: 33px !important;
padding-top: 8px;
padding-bottom: 8px;
}
.chat-app .side-navigation ul li.compose:hover {
background-color: #B51533;
}
.chat-app .side-navigation ul li.compose span {
position: absolute;
top: 12px;
left: 10px;
}
.chat-app .side-navigation ul li.compose:before {
display:none !important;
}
.chat-app .side-navigation ul.direct-messages li.title {
padding-left: 20px;
}
.chat-app .side-navigation ul.direct-messages li {
padding-left: 40px;
}
.chat-app .side-navigation ul.direct-messages li.active, .chat-app .side-navigation ul.channels li.active {
background-color: #B51533;
}
.chat-app .side-navigation ul.direct-messages li.title:before {
display:none;
}
.chat-app .side-navigation ul.direct-messages li:before {
content: " ";
width: 8px;
height: 8px;
background-color: rgba(255,255,255,0.3);
display: inline-block;
border-radius: 100%;
position: absolute;
left: 24px;
top: 9px;
}
.chat-app .side-navigation ul li.unread:after {
content: " ";
width: 8px;
height: 8px;
background-color: rgb(181, 21, 51);
display: inline-block;
border-radius: 100%;
position: absolute;
right: 24px;
top: 9px;
}
.chat-app .side-navigation ul.direct-messages li.online:before {
background-color:#CAFF4A;
}
.chat-app .conversation-section {
width: 100%;
height: 600px;
}
.chat-app .conversation-header {
height: 70px;
width: 560px;
border-bottom:1px solid #efefef;
}
.chat-app .conversation-header .conversation-user {
display: inline-block;
width: 240px;
margin-left: 23px;
float: left;
}
.chat-app .conversation-header .user-photo {
float: left;
margin-top: 20px;
}
.chat-app .conversation-header .user-name {
margin-top: 25px;
float: left;
margin-left: 10px;
font-family: 'robotobold';
font-size: 16px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 180px;
}
.chat-app .conversation-header .conversation-search {
display:inline-block;
float:left;
}
.chat-app .conversation-header .conversation-search input {
width: 180px;
height: 40px;
padding-left: 10px;
border: 1px solid #efefef;
border-radius: 3px;
outline: none;
margin-top: 15px;
}
.chat-app .conversation-header .close-chat-app, .chat-app .conversation-section-empty .close-chat-app {
display: inline-block;
float: left;
width: 40px;
height: 40px;
border: 1px solid #efefef;
text-align: center;
line-height: 40px;
margin-left: 10px;
border-radius: 3px;
margin-top:15px;
cursor: pointer;
}
.chat-app .conversation-section-empty .close-chat-app {
display: block;
position: absolute;
right: 15px;
top: 0px;
}
.chat-app .conversation-section-empty .close-chat-app {
display: block;
position: absolute;
right: 15px;
top: 0px;
}
.chat-app .conversation-header .chat-app-actions {
display: inline-block;
float: left;
width: 40px;
height: 40px;
border: 1px solid #efefef;
text-align: center;
line-height: 40px;
margin-left: 10px;
border-radius: 3px;
margin-top:15px;
}
.chat-app .conversation-body {
overflow: auto;
height: calc(100% - 140px);
overflow-x: hidden;
}
.chat-app .conversation-body.readonly {
height: calc(100% - 100px);
}
.chat-app .conversation-footer {
height: 70px;
width: 560px;
position: absolute;
bottom: 0;
padding-left: 23px;
padding-right: 23px;
padding-top: 10px;
}
.chat-app .conversation-footer textarea {
outline: none;
resize: none;
width: calc(100% - 110px);
padding: 6px;
height: 50px;
border: 1px solid #efefef;
border-radius: 3px;
float:left;
}
.chat-app .conversation-footer .add-attachment {
float:left;
}
.chat-app .conversation-footer .add-attachment .glyphicon {
width: 50px;
height: 50px;
float: left;
border: 1px solid #efefef;
border-radius: 3px;
line-height: 50px;
text-align: center;
font-size: 20px;
top: 0;
margin-left: 5px;
color:#4D4D4D;
cursor:pointer;
}
.chat-app .conversation-footer .add-attachment .glyphicon:hover {
background-color:#efefef;
color:#000000;
}
.chat-app .conversation-section .conversation-header .conversation-user .user-photo img {
width:35px;
height:35px;
border-radius:100%;
}
.chat-app .conversation-section .conversation-body .beginning-of-conversation, .chat-app .conversation-section-empty .conversation-body {
text-align: center;
font-family: 'robotobold';
font-size: 20px;
color: #ababab;
padding: 15px;
margin-bottom: 30px;
border-bottom: 1px solid #f3f3f3;
}
.chat-app .conversation-section-empty .conversation-body {
padding-top: 100px;
}
.chat-app .conversation-section .conversation-body .conversation-block {
display:block;
position:relative;
padding:5px 23px;
margin-bottom:10px;
}
.chat-app .conversation-section .conversation-body .conversation-block:hover {
background-color:#f5f5f5;
}
.chat-app .conversation-section .conversation-body .conversation-block .conversation-actions {
opacity:0;
width:0;
position:absolute;
}
.chat-app .conversation-section .conversation-body .conversation-block .conversation-actions .action {
background-color: #fff;
display: inline-block;
padding: 3px 9px;
border-radius: 3px;
border: 1px solid #ece8e8;
float: left;
margin-right: 5px;
cursor: pointer;
color: #696969;
}
.chat-app .conversation-section .conversation-body .conversation-block .conversation-actions .action:hover {
color:#000000;
}
.chat-app .conversation-section .conversation-body .conversation-block:hover > .conversation-actions {
opacity: 1;
width: 130px;
position: absolute;
top: -14px;
right: 0;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-photo img {
width: 40px;
float: left;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-photo img {
width:35px;
height:35px;
border-radius:100%;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-message {
float: left;
width: calc(100% - 40px);
padding-left:10px;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-message .user-name {
font-family: 'robotobold';
font-size: 16px;
float:left;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-message .message-time {
float: left;
margin-left: 10px;
font-size: 11px;
color: #a0a0a0;
margin-top: 4px;
}
.chat-app .conversation-section .user-message .message-content {
font-family: 'robotomedium';
position: relative;
}
.chat-app .conversation-section .message-content-url {
display: block;
}
.chat-app .conversation-section .user-message .message-content .attachment-message {
color: #909090;
}
.chat-app .conversation-section .user-message .message-content .attachment-message span {
color: #b51533;
}
.chat-app .conversation-section .user-message .message-content .attachment-holder {
position:relative;
display: inline-block;
-webkit-transition: all .2s;
-moz-transition: all .2s;
-ms-transition: all .2s;
-o-transition: all .2s;
transition: all .2s;
}
.chat-app .conversation-section .user-message .message-content .attachment-holder .attachment-download {
position: absolute;
right: 10px;
top: 10px;
color: #fff;
font-size: 21px;
opacity:0;
cursor:pointer;
-webkit-transition: all .2s;
-moz-transition: all .2s;
-ms-transition: all .2s;
-o-transition: all .2s;
transition: all .2s;
}
.chat-app .conversation-section .user-message .message-content .attachment-holder:hover > .attachment-download {
opacity:0.6;
}
.chat-app .conversation-section .user-message .message-content .attachment-holder .attachment-download:hover {
opacity:1;
}
.chat-app .conversation-section .user-message .message-content .image-attached img {
width: 220px;
border-radius: 3px;
border: 1px solid #a0a0a0;
}
.chat-app .conversation-section .user-message .message-content .file-attached {
width: 100%;
border: 1px solid #ccc;
border-radius: 3px;
padding: 10px;
padding-left: 5px;
background-color:#fff;
}
.chat-app .conversation-section .user-message .message-content .file-attached img {
width: 40px;
float:left;
}
.chat-app .conversation-section .user-message .message-content .file-attached .attached-file-info {
float:left;
margin-left:10px;
}
.chat-app .conversation-section .user-message .message-content .file-attached .attached-file-info div:first-child {
color: #333;
font-size: 15px;
}
.chat-app .conversation-section .user-message .message-content .file-attached .attached-file-info div:last-child {
color: #a2a2a2;
font-size: 13px;
}
.chat-app .conversation-section .user-message .message-content .file-attached .attachment-download {
color:#333;
margin-top:10px;
}
.chat-app .conversation-section .user-message .message-content .file-attached:hover > .attachment-download {
opacity:0.6;
}
.chat-app .conversation-section .user-message .message-content .file-attached .attachment-download:hover {
opacity:1;
}
.chat-app .conversation-section .user-message .edit-text-message .editor {
width: 100%;
margin-bottom: 7px;
margin-top: 7px;
border-radius: 3px;
border: 1px solid #ccc;
padding: 5px 10px;
outline: none;
}
.chat-app .chat-popup-window {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 11;
background-color: rgba(255,255,255,0.97);
border-radius:3px;
/*display:none;*/
}
.chat-app .create-new-message-window input {
width: 50%;
margin-left: 25%;
margin-top: 90px;
height: 50px;
padding-left: 15px;
border: 1px solid #ccc;
border-radius: 5px;
outline:none;
}
.chat-app .close-chat-popup-window {
width: 50px;
height: 50px;
border: 1px solid #ccc;
border-radius: 100%;
text-align: center;
line-height: 50px;
position: absolute;
right: 20px;
top: 20px;
font-size: 14px;
color: #a2a2a2;
cursor:pointer;
}
.chat-app .close-chat-popup-window:hover {
background-color:#efefef;
color:#000000;
}
.chat-app .create-new-message-window .search-results, .chat-app .add-user-unit .search-results {
width: 50%;
margin-left: 25%;
margin-top: 25px;
height: calc(100% - 165px);
overflow: auto;
}
.chat-app .create-new-message-window .search-results .user, .chat-app .add-user-unit .search-results .user {
width: 100%;
display: inline-block;
padding: 10px;
border-radius: 3px;
cursor:pointer;
}
.chat-app .create-new-message-window .search-results .user:hover, .chat-app .add-user-unit .search-results .user:hover{
background-color:#efefef;
}
.chat-app .create-new-message-window .search-results .user img, .chat-app .add-user-unit .search-results .user img{
width: 45px;
height: 45px;
border-radius: 100%;
float: left;
}
.chat-app .create-new-message-window .search-results .user .user-name, .chat-app .add-user-unit .search-results .user .user-name {
float: left;
margin-left: 15px;
font-family: 'robotobold';
font-size: 18px;
margin-top: 9px;
}
.chat-app-button {
display: block;
position: fixed;
bottom: 20px;
right: 20px;
background: white;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
padding: 0;
z-index: 1000;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
text-align: center;
cursor: pointer;
}
.chat-app-button i {
top: 16px;
color: #333;
font-size: 20px;
}
.chat-app .create-new-channel-window h3 {
width: 400px;
margin-left: auto;
margin-right: auto;
margin-top: 30px;
}
.chat-app .create-new-channel-window .text-center input {
width: 400px;
margin-top: 40px;
height: 50px;
padding-left: 15px;
border: 1px solid #ccc;
border-radius: 5px;
outline: none;
}
.chat-app .create-new-channel-window .text-center textarea {
width: 400px;
margin: 20px;
height: 110px;
padding-left: 15px;
padding-top: 15px;
border: 1px solid rgb(204, 204, 204);
border-radius: 5px;
outline: none;
max-width: 400px;
max-height:200px;
}
.chat-app .create-new-channel-window button {
width: 400px;
margin-top:0px;
height: 50px;
font-size: 19px;
}
.chat-app .add-user-unit h3 {
width: 400px;
margin-left: auto;
margin-right: auto;
margin-top: 30px;
}
.chat-app .add-user-unit input {
width: 400px;
margin-top: 10px;
height: 50px;
padding-left: 15px;
border: 1px solid #ccc;
border-radius: 5px;
outline: none;
}
.chat-app .add-user-unit .checkbox-inline {
width: 50%;
margin-left: 25%;
margin-top: 20px;
padding-left: 25px;
border: none;
}
.chat-app .add-user-unit .checkbox-inline input {
width: 20px;
margin-top: 0;
margin-left: -25px;
border: none;
height: 20px;
}
.chat-app-close-btn {
display: block;
position: absolute;
right: 5px;
top: 5px;
}
.chat-app-button {
display: block;
position: fixed;
bottom: 20px;
right: 20px;
background: white;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
padding: 0;
z-index: 9999;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
}
.chat-app-button i {
margin-top: 3px;
font-size: 18px;
}
/* END OF CHAT APPLICATION */
/* COURSE PROGRAM SCHEDULER */
.course-prg-scheduler {
margin:15px !important;
margin-left:0 !important;
}
.course-prg-scheduler .panel-body {
height: 550px;
}
.course-prg-scheduler .tabs-container {
overflow-y: auto;
height: 550px;
}
.course-prg-scheduler .tabs-left {
margin-right: 10px;
border-right: 1px solid #dddddf;
padding: 20px 0 20px 10px !important;
min-height: 550px;
}
.course-prg-scheduler ul.tabs-left li {
border-radius: 5px 0 0 5px;
border: 1px solid #fff;
border-right-color: #dddddf;
position: relative;
right: -1px;
}
.course-prg-scheduler ul.tabs-left li.active, .course-prg-scheduler ul.tabs-left li:hover {
border: 1px solid #dddddf;
border-right-color: #fff;
}
.course-prg-scheduler .tab-content {
padding: 25px 10px 25px 40px;
}
.course-prg-scheduler ul.tabs-left li.active a {
color: #bc1e2d;
}
.course-prg-scheduler ul.tabs-left li a:hover {
background: none;
cursor: pointer;
}
.course-prg-scheduler .tab-content .info-header {
margin-bottom: 30px;
}
.course-prg-scheduler .tab-content .info-header .info-wrapper {
float:left;
margin-right:45px;
height: 50px;
line-height: 50px;
}
.course-prg-scheduler .tab-content .info-header .info-wrapper .user-name {
font-family:'robotobold';
font-size: 17px;
color: #444;
margin-left: 10px;
}
.course-prg-scheduler .tab-content .info-wrapper.info-wrapper_hours {
font-size: 17px;
color: #444;
}
.course-prg-scheduler .tab-content .info-wrapper.info-wrapper_hours .info-title {
font-family:'robotobold';
}
.course-prg-scheduler .tab-content .info-header .info-wrapper .btn {
margin-top:8px;
}
.course-prg-scheduler .tab-content .info-header .profile-pic {
width: 50px;
height: 50px;
border-radius: 100%;
margin-right:7px;
}
.course-prg-scheduler .tab-content .table-warning {
background-color: #dedede;
padding: 10px 15px;
border-radius: 2px;
font-size: 15px;
font-weight: normal;
color: #444;
display: inline-block;
margin: 0 auto 15px auto;
}
.course-prg-scheduler .tab-content .table-warning .icon {
color: #8e8e8e;
font-size: 20px;
float: left;
margin-right: 10px;
}
.course-prg-scheduler .tab-content .table-container {
max-height: 350px;
overflow-y: auto;
}
.course-prg-scheduler .tab-content table tr.headers td {
font-family:'robotobold';
font-size: 16px;
}
.course-prg-scheduler .tab-content table , .course-prg-scheduler .tab-content th, .course-prg-scheduler .tab-content td {
border: 1px solid black;
}
.course-prg-scheduler .tab-content table tr td:first-child {
font-size: 14px;
/*font-family:'robotobold';*/
width: 180px;
/*background-color:#f9f9f9;*/
}
.course-prg-scheduler .tab-content table td {
width: 100px;
height: 70px;
text-align:center;
}
.course-prg-scheduler .loader {
margin-top: 25px;
}
.course-prg-scheduler ul.legend {
margin-top: 15px;
}
.course-prg-scheduler ul.legend li {
border: none;
display: inline-block;
padding: 15px 10px;
}
.course-prg-scheduler ul.legend li .action-indicator {
margin-right: 5px;
}
.course-prg-scheduler .action-indicator {
border: 10px solid #eee;
border-radius: 10px;
display: inline-block;
height: 10px;
width: 10px;
vertical-align: middle;
}
.course-prg-scheduler .action-indicator.action-indicator_appropriate {
border-color: #8ac73e;
}
.course-prg-scheduler .action-indicator.action-indicator_busy{
border-color: #ed1b24;
}
.course-prg-scheduler .action-indicator.action-indicator_uncertain {
border-color: #f7941d;
}
.course-prg-scheduler .action-selector {
display: inline-block;
position: relative;
padding-right: 15px;
cursor: pointer;
right: -7px;
}
.course-prg-scheduler .action-selector:after {
content: ' ';
display: block;
position: absolute;
top: 50%;
right: 0;
margin-top: -2px;
width: 0;
height: 0;
border-style: solid;
border-width: 5px 5px 0 5px;
border-color: #808080 transparent transparent transparent;
}
.course-prg-scheduler .action-selector.readonly {
right: 0;
padding-right: 0;
cursor: default;
}
.course-prg-scheduler .action-selector.readonly:after {
display: none;
}
.course-prg-scheduler .action-selector .popover {
display: block;
top: 25px;
left: -19px;
height: 120px;
}
.course-prg-scheduler .action-selector .popover .popover-content {
padding: 0 0 10px;
}
.course-prg-scheduler .action-selector .popover ul.actions-selector-select li {
padding: 7px 17px;
border-bottom: 1px solid #dddddf;
}
.course-prg-scheduler .action-selector .popover ul.actions-selector-select li:hover {
background-color: #f9f9f9;
}
.course-prg-scheduler .action-selector ul.actions-selector-select li:last-child {
border-bottom: none;
}
/* END OF COURSE PROGRAM SCHEDULER */
/* Responsive: Portrait tablets and up */
@media screen and (min-width: 768px) {
/* Remove the padding we set earlier */
.header,
.marketing,
.footer {
padding-left: 0;
padding-right: 0;
}
/* Space out the masthead */
.header {
margin-bottom: 30px;
}
/* Remove the bottom border on the jumbotron for visual effect */
.jumbotron {
border-bottom: 0;
}
.sidebar {
z-index: 1;
position: absolute;
overflow-y: auto;
width: 250px;
height: 100%;
-webkit-box-shadow: 0 0 25px rgba(0,0,0,0.1);
-moz-box-shadow: 0 0 25px rgba(0,0,0,0.1);
box-shadow: 0 0 25px rgba(0,0,0,0.1);
}
.navbar-top-links .dropdown-messages,
.navbar-top-links .dropdown-tasks,
.navbar-top-links .dropdown-alerts {
margin-left: auto;
}
.container {
max-width: 730px;
}
.manager-view {
height:100%;
}
.sidebar .sidebar-nav.navbar-collapse {
overflow-x: visible;
/*overflow-y: auto;*/
/*position: absolute;*/
width: 100%;
/*max-height: calc(50% - 139px);*/
}
.sidebar-container {
max-height: calc(100% - 120px); overflow-y: auto;
}
footer {
position: absolute;
bottom: 35px;
padding: 15px;
width:100%;
text-align:center;
}
footer span {
font-family:'robotobold';
color:#777;
}
}
@media (max-width: 767px) {
.manager-view {
width:100%;
}
ul.timeline:before {
left: 40px;
}
ul.timeline > li > .timeline-panel {
width: calc(100% - 90px);
width: -moz-calc(100% - 90px);
width: -webkit-calc(100% - 90px);
}
ul.timeline > li > .timeline-badge {
top: 16px;
left: 15px;
margin-left: 0;
}
ul.timeline > li > .timeline-panel {
float: right;
}
ul.timeline > li > .timeline-panel:before {
right: auto;
left: -15px;
border-right-width: 15px;
border-left-width: 0;
}
ul.timeline > li > .timeline-panel:after {
right: auto;
left: -14px;
border-right-width: 14px;
border-left-width: 0;
}
.sidebar {
width:100% !important;
}
.brand,
footer {
display:none;
}
.logo img {
width:200px;
margin-left:0;
}
.manager-view-content {
overflow:inherit;
}
body {
overflow:auto;
}
.sidebar-collapse-button {
display:none;
}
.right-sidebar {
display: none;
}
}
@media (max-width: 1350px) {
.personnel-info-container {
width:700px;
}
.personnel-info-right {
width:450px;
}
}
@media (max-width: 1000px) {
.personnel-info-container {
width:500px;
height:auto;
}
.personnel-info-left {
width:100%;
position:relative;
height:auto;
border:none;
}
.personnel-info-right {
width:100%;
position:relative;
height:auto;
}
.generic-profile-picture,
.personnel-info-left ul li:nth-child(1),
.personnel-info-left ul li:nth-child(2) {
text-align:center;
}
.generic-profile-picture img {
border-radius:100%;
}
}
@media (max-width: 560px) {
.personnel-info-container {
width: 350px;
}
}
@media (max-width: 991px) {
.dashboard .major-buttons a button {
margin-bottom:20px;
}
}
.tablescroll{
width: 100%;
overflow-x:auto;
overflow-y:visible;
padding-bottom:1px;
}
.tablescrollfixleft {
position:absolute;
left:0;
top:auto;
}
.tablescrollfixleft {
position:absolute;
right:0;
top:auto;
} }
...@@ -1827,4 +3300,37 @@ table.dataTable thead .sorting:after { ...@@ -1827,4 +3300,37 @@ table.dataTable thead .sorting:after {
filter: alpha(opacity=0); filter: alpha(opacity=0);
} }
/* end file upload */ /* end file upload */
\ No newline at end of file
.mid-h3 {
text-align: center;
margin-bottom: 20px;
color: #636363 ;
}
#toast-container {
margin-top: 90px;
}
.crud-mask {
width: 100%;
height: 100%;
background: #fff;
position: absolute;
top:43px; left:0;
z-index: 1000;
}
.body-mask {
width: 100%;
height: 100%;
background: #fff;
position: absolute;
top:0; left:0;
z-index: 1099;
}
/* for overflowing buttons not collapsing each other */
.bottom-margined{
margin-bottom: 0.75em;
}
...@@ -22,12 +22,13 @@ ...@@ -22,12 +22,13 @@
*/ */
angular.module( angular.module(
'ulakbus', [ 'ulakbus', [
'ui.bootstrap', //'ui.bootstrap',
'angular-loading-bar', 'angular-loading-bar',
'ngRoute', 'ngRoute',
'ngSanitize', 'ngSanitize',
'ngCookies', 'ngCookies',
'ulakbus.formService', 'ulakbus.formService',
'ulakbus.messaging',
'ulakbus.dashboard', 'ulakbus.dashboard',
'ulakbus.auth', 'ulakbus.auth',
'ulakbus.error_pages', 'ulakbus.error_pages',
...@@ -35,8 +36,8 @@ angular.module( ...@@ -35,8 +36,8 @@ angular.module(
'ulakbus.debug', 'ulakbus.debug',
'ulakbus.devSettings', 'ulakbus.devSettings',
'ulakbus.version', 'ulakbus.version',
//'schemaForm',
'gettext', 'gettext',
'markdown',
'ulakbus.uitemplates' 'ulakbus.uitemplates'
]) ])
/** /**
...@@ -48,6 +49,7 @@ angular.module( ...@@ -48,6 +49,7 @@ angular.module(
* *
* For development needs backendurl can be switched from both dev/settings page and querystring `?backendurl=http://example.com` * For development needs backendurl can be switched from both dev/settings page and querystring `?backendurl=http://example.com`
*/ */
// todo: convert it to service
.constant("RESTURL", (function () { .constant("RESTURL", (function () {
// todo: below backendurl definition is for development purpose and will be deleted // todo: below backendurl definition is for development purpose and will be deleted
var backendurl = location.href.indexOf('nightly') > -1 ? "//nightly.api.ulakbus.net/" : "//api.ulakbus.net/"; var backendurl = location.href.indexOf('nightly') > -1 ? "//nightly.api.ulakbus.net/" : "//api.ulakbus.net/";
...@@ -56,6 +58,8 @@ angular.module( ...@@ -56,6 +58,8 @@ angular.module(
angular.forEach(cookiearray, function (item) { angular.forEach(cookiearray, function (item) {
if (item.indexOf("backendurl") > -1) { if (item.indexOf("backendurl") > -1) {
backendurl = item.split('=')[1]; backendurl = item.split('=')[1];
if (backendurl.slice(-1) !== '/') {backendurl += '/'}
if (backendurl.substring(0,4) !== 'http') {backendurl = 'http://'+backendurl}
} }
}); });
} }
...@@ -63,12 +67,73 @@ angular.module( ...@@ -63,12 +67,73 @@ angular.module(
if (location.href.indexOf("backendurl") > -1) { if (location.href.indexOf("backendurl") > -1) {
var urlfromqstr = location.href.split('?')[1].split('=')[1]; var urlfromqstr = location.href.split('?')[1].split('=')[1];
backendurl = decodeURIComponent(urlfromqstr.replace(/\+/g, " ")); backendurl = decodeURIComponent(urlfromqstr.replace(/\+/g, " "));
if (backendurl.slice(-1) !== '/') {backendurl += '/'}
if (backendurl.substring(0,4) !== 'http') {backendurl = 'http://'+backendurl}
document.cookie = "backendurl=" + backendurl; document.cookie = "backendurl=" + backendurl;
window.location.href = window.location.href.split('?')[0]; window.location.href = window.location.href.split('?')[0];
} }
return {url: backendurl}; return {url: backendurl};
})()) })())
.factory('IsOnline', function ($window, $document, $rootScope) {
var isOnlineService = {};
isOnlineService.status = true;
var offlineMask = angular.element(
'<div class="body-mask" style="z-index: 2010; opacity: 0.6">' +
'<div class="alert alert-danger text-center" role="alert" style="z-index: 2011; position: relative">' +
'İnternet bağlantınız kesilmiştir. Bağlantı sağlandığında kaldığınız yerden devam edebilirsiniz.' +
'</div>' +
'</div>'
);
var body = $document.find('body').eq(0);
isOnlineService.set_status = function (state) {
// status changed
if (state != isOnlineService.status){
// online
if (state){
offlineMask.remove();
// is user is set, reload page to init
if ($rootScope.current_user === true){
window.location.reload();
}
}
// offline
else {
body.append(offlineMask);
}
}
isOnlineService.status = state;
};
isOnlineService.get_status = function () {
return isOnlineService.status;
};
return isOnlineService;
})
// .service('DESIGN', function ($routeParams, $cookies, $log) {
// // use route param to change cookie for design
// // this is a config as a service added for designer can work without backend
// try {
// if (angular.isDefined($routeParams.design) || location.hash.split('?')[1].split('=')[1]) {
// $cookies.put('design', $routeParams.design || location.hash.split('?')[1].split('=')[1]);
// }
// } catch (e){
// $log.error("Error for design parameter", e);
// }
// return $cookies.get('design') === 'true' ? {switch: true} : {switch: false};
// })
.constant('toastr', window.toastr)
.constant('WS', window.WebSocket)
.config(function ($logProvider) { .config(function ($logProvider) {
$logProvider.debugEnabled(true); $logProvider.debugEnabled(true);
}); })
\ No newline at end of file .config(function(markdownProvider) {
//markdownProvider.config({
// extensions: ['table']
//});
});
...@@ -5,54 +5,73 @@ angular.module('ulakbus') ...@@ -5,54 +5,73 @@ angular.module('ulakbus')
$routeProvider $routeProvider
.when('/login', { .when('/login', {
templateUrl: 'components/auth/login.html', templateUrl: 'components/auth/login.html',
controller: 'LoginCtrl' controller: 'LoginController'
}) })
.when('/dashboard', { .when('/dashboard', {
templateUrl: 'components/dashboard/dashboard.html', templateUrl: 'components/dashboard/dashboard.html',
controller: 'DashCtrl' controller: 'DashController'
}) })
.when('/dev/settings', { .when('/dev/settings', {
templateUrl: 'components/devSettings/devSettings.html', templateUrl: 'components/devSettings/devSettings.html',
controller: 'DevSettingsCtrl' controller: 'DevSettingsController'
}) })
.when('/debug/list', { .when('/debug/list', {
templateUrl: 'components/debug/debug.html', templateUrl: 'components/debug/debug.html',
controller: 'DebugCtrl' controller: 'DebugController'
})
.when('/admin/bpmnmanager', {
templateUrl: 'components/admin/bpmn_manager.html',
controller: 'BpmnManagerController'
})
.when('/newdesigns', {
templateUrl: 'components/uitemplates/base.html',
controller: 'NewDesignsCtrl'
})
.when('/formservicepg', {
templateUrl: 'components/uitemplates/form_service_pg.html',
controller: 'FormServicePg'
}) })
// use crud without selected user // use crud without selected user
// important: regex urls must be defined later than static ones // important: regex urls must be defined later than static ones
.when('/:wf/', { .when('/:wf/', {
templateUrl: 'components/crud/templates/crud-preload.html',
controller: 'CRUDController'
})
.when('/cwf/:wf/:token', {
templateUrl: 'components/crud/templates/crud.html', templateUrl: 'components/crud/templates/crud.html',
controller: 'CRUDCtrl' controller: 'CRUDController'
}) })
.when('/:wf/do/:cmd', { .when('/:wf/do/:cmd', {
templateUrl: 'components/crud/templates/crud.html', templateUrl: 'components/crud/templates/crud.html',
controller: 'CRUDListFormCtrl' controller: 'CRUDListFormController'
}) })
.when('/:wf/do/:cmd/:key', { .when('/:wf/do/:cmd/:key', {
templateUrl: 'components/crud/templates/crud.html', templateUrl: 'components/crud/templates/crud.html',
controller: 'CRUDListFormCtrl' controller: 'CRUDListFormController'
}) })
.when('/:wf/:model', { .when('/:wf/:model', {
templateUrl: 'components/crud/templates/crud.html', templateUrl: 'components/crud/templates/crud-preload.html',
controller: 'CRUDCtrl' controller: 'CRUDController'
}) })
.when('/:wf/:model/do/:cmd', { .when('/:wf/:model/do/:cmd', {
templateUrl: 'components/crud/templates/crud.html', templateUrl: 'components/crud/templates/crud.html',
controller: 'CRUDListFormCtrl' controller: 'CRUDListFormController'
}) })
.when('/:wf/:model/do/:cmd/:key', { .when('/:wf/:model/do/:cmd/:key', {
templateUrl: 'components/crud/templates/crud.html', templateUrl: 'components/crud/templates/crud.html',
controller: 'CRUDListFormCtrl' controller: 'CRUDListFormController'
}) })
.otherwise({redirectTo: '/dashboard'}); .otherwise({redirectTo: '/dashboard'});
}]) }])
.run(function ($rootScope) {
$rootScope.loggedInUser = true; .run(function ($rootScope, AuthService) {
AuthService.check_auth();
$rootScope.loggedInUser = false;
$rootScope.loginAttempt = 0; $rootScope.loginAttempt = 0;
$rootScope.websocketIsOpen = false;
$rootScope.current_user = true;
$rootScope.$on("$routeChangeStart", function (event, next, current) { $rootScope.$on("$routeChangeStart", function (event, next, current) {
// will be used when needed // will be used when needed
}); });
...@@ -72,4 +91,4 @@ angular.module('ulakbus') ...@@ -72,4 +91,4 @@ angular.module('ulakbus')
cfpLoadingBarProvider.parentSelector = "loaderdiv"; cfpLoadingBarProvider.parentSelector = "loaderdiv";
// loader template will be used when loader initialized // loader template will be used when loader initialized
cfpLoadingBarProvider.spinnerTemplate = '<div class="loader">Loading...</div>'; cfpLoadingBarProvider.spinnerTemplate = '<div class="loader">Loading...</div>';
}]); }]);
\ No newline at end of file
<div class="content" id="js-drop-zone">
<div class="message intro">
<div class="note">
Drop BPMN diagram from your desktop or <a id="js-create-diagram" href>create a new diagram</a> to get started.
</div>
</div>
<div class="message error">
<div class="note">
<p>Ooops, we could not display the BPMN 2.0 diagram.</p>
<div class="details">
<span>cause of the problem</span>
<pre></pre>
</div>
</div>
</div>
<div class="canvas" id="js-canvas"></div>
<div id="js-properties-panel"></div>
</div>
<ul class="buttons">
<li>
download
</li>
<li>
<a id="js-download-diagram" href title="download BPMN diagram">
BPMN diagram
</a>
</li>
<li>
<a id="js-download-svg" href title="download as SVG image">
SVG image
</a>
</li>
</ul>
\ No newline at end of file
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
angular.module('ulakbus')
//.constant('require', require)
.controller('BpmnManagerController', function ($scope) {
var fs = require('fs');
var $ = require('jquery'),
BpmnModeler = require('bpmn-js/lib/Modeler');
var propertiesPanelModule = require('bpmn-js-properties-panel'),
propertiesProviderModule = require('bpmn-js-properties-panel/lib/provider/camunda'),
camundaModdleDescriptor = require('camunda-bpmn-moddle/resources/camunda');
var container = $('#js-drop-zone');
var canvas = $('#js-canvas');
var bpmnModeler = new BpmnModeler({
container: canvas,
propertiesPanel: {
parent: '#js-properties-panel'
},
additionalModules: [
propertiesPanelModule,
propertiesProviderModule
],
moddleExtensions: {
camunda: camundaModdleDescriptor
}
});
var newDiagramXML = fs.readFileSync(__dirname + 'new.bpmn', 'utf-8');
function createNewDiagram() {
openDiagram(newDiagramXML);
}
function openDiagram(xml) {
bpmnModeler.importXML(xml, function (err) {
if (err) {
container
.removeClass('with-diagram')
.addClass('with-error');
container.find('.error pre').text(err.message);
console.error(err);
} else {
container
.removeClass('with-error')
.addClass('with-diagram');
}
});
}
function saveSVG(done) {
bpmnModeler.saveSVG(done);
}
function saveDiagram(done) {
bpmnModeler.saveXML({format: true}, function (err, xml) {
done(err, xml);
});
}
function registerFileDrop(container, callback) {
function handleFileSelect(e) {
e.stopPropagation();
e.preventDefault();
var files = e.dataTransfer.files;
var file = files[0];
var reader = new FileReader();
reader.onload = function (e) {
var xml = e.target.result;
callback(xml);
};
reader.readAsText(file);
}
function handleDragOver(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}
container.get(0).addEventListener('dragover', handleDragOver, false);
container.get(0).addEventListener('drop', handleFileSelect, false);
}
if (!window.FileList || !window.FileReader) {
window.alert(
'Looks like you use an older browser that does not support drag and drop. ' +
'Try using Chrome, Firefox or the Internet Explorer > 10.');
} else {
registerFileDrop(container, openDiagram);
}
$(document).on('ready', function () {
$('#js-create-diagram').click(function (e) {
e.stopPropagation();
e.preventDefault();
createNewDiagram();
});
var downloadLink = $('#js-download-diagram');
var downloadSvgLink = $('#js-download-svg');
$('.buttons a').click(function (e) {
if (!$(this).is('.active')) {
e.preventDefault();
e.stopPropagation();
}
});
function setEncoded(link, name, data) {
var encodedData = encodeURIComponent(data);
if (data) {
link.addClass('active').attr({
'href': 'data:application/bpmn20-xml;charset=UTF-8,' + encodedData,
'download': name
});
} else {
link.removeClass('active');
}
}
var debounce = require('lodash/function/debounce');
var exportArtifacts = debounce(function () {
saveSVG(function (err, svg) {
setEncoded(downloadSvgLink, 'diagram.svg', err ? null : svg);
});
saveDiagram(function (err, xml) {
setEncoded(downloadLink, 'diagram.bpmn', err ? null : xml);
});
}, 500);
bpmnModeler.on('commandStack.changed', exportArtifacts);
});
});
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="sample-diagram" targetNamespace="http://bpmn.io/schema/bpmn">
<bpmn2:process id="Process_1" isExecutable="false">
<bpmn2:startEvent id="StartEvent_1"/>
</bpmn2:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
<dc:Bounds height="36.0" width="36.0" x="412.0" y="240.0"/>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</bpmn2:definitions>
\ No newline at end of file
...@@ -25,11 +25,15 @@ angular.module('ulakbus.auth', ['ngRoute', 'ngCookies']) ...@@ -25,11 +25,15 @@ angular.module('ulakbus.auth', ['ngRoute', 'ngCookies'])
* @description LoginCtrl responsible to handle login process.<br> * @description LoginCtrl responsible to handle login process.<br>
* Using 'ulakbus.formService.get_form' function generates the login form and post it to the API with input datas. * Using 'ulakbus.formService.get_form' function generates the login form and post it to the API with input datas.
*/ */
.controller('LoginCtrl', function ($scope, $q, $timeout, $routeParams, $rootScope, $log, Generator, AuthService) { .controller('LoginController', function ($scope, $q, $timeout, $location, $routeParams, $rootScope, $log, WSOps, Generator, AuthService) {
$scope.url = 'login'; $scope.url = 'login';
$scope.form_params = {}; $scope.form_params = {};
$scope.form_params['clear_wf'] = 1; $scope.form_params['clear_wf'] = 1;
Generator.get_form($scope).then(function (data) { // if websocket status is open ---> ws close
try {WSOps.close()}
catch (e) {$log.error(e.message)}
AuthService.get_form($scope).then(function (data) {
if (data.login) { $location.path('/'); }
$scope.form = [ $scope.form = [
{key: "username", type: "string", title: "Kullanıcı Adı"}, {key: "username", type: "string", title: "Kullanıcı Adı"},
{key: "password", type: "password", title: "Şifre"}, {key: "password", type: "password", title: "Şifre"},
...@@ -44,13 +48,17 @@ angular.module('ulakbus.auth', ['ngRoute', 'ngCookies']) ...@@ -44,13 +48,17 @@ angular.module('ulakbus.auth', ['ngRoute', 'ngCookies'])
$rootScope.loginAttempt = 1; $rootScope.loginAttempt = 1;
Generator.button_switch(false); Generator.button_switch(false);
AuthService.login($scope.url, $scope.model) AuthService.login($scope.url, $scope.model)
.success(function (data) {
$scope.message = data.title;
$scope.loggingIn = false;
})
.error(function (data) { .error(function (data) {
$scope.message = data.title; $scope.message = data.title;
$scope.loggingIn = false; $scope.loggingIn = false;
}) })
.then(function () { .then(function () {
$scope.loggingIn = false; $scope.loggingIn = false;
Generator.button_switch(false); Generator.button_switch(true);
}) })
} }
else { else {
......
...@@ -15,9 +15,31 @@ angular.module('ulakbus.auth') ...@@ -15,9 +15,31 @@ angular.module('ulakbus.auth')
* @name AuthService * @name AuthService
* @description provides generic functions for authorization process. * @description provides generic functions for authorization process.
*/ */
.factory('AuthService', function ($http, $rootScope, $location, $log, Generator, RESTURL) { .factory('AuthService', function ($http, $rootScope, $location, $log, $route, Generator, RESTURL, WSOps) {
var authService = {}; var authService = {};
authService.get_form = function (scope) {
return $http
.post(Generator.makeUrl(scope), scope.form_params)
.success(function (data, status, headers, config) {
// if response data.cmd is 'upgrade'
if (data.cmd === 'upgrade') {
$rootScope.loggedInUser = true;
$rootScope.$broadcast("user_ready");
$rootScope.$broadcast("ws_turn_on");
return $location.path('/dashboard');
}
if (data.cmd === 'retry') {
$location.path('/login');
} else{
if (angular.isDefined(data.forms) && $location.path() !== '/login'){
$location.path('/login');
}
return Generator.generate(scope, data);
}
});
};
/** /**
* @memberof ulakbus.auth * @memberof ulakbus.auth
* @ngdoc function * @ngdoc function
...@@ -35,12 +57,23 @@ angular.module('ulakbus.auth') ...@@ -35,12 +57,23 @@ angular.module('ulakbus.auth')
.post(RESTURL.url + url, credentials) .post(RESTURL.url + url, credentials)
.success(function (data, status, headers, config) { .success(function (data, status, headers, config) {
//$window.sessionStorage.token = data.token; //$window.sessionStorage.token = data.token;
Generator.button_switch(true);
$rootScope.loggedInUser = true; if (data.cmd === 'upgrade') {
$rootScope.loggedInUser = true;
// $rootScope.$broadcast("regenerate_menu");
// to display main view without flickering
$rootScope.$broadcast("user_ready");
$rootScope.$broadcast("ws_turn_on");
$location.path('/dashboard');
}
if (data.status_code === 403) {
data.title = "İşlem başarısız oldu. Lütfen girdiğiniz bilgileri kontrol ediniz.";
return data;
}
}) })
.error(function (data, status, headers, config) { .error(function (data, status, headers, config) {
// Handle login errors here // Handle login errors here
data.title = "İşlem başarısız oldu. Lütfen girdiğiniz bilgileri kontrol ediniz." data.title = "İşlem başarısız oldu. Lütfen girdiğiniz bilgileri kontrol ediniz.";
return data; return data;
}); });
}; };
...@@ -54,13 +87,21 @@ angular.module('ulakbus.auth') ...@@ -54,13 +87,21 @@ angular.module('ulakbus.auth')
* @returns {*} * @returns {*}
*/ */
authService.logout = function () { authService.logout = function () {
$log.debug("logout");
return $http.post(RESTURL.url + 'logout', {}).success(function (data) { $rootScope.loginAttempt = 0;
WSOps.request({wf: 'logout'}).then(function (data) {
$rootScope.loggedInUser = false; $rootScope.loggedInUser = false;
$rootScope.current_user = true;
$log.debug("loggedout"); $log.debug("loggedout");
$location.path("/login"); $location.path("/login");
WSOps.close();
}); });
}; };
authService.check_auth = function () {
var post_data = {url: 'login', form_params:{}};
return authService.get_form(post_data);
};
return authService; return authService;
}); });
\ No newline at end of file
...@@ -33,7 +33,7 @@ describe('ulakbus.auth module', function () { ...@@ -33,7 +33,7 @@ describe('ulakbus.auth module', function () {
describe('login controller and service', function () { describe('login controller and service', function () {
it('should have a login controller', inject(function () { it('should have a login controller', inject(function () {
expect('ulakbus.auth.LoginCtrl').toBeDefined(); expect('ulakbus.auth.LoginController').toBeDefined();
})); }));
it('should get login form', inject( it('should get login form', inject(
...@@ -44,7 +44,7 @@ describe('ulakbus.auth module', function () { ...@@ -44,7 +44,7 @@ describe('ulakbus.auth module', function () {
var $scope = $rootScope.$new(); var $scope = $rootScope.$new();
$scope['url'] = 'login'; $scope['url'] = 'login';
$scope['form_params'] = {clear_wf: 1}; $scope['form_params'] = {clear_wf: 1};
var controller = $controller('LoginCtrl', {$scope: $scope}); var controller = $controller('LoginController', {$scope: $scope});
expect($scope.onSubmit).toBeDefined(); expect($scope.onSubmit).toBeDefined();
}) })
......
<div ng-app="ulakbus.auth" class="container"> <div style="width: 100%; height: 100%; position: fixed; z-index: 1100; top:0; left:0; background: #fff;">
<div class="row"> <div ng-app="ulakbus.auth" class="container">
<div class="col-md-4 col-md-offset-4"> <div class="row">
<div class="login-panel panel panel-default"> <div class="col-md-6 col-md-offset-3">
<div class="panel-heading"> <div class="login-panel panel panel-default">
<h3 class="panel-title">Giriş Yap <span ng-if="loggingIn" class="loader pull-right"></span></h3> <div class="panel-heading">
</div> <h3 class="panel-title">Giriş Yap <span ng-if="loggingIn" class="loader pull-right"></span></h3>
<div class="panel-body"> </div>
<span class="label label-warning">{{message}}</span> <div class="panel-body">
<form name="loginForm" sf-schema="schema" sf-form="form" sf-model="model" ng-submit="onSubmit(loginForm)"></form> <form name="loginForm" sf-schema="schema" sf-form="form" sf-model="model"
ng-submit="onSubmit(loginForm)"></form>
</div>
</div> </div>
<span class="label label-inverse label-warning">{{message}}</span>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* @requires ulakbus.formService * @requires ulakbus.formService
* @type {ng.$compileProvider|*} * @type {ng.$compileProvider|*}
*/ */
angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formService']) angular.module('ulakbus.crud', ['schemaForm', 'ui.bootstrap', 'ulakbus.formService'])
.config(function (sfErrorMessageProvider) { .config(function (sfErrorMessageProvider) {
sfErrorMessageProvider.setDefaultMessage(302, 'Bu alan zorunludur.'); sfErrorMessageProvider.setDefaultMessage(302, 'Bu alan zorunludur.');
sfErrorMessageProvider.setDefaultMessage(200, 'En az {{schema.minLength}} değer giriniz.'); sfErrorMessageProvider.setDefaultMessage(200, 'En az {{schema.minLength}} değer giriniz.');
...@@ -41,7 +41,8 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -41,7 +41,8 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
* @memberof ulakbus.crud * @memberof ulakbus.crud
* @ngdoc function * @ngdoc function
* @name generateParam * @name generateParam
* @description generateParam is a function to generate required params to post backend api. * @description generateParam is a function to generate required params to send backend api.
* backend needs that params to work without errors
* @param {object} scope * @param {object} scope
* @param {object} routeParams * @param {object} routeParams
* @param {string} cmd * @param {string} cmd
...@@ -59,12 +60,16 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -59,12 +60,16 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
scope.form_params = { scope.form_params = {
//cmd: cmd, //cmd: cmd,
// model name in ulakbus
model: routeParams.model, model: routeParams.model,
// generic value passing by backend. would be any of these: id, personel_id, etc.
param: scope.param || routeParams.param, param: scope.param || routeParams.param,
// generic value passing by backend. would be the value of param
id: scope.param_id || routeParams.param_id, id: scope.param_id || routeParams.param_id,
wf: routeParams.wf, wf: routeParams.wf,
object_id: routeParams.key, object_id: routeParams.key,
filters: {} filters: {},
token: routeParams.token
}; };
if (scope.param_id) { if (scope.param_id) {
...@@ -92,27 +97,65 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -92,27 +97,65 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
angular.forEach(pageData, function (value, key) { angular.forEach(pageData, function (value, key) {
scope[key] = value; scope[key] = value;
}); });
angular.forEach(scope.objects, function (value, key) { // when selective_list is sent with meta key it means
if (key > 0) { // "objects" is a list of "objects"s
var linkIndexes = {}; if (scope.meta['selective_listing'] === true) {
angular.forEach(value.actions, function (v, k) { angular.forEach(scope.objects, function (_v, _k) {
if (v.show_as === 'link') {linkIndexes = v} angular.forEach(_v.objects, function (value, key) {
}); if (_v.selected === true) {
angular.forEach(value.fields, function (v, k) { scope.selected_key = _k;
if (value.actions.length > 0 && linkIndexes.fields){
scope.objects[key].fields[k] = {
type: linkIndexes.fields.indexOf(k) > -1 ? 'link' : 'str',
content: v,
cmd: linkIndexes.cmd,
mode: linkIndexes.mode
};
} }
else { if (key > 0) {
scope.objects[key].fields[k] = {type: 'str', content: v}; var linkIndexes = {};
angular.forEach(value.actions, function (v, k) {
if (v.show_as === 'link') {linkIndexes = v}
});
angular.forEach(value.fields, function (v, k) {
try {
if (value.actions.length > 0 && linkIndexes.fields){
scope.objects[_k][key].fields[k] = {
type: linkIndexes.fields.indexOf(k) > -1 ? 'link' : 'str',
content: v,
cmd: linkIndexes.cmd,
mode: linkIndexes.mode
};
}
else {
scope.objects[_k]['objects'][key].fields[k] = {type: 'str', content: v};
}
} catch (e) {
$log.error(e);
scope.objects[_k]['objects'][key].fields[k] = {type: 'str', content: v};
}
});
} }
}); });
} });
}); } else {
angular.forEach(scope.objects, function (value, key) {
if (key > 0) {
var linkIndexes = {};
angular.forEach(value.actions, function (v, k) {
if (v.show_as === 'link') {linkIndexes = v}
});
angular.forEach(value.fields, function (v, k) {
if (value.actions.length > 0 && linkIndexes.fields){
scope.objects[key].fields[k] = {
type: linkIndexes.fields.indexOf(k) > -1 ? 'link' : 'str',
content: v,
cmd: linkIndexes.cmd,
mode: linkIndexes.mode
};
}
else {
scope.objects[key].fields[k] = {type: 'str', content: v};
}
});
}
});
}
$log.debug(scope.objects); $log.debug(scope.objects);
} }
} }
...@@ -128,8 +171,12 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -128,8 +171,12 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
* *
* @returns {object} * @returns {object}
*/ */
.controller('CRUDCtrl', function ($scope, $routeParams, Generator, CrudUtility) { .controller('CRUDController', function ($scope, $routeParams, $location, Generator, CrudUtility) {
// get required params by calling CrudUtility.generateParam function // get required params by calling CrudUtility.generateParam function
if ($location.url().indexOf('?=') > 0) {
return $location.url($location.url().replace('?=', ''));
}
// before calling get_wf parameters need to be generated with CrudUtility.generateParam
CrudUtility.generateParam($scope, $routeParams); CrudUtility.generateParam($scope, $routeParams);
Generator.get_wf($scope); Generator.get_wf($scope);
}) })
...@@ -137,8 +184,8 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -137,8 +184,8 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
/** /**
* @memberof ulakbus.crud * @memberof ulakbus.crud
* @ngdoc controller * @ngdoc controller
* @name CRUDListFormCtrl * @name CRUDListFormController
* @description CRUDListFormCtrl is the main controller for crud module * @description CRUDListFormController is the main controller for crud module
* Based on the client_cmd parameter it generates its scope items. * Based on the client_cmd parameter it generates its scope items.
* client_cmd can be in ['show', 'list', 'form', 'reload', 'refresh'] * client_cmd can be in ['show', 'list', 'form', 'reload', 'refresh']
* There are 3 directives to manipulate controllers scope objects in crud.html * There are 3 directives to manipulate controllers scope objects in crud.html
...@@ -152,18 +199,30 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -152,18 +199,30 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
* *
* @returns {object} * @returns {object}
*/ */
.controller('CRUDListFormCtrl', function ($scope, $rootScope, $location, $http, $log, $uibModal, $timeout, Generator, $routeParams, CrudUtility) { .controller('CRUDListFormController', function ($scope, $rootScope, $location, $sce, $http, $log, $uibModal, $timeout, Generator, $routeParams, CrudUtility) {
// reloadData must be a json object // below show crud and $on --> $viewContentLoaded callback is for masking the view with unrendered and ugly html
$scope.reload = function (reloadData) { $scope.show_crud = false;
$scope.form_params.cmd = $scope.reload_cmd; $scope.$on('$viewContentLoaded', function () {
$scope.form_params = angular.extend($scope.form_params, reloadData); $timeout(function () {
$log.debug('reload data', $scope); $scope.show_crud = true;
Generator.get_wf($scope); }, 500);
}; });
// todo: new feature wf_step is for to start a workflow from a certain step
$scope.wf_step = $routeParams.step;
// pagination data is coming from api when too much results
$scope.paginate = function (reloadData) {
$scope.form_params.cmd = $scope.reload_cmd;
$scope.form_params = angular.extend($scope.form_params, reloadData);
$log.debug('reload data', $scope);
Generator.get_wf($scope);
};
// reload_cmd can be broadcasted app-wide, when $on it reloadCmd is called
$scope.$on('reload_cmd', function(event, data){ $scope.$on('reload_cmd', function(event, data){
$scope.reload_cmd = data; $scope.reload_cmd = data;
$scope.reload({}); $scope.reloadCmd();
}); });
// search directive updates objects after search results // search directive updates objects after search results
...@@ -176,6 +235,7 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -176,6 +235,7 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
// object by its name. to manage to locate the form to controllers scope we use a directive called form locator // object by its name. to manage to locate the form to controllers scope we use a directive called form locator
// a bit dirty way to find form working on but solves our problem // a bit dirty way to find form working on but solves our problem
$scope.$on('formLocator', function (event) { $scope.$on('formLocator', function (event) {
$scope.formgenerated = event.targetScope.formgenerated; $scope.formgenerated = event.targetScope.formgenerated;
}); });
...@@ -183,7 +243,7 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -183,7 +243,7 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
$scope.remove = function (item, type, index) { $scope.remove = function (item, type, index) {
$scope[type][item.title].model.splice(index, 1); $scope[type][item.title].model.splice(index, 1);
$scope[type][item.title].items.splice(index, 1); $scope[type][item.title].items.splice(index, 1);
} };
$scope.onSubmit = function (form) { $scope.onSubmit = function (form) {
$scope.$broadcast('schemaFormValidate'); $scope.$broadcast('schemaFormValidate');
...@@ -193,7 +253,6 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -193,7 +253,6 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
}; };
$scope.do_action = function (key, todo) { $scope.do_action = function (key, todo) {
//Generator.doItemAction($scope, key, todo.cmd, todo.wf, todo.mode || 'normal');
Generator.doItemAction($scope, key, todo, todo.mode || 'normal'); Generator.doItemAction($scope, key, todo, todo.mode || 'normal');
}; };
...@@ -201,6 +260,23 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -201,6 +260,23 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
return new Array(num); return new Array(num);
}; };
$scope.markdownWorkaround = function (value) {
// this is new line workaround for markdown support
// kind of ugly hack
return value.replace('\n', '<br>');
};
// inline edit fields
$scope.datepickerstatuses = {};
$scope.inline_datepicker_status = function (field) {
return ($scope.datepickerstatuses[field] || false);
};
$scope.openDatepicker = function (field) {
$scope.datepickerstatuses[field] = true;
};
$scope.createListObjects = function () { $scope.createListObjects = function () {
if ($scope.object.constructor === Array) { if ($scope.object.constructor === Array) {
$log.debug('new type show object') $log.debug('new type show object')
...@@ -231,6 +307,12 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -231,6 +307,12 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
} }
$scope.createListObjects(); $scope.createListObjects();
}; };
// selective listing for list page todo: add to documentation
$scope.update_selective_list = function (key) {
$scope.objects = key["objects"];
};
// end of selective listing
$scope.listFormCmd = function () { $scope.listFormCmd = function () {
// function to set scope objects // function to set scope objects
var setpageobjects = function (data) { var setpageobjects = function (data) {
...@@ -260,13 +342,26 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -260,13 +342,26 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
if ($scope.object) { if ($scope.object) {
$scope.createListObjects(); $scope.createListObjects();
} }
// if selective listing then change objects key to its first item
if (angular.isDefined($scope.meta.selective_listing)) {
$scope.all_objects = angular.copy($scope.objects);
$scope.selective_list_key = $scope.all_objects[$scope.selected_key];
$scope.objects = $scope.selective_list_key["objects"];
}
}; };
$scope.reloadCmd = function () { $scope.reloadCmd = function () {
$scope.reload({}); var pageData = Generator.getPageData();
CrudUtility.generateParam($scope, pageData, $routeParams.cmd);
$log.debug('reload data', $scope);
Generator.get_wf($scope);
}; };
$scope.resetCmd = function () { $scope.resetCmd = function () {
var pageData = Generator.getPageData();
CrudUtility.generateParam($scope, pageData, $routeParams.cmd);
delete $scope.token; delete $scope.token;
$scope.cmd = 'reset'; delete $scope.filters;
delete $scope.cmd;
Generator.get_wf($scope); Generator.get_wf($scope);
}; };
...@@ -353,6 +448,7 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -353,6 +448,7 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
replace: true, replace: true,
link: function ($scope) { link: function ($scope) {
$scope.form_params.filters = $scope.form_params.filters || {}; $scope.form_params.filters = $scope.form_params.filters || {};
$scope.form_params.token = $scope.token;
$scope.filterList = {}; $scope.filterList = {};
$scope.filterCollapsed = {}; $scope.filterCollapsed = {};
$scope.$watch('list_filters', function () { $scope.$watch('list_filters', function () {
...@@ -387,4 +483,175 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi ...@@ -387,4 +483,175 @@ angular.module('ulakbus.crud', ['ui.bootstrap', 'schemaForm', 'ulakbus.formServi
} }
} }
}; };
}); })
\ No newline at end of file
.controller("crudTimetableDirectiveCtrl", function($scope, WSOps, $q){
// todo: replace with utils service method
function groupBy (list, propName) {
return list.reduce(function(acc, item) {
(acc[item[propName]] = acc[item[propName]] || []).push(item);
return acc;
}, {});
};
$scope.groupBy = groupBy;
$scope.get_wf = function get_wf(data){
var fieldName = $scope.mainFieldName || 'ogretim_elemani_zt';
data.token = $scope.token;
data.wf = $scope.wf;
return WSOps.request(data).then(function(result){
if (result[fieldName]){
return result;
}
Generator.pathDecider(result.client_cmd || ['list'], $scope, result);
// prevent result processing
return $q.reject();
}).then(function(result){
$scope.message = result.notification;
return result[fieldName]
})
}
$scope.prepareTimetable = function prepareTimetable(timetable){
var grouped = groupBy(timetable, "saat");
for (var day in grouped){
if (!grouped.hasOwnProperty(day)) continue;
var dayItems = grouped[day];
grouped[day] = dayItems.sort(function(a, b){
return a.gun < b.gun ? -1 : 1;
});
}
var acc = [];
for (var t in grouped){
if (grouped.hasOwnProperty(t)){
acc.push([t, grouped[t]]);
}
}
return acc.sort(function(a, b){
return a[0] > b[0] ? 1 : -1;
});
}
})
.directive("crudTimetableDirective", function(){
return {
templateUrl: 'components/crud/templates/timetable.html',
restrict: 'E',
replace: true,
controller: 'crudTimetableDirectiveCtrl',
link: function(iScope, iElem, iAtrrs){
var mainFieldName = 'ogretim_elemani_zt';
iScope.mainFieldName = mainFieldName;
iScope.tablesList = iScope[mainFieldName].ogretim_elemanlari;
iScope.widgetTitle = "Öğretim Elemanı Zaman Tablosu"
initLecturer(iScope[mainFieldName]);
function initLecturer(data){
iScope.currentTable = {
key: data.oe_key,
name: data.name,
avatar_url: data.avatar_url,
totalHours: data.toplam_ders_saati,
readonly: data.readonly
};
iScope.timetable = iScope.prepareTimetable(data.uygunluk_durumu);
};
iScope.selectTable = function(lecturer){
iScope.loadingTable = true;
iScope.get_wf({
cmd: 'personel_sec',
secili_og_elemani: {key: lecturer.key}
}).then(function(response){
initLecturer(response);
}).finally(function(){
iScope.loadingTable = false;
})
};
iScope.changeValue = function(time){
iScope.loadingAction = true;
iScope.get_wf({
cmd: 'degistir',
change: {
'key': time.key,
'durum': time.durum
}
}).then(function(table){
var days = table.uygunluk_durumu;
// update durum value from the response
for (var i=0; i<days.length; i++){
if (days[i].key == time.key){
time.durum = days[i].durum;
break;
}
}
}).finally(function(){
iScope.loadingAction = false;
})
}
}
}
})
.directive("crudTimetableDirective2", function(){
return {
templateUrl: 'components/crud/templates/timetable.html',
restrict: 'E',
replace: true,
controller: 'crudTimetableDirectiveCtrl',
link: function(iScope, iElem, iAtrrs){
var mainFieldName = 'derslik_zaman_tablosu';
iScope.mainFieldName = mainFieldName;
iScope.tablesList = iScope[mainFieldName].derslikler;
iScope.widgetTitle = "Derslik Zaman Tablosu";
initTable(iScope[mainFieldName]);
function initTable(data){
iScope.currentTable = {
key: data.oe_key,
name: data.name,
avatar_url: data.avatar_url,
readonly: data.readonly
};
iScope.timetable = iScope.prepareTimetable(data.zaman_plani);
};
iScope.selectTable = function(table){
iScope.loadingTable = true;
iScope.get_wf({
cmd: 'derslik_degistir',
secili_derslik: {key: table.key}
}).then(function(response){
initTable(response);
}).finally(function(){
iScope.loadingTable = false;
})
};
iScope.changeValue = function(time){
iScope.loadingAction = true;
iScope.get_wf({
cmd: 'degistir',
change: {
'key': time.key,
'durum': time.durum
}
}).then(function(table){
var days = table.uygunluk_durumu;
// update durum value from the response
for (var i=0; i<days.length; i++){
if (days[i].key == time.key){
time.durum = days[i].durum;
break;
}
}
}).finally(function(){
iScope.loadingAction = false;
})
}
}
}
});
...@@ -29,8 +29,8 @@ describe('crud controller module', function () { ...@@ -29,8 +29,8 @@ describe('crud controller module', function () {
describe('crud controller', function () { describe('crud controller', function () {
it('should have CRUDListFormCtrl', inject(function () { it('should have CRUDListFormController', inject(function () {
expect('ulakbus.crud.CRUDListFormCtrl').toBeDefined(); expect('ulakbus.crud.CRUDListFormController').toBeDefined();
})); }));
it('should have CRUDCtrl', inject(function () { it('should have CRUDCtrl', inject(function () {
...@@ -52,24 +52,24 @@ describe('crud controller module', function () { ...@@ -52,24 +52,24 @@ describe('crud controller module', function () {
expect($controller).toBeDefined(); expect($controller).toBeDefined();
}])); }]));
it('should execute CRUDListFormCtrl with form cms', inject(function ($rootScope, RESTURL) { it('should execute CRUDListFormController with form cms', inject(function ($rootScope, RESTURL) {
$httpBackend.expectGET(RESTURL.url + 'ara/personel/123') $httpBackend.expectGET(RESTURL.url + 'ara/personel/123')
.respond(200, {}); .respond(200, {});
var $scope = $rootScope.$new(); var $scope = $rootScope.$new();
var $routeParams = {cmd: 'form'}; var $routeParams = {cmd: 'form'};
var controller = $controller('CRUDListFormCtrl', {$scope: $scope, $routeParams: $routeParams}); var controller = $controller('CRUDListFormController', {$scope: $scope, $routeParams: $routeParams});
})); }));
it('should execute CRUDListFormCtrl with list cmd', inject(function ($rootScope, RESTURL) { it('should execute CRUDListFormController with list cmd', inject(function ($rootScope, RESTURL) {
$httpBackend.expectGET(RESTURL.url + 'ara/personel/123') $httpBackend.expectGET(RESTURL.url + 'ara/personel/123')
.respond(200, {}); .respond(200, {});
var $scope = $rootScope.$new(); var $scope = $rootScope.$new();
$scope.meta = {'allow_filters': true}; $scope.meta = {'allow_filters': true};
var $routeParams = {cmd: 'list'}; var $routeParams = {cmd: 'list'};
var controller = $controller('CRUDListFormCtrl', {$scope: $scope, $routeParams: $routeParams}); var controller = $controller('CRUDListFormController', {$scope: $scope, $routeParams: $routeParams});
$scope.$broadcast('reload_cmd', 'list'); $scope.$broadcast('reload_cmd', 'list');
$scope.$broadcast('updateObjects', ['test', 'headers']); $scope.$broadcast('updateObjects', ['test', 'headers']);
...@@ -83,23 +83,23 @@ describe('crud controller module', function () { ...@@ -83,23 +83,23 @@ describe('crud controller module', function () {
$scope.resetCmd(); $scope.resetCmd();
})); }));
it('should execute CRUDListFormCtrl with show cmd', inject(function ($rootScope, Generator) { it('should execute CRUDListFormController with show cmd', inject(function ($rootScope, Generator) {
var $scope = $rootScope.$new(); var $scope = $rootScope.$new();
var $routeParams = {cmd: 'show'}; var $routeParams = {cmd: 'show'};
$scope.object = []; $scope.object = [];
var controller = $controller('CRUDListFormCtrl', {$scope: $scope, $routeParams: $routeParams}); var controller = $controller('CRUDListFormController', {$scope: $scope, $routeParams: $routeParams});
$scope.object = {test: {}}; $scope.object = {test: {}};
var controller = $controller('CRUDListFormCtrl', {$scope: $scope, $routeParams: $routeParams}); var controller = $controller('CRUDListFormController', {$scope: $scope, $routeParams: $routeParams});
$scope.pageData = true; $scope.pageData = true;
Generator.setPageData($scope); Generator.setPageData($scope);
var controller = $controller('CRUDListFormCtrl', {$scope: $scope, $routeParams: $routeParams}); var controller = $controller('CRUDListFormController', {$scope: $scope, $routeParams: $routeParams});
})); }));
it('should execute CRUDListFormCtrl with relad cmd', inject(function ($rootScope, RESTURL) { it('should execute CRUDListFormController with relad cmd', inject(function ($rootScope, RESTURL) {
$httpBackend.expectGET(RESTURL.url + 'ara/personel/123') $httpBackend.expectGET(RESTURL.url + 'ara/personel/123')
.respond(200, {}); .respond(200, {});
...@@ -107,7 +107,7 @@ describe('crud controller module', function () { ...@@ -107,7 +107,7 @@ describe('crud controller module', function () {
$scope.form_params = {}; $scope.form_params = {};
$scope.reload_cmd = 'list'; $scope.reload_cmd = 'list';
var $routeParams = {cmd: 'reload'}; var $routeParams = {cmd: 'reload'};
var controller = $controller('CRUDListFormCtrl', {$scope: $scope, $routeParams: $routeParams}); var controller = $controller('CRUDListFormController', {$scope: $scope, $routeParams: $routeParams});
})); }));
......
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
angular.module('ulakbus.crud')
/**
* this is a directive for quick add widget of listnodes
* quick add widget does simply that; no need to add listnode item with model,
* simply add an item to listnode searching related ulakbus model
* needs that keys in listnode schema:
* quick_add: true
* quick_add_view: <viewname>
* quick_add_model: <modelname>
* quick_add_field: to which field the data found will be added
* thanks u.u
*/
.directive('quickAdd', function (Generator) {
return {
templateUrl: 'components/crud/templates/quick_add.html',
restrict: 'E',
replace: true,
scope: {
node: '='
},
controller: function ($scope) {
$scope.kw = '';
$scope.getTitleMap = function () {
return $scope.generateTitleMap($scope.kw);
};
$scope.generateTitleMap = function (kw) {
var searchData = {
form_params: {
view: $scope.node.quick_add_view,
model: $scope.node.quick_add_model,
query: kw
}
};
if (angular.isDefined($scope.$parent.form_params.param)){
searchData.form_params['id'] = $scope.$parent.form_params.id;
}
return Generator.get_list(searchData).then(function (res) {
var titleMap = [];
angular.forEach(res.objects, function (item) {
titleMap.push({
"value": item[0],
"name": item[1]
});
});
return titleMap;
});
};
$scope.onSelect = function (item) {
// add to listnode here
// field default is node schema properties first index
var get_first_key = function () {
return Object.keys($scope.node.schema.properties)[0];
};
var field = $scope.node.quick_add_field || get_first_key();
var f = { key: item.value};
f[field] = item.name;
// loop item keys and if a key not found in f add it with no value
angular.forEach($scope.node.items[0], function (value, key) {
if (!angular.isDefined(f[key])) {
f[key] = undefined;
}
});
try {
angular.forEach($scope.node.items, function (value, key) {
if (value['key'] === item.value) {
throw Error();
}
});
$scope.node.model.push(f);
$scope.node.items.push(f);
} catch (e) {
alert('bu öğe listede zaten mevcut!!');
}
}
}}
});
\ No newline at end of file
<div class="crud-mask">
<span class="loader"></span>
</div>
\ No newline at end of file
<div class="container-fluid"> <div ng-hide="show_crud === false" class="container-fluid">
<crud-timetable-directive ng-if="ogretim_elemani_zt"></crud-timetable-directive>
<crud-timetable-directive2 ng-if="derslik_zaman_tablosu"></crud-timetable-directive2>
<div ng-class="{'col-md-8': meta.allow_filters}"> <div ng-class="{'col-md-8': meta.allow_filters}">
<h3>{{ schema.title }}</h3> <msgbox ng-show="msgbox"></msgbox>
<h3 ng-class="{'mid-h3': !objects}">{{ schema.title }}</h3>
<crud-show-directive ng-if="object"></crud-show-directive> <crud-show-directive ng-if="object"></crud-show-directive>
<crud-form-directive ng-if="forms"></crud-form-directive> <crud-form-directive ng-if="forms"></crud-form-directive>
<crud-list-directive ng-if="objects"></crud-list-directive> <crud-list-directive ng-if="objects"></crud-list-directive>
</div> </div>
<crud-filters ng-show="meta.allow_filters === true" class="col-md-4 filtre"></crud-filters> <crud-filters ng-show="meta.allow_filters === true" class="col-md-4 filtre"></crud-filters>
</div> </div>
\ No newline at end of file <div ng-show="show_crud === false" class="crud-mask">
<span class="loader"></span>
</div>
...@@ -13,8 +13,10 @@ ...@@ -13,8 +13,10 @@
<div ng-if="filter.type==='check' || !filter.type" uib-collapse="filterCollapsed[filter.field]"> <div ng-if="filter.type==='check' || !filter.type" uib-collapse="filterCollapsed[filter.field]">
<div class="checkbox" ng-repeat="filterItem in filter.values"> <div class="checkbox" ng-repeat="filterItem in filter.values">
<label class="checkbox-inline"> <label class="checkbox-inline">
<input type="checkbox" name="filter_group[]" ng-model="filterList[filter.field].model[filterItem.value]" <input type="checkbox" name="filter_group[]"
value="{{filterItem.value || filterItem[0]}}"/> ng-model="filterList[filter.field].model[filterItem.value]"
value="{{filterItem.value || filterItem[0]}}"
ng-checked="filterItem.selected"/>
{{filterItem.name || filterItem[1]}} {{filterItem.name || filterItem[1]}}
</label> </label>
</div> </div>
...@@ -22,8 +24,10 @@ ...@@ -22,8 +24,10 @@
<div ng-if="filter.type==='select'" uib-collapse="filterCollapsed[filter.field]"> <div ng-if="filter.type==='select'" uib-collapse="filterCollapsed[filter.field]">
<div class="col-md-12"> <div class="col-md-12">
<select name="filterSelect" id="filterSelect" class="form-control"> <select name="filterSelect" id="filterSelect" class="form-control" multiple>
<option ng-repeat="filterItem in filter.values" value="{{filterItem.value}}"> <option ng-repeat="filterItem in filter.values"
value="{{filterItem.value}}"
ng-selected="filterItem.selected">
{{filterItem.name}} {{filterItem.name}}
</option> </option>
</select> </select>
......
<div> <div class="clearfix" ng-class="{'form-container': !objects}">
<div class="buttons-on-top"></div> <div class="buttons-on-top"></div>
<form id="formgenerated" name="formgenerated" sf-schema="schema" sf-form="form" sf-model="model" <form id="formgenerated" name="formgenerated" sf-schema="schema" sf-form="form" sf-model="model"
ng-submit="onSubmit(formgenerated)" form-locator></form> ng-submit="onSubmit(formgenerated)" form-locator>
<!--<div>-->
<!--<uib-tabset active="active">-->
<!--<uib-tab index="0" heading="Static title">-->
<!--<div ng-repeat="field in form">-->
<!--<em>before</em>-->
<!--<div sf-insert-field="[field]"></div>-->
<!--<em>after</em>-->
<!--</div>-->
<!--</uib-tab>-->
<!--</uib-tabset>-->
<!--</div>-->
</form>
<div ng-repeat="node in Node"> <div ng-repeat="node in Node">
<h3>{{ node.title }} <h3>{{ node.title }}
...@@ -14,21 +26,25 @@ ...@@ -14,21 +26,25 @@
</h3> </h3>
<div class="node-table"> <div class="node-table">
<ng-include src="'shared/templates/nodeTable.html'"></ng-include> <ng-include src="'components/crud/templates/nodeTable.html'"></ng-include>
</div> </div>
<hr> <hr>
</div> </div>
<div ng-repeat="node in ListNode"> <div ng-repeat="node in ListNode">
<h3>{{ node.title }} <h3>{{ node.title }}
<span> <span ng-if="meta.allow_add_listnode !== false" ng-hide="node.quick_add === true">
<a modal-for-nodes="{{node.schema.model_name}},ListNode,add"> <a modal-for-nodes="{{node.schema.model_name}},ListNode,add">
<i class="fa fa-plus-circle fa-fw"></i> <i class="fa fa-plus-circle fa-fw"></i>
</a> </a>
</span> </span>
<quick-add node="node" ng-if="node.quick_add === true"></quick-add>
</h3> </h3>
<div class="list-node-table"> <div class="list-node-table" ng-if="!meta.translate_widget">
<ng-include src="'shared/templates/nodeTable.html'"></ng-include> <ng-include src="'components/crud/templates/nodeTable.html'"></ng-include>
</div>
<div class="list-node-table" ng-if="meta.translate_widget">
<ng-include src="'shared/templates/translate.html'"></ng-include>
</div> </div>
<hr> <hr>
</div> </div>
......
<input type="text"
class="form-control"
ng-if="node.schema.properties[k].type === 'date'"
ng-model="node.model[outerIndex][k]"
uib-datepicker-popup="dd.MM.yyyy"
is-open="datepickerstatuses[outerIndex]"
close-text="Kapat"
current-text="Bugün"
clear-text="Temizle"
ng-click="openDatepicker(outerIndex)">
<select ng-model="node.model[outerIndex][k]"
ng-if="node.schema.properties[k].type === 'select'"
class="form-control"
name="selectinline{{outerIndex}}">
<option ng-repeat="item in node.schema.properties[k].titleMap" value="{{item.value}}">{{item.name}}</option>
</select>
<input type="{{node.schema.properties[k].type}}"
class="form-control"
ng-if="node.schema.properties[k].type !== 'date' && node.schema.properties[k].type !== 'select'"
ng-model="node.model[outerIndex][k]"
ng-change="nodeModelChange(this)">
\ No newline at end of file
...@@ -3,13 +3,24 @@ ...@@ -3,13 +3,24 @@
<search-directive ng-if="meta['allow_search']===true"></search-directive> <search-directive ng-if="meta['allow_search']===true"></search-directive>
<div class="clearfix"></div> <div class="clearfix"></div>
<!--<h1>{{form_params.model || form_params.wf}}</h1>--> <!--<h1>{{form_params.model || form_params.wf}}</h1>-->
<div class="row" ng-if="!objects[1]"> <div class="row" ng-if="(!meta.selective_listing && !objects[1])">
<div class="col-md-12"> <div class="col-md-12">
<p class="no-content">Listelenecek içerik yok.</p> <p class="no-content">Listelenecek içerik yok.</p>
</div> </div>
</div> </div>
<!-- todo: add `selective_list` to documentation -->
<div ng-if="meta.selective_listing === true" class="row" style="margin-bottom: 25px;">
<label for="selective_list">{{meta.selective_listing_label || "Sayfa içinde filtrelemek için seçim yapınız."}}</label>
<select name="selective_list" id="selective_list"
ng-change="update_selective_list(selective_list_key)"
ng-model="selective_list_key"
ng-options="item as item.key for item in all_objects"
class="form-control">
<!--<option ng-repeat="item in all_objects" value="{{$index}}">{{item.key}}</option>-->
</select>
</div>
<div class="tablescroll" ng-if="objects[1]"> <div class="tablescroll" ng-if="objects[1]">
<table class="table table-bordered" style="background-color:#fff;"> <table class="table table-bordered table-striped" style="background-color:#fff;">
<thead> <thead>
<tr> <tr>
<td ng-if="meta.allow_selection === true"> <td ng-if="meta.allow_selection === true">
...@@ -20,7 +31,7 @@ ...@@ -20,7 +31,7 @@
</td> </td>
<td ng-repeat="value in objects[0] track by $index" ng-if="objects[0]!='-1'">{{value}}</td> <td ng-repeat="value in objects[0] track by $index" ng-if="objects[0]!='-1'">{{value}}</td>
<td ng-if="objects[0]=='-1'">{{ schema.title||model}}</td> <td ng-if="objects[0]=='-1'">{{ schema.title||model}}</td>
<td>İşlem</td> <td ng-if="meta.allow_actions !== false">İşlem</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
...@@ -34,11 +45,14 @@ ...@@ -34,11 +45,14 @@
<td ng-repeat="field in object.fields track by $index"> <td ng-repeat="field in object.fields track by $index">
<a role="button" ng-if="field.type==='link'" <a role="button" ng-if="field.type==='link'"
ng-click="do_action(object.key, field)">{{field.content}}</a> ng-click="do_action(object.key, field)"><markdown ng-bind-html="field.content"></markdown></a>
<span ng-if="field.type==='str'">{{field.content}}</span> <span ng-if="field.type==='str'" ng-bind-html="field.content || '' | markdown"></span>
<!--<a role="button" ng-if="field.type==='link'"-->
<!--ng-click="do_action(object.key, field)">{{trustashtml(field.content) | markdown}}</a>-->
<!--<span ng-if="field.type==='str'">{{trustashtml(field.content) | markdown}}</span>-->
</td> </td>
<td> <td ng-if="meta.allow_actions !== false">
<button class="btn btn-info" style="margin-right: 5px;" ng-repeat="action in object.actions track by $index" <button class="btn btn-info" style="margin-right: 5px;" ng-repeat="action in object.actions track by $index"
ng-if="action.show_as==='button'" ng-if="action.show_as==='button'"
ng-click="do_action(object.key, action)">{{action ng-click="do_action(object.key, action)">{{action
...@@ -55,16 +69,16 @@ ...@@ -55,16 +69,16 @@
<nav ng-if="pagination && pagination.total_pages > 1" class="text-center"> <nav ng-if="pagination && pagination.total_pages > 1" class="text-center">
<ul class="pagination"> <ul class="pagination">
<li ng-class="{disabled:pagination.page===1}"> <li ng-class="{disabled:pagination.page===1}">
<a aria-label="Önceki" ng-click="reload({page:pagination.page-1})"> <a role="button" aria-label="Önceki" ng-click="paginate({page:pagination.page-1})">
<span aria-hidden="true">&laquo;</span> <span aria-hidden="true">&laquo;</span>
</a> </a>
</li> </li>
<li ng-repeat="page in getNumber(pagination.total_pages) track by $index" <li ng-repeat="page in getNumber(pagination.total_pages) track by $index"
ng-class="{active:$index+1===pagination.page}"> ng-class="{active:$index+1===pagination.page}">
<a ng-click="reload({page:$index+1})">{{$index+1}}</a> <a role="button" ng-click="paginate({page:$index+1})">{{$index+1}}</a>
</li> </li>
<li ng-class="{disabled:pagination.page===pagination.total_pages}"> <li ng-class="{disabled:pagination.page===pagination.total_pages}">
<a aria-label="Sonraki" ng-click="reload({page:pagination.page+1})"> <a role="button" aria-label="Sonraki" ng-click="paginate({page:pagination.page+1})">
<span aria-hidden="true">&raquo;</span> <span aria-hidden="true">&raquo;</span>
</a> </a>
</li> </li>
......
...@@ -12,15 +12,19 @@ ...@@ -12,15 +12,19 @@
<th>İşlem</th> <th>İşlem</th>
</tr> </tr>
<tr ng-if="node.schema.formType=='ListNode'"> <tr ng-if="node.schema.formType=='ListNode'">
<th colspan="2"> <th colspan="2" ng-if="meta.allow_selection===true">
<!--<label>--> <label>
<!--<input type="checkbox" style="zoom:1.5; margin:5px 0 0 8px;">--> <input type="checkbox" style="zoom:1.5; margin:5px 0 0 8px;">
<!--Hepsini Seç--> Hepsini Seç
<!--</label>--> </label>
</th> </th>
<th ng-repeat="(key,value) in node.items[0] track by $index" ng-if="key!=='idx'"> <th scope="row" style="text-align:center">#</th>
<span ng-if="value.verbose_name">{{ value.verbose_name }}</span> <<<<<<< 6a71c6920efc5235eff71bf42763b82cc30f1827
<span ng-if="!value.verbose_name">{{key}}</span> <th ng-repeat="prop in node.schema.properties_list">
=======
<th ng-repeat="propName in node.form" ng-init="prop = node.schema.properties[propName]">
>>>>>>> FIX, rfix#5379. Fix ListNode's dose not respect schema order
<span ng-if="!value.verbose_name">{{prop.title||prop.name}}</span>
</th> </th>
<th ng-if="meta.allow_actions!==false">İşlem</th> <th ng-if="meta.allow_actions!==false">İşlem</th>
</tr> </tr>
...@@ -42,27 +46,35 @@ ...@@ -42,27 +46,35 @@
</td> </td>
</tr> </tr>
<tr ng-repeat="listnodemodel in node.items track by $index" ng-init="outerIndex=$index" ng-if="node.schema.formType=='ListNode'"> <tr ng-repeat="listnodemodel in node.items" ng-init="outerIndex=$index" ng-if="node.schema.formType=='ListNode'">
<td width="60"> <td ng-if="meta.allow_selection===true" width="60">
<!--<label>--> <label>
<!--<input type="checkbox" style="zoom:1.5; margin:5px 0 0 8px;">--> <input type="checkbox" style="zoom:1.5; margin:5px 0 0 8px;">
<!--</label>--> </label>
</td> </td>
<th scope="row" style="text-align:center">{{$index+1}}</th> <th scope="row" style="text-align:center">{{$index+1}}</th>
<td ng-repeat="(k, v) in listnodemodel track by $index" ng-init="innerIndex=$index" ng-if="k!=='idx'"> <td ng-repeat="prop in node.schema.properties_list" ng-init="k = prop.name; v = listnodemodel[k]; inline = node.schema.inline_edit && node.schema.inline_edit.indexOf(k) > -1">
<span ng-if="!node.schema.inline_edit || node.schema.inline_edit.indexOf(k) < 0">{{ v.unicode || v }}</span> <span ng-if="!inline">{{ v.unicode || v }}</span>
<input type="node.schema.formType" ng-if="node.schema.inline_edit.indexOf(k) > -1" <!--<input type="{{node.schema.properties[k].type}}"-->
ng-model="node.model[outerIndex][k]" <!--ng-if="node.schema.inline_edit.indexOf(k) > -1"-->
ng-change="nodeModelChange(this)"> <!--ng-model="node.model[outerIndex][k]"-->
<!--ng-change="nodeModelChange(this)">-->
<ng-include src="'components/crud/templates/inline_edit.html'" ng-if="inline"></ng-include>
</td> </td>
<td ng-if="meta.allow_actions!==false"> <td ng-if="meta.allow_actions!==false">
<button modal-for-nodes="{{node.schema.model_name}},{{node.schema.formType}},edit,{{$index}}">Düzenle <div ng-hide="meta.object_actions.length > 0">
</button> <span modal-for-nodes="{{node.schema.model_name}},{{node.schema.formType}},edit,{{$index}}"
<br> ng-hide="node.quick_add === true">
<button ng-click="remove(node, 'ListNode', $index)">Sil</button> <i class="fa fa-pencil-square-o fa-fw"></i>
</span>
<span ng-click="remove(node, 'ListNode', $index)"><i class="fa fa-times fa-fw"></i></span>
</div>
<div ng-show="meta.object_actions.length > 0">
<!-- define object actions here -->
</div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
\ No newline at end of file
<div>
<input class="form-control"
type="text"
placeholder="eklemek istediğiniz nesneyi yazınız..."
ng-model="kw"
uib-typeahead="item as item.name for item in getTitleMap($viewValue)"
typeahead-on-select="onSelect($item)"
typeahead-loading="loadingTitleMap" typeahead-no-results="noResults"
typeahead-wait-ms="500"/>
<div ng-show="loadingTitleMap" class="loader"></div>
<div ng-show="noResults">
<i class="fa fa-close"></i> bulunamadı.
</div>
</div>
\ No newline at end of file
...@@ -12,13 +12,15 @@ ...@@ -12,13 +12,15 @@
</thead> </thead>
<tbody ng-if="obj.type==='table-multiRow'"> <tbody ng-if="obj.type==='table-multiRow'">
<tr ng-repeat="row in obj.fields"> <tr ng-repeat="row in obj.fields">
<td ng-repeat="(k,v) in row track by $index">{{v}}</td> <!--<td ng-repeat="(k,v) in row track by $index"><markdown ng-bind-html="v"></markdown></td>-->
<td ng-repeat="(k,v) in row track by $index" ng-bind-html="v | markdown"></td>
</tr> </tr>
</tbody> </tbody>
<tbody ng-if="obj.type==='table'"> <tbody ng-if="obj.type==='table'">
<tr ng-repeat="(key, value) in obj.fields"> <tr ng-repeat="(key, value) in obj.fields">
<td class="col-md-2">{{key}}</td> <td class="col-md-2">{{key}}</td>
<td class="col-md-8">{{value}}</td> <!--<td class="col-md-8"><markdown ng-bind-html="value"></markdown></td>-->
<td class="col-md-8" ng-bind-html="markdownWorkaround(value) | markdown"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
......
<div class="row academician-dashboard dashboard">
<div class="col-md-12 course-prg-scheduler">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">{{widgetTitle}}</div>
</div>
<div class="panel-body">
<div class="col-xs-3 tabs-container"> <!-- required for floating -->
<ul class="tabs-left">
<li ng-repeat="table in tablesList" ng-click="selectTable(table)" ng-class="{active: currentTable.key == table.key}"><a>{{table.name}}</a></li>
</ul>
</div>
<div class="col-xs-9">
<div class="loader" ng-show="loadingTable">Loading...</div>
<!-- Tab panes -->
<div class="tab-content" ng-hide="loadingTable">
<div class="tab-pane active">
<div class="info-header clearfix">
<div class="info-wrapper">
<img ng-src="{{currentTable.avatar_url}}" class="profile-pic" ng-show="currentTable.avatar_url">
<span class="user-name">{{currentTable.name}}</span>
</div>
<div class="info-wrapper info-wrapper_hours" ng-show="currentTable.totalHours">
<span class="info-title">Ders Yükü:</span> <span>{{currentTable.totalHours}} saat</span>
</div>
</div>
<!-- end of header -->
<div class="table-warning" ng-show="message">
<span class="glyphicon glyphicon-exclamation-sign"></span> {{message.message}}
</div>
<div class="table-container">
<table>
<tbody>
<tr class="headers">
<td></td>
<td>PZT</td>
<td>SAL</td>
<td>ÇAR</td>
<td>PER</td>
<td>CUM</td>
<td>CMT</td>
<td>PAZ</td>
</tr>
<tr ng-repeat="time in timetable">
<td>{{time[0]}}</td>
<td ng-repeat="day in time[1]">
<div timetable-action-selector ng-model="day.durum" readonly="{{currentTable.readonly}}" ng-change="changeValue(day)"></div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="loader pull-right" ng-show="loadingAction">Loading...</div>
<ul class="legend">
<li>
<span class="action-indicator action-indicator_appropriate"></span> Uygun
</li>
<li>
<span class="action-indicator action-indicator_uncertain"></span> Mümkünse boş bırakılmalı
</li>
<li>
<span class="action-indicator action-indicator_busy"></span> Kesinlike boş bırakılmalı
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- end of panel-body -->
</div>
<!-- end of panel -->
</div>
</div>
<div ng-app="ulakbus.dashboard" class="dashboard"> <div ng-app="ulakbus.dashboard" class="dashboard academician-dashboard">
<div class="starter-template"> <div class="starter-template">
<div class="dashboard-main-search clearfix"> <academic-calendar></academic-calendar>
<ng-include src="'components/dashboard/user-templates/student.html'" ng-if="$root.current_user.is_student"></ng-include>
<div class="row" ng-show="$root.current_user.can_search"> <ng-include src="'components/dashboard/user-templates/staff.html'" ng-if="!$root.current_user.is_student"></ng-include>
<div class="col-md-12"> <ng-include src="'components/dashboard/user-templates/academician.html'" ng-if="$root.current_user.is_staff && $root.current_user.is_academic"></ng-include>
<div class="panel panel-default"> <!-- <user-tasks></user-tasks> -->
<div class="panel-heading">
<div class="panel-title">Arama</div>
</div>
<div class="panel-body">
<div class="dashboard-student-search" data-step="2"
data-intro="isim veya tcno ile öğrenci araması yapabilirsiniz."
ng-show="$root.searchInputs.ogrenci">
<div class="text-center">
<h3>ÖĞRENCİ</h3>
<input type="text" placeholder="Öğrenci ara" ng-model="keyword.student"
ng-keyup="search('ogrenci')">
<span class="bordered-fa-icon fa fa-search" ng-click="search('ogrenci')"></span>
</div>
<div class="dashboard-search-results" ng-show="showResults">
<ul ng-if="students.length > 0">
<li ng-repeat="student in students">
<a role="button">
<span ng-click="select(student, 'ogrenci')">{{student[0]}}</span>
<i class="fa fa-fw fa-info-circle pull-right" popover-placement="bottom"
uib-popover-template="userPopover.templateUrl"
ng-click="get_info('Ogrenci', student[2])"></i></a>
</li>
</ul>
</div>
<!-- end of dashboard-student-search-results -->
</div>
<!-- end of dashboard-student-search -->
<div class="dashboard-personnel-search" data-step="3"
data-intro="isim veya tcno ile personel araması yapabilirsiniz."
ng-show="$root.searchInputs.personel">
<div class="text-center">
<h3>PERSONEL</h3>
<input type="text" placeholder="Personel ara" ng-model="keyword.staff"
ng-keyup="search('personel')">
<span class="bordered-fa-icon fa fa-search" ng-click="search('personel')"></span>
</div>
<div class="dashboard-search-results" ng-show="showResults">
<ul ng-if="staffs.length > 0">
<li ng-repeat="staff in staffs">
<a role="button">
<span ng-click="select(staff, 'personel')">{{staff[0]}}</span>
<i class="fa fa-fw fa-info-circle pull-right"
popover-placement="bottom"
uib-popover-template="userPopover.templateUrl"
ng-click="get_info('Personel', staff[2])"></i></a>
</li>
</ul>
</div>
<!-- end of dashboard-personnel-search-results -->
</div>
<!-- end of dashboard-personnel-search -->
</div>
</div>
</div>
</div>
</div>
<!-- end of dashboard-main-search -->
<div class="row">
<div class="col-md-6 user-info">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Giriş Yapan Kullanıcı Bilgileri</div>
</div>
<div class="panel-body">
<div class="col-md-6">
<img class="img-rounded user-pic"
src="{{$root.current_user.avatar || 'img/empty-profile-pic.jpg'}}"
alt="{{$root.current_user.username}}">
</div>
<div class="col-md-6">
<p class="user-name">{{$root.current_user.name}}<br>{{$root.current_user.surname}}</p>
</div>
</div>
</div>
</div>
<div class="col-md-6 quick-links">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Hızlı İşlemler</div>
</div>
<div class="panel-body">
<div class="col-md-6 text-center link-buttons"
ng-repeat="item in $root.quick_menu track by $index">
<a
ng-href="#/{{item.wf}}/{{item.model}}?{{item.param}}={{selectedUser.key}}">
{{item.text}}
</a>
</div>
</div>
</div>
</div>
</div>
<!-- end of row -->
<div class="dashboard-main-anouncement clearfix">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Duyurular</div>
</div>
<div class="panel-body">
<a ng-click="markAsRead(notify)"
ng-repeat="notify in notifications[3] | limitTo:5">{{notify
.body}}</a>
</div>
</div>
</div>
</div>
</div>
<!-- end of dashboard-main-anouncement -->
<!--<div class="right-sidebar selected-person-field">-->
<!--<div class="right-sidebar-header">-->
<!--<span class="bar-title">Kişi seçildi</span>-->
<!--<span class="unselect-person"><i class="fa fa-times"></i></span>-->
<!--</div>-->
<!--&lt;!&ndash; end of right-sidebaer-header &ndash;&gt;-->
<!---->
<!--<div class="selected-person-info">-->
<!--<img src="../../img/sample-profile-pic.jpg" class="selected-person-img">-->
<!--<div class="selected-person-name">Erkan Öğümsöğütlü</div>-->
<!--</div>-->
<!--&lt;!&ndash; end of selected-person-info &ndash;&gt;-->
<!--</div>-->
<!-- end of right-sidebar -->
</div> </div>
</div> </div>
\ No newline at end of file
...@@ -21,7 +21,11 @@ angular.module('ulakbus.dashboard', []) ...@@ -21,7 +21,11 @@ angular.module('ulakbus.dashboard', [])
$uibTooltipProvider.setTriggers({'click': 'mouseleave'}); $uibTooltipProvider.setTriggers({'click': 'mouseleave'});
}) })
.controller('DashCtrl', function ($scope, $rootScope, $timeout, $http, $cookies, RESTURL, Generator) { .controller('DashController', function ($scope, $rootScope, $routeParams, $route, $timeout, $http, $cookies, RESTURL, Generator, WSOps) {
// first generate_dashboard broadcasted to get menu and dashboard items
// sidebar directive listens for "generate_dashboard"
$rootScope.$broadcast("generate_dashboard");
$scope.section = function (section_index) { $scope.section = function (section_index) {
$rootScope.section = section_index; $rootScope.section = section_index;
}; };
...@@ -36,43 +40,58 @@ angular.module('ulakbus.dashboard', []) ...@@ -36,43 +40,58 @@ angular.module('ulakbus.dashboard', [])
$scope.students = []; $scope.students = [];
$scope.staffs = []; $scope.staffs = [];
/**
* this function is for searchin student or personel
* uses $scope.keyword objects
* @param where
*/
$scope.search = function (where) { $scope.search = function (where) {
$timeout(function () { if ($scope.keyword.staff.length > 2 || $scope.keyword.student.length > 2) {
if (where === 'personel') { $timeout(function () {
// if input length greater than 2 search for the value if (where === 'personel') {
if ($scope.keyword.staff.length > 2) { // if input length greater than 2 search for the value
$scope.getItems(where, $scope.keyword.staff).success(function (data) {
$scope.getItems(where, $scope.keyword.staff).then(function (data) {
$scope.staffs = data.results; $scope.staffs = data.results;
}); });
} }
} if (where === 'ogrenci') {
if (where === 'ogrenci') { $scope.getItems(where, $scope.keyword.student).then(function (data) {
if ($scope.keyword.student.length > 2) {
$scope.getItems(where, $scope.keyword.student).success(function (data) {
$scope.students = data.results; $scope.students = data.results;
}) })
} }
} }, 500);
}, 500); }
}; };
$scope.getItems = function (where, what) { $scope.getItems = function (where, what) {
$scope.showResults = true; $scope.showResults = true;
return $http.get(RESTURL.url + 'ara/' + where + '/' + what); return WSOps.request({view: where + '_ara', query: what});
}; };
$scope.userPopover = {templateUrl: 'components/dashboard/user-info.html'}; $scope.userPopover = {templateUrl: 'components/dashboard/user-info.html'};
/**
* when student or personel search results appear,
* user can see the sample info of student/personel before to select it
* this function triggered onhover the item
* @param type
* @param key
*/
$scope.get_info = function (type, key) { $scope.get_info = function (type, key) {
Generator.get_list({url: 'crud', form_params: {model: type, object_id: key, cmd: 'show'}}) Generator.get_list({url: 'crud', form_params: {wf: 'crud', model: type, object_id: key, cmd: 'show'}})
.then(function (data) { .then(function (data) {
$scope.userPopover.name = data.data.object.unicode; $scope.userPopover.name = data.object['Ad'] + " " + data.object['Soyad'];
$scope.userPopover.tcno = data.data.object.tckn; $scope.userPopover.tcno = data.object['TC Kimlik No'];
$scope.userPopover.image = data.object['Avatar'] || 'img/sample-profile-pic.jpg';
//debugger;
}) })
}; };
/**
* @description selecting
* @param who - who is the data of selected person in search results
* @param type - type can be 'ogrenci' or 'personel'
*/
$scope.select = function (who, type) { $scope.select = function (who, type) {
$rootScope.$broadcast('selectedUser', {name: who[0], tcno: who[1], key: who[2]}); $rootScope.$broadcast('selectedUser', {name: who[0], tcno: who[1], key: who[2]});
// get 'who's related transactions and manipulate sidebar menu // get 'who's related transactions and manipulate sidebar menu
...@@ -81,6 +100,9 @@ angular.module('ulakbus.dashboard', []) ...@@ -81,6 +100,9 @@ angular.module('ulakbus.dashboard', [])
}; };
/**
* dashboard also catches notifications to use in widgets
*/
$scope.$on("notifications", function (event, data) { $scope.$on("notifications", function (event, data) {
$scope.notifications = data; $scope.notifications = data;
}); });
...@@ -89,28 +111,22 @@ angular.module('ulakbus.dashboard', []) ...@@ -89,28 +111,22 @@ angular.module('ulakbus.dashboard', [])
$scope.selectedUser = data; $scope.selectedUser = data;
}); });
/**
* removes selected user
*/
$scope.deselectUser = function () { $scope.deselectUser = function () {
delete $scope.selectedUser; delete $scope.selectedUser;
delete $scope.selectedMenuItems; delete $scope.selectedMenuItems;
}; };
// this function needed by tasks widget
// if a user wants to dismiss a task it broadcasts the item to markasread
$scope.markAsRead = function (items) { $scope.markAsRead = function (items) {
$rootScope.$broadcast("markasread", items); $rootScope.$broadcast("markasread", items);
} };
//if ($routeParams.cmd = 'reload') {
// $route.reload();
//}
})
.directive('sidebarNotifications', function () {
return {
templateUrl: 'shared/templates/directives/sidebar-notification.html',
restrict: 'E',
replace: true,
link: function ($scope) {
// sidebar notifications from rootScope broadcast
//$scope.$on("notifications", function (event, data) {
// $scope.notifications = data;
//});
}
}
}); });
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* (GPLv3). See LICENSE.txt for details. * (GPLv3). See LICENSE.txt for details.
*/ */
'use strict'; 'use strict';
describe('dashboard controller module', function () { describe('dashboard controller module', function () {
...@@ -26,16 +26,17 @@ describe('dashboard controller module', function () { ...@@ -26,16 +26,17 @@ describe('dashboard controller module', function () {
})); }));
describe('dashboard controller', function () { describe('dashboard controller', function () {
it('should define DashCtrl', inject(function () { it('should define DashController', inject(function () {
expect('ulakbus.dashboard.DashCtrl').toBeDefined(); expect('ulakbus.dashboard.DashController').toBeDefined();
})); }));
it('should execute DashCtrl functions', inject(function ($rootScope, RESTURL) { // todo: complete dashboard tests
it('should execute DashController functions', inject(function ($rootScope, RESTURL) {
$httpBackend.expectGET(RESTURL.url + 'ara/personel/123') $httpBackend.expectGET(RESTURL.url + 'ara/personel/123')
.respond(200, {}); .respond(200, {});
var $scope = $rootScope.$new(); var $scope = $rootScope.$new();
var controller = $controller('DashCtrl', { $scope: $scope }); var controller = $controller('DashController', {$scope: $scope});
$scope.student_kw = "123"; $scope.student_kw = "123";
$scope.staff_kw = "123"; $scope.staff_kw = "123";
......
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
/**
* @memberof ulakbus.dashboard
* @ngdoc directive
* @name stats
* @description Directive for .
*/
angular.module('ulakbus.dashboard')
.directive('userTasks', function (WSOps) {
return {
templateUrl: 'components/dashboard/directives/user-tasks.html',
restrict: 'E',
replace: true,
scope: {},
controller: function ($scope) {
// todo: below are for test, will be removed
$scope.task_list = [
{WFToken: "yfuialhfuial", title: "sample 1 workflow", description: "sample 1", wf_type: "type x", date: '02.05.2016'},
{WFToken: "yfuialhfuial", title: "sample 2 workflow", description: "sample 2", wf_type: "type x", date: '02.05.2016'},
{WFToken: "yfuialhfuial", title: "sample 3 workflow", description: "sample 3", wf_type: "type y", date: '02.05.2016'},
{WFToken: "yfuialhfuial", title: "sample 4 workflow", description: "sample 4", wf_type: "type y", date: '02.05.2016'}
];
/**
* tasks need to be regrouped by wf_type
* @returns {{}}
*/
var regroup_tasks = function () {
var grouped_tasks = {};
angular.forEach($scope.task_list, function (value, key) {
grouped_tasks[value.wf_type] = grouped_tasks[value.wf_type] || [];
grouped_tasks[value.wf_type].push(value);
});
return grouped_tasks;
};
$scope.task_list = regroup_tasks();
$scope.$on("task_list", function (event, data) {
$scope.task_list = regroup_tasks(data);
});
/**
* this will send the websocket that we need to go certain workflow
* and websocket will send the wf data with cmd in it
* @param wf_token
*/
$scope.gototask = function (wf_token) {
WSOps.doSend({view: "open_wf", wf_token: wf_token});
}
}
};
})
.directive('academicCalendar', function () {
return {
templateUrl: 'components/dashboard/directives/academic-calendar.html',
restrict: 'E',
replace: true,
scope: {},
controller: function ($scope) {
}
};
});;
\ No newline at end of file
<div class="row">
<div class="col-md-12 academic-calendar-widget">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Akademik Takvim Göstergeci</div>
<div class="panel-action pull-right">Tüm Akademik Takvim</div>
</div>
<div class="panel-body">
<div class="calendar-inner">
<div class="calendar-line"></div>
<div class="date-circle-container">
<div class="date-circle">
<a class="popper" data-toggle="popover">
<div class="date-day">02</div>
<div class="date-month">ŞUB</div>
</a>
<div class="year">2016</div>
</div>
<!-- end of date-circle -->
<div class="date-circle">
<a>
<div class="date-day">03</div>
<div class="date-month">ŞUB</div>
</a>
<div class="year">2016</div>
</div>
<!-- end of date-circle -->
<div class="date-circle">
<a>
<div class="date-day">04</div>
<div class="date-month">ŞUB</div>
</a>
<div class="year">2016</div>
</div>
<!-- end of date-circle -->
<div class="date-circle date-today">
<a popover-trigger="mouseenter" popover-placement="bottom" uib-popover-template="'components/dashboard/directives/calendar-popover.html'">
<div class="date-day">05</div>
<div class="date-month">ŞUB</div>
</a>
<div class="year">2016</div>
</div>
<!-- end of date-circle -->
<div class="date-circle">
<a>
<div class="date-day">06</div>
<div class="date-month">ŞUB</div>
</a>
<div class="year">2016</div>
</div>
<!-- end of date-circle -->
<div class="date-circle">
<a>
<div class="date-day">07</div>
<div class="date-month">ŞUB</div>
</a>
<div class="year">2016</div>
</div>
<!-- end of date-circle -->
<div class="date-circle">
<a>
<div class="date-day">08</div>
<div class="date-month">ŞUB</div>
</a>
<div class="year">2016</div>
</div>
<!-- end of date-circle -->
</div>
<!-- end of date-circle-container -->
</div>
<!-- end of calendar-inner -->
<div class="calendar-widget-navigation">
<span class="fa fa-angle-left"></span>
<span class="fa fa-angle-right"></span>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
<div class="academic-calendar-widget-popover">
<div class="content-wrapper">
<label>5 Şubat 2016</label>
<p>Öğrenci katkı paylarının Ödenmesi için son gün</p>
</div>
<div class="content-wrapper">
<label>5 - 8 Şubat 2016</label>
<p>Etkileşimli kayıtlar ve danışman onayları (Ön lisans, lisans ve lisansüstü programlar)</p>
</div>
</div>
\ No newline at end of file
<div class="col-lg-6 col-md-12 student-assignment-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Görevler</div>
</div>
<div class="panel-body">
<ul>
<li ng-repeat="(k,v) in task_list" class="last-assignment">
<div class="panel-heading">
<div class="panel-title">{{k}}</div>
</div>
<a ng-repeat="task in v" role="button" ng-click="gototask(task.wf_token)" class="clearfix">
<span class="assignment-status">
<div class="assignment-circle" uib-tooltip="Acil"></div>
</span>
<span class="assignment-title">
<div>{{task.title}}</div>
<div>{{task.description}}</div>
</span>
<span class="assignment-due-date">
<div>18</div>
<div>ŞUB</div>
</span>
</a>
</li>
<!-- end of urgent-assignment -->
<!--<li class="approaching-assignment">-->
<!--<a href="#" class="clearfix">-->
<!--<span class="assignment-status">-->
<!--<div class="assignment-circle" uib-tooltip="Yaklaşıyor"></div>-->
<!--</span>-->
<!--<span class="assignment-title">-->
<!--<div>Storyboard Design</div>-->
<!--<div>435 - Project Management and Development</div>-->
<!--</span>-->
<!--<span class="assignment-due-date">-->
<!--<div>27</div>-->
<!--<div>ŞUB</div>-->
<!--</span>-->
<!--</a>-->
<!--</li>-->
<!--&lt;!&ndash; end of approaching-assignment &ndash;&gt;-->
<!--<li class="non-urgent-assignment">-->
<!--<a href="#" class="clearfix">-->
<!--<span class="assignment-status">-->
<!--<div class="assignment-circle" uib-tooltip="Acil olmayan"></div>-->
<!--</span>-->
<!--<span class="assignment-title">-->
<!--<div>Design Report</div>-->
<!--<div>435 - Project Management and Development</div>-->
<!--</span>-->
<!--<span class="assignment-due-date">-->
<!--<div>05</div>-->
<!--<div>MAR</div>-->
<!--</span>-->
<!--</a>-->
<!--</li>-->
<!--&lt;!&ndash; end of non-urgent-assignment &ndash;&gt;-->
<!--<li class="last-assignment">-->
<!--<div class="panel-heading">-->
<!--<div class="panel-title">Tamamlanan Son Görevler</div>-->
<!--</div>-->
<!--<a href="#" class="clearfix">-->
<!--<span class="assignment-status">-->
<!--<div></div>-->
<!--</span>-->
<!--<span class="assignment-title">-->
<!--<div>Design Report</div>-->
<!--<div>435 - Project Management and Development</div>-->
<!--</span>-->
<!--<span class="assignment-due-date">-->
<!--<div><i class="fa fa-check"></i></div>-->
<!--</span>-->
<!--</a>-->
<!--</li>-->
<!-- end of last-assignment -->
</ul>
</div>
</div>
</div>
\ No newline at end of file
<div style="width:400px;"> <div style="width:400px;">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<img src="img/sample-profile-pic.jpg" alt="{{userPopover.name}}" class="img-thumbnail"> <img ng-src="userPopover.image" alt="{{userPopover.name}}" class="img-thumbnail">
</div> </div>
</div> </div>
......
<div class="row">
<!-- ACADEMICIAN COURSES -->
<div class="col-lg-5 col-md-12 academician-course-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Dersler</div>
</div>
<div class="panel-body">
<ul>
<li><a href="#"><span>181</span> Basic Physics <div>Asistanlar: Evren Kutar</div></a></li>
<li><a href="#"><span>421</span> Research and Development <div>Asistanlar: Erkan Öğümsöğütlü</div></a></li>
<li><a href="#"><span>435</span> Project Management and Development <div>Asistanlar: -</div></a></li>
<li><a href="#"><span>207</span> Design and Use of Instructional Material <div>Asistanlar: -</div></a></li>
<li><a href="#"><span>323</span> Multimedia Design and Development <div>Asistanlar: Evren Kutar</div></a></li>
<li><a href="#"><span>475</span> Climate Change Education for Sustainability <div>Asistanlar: Evren Kutar</div></a></li>
</ul>
</div>
</div>
</div>
<!-- END OF ACADEMICIAN COURSES -->
<!-- ACADEMICIAN WEEKLY SCHEDULE -->
<div class="col-lg-7 col-md-12 academician-weekly-schedule">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Ders Programı</div>
</div>
<div class="panel-body">
<table border="1">
<tbody>
<tr class="days">
<td></td>
<td>Pazartesi</td>
<td>Salı</td>
<td>Çarşamba</td>
<td>Perşembe</td>
<td>Cuma</td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td><a uib-tooltip="Bacis Physics - Derslik 5">181</a></td>
<td></td>
<td></td>
<td><a uib-tooltip="Research and Development - Derslik 1">421</a></td>
<td></td>
</tr>
<tr>
<td>09:40 - 09:30</td>
<td><a uib-tooltip="Bacis Physics - Derslik 5">181</a></td>
<td><a uib-tooltip="Project Management and Development - Derslik 8">435</a></td>
<td></td>
<td><a uib-tooltip="Research and Development - Derslik 1">421</a></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td><a uib-tooltip="Project Management and Development - Derslik 8">435</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td><a uib-tooltip="Design and Use of Instructional Material - Derslik 4">207</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td><a uib-tooltip="Design and Use of Instructional Material - Derslik 4">207</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td><a uib-tooltip="Design and Use of Instructional Material - Derslik 4">207</a></td>
<td><a uib-tooltip="Multimedia Design and Development - Derslik 9">323</a></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><a uib-tooltip="Climate Change Education for Sustainability - Derslik 15">475</a></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><a uib-tooltip="Climate Change Education for Sustainability - Derslik 15">475</a></td>
</tr>
</tbody>
</table>
<p class="schedule-notice"><span>Not:</span> Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
</div>
<!-- END OF ACADEMICIAN WEEKLY SCHEDULE -->
</div>
\ No newline at end of file
<div class="dashboard-main-search clearfix">
<div class="row" ng-if="$root.current_user.can_search">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Arama</div>
</div>
<div class="panel-body">
<div class="dashboard-student-search" data-step="2"
data-intro="isim veya tcno ile öğrenci araması yapabilirsiniz."
ng-show="$root.searchInputs.ogrenci">
<div class="text-center">
<h3>ÖĞRENCİ</h3>
<input type="text" placeholder="Öğrenci ara" ng-model="keyword.student"
ng-keyup="search('ogrenci')">
<span class="bordered-fa-icon fa fa-search" ng-click="search('ogrenci')"></span>
</div>
<div class="dashboard-search-results" ng-show="showResults">
<ul ng-if="students.length > 0">
<li ng-repeat="student in students">
<a role="button">
<span ng-click="select(student, 'ogrenci')">{{student[0]}}</span>
<i class="fa fa-fw fa-info-circle pull-right" popover-placement="bottom"
uib-popover-template="userPopover.templateUrl"
ng-click="get_info('Ogrenci', student[2])"></i></a>
</li>
</ul>
</div>
<!-- end of dashboard-student-search-results -->
</div>
<!-- end of dashboard-student-search -->
<div class="dashboard-personnel-search" data-step="3"
data-intro="isim veya tcno ile personel araması yapabilirsiniz."
ng-show="$root.searchInputs.personel">
<div class="text-center">
<h3>PERSONEL</h3>
<input type="text" placeholder="Personel ara" ng-model="keyword.staff"
ng-keyup="search('personel')">
<span class="bordered-fa-icon fa fa-search" ng-click="search('personel')"></span>
</div>
<div class="dashboard-search-results" ng-show="showResults">
<ul ng-if="staffs.length > 0">
<li ng-repeat="staff in staffs">
<a role="button">
<span ng-click="select(staff, 'personel')">{{staff[0]}}</span>
<i class="fa fa-fw fa-info-circle pull-right"
popover-placement="bottom"
uib-popover-template="userPopover.templateUrl"
ng-click="get_info('Personel', staff[2])"></i></a>
</li>
</ul>
</div>
<!-- end of dashboard-personnel-search-results -->
</div>
<!-- end of dashboard-personnel-search -->
</div>
</div>
</div>
</div>
</div>
<!-- end of dashboard-main-search -->
<div class="row">
<div class="col-md-12 quick-links">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Hızlı İşlemler</div>
<div class="panel-action pull-right"><i class="fa fa-edit fa-fw"></i> Düzenle</div>
</div>
<div class="panel-body">
<div class="col-md-6 text-center link-buttons"
ng-repeat="item in $root.quick_menu track by $index">
<a
ng-href="#/{{item.wf}}/{{item.model}}?{{item.param}}={{selectedUser.key}}">
{{item.text}}
</a>
</div>
</div>
</div>
</div>
</div>
<!-- end of row -->
<div class="dashboard-main-anouncement clearfix">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Duyurular</div>
</div>
<div class="panel-body">
<a ng-click="markAsRead(notify)"
ng-repeat="notify in notifications[3] | limitTo:5">{{notify
.body}}</a>
</div>
</div>
</div>
</div>
</div>
<!-- end of dashboard-main-anouncement -->
\ No newline at end of file
<!-- STUDENT DASHBOARD -->
<div class="row">
<!-- STUDENT COURSES -->
<div class="col-lg-6 col-md-12 student-course-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Dersler</div>
</div>
<div class="panel-body">
<ul>
<li><a href="#"><span>181</span> Basic Physics</a></li>
<li><a href="#"><span>421</span> Research and Development</a></li>
<li><a href="#"><span>435</span> Project Management and Development</a></li>
<li><a href="#"><span>207</span> Design and Use of Instructional Material</a></li>
<li><a href="#"><span>323</span> Multimedia Design and Development</a></li>
<li><a href="#"><span>475</span> Climate Change Education for Sustainability</a></li>
</ul>
</div>
</div>
</div>
<!-- END OF STUDENT COURSES -->
<!-- STUDENT ASSIGNMENTS -->
<div class="col-lg-6 col-md-12 student-assignment-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Görevler</div>
</div>
<div class="panel-body">
<ul>
<li class="urgent-assignment">
<a href="#" class="clearfix">
<span class="assignment-status">
<div class="assignment-circle" uib-tooltip="Acil"></div>
</span>
<span class="assignment-title">
<div>Needs Assessment Document</div>
<div>435 - Project Management and Development</div>
</span>
<span class="assignment-due-date">
<div>18</div>
<div>ŞUB</div>
</span>
</a>
</li>
<!-- end of urgent-assignment -->
<li class="approaching-assignment">
<a href="#" class="clearfix">
<span class="assignment-status">
<div class="assignment-circle" uib-tooltip="Yaklaşıyor"></div>
</span>
<span class="assignment-title">
<div>Storyboard Design</div>
<div>435 - Project Management and Development</div>
</span>
<span class="assignment-due-date">
<div>27</div>
<div>ŞUB</div>
</span>
</a>
</li>
<!-- end of approaching-assignment -->
<li class="non-urgent-assignment">
<a href="#" class="clearfix">
<span class="assignment-status">
<div class="assignment-circle" uib-tooltip="Acil olmayan"></div>
</span>
<span class="assignment-title">
<div>Design Report</div>
<div>435 - Project Management and Development</div>
</span>
<span class="assignment-due-date">
<div>05</div>
<div>MAR</div>
</span>
</a>
</li>
<!-- end of non-urgent-assignment -->
<li class="last-assignment">
<div class="panel-heading">
<div class="panel-title">Tamamlanan Son Görevler</div>
</div>
<a href="#" class="clearfix">
<span class="assignment-status">
<div></div>
</span>
<span class="assignment-title">
<div>Design Report</div>
<div>435 - Project Management and Development</div>
</span>
<span class="assignment-due-date">
<div><i class="fa fa-check"></i></div>
</span>
</a>
</li>
<!-- end of last-assignment -->
</ul>
</div>
</div>
</div>
<!-- END OF STUDENT ASSIGNMENTS -->
</div>
<div class="row">
<!-- STUDENT ANNOUNCEMENTS -->
<div class="col-lg-6 col-md-12 student-announcement-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Duyurular</div>
</div>
<div class="panel-body">
<ul>
<li>
<a href="#" class="clearfix">
<span class="announcement-date">
<div>05</div>
<div>MAR</div>
</span>
<span class="announcement-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus non molestie est. Phasellus suscipit ut quam pulvinar tincidunt. Etiam accumsan vel turpis vitae vehicula. Quisque vel est nisl. In massa sapien, congue at dapibus sed, maximus eu urna.
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="announcement-date">
<div>24</div>
<div>MAR</div>
</span>
<span class="announcement-text">
Donec nec purus et nunc imperdiet vulputate quis vel turpis. Suspendisse nec bibendum odio. Praesent et enim blandit, varius diam
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="announcement-date">
<div>11</div>
<div>NİS</div>
</span>
<span class="announcement-text">
Etiam eget libero sapien. Nulla vitae ultricies quam. Aliquam gravida ligula eu leo ullamcorper tristique. Donec accumsan nec odio non viverra.
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="announcement-date">
<div>19</div>
<div>MAY</div>
</span>
<span class="announcement-text">
Maecenas fermentum, metus sed feugiat lacinia, massa sem facilisis erat, eget sollicitudin ante ipsum id dolor. Curabitur id odio eleifend, lobortis ipsum id, lacinia lacus. Morbi ac rutrum nisl, id auctor purus. Fusce vulputate elit sed massa pellentesque convallis.
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<!-- END OF STUDENT ANNOUNCEMENTS -->
<!-- STUDENT MESSAGES -->
<div class="col-lg-6 col-md-12 student-message-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Görevler</div>
</div>
<div class="panel-body">
<ul>
<li>
<a href="#" class="clearfix">
<span class="profile-pic">
<img src="../../img/gokhan.jpg">
</span>
<span class="message-content">
<div>Gökhan Boranalp</div>
<div>Lorem ipsum dolor sit amet.</div>
</span>
<span class="message-time">
14:40
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="profile-pic">
<img src="../../img/evren.jpg">
</span>
<span class="message-content">
<div>Evren Kutar</div>
<div>Donec nec purus et nunc imperdiet vulputate quis vel turpis. Suspendisse nec bibendum odio. Praesent et enim blandit, varius diam in.</div>
</span>
<span class="message-time">
12:36
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="profile-pic">
<img src="../../img/erkan.jpg">
</span>
<span class="message-content">
<div>Erkan Öğümsöğütlü</div>
<div>Duis mi sem, euismod ut dui eget, egestas tincidunt ex. Aliquam id iaculis risus.</div>
</span>
<span class="message-time">
Yesterday
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="profile-pic">
<img src="../../img/sample-profile-pic.jpg">
</span>
<span class="message-content">
<div>Teddy Joyner</div>
<div>Nulla vitae ultricies quam.</div>
</span>
<span class="message-time">
16.02.2016
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<!-- END OF STUDENT MESSAGES -->
</div>
<!-- END OF STUDENT DASHBOARD -->
\ No newline at end of file
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
'use strict'; 'use strict';
angular.module('ulakbus.debug', ['ngRoute']) angular.module('ulakbus.debug', ['ngRoute'])
.controller('DebugCtrl', function ($scope, $rootScope, $location) { .controller('DebugController', function ($scope, $rootScope, $location) {
$scope.debug_queries = $rootScope.debug_queries; $scope.debug_queries = $rootScope.debug_queries;
......
...@@ -11,10 +11,10 @@ ...@@ -11,10 +11,10 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td>Notifications:</td> <td>KeepAlive Ping:</td>
<td> <td>
<button class="btn" <button class="btn"
ng-class="{'btn-success':notificate=='on', 'btn-danger':notificate=='off'}" ng-click="setnotification()">{{notificate}}</button> ng-class="{'btn-success':keepAlive=='on', 'btn-danger':keepAlive=='off'}" ng-click="setKeepAlive()">{{keepAlive}}</button>
</td> </td>
</tr> </tr>
<tr> <tr>
......
...@@ -7,12 +7,20 @@ ...@@ -7,12 +7,20 @@
*/ */
'use strict'; 'use strict';
angular.module('ulakbus')
.factory('DevSettings', function ($cookies) {
var devSettings = {};
devSettings.settings = {
keepAlive: $cookies.get("keepAlive") || 'on'
};
return devSettings;
});
angular.module('ulakbus.devSettings', ['ngRoute']) angular.module('ulakbus.devSettings', ['ngRoute'])
.controller('DevSettingsCtrl', function ($scope, $cookies, $rootScope, RESTURL) { .controller('DevSettingsController', function ($scope, $cookies, $rootScope, RESTURL, DevSettings) {
$scope.backendurl = $cookies.get("backendurl"); $scope.backendurl = $cookies.get("backendurl");
$scope.notificate = $cookies.get("notificate") || "on"; $scope.keepAlive = $cookies.get("keepAlive") || "on";
//$scope.querydebug = $cookies.get("querydebug") || "on"; //$scope.querydebug = $cookies.get("querydebug") || "on";
$scope.changeSettings = function (what, set) { $scope.changeSettings = function (what, set) {
...@@ -30,8 +38,9 @@ angular.module('ulakbus.devSettings', ['ngRoute']) ...@@ -30,8 +38,9 @@ angular.module('ulakbus.devSettings', ['ngRoute'])
RESTURL.url = $scope.backendurl; RESTURL.url = $scope.backendurl;
}; };
$scope.setnotification = function () { $scope.setKeepAlive = function () {
$scope.changeSettings("notificate", $scope.switchOnOff($scope.notificate)); $scope.changeSettings("keepAlive", $scope.switchOnOff($scope.keepAlive));
DevSettings.settings.keepAlive = $cookies.get("keepAlive");
}; };
//$scope.setquerydebug = function () { //$scope.setquerydebug = function () {
......
...@@ -12,18 +12,18 @@ angular.module('ulakbus').config(['$routeProvider', function ($routeProvider) { ...@@ -12,18 +12,18 @@ angular.module('ulakbus').config(['$routeProvider', function ($routeProvider) {
$routeProvider $routeProvider
.when('/error/500', { .when('/error/500', {
templateUrl: 'components/error_pages/500.html', templateUrl: 'components/error_pages/500.html',
controller: '500Ctrl' controller: '500Controller'
}) })
.when('/error/404', { .when('/error/404', {
templateUrl: 'components/error_pages/404.html', templateUrl: 'components/error_pages/404.html',
controller: '404Ctrl' controller: '404Controller'
}); });
}]); }]);
angular.module('ulakbus.error_pages', ['ngRoute']) angular.module('ulakbus.error_pages', ['ngRoute'])
.controller('500Ctrl', function ($scope, $rootScope, $location) { .controller('500Controller', function ($scope, $rootScope, $location) {
}) })
.controller('404Ctrl', function ($scope, $rootScope, $location) { .controller('404Controller', function ($scope, $rootScope, $location) {
}); });
\ No newline at end of file
angular.module("ulakbus.messaging")
.directive('messaging', function (Generator, MessagingService, $log, $rootScope, MessagingPopup, Utils, $q, $timeout) {
// get channel key
function getKey (channel) {
if (!channel) return;
if (!angular.isObject(channel)) return channel;
var channelKey = channel.channel_key;
if (!channelKey && channel.hasOwnProperty('key')){
channelKey = channel.key;
}
return channelKey;
}
function searchWrapper(scope, promiseWrapper){
scope.loading = true;
scope.searchResult = [];
promiseWrapper()
.then(function(result){
scope.searchResult = result;
})
.finally(function(){
scope.loading = false;
})
}
return {
templateUrl: 'components/messaging/templates/index.html',
restrict: 'E',
scope: {},
link: function(iScope, iElem, iAttrs){
iScope.chatAppIsHidden = true;
// reset state when user log in/log out
$rootScope.$watch('loggedInUser', function(v){
iScope.loggedIn = v;
reset();
});
// shared object to populate models through scopes
iScope.shared = {};
var popupRootElement = $(iElem).find('.popup-placeholder');
function reset(){
iScope.selectedChannel = null;
iScope.allMessagesLoaded = false;
iScope.publicChannels = [];
iScope.notificationsChannel = [];
iScope.directChannels = [];
}
function editChannelPopup(channel){
return MessagingPopup.show({
templateUrl: "components/messaging/templates/create_channel.html",
rootElement: popupRootElement,
link: function(scope){
scope.channel = channel||{};
scope.title = "Kanalı düzenle";
scope.actionTitle = "Düzenle";
if (!channel){
scope.title = "Yeni Kanal Oluştur";
scope.actionTitle = "Oluştur";
}
}
})
}
function getMessageElementByKey(key){
return $("#msg-"+key);
}
function updateLastMessage(message){
if (!message && iScope.selectedChannel && iScope.selectedChannel.messages.length > 0){
var last = iScope.selectedChannel.messages.length - 1;
return iScope.lastMessage = iScope.selectedChannel.messages[last];
}
return iScope.lastMessage = message;
}
function appendMessage(channel, message){
if (channel && getKey(message) == getKey(channel)){
if (channel.messages){
channel.messages.push(message);
}
}
updateLastMessage(message);
reportLastSeenMessage();
}
function updateMessage(message){
// update current channel messages only
if (message.channel_key != getKey(iScope.selectedChannel)) return;
// update only visible messages
var storedMessage = Utils.findWhere(iScope.selectedChannel.messages, {key: message.key})
if (storedMessage){
angular.extend(storedMessage, message)
var msgElement = getMessageElementByKey(message.key);
// use manual update because of 'bind-once' for messages list
if (msgElement) {
msgElement.text(message.content);
}
}
}
function updateAndSelect(channelKey){
channelKey = getKey(channelKey);
return iScope.updateChannelsList().then(function(){
return iScope.selectChannel(channelKey);
})
}
function deleteMessageLocally(messageKey){
if (iScope.selectedChannel){
Utils.deleteWhere(iScope.selectedChannel.messages, {'key': messageKey});
}
}
function reportLastSeenMessage(){
if (!iScope.lastMessage || !iScope.selectedChannel) return;
// instantly received messages haven't timestamp. Use moment
// FIXME: change to proper moment processing
// var ts = iScope.lastMessage.moment.toISOString();
var ts = iScope.lastMessage.moment.format("YYYY-MM-DDTHH:mm:ss");
MessagingService.report_last_seen_message(getKey(iScope.selectedChannel), iScope.lastMessage.key, ts);
};
iScope.deleteConfirmation = function(title){
return MessagingPopup.show({
templateUrl: "components/messaging/templates/delete_confirmation.html",
link: function(scope){
scope.title = title || "Silmek istediğinize emin misiniz?";
},
rootElement: popupRootElement
})
};
iScope.updateChannelsList = function(){
return MessagingService.list_channels().then(function (channels) {
var groupedChannels = channels.grouped;
iScope.publicChannels = groupedChannels[MessagingService.CHANNEL_TYPE.PUBLIC];
iScope.notificationsChannel = groupedChannels[MessagingService.CHANNEL_TYPE.NOTIFICATION][0];
iScope.directChannels = groupedChannels[MessagingService.CHANNEL_TYPE.DIRECT];
});
}
iScope.createDirectChannel = function (user){
// user format is ['username', 'key', 'avatarUrl']
var key = user[1];
MessagingService.create_direct_channel(key)
.then(function(result){
updateAndSelect(getKey(result));
})
};
iScope.hideApp = function(){
iScope.chatAppIsHidden = true;
MessagingService.toggle_messaging_window_visibility(false);
};
iScope.showApp = function(){
iScope.chatAppIsHidden = false;
MessagingService.toggle_messaging_window_visibility(true);
return iScope.updateChannelsList();
}
iScope.searchUser = function(){
MessagingPopup.show({
templateUrl: "components/messaging/templates/search_user.html",
rootElement: popupRootElement,
link: function(scope){
scope.onChange = function(query){
searchWrapper(scope, function(){
return MessagingService.search_user(query);
})
};
scope.onChange("");
}
}).then(function(user){
return iScope.createDirectChannel(user);
});
};
iScope.createChannel = function(){
return editChannelPopup().then(function(channel){
return MessagingService.create_channel(channel.name, channel.description||"")
.then(function(newChannel){
updateAndSelect(newChannel)
});
})
};
iScope.applyChannelAction = function(channel, action){
var actionView = action[1];
switch (actionView) {
case '_zops_pin_channel':
MessagingService.pin_channel(getKey(channel));
break;
case '_zops_delete_channel':
iScope.deleteConfirmation('Kanalı silmek istediğinize emin misiniz?')
.then(function(){
MessagingService.delete_channel(getKey(channel)).then(function(){
iScope.selectedChannel = null;
});
});
break;
case '_zops_edit_channel':
editChannelPopup(channel).then(function(channelData){
return MessagingService.edit_channel(getKey(channelData), channelData.name, channelData.description||"");
});
break;
case '_zops_add_members':
MessagingPopup.show({
templateUrl: "components/messaging/templates/add_user_unit.html",
rootElement: popupRootElement,
link: function(scope){
scope.title = "Kanala kullanıcı ekle";
scope.placeholder = "Eklemek için kullanıcı ara";
scope.onChange = function(query){
searchWrapper(scope, function(){
return MessagingService.search_user(query);
})
};
scope.onChange("");
}
}).then(function(user){
var userKey = user.key;
var channelKey = getKey(channel);
return MessagingService.add_members(channelKey, [userKey], user.readonly);
});
break;
case "_zops_add_unit_to_channel":
MessagingPopup.show({
templateUrl: "components/messaging/templates/add_user_unit.html",
rootElement: popupRootElement,
link: function(scope){
scope.title = "Birim Ekle";
scope.placeholder = "Kanala eklemek için birim ara";
scope.onChange = function(query){
searchWrapper(scope, function(){
return MessagingService.search_unit(query);
})
};
scope.onChange("");
}
}).then(function(unit){
var unitKey = unit.key;
var channelKey = getKey(channel);
return MessagingService.add_members(channelKey, unitKey, unit.readonly);
});
break;
}
};
function selectChannel(channelKey, silent){
if (!silent) iScope.loadingChannel = true;
return MessagingService.show_channel(channelKey)
.finally(function(){
iScope.loadingChannel = false;
})
}
iScope.selectChannel = function(channel, silent){
// enable channel history loading
iScope.allMessagesLoaded = false;
var channelKey = getKey(channel);
selectChannel(channelKey, silent).then(function(result){
iScope.selectedChannel = result;
iScope.selectedChannel.read_only = channel.read_only;
iScope.selectedChannel.messages = result.last_messages;
if (iScope.selectedChannel.messages.length < 15){
iScope.allMessagesLoaded = true;
}
updateLastMessage(channel.messages);
reportLastSeenMessage();
});
};
iScope.isChannelSelected = function(channel){
return iScope.selectedChannel && getKey(channel) == getKey(iScope.selectedChannel);
}
iScope.sendMessage = function(content){
if (!content) return;
var channelKey = getKey(iScope.selectedChannel);
// select message type: 2 - direct message, 4 - channel message;
var msgType = iScope.selectedChannel.type == MessagingService.CHANNEL_TYPE.DIRECT ? 2 : 4;
MessagingService.create_message(channelKey, msgType, content).then(function(){
iScope.shared.message = "";
});
};
iScope.applyMessageAction = function(message, action){
var actionView = action[1];
switch (actionView) {
case "_zops_favorite_message":
MessagingService.add_to_favorites(message.key)
.then(function(){
// force actions to reload
message.actions = null;
});
break;
case "_zops_flag_message":
MessagingService.flag_message(message.key, true)
.then(function(){
// force actions to reload
message.actions = null;
});
break;
case "_zops_unflag_message":
MessagingService.flag_message(message.key, false)
.then(function(){
// force actions to reload
message.actions = null;
});
break;
case "_zops_delete_message":
iScope.deleteConfirmation("Mesajı silmek istediğinize emin misiniz?")
.then(function(){
return MessagingService.delete_message(message.key).then(function(){
deleteMessageLocally(message.key);
})
});
break;
case "_zops_edit_message":
// find message content container
var messageContainer = getMessageElementByKey(message.key);
MessagingPopup.show({
templateUrl: "components/messaging/templates/edit_message.html",
rootElement: messageContainer,
// activate inplace editor logic
inplaceEditor: true,
link: function (scope) {
scope.internalContent = scope.content;
scope.save = function(){
// delete message if new content is empty
if (!scope.internalContent){
return iScope.applyMessageAction(message, ['_', '_zops_delete_message']);
}
MessagingService.edit_message(message.key, scope.internalContent)
.then(function(){
// apply changes to element
scope.content = scope.internalContent;
scope.done();
});
};
}
});
break;
}
};
iScope.getMessageActions = function(message){
if (message.actions) return;
MessagingService.get_message_actions(message.key).then(function(result){
message.actions = result.actions;
})
};
iScope.loadMore = function(){
if (iScope.allMessagesLoaded) return;
if (iScope.selectedChannel.messages.length > 0){
var first = iScope.selectedChannel.messages[0];
return MessagingService.channel_history(getKey(iScope.selectedChannel), first.timestamp)
.then(function(result){
var messages = iScope.selectedChannel.messages;
if (result.messages.length == 0){
iScope.allMessagesLoaded = true;
return;
}
// prepend loaded messages to current channel messages list
messages.unshift.apply(messages, result.messages);
return true;
});
}
};
// listen to new messages and add them to selected channel if any
$rootScope.$on("message", function(e, message){
if (message.is_update){
updateMessage(message);
} else {
appendMessage(iScope.selectedChannel, MessagingService.prepareMessage(message));
}
});
// notifications in messaging window are processed as ordinary messages
$rootScope.$on("notifications", function(e, notification){
appendMessage(iScope.selectedChannel, MessagingService.prepareMessage(notification));
});
$rootScope.$on("user_ready", function(){
// init service after user logged in
reset();
iScope.hideApp();
});
$rootScope.$on(MessagingService.SHOW_MESSAGING_WINDOW_EVENT, function(e, channelKey){
var showApp = $q.when();
if (iScope.chatAppIsHidden){
showApp = iScope.showApp();
}
if (channelKey && channelKey != getKey(iScope.selectedChannel)){
showApp.then(function(){
iScope.selectChannel(channelKey);
})
}
})
}
};
})
.filter('fromNow', function(Moment){
return function(datetime){
return Moment(datetime).fromNow();
}
})
.directive("scrollDownWhenUpdate", function($timeout){
return {
link: function(iScope, iElem, iAttrs){
var elem = $(iElem);
iAttrs.$observe("scrollDownWhenUpdate", function(value){
if (value){
// update on next digest
$timeout(function(){
elem.scrollTop(elem[0].scrollHeight);
}, 0);
}
});
}
}
})
.directive("loadMoreTop", function($compile, $timeout, $q) {
// centered loader
var loaderTpl = $compile('<div class="loader" style="float: none; margin: auto; margin-top: 10px;" ng-show="loading"></div>');
return {
scope: {
loadMoreCallback: "&loadMoreTop"
},
link: function(iScope, iElem, iAttrs){
var elem = $(iElem);
iElem.prepend(angular.element(loaderTpl(iScope)));
iScope.loading = false;
function onScroll(){
var scrollTop = elem.scrollTop();
if (scrollTop <= 0 && !iScope.loading){
if (iScope.loadMoreCallback){
// save last top element with id position
var id = elem.find("[id]").first().attr('id');
$timeout(function(){iScope.loading = true});
$q.when(iScope.loadMoreCallback())
.finally(function(loaded){
$timeout(function(){
iScope.loading = false;
// if new elements loaded
if (loaded){
// try to restore last scroll position;
var lastTopElem = elem.find("#"+id);
if (lastTopElem){
var top = lastTopElem.offset().top - elem.offset().top - 100;
elem.scrollTop(top);
}
}
});
})
}
}
}
elem.scroll(onScroll);
}
}
})
.directive("contenteditable", function(){
return {
require: "?ngModel",
scope: {},
link: function(iScope, iElem, iAttrs, ngModel) {
if(!ngModel) return;
ngModel.$render = function() {
iElem.text(ngModel.$viewValue || '');
};
// Listen for change events to enable binding
iElem.on('blur keyup change', function() {
iScope.$evalAsync(read);
});
function read() {
var html = iElem.text();
ngModel.$setViewValue(html);
}
iScope.$on('$destroy', function(){
iElem.off('blur keyup change');
})
}
}
})
.directive('autoFocus', function($timeout){
function placeCaretAtEnd(el) {
el.focus();
if (typeof window.getSelection != "undefined"
&& typeof document.createRange != "undefined") {
var range = document.createRange();
range.selectNodeContents(el);
range.collapse(false);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (typeof document.body.createTextRange != "undefined") {
var textRange = document.body.createTextRange();
textRange.moveToElementText(el);
textRange.collapse(false);
textRange.select();
}
}
return {
link: function(iScope, iElem){
$timeout(function(){
placeCaretAtEnd(iElem[0]);
}, 500);
}
}
});
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
angular.module('ulakbus.messaging', ['ui.bootstrap'])
/**
* @memberof ulakbus.messaging
* @ngdoc factory
* @name MessagingService
* @description Service handles all stuff related to messaging
*/
.factory('MessagingService', function ($q, $timeout, $compile, $log, $rootScope, Moment, WSOps, Utils) {
var msg = {};
var notificationsChannelKey;
var channelsMap = {};
var groupedChannels = {};
// channels loader promise
var channelsLoader;
msg.CHANNEL_TYPE = {
"PUBLIC": 15,
"DIRECT": 10,
"NOTIFICATION": 5
};
msg.SHOW_MESSAGING_WINDOW_EVENT = "show_messaging_window";
var unread = {
messages: {count: 0},
notifications: {count: 0}
};
var currentChannelKey;
// track messaging app state for proper unread messages count
var messagingAppIsHidden = true;
function wsReady () {
/**
* wait until websocket will be open
*/
var deferred = $q.defer();
var dismissWatcher = $rootScope.$watch('websocketIsOpen', function(isOpen){
if (isOpen){
dismissWatcher();
deferred.resolve();
}
});
return deferred.promise;
}
function wsRequest (outgoing){
return wsReady().then(function(){
return WSOps.request(outgoing);
})
}
function prepareMessages (messages){
for (var i = 0; i < messages.length; i++){
var message = messages[i];
msg.prepareMessage(message);
}
}
function increaseUnread(message, messageType){
// skip current channel messages. Don't update counters
if (!messagingAppIsHidden && message.channel_key == currentChannelKey){
return;
}
// skip message updates
if (message.is_update) return;
checkIfInitialized().then(function(){
var channel = channelsMap[message.channel_key];
if (channel){
channel.unread += 1;
}
unread[messageType].count += 1;
})
}
function decreaseUnread(channel){
// get channel from channelsMap. Channels in channelMap has unread property
// which is updated when messages arrive
channel = channelsMap[channel.key];
if (channel && channel.unread){
var counter;
if (channel.type == msg.CHANNEL_TYPE.NOTIFICATION){
counter = unread.notifications
} else {
counter = unread.messages;
}
counter.count -= channel.unread;
if (counter.count < 0) counter.count = 0;
channel.unread = 0;
}
}
function checkIfInitialized(){
if (!channelsLoader){
return msg.list_channels()
}
return channelsLoader;
}
// prepare message to show in UI
msg.prepareMessage = function(message){
if (!message.timestamp){
message.moment = Moment();
} else {
var ts = message.timestamp.replace("Z", "");
message.moment = Moment(ts);
}
return message;
};
msg.get_notifications_channel_key = function(){
return checkIfInitialized().then(function(){
return notificationsChannelKey;
});
};
msg.get_unread_counters = function(){
return unread;
};
msg.reset_state = function(){
currentChannelKey = null;
notificationsChannelKey = null;
channelsMap = {};
groupedChannels = {};
unread.messages.count = 0;
unread.notifications.count = 0;
channelsLoader = false;
}
msg.toggle_messaging_window_visibility = function(visibility, resetState){
messagingAppIsHidden = !visibility;
if (resetState){
msg.reset_state();
}
};
msg.show_messaging_window = function(channelKey){
$rootScope.$broadcast(msg.SHOW_MESSAGING_WINDOW_EVENT, channelKey);
}
/**
* API
*
* */
msg.list_channels = function list_channels (){
/**
* request channels list as below;
* {
* 'view':'_zops_list_channels',
* }
*
* wait for response
*
* {
* 'channels': [
* {'name': string, // name of channel
* 'key': key, // key of channel
* 'unread': int, // unread message count
* 'type': int, // channel type,
* // 15: public channels (chat room/broadcast channel distinction comes from "read_only" flag)
* // 10: direct channels
* // 5: one and only private channel which can be "Notifications"
* 'read_only': boolean, // true if this is a read-only subscription to a broadcast channel
* // false if it's a public chat room
*
* 'actions':[('action name', 'view name'),]
* }
*
*/
var outgoing = {
view: '_zops_list_channels'
};
channelsLoader = wsRequest(outgoing).then(function (data) {
var initialGroups = {};
initialGroups[msg.CHANNEL_TYPE.PUBLIC] = [];
initialGroups[msg.CHANNEL_TYPE.DIRECT] = [];
initialGroups[msg.CHANNEL_TYPE.NOTIFICATION] = [];
groupedChannels = Utils.groupBy(data.channels||[], "type", initialGroups);
// add all channels to channels map
for (var i = 0; i < data.channels.length; i++){
var channel = data.channels[i];
channelsMap[channel.key] = channel;
}
// save notifications channel key
notificationsChannelKey = groupedChannels[msg.CHANNEL_TYPE.NOTIFICATION][0].key;
return {grouped: groupedChannels, channelsMap: channelsMap};
});
return channelsLoader;
};
msg.search_user = function (query) {
var outgoing = {
view: '_zops_search_user',
query: query
};
return wsRequest(outgoing).then(function (data) {
return data.results
});
};
msg.search_unit = function (query) {
var outgoing = {
view: '_zops_search_unit',
query: query
};
return wsRequest(outgoing).then(function (data) {
return data.results
});
};
msg.create_direct_channel = function (key) {
var outgoing = {
'view': '_zops_create_direct_channel',
'user_key': key
};
return wsRequest(outgoing).then(function(result){
$log.info("Create direct channel result: ", result);
return result;
})
};
msg.create_channel = function (name, desription) {
var outgoing = {
view:'_zops_create_channel',
name: name,
description: desription
};
return wsRequest(outgoing).then(function(result){
$log.info("Channel ", name, "created: ", result);
return result;
})
};
msg.add_members = function (channelKey, members, readOnly) {
var outgoing = {
view:'_zops_add_members',
channel_key: channelKey,
read_only: !!readOnly,
members: members
};
return wsRequest(outgoing).then(function(result){
$log.info("Members ", members, " added to channel ", channelKey, ": ", result);
return result;
})
};
msg.add_unit_to_channel = function (channelKey, unitKey, readOnly) {
var outgoing = {
view: '_zops_add_unit_to_channel',
channel_key: channelKey,
unit_key: unitKey,
read_only: !!readOnly
};
return wsRequest(outgoing).then(function(result){
$log.info("Unit ", unitKey, " added to channel ", channelKey, ": ", result);
return result;
});
};
msg.delete_channel = function (channelKey) {
var outgoing = {
view: '_zops_delete_channel',
channel_key: channelKey
};
return wsRequest(outgoing).then(function(result){
$log.info("Channel ", channelKey, " deleted: ", result);
if (channelsMap[channelKey]){
channelsMap[channelKey].deleted = true;
}
return result;
})
};
msg.edit_channel = function (channelKey, name, desription) {
var outgoing = {
view:'_zops_edit_channel',
channel_key: channelKey,
name: name,
description: desription
};
return wsRequest(outgoing).then(function(result){
$log.info("Channel ", channelKey, " edited: ", outgoing, result);
return result;
})
};
msg.pin_channel = function (channelKey) {
var outgoing = {
view: '_zops_pin_channel',
channel_key: channelKey
};
return wsRequest(outgoing).then(function(result){
$log.info("Channel ", channelKey, " pinned: ", result);
return result;
})
};
msg.show_channel = function(channelKey){
var outgoing = {
view: '_zops_show_channel',
key: channelKey
};
return wsRequest(outgoing).then(function(result){
$log.info("Show channel ", channelKey, ": ", result);
// decrease unread messages for current channel
decreaseUnread(result);
// save current channel key
currentChannelKey = result.key;
prepareMessages(result.last_messages);
return result;
})
};
msg.channel_history = function (channelKey, lastMessageTimestamp) {
var outgoing = {
view:'_zops_channel_history',
channel_key: channelKey,
timestamp: lastMessageTimestamp
};
return wsRequest(outgoing).then(function(result){
$log.info("Load channel ", channelKey, "history: ", result);
prepareMessages(result.messages);
return result;
})
};
msg.get_unread_messages_count = function(){
var outgoing = {
'view': '_zops_unread_count'
};
return wsRequest(outgoing).then(function(result){
$log.info("Get unread messages count: ", result);
// update internal unread messages counters
unread.messages.count = result.messages;
unread.notifications.count = result.notifications;
return result;
})
};
msg.report_last_seen_message = function (channelKey, msgKey, timestamp){
var outgoing = {
view: '_zops_report_last_seen_message',
channel_key: channelKey,
msg_key: msgKey,
timestamp: timestamp
};
return wsRequest(outgoing).then(function(result){
$log.info("Report last seen message ", channelKey, msgKey, timestamp, ": ", result);
return result;
})
};
msg.create_message = function(channelKey, msgType, body, attachments){
var outgoing = {
view: '_zops_create_message',
message: {
channel: channelKey,
type: msgType,
title: "",
receiver: "",
body: body,
attachments: attachments
}
};
return wsRequest(outgoing).then(function(result){
$log.info("Message sent: ", result);
return result;
})
};
msg.find_message = function (channelKey, query, pageNumber) {
var outgoing = {
view: '_zops_search_find_message',
channel_key: channelKey,
query: query,
page: pageNumber
};
return wsRequest(outgoing).then(function(result){
$log.info("Find message: ", result);
return result;
});
};
msg.delete_message = function (msgKey) {
var outgoing = {
view: '_zops_delete_message',
key: msgKey
};
return wsRequest(outgoing).then(function(result){
$log.info("Delete message ", msgKey,":", result);
return result;
});
};
msg.edit_message = function(msgKey, body) {
var outgoing = {
view: '_zops_edit_message',
message: {
key: msgKey,
body: body
}
};
return wsRequest(outgoing).then(function(result){
$log.info("Edit message", msgKey, ":", result);
return result;
});
};
msg.flag_message = function (msgKey, flag) {
var outgoing = {
view: '_zops_flag_message',
key: msgKey,
flag: flag
};
return wsRequest(outgoing).then(function(result){
$log.info("Flag message ", msgKey, flag, ":", result);
return result;
});
};
msg.get_message_actions = function (msgKey) {
var outgoing = {
view: '_zops_get_message_actions',
key: msgKey
};
return wsRequest(outgoing).then(function(result){
$log.info("Get message actions", msgKey, ":", result);
return result;
});
};
msg.add_to_favorites = function (msgKey) {
var outgoing = {
view: '_zops_add_to_favorites',
key: msgKey
};
return wsRequest(outgoing).then(function(result){
$log.info("Add message ", msgKey, " to favorites: ", result);
return result;
});
};
msg.remove_from_favorites = function (msgKey) {
var outgoing = {
view: '_zops_remove_to_favorites',
key: msgKey
};
return wsRequest(outgoing).then(function(result){
$log.info("Remove message ", msgKey, " from favorites: ", result);
return result;
});
};
msg.list_favorites = function (channelKey) {
var outgoing = {
view: '_zops_list_favorites',
channel_key: channelKey
};
return wsRequest(outgoing).then(function(result){
$log.info("List favorites for channel", channelKey, ": ", result);
return result;
});
};
/**
* Event listeners
*/
$rootScope.$on("message", function(e, message){
increaseUnread(message, 'messages');
});
$rootScope.$on("notifications", function(e, message){
increaseUnread(message, 'notifications');
});
$rootScope.$on("channel_change", function(e, action, channel){
checkIfInitialized().then(function(){
if (action == 'add'){
var group = groupedChannels[channel.type];
if (!channelsMap[channel.key]){
channelsMap[channel.key] = channel;
}
return group.push(channel);
}
if (action == 'status'){
var localChannel = channelsMap[channel.channel_key];
if (localChannel){
localChannel.is_online = channel.is_online;
}
}
})
});
// reset state on logout
$rootScope.$watch("loggedInUser", function(value){
if (!value){
msg.reset_state();
};
});
// initialize unread messages counter when user logged in
$rootScope.$on("user_ready", function(){
msg.get_unread_messages_count();
});
return msg;
})
.service("MessagingPopup", function($q, $compile, $http, $rootScope){
function compile(template, config){
var resultDeferred = $q.defer();
var scope = config.scope || $rootScope.$new(true);
var rootElement = config.rootElement;
var originalContent, element;
if (config.inplaceEditor){
originalContent = rootElement.text();
scope.content = originalContent;
}
scope.done = function(result){
resultDeferred.resolve.apply(this, arguments);
};
scope.cancel = function(){
resultDeferred.reject.apply(this, arguments);
};
if (config.link){
config.link(scope);
}
element = $compile(template)(scope);
rootElement.empty();
rootElement.append(element);
resultDeferred.promise._done = scope.done;
resultDeferred.promise._cancel = scope.cancel;
return resultDeferred.promise
.finally(function(){
// inplace editor can change scope.content and it will be applied to original rootElement
if (config.inplaceEditor){
rootElement.text(scope.content);
} else {
rootElement.empty();
}
scope.$destroy();
});
}
this.show = function(config){
if (config.templateUrl){
return $http({method: 'GET', url: config.templateUrl, cache: true}).then(function(result){
return compile(result.data, config)
});
}
return compile(config.template, config);
};
})
<div class="chat-popup-window add-user-unit" style="display:block;">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<h3>{{title}}</h3>
<label class="checkbox-inline" >
<input type="checkbox" ng-model="readonly"/>
Read only
</label>
<div class="text-center">
<input type="text" ng-model="query" ng-change="onChange(query)" placeholder="{{placeholder}}">
</div>
<div class="search-results">
<span class="loader" ng-show="loading"></span>
<div class="user" ng-repeat="item in searchResult" ng-click="done({key: item[1], readonly: readonly})">
<img ng-src="{{item[2]}}" ng-show="item[2]">
<div class="user-name">{{item[0]}}</div>
</div>
</div>
</div>
<span class="loader" ng-show="loadingChannel"></span>
<div class="conversation-section conversation-section-empty" ng-hide="selectedChannel">
<div class="close-chat-app" ng-click="hideApp()">
<span class="glyphicon glyphicon-remove" ></span>
</div>
<div class="conversation-body" >
Konuşmaya başlamak için bir kanal seçin ya da oluşturun.
</div>
</div>
<div class="conversation-section" ng-hide="loadingChannel || !selectedChannel">
<div class="conversation-header">
<div class="conversation-user">
<div class="user-photo" ng-show="selectedChannel.avatar_url"><img ng-src="{{selectedChannel.avatar_url}}"></div>
<div class="user-name" title="{{selectedChannel.description}}">{{selectedChannel.name}}</div>
</div>
<div class="conversation-search">
<input type="text" placeholder="Arama Yap">
</div>
<div class="dropdown">
<div class="chat-app-actions dropdown-toggle" data-toggle="dropdown" id="chat-app-actions">
<span class="glyphicon glyphicon-option-vertical"></span>
</div>
<ul class="dropdown-menu" ng-show="selectedChannel.actions.length > 0" aria-labelledby="chat-app-actions" style="left: inherit; top: 53px; right: 66px;" >
<li><a ng-click="applyChannelAction(selectedChannel, action)" ng-repeat="action in selectedChannel.actions">{{action[0]}}</a></li>
</ul>
</div>
<div class="close-chat-app" ng-click="hideApp()">
<span class="glyphicon glyphicon-remove"></span>
</div>
</div>
<div class="conversation-body" ng-class="{readonly: selectedChannel.read_only}" scroll-down-when-update="{{lastMessage}}" load-more-top="loadMore()">
<div class="conversation-body-inner">
<div class="beginning-of-conversation" ng-show="allMessagesLoaded">
Burası yazışmanın başı!
</div>
<div class="conversation-block clearfix" ng-repeat="msg in selectedChannel.messages">
<div class="conversation-actions">
<div class="action dropdown-toggle" data-toggle="dropdown" ng-click="getMessageActions(msg)">
<span class="glyphicon glyphicon-option-horizontal"></span>
</div>
<ul class="dropdown-menu" style="left:-86px;" >
<li ng-repeat="act in msg.actions"><a ng-click="applyMessageAction(msg, act)">{{act[0]}}</a></li>
</ul>
</div>
<div class="user-photo">
<img ng-src="{{::msg.avatar_url}}" ng-if="msg.avatar_url">
</div>
<div class="user-message">
<div class="message-header clearfix">
<div class="user-name">{{::msg.sender_name}}</div>
<div class="message-time">{{::msg.moment|fromNow}}</div>
</div>
<div class="message-content">
<div class="editable-message-content" id="msg-{{::msg.key}}">{{::msg.content}}</div>
<a class="message-content-url" href="{{::msg.url}}" ng-click="hideApp()" ng-if="msg.url">{{::msg.url}}</a>
</div>
</div>
</div>
</div>
</div>
<div class="conversation-footer" ng-show="!selectedChannel.read_only">
<textarea placeholder="Mesajını buraya yaz..." ng-model="shared.message" on-enter-pressed="sendMessage(shared.message)"></textarea>
<div class="add-attachment">
<span class="glyphicon glyphicon-send" ng-click="sendMessage(shared.message);"></span>
<div class="dropup" style="float:left;">
<span class="glyphicon glyphicon-paperclip dropdown-toggle" data-toggle="dropdown" id="attachment"></span>
<ul class="dropdown-menu" aria-labelledby="attachment" style="left:-104px;">
<li><a >Görsel</a></li>
<li><a >Dosya</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="chat-popup-window create-new-channel-window">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<h3>{{title}}</h3>
<div class="text-center">
<input type="text" placeholder="Channel Name" ng-model="channel.name"><br>
<textarea placeholder="Channel Description" ng-model="channel.description"></textarea>
<button class="btn btn-success" ng-click="done(channel)">{{actionTitle}}</button>
</div>
</div>
<div class="chat-popup-window confirmation-window">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<div class="text-center" style="margin-top: 150px;font-size: 26px;">
<p>{{title}}</p>
<button class="btn btn-success" style="font-size: 20px;" ng-click="done()">Evet</button>
<button class="btn btn-default" style="font-size: 20px;" ng-click="cancel()">Vazgeç</button>
</div>
</div>
<div class="edit-text-message">
<div class="editor" contenteditable="" auto-focus on-enter-pressed="save()" on-esc-pressed="cancel()" ng-model="internalContent"></div>
<button class="btn btn-default" ng-click="cancel()">Cancel</button>
<button class="btn btn-success" ng-click="save()">Save Changes</button>
</div>
<div ng-show="loggedIn">
<a class="chat-app-button" ng-show="chatAppIsHidden" ng-click="showApp()"><i class="glyphicon glyphicon-comment"></i></a>
<div class="chat-app" ng-hide="chatAppIsHidden">
<div class="chat-app-container">
<div class="side-navigation">
<ul class="channels">
<li class="title" ng-click="selectChannel(notificationsChannel)">BİLDİRİMLER <span class="badge" ng-show="notificationsChannel.unread">{{notificationsChannel.unread}}</span></li>
</ul>
<ul class="channels">
<li class="title">KANALLAR <span class="add-action glyphicon glyphicon-plus-sign" ng-click="createChannel()"></span></li>
<li ng-class="{'unread': ch.unread, 'public-ro-channel': ch.read_only, 'active': isChannelSelected(ch)}" title="{{ch.description}}" ng-repeat="ch in publicChannels" ng-click="selectChannel(ch)" ng-hide="ch.deleted">{{ch.name}}</li>
</ul>
<ul class="direct-messages">
<li class="title">MESAJLAR <span class="add-action glyphicon glyphicon-plus-sign" ng-click="searchUser()"></span></li>
<li ng-class="{'unread': userChannel.unread, 'active': isChannelSelected(userChannel), 'online': userChannel.is_online}" ng-repeat="userChannel in directChannels" ng-click="selectChannel(userChannel)" ng-hide="userChannel.deleted">{{userChannel.name}}</li>
</ul>
</div>
<ng-include src="'components/messaging/templates/conversation.html'"></ng-include>
<div class="popup-placeholder"></div>
</div>
</div>
</div>
<div class="chat-popup-window create-new-message-window">
<div class="close-chat-popup-window" ng-click="cancel()"><span class="glyphicon glyphicon-remove"></span></div>
<input type="text" placeholder="Birini ismi ile ara..." ng-model="query" ng-change="onChange(query)">
<div class="search-results">
<span class="loader" ng-show="loading"></span>
<div class="user" ng-repeat="user in searchResult" ng-click="done(user)">
<img ng-src="{{user[2]}}" ng-show="user[2]">
<div class="user-name">{{user[0]}}</div>
</div>
</div>
</div>
<div class="row">
<!-- ACADEMICIAN COURSES -->
<div class="col-lg-5 col-md-12 academician-course-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Dersler</div>
</div>
<div class="panel-body">
<ul>
<li><a href="#"><span>181</span> Basic Physics <div>Asistanlar: Evren Kutar</div></a></li>
<li><a href="#"><span>421</span> Research and Development <div>Asistanlar: Erkan Öğümsöğütlü</div></a></li>
<li><a href="#"><span>435</span> Project Management and Development <div>Asistanlar: -</div></a></li>
<li><a href="#"><span>207</span> Design and Use of Instructional Material <div>Asistanlar: -</div></a></li>
<li><a href="#"><span>323</span> Multimedia Design and Development <div>Asistanlar: Evren Kutar</div></a></li>
<li><a href="#"><span>475</span> Climate Change Education for Sustainability <div>Asistanlar: Evren Kutar</div></a></li>
</ul>
</div>
</div>
</div>
<!-- END OF ACADEMICIAN COURSES -->
<!-- ACADEMICIAN WEEKLY SCHEDULE -->
<div class="col-lg-7 col-md-12 academician-weekly-schedule">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Ders Programı</div>
</div>
<div class="panel-body">
<table border="1">
<tbody>
<tr class="days">
<td></td>
<td>Pazartesi</td>
<td>Salı</td>
<td>Çarşamba</td>
<td>Perşembe</td>
<td>Cuma</td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td><a uib-tooltip="Bacis Physics - Derslik 5">181</a></td>
<td></td>
<td></td>
<td><a uib-tooltip="Research and Development - Derslik 1">421</a></td>
<td></td>
</tr>
<tr>
<td>09:40 - 09:30</td>
<td><a uib-tooltip="Bacis Physics - Derslik 5">181</a></td>
<td><a uib-tooltip="Project Management and Development - Derslik 8">435</a></td>
<td></td>
<td><a uib-tooltip="Research and Development - Derslik 1">421</a></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td><a uib-tooltip="Project Management and Development - Derslik 8">435</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td><a uib-tooltip="Design and Use of Instructional Material - Derslik 4">207</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td><a uib-tooltip="Design and Use of Instructional Material - Derslik 4">207</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td><a uib-tooltip="Design and Use of Instructional Material - Derslik 4">207</a></td>
<td><a uib-tooltip="Multimedia Design and Development - Derslik 9">323</a></td>
<td></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><a uib-tooltip="Climate Change Education for Sustainability - Derslik 15">475</a></td>
</tr>
<tr>
<td>08:40 - 09:30</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><a uib-tooltip="Climate Change Education for Sustainability - Derslik 15">475</a></td>
</tr>
</tbody>
</table>
<p class="schedule-notice"><span>Not:</span> Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
</div>
<!-- END OF ACADEMICIAN WEEKLY SCHEDULE -->
</div>
\ No newline at end of file
<select ng-model="selection" ng-options="item for item in items">
</select>
<div ng-switch on="selection">
<div ng-app="ulakbus.dashboard" class="dashboard academician-dashboard">
<div class="starter-template">
<div ng-switch-default="student">
<ng-include src="'components/uitemplates/student.html'"></ng-include>
</div>
<div ng-switch-when="staff">
<ng-include src="'components/uitemplates/staff.html'"></ng-include>
</div>
<div ng-switch-when="academician">
<ng-include src="'components/uitemplates/academician.html'"></ng-include>
</div>
</div>
</div>
</div>
\ No newline at end of file
<div>
<select ng-model="selection" ng-options="trialList.indexOf(trial) as trial.name for trial in trialList" ng-change="selectform(selection)">
</select>
<div class="container">
<div class="row">
<div class="col-xs-8 center">
<form sf-schema="schema" sf-form="form" sf-model="model"></form>
</div>
</div>
</div>
</div>
\ No newline at end of file
/**
* @license Ulakbus-UI
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*/
describe("FormServicePg", function(){
beforeEach(module('ulakbus'));
beforeEach(module('ulakbus.uitemplates'));
beforeEach(module('ulakbus.formService'));
var $controller;
beforeEach(inject(function(_$compile_, _$controller_){
// The injector unwraps the underscores (_) from around the parameter names when matching
$compile = _$compile_;
$controller = _$controller_;
}));
describe("Controller is loaded", function(){
expect("FormServicePG").toBeDefined();
})
describe('RESTURL', function(){
it('is Loaded',
inject(function(RESTURL){
expect(RESTURL).toBeDefined();
})
);
})
describe('Generator', function(){
it('is Loaded',
inject(function(Generator){
expect(Generator).toBeDefined();
})
);
})
describe("$scope.selectform", function() {
it("Generates schemaForm structures if $scope.forms parameters implemented properly.",
inject(function (Generator) {
var $scope = {};
var controller = $controller('FormServicePg', {$scope: $scope, Generator: Generator});
$scope.forms = [
{
name: 'Deneme Form 1',
form: ['email', 'id', 'name'],
schema: {
properties: {
email: {title: 'email', type: 'string'},
id: {title: 'id', type: 'int'},
name: {title: 'name', type: 'string'}
}, required: [], type: 'object', title: 'servicetest'
},
model: {
email: 'test@test.com', id: 2, name: 'travolta'
}
},
{
name: 'Deneme Form 2',
form: ['email', 'id', 'name'],
schema: {
properties: {
email: {title: 'email', type: 'string'},
id: {title: 'id', type: 'number'},
name: {title: 'name', type: 'string'}
}, required: [], type: 'object', title: 'servicetest'
},
model: {
email: 'test@test.com', id: 2, name: 'cageman'
}
}
];
$scope.form_params = {};
$scope.selection = 0;
$scope.selectform($scope.selection);
expect($scope.schema.properties.id.type).toEqual('number');
})
)}
)
})
<div class="dashboard-main-search clearfix">
<div class="row" ng-if="$root.current_user.can_search">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Arama</div>
</div>
<div class="panel-body">
<div class="dashboard-student-search" data-step="2"
data-intro="isim veya tcno ile öğrenci araması yapabilirsiniz."
ng-show="$root.searchInputs.ogrenci">
<div class="text-center">
<h3>ÖĞRENCİ</h3>
<input type="text" placeholder="Öğrenci ara" ng-model="keyword.student"
ng-keyup="search('ogrenci')">
<span class="bordered-fa-icon fa fa-search" ng-click="search('ogrenci')"></span>
</div>
<div class="dashboard-search-results" ng-show="showResults">
<ul ng-if="students.length > 0">
<li ng-repeat="student in students">
<a role="button">
<span ng-click="select(student, 'ogrenci')">{{student[0]}}</span>
<i class="fa fa-fw fa-info-circle pull-right" popover-placement="bottom"
uib-popover-template="userPopover.templateUrl"
ng-click="get_info('Ogrenci', student[2])"></i></a>
</li>
</ul>
</div>
<!-- end of dashboard-student-search-results -->
</div>
<!-- end of dashboard-student-search -->
<div class="dashboard-personnel-search" data-step="3"
data-intro="isim veya tcno ile personel araması yapabilirsiniz."
ng-show="$root.searchInputs.personel">
<div class="text-center">
<h3>PERSONEL</h3>
<input type="text" placeholder="Personel ara" ng-model="keyword.staff"
ng-keyup="search('personel')">
<span class="bordered-fa-icon fa fa-search" ng-click="search('personel')"></span>
</div>
<div class="dashboard-search-results" ng-show="showResults">
<ul ng-if="staffs.length > 0">
<li ng-repeat="staff in staffs">
<a role="button">
<span ng-click="select(staff, 'personel')">{{staff[0]}}</span>
<i class="fa fa-fw fa-info-circle pull-right"
popover-placement="bottom"
uib-popover-template="userPopover.templateUrl"
ng-click="get_info('Personel', staff[2])"></i></a>
</li>
</ul>
</div>
<!-- end of dashboard-personnel-search-results -->
</div>
<!-- end of dashboard-personnel-search -->
</div>
</div>
</div>
</div>
</div>
<!-- end of dashboard-main-search -->
<div class="row">
<div class="col-md-12 quick-links">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Hızlı İşlemler</div>
<div class="panel-action pull-right"><i class="fa fa-edit fa-fw"></i> Düzenle</div>
</div>
<div class="panel-body">
<div class="col-md-6 text-center link-buttons"
ng-repeat="item in $root.quick_menu track by $index">
<a
ng-href="#/{{item.wf}}/{{item.model}}?{{item.param}}={{selectedUser.key}}">
{{item.text}}
</a>
</div>
</div>
</div>
</div>
</div>
<!-- end of row -->
<div class="dashboard-main-anouncement clearfix">
<div class="row">
<div class="col-md-12">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Duyurular</div>
</div>
<div class="panel-body">
<a ng-click="markAsRead(notify)"
ng-repeat="notify in notifications[3] | limitTo:5">{{notify
.body}}</a>
</div>
</div>
</div>
</div>
</div>
<!-- end of dashboard-main-anouncement -->
\ No newline at end of file
<!-- STUDENT DASHBOARD -->
<div class="row">
<!-- STUDENT COURSES -->
<div class="col-lg-6 col-md-12 student-course-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Dersler</div>
</div>
<div class="panel-body">
<ul>
<li><a href="#"><span>181</span> Basic Physics</a></li>
<li><a href="#"><span>421</span> Research and Development</a></li>
<li><a href="#"><span>435</span> Project Management and Development</a></li>
<li><a href="#"><span>207</span> Design and Use of Instructional Material</a></li>
<li><a href="#"><span>323</span> Multimedia Design and Development</a></li>
<li><a href="#"><span>475</span> Climate Change Education for Sustainability</a></li>
</ul>
</div>
</div>
</div>
<!-- END OF STUDENT COURSES -->
<!-- STUDENT ASSIGNMENTS -->
<div class="col-lg-6 col-md-12 student-assignment-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Görevler</div>
</div>
<div class="panel-body">
<ul>
<li class="urgent-assignment">
<a href="#" class="clearfix">
<span class="assignment-status">
<div class="assignment-circle" uib-tooltip="Acil"></div>
</span>
<span class="assignment-title">
<div>Needs Assessment Document</div>
<div>435 - Project Management and Development</div>
</span>
<span class="assignment-due-date">
<div>18</div>
<div>ŞUB</div>
</span>
</a>
</li>
<!-- end of urgent-assignment -->
<li class="approaching-assignment">
<a href="#" class="clearfix">
<span class="assignment-status">
<div class="assignment-circle" uib-tooltip="Yaklaşıyor"></div>
</span>
<span class="assignment-title">
<div>Storyboard Design</div>
<div>435 - Project Management and Development</div>
</span>
<span class="assignment-due-date">
<div>27</div>
<div>ŞUB</div>
</span>
</a>
</li>
<!-- end of approaching-assignment -->
<li class="non-urgent-assignment">
<a href="#" class="clearfix">
<span class="assignment-status">
<div class="assignment-circle" uib-tooltip="Acil olmayan"></div>
</span>
<span class="assignment-title">
<div>Design Report</div>
<div>435 - Project Management and Development</div>
</span>
<span class="assignment-due-date">
<div>05</div>
<div>MAR</div>
</span>
</a>
</li>
<!-- end of non-urgent-assignment -->
<li class="last-assignment">
<div class="panel-heading">
<div class="panel-title">Tamamlanan Son Görevler</div>
</div>
<a href="#" class="clearfix">
<span class="assignment-status">
<div></div>
</span>
<span class="assignment-title">
<div>Design Report</div>
<div>435 - Project Management and Development</div>
</span>
<span class="assignment-due-date">
<div><i class="fa fa-check"></i></div>
</span>
</a>
</li>
<!-- end of last-assignment -->
</ul>
</div>
</div>
</div>
<!-- END OF STUDENT ASSIGNMENTS -->
</div>
<div class="row">
<!-- STUDENT ANNOUNCEMENTS -->
<div class="col-lg-6 col-md-12 student-announcement-list">
<div class="panel panel-default">
<div class="panel-heading">
<div class="panel-title">Duyurular</div>
</div>
<div class="panel-body">
<ul>
<li>
<a href="#" class="clearfix">
<span class="announcement-date">
<div>05</div>
<div>MAR</div>
</span>
<span class="announcement-text">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus non molestie est. Phasellus suscipit ut quam pulvinar tincidunt. Etiam accumsan vel turpis vitae vehicula. Quisque vel est nisl. In massa sapien, congue at dapibus sed, maximus eu urna.
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="announcement-date">
<div>24</div>
<div>MAR</div>
</span>
<span class="announcement-text">
Donec nec purus et nunc imperdiet vulputate quis vel turpis. Suspendisse nec bibendum odio. Praesent et enim blandit, varius diam
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="announcement-date">
<div>11</div>
<div>NİS</div>
</span>
<span class="announcement-text">
Etiam eget libero sapien. Nulla vitae ultricies quam. Aliquam gravida ligula eu leo ullamcorper tristique. Donec accumsan nec odio non viverra.
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="announcement-date">
<div>19</div>
<div>MAY</div>
</span>
<span class="announcement-text">
Maecenas fermentum, metus sed feugiat lacinia, massa sem facilisis erat, eget sollicitudin ante ipsum id dolor. Curabitur id odio eleifend, lobortis ipsum id, lacinia lacus. Morbi ac rutrum nisl, id auctor purus. Fusce vulputate elit sed massa pellentesque convallis.
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<!-- END OF STUDENT ANNOUNCEMENTS -->
<!-- STUDENT MESSAGES -->
<div class="col-lg-6 col-md-12 student-message-list">
<div class="panel panel-d efault">
<div class="panel-heading">
<div class="panel-title">Mesajlar</div>
</div>
<div class="panel-body">
<ul>
<li>
<a href="#" class="clearfix">
<span class="profile-pic">
<img src="../../img/gokhan.jpg">
</span>
<span class="message-content">
<div>Gökhan Boranalp</div>
<div>Lorem ipsum dolor sit amet.</div>
</span>
<span class="message-time">
14:40
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="profile-pic">
<img src="../../img/evren.jpg">
</span>
<span class="message-content">
<div>Evren Kutar</div>
<div>Donec nec purus et nunc imperdiet vulputate quis vel turpis. Suspendisse nec bibendum odio. Praesent et enim blandit, varius diam in.</div>
</span>
<span class="message-time">
12:36
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="profile-pic">
<img src="../../img/erkan.jpg">
</span>
<span class="message-content">
<div>Erkan Öğümsöğütlü</div>
<div>Duis mi sem, euismod ut dui eget, egestas tincidunt ex. Aliquam id iaculis risus.</div>
</span>
<span class="message-time">
Yesterday
</span>
</a>
</li>
<li>
<a href="#" class="clearfix">
<span class="profile-pic">
<img src="../../img/sample-profile-pic.jpg">
</span>
<span class="message-content">
<div>Teddy Joyner</div>
<div>Nulla vitae ultricies quam.</div>
</span>
<span class="message-time">
16.02.2016
</span>
</a>
</li>
</ul>
</div>
</div>
</div>
<!-- END OF STUDENT MESSAGES -->
</div>
<!-- END OF STUDENT DASHBOARD -->
\ No newline at end of file
...@@ -6,17 +6,72 @@ ...@@ -6,17 +6,72 @@
* (GPLv3). See LICENSE.txt for details. * (GPLv3). See LICENSE.txt for details.
*/ */
// 'use strict'; angular.module('ulakbus.uitemplates', ['ngRoute', 'ulakbus.crud'])
.controller('NewDesignsCtrl', function ($scope) {
$scope.items = ['student', 'staff', 'academician'];
$scope.selection = $scope.items[0];
})
.controller('FormServicePg', function ($scope, Generator, CrudUtility) {
// app.config(['$routeProvider', function ($routeProvider) { /*
// $routeProvider This controller is for testing new SchemaForm components. In addition, forms need to have the attribute:
// .when('/500', { "name" for defining the name shown in dropdown box. Paste the JSON of form as a member of $scope.forms.
// templateUrl: 'components/uitemplates/500.html', */
// controller: '500Ctrl' $scope.trialList = [
// }); {
// }]); name: 'Deneme Form 1',
form: ['email', 'id', 'name', 'valid'],
schema: {
properties: {
email: {title: 'email', type: 'string'},
id: {title: 'id', type: 'number'},
name: {title: 'name', type: 'string'},
valid: { type: 'submit', cmd:"list_user2", title: "submit with validation" }
angular.module('ulakbus.uitemplates', ['ngRoute']) }, required: ["email", "id", "name"], type: 'object', title: 'servicetest'
},
model: {
email: 'test@test.com', id: 2, name: 'travolta'
}
},
{
name: 'Confirm Form Trial',
form: ['email', 'id', 'name', 'confirm'],
schema: {
properties: {
email: {title: 'email', type: 'string'},
id: {title: 'id', type: 'number'},
name: {title: 'name', type: 'string'},
confirm: {
title: 'Confirm Form',
style:"btn-success",
type:'confirm',
confirm_message:"Lorem Ipsum Dolor Sit Amet",
buttons: [
{ text: "button 1", cmd:"cmd1", style: "btn-warning"},
{ text: "button 2", cmd:"cmd2", style: "btn-success"}
],
readonly:"true",
form_validate: false}
}, required: [], type: 'object', title: 'servicetest'
},
model: {
email: 'test@test.com', id: 3, name: 'cageman'
}
}
];
$scope.form_params = {};
$scope.selection = 0;
$scope.meta = {};
// .controller('500Ctrl', function ($scope, $rootScope, $location) { $scope.selectform = function (index) {
// }); var data = { forms: $scope.trialList[index] };
\ No newline at end of file CrudUtility.listPageItems($scope, data);
Generator.generate($scope, data);
Generator.setPageData({pageData: false});
};
$scope.selectform($scope.selection);
});
\ No newline at end of file
...@@ -5,4 +5,4 @@ angular.module('ulakbus.version', [ ...@@ -5,4 +5,4 @@ angular.module('ulakbus.version', [
'ulakbus.version.version-directive' 'ulakbus.version.version-directive'
]) ])
.value('version', '0.6.10'); .value('version', '0.1.1');
\ No newline at end of file \ No newline at end of file
...@@ -5,7 +5,7 @@ describe('ulakbus.version module', function() { ...@@ -5,7 +5,7 @@ describe('ulakbus.version module', function() {
describe('version service', function() { describe('version service', function() {
it('should return current version', inject(function(version) { it('should return current version', inject(function(version) {
expect(version).toEqual('0.6.10'); expect(version).toEqual('0.0.9');
})); }));
}); });
}); });
\ No newline at end of file
...@@ -25,21 +25,30 @@ ...@@ -25,21 +25,30 @@
<link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css" type="text/css"> <link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css" type="text/css">
<link rel="stylesheet" href="bower_components/intro.js/introjs.css" type="text/css"> <link rel="stylesheet" href="bower_components/intro.js/introjs.css" type="text/css">
<link rel="stylesheet" href="bower_components/intro.js/themes/introjs-nassim.css" type="text/css"> <link rel="stylesheet" href="bower_components/intro.js/themes/introjs-nassim.css" type="text/css">
<link rel="stylesheet" href="bower_components/toastr/toastr.min.css" type="text/css">
</head> </head>
<body> <body ng-controller="KeyListenController" ng-keydown="down($event)">
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0" ng-if="$root.loggedInUser"> <div ng-show="user_ready === false" class="body-mask">
<div class="text-center">
<span class="loader"></span>
</div>
</div>
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0"
ng-show="user_ready === true">
<collapse-menu></collapse-menu> <collapse-menu></collapse-menu>
<!--<ul class="header-menu">--> <!--<ul class="header-menu">-->
<!--<li><a href="">Mesajlar</a></li>--> <!--<li><a href="">Mesajlar</a></li>-->
<!--<li><a href="">Görevler</a></li>--> <!--<li><a href="">Görevler</a></li>-->
<!--<li><a href="">Raporlar</a></li>--> <!--<li><a href="">Raporlar</a></li>-->
<!--<li><a href="">Ayarlar</a></li>--> <!--<li><a href="">Ayarlar</a></li>-->
<!--</ul>--> <!--</ul>-->
<div class="navbar-header"> <div class="navbar-header">
<div class="brand"> <div class="brand">
<a href="#/dashboard" ng-click="$root.breadcrumbLinks = ['Panel']" class="logo"><img src="/img/brand-logo.png" /></a> <a href="#/dashboard" class="logo"><img src="/img/brand-logo.png"/></a>
</div> </div>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span> <span class="sr-only">Toggle navigation</span>
...@@ -52,12 +61,12 @@ ...@@ -52,12 +61,12 @@
<header-notification></header-notification> <header-notification></header-notification>
</nav> </nav>
<sidebar ng-if="$root.loggedInUser"></sidebar> <sidebar ng-show="user_ready === true"></sidebar>
<div class="manager-view"> <div class="manager-view">
<div class="manager-view-inner"> <div class="manager-view-inner">
<!-- manager-header --> <!-- manager-header -->
<header-sub-menu ng-if="$root.loggedInUser"></header-sub-menu> <header-sub-menu ng-if="$root.current_user"></header-sub-menu>
<!-- end of manager-header --> <!-- end of manager-header -->
<div class="manager-view-content"> <div class="manager-view-content">
<div class="row"> <div class="row">
...@@ -65,6 +74,7 @@ ...@@ -65,6 +74,7 @@
</div> </div>
<right-sidebar></right-sidebar> <right-sidebar></right-sidebar>
<messaging></messaging>
</div> </div>
</div> </div>
</div> </div>
...@@ -78,46 +88,56 @@ ...@@ -78,46 +88,56 @@
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="bower_components/angular-route/angular-route.min.js"></script> <script src="bower_components/angular-route/angular-route.min.js"></script>
<script src="bower_components/angular-cookies/angular-cookies.min.js"></script> <script src="bower_components/angular-cookies/angular-cookies.min.js"></script>
<script src="bower_components/angular-resource/angular-resource.min.js"></script> <!--<script src="bower_components/angular-resource/angular-resource.min.js"></script>-->
<script src="bower_components/angular-bootstrap/ui-bootstrap.min.js"></script> <!--<script src="bower_components/angular-bootstrap/ui-bootstrap.min.js"></script>-->
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script> <script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
<script src="bower_components/showdown/dist/showdown.js"></script>
<script src="bower_components/angular-markdown-filter/markdown.js"></script>
<script src="bower_components/angular-sanitize/angular-sanitize.min.js"></script> <script src="bower_components/angular-sanitize/angular-sanitize.min.js"></script>
<script src="bower_components/tv4/tv4.js"></script> <script src="bower_components/tv4/tv4.js"></script>
<script src="bower_components/objectpath/lib/ObjectPath.js"></script> <script src="bower_components/objectpath/lib/ObjectPath.js"></script>
<script src="bower_components/angular-schema-form/dist/schema-form.min.js"></script> <script src="bower_components/angular-schema-form/dist/schema-form.js"></script>
<script src="bower_components/angular-schema-form/dist/bootstrap-decorator.min.js"></script> <script src="bower_components/angular-schema-form/dist/bootstrap-decorator.min.js"></script>
<script src="bower_components/angular-gettext/dist/angular-gettext.min.js"></script> <script src="bower_components/angular-gettext/dist/angular-gettext.min.js"></script>
<script src="bower_components/moment/min/moment.min.js"></script> <script src="bower_components/moment/min/moment.min.js"></script>
<script src="bower_components/toastr/toastr.min.js"></script>
<!-- TODO: check all js and remove unused -->
<!--<script src="bower_components/json3/lib/json3.js"></script>-->
<script src="bower_components/angular-loading-bar/build/loading-bar.min.js"></script> <script src="bower_components/angular-loading-bar/build/loading-bar.min.js"></script>
<script src="bower_components/metisMenu/dist/metisMenu.min.js"></script> <script src="bower_components/metisMenu/dist/metisMenu.min.js"></script>
<script src="bower_components/intro.js/intro.js"></script> <script src="bower_components/intro.js/intro.js"></script>
<!--<script src="bower_components/Chart.js/Chart.js"></script>--> <!--<script src="bower_components/Chart.js/Chart.js"></script>-->
<script src="shared/translations.js"></script> <script src="shared/translations.js"></script>
<script src="tmp/templates.js"></script>
<script src="app.js"></script> <script src="app.js"></script>
<script src="app_routes.js"></script> <script src="app_routes.js"></script>
<script src="shared/scripts/highlight.pack.js"></script> <script src="shared/scripts/highlight.pack.js"></script>
<script src="shared/directives.js"></script> <script src="shared/directives.js"></script>
<script src="zetalib/interceptors.js"></script> <script src="zetalib/interceptors.js"></script>
<script src="zetalib/form_service.js"></script> <script src="zetalib/form_service.js"></script>
<script src="zetalib/form_constraints.js"></script>
<script src="zetalib/action_service.js"></script>
<script src="zetalib/error_service.js"></script>
<script src="zetalib/socket.js"></script>
<script src="zetalib/utils_service.js"></script>
<!-- components --> <!-- components -->
<script src="components/auth/auth_controller.js"></script> <script src="components/auth/auth_controller.js"></script>
<script src="components/auth/auth_service.js"></script> <script src="components/auth/auth_service.js"></script>
<script src="components/dashboard/dashboard_controller.js"></script> <script src="components/dashboard/dashboard_controller.js"></script>
<script src="components/dashboard/dashboard_widgets_directives.js"></script>
<script src="components/messaging/messaging_service.js"></script>
<script src="components/messaging/messaging.js"></script>
<script src="components/crud/crud_controller.js"></script> <script src="components/crud/crud_controller.js"></script>
<script src="components/crud/crud_widgets.js"></script>
<script src="components/debug/debug_controller.js"></script> <script src="components/debug/debug_controller.js"></script>
<script src="components/devSettings/devSettings_controller.js"></script> <script src="components/devSettings/devSettings_controller.js"></script>
<script src="components/uitemplates/uitemplates.js"></script>
<script src="components/error_pages/error_controller.js"></script> <script src="components/error_pages/error_controller.js"></script>
<script src="components/uitemplates/uitemplates.js"></script>
<script src="components/version/interpolate-filter.js"></script> <script src="components/version/interpolate-filter.js"></script>
<script src="components/version/version-directive.js"></script> <script src="components/version/version-directive.js"></script>
<script src="components/version/version.js"></script> <script src="components/version/version.js"></script>
</body> </body>
</html> </html>
...@@ -26,27 +26,34 @@ ...@@ -26,27 +26,34 @@
<link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css" type="text/css"> <link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css" type="text/css">
<link rel="stylesheet" href="bower_components/intro.js/introjs.css" type="text/css"> <link rel="stylesheet" href="bower_components/intro.js/introjs.css" type="text/css">
<link rel="stylesheet" href="bower_components/intro.js/themes/introjs-nassim.css" type="text/css"> <link rel="stylesheet" href="bower_components/intro.js/themes/introjs-nassim.css" type="text/css">
<link rel="stylesheet" href="bower_components/toastr/toastr.min.css" type="text/css">
<!-- @endif --> <!-- @endif -->
<!-- @if NODE_ENV == 'PRODUCTION' --> <!-- @if NODE_ENV == 'PRODUCTION' -->
<link rel="stylesheet" href="css/app.css"> <link rel="stylesheet" href="css/app.css">
<link rel="stylesheet" href="css/roboto/roboto.css"> <link rel="stylesheet" href="css/roboto/roboto.css">
<link rel="stylesheet" href="css/jquery-ui.min.css">
<!-- @endif --> <!-- @endif -->
</head> </head>
<body> <body ng-controller="KeyListenController" ng-keydown="down($event)">
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0" ng-if="$root.loggedInUser"> <div ng-show="user_ready === false" class="body-mask">
<div class="text-center">
<span class="loader"></span>
</div>
</div>
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0"
ng-show="user_ready === true">
<collapse-menu></collapse-menu> <collapse-menu></collapse-menu>
<!--<ul class="header-menu">--> <!--<ul class="header-menu">-->
<!--<li><a href="">Mesajlar</a></li>--> <!--<li><a href="">Mesajlar</a></li>-->
<!--<li><a href="">Görevler</a></li>--> <!--<li><a href="">Görevler</a></li>-->
<!--<li><a href="">Raporlar</a></li>--> <!--<li><a href="">Raporlar</a></li>-->
<!--<li><a href="">Ayarlar</a></li>--> <!--<li><a href="">Ayarlar</a></li>-->
<!--</ul>--> <!--</ul>-->
<div class="navbar-header"> <div class="navbar-header">
<div class="brand"> <div class="brand">
<a href="#/dashboard" ng-click="$root.breadcrumbLinks = ['Panel']" class="logo"><img src="/img/brand-logo.png" /></a> <a href="#/dashboard" class="logo"><img src="/img/brand-logo.png"/></a>
</div> </div>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span> <span class="sr-only">Toggle navigation</span>
...@@ -59,12 +66,12 @@ ...@@ -59,12 +66,12 @@
<header-notification></header-notification> <header-notification></header-notification>
</nav> </nav>
<sidebar ng-if="$root.loggedInUser"></sidebar> <sidebar ng-show="user_ready === true"></sidebar>
<div class="manager-view"> <div class="manager-view">
<div class="manager-view-inner"> <div class="manager-view-inner">
<!-- manager-header --> <!-- manager-header -->
<header-sub-menu ng-if="$root.loggedInUser"></header-sub-menu> <header-sub-menu ng-if="$root.current_user"></header-sub-menu>
<!-- end of manager-header --> <!-- end of manager-header -->
<div class="manager-view-content"> <div class="manager-view-content">
<div class="row"> <div class="row">
...@@ -72,6 +79,7 @@ ...@@ -72,6 +79,7 @@
</div> </div>
<right-sidebar></right-sidebar> <right-sidebar></right-sidebar>
<messaging></messaging>
</div> </div>
</div> </div>
</div> </div>
...@@ -86,43 +94,51 @@ ...@@ -86,43 +94,51 @@
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script> <script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="bower_components/angular-route/angular-route.min.js"></script> <script src="bower_components/angular-route/angular-route.min.js"></script>
<script src="bower_components/angular-cookies/angular-cookies.min.js"></script> <script src="bower_components/angular-cookies/angular-cookies.min.js"></script>
<script src="bower_components/angular-resource/angular-resource.min.js"></script> <!--<script src="bower_components/angular-resource/angular-resource.min.js"></script>-->
<script src="bower_components/angular-bootstrap/ui-bootstrap.min.js"></script> <!--<script src="bower_components/angular-bootstrap/ui-bootstrap.min.js"></script>-->
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script> <script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
<script src="bower_components/showdown/dist/showdown.js"></script>
<script src="bower_components/angular-markdown-filter/markdown.js"></script>
<script src="bower_components/angular-sanitize/angular-sanitize.min.js"></script> <script src="bower_components/angular-sanitize/angular-sanitize.min.js"></script>
<script src="bower_components/tv4/tv4.js"></script> <script src="bower_components/tv4/tv4.js"></script>
<script src="bower_components/objectpath/lib/ObjectPath.js"></script> <script src="bower_components/objectpath/lib/ObjectPath.js"></script>
<script src="bower_components/angular-schema-form/dist/schema-form.min.js"></script> <script src="bower_components/angular-schema-form/dist/schema-form.js"></script>
<script src="bower_components/angular-schema-form/dist/bootstrap-decorator.min.js"></script> <script src="bower_components/angular-schema-form/dist/bootstrap-decorator.min.js"></script>
<script src="bower_components/angular-gettext/dist/angular-gettext.min.js"></script> <script src="bower_components/angular-gettext/dist/angular-gettext.min.js"></script>
<script src="bower_components/moment/min/moment.min.js"></script> <script src="bower_components/moment/min/moment.min.js"></script>
<script src="bower_components/toastr/toastr.min.js"></script>
<!-- TODO: check all js and remove unused -->
<!--<script src="bower_components/json3/lib/json3.js"></script>-->
<script src="bower_components/angular-loading-bar/build/loading-bar.min.js"></script> <script src="bower_components/angular-loading-bar/build/loading-bar.min.js"></script>
<script src="bower_components/metisMenu/dist/metisMenu.min.js"></script> <script src="bower_components/metisMenu/dist/metisMenu.min.js"></script>
<script src="bower_components/intro.js/intro.js"></script> <script src="bower_components/intro.js/intro.js"></script>
<!--<script src="bower_components/Chart.js/Chart.js"></script>--> <!--<script src="bower_components/Chart.js/Chart.js"></script>-->
<script src="shared/translations.js"></script> <script src="shared/translations.js"></script>
<script src="tmp/templates.js"></script>
<script src="app.js"></script> <script src="app.js"></script>
<script src="app_routes.js"></script> <script src="app_routes.js"></script>
<script src="shared/scripts/highlight.pack.js"></script> <script src="shared/scripts/highlight.pack.js"></script>
<script src="shared/directives.js"></script> <script src="shared/directives.js"></script>
<script src="zetalib/interceptors.js"></script> <script src="zetalib/interceptors.js"></script>
<script src="zetalib/form_service.js"></script> <script src="zetalib/form_service.js"></script>
<script src="zetalib/form_constraints.js"></script>
<script src="zetalib/action_service.js"></script>
<script src="zetalib/error_service.js"></script>
<script src="zetalib/socket.js"></script>
<script src="zetalib/utils_service.js"></script>
<!-- components --> <!-- components -->
<script src="components/auth/auth_controller.js"></script> <script src="components/auth/auth_controller.js"></script>
<script src="components/auth/auth_service.js"></script> <script src="components/auth/auth_service.js"></script>
<script src="components/dashboard/dashboard_controller.js"></script> <script src="components/dashboard/dashboard_controller.js"></script>
<script src="components/dashboard/dashboard_widgets_directives.js"></script>
<script src="components/messaging/messaging_service.js"></script>
<script src="components/messaging/messaging.js"></script>
<script src="components/crud/crud_controller.js"></script> <script src="components/crud/crud_controller.js"></script>
<script src="components/crud/crud_widgets.js"></script>
<script src="components/debug/debug_controller.js"></script> <script src="components/debug/debug_controller.js"></script>
<script src="components/devSettings/devSettings_controller.js"></script> <script src="components/devSettings/devSettings_controller.js"></script>
<script src="components/uitemplates/uitemplates.js"></script>
<script src="components/error_pages/error_controller.js"></script> <script src="components/error_pages/error_controller.js"></script>
<script src="components/uitemplates/uitemplates.js"></script>
<script src="components/version/interpolate-filter.js"></script> <script src="components/version/interpolate-filter.js"></script>
<script src="components/version/version-directive.js"></script> <script src="components/version/version-directive.js"></script>
<script src="components/version/version.js"></script> <script src="components/version/version.js"></script>
...@@ -130,8 +146,7 @@ ...@@ -130,8 +146,7 @@
<!-- @if NODE_ENV == 'PRODUCTION' --> <!-- @if NODE_ENV == 'PRODUCTION' -->
<script src="bower_components/jquery.min.js"></script> <script src="bower_components/jquery.min.js"></script>
<script src="bower_components/jquery-ui.min.js"></script> <script src="bower_components/angular.js"></script>
<script src="bower_components/angular.min.js"></script>
<script src="bower_components/components.js"></script> <script src="bower_components/components.js"></script>
<script src="shared/translations.js"></script> <script src="shared/translations.js"></script>
<script src="templates.js"></script> <script src="templates.js"></script>
......
...@@ -22,12 +22,13 @@ ...@@ -22,12 +22,13 @@
*/ */
angular.module( angular.module(
'ulakbus', [ 'ulakbus', [
'ui.bootstrap', //'ui.bootstrap',
'angular-loading-bar', 'angular-loading-bar',
'ngRoute', 'ngRoute',
'ngSanitize', 'ngSanitize',
'ngCookies', 'ngCookies',
'ulakbus.formService', 'ulakbus.formService',
'ulakbus.messaging',
'ulakbus.dashboard', 'ulakbus.dashboard',
'ulakbus.auth', 'ulakbus.auth',
'ulakbus.error_pages', 'ulakbus.error_pages',
...@@ -35,8 +36,8 @@ angular.module( ...@@ -35,8 +36,8 @@ angular.module(
'ulakbus.debug', 'ulakbus.debug',
'ulakbus.devSettings', 'ulakbus.devSettings',
'ulakbus.version', 'ulakbus.version',
//'schemaForm',
'gettext', 'gettext',
'markdown',
// @if NODE_ENV='PRODUCTION' // @if NODE_ENV='PRODUCTION'
'templates-prod', 'templates-prod',
// @endif // @endif
...@@ -53,6 +54,7 @@ angular.module( ...@@ -53,6 +54,7 @@ angular.module(
* *
* For development needs backendurl can be switched from both dev/settings page and querystring `?backendurl=http://example.com` * For development needs backendurl can be switched from both dev/settings page and querystring `?backendurl=http://example.com`
*/ */
// todo: convert it to service
.constant("RESTURL", (function () { .constant("RESTURL", (function () {
// todo: below backendurl definition is for development purpose and will be deleted // todo: below backendurl definition is for development purpose and will be deleted
var backendurl = location.href.indexOf('nightly') > -1 ? "//nightly.api.ulakbus.net/" : "//api.ulakbus.net/"; var backendurl = location.href.indexOf('nightly') > -1 ? "//nightly.api.ulakbus.net/" : "//api.ulakbus.net/";
...@@ -61,6 +63,8 @@ angular.module( ...@@ -61,6 +63,8 @@ angular.module(
angular.forEach(cookiearray, function (item) { angular.forEach(cookiearray, function (item) {
if (item.indexOf("backendurl") > -1) { if (item.indexOf("backendurl") > -1) {
backendurl = item.split('=')[1]; backendurl = item.split('=')[1];
if (backendurl.slice(-1) !== '/') {backendurl += '/'}
if (backendurl.substring(0,4) !== 'http') {backendurl = 'http://'+backendurl}
} }
}); });
} }
...@@ -68,12 +72,78 @@ angular.module( ...@@ -68,12 +72,78 @@ angular.module(
if (location.href.indexOf("backendurl") > -1) { if (location.href.indexOf("backendurl") > -1) {
var urlfromqstr = location.href.split('?')[1].split('=')[1]; var urlfromqstr = location.href.split('?')[1].split('=')[1];
backendurl = decodeURIComponent(urlfromqstr.replace(/\+/g, " ")); backendurl = decodeURIComponent(urlfromqstr.replace(/\+/g, " "));
if (backendurl.slice(-1) !== '/') {backendurl += '/'}
if (backendurl.substring(0,4) !== 'http') {backendurl = 'http://'+backendurl}
document.cookie = "backendurl=" + backendurl; document.cookie = "backendurl=" + backendurl;
window.location.href = window.location.href.split('?')[0]; window.location.href = window.location.href.split('?')[0];
} }
return {url: backendurl}; return {url: backendurl};
})()) })())
.factory('IsOnline', function ($window, $document, $rootScope) {
var isOnlineService = {};
isOnlineService.status = true;
var offlineMask = angular.element(
'<div class="body-mask" style="z-index: 2010; opacity: 0.6">' +
'<div class="alert alert-danger text-center" role="alert" style="z-index: 2011; position: relative">' +
'İnternet bağlantınız kesilmiştir. Bağlantı sağlandığında kaldığınız yerden devam edebilirsiniz.' +
'</div>' +
'</div>'
);
var body = $document.find('body').eq(0);
isOnlineService.set_status = function (state) {
// status changed
if (state != isOnlineService.status){
// online
if (state){
offlineMask.remove();
// is user is set, reload page to init
if ($rootScope.current_user === true){
window.location.reload();
}
}
// offline
else {
body.append(offlineMask);
}
}
isOnlineService.status = state;
};
isOnlineService.get_status = function () {
return isOnlineService.status;
};
// @if NODE_ENV='PRODUCTION'
isOnlineService.status = navigator.onLine;
$window.addEventListener("offline", function(){
isOnlineService.set_status(false);
});
$window.addEventListener("online", function(){
isOnlineService.set_status(true);
});
// @endif
return isOnlineService;
})
// .service('DESIGN', function ($routeParams, $cookies, $log) {
// // use route param to change cookie for design
// // this is a config as a service added for designer can work without backend
// try {
// if (angular.isDefined($routeParams.design) || location.hash.split('?')[1].split('=')[1]) {
// $cookies.put('design', $routeParams.design || location.hash.split('?')[1].split('=')[1]);
// }
// } catch (e){
// $log.error("Error for design parameter", e);
// }
// return $cookies.get('design') === 'true' ? {switch: true} : {switch: false};
// })
.constant('toastr', window.toastr)
.constant('WS', window.WebSocket)
.config(function ($logProvider) { .config(function ($logProvider) {
// @if NODE_ENV='PRODUCTION' // @if NODE_ENV='PRODUCTION'
$logProvider.debugEnabled(false); $logProvider.debugEnabled(false);
...@@ -81,4 +151,9 @@ angular.module( ...@@ -81,4 +151,9 @@ angular.module(
// @if NODE_ENV='DEVELOPMENT' // @if NODE_ENV='DEVELOPMENT'
$logProvider.debugEnabled(true); $logProvider.debugEnabled(true);
// @endif // @endif
}); })
\ No newline at end of file .config(function(markdownProvider) {
//markdownProvider.config({
// extensions: ['table']
//});
});
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
* *
* This file is licensed under the GNU General Public License v3 * This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details. * (GPLv3). See LICENSE.txt for details.
* @type {ng.$compileProvider|*}
*/ */
angular.module('ulakbus') angular.module('ulakbus')
...@@ -15,14 +14,15 @@ angular.module('ulakbus') ...@@ -15,14 +14,15 @@ angular.module('ulakbus')
* @description logout directive provides a button with click event. When triggered it post to * @description logout directive provides a button with click event. When triggered it post to
* '/logout' path of the API. * '/logout' path of the API.
*/ */
.directive('logout', function ($http, $location, RESTURL) { .directive('logout', function ($http, $location, RESTURL, AuthService) {
return { return {
link: function ($scope, $element, $rootScope) { link: function ($scope, $element, $rootScope) {
$element.on('click', function () { $element.on('click', function () {
$http.post(RESTURL.url + 'logout', {}).then(function () { AuthService.logout();
$rootScope.loggedInUser = false; //$http.post(RESTURL.url + 'logout', {}).then(function () {
$location.path("/login"); // $rootScope.loggedInUser = false;
}); // $location.path("/login");
//});
}); });
} }
}; };
...@@ -32,68 +32,27 @@ angular.module('ulakbus') ...@@ -32,68 +32,27 @@ angular.module('ulakbus')
* @ngdoc directive * @ngdoc directive
* @name headerNotification * @name headerNotification
* @description This directive is responsible to get and show notification. * @description This directive is responsible to get and show notification.
* It calls API's /notify path with given interval and broadcasts `notifications` application-wide. * It calls API's '_zops_unread_count' view to init its state and updates state when 'message' or 'notifications' broadcast message received *
* There are 4 types of notifications:
* 1: tasks, 2: messages, 3: announcements, 4: recents
* - Notifications can be disabled in /dev/settings page * - Notifications can be disabled in /dev/settings page
*/ */
.directive('headerNotification', function ($http, $rootScope, $cookies, $interval, RESTURL) { .directive('headerNotification', function ($rootScope, $uibModal, MessagingService) {
return { return {
templateUrl: 'shared/templates/directives/header-notification.html', templateUrl: 'shared/templates/directives/header-notification.html',
restrict: 'E', restrict: 'E',
replace: true, replace: true,
link: function ($scope) { scope: {},
/** controller: function ($scope, $log) {
* Group notifications $scope.count = MessagingService.get_unread_counters();
* @param notifications
*/ $scope.showMessagesWindow = function(type){
$scope.groupNotifications = function (notifications) { if (type == 'notifications'){
// notification categories: return MessagingService.get_notifications_channel_key()
// 1: tasks, 2: messages, 3: announcements, 4: recents .then(function(channelKey){
$scope.notifications = {1: [], 2: [], 3: [], 4: []}; return MessagingService.show_messaging_window(channelKey);
})
angular.forEach(notifications, function (value, key) {
$scope.notifications[value.type].push(value);
});
};
/**
* Get notifications from API's /notify path and group it then broadcast "notifications" object.
* {ignoreLoadingBar: true} is telling loading bar not work on this particular request.
*/
$scope.getNotifications = function () {
// ignore loading bar here
$http.get(RESTURL.url + "notify", {ignoreLoadingBar: true}).success(function (data) {
$scope.groupNotifications(data.notifications);
$rootScope.$broadcast("notifications", $scope.notifications);
});
};
$scope.getNotifications();
// check notifications every 5 seconds
$interval(function () {
if ($cookies.get("notificate") == "on") {
$scope.getNotifications();
} }
}, 5000); MessagingService.show_messaging_window();
}
/**
* When clicked mark the notification as read.
* @param items
* @todo: do it in detail page of notification
*/
$scope.markAsRead = function (items) {
$http.post(RESTURL.url + "notify", {ignoreLoadingBar: true, read: [items]})
.success(function (data) {
$scope.groupNotifications(data.notifications);
$rootScope.$broadcast("notifications", $scope.notifications);
});
};
// if markasread triggered outside the directive
$scope.$on("markasread", function (event, data) {
$scope.markAsRead(data);
});
} }
}; };
}) })
...@@ -134,10 +93,10 @@ angular.module('ulakbus') ...@@ -134,10 +93,10 @@ angular.module('ulakbus')
$scope.$broadcast('schemaFormValidate'); $scope.$broadcast('schemaFormValidate');
if (form.$valid) { if (form.$valid) {
var searchparams = { var searchparams = {
url: $scope.wf,
token: $scope.$parent.token, token: $scope.$parent.token,
object_id: $scope.$parent.object_id, object_id: $scope.$parent.object_id,
form_params: { form_params: {
wf: $scope.$parent.wf,
model: $scope.$parent.form_params.model, model: $scope.$parent.form_params.model,
cmd: $scope.$parent.reload_cmd, cmd: $scope.$parent.reload_cmd,
flow: $scope.$parent.form_params.flow, flow: $scope.$parent.form_params.flow,
...@@ -145,10 +104,7 @@ angular.module('ulakbus') ...@@ -145,10 +104,7 @@ angular.module('ulakbus')
} }
}; };
Generator.submit(searchparams).success(function (data) { Generator.submit(searchparams);
// update objects item of page scope
$rootScope.$broadcast('updateObjects', data.objects);
});
} }
}; };
} }
...@@ -221,7 +177,7 @@ angular.module('ulakbus') ...@@ -221,7 +177,7 @@ angular.module('ulakbus')
scope: {}, scope: {},
controller: function ($scope, $rootScope) { controller: function ($scope, $rootScope) {
$rootScope.collapsed = false; $rootScope.collapsed = false;
$rootScope.sidebarPinned = $cookies.get('sidebarPinned') || 0; $rootScope.sidebarPinned = $cookies.get('sidebarPinned') || 1;
$scope.collapseToggle = function () { $scope.collapseToggle = function () {
if ($window.innerWidth > '768') { if ($window.innerWidth > '768') {
...@@ -287,41 +243,6 @@ angular.module('ulakbus') ...@@ -287,41 +243,6 @@ angular.module('ulakbus')
} }
}; };
}) })
/**
* @memberof ulakbus
* @ngdoc directive
* @name selectedUser
* @description Selected user on which the current job done is hold in this directive.
* @deprecated
*/
.directive('selectedUser', function ($http, RESTURL) {
return {
templateUrl: 'shared/templates/directives/selected-user.html',
restrict: 'E',
replace: true,
link: function ($scope, $rootScope) {
$scope.$on('selectedUser', function ($event, data) {
$scope.selectedUser = data;
$scope.dynamicPopover = {
content: '',
name: data.name,
tcno: data.tcno,
key: data.key,
templateUrl: 'shared/templates/directives/selectedUserPopover.html',
title: 'İşlem Yapılan Kişi'
};
});
$scope.$on('selectedUserTrigger', function ($event, data) {
var postToApi = {model: 'Personel', cmd: 'show', id: data[1]};
//postToApi[data[0]]=data[1];
$http.get(RESTURL.url + 'ara/personel/' + data[1]).success(
function (data) {
}
);
})
}
};
})
/** /**
* @memberof ulakbus * @memberof ulakbus
* @ngdoc directive * @ngdoc directive
...@@ -335,7 +256,7 @@ angular.module('ulakbus') ...@@ -335,7 +256,7 @@ angular.module('ulakbus')
restrict: 'E', restrict: 'E',
replace: true, replace: true,
scope: {}, scope: {},
controller: function ($scope, $rootScope, $cookies, $route, $http, RESTURL, $log, $location, $window, $timeout) { controller: function ($scope, $rootScope, $cookies, $route, AuthService, WSOps, RESTURL, $log, $location, $window, $timeout) {
$scope.prepareMenu = function (menuItems) { $scope.prepareMenu = function (menuItems) {
var newMenuItems = {}; var newMenuItems = {};
angular.forEach(menuItems, function (value, key) { angular.forEach(menuItems, function (value, key) {
...@@ -346,72 +267,90 @@ angular.module('ulakbus') ...@@ -346,72 +267,90 @@ angular.module('ulakbus')
return newMenuItems; return newMenuItems;
}; };
var sidebarmenu = $('#side-menu'); // check login status
//var sidebarUserMenu = $('#side-user-menu'); // AuthService.check_auth();
sidebarmenu.metisMenu();
$http.get(RESTURL.url + 'menu/')
.success(function (data) {
$scope.allMenuItems = angular.copy(data);
// regroup menu items based on their category
function reGroupMenuItems(items, baseCategory) {
var newItems = {};
angular.forEach(items, function (value, key) {
newItems[value.kategori] = newItems[value.kategori] || [];
value['baseCategory'] = baseCategory;
newItems[value.kategori].push(value);
});
return newItems;
}
angular.forEach($scope.allMenuItems, function (value, key) {
if (key !== 'current_user' && key !== 'settings') {
$scope.allMenuItems[key] = reGroupMenuItems(value, key);
}
});
// quick menus to dashboard via rootscope
$rootScope.quick_menu = reGroupMenuItems(data.quick_menu, 'quick_menus');
$rootScope.quick_menu = data.quick_menu;
delete data.quick_menu;
$log.debug('quick menu', $rootScope.quick_menu);
// broadcast for authorized menu items, consume in dashboard to show search inputs and/or
// related items
$rootScope.$broadcast("authz", data);
$rootScope.searchInputs = data;
$rootScope.current_user = data.current_user;
if (data.ogrenci || data.personel) {
$rootScope.current_user.can_search = true;
}
$rootScope.settings = data.settings;
$scope.menuItems = $scope.prepareMenu({other: $scope.allMenuItems.other});
// if selecteduser on cookie then add related part to the menu
//if ($cookies.get("selectedUserType")) {
// $scope.menuItems[$cookies.get("selectedUserType")] = $scope.allMenuItems[$cookies.get("selectedUserType")];
//}
var generate_dashboard = function () {
if ($rootScope.current_user !== true){
return;
}
if ($rootScope.websocketIsOpen) {
var sidebarmenu = $('#side-menu');
sidebarmenu.metisMenu();
WSOps.request({view: 'dashboard'})
.then(function (data) {
$scope.allMenuItems = angular.copy(data);
// regroup menu items based on their category
function reGroupMenuItems(items, baseCategory) {
var newItems = {};
angular.forEach(items, function (value, key) {
newItems[value.kategori] = newItems[value.kategori] || [];
// value['baseCategory'] = baseCategory;
newItems[value.kategori].push(value);
});
return newItems;
}
angular.forEach($scope.allMenuItems, function (value, key) {
if (key !== 'current_user' && key !== 'settings') {
$scope.allMenuItems[key] = reGroupMenuItems(value, key);
}
});
// quick menus to dashboard via rootscope
$rootScope.quick_menu = reGroupMenuItems(data.quick_menu, 'quick_menus');
$rootScope.quick_menu = data.quick_menu;
delete data.quick_menu;
$log.debug('quick menu', $rootScope.quick_menu);
// broadcast for authorized menu items, consume in dashboard to show search inputs and/or
// related items
$rootScope.$broadcast("authz", data);
$rootScope.searchInputs = data;
if (data.current_user) {
// $rootScope.$broadcast("ws_turn_on");
// to display main view without flickering
// $rootScope.$broadcast("user_ready");
}
$rootScope.current_user = data.current_user;
if (data.ogrenci || data.personel) {
$rootScope.current_user.can_search = true;
}
$rootScope.settings = data.settings;
$scope.menuItems = $scope.prepareMenu({other: $scope.allMenuItems.other});
$timeout(function () {
sidebarmenu.metisMenu();
});
});
// .error(function (data, status, headers, config) {
// $log.error('menu not retrieved', data);
// $log.info('design switch', DESIGN.switch);
// if (!DESIGN.switch) {
// $location.path('/login');
// }
// });
} else {
$timeout(function () { $timeout(function () {
sidebarmenu.metisMenu(); generate_dashboard();
//sidebarUserMenu.metisMenu(); }, 500);
}); }
}); };
$scope.$on("generate_dashboard", function () {
generate_dashboard();
});
// generate_menu();
// changing menu items by listening for broadcast // changing menu items by listening for broadcast
$scope.$on("menuitems", function (event, data) { $scope.$on("menuitems", function (event, data) {
var menu = {}; var menu = {};
menu[data] = $scope.allMenuItems[data]; menu[data] = $scope.allMenuItems[data];
$rootScope.$broadcast("usermenuitems", $scope.prepareMenu(menu)); $rootScope.$broadcast("usermenuitems", $scope.prepareMenu(menu));
//$timeout(function () {
// sidebarmenu.metisMenu();
// sidebarUserMenu.metisMenu();
//});
}); });
$scope.$on('selectedUser', function ($event, data) { $scope.$on('selectedUser', function ($event, data) {
...@@ -423,26 +362,26 @@ angular.module('ulakbus') ...@@ -423,26 +362,26 @@ angular.module('ulakbus')
delete $scope.selectedMenuItems; delete $scope.selectedMenuItems;
}; };
$scope.openSidebar = function () { // $scope.openSidebar = function () {
if ($window.innerWidth > '768') { // if ($window.innerWidth > '768') {
if ($rootScope.sidebarPinned === 0) { // if ($rootScope.sidebarPinned === 0) {
jQuery("span.menu-text, span.arrow, .sidebar footer, #side-menu").fadeIn(400); // jQuery("span.menu-text, span.arrow, .sidebar footer, #side-menu").fadeIn(400);
jQuery(".sidebar").css("width", "250px"); // jQuery(".sidebar").css("width", "250px");
jQuery(".manager-view").css("width", "calc(100% - 250px)"); // jQuery(".manager-view").css("width", "calc(100% - 250px)");
$rootScope.collapsed = false; // $rootScope.collapsed = false;
} // }
} // }
}; // };
//
$scope.closeSidebar = function () { // $scope.closeSidebar = function () {
if ($window.innerWidth > '768') { // if ($window.innerWidth > '768') {
if ($rootScope.sidebarPinned === 0) { // if ($rootScope.sidebarPinned === 0) {
jQuery(".sidebar").css("width", "62px"); // jQuery(".sidebar").css("width", "62px");
jQuery(".manager-view").css("width", "calc(100% - 62px)"); // jQuery(".manager-view").css("width", "calc(100% - 62px)");
$rootScope.collapsed = true; // $rootScope.collapsed = true;
} // }
} // }
}; // };
$rootScope.$watch(function ($rootScope) { $rootScope.$watch(function ($rootScope) {
return $rootScope.section; return $rootScope.section;
...@@ -664,12 +603,117 @@ angular.module('ulakbus') ...@@ -664,12 +603,117 @@ angular.module('ulakbus')
scope.$parent.model[changeEvent.target.name] = { scope.$parent.model[changeEvent.target.name] = {
file_name: changeEvent.target.files[0].name, file_name: changeEvent.target.files[0].name,
file_content: scope.$parent.model[changeEvent.target.name] file_content: scope.$parent.model[changeEvent.target.name]
} };
document.querySelector('#image-preview').src = URL.createObjectURL(changeEvent.target.files[0]); document.querySelector('#image-preview').src = URL.createObjectURL(changeEvent.target.files[0]);
}); });
} };
reader.readAsDataURL(changeEvent.target.files[0]); reader.readAsDataURL(changeEvent.target.files[0]);
}); });
} }
} }
}); })
\ No newline at end of file .directive('timetableActionSelector', function($timeout) {
// Display/hide popover with actions
// global listener used to close popover when user clicks outside of the popover
$('html').on('click', function (e) {
var target = $(e.target);
if (target.parents().is('.action-selector')) {
target.parents('.action-selector').children('.popover').toggleClass('ng-hide');
return;
}
if (target.hasClass('action-selector')) {
target.children('.popover').toggleClass('ng-hide');
return;
}
;
$('.course-prg-scheduler .action-selector>.popover').toggleClass('ng-hide', true);
});
return {
templateUrl: 'shared/templates/directives/timetable-action-selector.html',
scope: {
externalModel: '=ngModel',
onChange: "&ngChange"
},
link: function (iScope, iElem, iAttrs) {
var valueToClassMap = {
1: 'action-indicator_appropriate',
2: 'action-indicator_uncertain',
3: 'action-indicator_busy'
};
if (iAttrs.hasOwnProperty('readonly')) {
iAttrs.$observe('readonly', function (v) {
if (v && v == 'false') v = false;
iScope.readonly = v;
});
}
iScope.$watch('externalModel', function (value) {
iScope.value = valueToClassMap[value];
});
iScope.setModelValue = function (value) {
var oldValue = iScope.externalModel;
iScope.externalModel = value;
// call change in next digest
$timeout(function () {
if (iScope.onChange && value != oldValue) {
iScope.onChange();
}
});
}
}
}
})
/**
* @memberof ulakbus
* @ngdoc directive
* @name onEnterPressed
* @description Fire action when enter pressed on element
*/
.directive("onEnterPressed", function () {
return {
link: function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 13 && !event.ctrlKey) {
scope.$apply(function (){
scope.$eval(attrs.onEnterPressed);
});
event.preventDefault();
}
});
scope.$on('$destroy', function(){
element.unbind('keydown keypress');
})
}
}
})
/**
* @memberof ulakbus
* @ngdoc directive
* @name onEscPressed
* @description Fire action when ESC pressed on element
*/
.directive("onEscPressed", function () {
return {
link: function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if(event.which === 27 ) {
scope.$apply(function (){
scope.$eval(attrs.onEscPressed);
});
event.preventDefault();
}
});
scope.$on('$destroy', function(){
element.unbind('keydown keypress');
})
}
}
});
<div class="modal-body" style="padding: 0 !important; border-radius: 6px;">
<input type="text" ng-model="act.selected" placeholder="İşlem ismi giriniz..."
typeahead-on-select="doThis($item)"
uib-typeahead="act as act.name for act in actions | filter:$viewValue" typeahead-no-results="noResults"
typeahead-wait-ms="500" class="form-control" style="border-radius: 6px; height: 50px; line-height: 40px"
autofocus>
</div>
\ No newline at end of file
<div class="form-group schema-form-submit {{form.htmlClass}}">
<button class="btn {{ form.style || 'btn-default' }}"
type="button"
ng-disabled="form.readonly"
ng-click="form.openModal()">
<span ng-if="form.icon" class="{{form.icon}}"></span>
{{form.title}}
</button>
<!--<script type="text/ng-template" id="confirmModalTemplate.html">-->
<!--<div class="modal-header">-->
<!--<h3 class="modal-title">{{form.title}}</h3>-->
<!--</div>-->
<!--<div class="modal-body">-->
<!--<p>{{form.confirm_message}}</p>-->
<!--</div>-->
<!--<div class="modal-footer">-->
<!--<button ng-repeat="b in form.buttons" class="btn {{b.style || 'btn-default'}}" type="button" ng-click="form.send(b.cmd,(b.dismiss || false))">{{b.text}}</button>-->
<!--</div>-->
<!--</script>-->
</div>
\ No newline at end of file
<div class="modal-header">
<h3 class="modal-title">{{form.title}}</h3>
</div>
<div class="modal-body">
<p>{{form.confirm_message}}</p>
</div>
<div class="modal-footer">
<button ng-repeat="b in form.buttons" class="btn {{b.style || 'btn-default'}}" type="button" ng-click="form.onClick(b.cmd)">{{b.text}}</button>
</div>
\ No newline at end of file
<div class="form-group schema-form-submit {{form.htmlClass}}">
<button class="btn {{ form.style || 'btn-default' }}"
type="button"
ng-disabled="form.readonly"
uib-popover-template="'confirmPopoverTemplate.html'"
popover-title="{{form.title}}"
popover-trigger="none"
popover-placement="bottom"
popover-is-open="form.isOpen"
ng-click="form.clickHandler()">
<span ng-if="form.icon" class="{{form.icon}}"></span>
{{form.title}}
</button>
<script type="text/ng-template" id="confirmPopoverTemplate.html">
<div class="form-group">
<p>{{form.confirm_message}}</p>
<button class="btn btn-default" ng-click="form.confirm()">Confirm</button>
</div>
</script>
</div>
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
id="{{form.key.slice(-1)[0]}}" id="{{form.key.slice(-1)[0]}}"
ng-model-options="form.ngModelOptions" ng-model-options="form.ngModelOptions"
ng-model="$$value$$" ng-model="$$value$$"
ng-disabled="form.readonly" ng-disabled="form.is_disabled()"
schema-validate="form" schema-validate="form"
name="{{form.key.slice(-1)[0]}}" name="{{form.key.slice(-1)[0]}}"
aria-describedby="{{form.key.slice(-1)[0] + 'Status'}}" aria-describedby="{{form.key.slice(-1)[0] + 'Status'}}"
......
<ul class="nav navbar-top-links navbar-right"> <ul class="nav navbar-top-links navbar-right">
<li class="dropdown"> <!--<li class="dropdown" >
<a class="dropdown-toggle" data-toggle="dropdown"> <a class="dropdown-toggle" data-toggle="dropdown">
<div class="badge" ng-if="notifications[2].length > 0">{{notifications[2].length}}</div> <div class="badge" ng-show="notifications[2].length > 0">{{notifications[2].length}}</div>
<i class="fa fa-envelope fa-fw" tooltip-placement="bottom" uib-tooltip="Mesajlar"></i> <i <i class="fa fa-envelope fa-fw" tooltip-placement="bottom" uib-tooltip="Mesajlar"></i> <i
class="fa fa-caret-down"></i> class="fa fa-caret-down"></i>
</a> </a>
<ul class="dropdown-menu dropdown-messages" ng-if="notifications[2].length > 0"> <ul class="dropdown-menu dropdown-messages" ng-show="notifications[2].length > 0">
<li ng-repeat="notify in notifications[2] | limitTo: '8'"> <li ng-repeat="notify in notifications[2] | limitTo: '8'">
<a ng-click="markAsRead(notify)"> <a>
<div> <div ng-click="popModal(notify)">
<strong>{{notify.title}}</strong> <div>
<span class="pull-right text-muted"> <strong>{{notify.title}}</strong>
<em>22 Ekim 2015</em> <span class="pull-right text-muted">
</span> <em>22 Ekim 2015</em>
</span>
</div>
<div>{{notify.body}}...</div>
</div> </div>
<div>{{notify.body}}...</div> <span ng-click="markAsRead(notify, 2, $index)" class="pull-right fa fa-times"></span>
</a> </a>
</li> </li>
<li class="divider"></li> <li class="divider"></li>
...@@ -25,59 +28,99 @@ ...@@ -25,59 +28,99 @@
</a> </a>
</li> </li>
</ul> </ul>
<!-- /.dropdown-messages --> &lt;!&ndash; /.dropdown-messages &ndash;&gt;
</li> </li>-->
<!-- /.dropdown --> <li uib-dropdown auto-close="outsideClick">
<li class="dropdown"> <a uib-dropdown-toggle ng-click="showMessagesWindow('messages')">
<a class="dropdown-toggle" data-toggle="dropdown"> <div class="badge" ng-show="count.messages.count > 0">{{count.messages.count}}</div>
<div class="badge" ng-if="notifications[1].length > 0">{{notifications[1].length}}</div> <i class="fa fa-envelope fa-fw" tooltip-placement="bottom" uib-tooltip="Mesajlar"></i>
<i class="fa fa-tasks fa-fw" tooltip-placement="bottom" uib-tooltip="Görevler"></i> <i <!--<i class="fa fa-caret-down"></i>-->
class="fa fa-caret-down"></i>
</a> </a>
<ul class="dropdown-menu dropdown-tasks" ng-if="notifications[1].length > 0"> <ul class="dropdown-messages" uib-dropdown-menu ng-show="notifications[2].length > 0">
<li ng-repeat="notify in notifications[1] | limitTo: '8'"> <li ng-repeat="notify in notifications[2] | limitTo: '8'">
<a ng-click="markAsRead(notify)"> <a href="{{notify.url}}">
<div> <div ng-click="popModal(notify)">
<p> <div>
<strong>{{notify.title}}</strong> <strong>{{notify.title}}</strong>
<span class="pull-right text-muted">{{notify.body}}</span> <span class="pull-right text-muted">
</p> <em>22 Ekim 2015</em>
<!-- todo: progress bar will be used in future developments--> </span>
<!--<div class="progress progress-striped active">--> </div>
<!--<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">--> <div>{{notify.body}}...</div>
<!--<span class="sr-only">40% Complete (success)</span>-->
<!--</div>-->
<!--</div>-->
</div> </div>
<span ng-click="markAsRead($event,notify, 2, $index)" class="pull-right fa fa-times"></span>
</a> </a>
</li> </li>
<li class="divider"></li> <li class="divider"></li>
<li> <li>
<a class="text-center"> <a class="text-center">
<strong>See All Tasks</strong> <strong>Read All Messages</strong>
<i class="fa fa-angle-right"></i> <i class="fa fa-angle-right"></i>
</a> </a>
</li> </li>
</ul> </ul>
<!-- /.dropdown-messages -->
</li>
<!-- /.dropdown -->
<!--<li uib-dropdown auto-close="outsideClick">-->
<!--<a uib-dropdown-toggle>-->
<!--<div class="badge" ng-if="notifications[1].length > 0">{{notifications[1].length}}</div>-->
<!--<i class="fa fa-tasks fa-fw" tooltip-placement="bottom" uib-tooltip="Görevler"></i> <i-->
<!--class="fa fa-caret-down"></i>-->
<!--</a>-->
<!--<ul class="dropdown-tasks" uib-dropdown-menu ng-if="notifications[1].length > 0">-->
<!--<li ng-repeat="notify in notifications[1] | limitTo: '8'">-->
<!--<a href="{{notify.url}}">-->
<!--<div>-->
<!--<p>-->
<!--<strong>{{notify.title}}</strong>-->
<!--<span class="pull-right text-muted">{{notify.body}}</span>-->
<!--<span ng-click="markAsRead($event,notify, 1, $index)" class="pull-right fa fa-times"></span>-->
<!--</p>-->
<!--&lt;!&ndash; todo: progress bar will be used in future developments&ndash;&gt;-->
<!--&lt;!&ndash;<div class="progress progress-striped active">&ndash;&gt;-->
<!--&lt;!&ndash;<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">&ndash;&gt;-->
<!--&lt;!&ndash;<span class="sr-only">40% Complete (success)</span>&ndash;&gt;-->
<!--&lt;!&ndash;</div>&ndash;&gt;-->
<!--&lt;!&ndash;</div>&ndash;&gt;-->
<!--</div>-->
<!--</a>-->
<!--</li>-->
<!--<li class="divider"></li>-->
<!--<li>-->
<!--<a class="text-center">-->
<!--<strong>See All Tasks</strong>-->
<!--<i class="fa fa-angle-right"></i>-->
<!--</a>-->
<!--</li>-->
<!--</ul>-->
<!-- /.dropdown-tasks --> <!-- /.dropdown-tasks -->
</li> </li>
<!-- /.dropdown --> <!-- /.dropdown -->
<li class="dropdown"> <li uib-dropdown auto-close="outsideClick">
<a class="dropdown-toggle" data-toggle="dropdown"> <a uib-dropdown-toggle ng-click="showMessagesWindow('notifications')">
<div class="badge" ng-if="notifications[3].length > 0">{{notifications[3].length}}</div> <div class="badge" ng-if="count.notifications.count > 0">{{count.notifications.count}}</div>
<i class="fa fa-bell fa-fw" tooltip-placement="bottom" uib-tooltip="Duyurular"></i> <i <i class="fa fa-bell fa-fw" tooltip-placement="bottom" uib-tooltip="Duyurular"></i>
class="fa fa-caret-down"></i> <!--<i class="fa fa-caret-down"></i>-->
</a> </a>
<ul class="dropdown-menu dropdown-alerts" ng-if="notifications[3].length > 0"> <ul class="dropdown-alerts" uib-dropdown-menu ng-if="notifications[3].length > 0">
<li> <li ng-repeat="notify in notifications[3] | limitTo: '8'">
<a role="button"> <a role="button" href="{{notify.url}}">
<div> <div>
<i class="fa fa-comment fa-fw"></i> New Comment <i class="fa fa-comment fa-fw"></i> New Comment
<span class="pull-right text-muted small">4 minutes ago</span> <span class="pull-right text-muted small">4 minutes ago</span>
<span ng-click="markAsRead($event,notify, 3, $index)" class="pull-right fa fa-times"></span>
</div> </div>
</a> </a>
</li> </li>
<li class="divider"></li>
<li>
<a class="text-center">
<strong>See All Notifications</strong>
<i class="fa fa-angle-right"></i>
</a>
</li>
</ul> </ul>
<!-- /.dropdown-alerts --> <!-- /.dropdown-alerts -->
</li> </li>
...@@ -99,4 +142,3 @@ ...@@ -99,4 +142,3 @@
</li> </li>
<!-- /.dropdown --> <!-- /.dropdown -->
</ul> </ul>
<div class="conversation-section">
<div class="conversation-header">
<div class="conversation-user">
<div class="user-photo"><img src="../../../img/erkan.jpg"></div>
<div class="user-name">Erkan Öğümsöğütlü</div>
</div>
<div class="conversation-search">
<input type="text" placeholder="Arama Yap">
</div>
<div class="dropdown">
<div class="chat-app-actions dropdown-toggle" data-toggle="dropdown" id="chat-app-actions">
<span class="glyphicon glyphicon-option-vertical"></span>
</div>
<ul class="dropdown-menu" aria-labelledby="chat-app-actions" style="left: inherit; top: 53px; right: 66px;">
<li><a href="#">Action One</a></li>
<li><a href="#">Action Two</a></li>
<li><a href="#">Action Three</a></li>
</ul>
</div>
<div class="close-chat-app">
<span class="glyphicon glyphicon-remove" ng-click="hideApp()"></span>
</div>
</div>
<div class="conversation-body">
<div class="conversation-body-inner">
<div class="beginning-of-conversation">
This is the beginning of the conversation
</div>
<div class="conversation-block clearfix">
<div class="conversation-actions">
<div class="action"><span class="glyphicon glyphicon-star-empty"></span></div>
<div class="action dropdown-toggle" data-toggle="dropdown">
<span class="glyphicon glyphicon-option-horizontal"></span>
</div>
<ul class="dropdown-menu" style="left:-86px;">
<li><a href="#">Edit</a></li>
<li><a href="#">Delete</a></li>
</ul>
</div>
<div class="user-photo">
<img src="../../../img/erkan.jpg">
</div>
<div class="user-message">
<div class="message-header clearfix">
<div class="user-name">Erkan Öğümsöğütlü</div>
<div class="message-time">13:16</div>
</div>
<div class="message-content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer purus mauris.
</div>
<div class="edit-text-message">
<input type="text">
<button class="btn btn-default">Cancel</button>
<button class="btn btn-success">Save Changes</button>
</div>
<!-- end of edit-text-message -->
</div>
</div>
<!-- end of conversation-block -->
<div class="conversation-block clearfix">
<div class="conversation-actions">
<div class="action"><span class="glyphicon glyphicon-star-empty"></span></div>
<div class="action dropdown-toggle" data-toggle="dropdown">
<span class="glyphicon glyphicon-option-horizontal"></span>
</div>
<ul class="dropdown-menu" style="left:-86px;">
<li><a href="#">Edit</a></li>
<li><a href="#">Delete</a></li>
</ul>
</div>
<div class="user-photo">
<img src="../../../img/erkan.jpg">
</div>
<div class="user-message">
<div class="message-header clearfix">
<div class="user-name">Erkan Öğümsöğütlü</div>
<div class="message-time">13:16</div>
</div>
<div class="message-content">
<p class="attachment-message">uploaded an image: <span>sample.jpg</span></p>
<a href="#" class="attachment-holder image-attached" target="_blank">
<img src="../../../img/sample.jpg">
<span class="glyphicon glyphicon-download attachment-download"></span>
</a>
</div>
</div>
</div>
<!-- end of conversation-block -->
<div class="conversation-block clearfix">
<div class="conversation-actions">
<div class="action"><span class="glyphicon glyphicon-star-empty"></span></div>
<div class="action dropdown-toggle" data-toggle="dropdown">
<span class="glyphicon glyphicon-option-horizontal"></span>
</div>
<ul class="dropdown-menu" style="left:-86px;">
<li><a href="#">Edit</a></li>
<li><a href="#">Delete</a></li>
</ul>
</div>
<div class="user-photo">
<img src="../../../img/erkan.jpg">
</div>
<div class="user-message">
<div class="message-header clearfix">
<div class="user-name">Erkan Öğümsöğütlü</div>
<div class="message-time">13:16</div>
</div>
<div class="message-content">
<p class="attachment-message">uploaded a file</p>
<a href="#" class="attachment-holder file-attached" target="_blank">
<img src="../../../img/file-icon.png">
<div class="attached-file-info">
<div>ulakbus-pdf</div>
<div>128KB PDF</div>
</div>
<span class="glyphicon glyphicon-download attachment-download"></span>
</a>
</div>
</div>
</div>
<!-- end of conversation-block -->
</div>
</div>
<div class="conversation-footer">
<textarea placeholder="Mesajını buraya yaz..."></textarea>
<div class="add-attachment">
<span class="glyphicon glyphicon-send"></span>
<div class="dropup" style="float:left;">
<span class="glyphicon glyphicon-paperclip dropdown-toggle" data-toggle="dropdown" id="attachment"></span>
<ul class="dropdown-menu" aria-labelledby="attachment" style="left:-104px;">
<li><a href="#">Image</a></li>
<li><a href="#">File</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="chat-app" ng-hide="hidden">
<div class="chat-app-container">
<div class="side-navigation">
<ul class="channels">
<li class="title">CHANNELS <span class="badge">{{ }}</span></li>
<li class="unread">Public Channel</li>
<li class="public-ro-channel">Public Read Only Channel</li>
</ul>
<ul class="channels">
<li class="title">NOTIFICATIONS <span class="badge">8</span></li>
<li class="unread">Notification One</li>
</ul>
<ul class="direct-messages">
<li class="compose"><span class="glyphicon glyphicon-plus-sign"></span> Create New Message</li>
<li class="title">DIRECT MESSAGES <span class="badge">14</span></li>
<li class="online" ng-class="{'active':'active', 'unread': 'unread'}">Erkan Öğümsöğütlü</li>
</ul>
</div>
<message-detail></message-detail>
<div class="chat-popup-window create-new-message-window">
<div class="close-chat-popup-window"><span class="glyphicon glyphicon-remove"></span></div>
<input type="text" placeholder="Birini ismi ile ara...">
<div class="search-results">
<div class="user">
<img src="../../../../img/erkan.jpg">
<div class="user-name">Erkan Öğümsöğütlü</div>
</div>
</div>
</div>
<!-- end of create-new-message-window -->
<div class="chat-popup-window create-new-channel-window">
<div class="close-chat-popup-window"><span class="glyphicon glyphicon-remove"></span></div>
<h3>Create New Channel</h3>
<div class="text-center">
<input type="text" placeholder="Channel Name"><br>
<textarea placeholder="Channel Description"></textarea>
<button class="btn btn-success">Create</button>
</div>
</div>
<!-- end of create-new-message-window -->
<div class="chat-popup-window add-user-unit">
<div class="close-chat-popup-window"><span class="glyphicon glyphicon-remove"></span></div>
<h3>Add User/Unit</h3>
<div class="text-center">
<input type="text" placeholder="Search User/Unit to Add"><br>
</div>
</div>
<!-- end of create-new-message-window -->
</div>
</div>
<div class="right-sidebar">
<div class="right-sidebar-box">
<div class="right-sidebar-messages">
<div class="right-sidebar-title clearfix">
<h3>Mesajlar</h3>
<span><a role="button">Tüm Mesajlar</a></span>
</div>
<!-- end of right-sidebar-title -->
<div class="right-sidebar-message-block" ng-repeat="notify in notifications[2] | limitTo:5">
<a class="clearfix">
<img src="../../../img/sample-profile-pic.jpg">
<div class="right-sidebar-message-content">
<div>{{notify.title}}</div>
<div>{{notify.body}}</div>
<div>16:05</div>
</div>
<!-- end of right-sidebar-message-content -->
</a>
</div>
<!-- end of right-sidebar-message-block -->
</div>
<!-- end of right-sidebar-messages -->
</div>
<!-- end of right-sidebar-box -->
<div class="right-sidebar-box">
<div class="right-sidebar-tasks">
<div class="right-sidebar-title clearfix">
<h3>Görevler</h3>
<span><a role="button">Tüm Görevler</a></span>
</div>
<!-- end of right-sidebar-title -->
<!--<div class="right-sidebar-task-block">-->
<!--<div class="task-type">Devam Eden Görevler</div>-->
<!--<a role="button">-->
<!--<div class="task-title">Öğrenci Kayıt</div>-->
<!--<div class="progress">-->
<!--<div class="progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="min-width: 2em; width:25%;">-->
<!--25%-->
<!--</div>-->
<!--</div>-->
<!--&lt;!&ndash; end of progress &ndash;&gt;-->
<!--</a>-->
<!--</div>-->
<!-- end of right-sidebar-task-block -->
<div class="right-sidebar-task-block">
<div class="task-type">Onay Bekleyen Görevler</div>
<a ng-repeat="notify in notifications[1] | limitTo:5">
<div class="task-title">{{notify.title}}</div>
</a>
</div>
<!-- end of right-sidebar-task-block -->
</div>
<!-- end of right-sidebar-tasks -->
</div>
<!-- end of right-sidebar-box -->
<div class="right-sidebar-box">
<div class="right-sidebar-announcements">
<div class="right-sidebar-title clearfix">
<h3>Duyurular</h3>
<span><a role="button">Tüm Duyurular</a></span>
</div>
<!-- end of right-sidebar-title -->
<div class="right-sidebar-announcement-block">
<a ng-repeat="notify in notifications[3] | limitTo:5">{{notify.body}}</a>
</div>
<!-- end of right-sidebar-status-block -->
</div>
<!-- end of right-sidebar-status -->
</div>
<!-- end of right-sidebar-box -->
<div class="right-sidebar-box">
<div class="right-sidebar-last-actions">
<div class="right-sidebar-title clearfix">
<h3>Son İşlemler</h3>
<span><a role="button">Tüm İşlemler</a></span>
</div>
<!-- end of right-sidebar-title -->
<div class="right-sidebar-last-action-block">
<a role="button">Birinci dönem bitimine 10 gün kaldı.</a>
<a role="button">Ders seçimi işlemleri xx tarihinde başlayacaktır.</a>
</div>
<!-- end of right-sidebar-status-block -->
</div>
<!-- end of right-sidebar-status -->
</div>
<!-- end of right-sidebar-box -->
</div>
<!-- end of right-sidebar -->
\ No newline at end of file
<div class="navbar-default sidebar" role="navigation" ng-mouseenter="openSidebar()" ng-mouseleave="closeSidebar()"> <div class="navbar-default sidebar" role="navigation">
<div class="sidebar-container"> <div class="sidebar-container">
<div class="sidebar-nav navbar-collapse"> <div class="sidebar-nav navbar-collapse">
<ul class="nav in" id="side-menu" ng-class="{hidden: $root.loggedInUser != true}" data-step="1" <ul class="nav in" id="side-menu" data-step="1"
data-intro="Genel menüler yer almaktadır. yapılacak işlemi buradan seçebilirsiniz."> data-intro="Genel menüler yer almaktadır. yapılacak işlemi buradan seçebilirsiniz.">
<!--<sidebar-search></sidebar-search>--> <!--<sidebar-search></sidebar-search>-->
<li ui-sref-active="active"> <li ui-sref-active="active">
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
<li ng-repeat="(k, v) in item"> <li ng-repeat="(k, v) in item">
<!--<a ng-if="v.model" ng-href="#{{v.url}}" ng- --> <!--<a ng-if="v.model" ng-href="#{{v.url}}" ng- -->
<!--ng-click="breadcrumb([key, v.text], $event)">{{v.text}}</a>--> <!--ng-click="breadcrumb([key, v.text], $event)">{{v.text}}</a>-->
<a ng-href="#/{{v.wf}}/{{v.model}}?{{v.param}}={{selectedUser.key}}" <a ng-href="#/{{v.wf}}/{{v.model}}"
ng-click="breadcrumb([key, v.text], $event)">{{v.text}}</a> ng-click="breadcrumb([key, v.text], $event)">{{v.text}}</a>
</li> </li>
</ul> </ul>
......
<div class="action-selector" ng-class="{readonly: readonly}">
<span class="action-indicator" ng-class="value"></span>
<div class="popover bottom ng-hide" ng-if="!readonly">
<div class="arrow"></div>
<div class="popover-content">
<ul class="actions-selector-select">
<li ng-click="setModelValue(1)">
<span class="action-indicator action-indicator_appropriate"></span>
</li>
<li ng-click="setModelValue(2)">
<span class="action-indicator action-indicator_uncertain"></span>
</li>
<li ng-click="setModelValue(3)">
<span class="action-indicator action-indicator_busy"></span>
</li>
</ul>
</div>
</div>
</div>
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
data-toggle="dropdown"> data-toggle="dropdown">
<span class="caret"></span> <span class="caret"></span>
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu" ng-if="form.titleMap.length > 0">
<li class="text-center" ng-if="form.gettingTitleMap"><a><span class="loader"></span></a></li> <li class="text-center" ng-if="form.gettingTitleMap"><a><span class="loader"></span></a></li>
<li ng-repeat="item in form.titleMap"> <li ng-repeat="item in form.titleMap">
<a ng-click="form.onDropdownSelect(item, form.name)">{{item <a ng-click="form.onDropdownSelect(item, form.name)">{{item
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<label class="control-label {{form.labelHtmlClass}}" ng-show="showTitle()"> <label class="control-label {{form.labelHtmlClass}}" ng-show="showTitle()">
{{form.title}} {{form.title}}
</label> </label>
<a role="button"><i class="fa fa-plus-circle fa-fw" add-modal-for-linked-model="{{form.formName}}"></i></a> <!--<a role="button"><i class="fa fa-plus-circle fa-fw" add-modal-for-linked-model="{{form.formName}}"></i></a>-->
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
...@@ -26,7 +26,9 @@ ...@@ -26,7 +26,9 @@
class="form-control {{form.fieldHtmlClass}}" class="form-control {{form.fieldHtmlClass}}"
schema-validate="form" schema-validate="form"
ng-options="item as item.name for item in form.filteredItems" ng-options="item as item.name for item in form.filteredItems"
name="filterItems" multiple> name="filterItems"
size=30 style="height: 60%;"
multiple>
</select> </select>
</div> </div>
...@@ -45,7 +47,9 @@ ...@@ -45,7 +47,9 @@
class="form-control {{form.fieldHtmlClass}}" class="form-control {{form.fieldHtmlClass}}"
schema-validate="form" schema-validate="form"
ng-options="item as item.name for item in form.selectedFilteredItems" ng-options="item as item.name for item in form.selectedFilteredItems"
name="selectedItems" multiple> name="selectedItems"
size=30 style="height: 60%;"
multiple>
</select> </select>
</div> </div>
</div> </div>
......
<div class="modal-body">
<h3>{{notification.title}}</h3>
{{notification.body}}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" ng-click="cancel()">İptal</button>
</div>
<div class="tablescroll">
<table class="table table-bordered" style="background-color:#fff;">
<thead>
<tr ng-if="node.schema.formType=='ListNode'">
<th colspan="2" ng-if="meta.allow_selection===true">
<label>
<input type="checkbox" style="zoom:1.5; margin:5px 0 0 8px;">
Hepsini Seç
</label>
</th>
<th scope="row" style="text-align:center">#</th>
<th ng-repeat="(key,value) in node.items[0] track by $index"
ng-if="key!=='idx' && node.schema.properties[key]">
<span ng-if="value.verbose_name">{{ value.verbose_name }}</span>
<span ng-if="!value.verbose_name">{{key}}</span>
</th>
<th ng-if="meta.allow_actions!==false">İşlem</th>
</tr>
</thead>
<tbody ng-class="{hidden: node.lengthModels < 1}">
<tr ng-repeat="listnodemodel in node.items track by $index"
ng-init="outerIndex=$index"
ng-if="node.schema.formType=='ListNode'">
<td ng-if="meta.allow_selection===true" width="60">
<label>
<input type="checkbox" style="zoom:1.5; margin:5px 0 0 8px;">
</label>
</td>
<td scope="row" style="text-align:center">{{$index+1}}</td>
<td ng-repeat="(k, v) in listnodemodel track by $index"
ng-init="innerIndex=$index"
ng-if="k!=='idx' && node.schema.properties[k]">
<span ng-if="!node.schema.inline_edit || node.schema.inline_edit.indexOf(k) < 0">{{ v.unicode || v }}</span>
<input type="{{node.schema.properties[k].type}}"
ng-if="node.schema.inline_edit.indexOf(k) > -1"
ng-model="node.model[outerIndex][k]"
ng-change="nodeModelChange(this)">
</td>
<td ng-if="meta.allow_actions!==false">
<div ng-hide="meta.object_actions.length > 0">
<span ng-click="remove(node, 'ListNode', $index)"><i class="fa fa-times fa=fw"></i></span>
</div>
<div ng-show="meta.object_actions.length > 0">
<!-- define object actions here -->
</div>
</td>
</tr>
</tbody>
</table>
</div>
\ No newline at end of file
<div class="form-group {{form.htmlClass}} schema-form-select col-md-12"
ng-class="{'has-error': form.disableErrorState !== true && hasError(), 'has-success': form.disableSuccessState !== true && hasSuccess(), 'has-feedback': form.feedback !== false}">
<label class="control-label {{form.labelHtmlClass}}" ng-show="showTitle()">
{{form.title}}
</label>
<input ng-if="form.widget!=='custom'"
type="text"
autocomplete="off"
ng-model="$$value$$"
uib-typeahead="item as item.name for item in form.titleMap"
typeahead-wait-ms="500"
typeahead-loading="loadingTitleMap"
typeahead-on-select="form.onDropdownSelect($item, form.name)"
placeholder="{{form.title}}"
ng-model-options="form.ngModelOptions"
ng-disabled="form.readonly"
sf-changed="form"
class="form-control {{form.fieldHtmlClass}}"
schema-validate="form"
name="{{form.name}}"/>
<input ng-if="form.widget==='custom'"
type="text"
autocomplete="off"
ng-model="$$value$$"
uib-typeahead="item as item.name for item in form.getTitleMap($viewValue)"
typeahead-wait-ms="500"
typeahead-loading="loadingTitleMap"
typeahead-on-select="form.onDropdownSelect($item, form.name)"
placeholder="{{form.title}}"
ng-model-options="form.ngModelOptions"
ng-disabled="form.readonly"
sf-changed="form"
class="form-control {{form.fieldHtmlClass}}"
schema-validate="form"
name="{{form.name}}"/>
<div ng-show="loadingTitleMap" class="loader"></div>
<div class="help-block" sf-message="form.description"></div>
</div>
\ No newline at end of file
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
angular.module('ulakbus')
.controller('KeyListenController', function ($scope, action_service) {
$scope.keylog = [0,1];
$scope.down = function(e) {
angular.forEach(action_service.combinations, function (value, key) {
if (action_service.equal(value, $scope.keylog.concat([e.keyCode]))) {
action_service.acts[key]();
}
});
$scope.keylog.shift();
$scope.keylog.push(e.keyCode);
};
// when user_ready broadcasted then change value of user_ready=true to display view
$scope.$on('user_ready', function () {
$scope.user_ready = true;
});
$scope.user_ready = false;
})
.factory('action_service', function ($uibModal, $log) {
var actions = {};
actions.equal = function (a,b) { return !(a<b || b<a); };
actions.combinations = {
'open_inspector': [91,16,75] // ctrl + k
};
actions.acts = {
// opens a modal dialog full of menu items with typeahead
'open_inspector': function () {
var modalInstance = $uibModal.open({
animation: true,
templateUrl: 'shared/templates/actionsModalContent.html',
controller: 'ActionsModalController',
resolve: {
items: function () {
return document.querySelectorAll('.navbar-collapse a, #side-user-menu a, .dropdown-menu li a');
}
}
});
modalInstance.result.then(function (selectedItem) {
$log.info('resirect to:', selectedItem);
location.hash = selectedItem.value;
});
}
};
return actions;
})
.controller('ActionsModalController', function ($scope, $uibModalInstance, items) {
$scope.actions = [];
angular.forEach(items, function (value, key) {
if (!value.children[1]) {
$scope.actions.push({ name: value.innerHTML, value: value.hash});
}
});
$scope.doThis = function (item) {
$uibModalInstance.close(item);
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
});
\ No newline at end of file
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
angular.module('ulakbus')
.factory('ErrorService', function (toastr, $rootScope, $location, $log) {
var error_service = {};
error_service.handle = function (rejection, prtcl) {
var errorInModal;
if (prtcl === 'http') {
if (rejection.data) {
errorInModal = ('error' in rejection.data);
} else {
errorInModal = false;
}
}
if (prtcl === 'ws') {
rejection.status = rejection.status || rejection.code;
rejection.data = {error: rejection.error, title: rejection.title};
errorInModal = true;
}
var errorModal = function () {
if ($rootScope.loginAttempt === 0 && prtcl === 'http') {
$log.debug('not logged in, no alert message triggered');
return;
}
var codefield = "";
if (rejection.data.error) {
codefield = '<p><pre>' +
rejection.data.error +
'</pre></p>';
}
$('<div class="modal">' +
'<div class="modal-dialog" style="width:100%;" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span' +
' aria-hidden="true">&times;</span></button>' +
'<h4 class="modal-title" id="exampleModalLabel">' +
"Error Status: " + rejection.status + "<br>Error Title: " + rejection.data.title +
'</h4>' +
'</div>' +
'<div class="modal-body">' +
'<div class="alert alert-danger">' +
'<strong>' +
rejection.data.description +
'</strong>' +
codefield +
'</div>' +
'</div>' +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-default" data-dismiss="modal">Kapat</button>' +
'</div>' +
'</div>' +
'</div>' +
'</div>').modal();
// use no_highlight to display pure html
if (!rejection.no_highlight) {
try {
$('pre:not(.hljs)').each(function (i, block) {
hljs.highlightBlock(block);
});
}
catch (e) {
$log.debug('Exception: ', e.message);
}
}
};
var errorInAlertBox = function (alertContent) {
if (errorInModal) {
errorModal();
} else {
if ($rootScope.loginAttempt > 0) {
toastr.error(alertContent.msg, alertContent.title);
}
}
};
var errorForAlertBox = {
title: rejection.status,
msg: rejection.data ? rejection.data.description : 'Error',
type: 'error'
};
var errorDispatch = {
"-1": function () {
$log.error('-1 returned:', rejection);
},
"400": function () {
$location.reload();
},
"401": function () {
if ($location.path() === "/login") {
$log.debug("show errors on login form");
} else {
alert("Want relogin!");
return window.location.reload();
}
},
"403": function () {
if (rejection.data.is_login === true) {
$rootScope.loggedInUser = true;
if ($location.path() === "/login") {
$location.path("/dashboard");
}
}
},
"404": function () {
errorInAlertBox(errorForAlertBox);
},
"500": function () {
errorInAlertBox(errorForAlertBox);
},
"503": function () {
rejection.data = {description: "Servise erişilemiyor."};
errorInAlertBox(errorForAlertBox);
}
};
errorDispatch[rejection.status || rejection.code]();
};
return error_service;
});
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
angular.module('ulakbus')
.factory('FormConstraints', function ($q, $log, $timeout) {
// Generic functions
/**
* gets expression and returns reject/resolve promise
* @param condition {Expression}
* @returns {Promise}
*/
var cond = function (condition) {
return !condition;
};
var cond_generator = function () {
return {
lt: function (a, b) {
return !(a < b);
},
gt: function (a, b) {
return !(a > b);
}
}
};
/**
*
* @param va1 {String} value of input
* @param val2 {Array} values of other inputs
* @param condition {String}
*/
var cond_multiple = function (val1, val2, condition) {
var valid = true;
angular.forEach(val2, function (value, key) {
inputval = angular.element(document.querySelector('#' + value)).val();
if (cond_generator()[condition](val1, inputval)) {
valid = false;
}
});
return valid;
};
var fo_co = {};
/**
* lesser than
* @param value {String,Number}
* @param ref_val {String,Number}
* @param type {String}
* @returns {Promise}
*/
fo_co.lt = function (value, ref_val, input_name) {
return cond(value > ref_val);
};
/**
* lesser than date
* @param value {String,Number}
* @param ref_val {String,Number}
* @param type {String}
* @returns {Promise}
*/
fo_co.lt_date = function (value, ref_val, input_name) {
return cond(value > ref_val);
};
/**
* lesser than multiple
* @param value {String,Number}
* @param ref_vals {Array}
* @param type {String}
* @returns {Promise}
*/
fo_co.ltm = function (value, ref_vals, input_name) {
return cond_multiple(value, ref_vals, 'lt');
};
/**
* greater than
* @param value {String,Number}
* @param ref_val {String,Number}
* @param type {String}
* @returns {Promise}
*/
fo_co.gt = function (value, ref_val, input_name) {
return cond(value < ref_val);
};
/**
* greater than date
* @param value {String,Number}
* @param ref_val {String,Number}
* @param type {String}
* @returns {Promise}
*/
fo_co.gt_date = function (value, ref_val, input_name) {
return cond(value < ref_val);
};
/**
* greater than multiple
* @param value {String,Number}
* @param ref_vals {Array}
* @param type {String}
* @returns {Promise}
*/
fo_co.gtm = function (value, ref_vals, input_name) {
return cond_multiple(value, ref_vals, 'gt');
};
/**
* disable fields when input has value
* @param value {String,Number}
* @param fields {Array} they must be schemaform schema property items
* @param type {String}
*/
fo_co.selectbox_fields = function (value, fields, input_name) {
// use disableErrorState to disable hidden field validations
var form_items = angular.element(document.querySelectorAll('bootstrap-decorator'));
angular.forEach(form_items, function (v, k) {
angular.element(v).removeClass('hide');
var checkpoint;
try{
if (angular.isDefined(v.querySelector('input')) && v.querySelector('input') !== null ) {
checkpoint = v.querySelector('input').name
} else {
checkpoint = v.querySelector('select').name;
}
if (checkpoint !== input_name[0] && checkpoint !== fields[value][0]) {
angular.element(v).addClass('hide');
$log.debug(checkpoint, fields[value], angular.isDefined(fields[checkpoint]));
}
} catch(e){
$log.error(e.message);
}
});
};
return fo_co;
});
\ No newline at end of file
...@@ -19,7 +19,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -19,7 +19,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* Moment.js used for date type conversions. * Moment.js used for date type conversions.
* there must be no global object, so we change it into a service here. * there must be no global object, so we change it into a service here.
*/ */
.service('Moment', function(){ .service('Moment', function () {
return window.moment; return window.moment;
}) })
...@@ -29,7 +29,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -29,7 +29,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @name Generator * @name Generator
* @description form service's Generator factory service handles all generic form operations * @description form service's Generator factory service handles all generic form operations
*/ */
.factory('Generator', function ($http, $q, $timeout, $sce, $location, $route, $compile, $log, RESTURL, $rootScope, Moment) { .factory('Generator', function ($http, $q, $timeout, $sce, $location, $route, $compile, $log, RESTURL, $rootScope, Moment, WSOps, FormConstraints, $uibModal, $filter, Utils) {
var generator = {}; var generator = {};
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
...@@ -58,6 +58,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -58,6 +58,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
*/ */
generator.generate = function (scope, data) { generator.generate = function (scope, data) {
$log.debug("data before generation:", data);
// if no form in response (in case of list and single item request) return scope // if no form in response (in case of list and single item request) return scope
if (!data.forms) { if (!data.forms) {
return scope; return scope;
...@@ -182,13 +183,92 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -182,13 +183,92 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
) )
}); });
$log.debug('grouped form: ', newForm); if (newForm.length > 0) {
$log.debug('rest of form: ', scope.form); $log.debug('grouped form: ', newForm);
$log.debug('form united: ', newForm.concat(scope.form)); $log.debug('rest of form: ', scope.form);
$log.debug('form united: ', newForm.concat(scope.form));
}
scope.form = newForm.concat(scope.form); scope.form = newForm.concat(scope.form);
return scope; return scope;
}; };
/**
* @description generates form constraints as async validators
* async validators defined in form_constraints.js
* keys are input names
* @example
* `
* forms.constraints = {
*
* // date field type constraint to greater than certain date
* 'birth_date': {
* cons: 'gt_date',
* val: '22.10.1988',
* val_msg: 'Birthdate must be greater than 22.10.1988'
* },
* // a number field lesser than a certain number
* 'number': {
* cons: 'lt',
* val: 50,
* val_msg: 'number must be lesser than 50'
* },
* // a field lesser than multiple fields' values
* 'some_input': {
* cons: 'lt_m',
* val: ['this', 'and', 'that', 'inputs'],
* val_msg: 'some_input must be lesser than this, and, that, inputs'
* },
* // a field shows some other fields
* 'some_input2': {
* cons: 'selectbox_fields',
* val: [
* {'val1': ['this', 'and']},
* {'val2': ['this2', 'and2']}]
* val_msg: 'some_input2 disables this, and, this, inputs'
* },
* // a field hides some other fields
* 'some_input3': {
* cons: 'checkbox_fields',
* val: [
* {'val1': ['this', 'and']},
* {'val2': ['this2', 'and2']}]
* val_msg: 'some_input2 disables this, and, this, inputs'
* },
* // todo: a field change changes other field or fields values
* }
* `
* @param scope
*/
generator.constraints = function (scope) {
angular.forEach(scope.form, function (v, k) {
try {
var cons = scope.forms.constraints[v] || scope.forms.constraints[v.key];
if (angular.isDefined(cons)) {
if (v.constructor === String) {
scope.form[k] = {
key: v,
validationMessage: {'form_cons': cons.val_msg},
$validators: {
form_cons: function (value) {
return FormConstraints[cons.cons](value, cons.val, v);
}
}
};
} else {
v.key = v.key;
v.validationMessage = angular.extend({'form_cons': cons.val_msg}, v.validationMessage);
v.$validators = angular.extend({
form_cons: function (value) {
return FormConstraints[cons.cons](value, cons.val, v.key);
}
}, v.$asyncValidators);
}
}
} catch (e) {
$log.error(e.message);
}
});
return generator.group(scope);
};
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
* @ngdoc function * @ngdoc function
...@@ -207,9 +287,17 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -207,9 +287,17 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* *
* @returns scope {Object} * @returns scope {Object}
*/ */
generator.prepareFormItems = function (scope) { generator.prepareFormItems = function (scope) {
angular.forEach(scope.form, function (value, key) { angular.forEach(scope.form, function (value, key) {
// parse markdown for help text
if (value.type === 'help'){
var markdown = $filter('markdown');
value.helpvalue = markdown(value.helpvalue);
}
if (value.type === 'select') { if (value.type === 'select') {
scope.schema.properties[value.key].type = 'select'; scope.schema.properties[value.key].type = 'select';
scope.schema.properties[value.key].titleMap = value.titleMap; scope.schema.properties[value.key].titleMap = value.titleMap;
...@@ -217,453 +305,674 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -217,453 +305,674 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
} }
}); });
angular.forEach(scope.schema.properties, function (v, k) { var _buttons = function (scope, v, k) {
var buttonPositions = scope.modalElements ? scope.modalElements.buttonPositions : {
// generically change _id fields model value bottom: 'move-to-bottom',
if ('form_params' in scope) { top: 'move-to-top',
if (k == scope.form_params.param) { none: ''
scope.model[k] = scope.form_params.id; };
scope.form.splice(scope.form.indexOf(k), 1); var workOnForm = scope.modalElements ? scope.modalElements.workOnForm : 'formgenerated';
return; var workOnDiv = scope.modalElements ? scope.modalElements.workOnDiv : '';
} var buttonClass = (buttonPositions[v.position] || buttonPositions.bottom);
} var redirectTo = scope.modalElements ? false : true;
if (v.type === 'file') { // in case backend needs styling the buttons
scope.form[scope.form.indexOf(k)] = { // it needs to send style key with options below
type: "template", // btn-default btn-primary btn-success btn-info btn warning
title: v.title, // btn-danger is default
templateUrl: "shared/templates/filefield.html", scope.form[scope.form.indexOf(k)] = {
name: k, type: v.type,
key: k, title: v.title,
fileInsert: function () { style: (v.style || "btn-danger") + " hide bottom-margined " + buttonClass,
$scope.$broadcast('schemaForm.error.' + k, 'tv4-302', true); onClick: function () {
}, delete scope.form_params.cmd;
imageSrc: scope.model[k] ? $rootScope.settings.static_url + scope.model[k] : '', delete scope.form_params.flow;
avatar: k === 'avatar' if (v.cmd) {
}; scope.form_params["cmd"] = v.cmd;
v.type = 'string'; }
} if (v.flow) {
scope.form_params["flow"] = v.flow;
if (v.type === 'select') { }
scope.form[scope.form.indexOf(k)] = { if (v.wf) {
type: "template", delete scope.form_params["cmd"];
title: v.title, scope.form_params["wf"] = v.wf;
templateUrl: "shared/templates/select.html", }
name: k, scope.model[k] = 1;
key: k, // todo: test it
titleMap: v.titleMap if (scope.modalElements) {
}; scope.submitModalForm();
} } else {
if (!v.form_validate && angular.isDefined(v.form_validate)) {
if (v.type === 'submit' || v.type === 'button') { generator.submit(scope, redirectTo);
var buttonPositions = scope.modalElements ? scope.modalElements.buttonPositions : {
bottom: 'move-to-bottom',
top: 'move-to-top',
none: ''
};
var workOnForm = scope.modalElements ? scope.modalElements.workOnForm : 'formgenerated';
var workOnDiv = scope.modalElements ? scope.modalElements.workOnDiv : '';
var buttonClass = (buttonPositions[v.position] || buttonPositions.bottom);
var redirectTo = scope.modalElements ? false : true;
scope.form[scope.form.indexOf(k)] = {
type: v.type,
title: v.title,
style: "btn-danger hide " + buttonClass,
onClick: function () {
delete scope.form_params.cmd;
delete scope.form_params.flow;
if (v.cmd) {
scope.form_params["cmd"] = v.cmd;
}
if (v.flow) {
scope.form_params["flow"] = v.flow;
}
if (v.wf) {
delete scope.form_params["cmd"];
scope.form_params["wf"] = v.wf;
}
scope.model[k] = 1;
// todo: test it
if (scope.modalElements) {
scope.submitModalForm();
} else { } else {
if (v.validation === false) { scope.$broadcast('schemaFormValidate');
if (scope[workOnForm].$valid) {
generator.submit(scope, redirectTo); generator.submit(scope, redirectTo);
scope.$broadcast('disposeModal');
} else { } else {
scope.$broadcast('schemaFormValidate'); // focus to first input with validation error
if (scope[workOnForm].$valid) { $timeout(function () {
generator.submit(scope, redirectTo); var firsterror = angular.element(document.querySelectorAll('input.ng-invalid'))[0];
scope.$broadcast('disposeModal'); firsterror.focus();
} else { });
// focus to first input with validation error
$timeout(function () {
var firsterror = angular.element(document.querySelectorAll('input.ng-invalid'))[0]
firsterror.focus();
});
}
} }
} }
} }
}; }
// replace buttons according to their position values };
$timeout(function () { // ADD CONSTRAINTS if cons
var selectorBottom = '.buttons-on-bottom' + workOnDiv;
//var selectorTop = '.buttons-on-top'+workOnDiv; // replace buttons according to their position values
$timeout(function () {
var buttonsToBottom = angular.element(document.querySelector('.' + buttonClass)); var selectorBottom = '.buttons-on-bottom' + workOnDiv;
angular.element(document.querySelector(selectorBottom)).append(buttonsToBottom); //var selectorTop = '.buttons-on-top'+workOnDiv;
//var buttonsToTop = angular.element(document.querySelector('.' + buttonClass));
//angular.element(document.querySelector(selectorTop)).append(buttonsToTop); var buttonsToBottom = angular.element(document.querySelector('.' + buttonClass));
angular.element(document.querySelector(selectorBottom)).append(buttonsToBottom);
buttonsToBottom.removeClass('hide'); //var buttonsToTop = angular.element(document.querySelector('.' + buttonClass));
//buttonsToTop.removeClass('hide'); //angular.element(document.querySelector(selectorTop)).append(buttonsToTop);
}, 500);
} buttonsToBottom.removeClass('hide');
//buttonsToTop.removeClass('hide');
}, 500);
};
var _numbers = function (scope, v, k) {
v.type = 'number';
v.validationMessage = {'max': 'bu alan -2147483647 ve 2147483647 arasında olmalıdır.'}
v.$validators = {
max: function(value){
return 2147483647>value>-2147483647;
}
};
scope.model[k] = parseInt(scope.model[k]);
};
var _node_default = function (scope, v, k) {
scope[v.type] = scope[v.type] || {};
// no pass by reference
scope[v.type][k] = angular.copy({
title: v.title,
form: [],
schema: {
properties: {},
properties_list: [],
required: [],
title: v.title,
type: "object",
formType: v.type,
model_name: k,
inline_edit: scope.inline_edit
},
buttons: v.buttons,
url: scope.url,
wf: v.wf || scope.wf,
quick_add: v.quick_add,
quick_add_view: v.quick_add_view,
quick_add_model: v.quick_add_model,
quick_add_field: v.quick_add_field,
nodeModelChange: function (item) {
}
// check if type is date and if type date found change it to string });
if (v.type === 'date') {
$log.debug('date:', scope.model[k]);
scope.model[k] = generator.dateformatter(scope.model[k]);
scope.form[scope.form.indexOf(k)] = {
key: k, name: k, title: v.title,
type: 'template',
templateUrl: 'shared/templates/datefield.html',
validationMessage: {
'dateNotValid': "Girdiğiniz tarih geçerli değildir. <i>orn: '01.01.2015'<i/>",
302: 'Bu alan zorunludur.'
},
$asyncValidators: {
'dateNotValid': function (value) {
var deferred = $q.defer();
$timeout(function () {
scope.model[k] = angular.copy(generator.dateformatter(value));
if (scope.schema.required.indexOf(k) > -1) {
deferred.resolve();
}
if (value.constructor === Date) {
deferred.resolve();
}
else {
var dateValue = d = value.split('.');
if (isNaN(Date.parse(value)) || dateValue.length !== 3) {
deferred.reject();
} else {
deferred.resolve();
}
}
});
return deferred.promise;
}
},
status: {opened: false},
open: function ($event) {
this.status.opened = true;
},
format: 'dd.MM.yyyy',
onSelect: function () {
scope.model[k] = angular.copy(generator.dateformatter(scope.model[k]));
}
};
}
if (v.type === 'int' || v.type === 'float') { angular.forEach(v.schema, function (item) {
v.type = 'number'; scope[v.type][k].schema.properties[item.name] = angular.copy(item);
scope.model[k] = parseInt(scope.model[k]);
}
if (v.type === 'text_general') { // save properties order in schema
v.type = 'string'; if (item.name != 'idx'){
v["x-schema-form"] = { scope[v.type][k].schema.properties_list.push(scope[v.type][k].schema.properties[item.name]);
"type": "textarea"
//"placeholder": ""
} }
}
// if type is model use foreignKey.html template to show them
if (v.type === 'model') {
var formitem = scope.form[scope.form.indexOf(k)];
var modelScope = {"url": v.wf, "wf": v.wf, "form_params": {model: v.model_name, cmd: v.list_cmd}};
//scope.$on('refreshTitleMap', function (event, data) { if (angular.isDefined(item.wf)) {
// todo: write a function to refresh titleMap after new item add to linkedModel scope[v.type][k].schema.properties[item.name]['wf'] = angular.copy(item.wf);
//}); }
scope.generateTitleMap = function (modelScope) { // prepare required fields
return generator.get_list(modelScope).then(function (res) { if (item.required === true && item.name !== 'idx') {
formitem.titleMap = []; scope[v.type][k].schema.required.push(angular.copy(item.name));
angular.forEach(res.data.objects, function (item) { }
if (item !== -1) {
formitem.titleMap.push({
"value": item.key,
"name": item.value
});
} else {
formitem.focusToInput = true;
}
});
return formitem.titleMap; // idx field must be hidden
if (item.name !== 'idx') {
scope[v.type][k].form.push(item.name);
}
}); try {
}; if (item.type === 'date') {
//scope.model[k][item.name] = generator.dateformatter(scope.model[k][item.name]);
}
} catch (e) {
$log.debug('Error: ', e.message);
}
// get selected item from titleMap using model value
if (scope.model[k]) {
generator.get_list({
url: 'crud',
form_params: {model: v.model_name, object_id: scope.model[k], cmd: 'object_name'}
})
.then(function (data) {
try {
scope.$watch(document.querySelector('input[name=' + v.model_name + ']'),
function () {
document.querySelector('input[name=' + k + ']').value = data.data.object_name;
}
);
}
catch (e) {
document.querySelector('input[name=' + k + ']').value = data.data.object_name;
$log.debug('exception', e);
}
}); });
}
formitem = { $timeout(function () {
type: "template", if (v.type != 'ListNode') return;
templateUrl: "shared/templates/foreignKey.html",
// formName will be used in modal return to save item on form
formName: k,
title: v.title,
wf: v.wf,
add_cmd: v.add_cmd,
name: k,
key: k,
model_name: v.model_name,
selected_item: {},
titleMap: [],
onSelect: function (item, inputname) {
scope.model[k] = item.value;
$timeout(function () {
document.querySelector('input[name=' + inputname + ']').value = item.name;
});
},
onDropdownSelect: function (item, inputname) {
scope.model[k] = item.value;
$timeout(function () {
document.querySelector('input[name=' + inputname + ']').value = item.name;
});
},
getTitleMap: function (viewValue) {
modelScope.form_params.query = viewValue;
return scope.generateTitleMap(modelScope);
},
getDropdownTitleMap: function () {
delete modelScope.form_params.query;
formitem.gettingTitleMap = true;
scope.generateTitleMap(modelScope)
.then(function (data) {
formitem.titleMap = data;
formitem.gettingTitleMap = false;
});
// todo: needs refactor
var list = scope[v.type][k];
list.items = angular.copy(scope.model[k] || []);
} angular.forEach(list.items, function (node, fieldName) {
};
scope.form[scope.form.indexOf(k)] = formitem; if (!Object.keys(node).length) return;
}
if ((v.type === 'ListNode' || v.type === 'Node') && v.widget === 'filter_interface') { angular.forEach(node, function (prop, propName) {
var formitem = scope.form[scope.form.indexOf(k)]; var propInSchema = list.schema.properties[propName];
var modelScope = { try {
"url": v.wf || scope.wf, "wf": v.wf || scope.wf, if (propInSchema.type === 'date') {
"form_params": {model: v.model_name || v.schema[0].model_name, cmd: v.list_cmd || 'select_list', query: ''} node[propName] = generator.dateformatter(prop);
}; list.model[fieldName][propName] = generator.dateformatter(prop);
scope.generateTitleMap = function (modelScope) {
generator.get_list(modelScope).then(function (res) {
formitem.titleMap = [];
angular.forEach(res.data.objects, function (item) {
if (item !== "-1") {
formitem.titleMap.push({
"value": item.key,
"name": item.value
});
} }
}); if (propInSchema.type === 'select') {
formitem.filteredItems = generator.get_diff_array(angular.copy(formitem.titleMap), angular.copy(formitem.selectedFilteredItems), 1); node[propName] = generator.item_from_array(prop.toString(), list.schema.properties[propName].titleMap)
}) }
}; if (propInSchema.titleMap){
node[propName] = {
var modelItems = []; key: prop,
var modelKeys = []; unicode: generator.item_from_array(prop, propInSchema.titleMap)
angular.forEach(scope.model[k], function (value, mkey) { };
modelItems.push({ }
"value": value[v.schema[0].name].key, } catch (e) {
"name": value[v.schema[0].name].unicode $log.debug('Field is not date');
}
}); });
var modelKey = {};
modelKey[v.schema[0].name] = value[v.schema[0].name].key;
modelKeys.push(modelKey);
});
scope.model[k] = angular.copy(modelKeys);
formitem = { });
type: "template", });
templateUrl: "shared/templates/multiselect.html",
title: v.title,
// formName will be used in modal return to save item on form
formName: k,
wf: v.wf,
add_cmd: v.add_cmd,
name: v.model_name,
model_name: v.model_name,
filterValue: '',
selected_item: {},
filteredItems: [],
selectedFilteredItems: modelItems,
titleMap: scope.generateTitleMap(modelScope),
appendFiltered: function (filterValue) {
if (filterValue.length > 2) {
formitem.filteredItems = [];
angular.forEach(formitem.titleMap, function (value, key) {
if (value.name.indexOf(filterValue) > -1) {
formitem.filteredItems.push(formitem.titleMap[key]);
}
});
}
if (filterValue <= 2) { formitem.filteredItems = formitem.titleMap}
formitem.filteredItems = generator.get_diff_array(formitem.filteredItems, formitem.selectedFilteredItems);
},
select: function (selectedItemsModel) {
if (!selectedItemsModel) {
return;
}
formitem.selectedFilteredItems = formitem.selectedFilteredItems.concat(selectedItemsModel);
formitem.appendFiltered(formitem.filterValue);
scope.model[k] = (scope.model[k] || []).concat(formitem.dataToModel(selectedItemsModel));
},
deselect: function (selectedFilteredItemsModel) {
if (!selectedFilteredItemsModel) {
return;
}
formitem.selectedFilteredItems = generator.get_diff_array(angular.copy(formitem.selectedFilteredItems), angular.copy(selectedFilteredItemsModel));
formitem.appendFiltered(formitem.filterValue);
formitem.filteredItems = formitem.filteredItems.concat(selectedFilteredItemsModel);
scope.model[k] = generator.get_diff_array(scope.model[k] || [], formitem.dataToModel(selectedFilteredItemsModel));
},
dataToModel: function (data) {
var dataValues = [];
angular.forEach(data, function (value, key) {
var dataKey = {};
dataKey[v.schema[0].name] = value.value;
dataValues.push(dataKey);
});
return dataValues;
}
};
scope.form[scope.form.indexOf(k)] = formitem; scope.model[k] = scope.model[k] || [];
} scope[v.type][k].model = scope.model[k];
if ((v.type === 'ListNode' || v.type === 'Node') && v.widget !== 'filter_interface') { // lengthModels is length of the listnode models. if greater than 0 show records on template
scope[v.type][k]['lengthModels'] = scope.model[k] ? 1 : 0;
scope[v.type] = scope[v.type] || {}; };
var _node_filter_interface = function (scope, v, k) {
var formitem = scope.form[scope.form.indexOf(k)];
var modelScope = {
"form_params": {
wf: v.wf || scope.wf || scope.form_params.wf,
model: v.model_name || v.schema[0].model_name,
cmd: v.list_cmd || 'select_list',
query: ''
}
};
scope.generateTitleMap = function (modelScope) {
generator.get_list(modelScope).then(function (res) {
formitem.titleMap = [];
angular.forEach(res.objects, function (item) {
if (item !== "-1") {
formitem.titleMap.push({
"value": item.key,
"name": item.value
});
}
});
formitem.filteredItems = generator.get_diff_array(angular.copy(formitem.titleMap), angular.copy(formitem.selectedFilteredItems), 1);
})
};
// no pass by reference var modelItems = [];
scope[v.type][k] = angular.copy({ var modelKeys = [];
title: v.title,
form: [],
schema: {
properties: {},
required: [],
title: v.title,
type: "object",
formType: v.type,
model_name: k,
inline_edit: scope.inline_edit
},
url: scope.url,
wf: scope.wf,
nodeModelChange: function (item) {
//debugger;
}
angular.forEach(scope.model[k], function (value, mkey) {
modelItems.push({
"value": value[v.schema[0].name].key,
"name": value[v.schema[0].name].unicode
}); });
var modelKey = {};
angular.forEach(v.schema, function (item) { modelKey[v.schema[0].name] = value[v.schema[0].name].key;
scope[v.type][k].schema.properties[item.name] = angular.copy(item); modelKeys.push(modelKey);
});
// prepare required fields scope.model[k] = angular.copy(modelKeys);
if (item.required === true && item.name !== 'idx') {
scope[v.type][k].schema.required.push(angular.copy(item.name)); formitem = {
type: "template",
templateUrl: "shared/templates/multiselect.html",
title: v.title,
// formName will be used in modal return to save item on form
formName: k,
wf: v.wf || scope.wf,
add_cmd: v.add_cmd,
name: v.model_name || v.schema[0].model_name,
model_name: v.model_name || v.schema[0].model_name,
filterValue: '',
selected_item: {},
filteredItems: [],
selectedFilteredItems: modelItems,
titleMap: scope.generateTitleMap(modelScope),
appendFiltered: function (filterValue) {
if (filterValue.length > 2) {
formitem.filteredItems = [];
angular.forEach(formitem.titleMap, function (value, key) {
if (value.name.indexOf(filterValue) > -1) {
formitem.filteredItems.push(formitem.titleMap[key]);
}
});
} }
if (filterValue <= 2) {
// idx field must be hidden formitem.filteredItems = formitem.titleMap
if (item.name !== 'idx') {
scope[v.type][k].form.push(item.name);
} }
formitem.filteredItems = generator.get_diff_array(formitem.filteredItems, formitem.selectedFilteredItems);
try { },
if (item.type === 'date') { select: function (selectedItemsModel) {
scope.model[k][item.name] = generator.dateformatter(scope.model[k][item.name]); if (!selectedItemsModel) {
} return;
} catch (e) { }
$log.debug('Error: ', e.message); formitem.selectedFilteredItems = formitem.selectedFilteredItems.concat(selectedItemsModel);
formitem.appendFiltered(formitem.filterValue);
scope.model[k] = (scope.model[k] || []).concat(formitem.dataToModel(selectedItemsModel));
},
deselect: function (selectedFilteredItemsModel) {
if (!selectedFilteredItemsModel) {
return;
} }
formitem.selectedFilteredItems = generator.get_diff_array(angular.copy(formitem.selectedFilteredItems), angular.copy(selectedFilteredItemsModel));
formitem.appendFiltered(formitem.filterValue);
formitem.filteredItems = formitem.filteredItems.concat(selectedFilteredItemsModel);
scope.model[k] = generator.get_diff_array(scope.model[k] || [], formitem.dataToModel(selectedFilteredItemsModel));
},
dataToModel: function (data) {
var dataValues = [];
angular.forEach(data, function (value, key) {
var dataKey = {};
dataKey[v.schema[0].name] = value.value;
dataValues.push(dataKey);
});
return dataValues;
}
};
scope.form[scope.form.indexOf(k)] = formitem;
}); };
// generate_fields covers all field types as functions
var generate_fields = {
button: {default: _buttons},
submit: {default: _buttons},
file: {
default: function (scope, v, k) {
scope.form[scope.form.indexOf(k)] = {
type: "template",
title: v.title,
templateUrl: "shared/templates/filefield.html",
name: k,
key: k,
fileInsert: function () {
$scope.$broadcast('schemaForm.error.' + k, 'tv4-302', true);
},
imageSrc: scope.model[k] ? $rootScope.settings.static_url + scope.model[k] : '',
avatar: k === 'avatar'
};
v.type = 'string';
}
},
select: {
default: function (scope, v, k) {
scope.form[scope.form.indexOf(k)] = {
type: "template",
title: v.title,
templateUrl: "shared/templates/select.html",
name: k,
key: k,
titleMap: v.titleMap
};
}
},
confirm: {
default: function (scope, v, k) {
scope.form[scope.form.indexOf(k)] = {
type: "template",
title: v.title,
confirm_message: v.confirm_message,
templateUrl: "shared/templates/confirm.html",
name: k,
key: k,
style: v.style,
buttons: v.buttons,
modalInstance: "",
// buttons is an object array
//Example:
//buttons: [{
// text: "Button text",
// cmd: "button command",
// style: "btn-warning",
// dismiss: false --> this one is for deciding if the button can dismiss modal
//}]
modalFunction: function(){
delete scope.form_params.cmd;
delete scope.form_params.flow;
if (v.cmd) {
scope.form_params["cmd"] = v.cmd;
}
if (v.flow) {
scope.form_params["flow"] = v.flow;
}
if (v.wf) {
delete scope.form_params["cmd"];
scope.form_params["wf"] = v.wf;
}
$timeout(function () { var modalInstance = $uibModal.open({
if (v.type === 'ListNode') { animation: true,
scope[v.type][k].items = angular.copy(scope.model[k] || []); templateUrl: 'shared/templates/confirmModalContent.html',
angular.forEach(scope[v.type][k].items, function (value, key) { controller: 'ModalController',
if (value.constructor === Object) { resolve: {
angular.forEach(value, function (x, y) { items: function(){
try { var newscope = {
if (scope[v.type][k].schema.properties[y].type === 'date') { form: {
scope[v.type][k].items[key][y] = generator.dateformatter(x); title: v.title,
scope[v.type][k].model[key][y] = generator.dateformatter(x); confirm_message: v.confirm_message,
} buttons: v.buttons,
if (scope[v.type][k].schema.properties[y].type === 'select') { onClick: function (cmd) {
scope[v.type][k].items[key][y] = generator.item_from_array(x.toString(), scope[v.type][k].schema.properties[y].titleMap) // send cmd with submit
modalInstance.dismiss();
if (cmd) generator.submit(scope, false);
}
}
};
return newscope;
}
}
});
},
openModal: function(){
var workOnForm = scope.modalElements ? scope.modalElements.workOnForm : 'formgenerated';
if (!v.form_validate && angular.isDefined(v.form_validate)){
this.modalFunction();
}
else{
scope.$broadcast('schemaFormValidate');
if (scope[workOnForm].$valid) {
this.modalFunction();
} else {
// focus to first input with validation error
$timeout(function () {
var firsterror = angular.element(document.querySelectorAll('input.ng-invalid'))[0];
firsterror.focus();
});
}
}
}
};
}
},
date: {
default: function (scope, v, k) {
$log.debug('date:', scope.model[k]);
scope.model[k] = generator.dateformatter(scope.model[k]);
scope.form[scope.form.indexOf(k)] = {
key: k, name: k, title: v.title,
type: 'template',
templateUrl: 'shared/templates/datefield.html',
validationMessage: {
'dateNotValid': "Girdiğiniz tarih geçerli değildir. <i>orn: '01.01.2015'<i/>",
302: 'Bu alan zorunludur.'
},
$asyncValidators: {
'dateNotValid': function (value) {
var deferred = $q.defer();
$timeout(function () {
scope.model[k] = angular.copy(generator.dateformatter(value));
if (scope.schema.required.indexOf(k) > -1) {
deferred.resolve();
}
if (value.constructor === Date) {
deferred.resolve();
}
else {
var dateValue = d = value.split('.');
if (isNaN(Date.parse(value)) || dateValue.length !== 3) {
deferred.reject();
} else {
deferred.resolve();
} }
} catch (e) {
$log.debug('Field is not date');
} }
}); });
return deferred.promise;
} }
},
disabled: false,
is_disabled: function () {
return this.disabled;
},
status: {opened: false},
open: function ($event) {
this.disabled = true;
// scope.$apply();
scope.model[k] = Moment(scope.model[k], "DD.MM.YYYY").toDate();
var that = this;
$timeout(function () {
that.status.opened = true;
}, 100);
},
format: 'dd.MM.yyyy',
onSelect: function () {
this.disabled = false;
scope.model[k] = angular.copy(generator.dateformatter(scope.model[k]));
}
};
}
},
int: {default: _numbers},
boolean: {
default: function (scope, v, k) {
}
},
string: {
default: function (scope, v, k) {
}
},
typeahead: {
default: function (scope, v, k) {
scope.form[scope.form.indexOf(k)] = {
type: "template",
title: v.title,
titleMap: v.titleMap,
templateUrl: "shared/templates/typeahead.html",
name: k,
key: k,
onDropdownSelect: function (item, inputname) {
scope.model[k] = item.value;
$timeout(function () {
document.querySelector('input[name=' + inputname + ']').value = item.name;
});
}
};
v.type = 'string';
},
custom: function (scope, v, k) {
scope.form[scope.form.indexOf(k)] = {
type: "template",
title: v.title,
widget: v.widget,
getTitleMap: function (viewValue) {
// v.view is where that value will looked up
var searchData = {
"form_params": {
"url": v.wf,
"wf": v.wf,
"view": v.view,
"query": viewValue
}
};
generator.get_list(searchData).then(function (res) {
// response must be in titleMap format
return res;
});
},
templateUrl: "shared/templates/typeahead.html",
name: k,
key: k,
onDropdownSelect: function (item, inputname) {
scope.model[k] = item.value;
$timeout(function () {
document.querySelector('input[name=' + inputname + ']').value = item.name;
});
}
};
v.type = 'string';
}
},
text_general: {
default: function (scope, v, k) {
v.type = 'string',
v["x-schema-form"] = {
"type": "textarea"
}
}
},
float: {default: _numbers},
model: {
default: function (scope, v, k) {
var formitem = scope.form[scope.form.indexOf(k)];
var modelScope = {
"url": v.wf,
"wf": v.wf,
"form_params": {wf: v.wf, model: v.model_name, cmd: v.list_cmd}
};
//scope.$on('refreshTitleMap', function (event, data) {
// todo: write a function to refresh titleMap after new item add to linkedModel
//});
var generateTitleMap = function (modelScope) {
return generator.get_list(modelScope).then(function (res) {
formitem.titleMap = [];
angular.forEach(res.objects, function (item) {
if (item !== -1) {
formitem.titleMap.push({
"value": item.key,
"name": item.value
});
} else {
formitem.focusToInput = true;
}
});
return formitem.titleMap;
}); });
} };
});
if (scope.model[k]) { formitem = {
angular.forEach(scope.model[k], function (value, key) { type: "template",
angular.forEach(value, function (y, x) { templateUrl: "shared/templates/foreignKey.html",
if (y.constructor === Object) { // formName will be used in modal return to save item on form
scope.model[k][key][x] = y.key; formName: k,
title: v.title,
wf: v.wf,
add_cmd: v.add_cmd,
name: k,
key: k,
model_name: v.model_name,
selected_item: {},
titleMap: [],
onSelect: function (item, inputname) {
scope.model[k] = item.value;
$timeout(function () {
document.querySelector('input[name=' + inputname + ']').value = item.name;
});
},
onDropdownSelect: function (item, inputname) {
scope.model[k] = item.value;
$timeout(function () {
document.querySelector('input[name=' + inputname + ']').value = item.name;
});
},
getTitleMap: function (viewValue) {
modelScope.form_params.query = viewValue;
return generateTitleMap(modelScope);
},
getDropdownTitleMap: function () {
delete modelScope.form_params.query;
formitem.gettingTitleMap = true;
generateTitleMap(modelScope)
.then(function (data) {
formitem.titleMap = data;
formitem.gettingTitleMap = false;
});
}
};
scope.form[scope.form.indexOf(k)] = formitem;
// get selected item from titleMap using model value
if (scope.model[k]) {
generator.get_list({
url: 'crud',
form_params: {
wf: v.wf,
model: v.model_name,
object_id: scope.model[k],
cmd: 'object_name'
} }
}); }).then(function (data) {
});
}
scope.model[k] = scope.model[k] || []; try {
$timeout(function () {
document.querySelector('input[name=' + k + ']').value = data.object_name;
}, 200);
scope[v.type][k].model = scope.model[k]; }
catch (e) {
document.querySelector('input[name=' + k + ']').value = data.object_name;
$log.debug('exception', e);
}
// lengthModels is length of the listnode models. if greater than 0 show records on template });
scope[v.type][k]['lengthModels'] = scope.model[k] ? 1 : 0; }
}
},
Node: {
default: _node_default,
filter_interface: _node_filter_interface
},
ListNode: {
default: _node_default,
filter_interface: _node_filter_interface
}
};
// todo: delete after constraints done
// scope.forms = scope.forms || {};
// scope.forms.constraints = {
// "cinsiyet": {
// "cons": "selectbox_fields",
// "val":
// {'1': ["kiz_kardes_sayisi"], '2': ["erkek_kardes_sayisi"]},
// "val_msg": "Erkek kardes sayisi kiz kardes sayisindan az olamaz."
// }
// };
angular.forEach(scope.schema.properties, function (v, k) {
// generically change _id fields model value
if ('form_params' in scope) {
if (k == scope.form_params.param) {
scope.model[k] = scope.form_params.id;
scope.form.splice(scope.form.indexOf(k), 1);
return;
}
}
try {
generate_fields[v.type][v.widget || 'default'](scope, v, k);
}
catch (e) {
// todo: raise not implemented
console.log(v.type)
} }
}); });
$log.debug('scope at after prepareformitems', scope); $log.debug('scope at after prepareformitems', scope);
return generator.group(scope); generator.constraints(scope);
}; };
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
...@@ -698,30 +1007,61 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -698,30 +1007,61 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @returns {*} * @returns {*}
*/ */
generator.doItemAction = function ($scope, key, todo, mode) { generator.doItemAction = function ($scope, key, todo, mode) {
$scope.form_params.cmd = todo.cmd;
$scope.form_params.wf = $scope.wf;
if (todo.wf) {
$scope.url = todo.wf;
$scope.form_params.wf = todo.wf;
delete $scope.token;
delete $scope.form_params.model;
delete $scope.form_params.cmd
}
if (todo.object_key) {
$scope.form_params[todo.object_key] = key;
} else {
$scope.form_params.object_id = key;
}
$scope.form_params.param = $scope.param;
$scope.form_params.id = $scope.param_id;
$scope.form_params.token = $scope.token;
var _do = { var _do = {
normal: function () { normal: function () {
$log.debug('normal mode starts'); $log.debug('normal mode starts');
$scope.form_params.cmd = todo.cmd;
if (todo.wf) {
$scope.url = todo.wf;
$scope.form_params.wf = todo.wf;
delete $scope.token;
delete $scope.form_params.model;
delete $scope.form_params.cmd
}
if (todo.object_key) {
$scope.form_params[todo.object_key] = key;
} else {
$scope.form_params.object_id = key;
}
$scope.form_params.param = $scope.param;
$scope.form_params.id = $scope.param_id;
$scope.form_params.token = $scope.token;
return generator.get_wf($scope); return generator.get_wf($scope);
}, },
modal: function () { modal: function () {
$log.debug('modal mode is not not ready'); $log.debug('modal mode starts');
var modalInstance = $uibModal.open({
animation: true,
backdrop: 'static',
keyboard: false,
templateUrl: 'shared/templates/confirmModalContent.html',
controller: 'ModalController',
size: '',
resolve: {
items: function () {
var newscope = {
form: {
buttons: [ { text: "Evet", style: "btn-success", cmd:"confirm" }, { text: "Hayir", "style": "btn-warning", dismiss: true } ],
title: todo.name,
confirm_message: "Islemi onayliyor musunuz?",
onClick: function(cmd){
modalInstance.close();
if (cmd === "confirm" && angular.isDefined(cmd)) {
modalInstance.close();
return generator.get_wf($scope);
}
}
}
}
return newscope;
}
}
});
}, },
new: function () { new: function () {
$log.debug('new mode is not not ready'); $log.debug('new mode is not not ready');
...@@ -736,6 +1076,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -736,6 +1076,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @description Changes html disabled and enabled attributes of all buttons on current page. * @description Changes html disabled and enabled attributes of all buttons on current page.
* @param {boolean} position * @param {boolean} position
*/ */
// todo: remove
generator.button_switch = function (position) { generator.button_switch = function (position) {
var buttons = angular.element(document.querySelectorAll('button')); var buttons = angular.element(document.querySelectorAll('button'));
var positions = {true: "enabled", false: "disabled"}; var positions = {true: "enabled", false: "disabled"};
...@@ -743,7 +1084,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -743,7 +1084,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
button[positions[position]] = true; button[positions[position]] = true;
}); });
$log.debug('buttons >> ', positions[position]) $log.debug('buttons >> ', positions[position])
} };
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
* @ngdoc function * @ngdoc function
...@@ -753,13 +1094,16 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -753,13 +1094,16 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @returns {*} * @returns {*}
*/ */
generator.get_form = function (scope) { generator.get_form = function (scope) {
generator.button_switch(false); if ($rootScope.websocketIsOpen === true) {
return $http return WSOps.request(scope.form_params)
.post(generator.makeUrl(scope), scope.form_params) .then(function (data) {
.then(function (res) { return generator.generate(scope, data);
generator.button_switch(true); });
return generator.generate(scope, res.data); } else {
}); $timeout(function () {
generator.get_form(scope);
}, 500);
}
}; };
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
...@@ -770,13 +1114,17 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -770,13 +1114,17 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @returns {*} * @returns {*}
*/ */
generator.get_list = function (scope) { generator.get_list = function (scope) {
generator.button_switch(false);
return $http if ($rootScope.websocketIsOpen === true) {
.post(generator.makeUrl(scope), scope.form_params) return WSOps.request(scope.form_params)
.then(function (res) { .then(function (data) {
generator.button_switch(true); return data;
return res; });
}); } else {
$timeout(function () {
generator.get_list(scope);
}, 500);
}
}; };
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
...@@ -788,59 +1136,19 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -788,59 +1136,19 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @returns {*} * @returns {*}
*/ */
generator.get_wf = function (scope) { generator.get_wf = function (scope) {
generator.button_switch(false); // todo: remove this condition
return $http if ($rootScope.websocketIsOpen === true) {
.post(generator.makeUrl(scope), scope.form_params) WSOps.request(scope.form_params)
.then(function (res) { .then(function (data) {
generator.button_switch(true); return generator.pathDecider(data.client_cmd || ['list'], scope, data);
if (res.data.client_cmd) { });
return generator.pathDecider(res.data.client_cmd, scope, res.data); } else {
} $timeout(function () {
if (res.data.msgbox) { // todo: loop restrict listen ws open
scope.msgbox = res.data.msgbox; generator.get_wf(scope);
var newElement = $compile("<msgbox></msgbox>")(scope); }, 500);
// this is the default action, which is removing page items and reload page with msgbox }
angular.element(document.querySelector('.main.ng-scope')).children().remove();
angular.element(document.querySelector('.main.ng-scope')).append(newElement);
}
});
};
/**
* @memberof ulakbus.formService
* @ngdoc function
* @name isValidEmail
* @description checks if given value is a valid email address.
* @param email
* @returns {boolean}
*/
generator.isValidEmail = function (email) {
var re = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
return re.test(email);
};
/**
* @memberof ulakbus.formService
* @ngdoc function
* @name isValidTCNo
* @description checks if given value is a valid identity number for Turkey.
* @param tcno
* @returns {boolean}
*/
generator.isValidTCNo = function (tcno) {
var re = /^([1-9]{1}[0-9]{9}[0,2,4,6,8]{1})$/i;
return re.test(tcno);
};
/**
* @memberof ulakbus.formService
* @ngdoc function
* @name isValidDate
* @description checks if given value can be parsed as Date object
* @param dateValue
* @returns {boolean}
*/
generator.isValidDate = function (dateValue) {
return !isNaN(Date.parse(dateValue));
}; };
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
* @ngdoc property * @ngdoc property
...@@ -856,8 +1164,6 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -856,8 +1164,6 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
generator.setPageData = function (value) { generator.setPageData = function (value) {
generator.pageData = value; generator.pageData = value;
}; };
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
* @ngdoc function * @ngdoc function
...@@ -868,10 +1174,11 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -868,10 +1174,11 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @param {Object} data * @param {Object} data
*/ */
generator.pathDecider = function (client_cmd, $scope, data) { generator.pathDecider = function (client_cmd, $scope, data) {
if (client_cmd[0] === 'reload' || client_cmd[0] === 'reset') { //if (client_cmd[0] === 'reload' || client_cmd[0] === 'reset') {
$rootScope.$broadcast('reload_cmd', $scope.reload_cmd); // $rootScope.$broadcast('reload_cmd', $scope.reload_cmd);
return; // //return;
} //}
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
* @ngdoc function * @ngdoc function
...@@ -916,7 +1223,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -916,7 +1223,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
data['param'] = $scope.form_params.param; data['param'] = $scope.form_params.param;
data['param_id'] = $scope.form_params.id; data['param_id'] = $scope.form_params.id;
data['pageData'] = true; data['pageData'] = true;
data['second_client_cmd'] = client_cmd[1]; //data['second_client_cmd'] = client_cmd[1];
generator.setPageData(data); generator.setPageData(data);
redirectTo($scope, client_cmd[0]); redirectTo($scope, client_cmd[0]);
...@@ -924,7 +1231,6 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -924,7 +1231,6 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
dispatchClientCmd(); dispatchClientCmd();
}; };
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
* @ngdoc function * @ngdoc function
...@@ -1032,11 +1338,11 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1032,11 +1338,11 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* *
* @param {Object} $scope * @param {Object} $scope
* @param {Object} redirectTo * @param {Object} redirectTo
* @param {Boolean} dontProcessReply - used in modal forms
* @returns {*} * @returns {*}
* @todo diff for all submits to recognize form change. if no change returns to view with no submit * @todo diff for all submits to recognize form change. if no change returns to view with no submit
*/ */
generator.submit = function ($scope, redirectTo) { generator.submit = function ($scope, redirectTo, dontProcessReply) {
/** /**
* In case of unformatted date object in any key recursively, it must be converted. * In case of unformatted date object in any key recursively, it must be converted.
* @param model * @param model
...@@ -1046,7 +1352,9 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1046,7 +1352,9 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
if (value && value.constructor === Date) { if (value && value.constructor === Date) {
model[key] = generator.dateformatter(value); model[key] = generator.dateformatter(value);
} }
if (value && value.constructor === Object) {convertDate(value);} if (value && value.constructor === Object) {
convertDate(value);
}
}); });
}; };
...@@ -1056,10 +1364,13 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1056,10 +1364,13 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
angular.forEach($scope.Node, function (value, key) { angular.forEach($scope.Node, function (value, key) {
$scope.model[key] = value.model; $scope.model[key] = value.model;
}); });
var data = { // todo: unused var delete
var send_data = {
"form": $scope.model, "form": $scope.model,
"object_key": $scope.object_key,
"token": $scope.token, "token": $scope.token,
"model": $scope.form_params.model, "model": $scope.form_params.model,
"wf": $scope.form_params.wf,
"cmd": $scope.form_params.cmd, "cmd": $scope.form_params.cmd,
"flow": $scope.form_params.flow, "flow": $scope.form_params.flow,
"object_id": $scope.object_id, "object_id": $scope.object_id,
...@@ -1067,32 +1378,19 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1067,32 +1378,19 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
"query": $scope.form_params.query "query": $scope.form_params.query
}; };
return $http.post(generator.makeUrl($scope), data) if ($rootScope.websocketIsOpen === true) {
.success(function (data, status, headers) { return WSOps.request(send_data)
if (headers('content-type') === "application/pdf") { .then(function (data) {
var a = document.createElement("a"); if (!dontProcessReply){
document.body.appendChild(a); return generator.pathDecider(data.client_cmd || ['list'], $scope, data);
a.style = "display: none";
var file = new Blob([data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
var fileName = $scope.schema.title;
a.href = fileURL;
a.download = fileName;
a.click();
}
if (redirectTo === true) {
if (data.client_cmd) {
generator.pathDecider(data.client_cmd, $scope, data);
}
if (data.msgbox) {
$scope.msgbox = data.msgbox;
var newElement = $compile("<msgbox></msgbox>")($scope);
// this is the default action, which is removing page items and reload page with msgbox
angular.element(document.querySelector('.main.ng-scope')).children().remove();
angular.element(document.querySelector('.main.ng-scope')).append(newElement);
} }
} return data;
}); });
} else {
$timeout(function () {
generator.scope($scope, redirectTo);
}, 500);
}
}; };
return generator; return generator;
}) })
...@@ -1100,7 +1398,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1100,7 +1398,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
/** /**
* @memberof ulakbus.formService * @memberof ulakbus.formService
* @ngdoc controller * @ngdoc controller
* @name ModalCtrl * @name ModalController
* @description controller for listnode, node and linkedmodel modal and save data of it * @description controller for listnode, node and linkedmodel modal and save data of it
* @param {Object} items * @param {Object} items
* @param {Object} $scope * @param {Object} $scope
...@@ -1108,7 +1406,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1108,7 +1406,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @param {Object} $route * @param {Object} $route
* @returns {Object} returns value for modal * @returns {Object} returns value for modal
*/ */
.controller('ModalCtrl', function ($scope, $uibModalInstance, Generator, items) { .controller('ModalController', function ($scope, $uibModalInstance, Generator, items, $timeout, Utils) {
angular.forEach(items, function (value, key) { angular.forEach(items, function (value, key) {
$scope[key] = items[key]; $scope[key] = items[key];
}); });
...@@ -1118,6 +1416,17 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1118,6 +1416,17 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
}); });
$scope.$on('modalFormLocator', function (event) { $scope.$on('modalFormLocator', function (event) {
// fix default model with unicode assign
$timeout(function () {
Utils.iterate($scope.model, function(modelValue, k){
if (angular.isUndefined($scope.edit)) return;
var unicode = $scope.items[$scope.edit][k].unicode;
if (unicode){
document.querySelector('input[name=' + k + ']').value = unicode;
}
})
});
$scope.linkedModelForm = event.targetScope.linkedModelForm; $scope.linkedModelForm = event.targetScope.linkedModelForm;
}); });
...@@ -1159,7 +1468,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1159,7 +1468,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
* @returns {Object} openmodal directive * @returns {Object} openmodal directive
*/ */
.directive('modalForNodes', function ($uibModal, Generator) { .directive('modalForNodes', function ($uibModal, Generator, Utils) {
return { return {
link: function (scope, element, attributes) { link: function (scope, element, attributes) {
element.on('click', function () { element.on('click', function () {
...@@ -1168,7 +1477,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1168,7 +1477,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
backdrop: 'static', backdrop: 'static',
keyboard: false, keyboard: false,
templateUrl: 'shared/templates/listnodeModalContent.html', templateUrl: 'shared/templates/listnodeModalContent.html',
controller: 'ModalCtrl', controller: 'ModalController',
size: 'lg', size: 'lg',
resolve: { resolve: {
items: function () { items: function () {
...@@ -1191,10 +1500,19 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1191,10 +1500,19 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
scope.node.schema.wf = scope.node.url; scope.node.schema.wf = scope.node.url;
angular.forEach(scope.node.schema.properties, function (value, key) { angular.forEach(scope.node.schema.properties, function (value, key) {
scope.node.schema.properties[key].wf = scope.node.url; if (angular.isDefined(scope.node.schema.properties[key].wf)) {
}
else {
scope.node.schema.properties[key].wf = scope.node.url;
}
scope.node.schema.properties[key].list_cmd = 'select_list'; scope.node.schema.properties[key].list_cmd = 'select_list';
}); });
// scope.node.schema.footerButtons = [
// {type: "submit", text:"Onayla", style:"btn-success" },
// {type: "button", text:"Vazgec", style:"btn-danger" },
// ]
var newscope = { var newscope = {
wf: scope.node.wf, wf: scope.node.wf,
url: scope.node.url, url: scope.node.url,
...@@ -1204,7 +1522,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1204,7 +1522,7 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
Generator.generate(newscope, {forms: scope.node}); Generator.generate(newscope, {forms: scope.node});
// modal will add only one item to listNode, so just need one model (not array) // modal will add only one item to listNode, so just need one model (not array)
newscope.model = newscope.model[node.edit] || newscope.model[0] || {}; newscope.model = newscope.model[node.edit] || {};
return newscope; return newscope;
} }
} }
...@@ -1223,19 +1541,30 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1223,19 +1541,30 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
var reformattedModel = {}; var reformattedModel = {};
angular.forEach(childmodel.model, function (value, key) { angular.forEach(childmodel.model, function (value, key) {
if (key.indexOf('_id') > -1) { if (key.indexOf('_id') > -1) {
// todo: understand why we got object here!
// hack to fix bug with value as object
if (angular.isObject(value) && value.value){
value = value.value;
childmodel.model[key] = value;
}
angular.forEach(childmodel.form, function (v, k) { angular.forEach(childmodel.form, function (v, k) {
if (v.formName === key) { if (v.formName === key) {
//if (!childmodel.model[key].key) { //if (!childmodel.model[key].key) {
function indexInTitleMap(element, index, array) { var unicodeValue = v.titleMap.find(function (element, index, array) {
if (element['value'] === value) { if (element['value'] === value) {
return element; return element;
} }
});
if (unicodeValue){
unicodeValue = unicodeValue.name;
reformattedModel[key] = {
"key": value,
"unicode": unicodeValue
}
} }
reformattedModel[key] = {
"key": value,
"unicode": v.titleMap.find(indexInTitleMap).name
};
//} //}
} }
}); });
...@@ -1290,15 +1619,17 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1290,15 +1619,17 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
backdrop: 'static', backdrop: 'static',
keyboard: false, keyboard: false,
templateUrl: 'shared/templates/linkedModelModalContent.html', templateUrl: 'shared/templates/linkedModelModalContent.html',
controller: 'ModalCtrl', controller: 'ModalController',
size: 'lg', size: 'lg',
resolve: { resolve: {
items: function () { items: function () {
var formName = attributes.addModalForLinkedModel; var formName = attributes.addModalForLinkedModel;
return Generator.get_form({ return Generator.get_form({
url: scope.form.wf, form_params: {
wf: scope.form.wf, wf: scope.form.wf,
form_params: {model: scope.form.model_name, cmd: scope.form.add_cmd}, model: scope.form.model_name,
cmd: scope.form.add_cmd
},
modalElements: { modalElements: {
// define button position properties // define button position properties
buttonPositions: { buttonPositions: {
...@@ -1323,27 +1654,18 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1323,27 +1654,18 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
modalInstance.result.then(function (childscope, key) { modalInstance.result.then(function (childscope, key) {
var formName = childscope.formName; var formName = childscope.formName;
Generator.submit(childscope, false) Generator.submit(childscope, false, true).then(
.success(function (data) { function (data) {
// response data contains object_id and unicode // response data contains object_id and unicode
// scope.model can be reached via prototype chain // scope.form can be reached via prototype chain
scope.model[formName] = data.forms.model.object_key; var item = {
// scope.form prototype chain returns this form item
scope.form.titleMap.push({
value: data.forms.model.object_key,
name: data.forms.model.unicode
});
scope.form.selected_item = {
value: data.forms.model.object_key, value: data.forms.model.object_key,
name: data.forms.model.unicode name: data.forms.model.unicode
}; };
scope.$watch(document.querySelector('input[name=' + scope.form.model_name + ']'), scope.form.titleMap.push(item);
function () { scope.form.onSelect(item, formName);
angular.element(document.querySelector('input[name=' + scope.form.model_name + ']')).val(scope.form.selected_item.name);
}
);
}); });
//$route.reload();
}); });
}); });
} }
...@@ -1363,4 +1685,4 @@ angular.module('ulakbus.formService', ['ui.bootstrap']) ...@@ -1363,4 +1685,4 @@ angular.module('ulakbus.formService', ['ui.bootstrap'])
scope.$emit('modalFormLocator'); scope.$emit('modalFormLocator');
} }
} }
}); });
\ No newline at end of file
...@@ -301,82 +301,83 @@ describe('form service module', function () { ...@@ -301,82 +301,83 @@ describe('form service module', function () {
}) })
); );
it('should validate email', //it('should validate email',
inject(function (Generator) { // inject(function (Generator) {
var validEmails = [ // var validEmails = [
'test@test.com', // 'test@test.com',
'test@test.co.uk', // 'test@test.co.uk',
'test734ltylytkliytkryety9ef@jb-fe.com' // 'test734ltylytkliytkryety9ef@jb-fe.com'
]; // ];
//
var invalidEmails = [ // var invalidEmails = [
'test@testcom', // 'test@testcom',
'test@ test.co.uk', // 'test@ test.co.uk',
'ghgf@fe.com.co.', // 'ghgf@fe.com.co.',
'tes@t@test.com', // 'tes@t@test.com',
'' // ''
]; // ];
//
for (var i in validEmails) { // for (var i in validEmails) {
var valid = Generator.isValidEmail(validEmails[i]); // var valid = Generator.isValidEmail(validEmails[i]);
expect(valid).toBeTruthy(); // expect(valid).toBeTruthy();
} // }
for (var i in invalidEmails) { // for (var i in invalidEmails) {
var valid = Generator.isValidEmail(invalidEmails[i]); // var valid = Generator.isValidEmail(invalidEmails[i]);
expect(valid).toBeFalsy(); // expect(valid).toBeFalsy();
} // }
}) // })
); //);
//
it('should validate tcNo', //it('should validate tcNo',
inject(function (Generator) { // inject(function (Generator) {
var validTCNos = [ // var validTCNos = [
'12345678902', // '12345678902',
'18307990654' // '18307990654'
]; // ];
//
var invalidTCNos = [ // var invalidTCNos = [
'00000000000', // '00000000000',
'00000000002', // '00000000002',
'12345678901', // '12345678901',
'1234567892', // '1234567892',
'' // ''
]; // ];
//
for (var i in validTCNos) { // for (var i in validTCNos) {
var valid = Generator.isValidTCNo(validTCNos[i]); // var valid = Generator.isValidTCNo(validTCNos[i]);
expect(valid).toBeTruthy(); // expect(valid).toBeTruthy();
} // }
for (var i in invalidTCNos) { // for (var i in invalidTCNos) {
var valid = Generator.isValidTCNo(invalidTCNos[i]); // var valid = Generator.isValidTCNo(invalidTCNos[i]);
expect(valid).toBeFalsy(); // expect(valid).toBeFalsy();
} // }
}) // })
); //);
//
it('should validate date', //it('should validate date',
inject(function (Generator) { // inject(function (Generator) {
var validDates = [ // var validDates = [
'12/12/2012' // '12.12.2012'
]; // ];
//
var invalidDates = [ // var invalidDates = [
'dsad', // 'dsad',
'0.0.0', // '0.0.0',
'12.15.2012', // '15/12/2012',
'' // ''
]; // ];
//
for (var i in validDates) { // for (var i in validDates) {
var valid = Generator.isValidDate(validDates[i]); // var valid = Generator.isValidDate(validDates[i]);
expect(valid).toBeTruthy(); //
} // expect(valid).toBeTruthy();
for (var i in invalidDates) { // }
var valid = Generator.isValidDate(invalidDates[i]); // for (var j in invalidDates) {
expect(valid).toBeFalsy(); // var notValid = Generator.isValidDate(invalidDates[j]);
} // expect(notValid).toBeFalsy();
}) // }
); // })
//);
it('should get wf and redirect according to client_cmd', it('should get wf and redirect according to client_cmd',
inject(function (Generator, $httpBackend, RESTURL) { inject(function (Generator, $httpBackend, RESTURL) {
...@@ -431,24 +432,6 @@ describe('form service module', function () { ...@@ -431,24 +432,6 @@ describe('form service module', function () {
}) })
); );
it('should get wf and put msgbox to scope',
inject(function (Generator, $httpBackend, RESTURL) {
scope.form_params = {};
$httpBackend.expectPOST(RESTURL.url + 'testmsgbox')
.respond(200, {
"msgbox": "test message"
});
scope.url = 'testmsgbox';
Generator.get_wf(scope);
$httpBackend.flush();
expect(scope.msgbox).toEqual("test message");
})
);
it('doItemAction should do given action', it('doItemAction should do given action',
inject(function (Generator, $httpBackend, RESTURL) { inject(function (Generator, $httpBackend, RESTURL) {
$httpBackend.expectPOST(RESTURL.url + 'otherwf') $httpBackend.expectPOST(RESTURL.url + 'otherwf')
......
...@@ -21,7 +21,7 @@ angular.module('ulakbus') ...@@ -21,7 +21,7 @@ angular.module('ulakbus')
* - API returns `is_login` key to check if current user is authenticated. Interceptor checks and if not logged * - API returns `is_login` key to check if current user is authenticated. Interceptor checks and if not logged
* in redirects to login page. * in redirects to login page.
*/ */
$httpProvider.interceptors.push(function ($q, $rootScope, $location, $timeout, $log) { $httpProvider.interceptors.push(function (ErrorService, $q, $rootScope, $location, $timeout, $log, toastr) {
return { return {
'request': function (config) { 'request': function (config) {
if (config.method === "POST") { if (config.method === "POST") {
...@@ -55,98 +55,15 @@ angular.module('ulakbus') ...@@ -55,98 +55,15 @@ angular.module('ulakbus')
} }
} }
// if (response.data.client_cmd) { // handle toast notifications here
//$location.path(response.data.screen);
// } if (response.data.notify) {toastr.info(response.data.notify)}
return response; return response;
}, },
'responseError': function (rejection) { 'responseError': function (rejection) {
ErrorService.handle(rejection, 'http');
var errorModal = function () {
if ($rootScope.loginAttempt === 0) {
$log.debug('not logged in, no alert message triggered');
return;
}
var codefield = "";
if (rejection.data.error) {
codefield = '<p><pre>' +
rejection.data.error +
'</pre></p>';
}
$('<div class="modal">' +
'<div class="modal-dialog" style="width:100%;" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span' +
' aria-hidden="true">&times;</span></button>' +
'<h4 class="modal-title" id="exampleModalLabel">' +
rejection.status + rejection.data.title +
'</h4>' +
'</div>' +
'<div class="modal-body">' +
'<div class="alert alert-danger">' +
'<strong>' +
rejection.data.description +
'</strong>' +
codefield +
'</div>' +
'</div>' +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-default" data-dismiss="modal">Kapat</button>' +
'</div>' +
'</div>' +
'</div>' +
'</div>').modal();
try {
$('pre:not(.hljs)').each(function (i, block) {
hljs.highlightBlock(block);
});
}
catch (e) {
$log.debug('Exception: ', e.message);
}
};
if (rejection.status === -1) {
rejection.status = 'Sunucu hatası'
rejection.data = {
title: "", description: 'Sunucu bağlantısında bir hata oluştu.' +
'Lütfen yetkili personelle iletişime geçiniz.'
};
$rootScope.$broadcast('alertBox', {
title: rejection.status,
msg: rejection.data.description,
type: 'error'
});
}
if (rejection.status === 400) {
$location.reload();
}
if (rejection.status === 401) {
$location.path('/login');
if ($location.path() === "/login") {
$log.debug("show errors on login form");
}
}
if (rejection.status === 403) {
if (rejection.data.is_login === true) {
$rootScope.loggedInUser = true;
if ($location.path() === "/login") {
$location.path("/dashboard");
}
}
//errorModal();
}
$rootScope.$broadcast('show_notifications', rejection.data);
if (rejection.status === 404) {
errorModal();
}
if (rejection.status === 500) {
errorModal();
}
return $q.reject(rejection); return $q.reject(rejection);
} }
}; };
......
/**
* @license Ulakbus-UI
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*/
//'use strict';
describe('interceptor module', function () {
beforeEach(module('ulakbus'));
var $httpBackend, $rootScope;
beforeEach(inject(function ($injector) {
$httpBackend = $injector.get('$httpBackend');
$rootScope = $injector.get('$rootScope');
}));
describe('http interceptor', function () {
it('should handle errors properly', inject(function ($http, $rootScope, RESTURL) {
this.statuses = [-1, 404, 500];
angular.forEach(this.statuses, function (value, key) {
var resp = {data: {title: 'test', description: 'test', is_login: true}};
//if (modal) { resp.data.error = 'some error'; }
$httpBackend.expectGET(RESTURL.url + 'testforerror').respond(value, resp);
var listener = jasmine.createSpy('listener');
$rootScope.$on('alertBox', listener);
$http.get(RESTURL.url + 'testforerror').error(function (data) {
expect(listener).toHaveBeenCalled();
});
$httpBackend.flush();
});
var resp2 = {data: {title: 'test', description: 'test', is_login: true, error: 'test error'}};
$httpBackend.expectGET(RESTURL.url + 'testforerror2').respond(500, resp2);
var listener2 = jasmine.createSpy('listener2');
$rootScope.$on('alertBox', listener2);
$http.get(RESTURL.url + 'testforerror2').error(function (data) {
expect(listener2).toHaveBeenCalled();
});
$httpBackend.flush();
var resp3 = {is_login: true, _debug_queries: [{query: ''}]};
$httpBackend.expectGET(RESTURL.url + 'testforerror3').respond(200, resp3);
$http.get(RESTURL.url + 'testforerror3').success(function (data) {
expect($rootScope.debug_queries[0].queries).toEqual([{query: ''}]);
});
$httpBackend.flush();
}));
});
});
\ No newline at end of file
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Evren Kutar
*/
angular.module('ulakbus')
/**
* WSUri returns websocket uri
*/
.service('WSUri', function (RESTURL) {
var base = RESTURL.url.replace('http', 'ws');
return {url: base + 'ws'}
})
/**
* WSOps operates all websocket interactions
*/
.factory('WSOps', function (WSUri, $q, $log, $rootScope, $timeout, $document, ErrorService, WS, IsOnline, DevSettings) {
$rootScope.$on('ws_turn_on', function () {
generate_ws();
});
// websocket object
var websocket;
// when websocket tries to reconnect it counts
var refresh_count = 0;
// an interval integer in miliseconds depending on refresh_count
var refresh_websocket = refresh_count < 5 ? 1000 : 5000;
// check and return if browser supports websocket
var isSupported = function () {
return "WebSocket" in window;
};
/**
* generate_ws generates web socket with necessary functions to configure
*/
var generate_ws = function () {
if (isSupported()) {
$log.info('Openning web socket...');
websocket = new WS(WSUri.url);
websocket.onopen = function (evt) {
wsOps.onOpen(evt);
refresh_count = 0;
};
websocket.onclose = function (evt) {
wsOps.onClose(evt);
if (wsOps.loggedOut === true) {
return;
}
$timeout(function () {
generate_ws();
refresh_count += 1;
}, refresh_websocket);
};
websocket.onmessage = function (evt) {
wsOps.onMessage(evt)
};
websocket.onerror = function (evt) {
wsOps.onError(evt)
};
} else {
var error = {
error: "Tarayıcınız websocket desteklememektedir. Lütfen güncel bir tarayıcı kullanınız.",
code: 500,
title: "Uyumsuz Tarayıcı",
no_highlight: true
};
ErrorService.handle(error, "ws");
}
};
// wsOps is service object when WSOps called
var wsOps = {};
var pingCounter = 0;
// ping is to keep alive websocket session when ui is open and used
// backend needs it to refresh session in order to not timeout
// checkPing is control function if 3 ping sent without response 'pong' refresh websocket object by closing it
// keepAlivePing is a function sends ping data when socket opens
var checkPing = function () {
if (pingCounter > 2) {
websocket.close();
$log.debug("websocket not pong");
pingCounter = 0;
}
};
var keepAlivePing = function (interval) {
return setInterval(function () {
if ($rootScope.websocketIsOpen && IsOnline.get_status() && DevSettings.settings.keepAlive === 'on') {
wsOps.doSend(angular.toJson({data: {view: "ping"}}));
pingCounter += 1;
checkPing();
}
}, interval);
};
wsOps.onOpen = function (evt) {
$rootScope.websocketIsOpen = true;
$log.info("CONNECTED", evt);
keepAlivePing(20000);
wsOps.loggedOut = false;
};
wsOps.onClose = function (event) {
$rootScope.websocketIsOpen = false;
$log.info("DISCONNECTED", event);
};
// two types of data can be come from websocket: with and without callback
// if callback in callbacks list it will run the callback and delete it
wsOps.callbacks = {};
wsOps.onMessage = function (event) {
// msg_methods are dispatch methods for incoming events. init is the default method to run
var msg_methods = {
init: function (data) {
if (angular.isDefined(wsOps.callbacks[data.callbackID])) {
var callback = wsOps.callbacks[data.callbackID];
delete wsOps.callbacks[data.callbackID];
callback.resolve(data);
} else {
if (data.msg != 'pong') {
$log.info("Data without callback: %o", data);
};
// if pong in msg reduce pingCounter
if (msg_data.msg === 'pong') {
pingCounter -= 1;
}
}
},
error: function () {
// when error in message redirect to ErrorService with error data
return ErrorService.handle(msg_data, 'ws');
},
message: function () {
// broadcast notifications data to notifications directive
// parse messages by type
// (1, "Info Notification"),
// (11, "Error Notification"),
// (111, "Success Notification"),
// (2, "Direct Message"),
// (3, "Broadcast Message"),
// (4, "Channel Message")
var type = {
1: "notifications",
11: "notifications",
111: "notifications",
2: "message",
3: "message",
4: "message"
};
// this way it broadcasts to relevant listener
// i group messages and notifications into 2 groups
// necessary actions will taken where it is listened
$timeout(function(){
$rootScope.$broadcast(type[msg_data["type"]], msg_data);
});
},
dashboard: function () {
// dashboard consists of menu and user specifications
var callback = wsOps.callbacks[msg_data.callbackID];
delete wsOps.callbacks[msg_data.callbackID];
callback.resolve(msg_data);
},
task_list: function () {
// broadcast task list to task_list directive in dashboard_widget_directives.js
$rootScope.$broadcast('task_list', msg_data["task_list"]);
},
channel_subscription: function(){
$timeout(function(){
$rootScope.$broadcast('channel_change', 'add', msg_data);
})
},
user_status: function(){
$timeout(function(){
$rootScope.$broadcast('channel_change', 'status', msg_data);
})
}
};
// do_action is the dispatcher function for incoming events
var do_action = function (options) {
// remove mask from crud here
// togglePageReadyMask(0);
// $log.info("togglePageReadyMask off");
var args = [].slice.call(arguments, 0),
initialized = false,
action = 'init';
if (typeof msg_methods[args[1]] === 'function') {
action = args[1];
args.shift();
}
return msg_methods[action](args[0]);
};
var msg_data = angular.fromJson(event.data);
if (msg_data.error) {
msg_data.cmd = 'error';
}
do_action(msg_data, msg_data.cmd);
if (msg_data.msg != "pong"){
$log.info("MESSAGE:", event, "Data:", angular.copy(msg_data));
}
};
wsOps.onError = function (evt) {
$log.error("ERROR :: " + evt);
};
wsOps.doSend = function (data) {
websocket.send(data);
$log.info('SENT:', data);
};
// reactor with promise
wsOps.request = function (data) {
if ($rootScope.websocketIsOpen) {
var request = {
callbackID: Math.random().toString(36).substring(7),
data: data
};
var deferred = $q.defer();
wsOps.callbacks[request.callbackID] = deferred;
websocket.send(angular.toJson(request));
$log.info('SENT:', data);
// togglePageReadyMask(1);
// $log.info("togglePageReadyMask on");
//
// todo: add success & error promises
return deferred.promise.then(function (response) {
request.response = response;
return response;
}
);
} else {
// is $rootScope.websocketIsOpen is not true try again in one second
$timeout(function () {
wsOps.request(data);
}, 1000);
}
};
wsOps.close = function () {
wsOps.loggedOut = true;
websocket.close();
$log.info("CLOSED");
};
/**
* below elements used by togglePageReadyMask function
* when data with callback function sent to websocket it toggles on the mask
* so the user not able to interact with interface
*/
var pageReady;
var mask = angular.element('<div class="body-mask"><div class="loader"></div>' +
'</div>');
mask.css({zIndex: '2010', opacity: '0.6'});
var body = $document.find('body').eq(0);
var togglePageReadyMask = function (st) {
var toggle = [
function () {
if (pageReady === 0) {
return;
}
$timeout(function () {
mask.remove();
pageReady = 0;
}, 1000);
},
function () {
if (pageReady === 1) {
return;
}
body.append(mask);
pageReady = 1;
}
];
toggle[st]();
};
return wsOps;
});
/**
* Copyright (C) 2015 ZetaOps Inc.
*
* This file is licensed under the GNU General Public License v3
* (GPLv3). See LICENSE.txt for details.
*
* @author Vladimir Baranov
*/
angular.module("ulakbus")
.service("Utils", function(){
var self = this;
// check if obj1 has properties values equal to corresponding properties in obj2
function hasEqualProperties(obj1, obj2){
var result = true;
for (var prop in obj2){
if(obj2.hasOwnProperty(prop)){
result = result && obj2[prop] == obj1[prop];
}
}
return result;
}
/**
* @param list {Array} Array of objects to group
* @param propName {String} property name to group array by
* @param initialObject {Object} initial object for groups setup
* @returns {Object}
*/
this.groupBy = function (list, propName, initialObject) {
if (!initialObject) initialObject = {};
return list.reduce(function(acc, item) {
(acc[item[propName]] = acc[item[propName]] || []).push(item);
return acc;
}, initialObject);
};
/**
* @param list {Array} Array of objects to group
* @param condition {Object} conditions object. If object in collection has same values as in conditions object it will be removed
* @returns {Object}|undefined removed object or undefined
*/
this.deleteWhere = function(list, condition){
for (var i = 0; i < list.length; i++){
if (hasEqualProperties(list[i], condition)){
list.splice(i, 1);
return list[i];
}
}
};
/**
* @param list {Array} Array of objects to group
* @param condition {Object} conditions object. If object in collection has same values as in conditions object found object will be returned
* @returns {Object}|undefined
*/
this.findWhere = function(list, condition){
for (var i = 0; i < list.length; i++){
if (hasEqualProperties(list[i], condition)){
return list[i];
}
}
}
/**
* @param collection {Array|Object} Array of objects to group
* @param callback {Function} Callback to apply to every element of the collection
* @returns None
*/
this.iterate = function(collection, callback){
angular.forEach(collection, function(val, key){
// don't iterate over angular binding indexes
if (key.indexOf && key.indexOf('$$') == 0){
return;
}
callback(val, key);
})
}
})
.filter("formatJson", function(){
return function(val){
try {
return JSON.stringify(val, null, 4);
} catch(e){
return val;
}
}
});
{ {
"name": "ulakbus-ui", "name": "ulakbus-ui",
"description": "UI for Ulakbüs", "description": "UI for Ulakbüs",
"version": "0.4.0", "version": "0.1.0",
"homepage": "https://github.com/zetaops/ulakbus-ui", "homepage": "https://github.com/zetaops/ulakbus-ui",
"license": "GPL", "license": "GPL",
"private": false, "private": false,
...@@ -13,18 +13,21 @@ ...@@ -13,18 +13,21 @@
"angular-animate": "1.4.7", "angular-animate": "1.4.7",
"angular-route": "1.4.7", "angular-route": "1.4.7",
"angular-resource": "1.4.7", "angular-resource": "1.4.7",
"angular-sanitize": "1.4.7",
"angular-cookies": "1.4.7", "angular-cookies": "1.4.7",
"angular-bootstrap": "0.14.3", "angular-bootstrap": "0.14.3",
"angular-i18n": "1.4.7", "angular-i18n": "1.4.7",
"angular-markdown-filter": "1.3.2",
"font-awesome": "4.3.0", "font-awesome": "4.3.0",
"angular-schema-form": "0.8.3", "angular-schema-form": "0.8.3",
"angular-loading-bar": "~0.8.0", "angular-loading-bar": "0.9.0",
"angular-toggle-switch": "~1.2.1", "angular-toggle-switch": "~1.2.1",
"metisMenu": "~1.1.3", "metisMenu": "~1.1.3",
"angular-chart.js": "~0.5.2", "angular-chart.js": "~0.5.2",
"angular-gettext": "2.1.0", "angular-gettext": "2.1.0",
"intro.js": "1.1.1", "intro.js": "1.1.1",
"moment": "2.10.6" "moment": "2.10.6",
"toastr": "*"
}, },
"resolutions": { "resolutions": {
"angular": "1.4.7" "angular": "1.4.7"
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -32,6 +32,13 @@ body { ...@@ -32,6 +32,13 @@ body {
background-color:#999; background-color:#999;
} }
.tooltip {
font-family:'robotolight';
font-size:13px;
letter-spacing:0.3px;
padding:15px;
}
.badge { .badge {
border-radius: 100%; border-radius: 100%;
width: 22px; width: 22px;
...@@ -48,6 +55,19 @@ body { ...@@ -48,6 +55,19 @@ body {
font-weight: normal; font-weight: normal;
} }
.form-container {
width: 650px;
background-color: #fff;
padding: 25px;
border-radius: 3px;
margin-left: auto;
margin-right: auto;
-webkit-box-shadow: 0 0 25px rgba(0,0,0,0.04);
-moz-box-shadow: 0 0 25px rgba(0,0,0,0.04);
box-shadow: 0 0 25px rgba(0,0,0,0.04);
}
.form-control { .form-control {
box-shadow:none; box-shadow:none;
border-radius:0; border-radius:0;
...@@ -1085,6 +1105,7 @@ table.dataTable thead .sorting:after { ...@@ -1085,6 +1105,7 @@ table.dataTable thead .sorting:after {
.dashboard-main-search .panel-default { .dashboard-main-search .panel-default {
padding-bottom:25px; padding-bottom:25px;
border-radius:2px;
} }
.dashboard-main-search .dashboard-student-search h3, .dashboard-main-search .dashboard-student-search h3,
...@@ -1325,13 +1346,22 @@ table.dataTable thead .sorting:after { ...@@ -1325,13 +1346,22 @@ table.dataTable thead .sorting:after {
.dashboard .panel-default > .panel-heading { .dashboard .panel-default > .panel-heading {
background-color:#fff; background-color:#fff;
border-color:#F2F2F2; border-color:#F2F2F2;
font-family:'robotomedium'; font-family:'robotolight';
color: rgb(93, 93, 93); color: rgb(95, 95, 95);
text-align:center; padding:15px;
} }
.dashboard .panel-default > .panel-heading .panel-title { .dashboard .panel-default > .panel-heading .panel-title {
font-size:18px; font-size:18px;
display:inline-block;
}
.dashboard .panel-default > .panel-heading .panel-action {
font-size: 15px;
padding-top: 3px;
padding-right: 10px;
font-family:'robotomedium';
cursor:pointer;
} }
.dashboard .user-info .user-name { .dashboard .user-info .user-name {
...@@ -1561,223 +1591,1146 @@ table.dataTable thead .sorting:after { ...@@ -1561,223 +1591,1146 @@ table.dataTable thead .sorting:after {
/* END OF SIDEBAR COLLAPSE */ /* END OF SIDEBAR COLLAPSE */
/* Responsive: Portrait tablets and up */
@media screen and (min-width: 768px) {
/* Remove the padding we set earlier */
.header,
.marketing,
.footer {
padding-left: 0;
padding-right: 0;
}
/* Space out the masthead */
.header {
margin-bottom: 30px;
}
/* Remove the bottom border on the jumbotron for visual effect */
.jumbotron {
border-bottom: 0;
}
.sidebar {
z-index: 1;
position: absolute;
overflow-y: auto;
width: 250px;
height: 100%;
-webkit-box-shadow: 0 0 25px rgba(0,0,0,0.1);
-moz-box-shadow: 0 0 25px rgba(0,0,0,0.1);
box-shadow: 0 0 25px rgba(0,0,0,0.1);
}
.navbar-top-links .dropdown-messages, /* STUDENT DASHBOARD */
.navbar-top-links .dropdown-tasks,
.navbar-top-links .dropdown-alerts {
margin-left: auto;
}
.container { .student-dashboard a:hover {
max-width: 730px; text-decoration:none;
} background-color:#f9f9f9;
}
.manager-view { .student-dashboard .panel-body ul,
height:100%; .student-dashboard .panel-body {
} padding:0;
margin:0;
.sidebar .sidebar-nav.navbar-collapse { }
overflow-x: visible;
/*overflow-y: auto;*/
/*position: absolute;*/
width: 100%;
/*max-height: calc(50% - 139px);*/
}
.sidebar-container { .student-dashboard .panel-body ul li {
max-height: calc(100% - 120px); overflow-y: auto; list-style: none;
} border-bottom: 1px solid #f5f5f5;
font-size:16px;
footer {
position: absolute;
bottom: 35px;
padding: 15px;
width:100%;
text-align:center;
}
footer span {
font-family:'robotobold';
color:#777;
}
} }
@media (max-width: 767px) { .student-dashboard .panel-body ul li a {
.manager-view { padding:25px;
width:100%; display:block;
} color:#333;
ul.timeline:before { }
left: 40px;
}
ul.timeline > li > .timeline-panel { .student-dashboard .panel-body ul li:last-child {
width: calc(100% - 90px); border:none;
width: -moz-calc(100% - 90px); }
width: -webkit-calc(100% - 90px);
}
ul.timeline > li > .timeline-badge { .student-course-list .panel-body,
top: 16px; .student-assignment-list .panel-body {
left: 15px; height:437px;
margin-left: 0; overflow-y:auto;
} }
ul.timeline > li > .timeline-panel { .student-course-list .panel-body ul li span {
float: right; margin-right:15px;
} }
ul.timeline > li > .timeline-panel:before {
right: auto;
left: -15px;
border-right-width: 15px;
border-left-width: 0;
}
ul.timeline > li > .timeline-panel:after { .student-assignment-list .assignment-status {
right: auto; width:35px;
left: -14px; float:left;
border-right-width: 14px; }
border-left-width: 0;
}
.sidebar {
width:100% !important;
}
.brand, .student-assignment-list .assignment-status .assignment-circle {
footer { width:10px;
display:none; height:10px;
} border-radius:100%;
margin-top: 7px;
margin-left: 3px;
}
.logo img { .student-assignment-list .urgent-assignment .assignment-circle {
width:200px; background-color:#D4244B;
margin-left:0; }
}
.manager-view-content { .student-assignment-list .urgent-assignment .assignment-due-date {
overflow:inherit; color:#D4244B;
} }
body { .student-assignment-list .approaching-assignment .assignment-circle {
overflow:auto; background-color:#F7941E;
}
.sidebar-collapse-button {
display:none;
}
.right-sidebar {
display: none;
}
} }
.student-assignment-list .approaching-assignment .assignment-due-date {
color:#F7941E;
}
@media (max-width: 1350px) { .student-assignment-list .non-urgent-assignment .assignment-circle {
.personnel-info-container { background-color:#01AEEE;
width:700px; }
}
.personnel-info-right { .student-assignment-list .non-urgent-assignment .assignment-due-date {
width:450px; color:#01AEEE;
}
} }
.student-assignment-list .assignment-title {
width:calc(100% - 100px);
float:left;
}
.student-assignment-list .assignment-title {
font-family:'robotomedium';
}
.student-assignment-list .assignment-title div:nth-child(1) {
font-family:'robotomedium';
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-right: 15px;
}
.student-assignment-list .assignment-title div:nth-child(2) {
font-size:15px;
font-family:'robotolight';
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-right: 15px;
}
.student-assignment-list .assignment-due-date {
width:65px;
float:left;
font-family:'robotolight';
position:relative;
}
@media (max-width: 1000px) { .student-assignment-list .assignment-due-date div:nth-child(1) {
.personnel-info-container { width:65px;
width:500px; font-size:22px;
height:auto; position:absolute;
} text-align:center;
}
.personnel-info-left { .student-assignment-list .assignment-due-date div:nth-child(2) {
width:100%; width:65px;
position:relative; font-size:13px;
height:auto; position:absolute;
border:none; margin-top:25px;
} text-align:center;
}
.personnel-info-right { .student-assignment-list .last-assignment .assignment-status div {
width:100%; width:3px;
position:relative; height:47px;
height:auto; background-color: #00A650;
} margin-left: 6px;
}
.generic-profile-picture, .student-assignment-list .last-assignment .panel-title {
.personnel-info-left ul li:nth-child(1), background-color: #fff;
.personnel-info-left ul li:nth-child(2) { border-color: #F2F2F2;
text-align:center; font-family: 'robotolight';
} color: rgb(95, 95, 95);
padding: 12px 0 0;
font-size: 18px;
}
.student-assignment-list .last-assignment .assignment-due-date i {
color:#01A550;
margin-top: 16px;
}
.generic-profile-picture img { .student-announcement-list .announcement-date {
border-radius:100%; float:left;
} font-family:'robotolight';
margin-right:25px;
width:30px;
} }
.student-announcement-list .announcement-text {
float:left;
width:calc(100% - 55px);
margin-top:3px;
}
.student-announcement-list .announcement-date div:first-child {
font-size: 22px;
text-align: center;
}
.student-announcement-list .announcement-date div:last-child {
font-size: 13px;
text-align: center;
}
@media (max-width: 560px) { .student-message-list .profile-pic {
.personnel-info-container { width: 65px;
width: 350px; display: block;
} margin-right: 20px;
float: left;
} }
@media (max-width: 991px) { .student-message-list .profile-pic img {
.dashboard .major-buttons a button { width: 100%;
margin-bottom:20px; border-radius: 100%;
}
} }
.tablescroll{
width: 100%; .student-message-list .message-content {
overflow-x:auto; width: calc(100% - 200px);
overflow-y:visible; float: left;
padding-bottom:1px;
} }
.tablescrollfixleft { .student-message-list .message-content div:first-child {
position:absolute; margin-top:7px;
left:0; font-family:'robotomedium';
top:auto; font-size:18px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
} }
.tablescrollfixleft {
position:absolute; .student-message-list .message-content div:last-child {
right:0; margin-top: 5px;
top:auto; color: #848484;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
} }
.student-message-list .message-time {
width: 100px;
float: right;
text-align:right;
padding-top: 21px;
color: #B3B3B3;
font-size: 14px;
}
/* loading bar */
/* END OF STUDENT DASHBOARD */
/* ACADEMICIAN DASHBOARD */
.academician-dashboard a:hover {
text-decoration:none;
background-color:#f9f9f9;
}
.academician-dashboard .panel-body ul,
.academician-dashboard .panel-body {
padding:0;
margin:0;
}
.academician-dashboard .panel-body ul li {
list-style: none;
border-bottom: 1px solid #f5f5f5;
font-size:16px;
}
.academician-dashboard .panel-body ul li a {
padding:20px 25px;
display:block;
color:#333;
}
.academician-dashboard .panel-body ul li:last-child {
border:none;
}
.academician-course-list .panel-body,
.academician-weekly-schedule .panel-body {
height:437px;
overflow-y:auto;
overflow-x:hidden;
}
.academician-course-list .panel-body ul li span {
margin-right:15px;
}
.academician-course-list .panel-body ul li div {
margin-left: 47px;
font-size: 15px;
color: #7E7E7E;
}
.academician-dashboard .academician-weekly-schedule table {
width: calc(100% + 2px);
-webkit-width: calc(100% + 2px);
border: none;
margin-top: -1px;
margin-left: -1px;
text-align:center;
}
.academician-dashboard .academician-weekly-schedule table a {
color:#333;
display:block;
height: 38px;
line-height: 38px;
}
.academician-dashboard .academician-weekly-schedule table a:hover {
font-family:'robotobold';
background-color:transparent;
font-size:16px;
}
.academician-dashboard .academician-weekly-schedule table tr.days td {
width: calc(100% / 6);
font-family: 'robotomedium';
background-color: #FDFDFD;
}
.academician-dashboard .academician-weekly-schedule table tr.days td:first-child {
background-color:transparent;
}
.academician-dashboard .academician-weekly-schedule table tr td:first-child {
height: 38px;
font-family: 'robotomedium';
background-color: #FDFDFD;
}
.academician-dashboard .academician-weekly-schedule p.schedule-notice {
margin-left: 36px;
margin-top: 18px;
}
.academician-dashboard .academician-weekly-schedule p.schedule-notice span {
font-family: 'robotomedium';
}
/* END OF ACADEMICIAN DASHBOARD */
/* ACADEMIC CALENDER DASHBOARD WIDGET */
.academic-calendar-widget .panel-body {
padding-top:30px;
padding-bottom:30px;
}
.academic-calendar-widget .calendar-inner {
width: 85%;
margin-left: auto;
margin-right: auto;
position: relative;
}
.academic-calendar-widget .date-circle {
width: calc(100%/7);
float:left;
}
.academic-calendar-widget .date-circle .year {
width: 75px;
text-align: center;
font-size: 11px;
color: #C6C6C6;
}
.academic-calendar-widget .date-circle-container .date-circle:nth-child(5) .year,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(6) .year,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(7) .year {
float:right;
}
.academic-calendar-widget .date-circle a {
width:75px;
height:75px;
color:#808285;
border: 3px solid #fff;
background-color:#fff;
border-radius: 100%;
text-align: center;
display:block;
margin-left: auto;
margin-right: auto;
margin-top:12px;
z-index:1;
position:relative;
cursor:pointer;
font-family:'robotolight';
}
.academic-calendar-widget .date-circle a:hover {
background-color:#EBEBEB;
}
.academic-calendar-widget .date-circle a:before {
border: 2px solid #939598;
content: " ";
position: absolute;
z-index: -1;
border-radius: 100%;
width: 100%;
height: 100%;
margin-left: auto;
margin-right: auto;
left: 0;
right: 0;
}
.academic-calendar-widget .date-today .year {
width: 95px;
margin-left: auto;
margin-right: auto;
}
.academic-calendar-widget .date-today a {
width:95px;
height:95px;
border: 2px solid #fff;
border-radius: 100%;
text-align: center;
margin-top:0;
color:#000;
}
.academic-calendar-widget .date-today a:hover {
background-color:#C9635F;
color:#fff;
}
.academic-calendar-widget .date-today a:before {
border-color: #BE1E2D;
}
.academic-calendar-widget .date-today a .date-day {
margin-top: 18px;
font-size: 25px;
}
.academic-calendar-widget .date-today a .date-month {
font-size: 17px;
}
.academic-calendar-widget a .date-day {
margin-top: 12px;
font-size: 19px;
}
.academic-calendar-widget a .date-month {
line-height: 7px;
}
.calendar-line {
width: 100%;
height: 1px;
background-color: #E5E5E5;
position: absolute;
margin-top: 48px;
z-index: 0;
}
.academic-calendar-widget .date-circle-container .date-circle:nth-child(1) a,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(2) a,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(3) a {
margin-left:0;
}
.academic-calendar-widget .date-circle-container .date-circle:nth-child(5) a,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(6) a,
.academic-calendar-widget .date-circle-container .date-circle:nth-child(7) a {
margin-right:0;
}
.calendar-widget-navigation {
position: relative;
font-size: 40px;
color: #ccc;
}
.calendar-widget-navigation .fa {
position:absolute;
top: 27px;
cursor:pointer;
-webkit-transition: all .2s;
-moz-transition: all .2s;
-ms-transition: all .2s;
-o-transition: all .2s;
transition: all .2s;
}
.calendar-widget-navigation .fa:hover {
color:#666;
}
.calendar-widget-navigation .fa-angle-left {
left:25px;
}
.calendar-widget-navigation .fa-angle-right {
right:25px;
}
.academic-calendar-widget-popover label {
color:#A61229;
}
.academic-calendar-widget-popover .content-wrapper {
border-bottom:1px solid #dedede;
margin-bottom:10px;
}
.academic-calendar-widget-popover .content-wrapper:last-child {
border:none;
}
.academic-calendar-widget .date-circle .popover {
width:450px !important;
padding-bottom:0 !important;
}
/* END OF ACADEMIC CALENDER DASHBOARD WIDGET */
/* CHAT APPLICATION */
.chat-app {
width: 800px;
height: 600px;
background-color: #fff;
position: fixed;
bottom: 15px;
right: 15px;
-moz-box-shadow: 0px 0px 15px rgba(0,0,0,0.2);
box-shadow: 0px 0px 15px rgba(0,0,0,0.2);
z-index: 10;
border-radius: 3px;
}
.chat-app .chat-app-container {
padding-left:240px;
}
.chat-app .side-navigation {
background-color: #8C1028;
width: 240px;
height: 100%;
position: absolute;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
overflow: auto;
padding-bottom: 20px;
left:0;
}
.chat-app .side-navigation ul {
margin: 0;
padding-left: 0;
padding-top: 15px;
}
.chat-app .side-navigation ul.channels {
border-bottom: 1px solid #9B1334;
padding-bottom: 15px;
}
.chat-app .side-navigation ul li {
list-style: none;
color: #fff;
font-size: 15px;
padding-left: 20px;
padding-bottom: 3px;
padding-top: 3px;
position:relative;
cursor:pointer;
}
.chat-app .side-navigation ul li:hover {
background-color:#B51533;
}
.chat-app .side-navigation ul li.title {
font-family:'robotobold';
cursor:default;
}
.chat-app .side-navigation ul li.title:hover {
background-color:transparent;
}
.chat-app .side-navigation ul li.title .badge {
position: relative;
top: -3px;
border-radius: 20px;
padding: 1px 7px;
width: auto;
height: auto;
background-color: #B51533;
border: none;
margin-left: 4px;
font-family: 'robotoblack';
}
.chat-app .side-navigation ul li.compose {
background-color: #6f0d20;
margin: 5px 10px;
border-radius: 3px;
padding-left: 33px !important;
padding-top: 8px;
padding-bottom: 8px;
}
.chat-app .side-navigation ul li.compose:hover {
background-color: #B51533;
}
.chat-app .side-navigation ul li.compose span {
position: absolute;
top: 12px;
left: 10px;
}
.chat-app .side-navigation ul li.compose:before {
display:none !important;
}
.chat-app .side-navigation ul.direct-messages li.title {
padding-left: 20px;
}
.chat-app .side-navigation ul.direct-messages li {
padding-left: 40px;
}
.chat-app .side-navigation ul.direct-messages li.active {
background-color: #B51533;
}
.chat-app .side-navigation ul.direct-messages li.title:before {
display:none;
}
.chat-app .side-navigation ul.direct-messages li:before {
content: " ";
width: 8px;
height: 8px;
background-color: rgba(255,255,255,0.3);
display: inline-block;
border-radius: 100%;
position: absolute;
left: 24px;
top: 9px;
}
.chat-app .side-navigation ul li.notification:after {
content: " ";
width: 8px;
height: 8px;
background-color: rgb(181, 21, 51);
display: inline-block;
border-radius: 100%;
position: absolute;
right: 24px;
top: 9px;
}
.chat-app .side-navigation ul.direct-messages li.online:before {
background-color:#CAFF4A;
}
.chat-app .conversation-section {
width: 100%;
height: 600px;
}
.chat-app .conversation-header {
height: 70px;
width: 560px;
border-bottom:1px solid #efefef;
}
.chat-app .conversation-header .conversation-user {
display: inline-block;
width: 280px;
margin-left: 23px;
float: left;
}
.chat-app .conversation-header .user-photo {
float: left;
margin-top: 20px;
}
.chat-app .conversation-header .user-name {
margin-top: 25px;
float: left;
margin-left: 10px;
font-family: 'robotobold';
font-size: 16px;
}
.chat-app .conversation-header .conversation-search {
display:inline-block;
float:left;
}
.chat-app .conversation-header .conversation-search input {
width: 180px;
height: 40px;
padding-left: 10px;
border: 1px solid #efefef;
border-radius: 3px;
outline: none;
margin-top: 15px;
}
.chat-app .conversation-header .close-chat-app {
display: inline-block;
float: left;
width: 40px;
height: 40px;
border: 1px solid #efefef;
text-align: center;
line-height: 40px;
margin-left: 10px;
border-radius: 3px;
margin-top:15px;
}
.chat-app .conversation-body {
overflow: auto;
height: calc(100% - 140px);
overflow-x: hidden;
}
.chat-app .conversation-footer {
height: 70px;
width: 560px;
position: absolute;
bottom: 0;
padding-left: 23px;
padding-right: 23px;
padding-top: 10px;
}
.chat-app .conversation-footer textarea {
outline: none;
resize: none;
width: calc(100% - 110px);
padding: 6px;
height: 50px;
border: 1px solid #efefef;
border-radius: 3px;
float:left;
}
.chat-app .conversation-footer .add-attachment {
float:left;
}
.chat-app .conversation-footer .add-attachment .glyphicon {
width: 50px;
height: 50px;
float: left;
border: 1px solid #efefef;
border-radius: 3px;
line-height: 50px;
text-align: center;
font-size: 20px;
top: 0;
margin-left: 5px;
color:#4D4D4D;
cursor:pointer;
}
.chat-app .conversation-footer .add-attachment .glyphicon:hover {
background-color:#efefef;
color:#000000;
}
.chat-app .conversation-section .conversation-header .conversation-user .user-photo img {
width:35px;
height:35px;
border-radius:100%;
}
.chat-app .conversation-section .conversation-body .beginning-of-conversation {
text-align: center;
font-family: 'robotobold';
font-size: 20px;
color: #ababab;
padding: 15px;
margin-bottom: 30px;
border-bottom: 1px solid #f3f3f3;
}
.chat-app .conversation-section .conversation-body .conversation-block {
display:block;
position:relative;
padding:5px 23px;
margin-bottom:10px;
}
.chat-app .conversation-section .conversation-body .conversation-block:hover {
background-color:#f5f5f5;
}
.chat-app .conversation-section .conversation-body .conversation-block .conversation-actions {
opacity:0;
width:0;
position:absolute;
}
.chat-app .conversation-section .conversation-body .conversation-block .conversation-actions .action {
background-color: #fff;
display: inline-block;
padding: 3px 9px;
border-radius: 3px;
border: 1px solid #ece8e8;
float: left;
margin-right: 5px;
cursor: pointer;
color: #696969;
}
.chat-app .conversation-section .conversation-body .conversation-block .conversation-actions .action:hover {
color:#000000;
}
.chat-app .conversation-section .conversation-body .conversation-block:hover > .conversation-actions {
opacity: 1;
width: 130px;
position: absolute;
top: -14px;
right: 0;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-photo img {
width: 40px;
float: left;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-photo img {
width:35px;
height:35px;
border-radius:100%;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-message {
float: left;
width: calc(100% - 40px);
padding-left:10px;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-message .user-name {
font-family: 'robotobold';
font-size: 16px;
float:left;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-message .message-time {
float: left;
margin-left: 10px;
font-size: 11px;
color: #a0a0a0;
margin-top: 4px;
}
.chat-app .conversation-section .conversation-body .conversation-block .user-message .message-content {
font-family: 'robotomedium';
}
.chat-app .create-new-message-window {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 11;
background-color: rgba(255,255,255,0.97);
border-radius:3px;
display:none;
}
.chat-app .create-new-message-window input {
width: 50%;
margin-left: 25%;
margin-top: 90px;
height: 50px;
padding-left: 15px;
border: 1px solid #ccc;
border-radius: 5px;
outline:none;
}
.chat-app .close-create-new-message-window {
width: 50px;
height: 50px;
border: 1px solid #ccc;
border-radius: 100%;
text-align: center;
line-height: 50px;
position: absolute;
right: 20px;
top: 20px;
font-size: 14px;
color: #a2a2a2;
cursor:pointer;
}
.chat-app .close-create-new-message-window:hover {
background-color:#efefef;
color:#000000;
}
.chat-app .create-new-message-window .search-results {
width: 50%;
margin-left: 25%;
margin-top: 25px;
height: calc(100% - 165px);
overflow: auto;
}
.chat-app .create-new-message-window .search-results .user {
width: 100%;
display: inline-block;
padding: 10px;
border-radius: 3px;
cursor:pointer;
}
.chat-app .create-new-message-window .search-results .user:hover {
background-color:#efefef;
}
.chat-app .create-new-message-window .search-results .user img {
width: 45px;
height: 45px;
border-radius: 100%;
float: left;
}
.chat-app .create-new-message-window .search-results .user .user-name {
float: left;
margin-left: 15px;
font-family: 'robotobold';
font-size: 18px;
margin-top: 9px;
}
/* END OF CHAT APPLICATION */
/* Responsive: Portrait tablets and up */
@media screen and (min-width: 768px) {
/* Remove the padding we set earlier */
.header,
.marketing,
.footer {
padding-left: 0;
padding-right: 0;
}
/* Space out the masthead */
.header {
margin-bottom: 30px;
}
/* Remove the bottom border on the jumbotron for visual effect */
.jumbotron {
border-bottom: 0;
}
.sidebar {
z-index: 1;
position: absolute;
overflow-y: auto;
width: 250px;
height: 100%;
-webkit-box-shadow: 0 0 25px rgba(0,0,0,0.1);
-moz-box-shadow: 0 0 25px rgba(0,0,0,0.1);
box-shadow: 0 0 25px rgba(0,0,0,0.1);
}
.navbar-top-links .dropdown-messages,
.navbar-top-links .dropdown-tasks,
.navbar-top-links .dropdown-alerts {
margin-left: auto;
}
.container {
max-width: 730px;
}
.manager-view {
height:100%;
}
.sidebar .sidebar-nav.navbar-collapse {
overflow-x: visible;
/*overflow-y: auto;*/
/*position: absolute;*/
width: 100%;
/*max-height: calc(50% - 139px);*/
}
.sidebar-container {
max-height: calc(100% - 120px); overflow-y: auto;
}
footer {
position: absolute;
bottom: 35px;
padding: 15px;
width:100%;
text-align:center;
}
footer span {
font-family:'robotobold';
color:#777;
}
}
@media (max-width: 767px) {
.manager-view {
width:100%;
}
ul.timeline:before {
left: 40px;
}
ul.timeline > li > .timeline-panel {
width: calc(100% - 90px);
width: -moz-calc(100% - 90px);
width: -webkit-calc(100% - 90px);
}
ul.timeline > li > .timeline-badge {
top: 16px;
left: 15px;
margin-left: 0;
}
ul.timeline > li > .timeline-panel {
float: right;
}
ul.timeline > li > .timeline-panel:before {
right: auto;
left: -15px;
border-right-width: 15px;
border-left-width: 0;
}
ul.timeline > li > .timeline-panel:after {
right: auto;
left: -14px;
border-right-width: 14px;
border-left-width: 0;
}
.sidebar {
width:100% !important;
}
.brand,
footer {
display:none;
}
.logo img {
width:200px;
margin-left:0;
}
.manager-view-content {
overflow:inherit;
}
body {
overflow:auto;
}
.sidebar-collapse-button {
display:none;
}
.right-sidebar {
display: none;
}
}
@media (max-width: 1350px) {
.personnel-info-container {
width:700px;
}
.personnel-info-right {
width:450px;
}
}
@media (max-width: 1000px) {
.personnel-info-container {
width:500px;
height:auto;
}
.personnel-info-left {
width:100%;
position:relative;
height:auto;
border:none;
}
.personnel-info-right {
width:100%;
position:relative;
height:auto;
}
.generic-profile-picture,
.personnel-info-left ul li:nth-child(1),
.personnel-info-left ul li:nth-child(2) {
text-align:center;
}
.generic-profile-picture img {
border-radius:100%;
}
}
@media (max-width: 560px) {
.personnel-info-container {
width: 350px;
}
}
@media (max-width: 991px) {
.dashboard .major-buttons a button {
margin-bottom:20px;
}
}
.tablescroll{
width: 100%;
overflow-x:auto;
overflow-y:visible;
padding-bottom:1px;
}
.tablescrollfixleft {
position:absolute;
left:0;
top:auto;
}
.tablescrollfixleft {
position:absolute;
right:0;
top:auto;
}
/* loading bar */
.loadingbarfullsize{ .loadingbarfullsize{
z-index:10001; z-index:10001;
...@@ -1843,6 +2796,39 @@ table.dataTable thead .sorting:after { ...@@ -1843,6 +2796,39 @@ table.dataTable thead .sorting:after {
/* end file upload */ /* end file upload */
.mid-h3 {
text-align: center;
margin-bottom: 20px;
color: #636363 ;
}
#toast-container {
margin-top: 90px;
}
.crud-mask {
width: 100%;
height: 100%;
background: #fff;
position: absolute;
top:43px; left:0;
z-index: 1000;
}
.body-mask {
width: 100%;
height: 100%;
background: #fff;
position: absolute;
top:0; left:0;
z-index: 1099;
}
/* for overflowing buttons not collapsing each other */
.bottom-margined{
margin-bottom: 0.75em;
}
/* /*
* metismenu - v1.1.3 * metismenu - v1.1.3
* Easy menu jQuery plugin for Twitter Bootstrap 3 * Easy menu jQuery plugin for Twitter Bootstrap 3
...@@ -1861,300 +2847,303 @@ table.dataTable thead .sorting:after { ...@@ -1861,300 +2847,303 @@ table.dataTable thead .sorting:after {
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"} */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.3.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.3.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.3.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.3.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;transform:translate(0, 0)}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-genderless:before,.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}
.introjs-overlay { .introjs-overlay {
position: absolute; position: absolute;
z-index: 999999; z-index: 999999;
background: #181818; background: #181818;
opacity: 0; opacity: 0;
-webkit-transition: all 0.3s ease-out; -webkit-transition: all 0.3s ease-out;
-moz-transition: all 0.3s ease-out; -moz-transition: all 0.3s ease-out;
-ms-transition: all 0.3s ease-out; -ms-transition: all 0.3s ease-out;
-o-transition: all 0.3s ease-out; -o-transition: all 0.3s ease-out;
transition: all 0.3s ease-out; transition: all 0.3s ease-out;
} }
.introjs-fixParent { .introjs-fixParent {
z-index: auto !important; z-index: auto !important;
opacity: 1.0 !important; opacity: 1.0 !important;
} }
.introjs-showElement { .introjs-showElement {
z-index: 9999999 !important; z-index: 9999999 !important;
} }
.introjs-relativePosition { .introjs-relativePosition {
position: relative; position: relative;
} }
.introjs-helperLayer { .introjs-helperLayer {
position: absolute; position: absolute;
z-index: 9999998; z-index: 9999998;
background-color: #FFF; background-color: #FFF;
background-color: rgba(255,255,255,.9); background-color: rgba(255,255,255,.9);
border: 1px solid #777; border: 1px solid #777;
border: 2px solid rgba(117, 117, 117, 1); border: 2px solid rgba(117, 117, 117, 1);
border-radius: 4px; border-radius: 4px;
box-shadow: 0 5px 8px -3px rgba(0,0,0,.6); box-shadow: 0 5px 8px -3px rgba(0,0,0,.6);
-webkit-transition: all 0.3s ease-out; -webkit-transition: all 0.3s ease-out;
-moz-transition: all 0.3s ease-out; -moz-transition: all 0.3s ease-out;
-ms-transition: all 0.3s ease-out; -ms-transition: all 0.3s ease-out;
-o-transition: all 0.3s ease-out; -o-transition: all 0.3s ease-out;
transition: all 0.3s ease-out; transition: all 0.3s ease-out;
} }
.introjs-helperNumberLayer { .introjs-helperNumberLayer {
position: absolute; position: absolute;
top: -16px; top: -16px;
left: -9px; left: -9px;
z-index: 9999999999 !important; z-index: 9999999999 !important;
padding: 2px; padding: 2px;
font-family: Arial, verdana, tahoma; font-family: Arial, verdana, tahoma;
font-size: 13px; font-size: 13px;
font-weight: bold; font-weight: bold;
color: #fff; /* Old browsers */ /* Chrome10+,Safari5.1+ */ color: #fff; /* Old browsers */ /* Chrome10+,Safari5.1+ */
background: #DA4433; background: #DA4433;
width: 20px; width: 20px;
box-shadow: 0 1px 1px rgba(0,0,0,.35); box-shadow: 0 1px 1px rgba(0,0,0,.35);
height:20px; height:20px;
text-align: center; text-align: center;
line-height: 20px; line-height: 20px;
border: 2px solid #DA4433; border: 2px solid #DA4433;
border-radius: 0; /* IE6-9 */ /* IE10 text shadows */ border-radius: 0; /* IE6-9 */ /* IE10 text shadows */
} }
.introjs-helperNumberLayer:after { .introjs-helperNumberLayer:after {
content:""; content:"";
width:0; width:0;
height:0; height:0;
position:absolute; position:absolute;
content:0; content:0;
left:-3px; left:-3px;
bottom:-10px; bottom:-10px;
border:4px solid transparent; border:4px solid transparent;
border-right-color:#900; border-right-color:#900;
border-top-color:#900; border-top-color:#900;
} }
.introjs-arrow { .introjs-arrow {
border: 5px solid white; border: 5px solid white;
content:''; content:'';
position: absolute; position: absolute;
} }
.introjs-arrow.top { .introjs-arrow.top {
top: -10px; top: -10px;
border-top-color:transparent; border-top-color:transparent;
border-right-color:transparent; border-right-color:transparent;
border-bottom-color: #ecf0f1; border-bottom-color: #ecf0f1;
border-left-color:transparent; border-left-color:transparent;
} }
.introjs-arrow.right { .introjs-arrow.right {
right: -10px; right: -10px;
top: 10px; top: 10px;
border-top-color:transparent; border-top-color:transparent;
border-right-color:transparent; border-right-color:transparent;
border-bottom-color:transparent; border-bottom-color:transparent;
border-left-color:#ecf0f1; border-left-color:#ecf0f1;
} }
.introjs-arrow.bottom { .introjs-arrow.bottom {
bottom: -10px; bottom: -10px;
border-top-color:#ecf0f1; border-top-color:#ecf0f1;
border-right-color:transparent; border-right-color:transparent;
border-bottom-color:transparent; border-bottom-color:transparent;
border-left-color:transparent; border-left-color:transparent;
} }
.introjs-arrow.left { .introjs-arrow.left {
left: -10px; left: -10px;
top: 10px; top: 10px;
border-top-color:transparent; border-top-color:transparent;
border-right-color: #ecf0f1; border-right-color: #ecf0f1;
border-bottom-color:transparent; border-bottom-color:transparent;
border-left-color:transparent; border-left-color:transparent;
} }
.introjs-tooltip { .introjs-tooltip {
position: absolute; position: absolute;
padding: 10px 10px; padding: 10px 10px;
background-color: #ecf0f1; background-color: #ecf0f1;
min-width: 200px; min-width: 200px;
max-width: 300px; max-width: 300px;
border-radius: 3px; border-radius: 3px;
/* border-radius: 3px; */ /* border-radius: 3px; */
/* box-shadow: 0 6px 7px -4px rgba(0,0,0,.4); */ /* box-shadow: 0 6px 7px -4px rgba(0,0,0,.4); */
-webkit-transition: opacity 0.1s ease-out; -webkit-transition: opacity 0.1s ease-out;
-moz-transition: opacity 0.1s ease-out; -moz-transition: opacity 0.1s ease-out;
-ms-transition: opacity 0.1s ease-out; -ms-transition: opacity 0.1s ease-out;
-o-transition: opacity 0.1s ease-out; -o-transition: opacity 0.1s ease-out;
transition: opacity 0.1s ease-out; transition: opacity 0.1s ease-out;
/* border: 5px double #0787AF; */ /* border: 5px double #0787AF; */
} }
.introjs-tooltiptext { .introjs-tooltiptext {
margin-left: -10px; margin-left: -10px;
margin-right: -10px; margin-right: -10px;
/* border-top: 1px solid #FFFFFF; */ /* border-top: 1px solid #FFFFFF; */
/* background: #FAFAFA; */ /* background: #FAFAFA; */
color: #2c3e50; color: #2c3e50;
padding: 25px 30px 15px; padding: 25px 30px 15px;
/* border-bottom: 1px solid #FFFFFF; */ /* border-bottom: 1px solid #FFFFFF; */
} }
.introjs-tooltipbuttons { .introjs-tooltipbuttons {
text-align: center; text-align: center;
/* background: rgba(0, 0, 0, 0.06); */ /* background: rgba(0, 0, 0, 0.06); */
border-radius: 0 0 8px 8px; border-radius: 0 0 8px 8px;
padding-bottom: 10px; padding-bottom: 10px;
} }
/* /*
Buttons style by http://nicolasgallagher.com/lab/css3-github-buttons/ Buttons style by http://nicolasgallagher.com/lab/css3-github-buttons/
Changed by Afshin Mehrabani Changed by Afshin Mehrabani
*/ */
.introjs-button { .introjs-button {
position: relative; position: relative;
overflow: visible; overflow: visible;
display: inline-block; display: inline-block;
padding: 0.5em 0.8em; padding: 0.5em 0.8em;
/* box-shadow: 0 2px 0px -0px #306588; */ /* box-shadow: 0 2px 0px -0px #306588; */
margin: 0; margin: 0;
outline: none; outline: none;
border: 2px solid; border: 2px solid;
background: transparent; background: transparent;
text-decoration: none; text-decoration: none;
font: 11px/normal sans-serif; font: 11px/normal sans-serif;
color: #2980b9 !important; color: #2980b9 !important;
white-space: nowrap; white-space: nowrap;
cursor: pointer; cursor: pointer;
outline: none !important; outline: none !important;
-webkit-background-clip: padding; -webkit-background-clip: padding;
-moz-background-clip: padding; -moz-background-clip: padding;
-o-background-clip: padding-box; -o-background-clip: padding-box;
/*background-clip: padding-box;*/ /* commented out due to Opera 11.10 bug */ /*background-clip: padding-box;*/ /* commented out due to Opera 11.10 bug */
-webkit-border-radius: 0.2em; -webkit-border-radius: 0.2em;
-moz-border-radius: 0.2em; -moz-border-radius: 0.2em;
border-radius: 0.2em; border-radius: 0.2em;
/* IE hacks */ /* IE hacks */
zoom: 1; zoom: 1;
*display: inline; *display: inline;
margin-top: 10px; margin-top: 10px;
transition:all 0.25s ease; transition:all 0.25s ease;
-webkit-transition:all 0.25s ease; -webkit-transition:all 0.25s ease;
-moz-transition:all 0.25s ease; -moz-transition:all 0.25s ease;
-ms-transition:all 0.25s ease; -ms-transition:all 0.25s ease;
-o-transition:all 0.25s ease; -o-transition:all 0.25s ease;
} }
.introjs-button:hover { .introjs-button:hover {
color: #fff; color: #fff;
background: #2671A2; background: #2671A2;
text-decoration: none; text-decoration: none;
border-color: #235677; border-color: #235677;
} }
.introjs-button:focus, .introjs-button:focus,
.introjs-button:active { .introjs-button:active {
background: #23587A; text-decoration: none; background: #23587A; text-decoration: none;
color: #fff; color: #fff;
/* bottom: -1px; */ /* bottom: -1px; */
box-shadow: none; box-shadow: none;
border-color: #173B53; border-color: #173B53;
} }
/* overrides extra padding on button elements in Firefox */ /* overrides extra padding on button elements in Firefox */
.introjs-button::-moz-focus-inner { .introjs-button::-moz-focus-inner {
padding: 0; padding: 0;
border: 0; border: 0;
} }
.introjs-skipbutton { .introjs-skipbutton {
margin-right: 5px; margin-right: 5px;
color: #c00; color: #c00;
background: transparent; background: transparent;
} }
.introjs-skipbutton:hover { .introjs-skipbutton:hover {
background: #EB1540; background: #EB1540;
border-color: #B91D0D; border-color: #B91D0D;
} }
.introjs-skipbutton:active, .introjs-skipbutton:focus { .introjs-skipbutton:active, .introjs-skipbutton:focus {
background: #C02312; background: #C02312;
/* box-shadow: 0 1px 0px -0px #6F1309; */ /* box-shadow: 0 1px 0px -0px #6F1309; */
} }
.introjs-prevbutton { .introjs-prevbutton {
-webkit-border-radius: 0.2em 0 0 0.2em; -webkit-border-radius: 0.2em 0 0 0.2em;
-moz-border-radius: 0.2em 0 0 0.2em; -moz-border-radius: 0.2em 0 0 0.2em;
border-radius: 0.2em 0 0 0.2em; border-radius: 0.2em 0 0 0.2em;
border-right: none; border-right: none;
} }
.introjs-nextbutton { .introjs-nextbutton {
-webkit-border-radius: 0 0.2em 0.2em 0; -webkit-border-radius: 0 0.2em 0.2em 0;
-moz-border-radius: 0 0.2em 0.2em 0; -moz-border-radius: 0 0.2em 0.2em 0;
border-radius: 0 0.2em 0.2em 0; border-radius: 0 0.2em 0.2em 0;
} }
.introjs-disabled, .introjs-disabled:hover, .introjs-disabled:focus { .introjs-disabled, .introjs-disabled:hover, .introjs-disabled:focus {
color: #C2C2C2 !important; color: #C2C2C2 !important;
border-color: #d4d4d4; border-color: #d4d4d4;
cursor: default; cursor: default;
/* box-shadow: 0 2px 0px -0px #CACED1; */ /* box-shadow: 0 2px 0px -0px #CACED1; */
background-color: #E6E6E6; background-color: #E6E6E6;
background-image: none; background-image: none;
text-decoration: none; text-decoration: none;
} }
.introjs-bullets { .introjs-bullets {
text-align: center; text-align: center;
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
top: -5px; top: -5px;
} }
.introjs-bullets ul { .introjs-bullets ul {
clear: both; clear: both;
margin: 15px auto 0; margin: 15px auto 0;
padding: 0; padding: 0;
display: inline-block; display: inline-block;
} }
.introjs-bullets ul li { .introjs-bullets ul li {
list-style: none; list-style: none;
float: left; float: left;
margin: 0 2px; margin: 0 2px;
} }
.introjs-bullets ul li a { .introjs-bullets ul li a {
display: block; display: block;
width: 6px; width: 6px;
height: 6px; height: 6px;
background: #ccc; background: #ccc;
border-radius: 10px; border-radius: 10px;
-moz-border-radius: 10px; -moz-border-radius: 10px;
-webkit-border-radius: 10px; -webkit-border-radius: 10px;
text-decoration: none; text-decoration: none;
} }
.introjs-bullets ul li a:hover { .introjs-bullets ul li a:hover {
background: #999; background: #999;
} }
.introjs-bullets ul li a.active { .introjs-bullets ul li a.active {
background: #999; background: #999;
} }
.introjs-progress { .introjs-progress {
background-color: #FAFAFA; background-color: #FAFAFA;
margin: 5px 20px; margin: 5px 20px;
} }
.introjs-progressbar { .introjs-progressbar {
background-color: #2980b9; background-color: #2980b9;
} }
.introjsFloatingElement { .introjsFloatingElement {
position: absolute; position: absolute;
height: 0; height: 0;
width: 0; width: 0;
left: 50%; left: 50%;
top: 50%; top: 50%;
} }
.toast-title{font-weight:700}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#fff}.toast-message a:hover{color:#ccc;text-decoration:none}.toast-close-button{position:relative;right:-.3em;top:-.3em;float:right;font-size:20px;font-weight:700;color:#fff;-webkit-text-shadow:0 1px 0 #fff;text-shadow:0 1px 0 #fff;opacity:.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}.toast-close-button:focus,.toast-close-button:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}button.toast-close-button{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999;pointer-events:none}#toast-container *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}#toast-container>div{position:relative;pointer-events:auto;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-position:15px center;background-repeat:no-repeat;-moz-box-shadow:0 0 12px #999;-webkit-box-shadow:0 0 12px #999;box-shadow:0 0 12px #999;color:#fff;opacity:.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80)}#toast-container>:hover{-moz-box-shadow:0 0 12px #000;-webkit-box-shadow:0 0 12px #000;box-shadow:0 0 12px #000;opacity:1;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);filter:alpha(opacity=100);cursor:pointer}#toast-container>.toast-info{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}#toast-container>.toast-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}#toast-container>.toast-success{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}#toast-container>.toast-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}#toast-container.toast-bottom-center>div,#toast-container.toast-top-center>div{width:300px;margin-left:auto;margin-right:auto}#toast-container.toast-bottom-full-width>div,#toast-container.toast-top-full-width>div{width:96%;margin-left:auto;margin-right:auto}.toast{background-color:#030303}.toast-success{background-color:#51a351}.toast-error{background-color:#bd362f}.toast-info{background-color:#2f96b4}.toast-warning{background-color:#f89406}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width:240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container .toast-close-button{right:-.2em;top:-.2em}}@media all and (min-width:241px) and (max-width:480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container .toast-close-button{right:-.2em;top:-.2em}}@media all and (min-width:481px) and (max-width:768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}}
\ No newline at end of file
...@@ -19,19 +19,26 @@ ...@@ -19,19 +19,26 @@
<link rel="stylesheet" href="css/roboto/roboto.css"> <link rel="stylesheet" href="css/roboto/roboto.css">
<link rel="stylesheet" href="css/jquery-ui.min.css"> <link rel="stylesheet" href="css/jquery-ui.min.css">
</head> </head>
<body> <body ng-controller="KeyListenController" ng-keydown="down($event)">
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0" ng-if="$root.loggedInUser"> <div ng-show="user_ready === false" class="body-mask">
<div class="text-center">
<span class="loader"></span>
</div>
</div>
<nav class="navbar navbar-default navbar-static-top" role="navigation" style="margin-bottom: 0"
ng-show="user_ready === true">
<collapse-menu></collapse-menu> <collapse-menu></collapse-menu>
<!--<ul class="header-menu">--> <!--<ul class="header-menu">-->
<!--<li><a href="">Mesajlar</a></li>--> <!--<li><a href="">Mesajlar</a></li>-->
<!--<li><a href="">Görevler</a></li>--> <!--<li><a href="">Görevler</a></li>-->
<!--<li><a href="">Raporlar</a></li>--> <!--<li><a href="">Raporlar</a></li>-->
<!--<li><a href="">Ayarlar</a></li>--> <!--<li><a href="">Ayarlar</a></li>-->
<!--</ul>--> <!--</ul>-->
<div class="navbar-header"> <div class="navbar-header">
<div class="brand"> <div class="brand">
<a href="#/dashboard" ng-click="$root.breadcrumbLinks = ['Panel']" class="logo"><img src="/img/brand-logo.png" /></a> <a href="#/dashboard" class="logo"><img src="/img/brand-logo.png"/></a>
</div> </div>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span> <span class="sr-only">Toggle navigation</span>
...@@ -44,12 +51,12 @@ ...@@ -44,12 +51,12 @@
<header-notification></header-notification> <header-notification></header-notification>
</nav> </nav>
<sidebar ng-if="$root.loggedInUser"></sidebar> <sidebar ng-show="user_ready === true"></sidebar>
<div class="manager-view"> <div class="manager-view">
<div class="manager-view-inner"> <div class="manager-view-inner">
<!-- manager-header --> <!-- manager-header -->
<header-sub-menu ng-if="$root.loggedInUser"></header-sub-menu> <header-sub-menu ng-if="$root.current_user"></header-sub-menu>
<!-- end of manager-header --> <!-- end of manager-header -->
<div class="manager-view-content"> <div class="manager-view-content">
<div class="row"> <div class="row">
...@@ -57,6 +64,7 @@ ...@@ -57,6 +64,7 @@
</div> </div>
<right-sidebar></right-sidebar> <right-sidebar></right-sidebar>
<messaging></messaging>
</div> </div>
</div> </div>
</div> </div>
...@@ -67,7 +75,7 @@ ...@@ -67,7 +75,7 @@
<script src="bower_components/jquery.min.js"></script> <script src="bower_components/jquery.min.js"></script>
<script src="bower_components/jquery-ui.min.js"></script> <script src="bower_components/jquery-ui.min.js"></script>
<script src="bower_components/angular.min.js"></script> <script src="bower_components/angular.js"></script>
<script src="bower_components/components.js"></script> <script src="bower_components/components.js"></script>
<script src="shared/translations.js"></script> <script src="shared/translations.js"></script>
<script src="templates.js"></script> <script src="templates.js"></script>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -20,6 +20,8 @@ module.exports = function (config) { ...@@ -20,6 +20,8 @@ module.exports = function (config) {
'app/bower_components/angular-gettext/dist/angular-gettext.min.js', 'app/bower_components/angular-gettext/dist/angular-gettext.min.js',
'app/bower_components/angular-route/angular-route.js', 'app/bower_components/angular-route/angular-route.js',
'app/bower_components/angular-resource/angular-resource.js', 'app/bower_components/angular-resource/angular-resource.js',
"app/bower_components/showdown/dist/showdown.min.js",
"app/bower_components/angular-markdown-filter/markdown.js",
'app/bower_components/angular-sanitize/angular-sanitize.min.js', 'app/bower_components/angular-sanitize/angular-sanitize.min.js',
'app/bower_components/tv4/tv4.js', 'app/bower_components/tv4/tv4.js',
'app/bower_components/objectpath/lib/ObjectPath.js', 'app/bower_components/objectpath/lib/ObjectPath.js',
...@@ -29,7 +31,7 @@ module.exports = function (config) { ...@@ -29,7 +31,7 @@ module.exports = function (config) {
'app/bower_components/moment/min/moment.min.js', 'app/bower_components/moment/min/moment.min.js',
'app/app.js', 'app/app.js',
'app/app_routes.js', 'app/app_routes.js',
'app/zetalib/**/*.js', 'app/zetalib/**/!(action_service).js',
'app/components/**/*.js' 'app/components/**/*.js'
], ],
...@@ -37,7 +39,8 @@ module.exports = function (config) { ...@@ -37,7 +39,8 @@ module.exports = function (config) {
frameworks: ['jasmine'], frameworks: ['jasmine'],
browsers: ['PhantomJS'], //browsers: ['PhantomJS', 'Chrome', 'Firefox', 'Safari'],
browsers: ['Chrome'],
customLaunchers: { customLaunchers: {
'PhantomJS_custom': { 'PhantomJS_custom': {
...@@ -46,7 +49,7 @@ module.exports = function (config) { ...@@ -46,7 +49,7 @@ module.exports = function (config) {
windowName: 'my-window', windowName: 'my-window',
settings: { settings: {
webSecurityEnabled: false webSecurityEnabled: false
}, }
}, },
flags: ['--load-images=true'], flags: ['--load-images=true'],
debug: true debug: true
...@@ -60,9 +63,12 @@ module.exports = function (config) { ...@@ -60,9 +63,12 @@ module.exports = function (config) {
plugins: [ plugins: [
'karma-phantomjs-launcher', 'karma-phantomjs-launcher',
'karma-chrome-launcher',
//'karma-firefox-launcher',
//'karma-safari-launcher',
'karma-jasmine', 'karma-jasmine',
'karma-junit-reporter', //'karma-junit-reporter',
'karma-coverage' //'karma-coverage'
], ],
junitReporter: { junitReporter: {
...@@ -70,34 +76,33 @@ module.exports = function (config) { ...@@ -70,34 +76,33 @@ module.exports = function (config) {
suite: 'unit' suite: 'unit'
}, },
reporters: ['progress', 'coverage'], //reporters: ['progress', 'coverage'],
preprocessors: { //preprocessors: {
'app/app.js': ['coverage'], // 'app/app.js': ['coverage'],
'app/app_routes.js': ['coverage'], // 'app/app_routes.js': ['coverage'],
'app/components/auth/*.js': ['coverage'], // 'app/components/auth/*.js': ['coverage'],
'app/components/crud/*.js': ['coverage'], // 'app/components/crud/*.js': ['coverage'],
'app/components/dashboard/*.js': ['coverage'], // 'app/components/dashboard/*.js': ['coverage'],
'app/components/version/*.js': ['coverage'], // 'app/components/version/*.js': ['coverage'],
'app/zetalib/**/*.js': ['coverage'] // 'app/zetalib/**/!(action_service).js': ['coverage']
}, //},
coverageReporter: { //coverageReporter: {
check: { // check: {
global: { // global: {
statements: 60, // statements: 60,
branches: 10, // branches: 10,
functions: 60, // functions: 60,
lines: 60, // lines: 60,
excludes: [ // excludes: [
'app/components/uitemplates/*.js', // 'app/components/uitemplates/*.js'
//'app/zetalib/interceptors.js' // ]
] // }
} // },
}, // type : 'html',
type : 'html', // dir : 'coverage/'
dir : 'coverage/' //}
}
}); });
}; };
{ {
"name": "ulakbus-ui", "name": "ulakbus-ui",
"private": true, "private": true,
"version": "0.0.1", "version": "0.1.0",
"description": "", "description": "",
"repository": "https://github.com/zetaops/ulakbus-ui", "repository": "https://github.com/zetaops/ulakbus-ui",
"license": "GPL", "license": "GPL",
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
"karma": "~0.12", "karma": "~0.12",
"karma-chrome-launcher": "^0.1.12", "karma-chrome-launcher": "^0.1.12",
"karma-phantomjs-launcher": "^0.1", "karma-phantomjs-launcher": "^0.1",
"karma-firefox-launcher": "*",
"karma-safari-launcher": "*",
"karma-junit-reporter": "^0.2.2", "karma-junit-reporter": "^0.2.2",
"karma-jasmine": "~0.1", "karma-jasmine": "~0.1",
"istanbul": "^0.3.15", "istanbul": "^0.3.15",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment