' +
'
{{badgevalue}}' +
- '
' +
+ '
' +
'
' +
'
' +
'
' +
diff --git a/src/main/webapp/scripts/modules/layouts/containers/tabs/tabs.js b/src/main/webapp/scripts/modules/layouts/containers/tabs/tabs.js
index cfc1129bb..b3f673830 100644
--- a/src/main/webapp/scripts/modules/layouts/containers/tabs/tabs.js
+++ b/src/main/webapp/scripts/modules/layouts/containers/tabs/tabs.js
@@ -25,7 +25,8 @@ WM.module('wm.layouts.containers')
/* get the properties related to the tabs */
var widgetProps = PropertiesFactory.getPropertiesOf('wm.tabs', ['wm.base']),
notifyFor = {
- 'tabsposition': true
+ 'tabsposition' : true,
+ 'defaultpaneindex': true
};
/*Define the property change handler. This function will be triggered when there is a change in the widget property */
@@ -34,6 +35,15 @@ WM.module('wm.layouts.containers')
case 'tabsposition':
scope.setTabsPosition(newVal);
break;
+ case 'defaultpaneindex':
+ //If no active tab is set ie.. no isdefaulttab then honor the defaultpaneindex
+ if (!scope.activeTab) {
+ scope.activeTab = scope.tabs[newVal || 0];
+ }
+
+ scope.selectTab(scope.activeTab, false, true);
+
+ break;
}
}
@@ -162,7 +172,7 @@ WM.module('wm.layouts.containers')
*/
tabs.forEach(function (tab) {
if (!activeTab) {
- if (tab.isdefaulttab) {
+ if (tab.isdefaulttab && !attrs.defaultpaneindex) {
activeTab = tab;
activeTab.isActive = true;
}
@@ -171,6 +181,8 @@ WM.module('wm.layouts.containers')
}
});
+ scope.activeTab = activeTab;
+
/*selects a given tab and executes onBeforeSwitchTab before switching*/
function selectTab(tab, onBeforeSwitchTab) {
/*trigger onBeforeSwitchTab callback before switching*/
@@ -181,12 +193,6 @@ WM.module('wm.layouts.containers')
}
}
- /* if isdefaulttab is not set on any of the tabs, then set the first tab as active */
- activeTab = activeTab || tabs[0];
-
- if (activeTab) {
- scope.selectTab(activeTab, false, true);
- }
/**
* @ngdoc function
* @name wm.layouts.containers.directive:wmTabs#next
@@ -319,6 +325,7 @@ WM.module('wm.layouts.containers')
'
' +
' ' +
'' +
+ '{{badgevalue}}' +
'
' +
'' +
'',
@@ -355,6 +362,9 @@ WM.module('wm.layouts.containers')
scope.$lazyLoad = WM.noop;
},
'post': function (scope, element, attrs, ctrl) {
+
+ var parentScope = element.closest('.app-tabs').isolateScope();
+
//To support backward compatibility for old projects
if (scope.title === undefined && !scope.bindtitle) {
scope.title = scope.heading || scope.bindheading;
@@ -391,6 +401,11 @@ WM.module('wm.layouts.containers')
Utils.triggerFn(WM.element(this).isolateScope().redraw);
});
scope.isActive = true;
+
+ if (CONSTANTS.isRunMode && parentScope.onChange) {
+ parentScope.onChange({'$event': $event, '$scope': parentScope, 'newPaneIndex': scope.tabId, 'oldPaneIndex': parentScope.activeTab.tabId || 0});
+ }
+
ctrl.selectTab(scope);
};
@@ -495,7 +510,12 @@ WM.module('wm.layouts.containers')
* Width of the tabs widget.
* @param {string=} height
* Height of the tabs widget.
- * @param {boolean=} tabsposition
+ * @param {number=} defaultpaneindex
+ * Makes the tab active for given index.This property has backward compatibility for isdefaulttab property.
+ * Default value: 0
+ * @param {string=} on-change
+ * Callback function which will be triggered when the widget value is changed.
+ * @param {string=} tabsposition
* Align the tab headers to left/right/top/bottom of the content.
* Default value: `top`
* @param {string=} transition
@@ -608,10 +628,6 @@ WM.module('wm.layouts.containers')
* Show is a bindable property.
* This property will be used to show/hide the tab on the web page.
* Default value: `true`.
- * @param {boolean=} isdefaulttab
- * isdefaulttab is a bindable property.
- * First tab with `isdefaulttab = true` will be displayed by default.
- * Default value: `false`.
* @param {boolean=} show
* Show is a bindable property.
* This property will be used to show/hide the tab on the web page.
diff --git a/src/main/webapp/scripts/modules/layouts/containers/wizard/wizard.js b/src/main/webapp/scripts/modules/layouts/containers/wizard/wizard.js
index 23473a363..fcc08cadb 100644
--- a/src/main/webapp/scripts/modules/layouts/containers/wizard/wizard.js
+++ b/src/main/webapp/scripts/modules/layouts/containers/wizard/wizard.js
@@ -20,7 +20,7 @@ WM.module('wm.layouts.containers')
'
Skip »' +
'
' +
'
' +
- '
' +
- '
' +
+ '' +
'' +
'{{donebtnlabel}}' +
'' +
@@ -70,8 +70,10 @@ WM.module('wm.layouts.containers')
}
function navigateToStep($is, stepIndex) {
- $is.currentStep = $is.steps[stepIndex];
- $is.currentStep.status = STEP_STATUS.CURRENT;
+ if ($is.steps[stepIndex]) {
+ $is.currentStep = $is.steps[stepIndex];
+ $is.currentStep.status = STEP_STATUS.CURRENT;
+ }
}
return {
@@ -109,18 +111,23 @@ WM.module('wm.layouts.containers')
if (CONSTANTS.isRunMode) {
//Function to navigate to next step
$is.next = function () {
- var params = {$isolateScope: $is, currentStep: $is.currentStep, stepIndex: $is.currentStep.stepIndex};
+ var params = {$isolateScope: $is, currentStep: $is.currentStep, stepIndex: $is.currentStep.stepIndex},
+ stepIndex;
if ($is.currentStep.onNext) {
if ($is.currentStep.onNext(params) === false) {
return;
}
}
$is.currentStep.status = STEP_STATUS.COMPLETED;
- navigateToStep($is, $is.currentStep.stepIndex + 1);
+ stepIndex = $is.currentStep.stepIndex + 1;
+ stepIndex = $is.steps[stepIndex].show ? stepIndex : stepIndex + 1;
+
+ navigateToStep($is, stepIndex);
};
//Function to navigate to previous step
$is.prev = function () {
- var params;
+ var params,
+ stepIndex;
if ($is.currentStep.onPrev) {
params = {$isolateScope: $is, currentStep: $is.currentStep, stepIndex: $is.currentStep.stepIndex};
if ($is.currentStep.onPrev(params) === false) {
@@ -128,7 +135,9 @@ WM.module('wm.layouts.containers')
}
}
$is.currentStep.status = STEP_STATUS.DISABLED;
- navigateToStep($is, $is.currentStep.stepIndex - 1);
+ stepIndex = $is.currentStep.stepIndex - 1;
+ stepIndex = $is.steps[stepIndex].show ? stepIndex : stepIndex - 1;
+ navigateToStep($is, stepIndex);
};
//Function to skip current step
$is.skip = function () {
@@ -193,7 +202,7 @@ WM.module('wm.layouts.containers')
var widgetProps = PropertiesFactory.getPropertiesOf('wm.wizardstep', ['wm.base']),
STEP_STATUS = {'COMPLETED': 'COMPLETED', 'CURRENT': 'CURRENT', 'DISABLED': 'DISABLED'},
- $headerElement = '' +
+ $headerElement = '' +
'' +
'' +
' ' +
@@ -238,6 +247,7 @@ WM.module('wm.layouts.containers')
//$watch on step load ie.. step is active and trigger onLoad event
$is.$watch('status', function (nv) {
if (nv === STEP_STATUS.CURRENT) {
+ $is.__load();
if (CONSTANTS.isRunMode) {
if ($is.onLoad) {
$is.onLoad({$isolateScope: $is});
diff --git a/src/main/webapp/scripts/modules/layouts/device/styles/less/mobile.less b/src/main/webapp/scripts/modules/layouts/device/styles/less/mobile.less
index 3922ea1bc..f8dbf465d 100644
--- a/src/main/webapp/scripts/modules/layouts/device/styles/less/mobile.less
+++ b/src/main/webapp/scripts/modules/layouts/device/styles/less/mobile.less
@@ -10,7 +10,7 @@
top: 0;
&.slide-over {
left: -100%;
- z-index: 1049;
+ z-index: 1050;
&.visible {
left: 0;
@@ -45,6 +45,16 @@
left: 0;
height: 100%;
width: 100%;
+ &.left-panel-container:after {
+ background: rgba(0, 0, 0, 0.5);
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ content: "";
+ display: block;
+ z-index: 1049;
+ }
&.slide-in-left-panel-container {
position: fixed;
overflow: visible;
@@ -70,7 +80,7 @@
height: @app-mobile-nav-height !important;
width: 100%;
position: fixed;
- z-index: 1060;
+ z-index: 1049;
display: table;
top: 0;
left: 0;
@@ -124,7 +134,7 @@
/*Search widget container (available only in Mobile)*/
.app-search {
- z-index: 99999;
+ z-index: 3000;
position: fixed;
left: 0;
top: @app-mobile-nav-height;
@@ -227,9 +237,6 @@
}
- }
- .modal {
- z-index: 999999 !important;
}
.app-top-nav {
color: #999;
diff --git a/src/main/webapp/scripts/modules/layouts/page/leftpanel.js b/src/main/webapp/scripts/modules/layouts/page/leftpanel.js
index a3710344d..b5c19ddc5 100644
--- a/src/main/webapp/scripts/modules/layouts/page/leftpanel.js
+++ b/src/main/webapp/scripts/modules/layouts/page/leftpanel.js
@@ -85,6 +85,7 @@ WM.module('wm.layouts.page')
element.on(eventName, function () {
skipEvent = true;
});
+ appPage.addClass('left-panel-container');
appPage.on(eventName, function () {
if (!skipEvent) {
scope.collapse();
@@ -94,6 +95,7 @@ WM.module('wm.layouts.page')
};
scope.collapse = function () {
var appPage = element.closest('.app-page');
+ appPage.removeClass('left-panel-container');
element.removeClass('visible');
element.off(eventName);
appPage.off(eventName);
diff --git a/src/main/webapp/scripts/modules/layouts/page/page.js b/src/main/webapp/scripts/modules/layouts/page/page.js
index 3124e91a6..94c08d3db 100644
--- a/src/main/webapp/scripts/modules/layouts/page/page.js
+++ b/src/main/webapp/scripts/modules/layouts/page/page.js
@@ -52,7 +52,6 @@ WM.module('wm.layouts.page')
count,
subView,
AppManager;
-
/* if the page belongs to a prefab use the name of the prefab
* else if the project is of prefab type use `Main`
* else get the name of the page from the ng-controller attribute
@@ -315,15 +314,6 @@ WM.module('wm.layouts.page')
}
}
- /*For popover variables will not be set as init of popover will happen first and then setting variables
- so popover calls reset partial variables in case of partial content bind
- */
- $rs.$on('reset-partial-variables', function (evt, partialName) {
- if (partialName === pageName) {
- setVariables($s, containerScope, variableScope, pageName);
- }
- });
-
setVariables($s, containerScope, variableScope, pageName);
},
'post': function ($s, $el, attrs) {
@@ -333,7 +323,10 @@ WM.module('wm.layouts.page')
if (CONSTANTS.isRunMode) {
// register session timeout handler
handlers.push($rs.$on('on-sessionTimeout', function () {
- Utils.triggerFn($s.onSessionTimeout);
+ //check if 'onSessionTimeout' event is present in current partial page script
+ if ($s.hasOwnProperty('onSessionTimeout')) {
+ Utils.triggerFn($s.onSessionTimeout);
+ }
}));
/**
diff --git a/src/main/webapp/scripts/modules/layouts/page/pagecontent.js b/src/main/webapp/scripts/modules/layouts/page/pagecontent.js
index e3fd68069..1227dcaab 100644
--- a/src/main/webapp/scripts/modules/layouts/page/pagecontent.js
+++ b/src/main/webapp/scripts/modules/layouts/page/pagecontent.js
@@ -6,8 +6,14 @@ WM.module('wm.layouts.page')
$templateCache.put('template/layout/page/pagecontent.html',
''
);
+ $templateCache.put('template/layout/page/pagecontent-loader.html',
+ ''
+ );
}])
- .directive('wmPageContent', ['PropertiesFactory', 'WidgetUtilService', 'CONSTANTS', 'Utils', function (PropertiesFactory, WidgetUtilService, CONSTANTS, Utils) {
+ .directive('wmPageContent', ['$route', '$rootScope', '$templateCache', '$timeout', 'PropertiesFactory', 'WidgetUtilService', 'CONSTANTS', 'Utils', function ($route, $rootScope, $templateCache, $timeout, PropertiesFactory, WidgetUtilService, CONSTANTS, Utils) {
'use strict';
var widgetProps = PropertiesFactory.getPropertiesOf('wm.layouts.pagecontent', ['wm.layouts', 'wm.base.events.touch']),
@@ -25,6 +31,27 @@ WM.module('wm.layouts.page')
}
}
+ /*Delays transclusion for the transition and variables to load.*/
+ function waitForTransition($ele) {
+ var iScope = $ele.isolateScope(),
+ $spinnerEl;
+ $ele.addClass('load');
+ $spinnerEl = WM.element($templateCache.get('template/layout/page/pagecontent-loader.html'));
+ $spinnerEl.appendTo($ele);
+ Utils.listenOnce($rootScope, 'page-transition-end', function () {
+ iScope.__load();
+ Utils.triggerFn($ele.scope().onPagePartLoad);
+ });
+ Utils.listenOnce($rootScope, 'page-startupdate-variables-loaded', function () {
+ $timeout(function () {
+ $spinnerEl.remove();
+ $ele.removeClass('load');
+ }, 100);
+ });
+ iScope.loadmode = 'after-select';
+ Utils.triggerFn($ele.scope().registerPagePart);
+ }
+
return {
'restrict': 'E',
'replace': true,
@@ -37,17 +64,8 @@ WM.module('wm.layouts.page')
'pre': function (scope, element) {
/*Applying widget properties to directive scope*/
scope.widgetProps = widgetProps;
- if (CONSTANTS.isRunMode) {
- Utils.triggerFn(element.scope().registerPagePart);
-
- /** We do not require a delay for page dialogs. Delay is required only for pages*/
- if(!element.closest('.app-dialog').length){
- scope.loadmode = 'after-delay';
- scope.loaddelay = 100;
- }
- scope.__onTransclude = function () {
- Utils.triggerFn(element.scope().onPagePartLoad);
- };
+ if (CONSTANTS.isRunMode && $route.current && !$route.current.transitionCompleted) {
+ waitForTransition(element);
}
},
diff --git a/src/main/webapp/scripts/modules/layouts/styles/less/layouts.less b/src/main/webapp/scripts/modules/layouts/styles/less/layouts.less
index ab205a09a..331885a0a 100644
--- a/src/main/webapp/scripts/modules/layouts/styles/less/layouts.less
+++ b/src/main/webapp/scripts/modules/layouts/styles/less/layouts.less
@@ -84,12 +84,12 @@ body {
vertical-align: top;
.app-menu .app-button, .panel-action {
color: inherit;
+ outline: none;
.app-anchor {
color: inherit;
text-decoration: none;
}
a:hover {
- color: inherit;
text-decoration: none;
}
background: transparent;
@@ -124,7 +124,6 @@ body {
min-width: 100px;
.panel-help-header {
background: @app-panel-help-header-color;
- font-weight: bold;
border-bottom: 1px @app-panel-border-color solid;
padding: 0.5em;
margin: 0;
@@ -156,7 +155,7 @@ body {
}
&.fullscreen {
position: fixed;
- z-index: 10000;
+ z-index: 1049;
left: 0.2em;
right: 0.2em;
top: 0.2em;
@@ -173,6 +172,11 @@ body {
}
}
}
+.app-dialog {
+ .app-panel.fullscreen {
+ height: 95vh;
+ }
+}
.app-panel-footer {
position: relative;
}
@@ -423,6 +427,7 @@ body {
#wm-app-content , .app-page, .app-partial, .app-included-page {
.width-height();
position: relative;
+ background-color: inherit;
}
/*********************************************************************************************************************/
/***********************************overriding the bootstrap styles*************************************************/
@@ -462,6 +467,7 @@ body {
}
}
/*********************application content********************/
+ @app-page-content-loader-fg-color: rgba(0,0,0,0.5);
.app-content {
position: relative;
.width-height();
@@ -469,7 +475,7 @@ body {
float: none; /**added to support bootstrap col-*-* classes**/
margin-left: auto;
margin-right: auto;
- background-color: #fff;
+ background-color: inherit;
.app-content-row {
.width-height();
position: relative;
@@ -497,6 +503,18 @@ body {
}
}
}
+ .app-page-content {
+ > .app-ng-transclude {
+ opacity: 1;
+ transition: opacity 0.5s ease-in-out;
+ }
+ &.load {
+ overflow: hidden;
+ > .app-ng-transclude {
+ opacity: 0;
+ }
+ }
+ }
}
/*********************application content vertical scroll fix********************/
.app-top-nav + .app-content {
@@ -529,6 +547,14 @@ body {
text-align: left;
}
}
+ .app-left-panel, .app-right-panel {
+ .nav li {
+ .badge {
+ right: 1em;
+ top: 1em;
+ }
+ }
+ }
/*********************application right panel********************/
.app-right-panel {
height: 100%;
@@ -645,7 +671,7 @@ body {
> .panel-body {
padding: 4px 4px 0 4px;
}
- .app-label, .app-anchor {
+ .app-label {
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
@@ -654,43 +680,7 @@ body {
font-size: 0.8em;
padding: 0 1.25em;
}
- &.align-left .app-label {
- text-align: left;
- }
- &.align-center {
- .app-label {
- text-align: center;
- }
- &.position-top {
- text-align: center;
- .form-control {
- text-align: center;
- }
- }
- .form-control-static + .form-control {
- width: 100%;
- }
- .input-group, .app-blob-upload {
- display: inline-table;
- }
- }
- &.align-right {
- .app-label {
- text-align: right;
- }
- &.position-top {
- direction: rtl;
- }
- }
- &.position-left {
- direction: ltr;
- }
- &.position-right {
- direction: rtl;
- label {
- float: right;
- }
- }
+
input:focus.ng-invalid {
border-color: crimson;
}
@@ -749,85 +739,107 @@ body {
height: 1px;
}
}
-
- .app-form {
- &.position-top {
- .control-label {
- display: block;
- width: 100%;
+ /****************Alignment and position classes******************************/
+ .app-form, .app-liveform, .app-device-liveform, .app-livefilter {
+ /****************Caption Align Right******************************/
+ &.align-right {
+ .app-label {
+ text-align: right;
+ }
+ .caption-top {
+ .form-control, .app-toggle, .app-ratings, .input-group, .app-checkboxset, .app-radioset, .app-checkbox {
+ float: right;
+ }
+ }
+ .app-checkboxset .app-checkbox, .app-radioset .app-radio {
+ float: none;
+ label {
+ text-align: left;
+ }
}
}
- }
-
- .app-liveform-dialog {
- .app-dialog-body {
- padding: 0;
- }
- }
- /************** Composite Widget - Caption Position Styles ****************/
- .caption-left, .caption-right {
- > .app-currency, > .app-colorpicker {
- direction: inherit; // To maintain positions of currency ($) on left hand side and text box on right hand side
+ /****************Caption Align Middle******************************/
+ &.align-center {
+ .app-label {
+ text-align: center;
+ }
+ .caption-top {
+ text-align: center;
+ .form-control {
+ text-align: center;
+ width: 100%;
+ }
+ }
+ .input-group, .app-blob-upload {
+ display: inline-table;
+ }
}
- }
- .caption-left {
- > * {
- direction: ltr;
- float: left;
+ /************** Fixing widgets when Position Right is applied on the parent ****************/
+
+ .app-checkboxset, .app-radioset {
+ margin-bottom:0;
+ }
+ /*To remove the animation caused by ng-show/ng-hide*/
+ .ng-hide-add, .ng-hide-remove {
+ transition: 0s linear all;
}
}
- .caption-right {
- > * {
- direction: rtl;
- float: right;
- left: auto; // To override col-md-push-2 inherited from bootstrap
+ .app-liveform-dialog {
+ .app-dialog-body {
+ padding: 0;
}
}
-
- .caption-top {
- > .app-label {
+ /****************Caption Position top do not remove for old projects******************************/
+ [captionposition="top"]{
+ .control-label {
width: 100%;
}
}
- /************** Composite Widget - Caption Position Styles(to override style inside form) ****************/
- .app-form, .app-liveform, .app-livefilter {
-
- .caption-left.app-composite-widget, .caption-right.app-composite-widget {
- > .app-currency, > .app-colorpicker {
- direction: inherit; // To maintain positions of currency ($) on left hand side and text box on right hand side
+ /*******Caption Styling in the composite widget********/
+ .app-composite-widget {
+ &.caption-right {
+ .form-control, .input-group, .app-ratings, .app-toggle, .app-switch, .app-fileupload, .app-button-wrapper, .control-label, .app-checkbox, .app-checkboxset, .app-radioset {
+ float: right;
}
- }
-
-
- .app-checkboxset, .app-radioset {
- margin-bottom:0;
- }
-
- .caption-left.app-composite-widget {
- > * {
- float: left;
+ .app-checkboxset .app-checkbox, .app-radioset .app-radio {
+ float: none;
+ label {
+ text-align: left;
+ }
+ }
+ //Datetime, date & time widgets
+ .app-datetime, .app-date, .app-timeinput {
+ .dropdown-menu {
+ left: 0 !important; /*!important is used to overwrite the inline styles*/
+ white-space: normal; /*In order to prevent the UI from breaking*/
+ }
}
- }
- .caption-right.app-composite-widget {
- > * {
- float: right;
- left: auto; // To override col-md-push-2 inherited from bootstrap
+ //Tab Widget
+ .app-tabs {
+ .nav {
+ &.nav-tabs {
+ text-align: right;
+ }
+ }
}
- }
- .caption-top.app-composite-widget {
- > .app-label {
- width: 100%;
+ .app-slider {
+ text-align: right; /*IE9 support*/
+ .range-input {
+ margin-top: 0.5em;
+ }
}
}
- /*To remove the animation caused by ng-show/ng-hide*/
- .ng-hide-add, .ng-hide-remove {
- transition: 0s linear all;
+ &.caption-top {
+ .control-label {
+ width:100%
+ }
}
}
+
.app-search {
.app-textbox.ng-hide-animate {
display: none !important;
@@ -872,6 +884,30 @@ body {
animation: @name @duration ease-in;
}
+ @-webkit-keyframes toAndFro{
+ 0%{
+ -webkit-transform : translate3d(0, 0, 0);
+ }
+ 50% {
+ -webkit-transform : translate3d(1000%, 0, 0);
+ }
+ 100%{
+ -webkit-transform : translate3d(0, 0, 0);
+ }
+ }
+
+ @keyframes toAndFro {
+ from {
+ transform: translate3d(0, 0, 0);
+ }
+ 50% {
+ transform: translate3d(100vw, 0, 0);
+ }
+ to {
+ transform: translate3d(0, 0, 0);
+ }
+ }
+
.wmScaleInLeft {
.animation('wmScaleInLeft', 0.3s);
}
@@ -1059,6 +1095,19 @@ body {
}
}
+ @-webkit-keyframes flipEntry {
+ 0% {
+ opacity: 0;
+ -webkit-transform: perspective(1000px) rotateY(180deg);
+ }
+ 50%{opacity: 0;}
+ 51% {opacity : 1;}
+ 100% {
+ opacity : 1;
+ -webkit-transform: perspective(1000px) rotateY(0deg);
+ }
+ }
+
@keyframes flipEntry {
0% {
opacity: 0;
@@ -1072,6 +1121,19 @@ body {
}
}
+ @-webkit-keyframes flipExit {
+ 0% {
+ opacity: 1;
+ -webkit-transform: perspective(1000px) rotateY(0deg);
+ }
+ 50%{opacity: 1;}
+ 51% {opacity : 0;}
+ 100% {
+ opacity : 0;
+ -webkit-transform: perspective(1000px) rotateY(-180deg);
+ }
+ }
+
@keyframes flipExit {
0% {
opacity: 1;
@@ -1085,6 +1147,18 @@ body {
}
}
+ @-webkit-keyframes flipReverseEntry {
+ 0% {
+ opacity: 0;
+ -webkit-transform: perspective(1000px) rotateY(-180deg);
+ }
+ 50%{opacity: 0;}
+ 51% {opacity : 1;}
+ 100% {
+ opacity : 1;
+ -webkit-transform: perspective(1000px) rotateY(0deg);
+ }
+ }
@keyframes flipReverseEntry {
0% {
opacity: 0;
@@ -1098,6 +1172,19 @@ body {
}
}
+ @-webkit-keyframes flipReverseExit {
+ 0% {
+ opacity: 1;
+ -webkit-transform: perspective(1000px) rotateY(0deg);
+ }
+ 50%{opacity: 1;}
+ 51% {opacity : 0;}
+ 100% {
+ opacity : 0;
+ -webkit-transform: perspective(1000px) rotateY(180deg);
+ }
+ }
+
@keyframes flipReverseExit {
0% {
opacity: 1;
@@ -1112,79 +1199,95 @@ body {
}
#wm-app-content {
- +.ng-enter, &.ng-leave{
- position: fixed;
- top: 0;
- left: 0;
- -webkit-backface-visibility: visible !important;
- -ms-backface-visibility: visible !important;
- backface-visibility: visible !important;
- animation-duration: 0.5s;
- animation-timing-function: linear;
- -webkit-animation-fill-mode: forwards;
- animation-fill-mode: forwards;
-
- > .app-page >.app-left-panel {
+ >.page-transition {
+ &.app-page, +.app-page {
+ position: fixed;
+ top: 0;
+ left: 0;
+ -webkit-backface-visibility: visible !important;
+ -ms-backface-visibility: visible !important;
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+ -webkit-animation-duration: 0.3s;
+ animation-duration: 0.3s;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ -webkit-animation-fill-mode: forwards;
+ animation-fill-mode: forwards;
+ }
+ > .app-page > .app-left-panel {
display: none;
}
}
- &.page-transition-slide {
- &.ng-leave {
+ >.page-transition-slide {
+ &.ng-leave-active {
+ -webkit-animation-name: slideOutLeft;
animation-name: slideOutLeft;
}
- +.ng-enter {
+ +.ng-enter-active {
+ -webkit-animation-name: slideInRight;
animation-name: slideInRight;
}
}
- &.page-transition-slide-exit {
- &.ng-leave {
+ >.page-transition-slide-exit {
+ &.ng-leave-active {
+ -webkit-animation-name: slideOutRight;
animation-name: slideOutRight;
}
- +.ng-enter {
+ +.ng-enter-active {
+ -webkit-animation-name: slideInLeft;
animation-name: slideInLeft;
}
}
/** popup **/
- &.page-transition-pop +.ng-enter {
+ >.page-transition-pop +.ng-enter {
+ -webkit-animation-name: zoomIn;
animation-name: zoomIn ;
}
- &.page-transition-pop-exit {
- &.ng-leave {
+ >.page-transition-pop-exit {
+ &.ng-leave-active {
z-index: 1;
+ -webkit-animation-name: zoomOut;
animation-name: zoomOut;
}
- &.ng-enter {
+ &.ng-enter-active {
z-index: 0;
}
}
- &.page-transition-flip {
- &.ng-leave {
+ >.page-transition-flip {
+ &.ng-leave-active {
+ -webkit-animation-name: flipExit;
animation-name: flipExit;
}
- +.ng-enter {
+ +.ng-enter-active {
+ -webkit-animation-name: flipEntry;
animation-name: flipEntry;
}
}
- &.page-transition-flip-exit {
- &.ng-leave {
+ >.page-transition-flip-exit {
+ &.ng-leave-active {
+ -webkit-animation-name: flipReverseExit;
animation-name: flipReverseExit;
}
- +.ng-enter {
+ +.ng-enter-active {
+ -webkit-animation-name: flipReverseEntry;
animation-name: flipReverseEntry;
}
}
/** fade **/
- &.page-transition-fade +.ng-enter {
+ >.page-transition-fade +.ng-enter-active {
+ -webkit-animation-name: fadeIn;
animation-name: fadeIn;
}
- &.page-transition-fade-exit.ng-leave {
+ >.page-transition-fade-exit.ng-leave-active {
+ -webkit-animation-name: fadeOut;
animation-name: fadeOut;
z-index: 1;
}
@@ -1199,6 +1302,9 @@ body {
.item{
overflow : hidden;
height : 100%;
+ img {
+ width: 100%;
+ }
}
}
&.carousel {
@@ -1359,7 +1465,7 @@ body {
padding: 0;
text-align: center;
&:hover {
- color: initial;
+ color: inherit;
}
}
.btn {
@@ -1377,7 +1483,6 @@ body {
width: 42pt;
box-shadow: rgba(0, 0, 0, 0.117647) 0 1px 2px 0, rgba(0, 0, 0, 0.239216) 0 1px 1px 0;
border-radius: 500px;
- overflow: hidden;
padding: 0;
}
&.btn-raised {
@@ -1399,11 +1504,6 @@ body {
> .btn-caption, > .anchor-caption {
display: block;
}
- .badge {
- top: -10pt;
- right: -10pt;
- font-weight: normal;
- }
}
/********for buttons, anchors with icon on right****/
.btn[icon-position = "right"], a[icon-position = "right"] {
@@ -1411,8 +1511,10 @@ body {
}
/****Badge****/
.btn .badge, a .badge {
- right: -10px;
- top: -10px;
+ right: -1em;
+ top: -1em;
+ font-weight: normal;
+ z-index: 3;
&.btn-link {
top: 0;
right: 0;
@@ -1441,86 +1543,8 @@ body {
margin-top: 0;
}
- /************** Fixing widgets when Position Right is applied on the parent ****************/
- .position-right {
- //Switch widget
- .app-switch {
- float: right;
- .btn-group {
- direction: ltr;
- }
- }
-
- .app-search {
- &.input-group {
- .form-control {
- float: right;
- }
- }
- }
-
- //Common styles for Radio, Checkbox, Radioset & Checkboxset widgets
- .app-radioset, .app-checkboxset {
- direction: ltr;
- }
-
- .radio, .checkbox, .radio-inline, .checkbox-inline {
- label {
- text-align: right;
- }
-
- .caption {
- margin-right: 1.5em;
- }
-
- input[type="radio"], input[type="checkbox"] {
- right: 0;
- }
-
- //Reset position from left hand side
- &.col-md-push-3 {
- left: 0;
- }
- }
- //Datetime, date & time widgets
- .app-datetime, .app-date, .app-timeinput {
- .dropdown-menu {
- left: 0 !important; /*!important is used to overwrite the inline styles*/
- white-space: normal; /*In order to prevent the UI from breaking*/
- }
- }
-
- //Tab Widget
- .app-tabs {
- .nav {
- &.nav-tabs {
- text-align: right;
- }
- }
- }
-
- .app-toggle {
- float: right;
- }
-
- .app-slider {
- text-align: right; /*IE9 support*/
- .range-input {
- margin-top: 0.5em;
- }
- }
-
- .app-fileupload {
- float: right;
-
- .app-button-wrapper {
- float: right;
- }
- }
- }
.p {
width: 100%;
- color: inherit;
word-wrap: break-word;
}
.h1,.h2,.h3,.h4,.h5,.h6 {
@@ -1529,20 +1553,23 @@ body {
.inline {
display: inline;
}
+ .bold {
+ font-weight: bold;
+ }
.bordered {
- border: 1px solid rgb(0,0,0,0.2);
+ border: 1px solid rgba(0,0,0,0.2);
}
.bordered-left {
- border-left: 1px solid rgb(0,0,0,0.2);
+ border-left: 1px solid rgba(0,0,0,0.2);
}
.bordered-right {
- border-right: 1px solid rgb(0,0,0,0.2);
+ border-right: 1px solid rgba(0,0,0,0.2);
}
.bordered-top {
- border-top: 1px solid rgb(0,0,0,0.2);
+ border-top: 1px solid rgba(0,0,0,0.2);
}
.bordered-bottom {
- border-bottom: 1px solid rgb(0,0,0,0.2);
+ border-bottom: 1px solid rgba(0,0,0,0.2);
}
.vertical-align-top {
vertical-align: top;
@@ -1570,6 +1597,12 @@ body {
overflow: inherit;
}
}
+ .panel-heading {
+ .description:not(:empty) {
+ font-size: .75em;
+ margin-top: 5px;
+ }
+ }
//Angular UI bootstrap 1.1.0 related styles.
.ng-animate.item:not(.left):not(.right){-webkit-transition:0s ease-in-out left;transition:0s ease-in-out left};
.uib-datepicker .uib-title{width:100%;}
diff --git a/src/main/webapp/scripts/modules/layouts/styles/less/mobile-layouts.less b/src/main/webapp/scripts/modules/layouts/styles/less/mobile-layouts.less
index ca2968abb..4355bd121 100644
--- a/src/main/webapp/scripts/modules/layouts/styles/less/mobile-layouts.less
+++ b/src/main/webapp/scripts/modules/layouts/styles/less/mobile-layouts.less
@@ -7,6 +7,10 @@
@app-mobile-tabbar-active-item-bg-color: rgba(0,0,0,0.1);
@app-mobile-nav-searchinput-border: #fff;
@app-mobile-nav-button-padding: (@app-mobile-nav-height - @app-mobile-nav-font-size)/2;
+ /*****Removing outline*****/
+ * {
+ outline: none !important;
+ }
/********************************************************************************
*************************************** Mobile Left Panel ***********************
*********************************************************************************/
@@ -160,7 +164,6 @@
}
.navbar {
- background-color: inherit;
border: 0;
margin: 0;
min-height: 0;
@@ -190,21 +193,6 @@
}
.navbar-nav {
margin: auto;
- background-color: inherit;
- > li {
- height: @app-mobile-nav-height;
- > .app-menu, > .app-popover {
- > a {
- line-height: @app-mobile-nav-height;
- text-decoration: none;
- background-color: transparent;
- color: inherit;
- }
- .caret {
- display: none;
- }
- }
- }
.btn-back > * {
vertical-align: middle;
}
@@ -214,22 +202,19 @@
&.navbar-right {
text-align: right;
.dropdown {
- background-color: inherit;
> .app-button, > a {
- background-color: transparent;
font-size: inherit;
padding: 0 5pt;
line-height: @app-mobile-nav-height;
- color: inherit;
border: 0;
}
.dropdown-menu {
position: absolute;
- background-color: inherit;
right: 0;
left: auto;
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
+ background-color: #fff;
> li > a {
- color: inherit;
&:hover {
background-color: rgba(0,0,0,0.1);
}
@@ -240,8 +225,18 @@
> li {
display: inline-block;
vertical-align: top;
- background-color: inherit;
white-space: nowrap;
+ height: @app-mobile-nav-height;
+ > .app-menu, > .app-popover {
+ > a {
+ line-height: @app-mobile-nav-height;
+ text-decoration: none;
+ color: inherit;
+ }
+ .caret {
+ display: none;
+ }
+ }
i {
font-size: @app-mobile-nav-icon-size;
vertical-align: middle;
diff --git a/src/main/webapp/scripts/modules/mobile/common/services/deviceService.js b/src/main/webapp/scripts/modules/mobile/common/services/deviceService.js
index 693843b27..9a13c01a6 100644
--- a/src/main/webapp/scripts/modules/mobile/common/services/deviceService.js
+++ b/src/main/webapp/scripts/modules/mobile/common/services/deviceService.js
@@ -8,15 +8,18 @@
* The 'wm.modules.wmCommon.services.$DeviceService' provides high-level API to interact with device.
*/
wm.modules.wmCommon.services.DeviceService = [
+ '$document',
'$q',
+ '$rootScope',
'Utils',
//This is required for initialization
'OfflineSecurityService',
- function ($q, Utils) {
+ function ($document, $q, $rootScope, Utils) {
'use strict';
var isDeviceReady = true,
isDeviceReadyEventListeners = [],
+ backBtnTapListeners = [],
waitingFor = {};
function triggerListeners(listeners) {
@@ -69,4 +72,35 @@ wm.modules.wmCommon.services.DeviceService = [
}
return d.promise;
};
+
+ $document.on('backbutton', function () {
+ _.forEach(backBtnTapListeners, function (fn) {
+ return !(fn() === false);
+ });
+ $rootScope.$safeApply($rootScope);
+ });
+ /**
+ *
+ * @ngdoc method
+ * @name wm.modules.wmCommon.services.$DeviceService#onBackButtonTap
+ * @methodOf wm.modules.wmCommon.services.$DeviceService
+ * @description
+ * When back button on android devices is tapped, then this function will invoke the given callback. The
+ * registered callbacks are invoked in reverse chronological order. A callback can stop propagation by
+ * returning boolean false.
+ *
+ * @param {Function} fn callback function to invoke.
+ * @returns {Function} a function to call to deregister
+ */
+ this.onBackButtonTap = function (fn) {
+ backBtnTapListeners.splice(0, 0, fn);
+ return function () {
+ var i = _.findIndex(backBtnTapListeners, function (v) {
+ return v === fn;
+ });
+ if (i >= 0) {
+ backBtnTapListeners.splice(i, 1);
+ }
+ };
+ };
}];
\ No newline at end of file
diff --git a/src/main/webapp/scripts/modules/mobile/layouts/containers/navbar/navbar.js b/src/main/webapp/scripts/modules/mobile/layouts/containers/navbar/navbar.js
index 967ba7058..c2dde44b0 100644
--- a/src/main/webapp/scripts/modules/mobile/layouts/containers/navbar/navbar.js
+++ b/src/main/webapp/scripts/modules/mobile/layouts/containers/navbar/navbar.js
@@ -52,7 +52,7 @@ WM.module('wm.layouts.containers')
'' +
'' +
'
' +
- '' +
+ '' +
'
' +
'
' +
'
' +
@@ -92,7 +92,6 @@ WM.module('wm.layouts.containers')
var $searchEle = $el.find('.app-mobile-search'),
$searchElScope = $searchEle.isolateScope();
- $is.query = $searchElScope.query;
$is.datavalue = $searchElScope.datavalue;
if ($is.onSearch) {
$is.onSearch({$event: event, $scope: $is});
@@ -172,11 +171,19 @@ WM.module('wm.layouts.containers')
'transclude': true,
'template' : $templateCache.get('template/layouts/containers/mobile/navbar.html'),
'link' : {
- 'pre' : function ($is) {
+ 'pre' : function ($is, $el) {
// Applying widget properties to directive scope
$is.widgetProps = widgetProps;
$is.showSearchbar = false;
$is.readonlySearchBar = CONSTANTS.isStudioMode ? true : false;
+
+ var $s = $el.scope();
+
+ Object.defineProperty($is, 'Variables', {
+ get: function () {
+ return $s.Variables;
+ }
+ });
},
'post': function ($is, $el, attrs) {
$is.leftNavPanel = ($el.closest('.app-page').find('.app-left-panel:first')).isolateScope();
diff --git a/src/main/webapp/scripts/modules/mobile/layouts/containers/segmented/segmented.js b/src/main/webapp/scripts/modules/mobile/layouts/containers/segmented/segmented.js
index 83827cc7b..d2fc106cf 100644
--- a/src/main/webapp/scripts/modules/mobile/layouts/containers/segmented/segmented.js
+++ b/src/main/webapp/scripts/modules/mobile/layouts/containers/segmented/segmented.js
@@ -23,10 +23,7 @@ WM.module('wm.layouts.containers')
var widgetProps = PropertiesFactory.getPropertiesOf('wm.layouts.segmentedcontrol', ['wm.base']);
return {
'restrict' : 'E',
- 'scope' : {
- 'onBeforesegmentchange' : '&',
- 'onSegmentchange' : '&'
- },
+ 'scope' : {},
'replace' : 'true',
'transclude': true,
'template' : $templateCache.get('template/widget/mobile/segmentedcontrol/segmentedcontrol.html'),
diff --git a/src/main/webapp/scripts/modules/mobile/layouts/containers/tabbar/tabbar.js b/src/main/webapp/scripts/modules/mobile/layouts/containers/tabbar/tabbar.js
index 5a0fb8a0a..330706b88 100644
--- a/src/main/webapp/scripts/modules/mobile/layouts/containers/tabbar/tabbar.js
+++ b/src/main/webapp/scripts/modules/mobile/layouts/containers/tabbar/tabbar.js
@@ -119,7 +119,6 @@ WM.module('wm.layouts.containers')
return {
'scope' : {
- 'onSelect': '&',
'menutype': '&',
'position': '&'
},
diff --git a/src/main/webapp/scripts/modules/mobile/layouts/page/leftpanel.js b/src/main/webapp/scripts/modules/mobile/layouts/page/leftpanel.js
index 6631e561b..18cbe35db 100644
--- a/src/main/webapp/scripts/modules/mobile/layouts/page/leftpanel.js
+++ b/src/main/webapp/scripts/modules/mobile/layouts/page/leftpanel.js
@@ -1,14 +1,24 @@
/*global WM*/
/* This is an override to the existing leftpanel directive*/
WM.module('wm.layouts.page')
- .directive('wmLeftPanel', [function (){
+ .directive('wmLeftPanel', ['DeviceService', function (DeviceService){
'use strict';
return {
restrict : 'E',
priority : 1,
link : function ($scope, $ele) {
+ var backButtonListenerDeregister;
$ele.addClass('wm-mobile-app-left-panel');
+ backButtonListenerDeregister = DeviceService.onBackButtonTap(function () {
+ if ($ele.hasClass('visible')) {
+ $ele.isolateScope().collapse();
+ return false;
+ }
+ });
+ $scope.$on('$destroy', function () {
+ backButtonListenerDeregister();
+ });
}
};
}]);
\ No newline at end of file
diff --git a/src/main/webapp/scripts/modules/mobile/layouts/page/page.js b/src/main/webapp/scripts/modules/mobile/layouts/page/page.js
index 73a33a74c..0a60b16e1 100644
--- a/src/main/webapp/scripts/modules/mobile/layouts/page/page.js
+++ b/src/main/webapp/scripts/modules/mobile/layouts/page/page.js
@@ -1,18 +1,24 @@
/*global WM*/
/* This is an override to the existing leftpanel directive*/
WM.module('wm.layouts.page')
- .directive('wmPage', [function (){
+ .directive('wmPage', [function () {
'use strict';
return {
restrict : 'E',
priority : 1,
- link : function ($scope, $ele) {
- $ele.addClass('mobile-app-page');
- /**fnding the tabbar so that we can adjust the layout**/
- if ($ele.find('[data-role="mobile-tabbar"]').length > 0 ) {
- $ele.addClass("has-tabbar");
- }
+ compile : function () {
+ return {
+ 'pre' : function ($scope, $ele) {
+ $ele.addClass('mobile-app-page');
+ },
+ 'post': function ($scope, $ele) {
+ // finding the tabbar so that we can adjust the layout
+ if ($ele.find('[data-role="mobile-tabbar"]').length > 0) {
+ $ele.addClass("has-tabbar");
+ }
+ }
+ };
}
};
}]);
\ No newline at end of file
diff --git a/src/main/webapp/scripts/modules/mobile/plugins/database/services/localDBManager.js b/src/main/webapp/scripts/modules/mobile/plugins/database/services/localDBManager.js
index eab631068..1131322d8 100644
--- a/src/main/webapp/scripts/modules/mobile/plugins/database/services/localDBManager.js
+++ b/src/main/webapp/scripts/modules/mobile/plugins/database/services/localDBManager.js
@@ -1,4 +1,4 @@
-/*global wm, WM, _, window*/
+/*global wm, WM, _, window, moment*/
/*jslint sub: true, unparam:true*/
/**
@@ -16,8 +16,11 @@ wm.plugins.database.services.LocalDBManager = [
'BaseService',
'DatabaseService',
'DeviceFileService',
+ 'LocalKeyValueService',
'LocalDBStoreFactory',
'OFFLINE_WAVEMAKER_DATABASE_SCHEMA',
+ 'SecurityService',
+ '$timeout',
'Utils',
function ($cordovaFile,
$cordovaNetwork,
@@ -27,8 +30,11 @@ wm.plugins.database.services.LocalDBManager = [
BaseService,
DatabaseService,
DeviceFileService,
+ LocalKeyValueService,
LocalDBStoreFactory,
OFFLINE_WAVEMAKER_DATABASE_SCHEMA,
+ SecurityService,
+ $timeout,
Utils) {
'use strict';
var META_LOCATION = 'www/metadata/app',
@@ -37,8 +43,45 @@ wm.plugins.database.services.LocalDBManager = [
dbInstallDirectory,
dbInstallDirectoryName,
databases,
- connectivityChecker;
-
+ connectivityChecker,
+ lastPullInfoKey = 'localDBManager.lastPullInfo',
+ systemProperties;
+ systemProperties = {
+ 'USER_ID' : {
+ 'name' : 'USER_ID',
+ 'value' : function () {
+ var defer = $q.defer();
+ SecurityService.getUserId(defer.resolve, defer.reject);
+ return defer.promise;
+ }
+ },
+ 'USER_NAME' : {
+ 'name' : 'USER_NAME',
+ 'value' : function () {
+ var defer = $q.defer();
+ SecurityService.getUserName(defer.resolve, defer.reject);
+ return defer.promise;
+ }
+ },
+ 'DATE_TIME' : {
+ 'name' : 'DATE_TIME',
+ 'value' : function () {
+ return moment().format('YYYY-MM-DDThh:mm:ss');
+ }
+ },
+ 'DATE' : {
+ 'name' : 'CURRENT_DATE',
+ 'value' : function () {
+ return moment().format('YYYY-MM-DD');
+ }
+ },
+ 'TIME' : {
+ 'name' : 'TIME',
+ 'value' : function () {
+ return moment().format('hh:mm:ss');
+ }
+ }
+ };
if (cordova) {
if (Utils.isIOS()) {
dbInstallDirectoryName = 'LocalDatabase';
@@ -126,14 +169,27 @@ wm.plugins.database.services.LocalDBManager = [
_.forEach(queriesByDB.queries, function (queryData) {
var query, params;
if (queryData.nativeSql && !queryData.update) {
- query = queryData.query;
+ query = queryData.queryString;
params = _.map(query.match(/:[a-zA-Z0-9]+\s?/g), function (p) {
- return _.trim(p.substring(1));
+ var paramObj;
+ p = _.trim(p.substring(1));
+ paramObj = _.find(queryData.parameters, {'name' : p});
+ return {
+ 'name' : paramObj.name,
+ 'type' : paramObj.type,
+ 'variableType' : paramObj.variableType
+ };
});
queries[queryData.name] = {
name: queryData.name,
query: query.replace(/:[a-zA-Z0-9]+\s?/g, '? '),
- params: params
+ params: params,
+ response : {
+ properties: _.map(queryData.response.properties, function (p) {
+ p.nameInUpperCase = p.name.toUpperCase();
+ return p;
+ })
+ }
};
}
});
@@ -336,30 +392,78 @@ wm.plugins.database.services.LocalDBManager = [
* Clears and pulls data (other than 'BUNDLED') from server using the configured rules in offline configuration.
* Before clearing data, it is checked whether connection can be made to server.
*
+ * @param {boolean} clear if true, then data (other than 'BUNDLED') in the database will be deleted.
* @returns {object} a promise.
*/
- this.pullData = function () {
- return canConnectToServer()
+ this.pullData = function (clear) {
+ var defer = $q.defer(),
+ data = {
+ 'completedTaskCount' : 0,
+ 'totalTaskCount' : 0,
+ 'inProgress' : true
+ },
+ pullInfo = {
+ 'databases' : [],
+ 'totalPulledRecordCount' : 0
+ };
+ SecurityService.onUserLogin()
+ .then(canConnectToServer)
.then(function () {
- // clears all data other than BUNDLED data
- var promises = [];
- iterateExternalEntities(function (database, entity) {
- if (entity.syncType !== 'BUNDLED') {
- promises.push(database.stores[entity.entityName].clear());
- }
- });
- return $q.all(promises);
+ if (clear) {
+ // clears all data other than BUNDLED data
+ var promises = [];
+ iterateExternalEntities(function (database, entity) {
+ if (entity.syncType !== 'BUNDLED') {
+ promises.push(database.stores[entity.entityName].clear());
+ }
+ });
+ return $q.all(promises);
+ }
})
.then(function () {
// Pull data
var promises = [];
+ pullInfo.startTime = _.now();
iterateExternalEntities(function (database, eSchema) {
if (eSchema.syncType === 'APP_START') {
- promises.push(pullDataFromServer(database.schema.name, eSchema));
+ promises.push(pullDataFromServer(database.schema.name, eSchema).then(function (response) {
+ var pullDatabaseInfo = _.find(pullInfo.databases, {'name' : database.schema.name});
+ if (!pullDatabaseInfo) {
+ pullDatabaseInfo = {
+ 'name' : database.schema.name,
+ 'entities' : [],
+ 'pulledRecordCount' : 0
+ };
+ pullInfo.databases.push(pullDatabaseInfo);
+ }
+ pullDatabaseInfo.entities.push({
+ 'entityName' : eSchema.entityName,
+ 'pulledRecordCount' : response.totalElements
+ });
+ pullInfo.totalPulledRecordCount += response.totalElements;
+ data.completedTaskCount++;
+ defer.notify(data);
+ }));
}
});
+ data.totalTaskCount = promises.length;
return $q.all(promises);
+ }).then(function () {
+ //after successful pull, store metrics and resolve the promise.
+ pullInfo.endTime = _.now();
+ _.forEach(pullInfo.databases, function (database) {
+ database.pulledRecordCount = _.reduce(database.entities, function (sum, entity) {
+ return sum + entity.pulledRecordCount;
+ }, 0);
+ });
+ LocalKeyValueService.put(lastPullInfoKey, pullInfo);
+ data.inProgress = false;
+ defer.resolve(data);
+ }, function () {
+ data.inProgress = false;
+ defer.reject(data);
});
+ return defer.promise;
};
/**
@@ -431,6 +535,38 @@ wm.plugins.database.services.LocalDBManager = [
});
}
+ function openDatabase(dbMetadata) {
+ var deferredDBCall = $q.defer(),
+ storePromises = [],
+ database = _.extend({}, dbMetadata);
+ database.connection = window.sqlitePlugin.openDatabase({
+ name: database.schema.name + '.db',
+ location: 'default'
+ }, deferredDBCall.resolve, deferredDBCall.reject);
+ database.stores = {};
+ return deferredDBCall.promise.then(function () {
+ _.forEach(database.schema.entities, function (entitySchema) {
+ storePromises.push(LocalDBStoreFactory.createStore(database.connection, entitySchema));
+ });
+ return $q.all(storePromises).then(function (stores) {
+ _.forEach(stores, function (store) {
+ database.stores[store.schema.entityName] = store;
+ });
+ return database;
+ });
+ });
+ }
+
+ function closeDatabases() {
+ var closePromises = [];
+ _.forEach(databases, function (database) {
+ var defer = $q.defer();
+ database.connection.close(defer.resolve, defer.reject);
+ closePromises.push(defer.promise);
+ });
+ return $q.all(closePromises);
+ }
+
/**
* @ngdoc method
* @name wm.plugins.database.services.$LocalDBManager#canConnectToServer
@@ -445,6 +581,26 @@ wm.plugins.database.services.LocalDBManager = [
*/
this.canConnectToServer = canConnectToServer;
+ /**
+ * @ngdoc method
+ * @name wm.plugins.database.services.$LocalDBManager#close
+ * @methodOf wm.plugins.database.services.$LocalDBManager
+ *
+ *
+ * @description
+ * Closes all databases.
+ *
+ * @returns {object} a promise.
+ */
+ this.close = function () {
+ var defer = $q.defer();
+ //Before closing databases, give some time for the pending transactions (if any).
+ $timeout(function () {
+ closeDatabases().then(defer.resolve, defer.reject);
+ }, 1000);
+ return defer.promise;
+ };
+
/**
* @ngdoc method
* @name wm.plugins.database.services.$LocalDBManager#loadDatabases
@@ -457,7 +613,8 @@ wm.plugins.database.services.LocalDBManager = [
* @returns {object} a promise.
*/
this.loadDatabases = function () {
- var d = $q.defer();
+ var d = $q.defer(),
+ self = this;
if (databases) {
d.resolve(databases);
} else {
@@ -469,26 +626,12 @@ wm.plugins.database.services.LocalDBManager = [
.then(function (metadata) {
var dbPromises = [];
_.forEach(metadata, function (dbMetadata) {
- var dbPromise,
- storePromises = [],
- database = _.extend({}, dbMetadata);
- database.connection = $cordovaSQLite.openDB({
- name: database.schema.name + '.db',
- location: 'default'
- });
- database.stores = {};
- _.forEach(database.schema.entities, function (entitySchema) {
- storePromises.push(LocalDBStoreFactory.createStore(database.connection, entitySchema));
- });
- dbPromise = $q.all(storePromises).then(function (stores) {
- _.forEach(stores, function (store) {
- database.stores[store.schema.entityName] = store;
- });
- databases[database.schema.name] = database;
- });
- dbPromises.push(dbPromise);
+ dbPromises.push(openDatabase(dbMetadata).then(function (database) {
+ databases[dbMetadata.schema.name] = database;
+ }));
});
- $q.all(dbPromises).then(function (dbs) {
+ $q.all(dbPromises).then(function () {
+ LocalKeyValueService.init(self.getStore('wavemaker', 'key-value'));
d.resolve(databases);
});
});
@@ -509,21 +652,50 @@ wm.plugins.database.services.LocalDBManager = [
* @returns {object} a promise.
*/
this.executeNamedQuery = function (dbName, queryName, params) {
- var defer, queryData;
- if (databases[dbName]) {
- queryData = databases[dbName].queries[queryName];
- if (queryData) {
- if (params && queryData.params) {
- params = _.map(queryData.params, function (p) {
- return params[p];
+ var queryData, paramPromises, self = this;
+ if (!databases[dbName] || !databases[dbName].queries[queryName]) {
+ return $q.reject('Query by name \'' + queryName + '\'Not Found');
+ }
+ queryData = databases[dbName].queries[queryName];
+ paramPromises = _.chain(queryData.params).filter(function (p) {
+ return p.variableType !== 'PROMPT';
+ }).forEach(function (p) {
+ var paramValue = systemProperties[p.variableType].value(p.name, params);
+ return $q.when(paramValue, function (v) {
+ params[p.name] = v;
+ });
+ }).value();
+ return $q.all(paramPromises).then(function () {
+ params = _.map(queryData.params, function (p) {
+ return params[p.name];
+ });
+ return self.executeSQLQuery(dbName, queryData.query, params).then(function (result) {
+ var firstRow,
+ needTransform;
+ if (!_.isEmpty(result.rows)) {
+ firstRow = result.rows[0];
+ needTransform = _.find(queryData.response.properties, function (p) {
+ return !firstRow.hasOwnProperty(p.fieldName);
});
+ if (!_.isUndefined(needTransform)) {
+ result.rows = _.map(result.rows, function (row) {
+ var transformedRow = {},
+ rowWithUpperKeys = {};
+ //This is to make search for data as case-insensitive
+ _.forEach(row, function (v, k) {
+ rowWithUpperKeys[k.toUpperCase()] = v;
+ });
+ _.forEach(queryData.response.properties, function (p) {
+ transformedRow[p.name] = row[p.name];
+ transformedRow[p.fieldName] = row[p.fieldName] || rowWithUpperKeys[p.nameInUpperCase];
+ });
+ return transformedRow;
+ });
+ }
}
- return this.executeSQLQuery(dbName, queryData.query, params);
- }
- }
- defer = $q.defer();
- defer.reject('Query by name \'' + queryName + '\'Not Found');
- return defer.promise;
+ return result;
+ });
+ });
};
/**
@@ -609,4 +781,15 @@ wm.plugins.database.services.LocalDBManager = [
});
return $q.all(promises);
};
+
+ /**
+ * @ngdoc method
+ * @name wm.plugins.database.services.$LocalDBManager#getLastPullInfo
+ * @methodOf wm.plugins.database.services.$LocalDBManager
+ * @returns {object} that have total no of records fetched, start and end timestamps of last successful pull
+ * of data from remote server.
+ */
+ this.getLastPullInfo = function () {
+ return LocalKeyValueService.get(lastPullInfoKey);
+ };
}];
\ No newline at end of file
diff --git a/src/main/webapp/scripts/modules/mobile/plugins/database/services/localDBStoreFactory.js b/src/main/webapp/scripts/modules/mobile/plugins/database/services/localDBStoreFactory.js
index 8827a4e1c..843355b69 100644
--- a/src/main/webapp/scripts/modules/mobile/plugins/database/services/localDBStoreFactory.js
+++ b/src/main/webapp/scripts/modules/mobile/plugins/database/services/localDBStoreFactory.js
@@ -124,7 +124,7 @@ wm.plugins.database.services.LocalDBStoreFactory = [
if (sort) {
return ' ORDER BY ' + _.map(sort.split(','), function (field) {
var splits = _.trim(field).split(' ');
- splits[0] = escapeName(store.fieldToColumnMapping[splits[0]]);
+ splits[0] = escapeName(store.schema.name) + '.' + escapeName(store.fieldToColumnMapping[splits[0]]);
return splits.join(' ');
}).join(',');
}
diff --git a/src/main/webapp/scripts/modules/mobile/plugins/database/services/localKeyValueService.js b/src/main/webapp/scripts/modules/mobile/plugins/database/services/localKeyValueService.js
new file mode 100644
index 000000000..814c08fb0
--- /dev/null
+++ b/src/main/webapp/scripts/modules/mobile/plugins/database/services/localKeyValueService.js
@@ -0,0 +1,103 @@
+/*global wm, WM, _*/
+/**
+ * @ngdoc service
+ * @name wm.plugins.database.services.$LocalKeyValueService
+ * @description
+ * The 'wm.plugins.database.services.$LocalKeyValueService' stores key-value pair.
+ */
+wm.plugins.database.services.LocalKeyValueService = [function () {
+ 'use strict';
+ var store;
+ function fetchEntry(key) {
+ var filterCriteria = [{
+ 'attributeName' : 'key',
+ 'attributeValue' : key,
+ 'attributeType' : 'STRING',
+ 'filterCondition' : 'EQUALS'
+ }];
+ return store.filter(filterCriteria);
+ }
+ return {
+ /**
+ * @ngdoc method
+ * @name wm.plugins.database.services.$LocalKeyValueService#init
+ * @methodOf wm.plugins.database.services.$LocalKeyValueService
+ * @description
+ * Initializes the service with the given store.
+ *
+ * @param {object} storeToUse a store with id, key, value with fields.
+ * @returns {object} a promise that is resolved when data is persisted.
+ */
+ 'init' : function (storeToUse) {
+ store = storeToUse;
+ },
+ /**
+ * @ngdoc method
+ * @name wm.plugins.database.services.$LocalKeyValueService#put
+ * @methodOf wm.plugins.database.services.$LocalKeyValueService
+ * @description
+ * clear data in all databases.
+ *
+ * @param {string} key key
+ * @param {string} value value
+ * @returns {object} a promise that is resolved when data is persisted.
+ */
+ 'put' : function (key, value) {
+ if (value) {
+ value = JSON.stringify(value);
+ }
+ return fetchEntry(key).then(function (result) {
+ if (result && result.length > 0) {
+ return store.save({
+ 'id' : result[0].id,
+ 'key' : key,
+ 'value' : value
+ });
+ }
+ return store.add({
+ 'key' : key,
+ 'value' : value
+ });
+ });
+ },
+ /**
+ * @ngdoc method
+ * @name wm.plugins.database.services.$LocalKeyValueService#remove
+ * @methodOf wm.plugins.database.services.$LocalKeyValueService
+ * @description
+ * clear data in all databases.
+ *
+ * @param {string} key key
+ * @returns {object} a promise that is resolved when respective value is removed from store.
+ */
+ 'remove' : function (key) {
+ return fetchEntry(key).then(function (result) {
+ if (result && result.length > 0) {
+ return store.delete(result[0].id);
+ }
+ });
+ },
+ /**
+ * @ngdoc method
+ * @name wm.plugins.database.services.$LocalKeyValueService#get
+ * @methodOf wm.plugins.database.services.$LocalKeyValueService
+ * @description
+ * retrieves the value mapped to the key.
+ *
+ * @param {string} key key
+ * @returns {object} a promise that is resolved when value is retrieved from store.
+ */
+ 'get' : function (key) {
+ return fetchEntry(key).then(function (result) {
+ var value;
+ if (result && result.length > 0) {
+ value = result[0].value;
+ if (value) {
+ value = JSON.parse(value);
+ }
+ }
+ return value;
+ });
+ }
+ };
+}];
\ No newline at end of file
diff --git a/src/main/webapp/scripts/modules/mobile/plugins/offline/config.js b/src/main/webapp/scripts/modules/mobile/plugins/offline/config.js
index e13fd52de..a042155f5 100644
--- a/src/main/webapp/scripts/modules/mobile/plugins/offline/config.js
+++ b/src/main/webapp/scripts/modules/mobile/plugins/offline/config.js
@@ -90,7 +90,6 @@ wm.plugins.offline.run([
'LocalDBService',
'OfflineFileUploadService',
'Utils',
- 'wmSpinner',
'WebService',
function ($cordovaNetwork,
$rootScope,
@@ -100,7 +99,6 @@ wm.plugins.offline.run([
LocalDBService,
OfflineFileUploadService,
Utils,
- wmSpinner,
WebService) {
'use strict';
var initializationDone;
@@ -137,12 +135,11 @@ wm.plugins.offline.run([
if (str) {
str = decodeURIComponent(str);
_.forEach(str.split('&'), function (c) {
- var csplits = c.split('='),
- intVal = parseInt(csplits[1], 10);
- if (_.isNaN(intVal)) {
+ var csplits = c.split('=');
+ if (_.isEmpty(_.trim(csplits[1])) || isNaN(csplits[1])) {
result[csplits[0]] = csplits[1];
} else {
- result[csplits[0]] = intVal;
+ result[csplits[0]] = parseInt(csplits[1], 10);
}
});
}
@@ -195,18 +192,14 @@ wm.plugins.offline.run([
addOfflineNamedQuerySupport();
addOfflineFileUploadSupport();
ChangeLogService.registerCallback({
- 'preFlush' : function () {
- wmSpinner.show('');
- },
'postFlush' : function (stats) {
- if (stats.total > 0) {
- location.assign(window.location.origin + window.location.pathname);
+ if (stats.totalTaskCount > 0) {
+ LocalDBManager.close().finally(function () {
+ location.assign(window.location.origin + window.location.pathname);
+ });
}
}
});
- $rootScope.$on('on-App-variables-ready', function () {
- LocalDBManager.pullData();
- });
});
}
diff --git a/src/main/webapp/scripts/modules/mobile/plugins/offline/services/changeLogService.js b/src/main/webapp/scripts/modules/mobile/plugins/offline/services/changeLogService.js
index 0562b2bf7..653446c35 100644
--- a/src/main/webapp/scripts/modules/mobile/plugins/offline/services/changeLogService.js
+++ b/src/main/webapp/scripts/modules/mobile/plugins/offline/services/changeLogService.js
@@ -22,19 +22,18 @@ wm.plugins.offline.services.ChangeLogService = [
'Utils',
'$log',
'$injector',
+ 'LocalKeyValueService',
'SecurityService',
- function (LocalDBManager, $q, Utils, $log, $injector, SecurityService) {
+ function (LocalDBManager, $q, Utils, $log, $injector, LocalKeyValueService, SecurityService) {
'use strict';
var contextKey = 'changeLogService.flushContext',
+ lastPushInfoKey = 'changeLogService.lastPushInfo',
flushContext,
services = {},
callbacks = [],
flushInProgress = false,
- stats = {
- 'total': 0,
- 'success': 0
- };
+ stats = {};
function getService(serviceName) {
var service = services[serviceName];
@@ -182,6 +181,12 @@ wm.plugins.offline.services.ChangeLogService = [
var cbs = _.reverse(_.map(callbacks, "postFlush"));
flushInProgress = false;
return resetNetworkFailures().then(function () {
+ if (stats.failedTaskCount === 0) {
+ return flushContext.clear().then(function () {
+ flushContext = undefined;
+ });
+ }
+ }).then(function () {
return executeDeferChain(cbs, [stats, flushContext]);
}).finally(function () {
Utils.triggerFn(fn, stats);
@@ -189,28 +194,13 @@ wm.plugins.offline.services.ChangeLogService = [
};
}
- function prepareForFlush() {
- var filterCriteria = [{
- 'attributeName' : 'key',
- 'attributeValue' : contextKey,
- 'attributeType' : 'STRING',
- 'filterCondition' : 'EQUALS'
- }];
- return LocalDBManager.getStore('wavemaker', 'key-value').filter(filterCriteria).then(function (result) {
- var id,
- context = {};
- if (result && result.length > 0) {
- id = result[0].id;
- context = JSON.parse(result[0].value) || {};
- }
+ function createContext() {
+ return LocalKeyValueService.get(contextKey).then(function (context) {
+ context = context || {};
return {
'clear' : function () {
- var defer = $q.defer();
- if (id > 0) {
- return LocalDBManager.getStore('wavemaker', 'key-value').delete(id);
- }
- defer.resolve();
- return defer.promise;
+ context = {};
+ return LocalKeyValueService.remove(contextKey);
},
'get' : function (key) {
var value = context[key];
@@ -221,15 +211,7 @@ wm.plugins.offline.services.ChangeLogService = [
return value;
},
'save' : function () {
- return LocalDBManager.getStore('wavemaker', 'key-value').save({
- 'id' : id,
- 'key' : contextKey,
- 'value' : JSON.stringify(context)
- }).then(function (insertId) {
- if (insertId) {
- id = insertId;
- }
- });
+ return LocalKeyValueService.put(contextKey, context);
}
};
});
@@ -243,10 +225,12 @@ wm.plugins.offline.services.ChangeLogService = [
$log.debug('Added the following call %o to log.', change);
},
'preFlush': function () {
- stats.total = 0;
- stats.success = 0;
- stats.error = 0;
- stats.completed = 0;
+ stats.totalTaskCount = 0;
+ stats.successfulTaskCount = 0;
+ stats.failedTaskCount = 0;
+ stats.completedTaskCount = 0;
+ stats.inProgress = true;
+ stats.startTime = _.now();
$log.debug('Starting flush');
return getStore().count([{
'attributeName' : 'hasError',
@@ -254,30 +238,28 @@ wm.plugins.offline.services.ChangeLogService = [
'attributeType' : 'NUMBER',
'filterCondition' : 'EQUALS'
}]).then(function (count) {
- stats.total = count;
+ stats.totalTaskCount = count;
});
},
'postFlush': function (stats, flushContext) {
$log.debug('flush completed. {Success : %i , Error : %i , completed : %i, total : %i }.',
- stats.success, stats.error, stats.completed, stats.total);
- if (stats.error === 0) {
- return flushContext.clear().then(function () {
- flushContext = undefined;
- });
- }
+ stats.successfulTaskCount, stats.failedTaskCount, stats.completedTaskCount, stats.totalTaskCount);
+ stats.inProgress = false;
+ stats.endTime = _.now();
+ LocalKeyValueService.put(lastPushInfoKey, stats);
},
'preCall': function (change) {
- $log.debug("%i. Invoking call %o", (1 + stats.completed), change);
+ $log.debug("%i. Invoking call %o", (1 + stats.completedTaskCount), change);
},
'postCallError': function (change, response) {
- stats.completed++;
- stats.error++;
+ stats.completedTaskCount++;
+ stats.failedTaskCount++;
$log.error('call failed with the response %o.', response);
return flushContext.save();
},
'postCallSuccess': function (change, response) {
- stats.completed++;
- stats.success++;
+ stats.completedTaskCount++;
+ stats.successfulTaskCount++;
$log.debug('call returned the following response %o.', response);
return flushContext.save();
}
@@ -404,7 +386,7 @@ wm.plugins.offline.services.ChangeLogService = [
onComplete = onFlushComplete(onComplete);
flushInProgress = true;
SecurityService.onUserLogin()
- .then(prepareForFlush)
+ .then(createContext)
.then(function (context) {
flushContext = context;
return executeDeferChain(_.map(callbacks, "preFlush"), [flushContext]);
@@ -429,8 +411,8 @@ wm.plugins.offline.services.ChangeLogService = [
* completed : 0
* }
*/
- this.getFlushStats = function () {
- return stats;
+ this.getLastPushInfo = function () {
+ return LocalKeyValueService.get(lastPushInfoKey);
};
}
];
diff --git a/src/main/webapp/scripts/modules/mobile/plugins/offline/services/offlineFileUploadService.js b/src/main/webapp/scripts/modules/mobile/plugins/offline/services/offlineFileUploadService.js
index 7d32ddde1..fa1b243ba 100644
--- a/src/main/webapp/scripts/modules/mobile/plugins/offline/services/offlineFileUploadService.js
+++ b/src/main/webapp/scripts/modules/mobile/plugins/offline/services/offlineFileUploadService.js
@@ -53,7 +53,9 @@ wm.plugins.offline.services.OfflineFileUploadService = ['$cordovaFile', 'ChangeL
this.uploadToServer = function (params, onSuccess, onFail) {
var ft = new FileTransfer();
ft.upload(params.file, params.serverUrl, function (evt) {
- fileStore[params.file] = JSON.parse(evt.response)[0].path;
+ var response = JSON.parse(evt.response)[0];
+ fileStore[params.file] = response.path;
+ fileStore[params.file + '?inline'] = response.inlinePath;
onSuccess(evt);
}, onFail, params.ftOptions);
};
@@ -77,16 +79,18 @@ wm.plugins.offline.services.OfflineFileUploadService = ['$cordovaFile', 'ChangeL
destFile = Date.now().toString();
$cordovaFile.copyFile(soureDir, soureFile, uploadDir, destFile)
.then(function () {
+ var filePath = uploadDir + '/' + destFile;
ChangeLogService.add('OfflineFileUploadService', 'uploadToServer', {
- 'file': uploadDir + '/' + destFile,
+ 'file' : filePath,
'serverUrl': serverUrl,
'ftOptions': ftOptions
});
defer.resolve({
- 'fileName': soureFile,
- 'path': uploadDir + '/' + destFile,
- 'length': 0,
- 'success': true
+ 'fileName' : soureFile,
+ 'path' : filePath,
+ 'length' : 0,
+ 'success' : true,
+ 'inlinePath': filePath + '?inline'
});
}, defer.reject.bind());
return defer.promise;
diff --git a/src/main/webapp/scripts/modules/mobile/variables/datasync/datasync.js b/src/main/webapp/scripts/modules/mobile/variables/datasync/datasync.js
index faf59b2dd..4d5c99448 100644
--- a/src/main/webapp/scripts/modules/mobile/variables/datasync/datasync.js
+++ b/src/main/webapp/scripts/modules/mobile/variables/datasync/datasync.js
@@ -1,6 +1,6 @@
/*global WM, _*/
-WM.module('wm.variables').run(['ChangeLogService', 'DeviceVariableService', 'LocalDBManager', 'VARIABLE_CONSTANTS',
- function (ChangeLogService, DeviceVariableService, LocalDBManager, VARIABLE_CONSTANTS) {
+WM.module('wm.variables').run(['$rootScope', 'ChangeLogService', 'DeviceVariableService', 'LocalDBManager', 'SecurityService', 'VARIABLE_CONSTANTS',
+ function ($rootScope, ChangeLogService, DeviceVariableService, LocalDBManager, SecurityService, VARIABLE_CONSTANTS) {
"use strict";
var operations,
dataChangeTemplate = {
@@ -55,47 +55,139 @@ WM.module('wm.variables').run(['ChangeLogService', 'DeviceVariableService', 'Loc
};
});
}
+
+ /**
+ * This function adds the old properties to the push dataSet to support old projects.
+ * @param data
+ * @returns {*}
+ */
+ function addOldPropertiesForPushData(data) {
+ var result = _.clone(data);
+ result.success = data.successfulTaskCount;
+ result.error = data.failedTaskCount;
+ result.completed = data.completedTaskCount;
+ result.total = data.totalTaskCount;
+ return result;
+ }
operations = {
pull : {
owner : VARIABLE_CONSTANTS.OWNER.APP,
- model: {},
- properties : [],
+ model: {
+ 'totalTaskCount' : 0,
+ 'completedTaskCount' : 0,
+ 'inProgress' : false
+ },
+ properties : [
+ {"target": "clearData", "type": "boolean", "widgettype": "boolean-inputfirst", "value": true, "group" : "properties", "subGroup" : "behavior"},
+ {"target": "startUpdate", "type": "boolean", "hide" : false},
+ {"target": "onBefore", "hide" : false},
+ {"target": "onProgress", "hide" : false},
+ {"target": "spinnerContext", "hide" : false}
+ ],
requiredCordovaPlugins: [],
invoke: function (variable, options, success, error) {
- LocalDBManager.pullData().then(success, error);
+ // If user is authenticated and online, then start the data pull process.
+ SecurityService.onUserLogin()
+ .then(LocalDBManager.canConnectToServer.bind(LocalDBManager))
+ .then(function () {
+ var clearData = variable.clearData === "true" || variable.clearData === true;
+ DeviceVariableService.initiateCallback('onBefore', variable);
+ $rootScope.$emit('toggle-variable-state', variable.name, true);
+ LocalDBManager.pullData(clearData).then(success, error, function (progress) {
+ variable.dataSet = progress;
+ DeviceVariableService.initiateCallback('onProgress', variable, progress);
+ }).finally(function () {
+ $rootScope.$emit('toggle-variable-state', variable.name, false);
+ });
+ });
+ }
+ },
+ lastPullInfo : {
+ owner : VARIABLE_CONSTANTS.OWNER.APP,
+ model: {
+ 'databases' : [{
+ 'name' : 'datbaseName',
+ 'entities': [{
+ 'entityName': 'entityName',
+ 'pulledRecordCount': 0
+ }],
+ 'pulledRecordCount' : 0
+ }],
+ 'totalPulledRecordCount' : 0,
+ 'startTime' : 0,
+ 'endTime' : 0
+ },
+ properties : [
+ {"target": "startUpdate", "type": "boolean", "value": true, "hide" : true},
+ {"target": "spinnerContext", "hide" : false}
+ ],
+ requiredCordovaPlugins: [],
+ invoke: function (variable, options, success, error) {
+ $rootScope.$emit('toggle-variable-state', variable.name, true);
+ LocalDBManager.getLastPullInfo().then(success, error).finally(function () {
+ $rootScope.$emit('toggle-variable-state', variable.name, false);
+ });
}
},
push : {
owner : VARIABLE_CONSTANTS.OWNER.APP,
model: {
- 'success' : 0,
- 'error' : 0,
- 'completed' : 0,
- 'total' : 0
+ 'successfulTaskCount' : 0,
+ 'failedTaskCount' : 0,
+ 'completedTaskCount' : 0,
+ 'totalTaskCount' : 0,
+ 'inProgress' : false
},
properties : [
- {"target": "onBeforePush", "hide" : false},
- {"target": "onProgress", "hide" : false}
+ {"target": "onBefore", "hide" : false},
+ {"target": "onProgress", "hide" : false},
+ {"target": "spinnerContext", "hide" : false}
],
requiredCordovaPlugins: [],
- invoke: function (variable, options) {
- LocalDBManager.canConnectToServer()
+ invoke: function (variable) {
+ // If user is authenticated and online, then start the data push process.
+ SecurityService.onUserLogin()
+ .then(LocalDBManager.canConnectToServer.bind(LocalDBManager))
.then(getOfflineChanges)
.then(function (changes) {
if (changes.pendingToSync.total > 0) {
- DeviceVariableService.initiateCallback('onBeforePush', variable, options, changes);
+ DeviceVariableService.initiateCallback('onBefore', variable, changes);
+ $rootScope.$emit('toggle-variable-state', variable.name, true);
ChangeLogService.flush(function (stats) {
var eventName = stats.error > 0 ? 'onError' : 'onSuccess';
- variable.dataSet = stats;
- DeviceVariableService.initiateCallback(eventName, variable, options, stats);
+ variable.dataSet = addOldPropertiesForPushData(stats);
+ $rootScope.$emit('toggle-variable-state', variable.name, false);
+ DeviceVariableService.initiateCallback(eventName, variable, stats);
}, function (stats) {
- variable.dataSet = stats;
- DeviceVariableService.initiateCallback('onProgress', variable, options, stats);
+ variable.dataSet = addOldPropertiesForPushData(stats);
+ DeviceVariableService.initiateCallback('onProgress', variable, stats);
});
}
});
}
},
+ lastPushInfo : {
+ owner : VARIABLE_CONSTANTS.OWNER.APP,
+ model: {
+ 'successfulTaskCount' : 0,
+ 'failedTaskCount' : 0,
+ 'completedTaskCount' : 0,
+ 'totalTaskCount' : 0,
+ 'startTime' : 0,
+ 'endTime' : 0
+ },
+ properties : [
+ {"target": "startUpdate", "type": "boolean", "value": true, "hide" : true},
+ {"target": "spinnerContext", "hide" : false}
+ ],
+ requiredCordovaPlugins: [],
+ invoke: function (variable, options, success, error) {
+ $rootScope.$emit('toggle-variable-state', variable.name, true);
+ ChangeLogService.getLastPushInfo().then(success, error).finally(function () {
+ $rootScope.$emit('toggle-variable-state', variable.name, false);
+ });
+ }
+ },
getOfflineChanges : {
model: {
'total' : 0,
diff --git a/src/main/webapp/scripts/modules/mobile/variables/device/device.js b/src/main/webapp/scripts/modules/mobile/variables/device/device.js
index b6a9e2dc8..1a09c9a1d 100644
--- a/src/main/webapp/scripts/modules/mobile/variables/device/device.js
+++ b/src/main/webapp/scripts/modules/mobile/variables/device/device.js
@@ -127,9 +127,9 @@ WM.module('wm.variables').run([
isOffline: $cordovaNetwork.isOffline()
});
if ($cordovaNetwork.isOnline()) {
- DeviceVariableService.initiateCallback('onOnline', variable, options);
+ DeviceVariableService.initiateCallback('onOnline', variable);
} else {
- DeviceVariableService.initiateCallback('onOffline', variable, options);
+ DeviceVariableService.initiateCallback('onOffline', variable);
}
}
},
diff --git a/src/main/webapp/scripts/modules/mobile/variables/deviceVariable/deviceVariableService.js b/src/main/webapp/scripts/modules/mobile/variables/deviceVariable/deviceVariableService.js
index db157db42..0bcf68ce8 100644
--- a/src/main/webapp/scripts/modules/mobile/variables/deviceVariable/deviceVariableService.js
+++ b/src/main/webapp/scripts/modules/mobile/variables/deviceVariable/deviceVariableService.js
@@ -6,42 +6,37 @@
* @ngdoc service
* @name wm.variables.DeviceVariableService
* @requires $rootScope
- * @requires Varibales
+ * @requires Variables
* @requires Utils
* @requires BaseVariablePropertyFactory
* @requires CONSTANTS
* @description
* The 'DeviceVariableService' provides methods to work with Mobile API.
*/
-wm.variables.services.DeviceVariableService = ['$rootScope', 'Variables', 'Utils', 'CONSTANTS',
- function ($rootScope, Variables, Utils, CONSTANTS) {
+wm.variables.services.DeviceVariableService = ['$rootScope', 'Variables', 'Utils', 'CONSTANTS', 'BaseVariablePropertyFactory',
+ function ($rootScope, Variables, Utils, CONSTANTS, BaseVariablePropertyFactory) {
"use strict";
- var initiateCallback = Variables.initiateCallback,
- availableServices = {};
-
- function getCallBackScope(variable, options) {
- /* get the callback scope for the variable based on its owner */
- if (variable.owner === "App") {
- return $rootScope || {};
- }
- if (variable._prefabName) {
- return options.scope || {};
+ var availableServices = {},
+ propertyGroups = BaseVariablePropertyFactory.getPropertyGroups();
+ function addPropertyToGroup(propertyDef) {
+ if (propertyDef.group && propertyDef.subGroup) {
+ var targetSubGroup = _.find(propertyGroups, {"name": propertyDef.subGroup, "parent": propertyDef.group});
+ if (targetSubGroup && _.findIndex(targetSubGroup.properties, propertyDef.target) < 0) {
+ targetSubGroup.properties.push(propertyDef.target);
+ }
}
- return (options && options.scope && options.scope.$$childTail) ? options.scope.$$childTail : {};
}
-
function invoke(options, success, error) {
var variable = this,
operation = availableServices[this.service][this.operation],
- callBackScope = getCallBackScope(variable, options),
successCb = function (data) {
variable.dataSet = data;
Utils.triggerFn(success);
- initiateCallback('onSuccess', variable, callBackScope, data);
+ Variables.initiateCallback('onSuccess', variable, data);
},
errorCb = function () {
Utils.triggerFn(error);
- initiateCallback('onError', variable, callBackScope);
+ Variables.initiateCallback('onError', variable);
};
if (operation && CONSTANTS.hasCordova) {
operation.invoke(this, options, successCb, errorCb);
@@ -73,8 +68,9 @@ wm.variables.services.DeviceVariableService = ['$rootScope', 'Variables', 'Utils
* }
*/
addOperation : function (serviceName, operationName, serviceInfo) {
- var service = availableServices[serviceName] = (availableServices[serviceName] || {});
- service[operationName] = serviceInfo;
+ availableServices[serviceName] = (availableServices[serviceName] || {});
+ availableServices[serviceName][operationName] = serviceInfo;
+ _.forEach(serviceInfo.properties, addPropertyToGroup);
},
listServices : function () {
return _.sortBy(_.keys(availableServices));
@@ -86,9 +82,8 @@ wm.variables.services.DeviceVariableService = ['$rootScope', 'Variables', 'Utils
}
return operation;
},
- initiateCallback : function (eventName, variable, options, eventData) {
- var callBackScope = getCallBackScope(variable, options);
- Variables.initiateCallback(eventName, variable, callBackScope, eventData);
+ initiateCallback : function (eventName, variable, eventData) {
+ Variables.initiateCallback(eventName, variable, eventData);
},
listAllOperations : function (serviceName) {
return _.sortBy(_.keys(availableServices[serviceName]));
diff --git a/src/main/webapp/scripts/modules/mobile/variables/file/file.js b/src/main/webapp/scripts/modules/mobile/variables/file/file.js
index c64304827..2e9d8c75e 100644
--- a/src/main/webapp/scripts/modules/mobile/variables/file/file.js
+++ b/src/main/webapp/scripts/modules/mobile/variables/file/file.js
@@ -5,10 +5,12 @@ WM.module('wm.variables').run(['$rootScope', 'DeviceVariableService', '$cordovaF
var operations = {
upload : {
model: {
- name: '',
- path: '',
- size: 0,
- type: ''
+ 'fileName' : '',
+ 'path' : '',
+ 'length' : 0,
+ 'success' : false,
+ 'inlinePath' : '',
+ 'errorMessage': ''
},
properties : [
{"target": "localFile", "type": "string", "value": "", "dataBinding": true},
diff --git a/src/main/webapp/scripts/modules/mobile/widgets/device/fileBrowser/fileBrowser.js b/src/main/webapp/scripts/modules/mobile/widgets/device/fileBrowser/fileBrowser.js
index 81eee8571..9c116fb79 100644
--- a/src/main/webapp/scripts/modules/mobile/widgets/device/fileBrowser/fileBrowser.js
+++ b/src/main/webapp/scripts/modules/mobile/widgets/device/fileBrowser/fileBrowser.js
@@ -43,7 +43,7 @@ WM.module('wm.widgets.advanced')
'
'
);
}])
- .directive('wmMobileFileBrowser', [ '$templateCache', 'CONSTANTS', function ($templateCache, CONSTANTS) {
+ .directive('wmMobileFileBrowser', [ '$templateCache', 'CONSTANTS', 'DeviceService', function ($templateCache, CONSTANTS, DeviceService) {
'use strict';
function loadFileSize(files, onComplete, index) {
index = index || 0;
@@ -62,11 +62,21 @@ WM.module('wm.widgets.advanced')
'template' : $templateCache.get('template/widget/advanced/mobileFileBrowser.html'),
'scope' : {'onSelect' : '&'},
'link' : function (scope) {
+ var backButtonListenerDeregister;
if (CONSTANTS.isStudioMode) {
return;
}
+ backButtonListenerDeregister = DeviceService.onBackButtonTap(function () {
+ if (scope.show) {
+ scope.show = false;
+ return false;
+ }
+ });
+ scope.$on('$destroy', function () {
+ backButtonListenerDeregister();
+ });
scope.selectedFiles = [];
scope.directory = undefined;
scope.getFileExtension = function (fileName) {
diff --git a/src/main/webapp/scripts/modules/mobile/wmMobile.js b/src/main/webapp/scripts/modules/mobile/wmMobile.js
index dca9aa2ed..eb34c6561 100644
--- a/src/main/webapp/scripts/modules/mobile/wmMobile.js
+++ b/src/main/webapp/scripts/modules/mobile/wmMobile.js
@@ -1,4 +1,4 @@
-/*global WM, window, _, cordova, document*/
+/*global WM, window, _, cordova, document, navigator */
WM.module('wm.mobile', ['wm.variables', 'wm.layouts', 'wm.widgets', 'ngCordova', 'ngCordovaOauth', 'wm.plugins.offline'])
//Initialize project
@@ -7,24 +7,37 @@ WM.module('wm.mobile', ['wm.variables', 'wm.layouts', 'wm.widgets', 'ngCordova',
'DeviceFileService', 'DeviceFileCacheService',
function ($rootScope, $location, CONSTANTS, AppAutoUpdateService) {
'use strict';
+
+ var initialScreenSize,
+ $appEl,
+ pageReadyDeregister;
+
/* Mark the mobileApplication type to true */
$rootScope.isMobileApplicationType = true;
if ($location.protocol() === 'file') {
CONSTANTS.hasCordova = true;
+ $appEl = WM.element('.wm-app:first');
+ initialScreenSize = window.innerHeight;
+
+ $appEl.addClass('cordova');
+
+ // keyboard class is added when keyboard is open.
+ window.addEventListener('resize', function () {
+ if (window.innerHeight < initialScreenSize) {
+ $appEl.addClass('keyboard');
+ } else {
+ $appEl.removeClass('keyboard');
+ }
+ });
+
$rootScope.$on('application-ready', function () {
AppAutoUpdateService.start();
});
- }
- if (CONSTANTS.isRunMode) {
- $rootScope.$on('$routeChangeStart', function () {
- WM.element('body >.app-spinner:first').removeClass('ng-hide');
- });
- $rootScope.$on('page-ready', function () {
- WM.element('body >.app-spinner:first').addClass('ng-hide');
- });
- $rootScope.$on('template-ready', function () {
- WM.element('body >.app-spinner:first').addClass('ng-hide');
+
+ pageReadyDeregister = $rootScope.$on('page-ready', function () {
+ navigator.splashscreen.hide();
+ pageReadyDeregister();
});
}
}])
@@ -87,7 +100,7 @@ WM.module('wm.mobile', ['wm.variables', 'wm.layouts', 'wm.widgets', 'ngCordova',
};
//On Application start
$rootScope.$on('application-ready', function () {
- var msgContent = {key: 'on-load'};
+ var msgContent = {key: 'on-load'};
//Notify preview window that application is ready. Otherwise, identify the OS.
if (window.top !== window) {
window.top.postMessage(Utils.isIE9() ? JSON.stringify(msgContent) : msgContent, '*');
@@ -98,4 +111,4 @@ WM.module('wm.mobile', ['wm.variables', 'wm.layouts', 'wm.widgets', 'ngCordova',
}
});
}
- }]);
+ }]);
\ No newline at end of file
diff --git a/src/main/webapp/scripts/modules/plugins/database/application/services/databaseServices.js b/src/main/webapp/scripts/modules/plugins/database/application/services/databaseServices.js
index f16060d79..3afc7dffb 100644
--- a/src/main/webapp/scripts/modules/plugins/database/application/services/databaseServices.js
+++ b/src/main/webapp/scripts/modules/plugins/database/application/services/databaseServices.js
@@ -43,6 +43,7 @@
* - {@link wm.database.$DatabaseService#methods_deleteQuery deleteQuery}
* - {@link wm.database.$DatabaseService#methods_validateQuery validateQuery}
* - {@link wm.database.$DatabaseService#methods_testRunQuery testRunQuery}
+ * - {@link wm.database.$DatabaseService#methods_nativeTestRunQuery nativeTestRunQuery}
* - {@link wm.database.$DatabaseService#methods_readTableData readTableData}
* - {@link wm.database.$DatabaseService#methods_insertTableData insertTableData}
* - {@link wm.database.$DatabaseService#methods_updateTableData updateTableData}
@@ -1649,7 +1650,7 @@ wm.plugins.database.services.DatabaseService = [
*/
testRunProcedure: function (params, successCallback, failureCallback) {
- return initiateAction("testRunProcedure", params, successCallback, failureCallback);
+ return initiateAction("testRunProcedure", params, successCallback, failureCallback, true);
},
/**
* Internal function
@@ -2187,6 +2188,9 @@ wm.plugins.database.services.DatabaseService = [
},
data: params.data
});
+ },
+ executeAggregateQuery: function (params, successCallback, failureCallback) {
+ return initiateAction("executeAggregateQuery", params, successCallback, failureCallback);
}
};
}
diff --git a/src/main/webapp/scripts/modules/plugins/database/config.js b/src/main/webapp/scripts/modules/plugins/database/config.js
index c3f6d40ec..d8446410f 100644
--- a/src/main/webapp/scripts/modules/plugins/database/config.js
+++ b/src/main/webapp/scripts/modules/plugins/database/config.js
@@ -290,6 +290,10 @@ wm.plugins.database.constant('DB_SERVICE_URLS', {
url: "/:service/:dataModelName/queries/execute?page=:page&size=:size",
method: "POST"
},
+ executeAggregateQuery: {
+ url: "/services/:dataModelName/:entityName/aggregations?page=:page&size=:size&sort=:sort",
+ method: "POST"
+ },
testRunQuery: {
url: "/:service/:dataModelName/queries/test_run",
method: "POST"
@@ -306,7 +310,7 @@ wm.plugins.database.constant('DB_SERVICE_URLS', {
method: "GET"
},
testRunProcedure: {
- url: "/:service/:dataModelName/procedures/test_run",
+ url: "services/projects/:projectID/database/services/:dataModelName/procedures/testrun",
method: "POST"
},
proceduresInDatabase: {
@@ -655,6 +659,11 @@ wm.plugins.database.constant('DB_CONSTANTS', {
"label": "CURRENT_TIME",
"value": "TIME"
},
+ "CURRENT_DATE_TIME": {
+ "property": "Current DateTime",
+ "label": "CURRENT_DATE_TIME",
+ "value": "DATETIME"
+ },
"CURRENT_USER_ID": {
"property": "LoggedIn UserId",
"label": "CURRENT_USER_ID",
diff --git a/src/main/webapp/scripts/modules/plugins/security/application/services/securityservices.js b/src/main/webapp/scripts/modules/plugins/security/application/services/securityservices.js
index 59209c238..3087ff89a 100644
--- a/src/main/webapp/scripts/modules/plugins/security/application/services/securityservices.js
+++ b/src/main/webapp/scripts/modules/plugins/security/application/services/securityservices.js
@@ -622,23 +622,16 @@ wm.plugins.security.services.SecurityService = [
/**
* @ngdoc function
- * @name wm.security.$SecurityService#getCASOptions
+ * @name wm.security.$SecurityService#getSAMLOptions
* @methodOf wm.security.$SecurityService
* @function
*
* @description
- * The API is used to get the values of configured CAS (Central Authentication Service) security provider.
- * This API returns appropriate values on the basis of what is set earlier using configureCAS API.
+ * The API is used to get the values of configured SAML security provider.
+ * This API returns appropriate values on the basis of what is set earlier using configureSAML API.
*
- * Following are the fields which need to be set for using CAS:
- * a) casURL - A CAS url
- * b) projectURL - projects url.
- * c) userDetailsProvider - A string which contains the value “CAS”.
- * d) DatabaseOptions - DatabaseOptions object
*
* @param {string} projectID project id
- * @param {function} successCallback to be called on success
- * @param {function} failureCallback to be called on failure
*/
getSAMLOptions: function (projectID) {
@@ -658,16 +651,23 @@ wm.plugins.security.services.SecurityService = [
* @function
*
* @description
- * The URL configures the SAML as the service provider. This mechanism enables the
- * Configuration parameters should be sent through json object using RequestBody.
- * Following 3 data members value to be set for using SAML:
- * e) samlURL - A CAS url.
- * f) projectURL - project url.
- * g) userDetailsProvider - A string which contains the value “SAML”.
+ * Save SAML configurations.
+ * While calling this API, it is mandatory to set the requestBody.
+ * Following is the structure of SAMLOptions:
+ * 1. samlOptions - this property has all the saml related configuration.
+ * a. createKeystore - (boolean) to auto generate key-store.
+ * b. idpEndpointUrl - Identity Provider endpoint url.
+ * c. idpMetadataUrl - Identity Provider metadata url.
+ * d. idpPublicKey - Identity Provider public key.
+ * e. keyAlias - Alias key.
+ * f. keyStoreLocation - Path where the key-store is placed in the project.
+ * g. keyStoreName - Name of the key-store.
+ * h. keyStorePassword - Key-store password.
+ * i. roleMappingEnabled - (boolean) whether the role is mapped.
+ * j. subjectName - subject name for key-store.
+ * 2. generalOptions - It consist of 5 fields viz., enforceSecurity, enforceIndexHtml, useSSL, sslPort and dataSourceType respectively. To configure SAML, dataSourceType must be set to “SAML” and enforceSecurity must be true. Other options must be set as per the requirement.
*
* @param {object} params object containing parameters for the request
- * @param {function} successCallback to be called on success
- * @param {function} failureCallback to be called on failure
*/
configSAML: function (params) {
@@ -683,27 +683,24 @@ wm.plugins.security.services.SecurityService = [
/**
* @ngdoc function
- * @name wm.security.$SecurityService#configSAML
+ * @name wm.security.$SecurityService#loadIdpMetadata
* @methodOf wm.security.$SecurityService
* @function
*
* @description
- * The URL configures the SAML as the service provider. This mechanism enables the
- * Configuration parameters should be sent through json object using RequestBody.
- * Following 3 data members value to be set for using SAML:
- * e) samlURL - A CAS url.
- * f) projectURL - project url.
- * g) userDetailsProvider - A string which contains the value “SAML”.
+ * Loads SAML metadata through MetadataUrl.
+ *
+ * Url Parameters
+ * 1) Project ID
+ * 2) IDP Metadata URL
*
* @param {object} params object containing parameters for the request
- * @param {function} successCallback to be called on success
- * @param {function} failureCallback to be called on failure
*/
- loadIdpMatadata: function (params) {
+ loadIdpMetadata: function (params) {
return BaseService.execute({
target: 'Security',
- action: 'loadIdpMatadata',
+ action: 'loadIdpMetadata',
urlParams: {
projectID: params.projectID,
idpMetadataUrl: params.idpMetadataUrl
@@ -711,6 +708,32 @@ wm.plugins.security.services.SecurityService = [
});
},
+ /**
+ * @ngdoc function
+ * @name wm.security.$SecurityService#uploadIdpMetadata
+ * @methodOf wm.security.$SecurityService
+ * @function
+ *
+ * @description
+ * The uploaded xml file configures SAML as the service provider.
+ * Configuration parameters should be sent through json object using RequestBody.
+ *
+ * This call is a multipart data request. Metadata file should be sent in the request body.
+ *
+ * @param {object} params object containing parameters for the request
+ */
+
+ uploadIdpMetadata: function (params) {
+ return BaseService.execute({
+ target: 'Security',
+ action: 'uploadIdpMetadata',
+ urlParams: {
+ projectID: params.projectID
+ },
+ data: params.content
+ });
+ },
+
/**
* @ngdoc function
* @name wm.security.$SecurityService#configCustomAuth
@@ -961,6 +984,32 @@ wm.plugins.security.services.SecurityService = [
Utils.triggerFn(successCallback, response);
}, failureCallback);
},
+
+ /**
+ * @ngdoc function
+ * @name wm.security.$SecurityService#generateConfig
+ * @methodOf wm.security.$SecurityService
+ * @function
+ *
+ * @description
+ * The API is used to re-generate provider xml file
+ *
+ * @param {object} params object containing parameters for the request
+ * @param {function} successCallback to be called on success
+ * @param {function} failureCallback to be called on failure
+ */
+
+ generateConfig: function (params, successCallback, failureCallback) {
+ BaseService.send({
+ target: 'Security',
+ action: 'generateConfig',
+ urlParams: {
+ projectID: params.projectID
+ }
+ }, function (response) {
+ Utils.triggerFn(successCallback, response);
+ }, failureCallback);
+ },
/**
* @ngdoc function
* @name wm.security.$SecurityService#setRoles
diff --git a/src/main/webapp/scripts/modules/plugins/security/config.js b/src/main/webapp/scripts/modules/plugins/security/config.js
index 8591aa03c..8f116143f 100644
--- a/src/main/webapp/scripts/modules/plugins/security/config.js
+++ b/src/main/webapp/scripts/modules/plugins/security/config.js
@@ -80,9 +80,16 @@ wm.plugins.security.constant('SECURITY_URLS', {
url: "services/projects/:projectID/securityservice/providers/saml",
method: "POST"
},
- loadIdpMatadata: {
+ loadIdpMetadata: {
url: "services/projects/:projectID/securityservice/providers/saml/loadidpmetadata?idpMetadataUrl=:idpMetadataUrl",
- method: "get"
+ method: "GET"
+ },
+ uploadIdpMetadata: {
+ url: "services/projects/:projectID/securityservice/providers/saml/loadidpmetadata",
+ method: "POST",
+ headers: {
+ 'Content-Type': undefined
+ }
},
configCustomAuth: {
url: "services/projects/:projectID/securityservice/providers/customauth",
@@ -120,6 +127,10 @@ wm.plugins.security.constant('SECURITY_URLS', {
url: "services/projects/:projectID/securityservice/rolesconfig",
method: "POST"
},
+ generateConfig: {
+ url: "services/projects/:projectID/securityservice/generateconfig",
+ method: "POST"
+ },
appLogin: {
url: "j_spring_security_check",
method: "POST",
diff --git a/src/main/webapp/scripts/modules/plugins/webservice/application/factories/servicefactory.js b/src/main/webapp/scripts/modules/plugins/webservice/application/factories/servicefactory.js
index 491b28980..2962798c2 100644
--- a/src/main/webapp/scripts/modules/plugins/webservice/application/factories/servicefactory.js
+++ b/src/main/webapp/scripts/modules/plugins/webservice/application/factories/servicefactory.js
@@ -54,6 +54,14 @@ wm.plugins.webServices.factories.ServiceFactory = [
return (operationId ? (_.find(serviceObj.operations, {'operationId' : operationId})) : serviceObj.operations[0]) || {};
},
+ /**
+ * resets the cached operation info for a service
+ * @param serviceName
+ */
+ resetServiceOperations = function (serviceName) {
+ getServiceObjectByName(serviceName).operations.length = 0;
+ },
+
/*function to get list of services from the backend*/
getServicesWithType = function (successCallBack, reloadFlag) {
/*sanity checking of the params*/
@@ -128,6 +136,14 @@ wm.plugins.webServices.factories.ServiceFactory = [
return;
}
+ /*
+ * TODO [VIBHU]: doing this to clear previous operation info if cached.
+ * the getServiceOperations method needs to be merged with this method for consistency
+ */
+ if (forceReload) {
+ resetServiceOperations(serviceId);
+ }
+
/*invoking a service to get the operations that a particular service has and it's
* parameters to create a unique url pattern*/
WebService.retrieveServiceOperations(urlParams, function (response) {
@@ -199,6 +215,26 @@ wm.plugins.webServices.factories.ServiceFactory = [
return (VARIABLE_CONSTANTS.REST_SUPPORTED_SERVICES.indexOf(type) !== -1);// || VARIABLE_CONSTANTS.SERVICE_TYPE_DATA === type);
},
+ //Check if variable/operation is a query type and of put/post type
+ isBodyTypeQueryProcedure = function (variable) {
+ return (_.includes(['QueryExecution', 'ProcedureExecution'], variable.controller)) && (_.includes(['put', 'post'], variable.operationType));
+ },
+
+ //Return params from swagger for post/put query types
+ getRawParams = function (operationObj, definitions) {
+ var refValue = _.get(operationObj, ['parameters', 0, 'schema', '$ref']),
+ refKey = _.last(_.split(refValue, '/')),
+ defObj = definitions[refKey],
+ operationList = [];
+ _.forEach(defObj.properties, function (value, key) {
+ value.name = key;
+ value[parameterTypeKey] = VARIABLE_CONSTANTS.BODY_FIELD;
+ value.required = _.includes(defObj.required, key);
+ operationList.push(value);
+ });
+ return operationList;
+ },
+
processOperations = function (serviceObj, operations, swagger) {
var paramsKey,
isRestSupportedService = isRESTSupported(serviceObj.type),
@@ -234,8 +270,7 @@ wm.plugins.webServices.factories.ServiceFactory = [
returnObj,
returnType,
returnFormat,
- dbOperationName,
- tag,
+ rawParameters,
isDbServiceOp = function (type) {
return type === "hqlquery" || type === "nativequery" || type === "procedure";
};
@@ -243,9 +278,6 @@ wm.plugins.webServices.factories.ServiceFactory = [
if (isDbServiceOp(operation.operationType)) {
returnType = operation.return;
} else {
- dbOperationName = operation.relativePath && operation.relativePath.split("/").pop();
- tag = _.get(operation, 'tags[0]');
-
// fetch return type and operation object from swagger
if (operation.responses && operation.responses['200'].schema) {
schemaObject = operation.responses['200'].schema;
@@ -297,7 +329,13 @@ wm.plugins.webServices.factories.ServiceFactory = [
/* process the operation params as well */
if (!WM.element.isEmptyObject(operation[paramsKey])) {
operationObject.parameter = [];
- WM.forEach(operation[paramsKey], function (param) {
+ //For post/put query methods get params from definitions
+ if (isBodyTypeQueryProcedure(operationObject)) {
+ rawParameters = getRawParams(operation, definitions);
+ } else {
+ rawParameters = operation[paramsKey];
+ }
+ WM.forEach(rawParameters, function (param) {
isList = param[IS_LIST_KEY];
/* special cases for MultiPart type params */
@@ -315,6 +353,7 @@ wm.plugins.webServices.factories.ServiceFactory = [
if (param.type === "array") {
isList = true;
typeRef = param.items && param.items.type;
+ format = param.items && param.items.format;
} else {
typeRef = param.type;
format = param.format;
@@ -340,6 +379,8 @@ wm.plugins.webServices.factories.ServiceFactory = [
parameterType: param[parameterTypeKey]
});
});
+ } else {
+ operationObject.parameter = [];
}
/* push an extra RequestBody param for WebSocketService */
@@ -434,9 +475,9 @@ wm.plugins.webServices.factories.ServiceFactory = [
path[operation].relativePath = path['x-WM-RELATIVE_PATH'];
/* set operationType for Query/Procedure operations */
- if (path[operation].tags && path[operation].tags[0] === "ProcedureExecutionController") {
+ if (path[operation].tags && path[operation].tags[0] === WS_CONSTANTS.CONTROLLER_NAMES.PROCEDURE_CONTROLLER) {
path[operation].serviceSubType = "procedure";
- } else if (path[operation].tags && path[operation].tags[0] === "QueryExecutionController") {
+ } else if (path[operation].tags && path[operation].tags[0] === WS_CONSTANTS.CONTROLLER_NAMES.QUERY_CONTROLLER) {
path[operation].serviceSubType = "query";
/* here we have to set operationType to either hqlquery or nativequery (have to check how)*/
}
@@ -696,7 +737,8 @@ wm.plugins.webServices.factories.ServiceFactory = [
* @param {prefabName} prefab name
* @param {object} having service output
*/
- getPrefabTypes: getPrefabTypes
+ getPrefabTypes: getPrefabTypes,
+ isBodyTypeQueryProcedure: isBodyTypeQueryProcedure
};
}
];
diff --git a/src/main/webapp/scripts/modules/plugins/webservice/application/services/webServices.js b/src/main/webapp/scripts/modules/plugins/webservice/application/services/webServices.js
index 5312cb6db..e9cd6eae4 100644
--- a/src/main/webapp/scripts/modules/plugins/webservice/application/services/webServices.js
+++ b/src/main/webapp/scripts/modules/plugins/webservice/application/services/webServices.js
@@ -559,7 +559,8 @@ wm.plugins.webServices.services.WebService = function (BaseService) {
},
data: params.dataParams || undefined,
"isDirectCall": params.isDirectCall,
- "byPassResult": true
+ "byPassResult": true,
+ "isExtURL": params.isExtURL
}, successCallback, failureCallback);
},
/**
diff --git a/src/main/webapp/scripts/modules/plugins/webservice/config.js b/src/main/webapp/scripts/modules/plugins/webservice/config.js
index 995aae94a..9115a6fef 100644
--- a/src/main/webapp/scripts/modules/plugins/webservice/config.js
+++ b/src/main/webapp/scripts/modules/plugins/webservice/config.js
@@ -148,6 +148,10 @@ wm.plugins.webServices.constant('WS_CONSTANTS', {
MULTIPART_FORMDATA: "multipart/form-data",
OCTET_STREAM: "application/octet-stream"
},
+ CONTROLLER_NAMES: {
+ QUERY_CONTROLLER: "QueryExecutionController",
+ PROCEDURE_CONTROLLER: "ProcedureExecutionController"
+ },
HTTP_STATUS_CODE: {
CORS_FAILURE: -1
}
diff --git a/src/main/webapp/scripts/modules/variables/application/base/basefactory.js b/src/main/webapp/scripts/modules/variables/application/base/basefactory.js
index d4ecb9761..d804210c5 100644
--- a/src/main/webapp/scripts/modules/variables/application/base/basefactory.js
+++ b/src/main/webapp/scripts/modules/variables/application/base/basefactory.js
@@ -109,7 +109,7 @@ wm.variables.factories.BaseVariablePropertyFactory = [
"dataBinding": {"value": ""},
"startUpdate": {"hide": true, "value": ""},
"autoUpdate": {"hide": true, "value": ""},
- "redirectTo": {"type": "list", "options": [], value: "", "widgettype": "typeahead"},
+ "redirectTo": {"type": "list", "options": [], value: "", "placeholder": "Search Redirect To", "widgettype": "typeahead"},
"useDefaultSuccessHandler": {"type": "boolean", "widgettype": "boolean-inputfirst", "value": true}
},
"wm.NavigationVariable": {
@@ -117,7 +117,7 @@ wm.variables.factories.BaseVariablePropertyFactory = [
"owner": {"type": "list", "options": {"Page": "LABEL_PAGE", "App": "LABEL_APPLICATION"}, "value": "Page"},
"operation": {"type": "list", "required": true, "options": {"goToPreviousPage": "goToPreviousPage", "gotoPage": "gotoPage", "gotoTab": "gotoTab", "gotoAccordion": "gotoAccordion"}, "value": "gotoPage"},
"dataBinding": {"type": "string", "value": [], "hide": true},
- "pageTransitions": {"type": "list", "options": {"none": "none", "slide": "slide", "pop": "pop", "fade": "fade", "flip": "flip"}, "value": "none", "hide": true},
+ "pageTransitions": {"type": "list", "widgettype": "typeahead", "options": {"none": "none", "slide": "slide", "pop": "pop", "fade": "fade", "flip": "flip"}, "value": "none", "hide": true},
"dataSet": {"hide": true, "value": []}
},
"wm.NotificationVariable": {
@@ -148,13 +148,15 @@ wm.variables.factories.BaseVariablePropertyFactory = [
"operation": {"type": "list", "hide": true, "options": [], "required": true},
"autoUpdate": {"type": "boolean", "widgettype": "boolean-inputfirst", "value": false, "hide": true},
"startUpdate": {"type": "boolean", "widgettype": "boolean-inputfirst", "value": false, "hide": true},
+ "spinnerContext": {"type": "list", "options": {"": "", "page": "page"}, "placeholder": "Search Widgets", "widgettype": "typeahead", "hide": true},
+ "spinnerMessage": {"type": "string", "hide": true},
/*events*/
"onSuccess": {"type": "event", "options": variableEventOptions},
"onError": {"type": "event", "options": variableEventOptions},
"onProgress": {"type": "event", "options": variableEventOptions, "hide": true},
"onOnline": {"type": "event", "options": variableEventOptions, "hide": true},
"onOffline": {"type": "event", "options": variableEventOptions, "hide": true},
- "onBeforePush": {"type": "event", "options": variableEventOptions, "hide": true}
+ "onBefore": {"type": "event", "options": variableEventOptions, "hide": true}
},
"wm.WebSocketVariable": {
"name": {"type": "string", "required": true, "pattern": variableRegex},
diff --git a/src/main/webapp/scripts/modules/variables/application/base/baseservice.js b/src/main/webapp/scripts/modules/variables/application/base/baseservice.js
index bedf5e850..c113a32ee 100644
--- a/src/main/webapp/scripts/modules/variables/application/base/baseservice.js
+++ b/src/main/webapp/scripts/modules/variables/application/base/baseservice.js
@@ -24,7 +24,8 @@ wm.variables.services.Variables = [
"BindingManager",
"MetaDataFactory",
"WIDGET_CONSTANTS",
- function ($rootScope, BaseVariablePropertyFactory, ProjectService, FileService, VariableService, CONSTANTS, VARIABLE_CONSTANTS, DialogService, $timeout, Utils, BindingManager, MetaDataFactory, WIDGET_CONSTANTS) {
+ "$q",
+ function ($rootScope, BaseVariablePropertyFactory, ProjectService, FileService, VariableService, CONSTANTS, VARIABLE_CONSTANTS, DialogService, $timeout, Utils, BindingManager, MetaDataFactory, WIDGET_CONSTANTS, $q) {
"use strict";
/**
@@ -50,7 +51,7 @@ wm.variables.services.Variables = [
var runMode = CONSTANTS.isRunMode,
DOT_EXPR_REX = /^\[("|')[\w\W]*(\1)\]$/g,
MAIN_PAGE = 'Main',
- startUpdateQueue = [],
+ startUpdateQueue = {},
lazySartUpdateQueue = {},
internalBoundNodeMap = {},
variableConfig = {
@@ -99,7 +100,8 @@ wm.variables.services.Variables = [
"defaultName" : "loginVariable",
"appOnly" : true,
"spinnerInFlight": true,
- "newVariableKey": "New LoginVariable"
+ "newVariableKey": "New LoginVariable",
+ "hideInEvents" : true
},
"wm.LogoutVariable": {
"collectionType" : "data",
@@ -107,7 +109,8 @@ wm.variables.services.Variables = [
"defaultName" : "logoutVariable",
"appOnly" : true,
"spinnerInFlight": true,
- "newVariableKey": "New LogoutVariable"
+ "newVariableKey": "New LogoutVariable",
+ "hideInEvents" : true
},
"wm.TimerVariable": {
"collectionType": "data",
@@ -517,7 +520,11 @@ wm.variables.services.Variables = [
if ((newVal === oldVal && WM.isUndefined(newVal)) || (WM.isUndefined(newVal) && (!WM.isUndefined(oldVal) || !WM.isUndefined(targetObj[targetNodeKey])))) {
return;
}
- setValueToNode(target, obj, root, variable, Utils.getClonedObject(newVal)); // clonning newVal to keep the source clean
+ //Skip cloning for blob column
+ if (!_.includes(['blob', 'file'], obj.type)) {
+ newVal = Utils.getClonedObject(newVal);
+ }
+ setValueToNode(target, obj, root, variable, newVal); // clonning newVal to keep the source clean
if (runMode) {
if (WM.isObject(newVal)) {
@@ -641,13 +648,14 @@ wm.variables.services.Variables = [
* @param variable
*/
makeVariableCall = function (variable) {
- var method;
+ var method, deferredVariableCall = $q.defer();
switch (variable.category) {
case 'wm.ServiceVariable':
method = 'update';
break;
case 'wm.WebSocketVariable':
method = 'open';
+ deferredVariableCall.resolve();
break;
case 'wm.LiveVariable':
/*
@@ -666,14 +674,18 @@ wm.variables.services.Variables = [
break;
case 'wm.TimerVariable':
method = 'fire';
+ deferredVariableCall.resolve();
break;
case 'wm.DeviceVariable':
method = 'invoke';
break;
}
if (WM.isFunction(variable[method])) {
- variable[method]();
+ variable[method](undefined, deferredVariableCall.resolve, deferredVariableCall.reject);
+ } else {
+ deferredVariableCall.reject();
}
+ return deferredVariableCall.promise;
},
/**
@@ -689,10 +701,124 @@ wm.variables.services.Variables = [
lazySartUpdateQueue[scope.$id] = lazySartUpdateQueue[scope.$id] || [];
lazySartUpdateQueue[scope.$id].push(variable);
} else {
- startUpdateQueue.push(variable);
+ startUpdateQueue[scope.$id] = startUpdateQueue[scope.$id] || [];
+ startUpdateQueue[scope.$id].push(variable);
}
},
+ /*
+ * Trigger update on variable based on run/studio mode
+ * */
+ updateVariableData = function (variable, name, context, scope, options) {
+ /* assign variable name to the variable object for later use */
+ variable.name = name;
+ if (variable.init) {
+ variable.init();
+ }
+ if (runMode) {
+ variable.activeScope = scope;
+ } else {
+ /* this copy is used by binding dialog in STUDIO mode */
+ self.studioCopy[context][name] = variable;
+ }
+ /* update variable bindings */
+ updateVariableBinding(variable, name, scope);
+
+ /*iterating over the collection to update the variables appropriately.*/
+ if (variable.category === "wm.Variable") {
+ /*
+ * Case: a LIST type static variable having only one object
+ * and the object has all fields empty, remove that object
+ */
+ if (CONSTANTS.isRunMode && variable.isList && variable.dataSet.length === 1) {
+ var firstObj = variable.dataSet[0],
+ isEmpty = true,
+ checkEmpty = function (obj) {
+ _.forEach(obj, function (value) {
+ if (!_.isEmpty(value)) {
+ if (_.isObject(value)) {
+ if (_.isArray(value)) {
+ //If array, check if array is empty or if it has only one value and the value is empty
+ isEmpty = _.isEmpty(value) || (value.length === 1 ? _.isEmpty(value[0]) : false);
+ } else {
+ //If object, loop over the object to check if it is empty or not
+ checkEmpty(value);
+ }
+ } else {
+ isEmpty = false;
+ }
+ }
+ return isEmpty;
+ });
+ };
+ checkEmpty(firstObj);
+ if (isEmpty) {
+ variable.dataSet = [];
+ }
+ }
+ } else if (variable.category === "wm.ServiceVariable") {
+ if (runMode) {
+ variable.canUpdate = true;
+ if (variable.startUpdate) {
+ processVariableStartUpdate(variable, scope);
+ }
+ } else {
+ //fetching the meta data in design mode always
+ if (WM.isFunction(variable.update)) {
+ variable.update(options);
+ }
+ }
+ } else if (variable.category === "wm.WebSocketVariable") {
+ if (runMode) {
+ if (variable.startUpdate) {
+ processVariableStartUpdate(variable, scope);
+ }
+ } else {
+ //fetching the meta data in design mode always
+ if (WM.isFunction(variable.update)) {
+ variable.update();
+ }
+ }
+ } else if (variable.category === "wm.LiveVariable") {
+ migrateOrderBy(variable);
+ if (runMode) {
+ variable.canUpdate = true;
+ if (variable.startUpdate) {
+ processVariableStartUpdate(variable, scope);
+ }
+ } else {
+ if (variable.startUpdate && WM.isFunction(variable.update)) {
+ $timeout(function () {
+ variable.update();
+ }, null, false);
+ } else {
+ /*
+ * In studio mode, DB and table related data is to be fetched and saved in the variable
+ * So, getData is called in STUDIO mode for liva variables with all types of operations
+ * since startUpdate is unset, table data is not required, hence skipFetchData flag is set
+ */
+ $timeout(function () {
+ /* keeping the call in a timeout to wait for the widgets to load first and the binding to take effect */
+ if (WM.isFunction(variable.update)) {
+ variable.update({skipFetchData: true});
+ }
+ }, null, false);
+ }
+ }
+ } else if (variable.category === "wm.LoginVariable") {
+ if (runMode && variable.startUpdate) {
+ processVariableStartUpdate(variable, scope);
+ }
+ } else if (variable.category === "wm.TimerVariable") {
+ if (runMode && variable.autoStart) {
+ processVariableStartUpdate(variable, scope);
+ }
+ } else if (variable.category === "wm.DeviceVariable") {
+ if (runMode && variable.startUpdate) {
+ processVariableStartUpdate(variable, scope);
+ }
+ }
+ },
/*
* Updates the variables in a context with their latest values
* context refers to the namespace for the variables collection, like 'app'/page/partial/prefab
@@ -724,100 +850,9 @@ wm.variables.services.Variables = [
}
});
}
- WM.forEach(self.variableCollection[scope.$id], function (variable, name) {
- /* assign variable name to the variable object for later use */
- variable.name = name;
- if (variable.init) {
- variable.init();
- }
- if (runMode) {
- variable.activeScope = scope;
- } else {
- /* this copy is used by binding dialog in STUDIO mode */
- self.studioCopy[context][name] = variable;
- }
-
- /* update variable bindings */
- updateVariableBinding(variable, name, scope);
-
- /*iterating over the collection to update the variables appropriately.*/
- if (variable.category === "wm.Variable") {
- /*
- * Case: a LIST type static variable having only one object
- * and the object has all fields empty, remove that object
- */
- if (CONSTANTS.isRunMode && variable.isList && variable.dataSet.length === 1) {
- var obj = variable.dataSet[0],
- keys = Object.keys(obj),
- isValueEmpty = function (val) {
- return _.isEmpty(obj[val]);
- };
- if (keys.every(isValueEmpty)) {
- variable.dataSet = [];
- }
- }
- } else if (variable.category === "wm.ServiceVariable") {
- if (runMode) {
- variable.canUpdate = true;
- if (variable.startUpdate) {
- processVariableStartUpdate(variable, scope);
- }
- } else {
- //fetching the meta data in design mode always
- if (WM.isFunction(variable.update)) {
- variable.update();
- }
- }
- } else if (variable.category === "wm.WebSocketVariable") {
- if (runMode) {
- if (variable.startUpdate) {
- processVariableStartUpdate(variable, scope);
- }
- } else {
- //fetching the meta data in design mode always
- if (WM.isFunction(variable.update)) {
- variable.update();
- }
- }
- } else if (variable.category === "wm.LiveVariable") {
- migrateOrderBy(variable);
- if (runMode) {
- variable.canUpdate = true;
- if (variable.startUpdate) {
- processVariableStartUpdate(variable, scope);
- }
- } else {
- if (variable.startUpdate && WM.isFunction(variable.update)) {
- $timeout(function () {
- variable.update();
- }, null, false);
- } else {
- /*
- * In studio mode, DB and table related data is to be fetched and saved in the variable
- * So, getData is called in STUDIO mode for liva variables with all types of operations
- * since startUpdate is unset, table data is not required, hence skipFetchData flag is set
- */
- $timeout(function () {
- /* keeping the call in a timeout to wait for the widgets to load first and the binding to take effect */
- if (WM.isFunction(variable.update)) {
- variable.update({skipFetchData: true});
- }
- }, null, false);
- }
- }
- } else if (variable.category === "wm.LoginVariable") {
- if (runMode && variable.startUpdate) {
- processVariableStartUpdate(variable, scope);
- }
- } else if (variable.category === "wm.TimerVariable") {
- if (runMode && variable.autoStart) {
- processVariableStartUpdate(variable, scope);
- }
- } else if (variable.category === "wm.DeviceVariable") {
- if (runMode && variable.startUpdate) {
- processVariableStartUpdate(variable, scope);
- }
- }
+ _.forEach(self.variableCollection[scope.$id], function (variable, name) {
+ //Trigger update on variable based on run/studio mode
+ updateVariableData(variable, name, context, scope);
});
},
@@ -949,9 +984,14 @@ wm.variables.services.Variables = [
// removing dataSet for live variable
if (!runMode && variable.category === "wm.LiveVariable") {
variables[name].dataSet = [];
- } else if (runMode && (variable.category === "wm.ServiceVariable" ||variable.category === "wm.WebSocketVariable")) {
+ } else if (runMode && (variable.category === "wm.ServiceVariable" || variable.category === "wm.WebSocketVariable")) {
// Attaching service operation info to variables if in run mode
variables[name]._wmServiceOperationInfo = MetaDataFactory.getByOperationId(variable.operationId, variable._prefabName);
+
+ // service variable migration for old service variables not having controller names
+ if (runMode && !variable.controller && variable.operationId) {
+ variables[name].controller = variable.operationId.split('_')[0].replace(/Controller$/, '');
+ }
}
});
@@ -1391,6 +1431,10 @@ wm.variables.services.Variables = [
varCollectionObj[scope.$id][name].name = name;
self.studioCopy[owner][name] = varCollectionObj[scope.$id][name];
+ if (variableObj.category === 'wm.LiveVariable') {
+ variableObj._isNew = true;
+ }
+
/* if app level variable make it available in the active page scope */
if (owner === VARIABLE_CONSTANTS.OWNER.APP) {
if ($rootScope.activePageName && pageScopeMap[$rootScope.activePageName]) {
@@ -1403,13 +1447,13 @@ wm.variables.services.Variables = [
}
}
if (!_.includes(CRUDMAP.CREATE[owner], name)) {
- CRUDMAP.CREATE[owner].push(name);/*Storing created variable name in map*/
+ CRUDMAP.CREATE[owner].push(name);/*Storing created variable name in map*/
}
if (isUpdate) {
- call('getData', name, {scope: scope, skipFetchData: !fetchData});
+ updateVariableData(varCollectionObj[scope.$id][name], name, owner, scope, {skipFetchData: !fetchData})
}
},
- initiateCallback = function (event, variable, response, info) {
+ initiateCallback = function (event, variable, response, info, skipDefaultNotification) {
/*checking if event is available and variable has event property and variable event property bound to function*/
var eventValues = variable[event],
retVal,
@@ -1417,7 +1461,7 @@ wm.variables.services.Variables = [
callBackScope = variable.activeScope;
if (eventValues) {
retVal = Utils.triggerCustomEvents(event, eventValues, callBackScope, response, variable, info);
- } else if (event === VARIABLE_CONSTANTS.EVENT.ERROR) {
+ } else if ((event === VARIABLE_CONSTANTS.EVENT.ERROR) && !skipDefaultNotification) {
/* in case of error, if no event assigned, handle through default notification variable */
errorVariable = getVariableByName(VARIABLE_CONSTANTS.DEFAULT_VAR.NOTIFICATION);
if (errorVariable) {
@@ -1458,14 +1502,24 @@ wm.variables.services.Variables = [
delete self.variableCollection[scopeId];
},
+ //Trigger error handler before discarding queued requests
+ triggerError = function (requestQueue) {
+ _.forEach(requestQueue, function (requestObj) {
+ Utils.triggerFn(requestObj && requestObj.error);
+ });
+ },
+
/* process the requests in the queue for a variable based on the inFlightBehavior flag of the variable */
- processRequestQueue = function (variable, requestQueue, handler) {
+ processRequestQueue = function (variable, requestQueue, handler, options) {
/* process request queue for the variable only if it is not empty */
if (requestQueue && requestQueue[variable.name] && requestQueue[variable.name].length) {
- var requestObj;
- switch (variable.inFlightBehavior) {
+ var requestObj,
+ inFlightBehavior = _.get(options, 'inFlightBehavior') || variable.inFlightBehavior;
+
+ switch (inFlightBehavior) {
case 'executeLast':
requestObj = requestQueue[variable.name].pop();
+ triggerError(requestQueue);
handler(requestObj.variable, requestObj.options, requestObj.success, requestObj.error);
requestQueue[variable.name] = null;
break;
@@ -1474,6 +1528,7 @@ wm.variables.services.Variables = [
handler(requestObj.variable, requestObj.options, requestObj.success, requestObj.error);
break;
default:
+ triggerError(requestQueue);
requestQueue[variable.name] = null;
break;
}
@@ -1636,8 +1691,32 @@ wm.variables.services.Variables = [
getBindMap(field.type, curFieldObj, oldBindings[fieldName], visitedNodes);
});
}
- };
+ },
+ getEvaluatedOrderBy = function (varOrder, optionsOrder) {
+ var optionFields,
+ varOrderBy;
+ //If options order by is not defined, return variable order
+ if (!optionsOrder || WM.element.isEmptyObject(optionsOrder)) {
+ return varOrder;
+ }
+ //If variable order by is not defined, return options order
+ if (!varOrder) {
+ return optionsOrder;
+ }
+ //If both are present, combine the options order and variable order, with options order as precedence
+ varOrder = _.split(varOrder, ',');
+ optionsOrder = _.split(optionsOrder, ',');
+ optionFields = _.map(optionsOrder, function (order) {
+ return _.split(_.trim(order), ' ')[0];
+ });
+ //If a field is present in both options and variable, remove the variable orderby
+ _.remove(varOrder, function (orderBy) {
+ return _.includes(optionFields, _.split(_.trim(orderBy), ' ')[0]);
+ });
+ varOrderBy = varOrder.length ? ',' + _.join(varOrder, ',') : '';
+ return _.join(optionsOrder, ',') + varOrderBy;
+ };
/*
* This object is used to collect all the variables and keep them organized
* based on their nature.
@@ -1670,14 +1749,31 @@ wm.variables.services.Variables = [
* This delay is to wait for the widgets to compile so that the same(and app variables) can be consumed as input to the variables.
*/
if (CONSTANTS.isRunMode) {
- $rootScope.$on('page-ready', function () {
- _.forEach(startUpdateQueue, makeVariableCall);
- startUpdateQueue = [];
+ $rootScope.$on('page-ready', function (e, pageName) {
+ /*
+ * checking on page name's equality to active page name.
+ * when swift navigation among two pages is done,
+ * the event for first page is emitted after the second page and its variables are loaded
+ */
+ var pageScope = pageScopeMap[pageName],
+ pageScopeId = pageScope.$id;
+ $q.all(_.map(startUpdateQueue[pageScopeId], makeVariableCall))
+ .finally(function () {
+ $rootScope.$emit('page-startupdate-variables-loaded', pageName);
+ });
+ delete startUpdateQueue[pageScopeId];
+
+ if (startUpdateQueue[$rootScope.$id]) {
+ _.forEach(startUpdateQueue[$rootScope.$id], makeVariableCall);
+ delete startUpdateQueue[$rootScope.$id];
+ }
});
$rootScope.$on('partial-ready', function (event, scope) {
- if (lazySartUpdateQueue[scope.$id]) {
- _.forEach(lazySartUpdateQueue[scope.$id], makeVariableCall);
- lazySartUpdateQueue[scope.$id] = undefined;
+ var queue = lazySartUpdateQueue[scope.$id] || startUpdateQueue[scope.$id];
+ if (queue) {
+ _.forEach(queue, makeVariableCall);
+ delete lazySartUpdateQueue[scope.$id];
+ delete startUpdateQueue[scope.$id];
}
});
}
@@ -2142,6 +2238,7 @@ wm.variables.services.Variables = [
/*Set the "liveSource" and "type" properties of the live-variable.*/
createdVariable.liveSource = variableDetails.service;
createdVariable.type = variableDetails.table;
+ createdVariable.package = variableDetails.package;
createdVariable.category = variableCategory;
createdVariable.isDefault = true;
_.forEach(['maxResults', 'startUpdate', 'autoUpdate', 'bindCount'], function (property) {
@@ -2381,7 +2478,17 @@ wm.variables.services.Variables = [
},
getVariableConfig: function () {
return variableConfig;
- }
+ },
+ /**
+ * @ngdoc method
+ * @name $Variables#getEvaluatedOrderBy
+ * @methodOf wm.variables.$Variables
+ * @description
+ * combines variable orderby and options orderby
+ * @params {string} varOrder variable order by
+ * @params {string} optionsOrder options order by
+ */
+ getEvaluatedOrderBy: getEvaluatedOrderBy
};
return returnObject;
diff --git a/src/main/webapp/scripts/modules/variables/application/livevariable/livevariableservice.js b/src/main/webapp/scripts/modules/variables/application/livevariable/livevariableservice.js
index f48d48da8..0f1f556bc 100644
--- a/src/main/webapp/scripts/modules/variables/application/livevariable/livevariableservice.js
+++ b/src/main/webapp/scripts/modules/variables/application/livevariable/livevariableservice.js
@@ -168,6 +168,7 @@ wm.variables.services.$liveVariable = [
DataModelDesignManager.getDataModel(projectID, variable.liveSource, false, function (database) {
var variableTable,
variableType,
+ firstPrimaryKey,
tableNameToEntityNameMap = {},
entityNameToTableNameMap = {},
getJavaType = function (javaType) {
@@ -373,8 +374,16 @@ wm.variables.services.$liveVariable = [
}
});
- setVariableProp(variable, writableVariable, "propertiesMap", tableDetails[variableType]);
+ setVariableProp(variable, writableVariable, 'propertiesMap', tableDetails[variableType]);
+ if (writableVariable && writableVariable._isNew) {
+ //For new variable, if orderby is not set, set the default orderby as primary field with ascending order
+ firstPrimaryKey = _.head(variable.propertiesMap.primaryFields);
+ if (!writableVariable.orderBy && firstPrimaryKey) {
+ setVariableProp(variable, writableVariable, 'orderBy', firstPrimaryKey + ' asc');
+ }
+ variable._isNew = writableVariable._isNew = false;
+ }
Utils.triggerFn(callback, projectID, variable, options, success);
}, WM.noop);
},
@@ -644,7 +653,7 @@ wm.variables.services.$liveVariable = [
}
query = 'q=' + query;
}
- orderByFields = (!options.orderBy || WM.element.isEmptyObject(options.orderBy)) ? variable.orderBy : options.orderBy;
+ orderByFields = Variables.getEvaluatedOrderBy(variable.orderBy, options.orderBy);
orderByOptions = orderByFields ? 'sort=' + orderByFields : '';
return {
@@ -694,7 +703,7 @@ wm.variables.services.$liveVariable = [
/* process next requests in the queue */
variableActive[variable.activeScope.$id][variable.name] = false;
- processRequestQueue(variable, requestQueue[variable.activeScope.$id], deployProjectAndFetchData);
+ processRequestQueue(variable, requestQueue[variable.activeScope.$id], deployProjectAndFetchData, options);
}, null, false);
}
};
@@ -705,8 +714,9 @@ wm.variables.services.$liveVariable = [
output = initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_UPDATE, variable, clonedFields);
if (output === false) {
variableActive[variable.activeScope.$id][variable.name] = false;
- processRequestQueue(variable, requestQueue[variable.activeScope.$id], deployProjectAndFetchData);
+ processRequestQueue(variable, requestQueue[variable.activeScope.$id], deployProjectAndFetchData, options);
$rootScope.$emit('toggle-variable-state', variable.name, false);
+ Utils.triggerFn(error);
return;
}
variable.canUpdate = false;
@@ -787,7 +797,7 @@ wm.variables.services.$liveVariable = [
if (CONSTANTS.isRunMode) {
/* process next requests in the queue */
variableActive[variable.activeScope.$id][variable.name] = false;
- processRequestQueue(variable, requestQueue[variable.activeScope.$id], deployProjectAndFetchData);
+ processRequestQueue(variable, requestQueue[variable.activeScope.$id], deployProjectAndFetchData, options);
}
/* if callback function is provided, send the data to the callback */
Utils.triggerFn(success, dataObj.data, variable.propertiesMap, dataObj.pagingOptions);
@@ -986,8 +996,9 @@ wm.variables.services.$liveVariable = [
output = initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_UPDATE, variableDetails, clonedFields);
if (output === false) {
variableActive[variableDetails.activeScope.$id][variableDetails.name] = false;
- processRequestQueue(variableDetails, requestQueue[variableDetails.activeScope.$id], deployProjectAndFetchData);
+ processRequestQueue(variableDetails, requestQueue[variableDetails.activeScope.$id], deployProjectAndFetchData, options);
$rootScope.$emit('toggle-variable-state', variableDetails.name, false);
+ Utils.triggerFn(error);
return;
}
inputFields = _.isObject(output) ? output : clonedFields;
diff --git a/src/main/webapp/scripts/modules/variables/application/loginvariable/loginvariableservice.js b/src/main/webapp/scripts/modules/variables/application/loginvariable/loginvariableservice.js
index 0773991ea..9ce6e05ae 100644
--- a/src/main/webapp/scripts/modules/variables/application/loginvariable/loginvariableservice.js
+++ b/src/main/webapp/scripts/modules/variables/application/loginvariable/loginvariableservice.js
@@ -41,26 +41,12 @@ wm.variables.services.LoginVariableService = ['Variables',
methods = {
login: function (variable, options, success, error) {
var params = {},
- variableOwner = variable.owner,
variableEvents = VARIABLE_CONSTANTS.EVENTS,
- callBackScope,
errMsg,
paramKey,
output,
loginInfo = {};
- /* get the callback scope for the variable based on its owner */
- if (variableOwner === "App") {
- /* TODO: to look for a better option to get App/Page the controller's scope */
- callBackScope = $rootScope || {};
- } else {
- if (variable._prefabName) {
- callBackScope = options.scope || {};
- } else {
- callBackScope = (options.scope && options.scope.$$childTail) ? options.scope.$$childTail : {};
- }
- }
-
/* If login info provided along explicitly with options, don't look into the variable bindings for the same */
if (options.loginInfo) {
loginInfo = options.loginInfo;
@@ -81,19 +67,22 @@ wm.variables.services.LoginVariableService = ['Variables',
/* if in RUN mode, trigger error events associated with the variable */
if (CONSTANTS.isRunMode) {
Utils.triggerFn(error, errMsg);
- initiateCallback("onError", variable, callBackScope, errMsg);
+ initiateCallback("onError", variable, errMsg);
}
return;
}
//Triggering 'onBeforeUpdate' and considering
- output = initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_UPDATE, variable, callBackScope, params);
+ output = initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_UPDATE, variable, params);
if (_.isObject(output)) {
params = output;
} else if (output === false) {
+ Utils.triggerFn(error);
return;
}
+ $rootScope.$emit('toggle-variable-state', variable.name, true);
variable.promise = SecurityService.appLogin(params, function (response) {
+ $rootScope.$emit('toggle-variable-state', variable.name, false);
var redirectUrl = response && response.url ? response.url : 'index.html',
appManager = Utils.getService("AppManager"),
lastLoggedinUser = SecurityService.getLastLoggedInUser();
@@ -114,7 +103,7 @@ wm.variables.services.LoginVariableService = ['Variables',
WM.forEach(variableEvents, function (event) {
if (event !== 'onError' && event !== VARIABLE_CONSTANTS.EVENT.BEFORE_UPDATE) {
- initiateCallback(event, variable, callBackScope, _.get(config, 'userInfo'));
+ initiateCallback(event, variable, _.get(config, 'userInfo'));
}
});
@@ -155,10 +144,11 @@ wm.variables.services.LoginVariableService = ['Variables',
$rootScope._noRedirect = undefined;
});
}, function (errorMsg) {
+ $rootScope.$emit('toggle-variable-state', variable.name, false);
errorMsg = errorMsg || "Invalid credentials.";
/* if in RUN mode, trigger error events associated with the variable */
if (CONSTANTS.isRunMode) {
- initiateCallback("onError", variable, callBackScope, errorMsg);
+ initiateCallback("onError", variable, errorMsg);
}
Utils.triggerFn(error, errorMsg);
});
diff --git a/src/main/webapp/scripts/modules/variables/application/logoutvariable/logoutvariableservice.js b/src/main/webapp/scripts/modules/variables/application/logoutvariable/logoutvariableservice.js
index 7bca32997..10b89ed70 100644
--- a/src/main/webapp/scripts/modules/variables/application/logoutvariable/logoutvariableservice.js
+++ b/src/main/webapp/scripts/modules/variables/application/logoutvariable/logoutvariableservice.js
@@ -41,72 +41,66 @@ wm.variables.services.LogoutVariableService = ['Variables',
methods = {
logout: function (variable, options, success, error) {
- var variableOwner = variable.owner,
- variableEvents = VARIABLE_CONSTANTS.EVENTS,
- callBackScope,
+ var variableEvents = VARIABLE_CONSTANTS.EVENTS,
logoutErrorMessage = "No authenticated user to logout.",
handleError,
redirectPage,
- appManager;
-
- /* get the callback scope for the variable based on its owner */
- if (variableOwner === "App") {
- /* TODO: to look for a better option to get App/Page the controller's scope */
- callBackScope = $rootScope || {};
- } else {
- if (variable._prefabName) {
- callBackScope = options.scope || {};
- } else {
- callBackScope = (options.scope && options.scope.$$childTail) ? options.scope.$$childTail : {};
- }
- }
+ appManager,
+ output;
handleError = function (msg) {
/* if in RUN mode, trigger error events associated with the variable */
if (CONSTANTS.isRunMode) {
- initiateCallback("onError", variable, callBackScope, msg);
+ initiateCallback("onError", variable, msg);
}
Utils.triggerFn(error, msg);
};
+ $rootScope.$emit('toggle-variable-state', variable.name, true);
+ // EVENT: ON_BEFORE_UPDATE
+ output = initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_UPDATE, variable);
+ if (output === false) {
+ Utils.triggerFn(error);
+ return;
+ }
SecurityService.isAuthenticated(function (isAuthenticated) {
+ $rootScope.$emit('toggle-variable-state', variable.name, false);
if (isAuthenticated) {
variable.promise = SecurityService.appLogout(function (redirectUrl) {
- redirectUrl = Utils.getValidJSON(redirectUrl);
+ // Reset Security Config.
+ $rootScope.isUserAuthenticated = false;
+ appManager = Utils.getService("AppManager");
+ appManager.resetSecurityConfig().
+ then(function () {
+ // EVENT: ON_RESULT
+ initiateCallback(VARIABLE_CONSTANTS.EVENT.RESULT, variable, redirectUrl);
+ // EVENT: ON_SUCCESS
+ initiateCallback(VARIABLE_CONSTANTS.EVENT.SUCCESS, variable, redirectUrl);
+ });
+
//In case of CAS response will be the redirectUrl
+ redirectUrl = Utils.getValidJSON(redirectUrl);
if (redirectUrl) {
$window.location.href = redirectUrl.result;
- } else {
- if (variable.useDefaultSuccessHandler) {
- redirectPage = variable.redirectTo;
- /* backward compatibility (index.html/login.html may be present in older projects) */
- if (!redirectPage || redirectPage === "login.html" || redirectPage === "index.html") {
- redirectPage = "";
- }
- $location.url(redirectPage);
- $timeout(function () {
- // reloading in timeout as, firefox and safari are not updating the url before reload(WMS-7887)
- $window.location.reload();
- });
- } else if (CONSTANTS.isRunMode) {
- appManager = Utils.getService("AppManager");
- appManager.resetSecurityConfig().
- then(function () {
- WM.forEach(variableEvents, function (event) {
- if (event !== "onError") {
- initiateCallback(event, variable, callBackScope);
- }
- });
- });
+ } else if (variable.useDefaultSuccessHandler) {
+ redirectPage = variable.redirectTo;
+ /* backward compatibility (index.html/login.html may be present in older projects) */
+ if (!redirectPage || redirectPage === "login.html" || redirectPage === "index.html") {
+ redirectPage = "";
}
+ $location.url(redirectPage);
+ $timeout(function () {
+ // reloading in timeout as, firefox and safari are not updating the url before reload(WMS-7887)
+ $window.location.reload();
+ });
}
- $rootScope.isUserAuthenticated = false;
Utils.triggerFn(success);
}, handleError);
} else {
handleError();
}
}, function () {
+ $rootScope.$emit('toggle-variable-state', variable.name, false);
handleError(logoutErrorMessage);
});
},
diff --git a/src/main/webapp/scripts/modules/variables/application/servicevariable/servicevariableservice.js b/src/main/webapp/scripts/modules/variables/application/servicevariable/servicevariableservice.js
index f0df190ed..5b6a89c5d 100644
--- a/src/main/webapp/scripts/modules/variables/application/servicevariable/servicevariableservice.js
+++ b/src/main/webapp/scripts/modules/variables/application/servicevariable/servicevariableservice.js
@@ -154,23 +154,49 @@ wm.variables.services.$servicevariable = ['Variables',
function isQueryServiceVar(variable) {
return variable.controller === CONTROLLER_TYPE_QUERY && variable.serviceType === VARIABLE_CONSTANTS.SERVICE_TYPE_DATA;
}
-
+ /*
+ * Check for missing required params and format the date/time param values
+ * */
+ function processRequestBody(inputData, params) {
+ var requestBody = {},
+ missingParams = [],
+ paramValue;
+ _.forEach(params, function (param) {
+ paramValue = _.get(inputData, param.name);
+ if (WM.isDefined(paramValue) && (paramValue !== '')) {
+ paramValue = Utils.isDateTimeType(param.type) ? Utils.formatDate(paramValue, param.type) : paramValue;
+ //Construct ',' separated string if param is not array type but value is an array
+ if (WM.isArray(paramValue) && _.toLower(Utils.extractType(param.type)) === 'string') {
+ paramValue = _.join(paramValue, ',');
+ }
+ requestBody[param.name] = paramValue;
+ } else if (param.required) {
+ missingParams.push(param.name || param.id);
+ }
+ });
+ return {
+ 'requestBody' : requestBody,
+ 'missingParams' : missingParams
+ };
+ }
/**
* function to create the params to invoke the java service. creating the params and the corresponding
* url to invoke based on the type of the parameter
* @param operationInfo
* @param variable
+ * @param inputFields to be considered for body type query/procedure variables
* @returns {*}
*/
- function constructRestRequestParams(operationInfo, variable) {
+ function constructRestRequestParams(operationInfo, variable, inputFields) {
variable = variable || {};
var queryParams = '',
directPath = operationInfo.directPath || '',
relativePath = operationInfo.basePath ? operationInfo.basePath + operationInfo.relativePath : operationInfo.relativePath,
+ bodyInfo,
headers = {},
requestBody,
url,
- requiredParamMissing = false,
+ requiredParamMissing = [],
target,
pathParamRex,
invokeParams,
@@ -180,7 +206,10 @@ wm.variables.services.$servicevariable = ['Variables',
method,
formData,
formDataContentType,
- isProxyCall;
+ isProxyCall,
+ isBodyTypeQueryProcedure = ServiceFactory.isBodyTypeQueryProcedure(variable),
+ variableData,
+ params;
function getFormDataObj() {
if (formData) {
@@ -204,11 +233,15 @@ wm.variables.services.$servicevariable = ['Variables',
_.forEach(operationInfo.parameters, function (param) {
var paramValue = param.sampleValue;
- if (WM.isDefined(paramValue) && paramValue !== '') {
+ if ((WM.isDefined(paramValue) && paramValue !== '') || isBodyTypeQueryProcedure) {
//Format dateTime params for dataService variables
if (variable.serviceType === 'DataService' && Utils.isDateTimeType(param.type)) {
paramValue = Utils.formatDate(paramValue, param.type);
}
+ //Construct ',' separated string if param is not array type but value is an array
+ if (WM.isArray(paramValue) && _.toLower(Utils.extractType(param.type)) === 'string' && variable.serviceType === 'DataService') {
+ paramValue = _.join(paramValue, ',');
+ }
switch (param.parameterType.toUpperCase()) {
case 'QUERY':
//Ignore null valued query params for queryService variable
@@ -241,25 +274,42 @@ wm.variables.services.$servicevariable = ['Variables',
headers[param.name] = paramValue;
break;
case 'BODY':
- requestBody = paramValue;
+ //For post/put query methods wrap the input
+ if (isBodyTypeQueryProcedure) {
+ if (inputFields) {
+ variableData = inputFields;
+ params = _.get(operationInfo, ['definitions', param.type]);
+ } else {
+ //This is for Api Designer
+ variableData = paramValue || {};
+ params = param.children;
+ }
+ bodyInfo = processRequestBody(variableData, params);
+ requestBody = bodyInfo.requestBody;
+ requiredParamMissing = _.concat(requiredParamMissing, bodyInfo.missingParams);
+ } else {
+ requestBody = paramValue;
+ }
break;
case 'FORMDATA':
requestBody = Utils.getFormData(getFormDataObj(), param, paramValue);
break;
}
} else if (param.required) {
- requiredParamMissing = param.name || param.id;
+ requiredParamMissing.push(param.name || param.id);
return false;
}
});
// if required param not found, return error
+ requiredParamMissing = requiredParamMissing.join(', ');
if (requiredParamMissing) {
return {
'error': {
- 'type': 'required_field_missing',
- 'field': requiredParamMissing,
- 'message': 'Required field : "' + requiredParamMissing + '" missing'
+ 'type' : 'required_field_missing',
+ 'field' : requiredParamMissing,
+ 'message' : 'Required field(s) missing: "' + requiredParamMissing + '"',
+ 'skipDefaultNotification' : true
}
};
}
@@ -314,7 +364,8 @@ wm.variables.services.$servicevariable = ['Variables',
"headers": headers,
"dataParams": requestBody,
"authType": authType,
- "isDirectCall": !isProxyCall
+ "isDirectCall": !isProxyCall,
+ "isExtURL": variable.serviceType === SERVICE_TYPE_REST
};
return invokeParams;
@@ -323,10 +374,10 @@ wm.variables.services.$servicevariable = ['Variables',
/**
* function to process error response from a service
*/
- function processErrorResponse(variable, errMsg, errorCB, xhrObj, skipNotification) {
+ function processErrorResponse(variable, errMsg, errorCB, xhrObj, skipNotification, skipDefaultNotification) {
// EVENT: ON_ERROR
if (!skipNotification) {
- initiateCallback(VARIABLE_CONSTANTS.EVENT.ERROR, variable, errMsg, xhrObj);
+ initiateCallback(VARIABLE_CONSTANTS.EVENT.ERROR, variable, errMsg, xhrObj, skipDefaultNotification);
}
/* trigger error callback */
@@ -407,7 +458,7 @@ wm.variables.services.$servicevariable = ['Variables',
} else if (param.name === "page") {
param.sampleValue = options.page || param.sampleValue;
} else if (param.name === "sort") {
- param.sampleValue = options.orderBy || param.sampleValue || variable.orderBy;
+ param.sampleValue = Variables.getEvaluatedOrderBy(variable.orderBy, options.orderBy) || param.sampleValue;
}
}
});
@@ -438,6 +489,7 @@ wm.variables.services.$servicevariable = ['Variables',
if (CONSTANTS.isRunMode) {
output = initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_UPDATE, variable, inputFields);
if (output === false) {
+ Utils.triggerFn(error);
return;
}
if (_.isObject(output)) {
@@ -464,10 +516,10 @@ wm.variables.services.$servicevariable = ['Variables',
}
};
} else {
- params = constructRestRequestParams(methodInfo, variable);
+ params = constructRestRequestParams(methodInfo, variable, inputFields);
}
if (params.error && params.error.message) {
- processErrorResponse(variable, params.error.message, error, options.skipNotification);
+ processErrorResponse(variable, params.error.message, error, options.xhrObj, options.skipNotification, params.error.skipDefaultNotification);
return;
}
} else if (serviceType === SERVICE_TYPE_REST) {
@@ -846,24 +898,35 @@ wm.variables.services.$servicevariable = ['Variables',
setInput: function (key, val, options) {
return methods.setInput(this, key, val, options);
},
- download: function (options) {
- var inputParams = Utils.getClonedObject(this.dataBinding),
- methodInfo = getMethodInfo(this, inputParams, {});
+ download: function (options, errorHandler) {
+ var inputParams = Utils.getClonedObject(this.dataBinding),
+ methodInfo = getMethodInfo(this, inputParams, options),
+ requestParams;
methodInfo.relativePath += '/export/' + options.exportFormat;
- Utils.simulateFileDownload(constructRestRequestParams(methodInfo, this));
+ requestParams = constructRestRequestParams(methodInfo, this);
+
+ //If request params returns error then show an error toaster
+ if (_.hasIn(requestParams, 'error.message')) {
+ Utils.triggerFn(errorHandler, requestParams.error.message);
+ } else {
+ Utils.simulateFileDownload(requestParams);
+ }
},
init: function () {
if (this.isList) {
Object.defineProperty(this, 'firstRecord', {
'get': function () {
- return _.get(methods.getDataSet(this), 'content[0]', {});
+ var dataSet = methods.getDataSet(this);
+ //For procedure(v1) data doesn't come under content
+ return _.head(dataSet && dataSet.content) || _.head(dataSet) || {};
}
});
Object.defineProperty(this, 'lastRecord', {
'get': function () {
- var content = _.get(methods.getDataSet(this), 'content', []);
- return content[content.length - 1];
+ var dataSet = methods.getDataSet(this);
+ //For procedure(v1) data doesn't come under content
+ return _.last(dataSet && dataSet.content) || _.last(dataSet) || {};
}
});
}
diff --git a/src/main/webapp/scripts/modules/variables/application/timervariable/timervariableservice.js b/src/main/webapp/scripts/modules/variables/application/timervariable/timervariableservice.js
index 986446bea..33b331607 100644
--- a/src/main/webapp/scripts/modules/variables/application/timervariable/timervariableservice.js
+++ b/src/main/webapp/scripts/modules/variables/application/timervariable/timervariableservice.js
@@ -40,7 +40,7 @@ wm.variables.services.TimerVariableService = ['Variables',
event = "onTimerFire",
callBackScope = options.scope || $rootScope,
exec = function () {
- initiateCallback(event, variable, callBackScope);
+ initiateCallback(event, variable);
};
variable._promise = repeatTimer ? $interval(exec, delay) : $timeout(function () {
diff --git a/src/main/webapp/scripts/modules/variables/application/websocketvariable/websocketvariableservice.js b/src/main/webapp/scripts/modules/variables/application/websocketvariable/websocketvariableservice.js
index a6839689d..d14f7971f 100644
--- a/src/main/webapp/scripts/modules/variables/application/websocketvariable/websocketvariableservice.js
+++ b/src/main/webapp/scripts/modules/variables/application/websocketvariable/websocketvariableservice.js
@@ -77,7 +77,7 @@ wm.variables.services.$websocketvariable = ['BaseVariablePropertyFactory', 'Vari
function _onSocketOpen(variable, evt) {
variable._socketConnected = true;
// EVENT: ON_OPEN
- initiateCallback(VARIABLE_CONSTANTS.EVENT.OPEN, variable, variable.activeScope, _.get(evt, 'data'), evt);
+ initiateCallback(VARIABLE_CONSTANTS.EVENT.OPEN, variable, _.get(evt, 'data'), evt);
}
/**
@@ -91,7 +91,7 @@ wm.variables.services.$websocketvariable = ['BaseVariablePropertyFactory', 'Vari
variable._socketConnected = false;
freeSocket(variable);
// EVENT: ON_CLOSE
- initiateCallback(VARIABLE_CONSTANTS.EVENT.CLOSE, variable, variable.activeScope, _.get(evt, 'data'), evt);
+ initiateCallback(VARIABLE_CONSTANTS.EVENT.CLOSE, variable, _.get(evt, 'data'), evt);
}
/**
@@ -105,7 +105,7 @@ wm.variables.services.$websocketvariable = ['BaseVariablePropertyFactory', 'Vari
variable._socketConnected = false;
freeSocket(variable);
// EVENT: ON_ERROR
- initiateCallback(VARIABLE_CONSTANTS.EVENT.ERROR, variable, variable.activeScope, _.get(evt, 'data') || 'Error while connecting with ' + variable.service, evt);
+ initiateCallback(VARIABLE_CONSTANTS.EVENT.ERROR, variable, _.get(evt, 'data') || 'Error while connecting with ' + variable.service, evt);
}
/**
@@ -121,7 +121,7 @@ wm.variables.services.$websocketvariable = ['BaseVariablePropertyFactory', 'Vari
var data = _.get(evt, 'data'), value, dataLength, dataLimit, shouldAddToLast, insertIdx;
data = Utils.getValidJSON(data) || Utils.xmlToJson(data) || data;
// EVENT: ON_MESSAGE
- value = initiateCallback(VARIABLE_CONSTANTS.EVENT.MESSAGE_RECEIVE, variable, variable.activeScope, data, evt);
+ value = initiateCallback(VARIABLE_CONSTANTS.EVENT.MESSAGE_RECEIVE, variable, data, evt);
data = WM.isDefined(value) ? value : data;
if (shouldAppendData(variable)) {
variable.dataSet = variable.dataSet || [];
@@ -151,7 +151,7 @@ wm.variables.services.$websocketvariable = ['BaseVariablePropertyFactory', 'Vari
*/
function _onBeforeSend(variable, message) {
// EVENT: ON_BEFORE_SEND
- return initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_SEND, variable, variable.activeScope, message);
+ return initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_SEND, variable, message);
}
/**
@@ -163,7 +163,7 @@ wm.variables.services.$websocketvariable = ['BaseVariablePropertyFactory', 'Vari
*/
function _onBeforeSocketClose(variable, evt) {
// EVENT: ON_BEFORE_CLOSE
- return initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_CLOSE, variable, variable.activeScope, _.get(evt, 'data'), evt);
+ return initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_CLOSE, variable, _.get(evt, 'data'), evt);
}
/**
@@ -176,7 +176,7 @@ wm.variables.services.$websocketvariable = ['BaseVariablePropertyFactory', 'Vari
*/
function _onBeforeSocketOpen(variable, evt) {
// EVENT: ON_BEFORE_OPEN
- return initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_OPEN, variable, variable.activeScope, _.get(evt, 'data'), evt);
+ return initiateCallback(VARIABLE_CONSTANTS.EVENT.BEFORE_OPEN, variable, _.get(evt, 'data'), evt);
}
/**
diff --git a/src/main/webapp/scripts/modules/variables/config.js b/src/main/webapp/scripts/modules/variables/config.js
index 8e8803ed1..062776b25 100644
--- a/src/main/webapp/scripts/modules/variables/config.js
+++ b/src/main/webapp/scripts/modules/variables/config.js
@@ -21,7 +21,7 @@ wm.variables.filter(wm.variables.filters);
/* Defining route path constants for wmCoreModule application */
wm.variables.constant('VARIABLE_CONSTANTS', {
- EVENTS: ["onBeforeUpdate", "onResult", "onBeforeOpen", "onOpen", "onBeforeMessageSend", "onMessageReceive", "onError", "onBeforeDatasetReady", "onCanUpdate", "onClick", "onHide", "onOk", "onCancel", "onBeforeClose", "onClose", "onTimerFire", "onSuccess", "onProgress", "onOnline", "onOffline", "onBeforePush"],
+ EVENTS: ["onBeforeUpdate", "onResult", "onBeforeOpen", "onOpen", "onBeforeMessageSend", "onMessageReceive", "onError", "onBeforeDatasetReady", "onCanUpdate", "onClick", "onHide", "onOk", "onCancel", "onBeforeClose", "onClose", "onTimerFire", "onSuccess", "onProgress", "onOnline", "onOffline", "onBefore"],
EVENT: {
"CAN_UPDATE": "onCanUpdate",
"BEFORE_UPDATE": "onBeforeUpdate",
@@ -50,6 +50,7 @@ wm.variables.constant('VARIABLE_CONSTANTS', {
SERVICE_TYPE_SECURITY: "SecurityServiceType",
SERVICE_NAME_FEED: "FeedService",
SERVICE_TYPE_WEBSOCKET: "WebSocketService",
+ BODY_FIELD: "bodyField",
REST_SUPPORTED_SERVICES: ["JavaService", "SoapService", "FeedService", "RestService", "SecurityServiceType", "DataService", "WebSocketService"],
PAGINATION_PARAMS: ["page", "size", "sort"],
DEFAULT_VAR: {
diff --git a/src/main/webapp/scripts/modules/widgets/advanced/calendar/calendar.js b/src/main/webapp/scripts/modules/widgets/advanced/calendar/calendar.js
index 42ba4690f..f8c8f4601 100644
--- a/src/main/webapp/scripts/modules/widgets/advanced/calendar/calendar.js
+++ b/src/main/webapp/scripts/modules/widgets/advanced/calendar/calendar.js
@@ -34,12 +34,19 @@ WM.module('wm.widgets.advanced')
},
VIEW_TYPES = {
'BASIC' : 'basic',
- 'AGENDA': 'agenda'
+ 'AGENDA': 'agenda',
+ 'LIST' : 'list'
},
SELECTION_MODES = {
'NONE' : 'none',
'SINGLE' : 'single',
'MULTIPLE' : 'multiple'
+ },
+ LIST_BUTTONTEXT = {
+ 'DAY' : 'Day',
+ 'MONTH' : 'Month',
+ 'YEAR' : 'Year',
+ 'WEEK' : 'Week'
};
/* datavalue property is removed from the calendar widget.*/
@@ -58,16 +65,20 @@ WM.module('wm.widgets.advanced')
left += ' today';
}
+ if (_.includes(ctrls, 'year')) {
+ right += (viewType === VIEW_TYPES.LIST) ? 'listYear' : '';
+ }
+
if (_.includes(ctrls, 'month')) {
- right += ' month';
+ right += (viewType === VIEW_TYPES.LIST) ? ' listMonth' : ' month';
}
if (_.includes(ctrls, 'week')) {
- right += viewType === VIEW_TYPES.BASIC ? ' basicWeek' : ' agendaWeek';
+ right += (viewType === VIEW_TYPES.BASIC) ? ' basicWeek' : (viewType === VIEW_TYPES.LIST) ? ' listWeek' : ' agendaWeek';
}
if (regEx.test(ctrls)) {
- right += viewType === VIEW_TYPES.BASIC ? ' basicDay' : ' agendaDay';
+ right += (viewType === VIEW_TYPES.BASIC) ? ' basicDay' : (viewType === VIEW_TYPES.LIST) ? ' listDay' : ' agendaDay';
}
WM.extend($is.calendarOptions.calendar.header, {'left': left, 'right': right});
@@ -77,7 +88,7 @@ WM.module('wm.widgets.advanced')
function calculateHeight(calendar, $el, $is) {
var $parentEl = $el.parent(),
parentHeight = $parentEl.css('height'),
- elHeight = $is.height,
+ elHeight = $is.height || '100%',
computedHeight;
if (_.includes(elHeight, '%')) {
if (_.includes(parentHeight, '%')) {
@@ -150,7 +161,10 @@ WM.module('wm.widgets.advanced')
eventSet.push(event);
}
});
- $is.eventSources.push(eventSet);
+ //as the calendar is not yet rendered, the fullcalendar tries to draw the events when events are bound. hence delay the event assignment.
+ $timeout(function () {
+ $is.eventSources.push(eventSet);
+ });
}
}
break;
@@ -168,7 +182,7 @@ WM.module('wm.widgets.advanced')
return;
}
if (!isMobile) {
- if (newVal !== 'month') {
+ if (newVal !== 'month' || $is.calendartype === VIEW_TYPES.LIST) {
calendar.defaultView = $is.calendartype + _.capitalize(newVal);
} else {
calendar.defaultView = newVal;
@@ -301,7 +315,7 @@ WM.module('wm.widgets.advanced')
$is.onEventclick({$event: jsEvent, $data: event, $view: view});
}
function viewRenderProxy(view) {
- $is.currentview = {start: view.start.format(), end: view.end.format()};
+ $is.currentview = {start: view.start.format(), end: view.end.subtract(1, 'days').format()};
$is.onViewrender({$view: view});
}
function eventRenderProxy(event, jsEvent, view) {
@@ -309,20 +323,23 @@ WM.module('wm.widgets.advanced')
$is.onEventrender({$event: {}, $data: event, $view: view});
}
function setSelectedData(start, end) {
- var filteredDates = [],
- dataset = $is.dataset;
+ var filteredDates = [],
+ dataset = $is.dataset,
+ eventStartKey = $is.eventstart || 'start',
+ eventEndKey = $is.eventend || 'end',
+ startDate = moment(new Date(start)).format('MM/DD/YYYY'),
+ endDate = moment(new Date(end)).subtract(1, 'days').format('MM/DD/YYYY');
if (!dataset) {
return;
}
dataset = dataset.data || dataset;
_.forEach(dataset, function (value) {
- if (!value.start) {
+ if (!value[eventStartKey]) {
return;
}
- var eventDate = moment(new Date(value.start)).format('MM/DD/YYYY'),
- startDate = moment(new Date(start)).format('MM/DD/YYYY'),
- endDate = moment(new Date(end)).format('MM/DD/YYYY'),
- eventExists = moment(eventDate).isSameOrAfter(startDate) && moment(eventDate).isBefore(endDate);
+ var eventStartDate = moment(new Date(value[eventStartKey])).format('MM/DD/YYYY'),
+ eventEndDate = moment(new Date(value[eventEndKey] || value[eventStartKey])).format('MM/DD/YYYY'),
+ eventExists = moment(startDate).isSame(eventStartDate) && moment(eventEndDate).isSame(endDate);
if (eventExists) {
filteredDates.push(value);
}
@@ -424,7 +441,6 @@ WM.module('wm.widgets.advanced')
} else {
$is.calendarOptions = {
calendar: {
- 'height' : parseInt($is.height, 10),
'editable' : true,
'selectable' : false,
'header' : headerOptions,
@@ -436,11 +452,24 @@ WM.module('wm.widgets.advanced')
'select' : onSelectProxy,
'eventRender' : eventRenderProxy,
'viewRender' : viewRenderProxy,
+ 'unselectAuto' : false,
'dayNames' : $locale.DATETIME_FORMATS.DAY,
'dayNamesShort' : $locale.DATETIME_FORMATS.SHORTDAY,
'views' : {
'month': {
'eventLimit': 0
+ },
+ 'listDay': {
+ 'buttonText': LIST_BUTTONTEXT.DAY
+ },
+ 'listWeek': {
+ 'buttonText': LIST_BUTTONTEXT.WEEK
+ },
+ 'listMonth': {
+ 'buttonText': LIST_BUTTONTEXT.MONTH
+ },
+ 'listYear': {
+ 'buttonText': LIST_BUTTONTEXT.YEAR
}
}
}
diff --git a/src/main/webapp/scripts/modules/widgets/advanced/login/login.js b/src/main/webapp/scripts/modules/widgets/advanced/login/login.js
index fe1152ce7..65b60ea29 100644
--- a/src/main/webapp/scripts/modules/widgets/advanced/login/login.js
+++ b/src/main/webapp/scripts/modules/widgets/advanced/login/login.js
@@ -92,7 +92,7 @@ WM.module('wm.widgets.advanced')
}
if (rememberMeElement.length) {
- $rememberMe = rememberMeElement.val();
+ $rememberMe = rememberMeElement.scope().datavalue;
}
// prevent the actions when the userName/Pwd fields are not valid.
diff --git a/src/main/webapp/scripts/modules/widgets/base/Base.js b/src/main/webapp/scripts/modules/widgets/base/Base.js
index 4ee811a2f..81e36bd21 100644
--- a/src/main/webapp/scripts/modules/widgets/base/Base.js
+++ b/src/main/webapp/scripts/modules/widgets/base/Base.js
@@ -52,7 +52,7 @@ WM.module('wm.widgets.base', [])
{
"name" : "Decimal Digits",
"groupOptions" : {
- ".f" : "9",
+ ".0f" : "9",
".1f" : "9.9",
".2f" : "9.99",
".3f" : "9.999"
@@ -152,49 +152,17 @@ WM.module('wm.widgets.base', [])
'value': 'top',
'label': 'Top'
},
- {
- 'value': 'top-left',
- 'label': 'Top Left'
- },
- {
- 'value': 'top-right',
- 'label': 'Top Right'
- },
{
'value': 'bottom',
'label': 'Bottom'
},
- {
- 'value': 'bottom-left',
- 'label': 'Bottom Left'
- },
- {
- 'value': 'bottom-right',
- 'label': 'Bottom Right'
- },
{
'value': 'left',
'label': 'Left'
},
- {
- 'value': 'left-top',
- 'label': 'Left Top'
- },
- {
- 'value': 'left-bottom',
- 'label': 'Left Bottom'
- },
{
'value': 'right',
'label': 'Right'
- },
- {
- 'value': 'right-top',
- 'label': 'Right Top'
- },
- {
- 'value': 'right-bottom',
- 'label': 'Right Bottom'
}
],
EVERYONE = "Everyone",
@@ -203,7 +171,7 @@ WM.module('wm.widgets.base', [])
"wm.base": {
"name": {"type": "string", "pattern": nameRegex, "maxlength": 32},
"show": {"type": "boolean", "value": true, "bindable": "in-bound"},
- "deferload": {"type": "boolean", "value": false, "show": false, "ignoreGetterSetters": true},
+ "deferload": {"type": "boolean", "value": false, "show": false},
"class": {"type": "string", "pattern": classRegex},
"accessroles": {"type": "access-roles-select", "options": roles, "value": EVERYONE},
"showindevice": {"type": "select-all", "options": showInDeviceOptions, "value": "all", "displaytype": 'block'}
@@ -329,6 +297,8 @@ WM.module('wm.widgets.base', [])
},
"wm.icon": {
"hint": {"type": "string", "bindable": "in-bound"},
+ "caption": {"type": "string", "bindable": "in-out-bound", "maxlength": 256, "showPrettyExprInDesigner": true},
+ "iconposition": {"type": "list", "options": ["left", "right"], "value": "left"},
"iconclass": {"type": "string", "value": "wi wi-star-border", "widget": "select-icon", "bindable": "in-out-bound", "pattern": classRegex},
"iconsize": {"type": "string", "pattern": dimensionRegex},
"animation": {"type": "list", "options": animationOptions},
@@ -358,7 +328,8 @@ WM.module('wm.widgets.base', [])
"animation": {"type": "list", "options": animationOptions},
"shortcutkey": {"type": "string"},
"class": {"type": "string", "pattern": classRegex, "widget": "list-picker", "value": "btn-default", "options": ["btn-default", "btn-primary", "btn-info", "btn-warning", "btn-success", "btn-danger", "btn-inverse", "btn-lg", "btn-sm", "btn-xs", "btn-raised", "btn-fab", "btn-link", "btn-transparent", "no-border", "jumbotron"]},
- "margin": {"type": "string", "widget": "box-model"}
+ "margin": {"type": "string", "widget": "box-model"},
+ "horizontalalign": {"type": "string", "options": ["left", "center", "right"], "widget": "icons-align", "show": false}
},
"wm.rating": {
"hint": {"show": false},
@@ -422,7 +393,7 @@ WM.module('wm.widgets.base', [])
"height": {"type": "string", "pattern": dimensionRegex},
"datavalue": {"type": "string, object", "bindable": "in-out-bound", "widget": "string", "getTypeFrom": "dataset"},
"scopedatavalue": {"type": "string"},
- "dataset": {"type": "array, string", "bindable": "in-bound", "widget": "string", "value": "yes, no, maybe"},
+ "dataset": {"type": "array, string", "bindable": "in-bound", "widget": "string", "value": "yes, no, maybe", "showPrettyExprInDesigner": true, "defaultvalue": "yes, no, maybe"},
"scopedataset": {"type": "string"},
"datafield": {"type": "list", "options": ["All Fields"], "value": "All Fields", "datasetfilter" : "terminals", "allfields" : true},
"displayfield": {"type": "list", "options": [""], "value": "", "datasetfilter": "terminals"},
@@ -457,7 +428,9 @@ WM.module('wm.widgets.base', [])
"itemlabel": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"},
"itemlink": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"},
"itemicon": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"},
- "itemchildren": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "objects"}
+ "itemchildren": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "objects"},
+ "itemaction": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"},
+ "userrole": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"}
},
"wm.tree": {
@@ -472,7 +445,7 @@ WM.module('wm.widgets.base', [])
"nodeid": {"type": "string", "widget": "list", "datasetfilter" : "terminals", "bindable": "in-bound", "bindonly": "expression"},
"tabindex": {"type": "number", "value": "0"},
"levels": {"type": "number", "value": 0, "min": "0", "max": "10", "step": "1"},
- "datavalue": {"type": "string", "bindable": "in-out-bound", "widget": "tree-datavalue"},
+ "datavalue": {"type": "string, number, boolean, date, time, object", "bindable": "in-out-bound", "widget": "tree-datavalue", "getTypeFrom": "expr:getDataValueType()"},
"orderby": {"type": "list", "widget": "order-by", "datasetfilter": "terminals"}
},
@@ -541,8 +514,8 @@ WM.module('wm.widgets.base', [])
"showweeks": {"type": "boolean", "value": false, "bindable": "in-bound"},
"readonly": {"type": "boolean", "bindable": "in-bound"},
"disabled": {"type": "boolean", "bindable": "in-bound"},
- "mindate": {"type": dateTimeTypes, "widget": "string", "bindable": "in-bound", "hint": "yyyy-MM-dd"},
- "maxdate": {"type": dateTimeTypes, "widget": "string", "bindable": "in-bound", "hint": "yyyy-MM-dd"},
+ "mindate": {"type": dateTimeTypes, "widget": "data-list", "options": ["CURRENT_DATE"], "bindable": "in-bound", "hint": "yyyy-MM-dd"},
+ "maxdate": {"type": dateTimeTypes, "widget": "data-list", "options": ["CURRENT_DATE"], "bindable": "in-bound", "hint": "yyyy-MM-dd"},
"datepattern": {"value": "yyyy-MM-dd", "type": "list", "options": [], "widget": "date-patterns"},
"outputformat": {"value": "yyyy-MM-dd", "type": "list", "options": [], "widget": "date-patterns"},
"datavalue": {"type": dateTimeTypes, "widget": "data-list", "options": ["CURRENT_DATE"], "bindable": "in-out-bound", "hint": "yyyy-MM-dd"},
@@ -562,7 +535,7 @@ WM.module('wm.widgets.base', [])
},
"wm.calendar": {
"backgroundcolor": {"type": "string", "widget": "color"},
- "width": {"type": "string", "pattern": dimensionRegex},
+ "width": {"type": "string", "value": "100%", "pattern": dimensionRegex},
"height": {"type": "string", "pattern": dimensionRegex},
"dataset": {"type": "array, object", "bindable": "in-bound", "widget": "string"},
"scopedataset": {"type": "string"},
@@ -570,14 +543,14 @@ WM.module('wm.widgets.base', [])
"selecteddates": {"type": "object", "widget": "string", "bindable": "in-out-bound", "getTypeFrom": "expr:getPropertyType('selecteddates')"},
"currentview": {"type": "object", "widget": "string", "bindable": "in-out-bound", "getTypeFrom": "expr:getPropertyType('currentview')"},
"selecteddata": {"type": "array, object", "isList": true, "show": false, "bindable": "out-bound", "getTypeFrom": "expr.getPropertyType('selecteddata')" },
- "calendartype": {"type": "list", "options": ["basic", "agenda"], "value": "basic"},
+ "calendartype": {"type": "list", "options": ["basic", "agenda", "list"], "value": "basic"},
"eventstart": {"type": "list", "value": "start", "options": [""], "datasetfilter" : "terminals"},
"eventend": {"type": "list", "value": "end", "options": [""], "datasetfilter" : "terminals"},
"eventallday": {"type": "list", "value": "allday", "options": [""], "datasetfilter" : "terminals"},
"eventtitle": {"type": "list", "value": "title", "options": [""], "datasetfilter" : "terminals"},
"eventclass": {"type": "list", "value": "class", "options": [""], "datasetfilter" : "terminals"},
"view": {"type": "list", "options": ["month", "week", "day"], "value": "month"},
- "controls": {"type": "list", "options": "navigation, today, month, week, day", "value": "navigation, today, month, week, day", "widget": "select-all"},
+ "controls": {"type": "list", "options": "navigation, today, year, month, week, day", "value": "navigation, today, year, month, week, day", "widget": "select-all"},
"onViewrender": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
"onSelect": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
"onEventdrop": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
@@ -591,6 +564,7 @@ WM.module('wm.widgets.base', [])
"controls": {"show": false},
"multiselect": {"show": false},
"calendartype": {"show": false},
+ "selectionmode": {"show": false},
"onEventdrop": {"show": false},
"onEventresize": {"show": false},
"eventstart": {"type": "list", "value": "start", "options": [""], "datasetfilter" : "terminals"},
@@ -629,8 +603,8 @@ WM.module('wm.widgets.base', [])
"disabled": {"type": "boolean", "bindable": "in-bound"},
"hourstep": {"type": "number", "value": 1},
"minutestep": {"type": "number", "value": 15},
- "mindate": {"type": dateTimeTypes, "widget": "string", "bindable": "in-bound", "hint": "yyyy-MM-dd"},
- "maxdate": {"type": dateTimeTypes, "widget": "string", "bindable": "in-bound", "hint": "yyyy-MM-dd"},
+ "mindate": {"type": dateTimeTypes, "widget": "data-list", "options": ["CURRENT_DATE"], "bindable": "in-bound", "hint": "yyyy-MM-dd"},
+ "maxdate": {"type": dateTimeTypes, "widget": "data-list", "options": ["CURRENT_DATE"], "bindable": "in-bound", "hint": "yyyy-MM-dd"},
"datepattern": {"value": "yyyy-MM-dd hh:mm:ss a", "type": "list", "options": [], "widget": "date-time-patterns"},
"outputformat": {"value": "timestamp", "type": "list", "options": [], "widget": "date-time-patterns"},
"datavalue": {"type": dateTimeTypes, "widget": "data-list", "options": ["CURRENT_DATE"], "bindable": "in-out-bound", "hint": "yyyy-MM-dd HH:mm:ss"},
@@ -702,7 +676,7 @@ WM.module('wm.widgets.base', [])
"datavalue": {"type": "string", "bindable": "in-out-bound", "show": false, "getTypeFrom": "dataset"},
"scopedatavalue": {"type": "string"},
- "dataset": {"type": "array, object", "bindable": "in-bound", "widget": "string", "value": "Option 1, Option 2, Option 3"},
+ "dataset": {"type": "array, object", "bindable": "in-bound", "widget": "string", "value": "Option 1, Option 2, Option 3", "showPrettyExprInDesigner": true, "defaultvalue": "Option 1, Option 2, Option 3"},
"usekeys": {"type": "boolean"},
"required": {"type": "boolean", "bindable": "in-bound", "value": false},
"selectedvalue": {"type": "string, number, boolean, date, time, object", "widget": "string", "bindable": "in-bound", "getTypeFrom": "dataset"},
@@ -711,6 +685,7 @@ WM.module('wm.widgets.base', [])
"wm.colorpicker": {
"readonly": {"type": "boolean", "value": false, "bindable": "in-bound"},
"disabled": {"type": "boolean", "value": false, "bindable": "in-bound"},
+ "required": {"type": "boolean", "value": false, "bindable": "in-bound"},
"datavalue": {"type": "string", "bindable": "in-out-bound"},
"scopedatavalue": {"type": "string"},
"placeholder": {"type": "string", "value": "Select Color", "bindable": "in-bound"},
@@ -780,7 +755,7 @@ WM.module('wm.widgets.base', [])
"datavalue": {"type": "string, array", "bindable": "in-out-bound", "show": false, "widget": "string", "getTypeFrom": "dataset"},
"scopedatavalue": {"type": "string"},
- "dataset": {"type": "array, object", "bindable": "in-bound", "widget": "string", "value": "Option 1, Option 2, Option 3"},
+ "dataset": {"type": "array, object", "bindable": "in-bound", "widget": "string", "value": "Option 1, Option 2, Option 3", "showPrettyExprInDesigner": true, "defaultvalue": "Option 1, Option 2, Option 3"},
"usekeys": {"type": "boolean"},
"selectedvalues": {"type": "string, object", "isList": true, "bindable": "in-bound", "widget": "string", "getTypeFrom": "dataset"},
"onReady": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
@@ -821,7 +796,7 @@ WM.module('wm.widgets.base', [])
"shortcutkey": {"type": "string"},
"class": {"type": "string", "pattern": classRegex, "widget": "list-picker", "options": ["input-lg", "input-sm"]},
"backgroundcolor": {"type": "string", "widget": "color"},
- "displayValue": {"type": "string, array", "getIsListFrom": "expr:multiple", "show": false, "bindable": "out-bound"}
+ "displayValue": {"type": "string", "getIsListFrom": "expr:multiple", "show": false, "bindable": "out-bound"}
},
"wm.marquee": {
@@ -840,7 +815,8 @@ WM.module('wm.widgets.base', [])
"animation": {"type": "list", "options": animationOptions},
"class": {"type": "string", "pattern": classRegex, "widget": "list-picker", "options": [ "h1", "h2", "h3", "h4", "h5", "h6", "p", "text-ellipsis", "text-left", "text-right", "text-center", "text-muted", "text-primary", "text-success", "text-info", "text-warning", "text-danger", "label-default", "label-primary", "label-success", "label-info", "label-warning", "label-danger", "vertical-align-top", "vertical-align-middle", "vertical-align-bottom", "lead", "badge", "form-control-static", "control-label"]},
"whitespace": {"type": "list", "options": [" ", "normal", "nowrap", "pre", "pre-line", "pre-wrap"], "value": " "},
- "wordbreak": {"type": "list", "options": ["break-word", "normal"]}
+ "wordbreak": {"type": "list", "options": ["break-word", "normal"]},
+ "horizontalalign": {"type": "string", "options": ["left", "center", "right"], "widget": "icons-align", "show": false}
},
"wm.picture": {
@@ -879,7 +855,7 @@ WM.module('wm.widgets.base', [])
"datavalue": {"type": "string", "bindable": "in-out-bound"},
"scopedatavalue": {"type": "string"},
"placeholder": {"type": "string", "value": "Place your text", "bindable": "in-bound"},
- "maxchars": {"type": "number"},
+ "maxchars": {"type": "number", "bindable": "in-bound"},
"updateon": {"type": "list", "value": "blur", "widget": "update-on"},
"updatedelay": {"type": "number", "value": 0},
"shortcutkey": {"type": "string"},
@@ -901,7 +877,7 @@ WM.module('wm.widgets.base', [])
"iconmargin": {"type": "string", "pattern": dimensionRegex},
"actiontitle": {"type": "string", "show": false, "pattern": dimensionRegex},
"actionlink": {"type": "string", "show": false, "pattern": dimensionRegex},
- "closable": {"type": "boolean", "show": false},
+ "closable": {"type": "boolean", "show": true, "value": true},
"contentclass": {"type": "string", "pattern": classRegex, "show": false}
},
"wm.dialog.dialogheader": {
@@ -910,7 +886,7 @@ WM.module('wm.widgets.base', [])
"iconwidth": {"type": "string", "pattern": dimensionRegex},
"iconheight": {"type": "string", "pattern": dimensionRegex},
"iconmargin": {"type": "string", "pattern": dimensionRegex},
- "closable": {"type": "boolean", "show": false}
+ "closable": {"type": "boolean", "show": true, "value": true}
},
"wm.dialog.onOk": {
"onOk": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"}
@@ -923,7 +899,7 @@ WM.module('wm.widgets.base', [])
"message": {"type": "string", "value": "I am an alert box!", "bindable": "in-bound", "showPrettyExprInDesigner": true},
"alerttype": {"type": "list", "options": ["error", "information", "success", "warning"], "value": "error"},
"modal": {"type": "boolean", "value": false},
- "keyboard": {"type": "boolean", "value": true}
+ "keyboard": {"type": "boolean", "value": true, "show": false}
},
"wm.confirmdialog": {
"title": {"type": "string", "value": "Confirm", "bindable": "in-bound", "showPrettyExprInDesigner": true},
@@ -933,7 +909,7 @@ WM.module('wm.widgets.base', [])
"message": {"type": "string", "value": "I am confirm box!", "bindable": "in-bound", "showPrettyExprInDesigner": true},
"onCancel": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
"modal": {"type": "boolean", "value": false},
- "keyboard": {"type": "boolean", "value": true}
+ "keyboard": {"type": "boolean", "value": true, "show": false}
},
"wm.iframedialog": {
"title": {"type": "string", "value": "External Content", "bindable": "in-bound", "showPrettyExprInDesigner": true},
@@ -947,7 +923,7 @@ WM.module('wm.widgets.base', [])
"showactions": {"type": "boolean", "value": true},
"showheader": {"type": "boolean", "value": true},
"modal": {"type": "boolean", "value": false},
- "keyboard": {"type": "boolean", "value": true}
+ "keyboard": {"type": "boolean", "value": true, "show": false}
},
"wm.pagedialog": {
"title": {"type": "string", "value": "Page Content", "bindable": "in-bound", "showPrettyExprInDesigner": true},
@@ -957,15 +933,15 @@ WM.module('wm.widgets.base', [])
"closable": {"type": "boolean", "value": true},
"showactions": {"type": "boolean", "value": true},
"modal": {"type": "boolean", "value": false},
- "keyboard": {"type": "boolean", "value": true}
+ "keyboard": {"type": "boolean", "value": true, "show": false}
},
"wm.logindialog": {
"tabindex": {"show": false},
"height": {"type": "string", "show": false, "pattern": dimensionRegex},
"onClose": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
- "closable": {"type": "boolean", "value": true},
+ "closable": {"type": "boolean", "value": false, "show": false},
"modal": {"type": "boolean", "value": true},
- "keyboard": {"type": "boolean", "value": true},
+ "keyboard": {"type": "boolean", "value": true, "show": false},
"onSubmit": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
"title": {"type": "string", "maxlength": 256, "bindable": "in-bound", "showPrettyExprInDesigner": true},
"iconclass": {"type": "string", "widget": "select-icon", "bindable": "in-out-bound", "pattern": classRegex},
@@ -976,7 +952,7 @@ WM.module('wm.widgets.base', [])
"wm.designdialog": {
"modal": {"type": "boolean", "value": false},
"onClose": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
- "keyboard": {"type": "boolean", "value": true},
+ "keyboard": {"type": "boolean", "value": true, "show": false},
"closable": {"type": "boolean", "value": true},
"title": {"type": "string"},
"showheader": {"type": "boolean", "value": true}
@@ -1031,7 +1007,7 @@ WM.module('wm.widgets.base', [])
"name": {"type": "string", "pattern": nameRegex, "maxlength": 32},
"class": {"type": "string", "pattern": classRegex},
"show": {"type": "boolean", "value": true, "bindable": "in-bound"},
- "deferload": {"type": "boolean", "value": false, "show": false, "ignoreGetterSetters": true},
+ "deferload": {"type": "boolean", "value": false, "show": false},
"height": {"type": "string", "pattern": dimensionRegex},
"width": {"type": "string", "pattern": dimensionRegex},
"accessroles": {"type": "access-roles-select", "options": roles, "value": EVERYONE},
@@ -1096,7 +1072,9 @@ WM.module('wm.widgets.base', [])
"itemlabel": {"type": "list", "options": [""], "datasetfilter" : "terminals"},
"itemlink": {"type": "list", "options": [""], "datasetfilter" : "terminals"},
"itembadge": {"type": "list", "options": [""], "datasetfilter" : "terminals"},
+ "itemaction": {"type": "list", "options": [""], "datasetfilter" : "terminals"},
"itemchildren": {"type": "list", "options": [""], "datasetfilter" : "objects"},
+ "userrole": {"type": "list", "options": [""], "datasetfilter" : "terminals"},
"addchild": {"hidelabel": true, "options": [{'label': 'Anchor', 'widgettype': 'wm-anchor', 'defaults': {'wm-anchor': {'iconclass': 'wi wi-file', 'margin': ''} } }, {'label': 'Menu', 'widgettype': 'wm-menu', 'defaults': {'wm-menu': {'iconclass': 'wi wi-file', 'type': 'anchor'} } }, {'label': 'Popover', 'widgettype': 'wm-popover', 'defaults': {'wm-popover': {'iconclass': 'wi wi-file'} } }, {'label': 'Button', 'widgettype': 'wm-button', 'defaults': {'wm-button': {'iconclass': 'wi wi-file'} } }], "widget": "add-widget"},
"selecteditem": {"type": "object", "bindable": "in-out-bound", "show": false, "widget": "string", "getTypeFrom": "dataset"},
"onSelect": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
@@ -1140,9 +1118,9 @@ WM.module('wm.widgets.base', [])
"datavalue": {"type": "string, object", "widget": "string", "bindable": "in-out-bound", "getTypeFrom": "dataset"},
"scopedataset": {"type": "string"},
"dataset": {"type": "array, object", "bindable": "in-bound", "widget": "string"},
- "searchkey": {"type": "list", "options": [""], "datasetfilter": "terminals"},
- "displaylabel": {"type": "list", "options": [""], "datasetfilter": "terminals"},
- "displayimagesrc": {"type": "list", "options": [""], "datasetfilter": "terminals"},
+ "searchkey": {"type": "string", "widget": "select-all", "datasetfilter" : "terminals"},
+ "displaylabel": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"},
+ "displayimagesrc": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"},
"datafield": {"type": "list", "options": ["All Fields"], "value": "All Fields", "datasetfilter" : "terminals", "allfields" : true},
"defaultview": {"type": "select-by-object", "options": [{"label": "action-view", "value": "actionview"}, {"label": "search-view", "value": "searchview"}], "value": "actionview", "displayfield": "label", "datafield": "value" },
"query": {"type": "string", "bindable": "in-out-bound", "value": ""},
@@ -1184,7 +1162,7 @@ WM.module('wm.widgets.base', [])
},
'wm.layouts.panel': {
"height": {"type": "string", "pattern": dimensionRegex},
- "title": {"type": "string", "value": "Title", "bindable": "in-bound", "showPrettyExprInDesigner": true},
+ "title": {"type": "string", "bindable": "in-bound", "showPrettyExprInDesigner": true},
"subheading": {"type": "string", "bindable": "in-bound", "showPrettyExprInDesigner": true},
"iconclass": {"type": "string", "widget": "select-icon", "bindable": "in-out-bound", "pattern": classRegex, "label": 'Title Icon Class'},
"iconurl": {"type": "string", "bindable": "in-bound"},
@@ -1297,7 +1275,7 @@ WM.module('wm.widgets.base', [])
"height": {"type": "string", "pattern": dimensionRegex},
"width": {"type": "string", "pattern": dimensionRegex},
"show": {"type": "boolean", "value": true, "bindable": "in-bound"},
- "deferload": {"type": "boolean", "value": false, "show": false, "ignoreGetterSetters": true},
+ "deferload": {"type": "boolean", "value": false, "show": false},
"insert": {"type": "toolbar", "actions": [{'action': 'addrow', 'label': 'LABEL_PROPERTY_ADDROW', 'icon': 'add-row'}]},
"columns": {"type": "list", "options": ["1", "2", "3", "4", "6", "12"]},
"backgroundcolor": {"type": "string", "widget": "color", "show": false},
@@ -1353,7 +1331,7 @@ WM.module('wm.widgets.base', [])
},
'wm.layouts.view': {
"show": {"type": "boolean", "value": true, "bindable" : "in-out-bound"},
- "deferload": {"type": "boolean", "value": false, "show": false, "ignoreGetterSetters": true},
+ "deferload": {"type": "boolean", "value": false, "show": false},
"viewgroup": {"type": "string", "value": "default"},
"animation": {"type": "list", "options": animationOptions}
},
@@ -1367,7 +1345,7 @@ WM.module('wm.widgets.base', [])
"method": {"type": "list", "options": ["post", "put", "delete"], "showindesigner": true},
"height": {"type": "string", "pattern": dimensionRegex},
"width": {"type": "string", "pattern": dimensionRegex},
- "dataset": {"type": "array, object", "widget": "string", "disabled": true, "bindable": "in-bound"},
+ "dataset": {"type": "array, object", "widget": "string", "bindable": "in-bound"},
"captionsize": {"type": "string", "showindesigner": true},
"iconclass": {"type": "string", "widget": "select-icon", "bindable": "in-bound", "pattern": classRegex, "label": 'Title Icon Class'},
"formdata": {"type": "object", "bindable": "in-bound", "widget": "string", "getTypeFrom": "dataset"},
@@ -1490,6 +1468,7 @@ WM.module('wm.widgets.base', [])
"filternullrecords": {"type": "boolean", "value": true},
"nodatamessage": {"type": "string", "value": "No data found.", "bindable": "in-bound", "showindesigner": true},
"loadingdatamsg": {"type": "string", "value": "Loading...", "bindable": "in-bound", "showindesigner": true},
+ "loadingicon": {"type": "string", "widget": "select-icon", "bindable": "in-bound", "value": "fa fa-spinner fa-spin", "pattern": classRegex},
"deletemessage": {"type": "string", "value": "Record deleted successfully", "bindable": "in-bound", "show": true, "showindesigner": true},
"errormessage": {"type": "string", "value": "", "bindable": "in-bound", "showindesigner": true},
"insertmessage": {"type": "string", "value": "Record added successfully", "bindable": "in-bound", "showindesigner": true},
@@ -1586,7 +1565,8 @@ WM.module('wm.widgets.base', [])
"showindevice": {"type": "select-all", "options": showInDeviceOptions, "value": "all", "displaytype": 'inline'},
"animation": {"type": "list", "options": animationOptions},
"shortcutkey": {"type": "string"},
- "class": {"type": "string", "pattern": classRegex, "widget": "list-picker", "options": ["h1", "h2", "h3", "h4", "h5", "h6", "btn-primary", "btn-success", "btn-info", "btn-warning", "btn-danger", "btn-lg", "btn-sm", "btn-xs", "btn-link", "text-ellipsis", "text-left", "text-right", "text-center", "text-muted", "text-primary", "text-success", "text-info", "text-warning", "text-danger", "vertical-align-top", "vertical-align-middle", "vertical-align-bottom", "lead", "badge"]}
+ "class": {"type": "string", "pattern": classRegex, "widget": "list-picker", "options": ["h1", "h2", "h3", "h4", "h5", "h6", "btn-primary", "btn-success", "btn-info", "btn-warning", "btn-danger", "btn-lg", "btn-sm", "btn-xs", "btn-link", "text-ellipsis", "text-left", "text-right", "text-center", "text-muted", "text-primary", "text-success", "text-info", "text-warning", "text-danger", "vertical-align-top", "vertical-align-middle", "vertical-align-bottom", "lead", "badge"]},
+ "horizontalalign": {"type": "string", "options": ["left", "center", "right"], "widget": "icons-align", "show": false}
},
"wm.popover": {
"contentsource": {"type": "list", "options": ['inline', 'partial'], value: "partial"},
@@ -1598,6 +1578,7 @@ WM.module('wm.widgets.base', [])
"popoverheight" : {"type": "string"},
"popoverarrow" : {"type": "boolean", "value" : true},
"popoverautoclose": {"type": "boolean", "value" : true, "show": false},
+ "interaction": {"type": "select-by-object", "options": [{'label': 'Click', 'value': 'click'}, {'label': 'Hover', 'value': 'hover'}, {'label': 'Click and Hover', 'value': 'default'}], value: "click"},
"popoverplacement": {"type": "select-by-object", "options": popoverOptions, "value": "bottom"},
"title": {"type": "string", "bindable": "in-bound"},
"onShow": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
@@ -1619,7 +1600,9 @@ WM.module('wm.widgets.base', [])
"addchild": {"hidelabel": true, "options": [{"label": "Add Accordion Pane", "widgettype": "wm-accordionpane"}], "widget": "add-widget"},
"closeothers": { "type": "boolean", "value": true},
"height": {"type": "string", "pattern": dimensionRegex},
- "tabindex": {"type": "number", "value": "0"}
+ "tabindex": {"type": "number", "value": "0"},
+ "defaultpaneindex": {"type": "number", "value": 0, "bindable": "in-bound"},
+ "onChange": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"}
},
"wm.accordionpane": {
@@ -1632,7 +1615,7 @@ WM.module('wm.widgets.base', [])
"badgevalue": {"type": "string", "bindable": "in-out-bound"},
"badgetype": {"type": "string", "widget": "list", "options": ["default", "primary", "success", "info", "warning", "danger"], "value": "default", "bindable": "in-out-bound"},
"tabindex": {"type": "number", "value": "0"},
- "isdefaultpane": {"type": "boolean", "bindable": "in-bound"},
+ "isdefaultpane": {"type": "boolean", "bindable": "in-bound", "show": false}, //Deprecated property
"padding": {"type": "string", "widget": "box-model"},
"backgroundcolor": {"type": "string", "widget": "color"},
"color": {"type": "string", "hidelabel": true, "widget": "color"},
@@ -1646,6 +1629,7 @@ WM.module('wm.widgets.base', [])
"datavalue": {"type": "string", value: "", "bindable": "in-out-bound"},
"showpreview": {"type": "boolean", "value": false},
"placeholder": {"type": "string", "bindable": "in-bound"},
+ "htmlcontent": {"type": "string", "bindable": "out-bound"},
"tabindex": {"type": "number", "value": "0"},
"scopedatavalue": {"type": "string"},
"onChange": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
@@ -1660,7 +1644,9 @@ WM.module('wm.widgets.base', [])
"transition": {"type": "list", "options": ["none", "slide"], "value": "none"},
"name": {"type": "string", "pattern": nameRegex, "maxlength": 32},
"height": {"type": "string", "pattern": dimensionRegex},
- "horizontalalign": {"type": "string", "options": ["left", "center", "right"], "widget": "icons-align"}
+ "horizontalalign": {"type": "string", "options": ["left", "center", "right"], "widget": "icons-align"},
+ "defaultpaneindex": {"type": "number", "value": 0, "bindable": "in-bound"},
+ "onChange": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"}
},
"wm.tab": {
@@ -1672,8 +1658,10 @@ WM.module('wm.widgets.base', [])
"onDeselect": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
"title": {"type": "string", "value": "Tab Title", "bindable": "in-bound", "showPrettyExprInDesigner": true},
"paneicon": {"type": "string", "widget": "select-icon", "bindable": "in-bound", "pattern": classRegex, "label": 'Title Icon Class'},
- "isdefaulttab": {"type": "boolean", "bindable": "in-bound"},
- "tabindex": {"type": "number", "value": "0"}
+ "isdefaulttab": {"type": "boolean", "bindable": "in-bound", "show": false}, //Deprecated property
+ "tabindex": {"type": "number", "value": "0"},
+ "badgevalue": {"type": "string", "bindable": "in-out-bound"},
+ "badgetype": {"type": "string", "widget": "list", "options": ["default", "primary", "success", "info", "warning", "danger"], "value": "default", "bindable": "in-out-bound"}
},
"wm.wizard": {
"addchild": {"hidelabel": true, "options": [{"label": "Add Step", "widgettype": "wm-wizardstep"}], "widget": "add-widget"},
@@ -1689,13 +1677,16 @@ WM.module('wm.widgets.base', [])
"wm.wizardstep": {
"title": {"type": "string", "value": "Step Title", "bindable": "in-bound", "showPrettyExprInDesigner": true},
"disablenext": {"type": "boolean", "value": false, "show": false},
+ "disableprevious": {"type": "boolean", "value": false, "show": false},
+ "disabledone": {"type": "boolean", "value": false, "show": false},
"enabledone": {"type": "boolean", "value": false, "show": false},
"enableskip": {"type": "boolean", "value": false, "bindable": "in-bound"},
"iconclass": {"type": "string", "widget": "select-icon", "bindable": "in-out-bound", "pattern": classRegex, "label": 'Title Icon Class'},
"onNext": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
"onPrev": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
"onLoad": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
- "onSkip": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"}
+ "onSkip": {"type": "event", "options": widgetEventOptions, "widget": "eventlist"},
+ "loadmode" : {"type" : "list", "show": false, "value" : "after-select"}
},
"wm.carousel" : {
"addchild": {"hidelabel": true, "options": [{"label": "Add Carousel", "widgettype": "wm-carousel-content"}], "widget": "add-widget"},
@@ -1767,7 +1758,7 @@ WM.module('wm.widgets.base', [])
"showcount": {"type": "boolean", "show": false},
"disableitem": {"type": "boolean", "bindable": "in-bound", "value": false},
"ondemandmessage": {"type": "string", "bindable": "in-bound", "showPrettyExprInDesigner": true, "value": "Load More"},
- "loadingicon": {"type": "string", "widget": "select-icon", "bindable": "in-bound", "value": "", "pattern": classRegex},
+ "loadingicon": {"type": "string", "widget": "select-icon", "bindable": "in-bound", "value": "fa fa-circle-o-notch", "pattern": classRegex},
"paginationclass": {"type": "string", "pattern": classRegex, "widget": "list-picker", "options": ["pagination-sm", "pagination-lg", "btn-default", "btn-primary", "btn-info", "btn-warning", "btn-success", "btn-danger", "btn-inverse", "btn-lg", "btn-sm", "btn-xs", "btn-raised", "btn-fab", "btn-link", "btn-transparent", "jumbotron"]}
},
"wm.medialist": {
@@ -1815,7 +1806,7 @@ WM.module('wm.widgets.base', [])
"datavalue": {"type": "string, object", "widget": "string", "bindable": "in-out-bound", "getTypeFrom": "dataset"},
"scopedataset": {"type": "string"},
"query": {"type": "string", "bindable": "out-bound"},
- "searchkey": {"type": "string", "widget": "select-all", "bindable": "in-bound", "datasetfilter" : "terminals"},
+ "searchkey": {"type": "string", "widget": "select-all", "datasetfilter" : "terminals"},
"displaylabel": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"},
"displayimagesrc": {"type": "string", "widget": "list", "options": [""], "bindable": "in-bound", "bindonly": "expression", "datasetfilter" : "terminals"},
"datafield": {"type": "list", "options": ["All Fields"], "value": "All Fields", "datasetfilter" : "terminals", "allfields" : true},
@@ -1980,10 +1971,10 @@ WM.module('wm.widgets.base', [])
"hint": {"type": "string", "bindable": "in-bound"},
"minvalue": {"type": "number", "value": 0, "bindable": "in-bound"},
"maxvalue": {"type": "number", "value": 100, "bindable": "in-bound"},
- "datavalue": {"type": "number, string", "value": 30, "bindable": "in-out-bound", "widget": "string"},
+ "datavalue": {"type": "number, string", "bindable": "in-out-bound", "widget": "string"},
"dataset": {"type": "array, object", "bindable": "in-bound", "widget": "string"},
"pollinterval": {"type": "number"},
- "displayformat": {"type": "list", "options": ["percentage", "absolute"], "value": "percentage"},
+ "displayformat": {"type": "list", "options": ["9", "9.9", "9.99", "9.999", "9%", "9.9%", "9.99%", "9.999%"]},
"captionplacement": {"type": "list", "options": ["inside", "hidden"], "value": "hidden"},
"type": {"type": "list", "options": ["default", "default-striped", "success", "success-striped", "info", "info-striped", "warning", "warning-striped", "danger", "danger-striped"], "value": "default", "bindable": "in-bound"},
@@ -2033,16 +2024,16 @@ WM.module('wm.widgets.base', [])
{"name": "valuedisplay", "properties": ["datepattern", "timepattern", "hourstep", "minutestep", "limit"], "parent": "properties"},
{"name": "output", "properties": ["outputformat"], "parent": "properties"},
{"name": "eventsdata", "properties": ["eventtitle", "eventstart", "eventend", "eventallday", "eventclass"], "parent": "properties"},
- {"name": "actions", "properties": ["actions", "itemlabel", "itemicon", "itemlink", "itembadge", "itemchildren"], "parent": "properties"},
+ {"name": "actions", "properties": ["actions", "itemlabel", "itemicon", "itemlink", "itemaction", "userrole", "itembadge", "itemchildren"], "parent": "properties"},
{"name": "xaxis", "properties": ["xaxisdatakey"], "parent": "properties"},
{"name": "yaxis", "properties": ["yaxisdatakey"], "parent": "properties"},
{"name": "zaxis", "properties": ["bubblesize"], "parent": "properties"},
{"name": "validation", "properties": ["required", "validationmessage", "regexp", "mindate", "maxdate", "excludedays", "excludedates", "novalidate", "maxchars"], "parent": "properties"},
- {"name": "behavior", "properties": ["method", "action", "enctype", "target", "defaultview", "defaultmode", "pollinterval", "radiogroup", "viewgroup", "showweeks", "showbuttonbar", "autofocus", "readonly", "ignoreparentreadonly", "editmode", "scrolldelay", "scrollamount", "direction",
+ {"name": "behavior", "properties": ["method", "action", "enctype", "target", "defaultview", "defaultmode", "defaultpaneindex", "pollinterval", "radiogroup", "viewgroup", "showweeks", "showbuttonbar", "autofocus", "readonly", "ignoreparentreadonly", "editmode", "scrolldelay", "scrollamount", "direction",
"multiple", "maxsize", "allowonlyselect", "enablereorder", "fileuploadmessage", "mode", "show", "deferload", "hideclose", "calendartype", "controls", "view", "disabled", "disableitem", "pagesize", "dynamicslider", "selectionclick", "closeothers", "collapsible", "showcount", "enablefullscreen",
"lock", "freeze", "autoscroll", "closable", "showactions", "expanded", "destroyable", "showDirtyFlag", "link", "linktarget",
- "uploadpath", "contenttype", "origin", "destination", "maxfilesize", "isdefaulttab", "disablenext", "enabledone", "enableskip", "cancelable", "isdefaultpane", "autocomplete", "showpreview", "autoplay", "loop", "muted",
- "xpadding", "ypadding", "popoverplacement", "popoverarrow", "popoverautoclose", "autoclose", "transition", "animation", "animateitems", "animationinterval", "leftnavpaneliconclass", "backbutton", "backbuttoniconclass", "backbuttonlabel", "searchbutton",
+ "uploadpath", "contenttype", "origin", "destination", "maxfilesize", "isdefaulttab", "disablenext", "disableprevious", "disabledone", "enabledone", "enableskip", "cancelable", "isdefaultpane", "autocomplete", "showpreview", "autoplay", "loop", "muted",
+ "xpadding", "ypadding", "popoverplacement", "popoverarrow", "popoverautoclose", "interaction", "autoclose", "transition", "animation", "animateitems", "animationinterval", "leftnavpaneliconclass", "backbutton", "backbuttoniconclass", "backbuttonlabel", "searchbutton",
"morebuttoniconclass", "menuiconclass", "morebuttonlabel", "capturetype", "loadmode", "loaddelay", "selectionlimit", "showcaptions", "multiselect", "radioselect", "enablesort", "enablecolumnselection", "gridfirstrowselect", "selectfirstitem", "enableemptyfilter", "autoupdate", "displayformat", "captionplacement", "updateon", "updatedelay", "actionlink", "actiontitle", "offline", "encodeurl", "keyboard"], "parent": "properties"},
{"name": "navigation", "properties": ["navigation", "shownavigation", "showrecordcount", "navigationalign", "ondemandmessage"], "parent": "properties"},
{"name": "searchproperties", "properties": ["searchbuttoniconclass", "searchbuttonlabel", "searchplaceholder"], "parent": "properties"},
diff --git a/src/main/webapp/scripts/modules/widgets/base/initWidget.js b/src/main/webapp/scripts/modules/widgets/base/initWidget.js
index a38739120..27b30f5a2 100644
--- a/src/main/webapp/scripts/modules/widgets/base/initWidget.js
+++ b/src/main/webapp/scripts/modules/widgets/base/initWidget.js
@@ -201,7 +201,11 @@ WM.module('wm.widgets.base')
//removing the data-evaluated attribute. If the evaluation value is correct this property is not required in design mode.
$el.removeAttr(dataAttrKey);
$is[key + '__updateFromWatcher'] = true;
- if (WM.isDefined(newVal) && newVal !== null && newVal !== '') {
+ //For dataset widgets, show default dataset values, if dataset is not available in studio mode
+ if ($is.widgetid && propDetails.showPrettyExprInDesigner && propDetails.defaultvalue && (_.isEmpty(newVal) || (newVal.data && _.isEmpty(newVal.data)))) {
+ value = propDetails.defaultvalue;
+ $el.attr(dataAttrKey, '');
+ } else if (WM.isDefined(newVal) && newVal !== null && newVal !== '') {
//Check if "newVal" is a Pageable object.
if (WM.isObject(newVal) && Utils.isPageable(newVal)) {
// Check if the scope is configured to accept Pageable objects.
diff --git a/src/main/webapp/scripts/modules/widgets/base/pageContainer.js b/src/main/webapp/scripts/modules/widgets/base/pageContainer.js
index 159302487..8e541bba6 100644
--- a/src/main/webapp/scripts/modules/widgets/base/pageContainer.js
+++ b/src/main/webapp/scripts/modules/widgets/base/pageContainer.js
@@ -60,7 +60,6 @@ WM.module('wm.widgets.base')
if (CONSTANTS.isRunMode && iScope._widgettype === 'wm-popover' && iScope.contentsource === 'partial') {
//Class will be used to set popover height width to avoid flickering issue
iScope._popoverOptions.customclass = 'popover_' + iScope.$id + '_' + partialName + '_' + _.toLower($rootScope.activePageName);
- $rootScope.$emit('reset-partial-variables', partialName);
}
/* append the pageContentMarkup to original markup, to compile it manually*/
@@ -101,10 +100,10 @@ WM.module('wm.widgets.base')
} else {
/* compile */
target.html($compile(partialMarkup)(scope));
+ $timeout(function () {
+ Utils.triggerFn(iScope.onLoad, {$isolateScope: iScope});
+ }, undefined, false);
}
- $timeout(function () {
- Utils.triggerFn(iScope.onLoad, {$isolateScope: iScope});
- }, undefined, false);
} else {
return;
}
diff --git a/src/main/webapp/scripts/modules/widgets/basic/chart/chart.js b/src/main/webapp/scripts/modules/widgets/basic/chart/chart.js
index a0c8d6334..04b632eda 100644
--- a/src/main/webapp/scripts/modules/widgets/basic/chart/chart.js
+++ b/src/main/webapp/scripts/modules/widgets/basic/chart/chart.js
@@ -23,7 +23,7 @@ WM.module('wm.widgets.basic')
'
'
);
}])
- .directive('wmChart', function (PropertiesFactory, $templateCache, $rootScope, WidgetUtilService, CONSTANTS, QueryBuilder, Utils, ChartService) {
+ .directive('wmChart', function (PropertiesFactory, $templateCache, $rootScope, WidgetUtilService, CONSTANTS, Utils, ChartService, DatabaseService) {
'use strict';
var widgetProps = PropertiesFactory.getPropertiesOf('wm.chart', ['wm.base']),
// properties of the respective chart type
@@ -82,6 +82,14 @@ WM.module('wm.widgets.basic')
'showlegend' : true,
'title' : true,
'subheading' : true
+ },
+ // Getting the relevant aggregation function based on the selected option
+ aggregationFnMap = {
+ 'average' : 'AVG',
+ 'count' : 'COUNT',
+ 'maximum' : 'MAX',
+ 'minimum' : 'MIN',
+ 'sum' : 'SUM'
};
// Configuring the properties panel based on the type of the chart chosen
@@ -163,34 +171,17 @@ WM.module('wm.widgets.basic')
function isDataFilteringEnabled(scope) {
/*Query need to be triggered if any of the following cases satisfy
* 1. Group By and aggregation both chosen
- * 2. Group By alone with atleast two columns chosen, one of which is x axis
- * 3. Only Order By is chosen
+ * 2. Only Order By is chosen
* */
- return isAggregationEnabled(scope) || (isGroupByEnabled(scope.groupby) && scope.isVisuallyGrouped) || scope.orderby;
- }
-
- //Gets the value by parsing upto the leaf node
- function getLeafNodeVal(key, dataObj) {
- var keys = key.split('.'),
- data = dataObj,
- i;
- for (i = 0; i < keys.length; i += 1) {
- if (data) {
- data = data[keys[i]];
- } else { //If value becomes undefined then acceess the key directly
- data = dataObj[key];
- break;
- }
- }
- return data;
+ return isAggregationEnabled(scope) || (!scope.isVisuallyGrouped && scope.orderby);
}
/*Charts like Line,Area,Cumulative Line does not support any other datatype
other than integer unlike the column and bar.It is a nvd3 issue. Inorder to
support that this is a fix*/
function getxAxisVal(scope, dataObj, xKey, index) {
- var value = getLeafNodeVal(xKey, dataObj);
+ var value = _.get(dataObj, xKey);
//If x axis is other than number type then add indexes
if (ChartService.isLineTypeChart(scope.type) && !Utils.isNumberType(scope.xAxisDataType)) {
//Verification to get the unique data keys
@@ -273,7 +264,7 @@ WM.module('wm.widgets.basic')
//Returns the single data point based on the type of the data chart accepts
function valueFinder(scope, dataObj, xKey, yKey, index, shape) {
var xVal = getxAxisVal(scope, dataObj, xKey, index),
- value = getLeafNodeVal(yKey, dataObj),
+ value = _.get(dataObj, yKey),
yVal = parseFloat(value) || value,
dataPoint = {},
size = parseFloat(dataObj[scope.bubblesize]) || 2;
@@ -311,7 +302,7 @@ WM.module('wm.widgets.basic')
scope.xDataKeyArr = [];
//Plotting the chart with sample data when the chart dataset is not bound
if (!scope.binddataset) {
- scope.xDataKeyArr = ['01-01-2001', '01-01-2002', '01-01-2003'];
+ scope.xDataKeyArr = ChartService.getDateList();
if (CONSTANTS.isStudioMode) {
scope.showContentLoadError = true;
scope.errMsg = $rootScope.locale.MESSAGE_INFO_SAMPLE_DATA;
@@ -373,110 +364,53 @@ WM.module('wm.widgets.basic')
return datum;
}
- // Getting the relevant aggregation function based on the selected option
- function getAggregationFunction(option) {
- switch (option) {
- case 'average':
- return 'AVG';
- case 'count':
- return 'COUNT';
- case 'maximum':
- return 'MAX';
- case 'minimum':
- return 'MIN';
- case 'sum':
- return 'SUM';
- default:
- return '';
- }
+ //Returns orderby columns and their orders in two separate arrays
+ function getLodashOrderByFormat(orderby) {
+ var orderByColumns = [],
+ orders = [],
+ columns;
+ _.forEach(_.split(orderby, ','), function (col) {
+ columns = _.split(col, ':');
+ orderByColumns.push(columns[0]);
+ orders.push(columns[1]);
+ });
+ return {
+ 'columns' : orderByColumns,
+ 'orders' : orders
+ };
}
+
//Constructing the grouped data based on the selection of orderby, x & y axis
- function getGroupedData(scope, queryResponse, groupingColumn) {
+ function getVisuallyGroupedData(scope, queryResponse, groupingColumn) {
var chartData = [],
groupData = {},
groupValues = [],
- groupKey,
- index = 0,
- i;
+ orderByDetails;
scope.xDataKeyArr = [];
-
- while (queryResponse.length !== 0) {
- groupKey = queryResponse[queryResponse.length - 1][groupingColumn];
- //Data should be in ascending order of 'x', since there is tooltips issue incase of line chart
- groupValues.push(valueFinder(scope, queryResponse[queryResponse.length - 1], scope.xaxisdatakey, scope.yaxisdatakey, 0));
- queryResponse.splice(queryResponse.length - 1, 1);
- for (i = queryResponse.length - 1; i >= 0; i -= 1) {
- /*Checking if the new column groupKey is same as the chosen groupKey
- Then pushing the data
- Then splicing the data since it is already pushed */
- if (groupKey === queryResponse[i][groupingColumn]) {
- index += 1;
- //Data should be in ascending order of 'x', since there is tooltips issue incase of line chart
- groupValues.push(valueFinder(scope, queryResponse[i], scope.xaxisdatakey, scope.yaxisdatakey, index));
- queryResponse.splice(i, 1);
- }
- }
-
- //Pushing the data with groupKey and values
+ queryResponse = _.orderBy(queryResponse, _.split(scope.groupby, ','));
+ if (scope.orderby) {
+ orderByDetails = getLodashOrderByFormat(scope.orderby);
+ queryResponse = _.orderBy(queryResponse, orderByDetails.columns, orderByDetails.orders);
+ }
+ queryResponse = _.groupBy(queryResponse, groupingColumn);
+ _.forEach(queryResponse, function (values, groupKey) {
+ groupValues = [];
+ _.forEachRight(values, function (value, index) {
+ groupValues.push(valueFinder(scope, value, scope.xaxisdatakey, scope.yaxisdatakey, index));
+ });
groupData = {
key : groupKey,
values : groupValues
};
chartData.push(groupData);
- groupValues = [];
- index = 0;
- }
- return chartData;
- }
-
- //Construct orderby expression
- function getOrderbyExpression(orderby) {
- var orderbyCols = (orderby ? orderby.replace(/:/g, ' ') : '').split(','),
- trimmedCols = '';
- orderbyCols = orderbyCols.map(function (col) {
- return col.trim();
});
- trimmedCols = orderbyCols.join();
- return trimmedCols;
+ return chartData;
}
- //Replacing the '.' by the '_' because '.' is not supported in the alias names
+ //Replacing the '.' by the '$' because '.' is not supported in the alias names
function getValidAliasName(aliasName) {
- return aliasName ? aliasName.replace(/\./g, '_') : null;
- }
-
- // Returns the columns that are to be fetched in the query response
- function getQueryColumns(scope) {
- var columns = [],
- groupbyColumns = scope.groupby && scope.groupby !== NONE ? scope.groupby.split(',') : [],
- yAxisKeys = scope.yaxisdatakey ? scope.yaxisdatakey.split(',') : [],
- expr,
- xAxisKey = scope.xaxisdatakey,
- aggColumn = scope.aggregationcolumn || [],
- requiredColumns = [];
-
- /*Merge all columns and filter unique ones and remove empty columns ('', undefined)
- * 1. X Axis
- * 2. Y Axis
- * 3. Aggregation
- * 4. Group By
- * */
- requiredColumns = _.compact(_.uniq(_.concat(xAxisKey, yAxisKeys, groupbyColumns, aggColumn)));
-
- // adding aggregation column, if enabled
- if (isAggregationEnabled(scope)) {
- columns.push(getAggregationFunction(scope.aggregation) + '(' + aggColumn + ') AS ' + getValidAliasName(aggColumn));
- }
-
- //Remove aggregation column since it is already added
- requiredColumns = _.without(requiredColumns, aggColumn);
-
- _.forEach(requiredColumns, function (column) {
- expr = column + ' AS ' + getValidAliasName(column);
- columns.push(expr);
- });
- return columns;
+ return aliasName ? aliasName.replace(/\./g, '$') : null;
}
/*Decides whether the data should be visually grouped or not
@@ -539,15 +473,15 @@ WM.module('wm.widgets.basic')
}
//Function to get the aggregated data after applying the aggregation & group by or order by operations.
- function getAggregatedData(scope, element, groupingDetails, callback) {
- var query,
- variableName,
+ function getAggregatedData(scope, element, callback) {
+ var variableName,
variable,
- columns,
yAxisKeys = scope.yaxisdatakey ? scope.yaxisdatakey.split(',') : [],
- orderbyexpression = getOrderbyExpression(scope.orderby),
- groupbyExpression = groupingDetails.expression,
- elScope = element.scope();
+ elScope = element.scope(),
+ data = {},
+ sortExpr = _.replace(scope.orderby, /:/g, ' '),
+ orderByColumn = _.first(_.split(sortExpr, ' ')),
+ columns = [];
//Returning if the data is not yet loaded
if (!scope.chartData) {
@@ -566,27 +500,36 @@ WM.module('wm.widgets.basic')
if (!variable) {
return;
}
- columns = getQueryColumns(scope);
- query = QueryBuilder.getQuery({
- 'tableName': variable.type,
- 'columns': columns,
- 'filterFields': scope.filterFields || variable.filterFields,
- 'groupby': groupbyExpression,
- 'orderby': orderbyexpression
- });
+ columns = _.concat(columns, data.groupByFields, [scope.aggregationcolumn]);
+ if (_.includes(columns, orderByColumn)) {
+ sortExpr = getValidAliasName(sortExpr);
+ }
+ if (isGroupByEnabled(scope.groupby)) {
+ data.groupByFields = _.split(scope.groupby, ',');
+ }
+ if (isAggregationEnabled(scope)) {
+ data.aggregations = [
+ {
+ "field": scope.aggregationcolumn,
+ "type": _.toUpper(scope.aggregation),
+ "alias": getValidAliasName(scope.aggregationcolumn)
+ }
+ ];
+ }
//Execute the query.
- QueryBuilder.executeQuery({
- 'databaseName': variable.liveSource,
- 'query': query,
- 'page': 1,
- 'size': variable.maxResults || 500,
- 'nativeSql': false
+ DatabaseService.executeAggregateQuery({
+ 'dataModelName' : variable.liveSource,
+ 'entityName' : variable.type,
+ 'page' : 1,
+ 'size' : variable.maxResults || 500,
+ 'sort' : sortExpr,
+ 'url' : $rootScope.project.deployedUrl,
+ 'data' : data
}, function (response) {
//Transform the result into a format supported by the chart.
var chartData = [],
aggregationAlias = getValidAliasName(scope.aggregationcolumn),
- visualGroupingColumnAlias = groupingDetails.visualGroupingColumn ? getValidAliasName(groupingDetails.visualGroupingColumn) : '',
xAxisAliasKey = getValidAliasName(scope.xaxisdatakey),
yAxisAliasKeys = [];
@@ -599,25 +542,20 @@ WM.module('wm.widgets.basic')
// Set the response in the chartData based on 'aggregationColumn', 'xAxisDataKey' & 'yAxisDataKey'.
if (isAggregationEnabled(scope)) {
obj[scope.aggregationcolumn] = data[aggregationAlias];
+ obj[scope.aggregationcolumn] = _.get(data, aggregationAlias) || _.get(data, scope.aggregationcolumn);
}
- if (visualGroupingColumnAlias) {
- obj[groupingDetails.visualGroupingColumn] = data[visualGroupingColumnAlias];
- }
-
- obj[scope.xaxisdatakey] = data[xAxisAliasKey];
- yAxisKeys.forEach(function (yAxisKey) {
- yAxisAliasKeys.push(getValidAliasName(yAxisKey));
- });
+ obj[scope.xaxisdatakey] = _.get(data, xAxisAliasKey) || _.get(data, scope.xaxisdatakey);
yAxisKeys.forEach(function (yAxisKey, index) {
obj[yAxisKey] = data[yAxisAliasKeys[index]];
+ obj[yAxisKey] = _.get(data, yAxisAliasKeys[index]) || _.get(data, yAxisKey);
});
chartData.push(obj);
});
- scope.chartData = groupingDetails.isVisuallyGrouped ? getGroupedData(scope, chartData, groupingDetails.visualGroupingColumn) : chartData;
+ scope.chartData = chartData;
Utils.triggerFn(callback);
}, function () {
@@ -879,12 +817,14 @@ WM.module('wm.widgets.basic')
// get the chart object
chart = ChartService.initChart(scope, xDomainValues, yDomainValues, null, !scope.binddataset);
- // changing the default no data message
- d3.select('#wmChart' + scope.$id + ' svg')
- .datum(chartData)
- .call(chart);
- postPlotProcess(scope, element, chart);
- return chart;
+ if (WM.isArray(chartData)) {
+ // changing the default no data message
+ d3.select('#wmChart' + scope.$id + ' svg')
+ .datum(chartData)
+ .call(chart);
+ postPlotProcess(scope, element, chart);
+ return chart;
+ }
}
// Plotting the chart with set of the properties set to it
@@ -938,13 +878,17 @@ WM.module('wm.widgets.basic')
var groupingDetails = getGroupingDetails(scope);
//If aggregation/group by/order by properties have been set, then get the aggregated data and plot the result in the chart.
if (scope.binddataset && scope.isLiveVariable && (scope.filterFields || isDataFilteringEnabled(scope))) {
- getAggregatedData(scope, element, groupingDetails, function () {
+ getAggregatedData(scope, element, function () {
plotChart(scope, element);
});
} else { //Else, simply plot the chart.
//In case of live variable resetting the aggregated data to the normal dataset when the aggregation has been removed
if (scope.dataset && scope.dataset.data && scope.isLiveVariable) {
scope.chartData = scope.dataset.data;
+ if (isGroupByEnabled(scope.groupby) && groupingDetails.isVisuallyGrouped) {
+ scope.chartData = getVisuallyGroupedData(scope, scope.chartData, groupingDetails.visualGroupingColumn);
+ }
+
}
plotChart(scope, element);
}
@@ -1108,6 +1052,7 @@ WM.module('wm.widgets.basic')
//Resetting the flag to false when the binding was removed
if (!newVal && !scope.binddataset) {
scope.isVisuallyGrouped = false;
+ scope.axisoptions = null;
}
variableObj = elScope.Variables && elScope.Variables[variableName];
@@ -1254,6 +1199,7 @@ WM.module('wm.widgets.basic')
return {
pre: function (iScope, $el, attrs) {
iScope.widgetProps = attrs.widgetid ? Utils.getClonedObject(widgetProps) : widgetProps;
+ $el.removeAttr('title');
},
post: function (scope, element, attrs) {
var handlers = [],
diff --git a/src/main/webapp/scripts/modules/widgets/basic/chart/chartService.js b/src/main/webapp/scripts/modules/widgets/basic/chart/chartService.js
index 75dea05d2..055fcf7f7 100644
--- a/src/main/webapp/scripts/modules/widgets/basic/chart/chartService.js
+++ b/src/main/webapp/scripts/modules/widgets/basic/chart/chartService.js
@@ -8,6 +8,7 @@ WM.module('wm.widgets.basic')
'use strict';
var chartTypes = ['Column', 'Line', 'Area', 'Cumulative Line', 'Bar', 'Pie', 'Donut', 'Bubble'],
allShapes = ['circle', 'square', 'diamond', 'cross', 'triangle-up', 'triangle-down'],
+ dateList = ['01/01/2001', '01/01/2002', '01/01/2003'],
themes = {
'Terrestrial': {
colors: ['#1f77b4', '#aec7e8', '#ff7f0e', '#ffbb78', '#2ca02c', '#98df8a', '#d62728', '#ff9896', '#9467bd', '#c5b0d5', '#8c564b', '#c49c94', '#e377c2', '#f7b6d2', '#7f7f7f', '#c7c7c7', '#bcbd22', '#dbdb8d', '#17becf', '#9edae5'],
@@ -225,19 +226,19 @@ WM.module('wm.widgets.basic')
switch (dataType) {
case 'jsonFormat':
first_series = [
- {'x': '01-01-2001', 'y': 4000000},
- {'x': '01-01-2002', 'y': 1000000},
- {'x': '01-01-2003', 'y': 5000000}
+ {'x': '01/01/2001', 'y': 4000000},
+ {'x': '01/01/2002', 'y': 1000000},
+ {'x': '01/01/2003', 'y': 5000000}
];
second_series = [
- {'x': '01-01-2001', 'y': 3000000},
- {'x': '01-01-2002', 'y': 4000000},
- {'x': '01-01-2003', 'y': 7000000}
+ {'x': '01/01/2001', 'y': 3000000},
+ {'x': '01/01/2002', 'y': 4000000},
+ {'x': '01/01/2003', 'y': 7000000}
];
third_series = [
- {'x': '01-01-2001', 'y': 2000000},
- {'x': '01-01-2002', 'y': 8000000},
- {'x': '01-01-2003', 'y': 6000000}
+ {'x': '01/01/2001', 'y': 2000000},
+ {'x': '01/01/2002', 'y': 8000000},
+ {'x': '01/01/2003', 'y': 6000000}
];
data[0] = {
values: first_series,
@@ -701,14 +702,14 @@ WM.module('wm.widgets.basic')
.showYAxis(propertyValueMap.showyaxis);
//Setting the labels if they are specified explicitly or taking the axiskeys chosen
- xaxislabel = propertyValueMap.xaxislabel || scope.xaxisdatakey || 'x caption';
- yaxislabel = propertyValueMap.yaxislabel || scope.yaxisdatakey || 'y caption';
+ xaxislabel = propertyValueMap.xaxislabel || Utils.prettifyLabels(scope.xaxisdatakey) || 'x caption';
+ yaxislabel = propertyValueMap.yaxislabel || Utils.prettifyLabels(scope.yaxisdatakey) || 'y caption';
//Adding the units to the captions if they are specified
xaxislabel += propertyValueMap.xunits ? '(' + propertyValueMap.xunits + ')' : '';
yaxislabel += propertyValueMap.yunits ? '(' + propertyValueMap.yunits + ')' : '';
chart.xAxis
- .axisLabel(Utils.prettifyLabels(xaxislabel))
+ .axisLabel(xaxislabel)
.axisLabelDistance(propertyValueMap.xaxislabeldistance)
.staggerLabels(propertyValueMap.staggerlabels);
@@ -717,7 +718,7 @@ WM.module('wm.widgets.basic')
if (isLineTypeChart(scope.type)) {
chart.xAxis.tickFormat(function (d) {
//get the actual value
- xAxisValue = scope.xDataKeyArr[d];
+ xAxisValue = isPreview ? dateList[d - 1] : scope.xDataKeyArr[d - 1];
return getDateFormatedData(propertyValueMap.xdateformat, xAxisValue);
});
} else {
@@ -738,7 +739,7 @@ WM.module('wm.widgets.basic')
}
}
chart.yAxis
- .axisLabel(Utils.prettifyLabels(yaxislabel))
+ .axisLabel(yaxislabel)
.axisLabelDistance(propertyValueMap.yaxislabeldistance)
.staggerLabels(propertyValueMap.staggerlabels)
.tickFormat(function (d) {
@@ -759,11 +760,6 @@ WM.module('wm.widgets.basic')
colors = propertyValueMap.customcolors;
}
- //Converting strings to numbers
- propertyValueMap.offsettop = Number(propertyValueMap.offsettop);
- propertyValueMap.offsetright = Number(propertyValueMap.offsetright);
- propertyValueMap.offsetbottom = Number(propertyValueMap.offsetbottom);
- propertyValueMap.offsetleft = Number(propertyValueMap.offsetleft);
showLegend = isShowLegend(propertyValueMap.showlegend);
chart.showLegend(showLegend)
.margin({top: propertyValueMap.offsettop, right: propertyValueMap.offsetright, bottom: propertyValueMap.offsetbottom, left: propertyValueMap.offsetleft})
@@ -790,6 +786,10 @@ WM.module('wm.widgets.basic')
}
}
+ function getDateList() {
+ return dateList;
+ }
+
this.isBarChart = isBarChart;
this.isBubbleChart = isBubbleChart;
this.isPieType = isPieType;
@@ -811,5 +811,6 @@ WM.module('wm.widgets.basic')
this.initProperties = initProperties;
this.allShapes = allShapes;
this.chartTypes = chartTypes;
+ this.getDateList = getDateList;
}
]);
diff --git a/src/main/webapp/scripts/modules/widgets/basic/dataNavigator/dataNavigator.js b/src/main/webapp/scripts/modules/widgets/basic/dataNavigator/dataNavigator.js
index 4b540adf4..1310d3be8 100644
--- a/src/main/webapp/scripts/modules/widgets/basic/dataNavigator/dataNavigator.js
+++ b/src/main/webapp/scripts/modules/widgets/basic/dataNavigator/dataNavigator.js
@@ -117,7 +117,7 @@ WM.module("wm.widgets.basic")
maxResults,
currentPage,
startIndex;
- dataSize = WM.isArray(newVal) ? newVal.length : (newVal.data ? newVal.data.length : 1);
+ dataSize = WM.isArray(newVal) ? newVal.length : (newVal.data ? newVal.data.length : _.isEmpty(newVal) ? 0 : 1);
maxResults = ($scope.pagingOptions && $scope.pagingOptions.maxResults) || dataSize;
//For static variable, keep the current page. For other variables without pagination reset the page to 1
if (variable && variable.category === 'wm.Variable') {
@@ -216,7 +216,8 @@ WM.module("wm.widgets.basic")
maxResults,
currentPage,
variable,
- variableOptions = {};
+ variableOptions = {},
+ elScope;
//Store the data in __fullData. This is used for client side searching with out modifying the actual dataset.
$scope.__fullData = newVal;
/*Set the default value of the "result" property to the newVal so that the widgets bound to the data-navigator can have the dataSet set properly.*/
@@ -229,8 +230,11 @@ WM.module("wm.widgets.basic")
if ($scope.binddataset.indexOf('bind:Variables.') !== -1) {
$scope.variableName = $scope.binddataset.replace('bind:Variables.', '');
$scope.variableName = $scope.variableName.substr(0, $scope.variableName.indexOf('.'));
- variable = $scope.variableName && $scope.navigatorElement.scope().Variables[$scope.variableName];
- variableOptions = variable._options || {};
+ elScope = $scope.navigatorElement.scope();
+ if ($scope.variableName && elScope) {
+ variable = elScope.Variables[$scope.variableName];
+ variableOptions = variable._options || {};
+ }
} else if (newVal) {
if (newVal.isBoundToFilter && newVal.widgetName) {
$scope.isBoundToFilter = true;
diff --git a/src/main/webapp/scripts/modules/widgets/basic/icon/icon.js b/src/main/webapp/scripts/modules/widgets/basic/icon/icon.js
index 4d0a631f7..6be680528 100644
--- a/src/main/webapp/scripts/modules/widgets/basic/icon/icon.js
+++ b/src/main/webapp/scripts/modules/widgets/basic/icon/icon.js
@@ -5,12 +5,48 @@ WM.module('wm.widgets.basic')
.run(['$templateCache', function ($templateCache) {
'use strict';
$templateCache.put('template/widget/icon.html',
- '